Archive for the 'Programming' category

pywst - setting up web projects quickly

published on February 22, 2009.
Heads-up! You're reading an old post and the information in it is quite probably outdated.

I wrote a Python script for automating the steps required to setup a web project environment on my local dev machine that runs on Ubuntu. Called it pywst: Python, Web, Svn, Trac. That’s the best I could do, sorry :P

The main steps for setting up a new project are:

  • Create a virtual host
  • Add it to /etc/hosts
  • Enable the virtual host
  • Import the new project to the SVN repository
  • Checkout the project to /var/www
  • Create a TRAC environment for the project
  • Restart Apache

After these steps I have http://projectName.lh/ which points to /var/www/projectName/public/, SVN repo under http://localhost/repos/projectName/ and the TRAC environment under http://localhost/trac/projectName/.

As I have this ability to forget things, I always forget a step or 2 of this process. Thus, I wrote pywst (note, this is a txt file, to use it, save it to your HDD and rename it to pywst.py). It’s not the best and nicest Python script ever wrote, but gets the job done. All that is need to be done to setup a project with pywst is:

sudo ./pywst.py projectName

2 things are required: to run it with sudo powers and to provide a name for the project.

Future improvements

The first, and the most important is to finish the rollback() method. Now, it only exits pywst when an error occurs, but it should undo all the steps made prior to the error.

Second, to make it work on other distros, not only on Ubuntu. That would require for me getting those other distros, set them up, look where they store Apache and stuff, where’s the default document root, etc. Hmm… This will take a while :)

Third, support PHP frameworks - Zend Framework, CodeIgniter and CakePHP — ZF is a must :P Under support I mean to create the basic file structure for them automagically.

Cheers!

Login example with Zend_Auth

published on January 05, 2009.
Heads-up! You're reading an old post and the information in it is quite probably outdated.

Happy New Year! Hope everyone had a blast for New Year’s Eve and managed to get some rest :) This is my first working day for this year. I’m still kinda lazy and sleepy. And I wanna eat something all the time. Damn you candies!!!

So, here’s what I’m going to do: authenticate an user against a database table using Zend Framework’s Zend_Auth component. It’s really a piece of cake. You can see a working example here: http://robertbasic.com/dev/login/. Feel free to test it and report any misbehavior down in the comments. In the codes below all paths, class names, actions, etc. will be as are in the example, so you probably will need to changed those according to your setup.

Preparation

Because I’m gonna use a database, be sure to have set the default database adapter in the bootstrap file, I have it setup like this:

<?php
$config = new Zend_Config_Ini('../application/dev/config/db_config.ini', 'offline');
$registry = Zend_Registry::getInstance();
$registry->set('db_config',$config);
$db_config = Zend_Registry::get('db_config');
$db = Zend_Db::factory($db_config->db);
Zend_Db_Table::setDefaultAdapter($db);

I’ll need it later in the code. The table structure is as follows:

--
-- Table structure for table `zendLogin`
--

CREATE TABLE `zendLogin` (
  `id` int(11) NOT NULL auto_increment,
  `username` varchar(32) NOT NULL,
  `password` varchar(32) NOT NULL,
  `name` varchar(100) NOT NULL,
  `email` varchar(100) NOT NULL,
  PRIMARY KEY  (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 AUTO_INCREMENT=2 ;

The login controller

The magic happens in the LoginController. It has two actions: indexAction and logoutAction. The indexAction will take care of showing the login form and processing the login process. The logoutAction will just logout the user. You would never figure out that one on your own, right?

Now, let’s get to the fun part — the code:

<?php
class Dev_LoginController extends Zend_Controller_Action
{
    public function indexAction()
    {
        // If we're already logged in, just redirect
        if(Zend_Auth::getInstance()->hasIdentity())
        {
            $this->_redirect('dev/secured/index');
        }

        $request = $this->getRequest();
        $loginForm = $this->getLoginForm();

        $errorMessage = "";

Not much happening here: if the user is already logged in, I don’t want him at the login form, so just redirect him somewhere else; most likely to a home page or a control panel’s index page.

The Zend_Auth implements the Singleton pattern — if you’re not familiar with it read http://framework.zend.com/manual/en/zend.auth.html#zend.auth.introduction and http://www.php.net/manual/en/language.oop5.patterns.php (at php.net scroll down to the example #2).

So, I’m just asking the Zend_Auth does it have an user identity stored in it; the identity gets stored only upon successful log in. I’m also getting the request object. The getLoginForm() is a function that I wrote for assembling the login form and is a part of the LoginController, I’ll show it’s code later.

<?php
if($request->isPost())
{
    if($loginForm->isValid($request->getPost()))
    {
        // get the username and password from the form
        $username = $loginForm->getValue('username');
        $password = $loginForm->getValue('password');

This doesn’t needs a lot of explanation: if it’s a post request, it means the form is submitted. If the submitted data is valid, just get the wanted values from the form.

<?php
        $dbAdapter = Zend_Db_Table::getDefaultAdapter();
        $authAdapter = new Zend_Auth_Adapter_DbTable($dbAdapter);

        $authAdapter->setTableName('zendLogin')
                    ->setIdentityColumn('username')
                    ->setCredentialColumn('password')
                    ->setCredentialTreatment('MD5(?)');

Here I’m getting the default database adapter, so I know whit which database I’m working with. Then I’m creating an adapter for Zend_Auth, which is used for authentication; the docs give good explanation on the adapter, read it here: http://framework.zend.com/manual/en/zend.auth.html#zend.auth.introduction.adapters.

Next, I’m telling the authentication adapter which table to use from the database, and which columns from that table. Also, I’m telling it how to treat the credentials — the passwords are stored as MD5 hashes, so the submitted passwords will first be MD5ed and then checked.

<?php
        // pass to the adapter the submitted username and password
        $authAdapter->setIdentity($username)
                    ->setCredential($password);

        $auth = Zend_Auth::getInstance();
        $result = $auth->authenticate($authAdapter);

I’m passing to the adapter the user submitted username and password, and then trying to authenticate with that username and password.

<?php
        // is the user a valid one?
        if($result->isValid())
        {
            // get all info about this user from the login table
            // ommit only the password, we don't need that
            $userInfo = $authAdapter->getResultRowObject(null, 'password');

            // the default storage is a session with namespace Zend_Auth
            $authStorage = $auth->getStorage();
            $authStorage->write($userInfo);

            $this->_redirect('dev/secured/index');
        }

If the user is successfully authenticated, get all information about him from the table (if any), like the real name, E-mail, etc. I’m leaving out the password, I don’t need that. Next I’m getting the Zend_Auth’s default storage and storing in it the user information. In the end I’m redirecting it where I want it.

<?php
else
{
    $errorMessage = "Wrong username or password provided. Please try again.";
}
}
}
$this->view->errorMessage = $errorMessage;
$this->view->loginForm = $loginForm;
}

And this is the end of the indexAction. I know I could take the correct message from $result with getMessages(), but I like more this kind of message, where I’m not telling the user which part did he got wrong.

<?php
public function logoutAction()
{
    // clear everything - session is cleared also!
    Zend_Auth::getInstance()->clearIdentity();
    $this->_redirect('dev/login/index');
}

This is the logoutAction. I’m clearing the identity from Zend_Auth, which is also clearing all data from the Zend_Auth session namespace. And, of course, redirecting back to the login form.

<?php
protected function getLoginForm()
{
    $username = new Zend_Form_Element_Text('username');
    $username->setLabel('Username:')
            ->setRequired(true);

    $password = new Zend_Form_Element_Password('password');
    $password->setLabel('Password:')
            ->setRequired(true);

    $submit = new Zend_Form_Element_Submit('login');
    $submit->setLabel('Login');

    $loginForm = new Zend_Form();
    $loginForm->setAction('/dev/login/index/')
            ->setMethod('post')
            ->addElement($username)
            ->addElement($password)
            ->addElement($submit);

    return $loginForm;
}

As promised, here’s the code for getLoginForm function. That’s the whole LoginController code, not really a rocket science :) Sorry if it’s a bit hard to keep up with the code, I needed it to break it up in smaller pieces…

And here’s the view script for the indexAction.

<?php
<h2>Zend_Login example</h2>

<p>
Hello! This is an example of authenticating users with the Zend Framework...
</p>

<p>Please login to proceed.</p>

<?php if($this->errorMessage != ""): ?>
<p class="error"><?= $this->errorMessage; ?></p>
<?php endif; ?>

<?= $this->loginForm; ?>

Other controllers

Couldn’t come up with a better subtitle :(

Here’s an example how to require the user to log in to see the page: in the init() method ask Zend_Auth is the user logged in, and if not redirect him to the login form. This way the user will have to log in to the “whole controller”. Implement the same only to the indexAction, and the user will have to only log in to see the index page; he’ll be able to access another page without logging in.

<?php
class Dev_SecuredController extends Zend_Controller_Action
{
    function init()
    {
        // if not logged in, redirect to login form
        if(!Zend_Auth::getInstance()->hasIdentity())
        {
            $this->_redirect('dev/login/index');
        }
    }

    public function indexAction()
    {
        // get the user info from the storage (session)
        $userInfo = Zend_Auth::getInstance()->getStorage()->read();

        $this->view->username = $userInfo->username;
        $this->view->name = $userInfo->name;
        $this->view->email = $userInfo->email;
    }

    public function anotherAction()
    {
    }
}

I’m also reading out the user information from the Zend_Auth’s storage, that I have stored there during the log in process.

So there. A fully working login system, which can be setup in a really short time.

Update: If you want, you can get an example source code from here: zendLogin.zip ~8kB

Happy hacking!

Styling the default Zend_Form layout

published on December 22, 2008.
Heads-up! You're reading an old post and the information in it is quite probably outdated.

Here’s an example for styling Zend_Form’s default layout. The default layout is using definition lists. While there’s an option for changing the default layout, the wrapper tags and stuff, I see no reason for it. Create the form, add some CSS and your good to go :)

Note: Be sure to provide a Document Type in your view scripts like this:

<?php
<?= $this->doctype('XHTML1_STRICT') ?>

because when the form is generated, ZF is looking at the doctype to see how to create the form elements. Forgetting the doctype will probably generate invalid markup. I learned the hard way. Don’t do the same mistake, k? :)

The generated markup

So, here’s what Zend_Form makes for us (this markup is after submitting the form, but whit generated error, to show the error markup, too):

<form enctype="application/x-www-form-urlencoded" method="post" action="">
<dl class="zend_form">
    <dt>
        <label for="input1" class="required">Input field #1:</label>
    </dt>
    <dd>
        <input type="text" name="input1" id="input1" value="" />
        <ul class="errors">
            <li>Value is empty, but a non-empty value is required</li>
        </ul>
        <p class="description">Description? Yes, please.</p>
    </dd>
    <dt>
        &nbsp;
    </dt>
    <dd>
        <input type="submit" name="submit" id="submit" value="Submit form" />
    </dd>
</dl>
</form>

The PHP code which generates this form (without the error, of course) goes like this:

<?php
$input1 = new Zend_Form_Element_Text('input1');
$input1->setLabel('Input field #1:')
          ->setDescription('Description? Yes, please.')
          ->setRequired(true);

$submit = new Zend_Form_Element_Submit('submit');
$submit->setLabel('Submit form')

$form = new Zend_Form();
$form->setMethod('post')
       ->addElement($input1)
       ->addElement($submit);

Now, the generated form looks kinda good with no styling (which is good, if some maniac comes to visit with CSS support disabled).

OK, I lie: there’s a minimum of CSS for setting the background to white and the width to 460 pixels.

As you can see I’ve shortened the HTML and the PHP in the example codes…

The styling

I like my forms a bit different: form elements and their labels side by side with element descriptions and eventual errors showing up under the element. Here’s the CSS to achieve this:

.zend_form{
background:#fff;
width:460px;
margin:5px auto;
padding:0;
overflow:auto;
}

.zend_form dt{
padding:0;
clear:both;
width:30%;
float:left;
text-align:right;
margin:5px 5px 5px 0;
}

.zend_form dd{
padding:0;
float:left;
width:68%;
margin:5px 2px 5px 0;
}

.zend_form p{
padding:0;
margin:0;
}

.zend_form input, .zend_form textarea{
margin:0 0 2px 0;
padding:0;
}

.submit{
float:right;
}

.required:before{content:'* '}

.optional:before{content:'+ '}

Of course, this CSS takes care only of the layout; things like font types and sizes, colors, borders, backgrounds, etc. are not essential for this.

So, with this CSS applied to the generated Zend_Form, you can see on the image what will come up. And you know what’s the best part? It’s good for Firefox, Internet Explorer 6, Chrome and Opera, both under Windows and GNU/Linux (sorry, not tested for Internet Explorer 7 and Safari, but they should play along as well).

I almost forgot: I added a class=“submit” to the submit button, to be able to float it right. I first tried to do that with input[type=submit], but IE doesn’t know that, and as I wanted to make a styling that looks (almost) the same in all browsers with no hacks, I decided to add the class attribute.

So there, this little CSS code snippet should get you started with styling your Zend Form’s.

Cheers!

Data filtering with PHP's Filter extension

published on December 15, 2008.
Heads-up! You're reading an old post and the information in it is quite probably outdated.

Today I was catching up on feeds and one of the articles lead me to GoPHP5.org, where I spent some time lurking. In the FAQ section of that site one sentence made me curios:

The Filter extension is a new security component in PHP.

Filter extension? Maybe it’s nothing new for some of you, but it is for me. I’ve never heard of it before. So I quickly hopped over to PHP.net and the Filter chapter of the manual.

The filter extension is an extension that comes by default in PHP 5.2. It is here to help us to “validate and filter data that comes from insecure sources, such as user input”. It can validate integers, booleans, floats, regular expressions, URLs, E-Mails and IPs. It can sanitize strings, integers, floats, URLs, E-Mails…

Examples

Here are some examples about what this extension is capable of. Lets assume that we get some data from a form with POST method. The 3 input fields are name, email and age (I’m not creating a real validator, but var_dump-ing the results of the filtering, to show what filter gives what kind of output).

<?php
// $_POST['name'] = "Robert <b>hello</b>";
var_dump(filter_input(INPUT_POST, 'name', FILTER_SANITIZE_STRING));
// Output: string(12) "Robert hello"

// $_POST['email'] = "mail@example.com";
var_dump(filter_input(INPUT_POST, 'name', FILTER_VALIDATE_EMAIL));
// Output: string(16) "mail@example.com"

// $_POST['age'] = "22";
var_dump(filter_input(INPUT_POST, 'age', FILTER_VALIDATE_INT,
                        array('options' => array('min_range' => 18,
                                                'max_range' => 28)
                        )));
// Output: int(22)

With the first filter I’m using the FILTER_SANITIZE_STRING which strips down all tags and unwanted characters from our string. The second filter validates the provided E-mail address: pass it a malformed E-mail address and it will result with a boolean false. The third filter validates the age: it must be an integer and in the range between 18 and 28 (the min and max ranges are optional, I added them just for the example).

Besides input filtering it can filter variables, too:

<?php
$string = "Some funky string with <b>html</b> code and 'quotes'";
var_dump(filter_var($string, FILTER_SANITIZE_STRING));
// Output: string(53) "Some funky string with html code and 'quotes'"
// NOTE: the single quotes in the output are encoded as &amp;#39;

var_dump(filter_var($string, FILTER_SANITIZE_MAGIC_QUOTES));
// Output: string(54) "Some funky string with html code and \'quotes\'"
// NOTE: the <b></b> html tags are NOT stripped in the output

var_dump(filter_var($string, FILTER_SANITIZE_ENCODED));
// Output: string(80) "Some%20funky%20string%20with%20%3Cb%3Ehtml%3C%2Fb%3E%20code%20and%20%27quotes%27"

Play around with it, get familiar, cause this is one nice extension that will help you make more secure web sites and web apps.

Cheers!

MyUrl view helper for Zend Framework

published on December 02, 2008.
Heads-up! You're reading an old post and the information in it is quite probably outdated.

I started writing some boring introduction but I’ll just skip to the point.

The problem

Zend Framework’s built in URL view helper — Zend_View_Helper_Url — is discarding the query string of the URL, thus breaking some links.

Example: If I’m on a page like:
http://project/foo/bar/?param1=value1
and in the bar.phtml I use the Url helper like this:

<?php
<?= $this->url(array('param2' => 'value2')); ?>

I expect this:
http://project/foo/bar/param2/value2/?param1=value1
or something similar to this. This would be just perfect:
http://project/foo/bar/param1/value1/param2/value2
But no, it gives:
http://project/foo/bar/param2/value2/

The solution

After working on several workarounds, currently this is the best one I can think of — take the link that is created by the built-in Url helper and add the query string on that link:

<?php

// Usage:
// <?= $this->myUrl($this->url(array('param2' => 'value2'))); ?>
// Output:
// http://project/controller/action/param2/value2/?param1=value1
class Zend_View_Helper_MyUrl
{
    public function myUrl(&$url, &$toAdd = array())
    {
        $requestUri = Zend_Controller_Front::getInstance()->getRequest()->getRequestUri();
        $query = parse_url($requestUri, PHP_URL_QUERY);
        if($query == '')
        {
            return $url;
        }
        else if(empty($toAdd))
        {
            return $url . '/?' . $query;
        }
        else
        {
            $toAdd = (array)$toAdd;
            $query = explode("&", $query);

            $add = '/?';

            foreach($toAdd as $addPart)
            {
                foreach($query as $queryPart)
                {
                    if(strpos($queryPart, $addPart) !== False)
                    {
                        $add .= '&' . $queryPart;
                    }
                }
            }
            return $url . $add;
        }
    }
}

The second parameter, $toAdd, should be an array of parameters that we want to add to the URL. Say, if I have a query string like:
?param1=value1&someotherparam=anditsvalue
but want only to add the param1=value1 to the URL, I would pass “param1” as the second parameter. Not passing anything as the second parameter will result in adding the complete query string to the URL.

This is an ugly hack to make ugly links work, but it works. Thoughts?

Cheers!

Robert Basic

Robert Basic

Software engineer, consultant, open source contributor.

Let's work together!

If you require outsourcing or consulting help on your projects, I'm available!

Robert Basic © 2008 — 2019
Get the feed