Tag Archives: zend framework

Zend_Controller_Router_Route_Regex – the Power of Regular Expressions

I posted once of custom URLs within Zend Framework, but back than I wasn’t quite sure enough there isn’t a better, more elegant way to do this job. Of course as it appears, there is! With no need to is to use the power of regular expressions with Zend_Controller_Router_Route_Regex. Thus you can match dynamically the URL.

Let’s assume you’d like to have a link with something like www.example.com/3939-some-title-here. This is really very common. So to proceed you’d have to have some regex like:

$pattern = '/\d+-.*/;

So what about Zend Framework

Here the things are going naturally more OOP.

$route = new Zend_Controller_Router_Route_Regex('(\d+)-?(.*)',
                       array('controller' => 'controller_name', 'action' => 'action_name'),
                       array(1 => 'id'));
 
$ctrl->addRoute('my-route', $route);

Iterate over YouTube Channel with Zend_Gdata_YouTube

Read YouTube’s Feed in Zend App

The task is to read the entire Gdata from a YouTube’s channel. It may sound easy, but as you may know Gdata is based on the Atom publishing protocol, and it naturally gives you only the latest few items.

Of course Zend Framework has a large set of classes dealing with Google’s Gdata services, one of them is the Zend_Gdata_YouTube.

It gives you the power to iterate/paginate over the entire set of YouTube user’s/channel’s videos. In that example let’s assume you have a protected function doing the reading of a single portion:

protected function _process(Zend_Gdata_YouTube_VideoFeed $videoFeed)
{
 
    /* @var $entry Zend_Gdata_YouTube_VideoEntry */
    foreach ($videoFeed as $entry) {
        /* @var $published Zend_Gdata_App_Extension_Published */
        $published = $entry->getPublished();
        $thumbnails = $entry->getVideoThumbnails();
 
        // set date format
        $date = new Zend_Date($published->getText());
 
        // array
        $tags = $entry->getVideoTags();
 
        $data['title'] = $entry->getVideoTitle();
        $data['description'] = $entry->getVideoDescription();
        $data['date'] = $date->get('Y-MM-d hh:mm:ss');
        $data['thumb'] = @$thumbnails[3]['url'];
        $data['id'] = $entry->getVideoId();
        $data['flash_player'] = $entry->getFlashPlayerUrl();
        $data['tags'] = implode(',', $tags) . ', ' . $entry->getVideoCategory();
        // do whatever you want with the data
    }
 
}

The only thing left is to iterate over the “pages” of the feed. This can be done with getNextFeed() method.

public function readRssAction()
{
    $userId = 'some_user';
    $client = new Zend_Http_Client();
    $gdata = new Zend_Gdata_YouTube($client, 'my-app', null, $this->_apiKey);
    $videoFeed = $gdata->getUserUploads($userId);
 
    // save the last items
    $this->_process($videoFeed);
 
    try {
        while ($videoFeed = $videoFeed->getNextFeed()) {
            $this->_process($videoFeed);
        }
    } catch (Zend_Gdata_App_Exception $e) {
        echo $e->getMessage();
    }
}

You’ll get an exception when there is no more feeds to process!

To combine all this into a single controller and to complete the code here’s the entire source:

class YoutubeController extends Zend_Controller_Action
{
    protected $_apiKey = 'your_api_key_goes_here';
 
    protected function _process(Zend_Gdata_YouTube_VideoFeed $videoFeed)
    {
 
        /* @var $entry Zend_Gdata_YouTube_VideoEntry */
        foreach ($videoFeed as $entry) {
            /* @var $published Zend_Gdata_App_Extension_Published */
            $published = $entry->getPublished();
            $thumbnails = $entry->getVideoThumbnails();
 
            // set date format
            $date = new Zend_Date($published->getText());
 
            // array
            $tags = $entry->getVideoTags();
 
            $data['title'] = $entry->getVideoTitle();
            $data['description'] = $entry->getVideoDescription();
            $data['date'] = $date->get('Y-MM-d hh:mm:ss');
            $data['thumb'] = @$thumbnails[3]['url'];
            $data['id'] = $entry->getVideoId();
            $data['flash_player'] = $entry->getFlashPlayerUrl();
            $data['tags'] = implode(',', $tags) . ', ' . $entry->getVideoCategory();
            // do whatever you want with the data
        }
    }
 
    public function readRssAction()
    {
        $userId = 'some_user';
        $client = new Zend_Http_Client();
        $gdata = new Zend_Gdata_YouTube($client, 'my-app', null, $this->_apiKey);
        $videoFeed = $gdata->getUserUploads($userId);
 
        // save the last items
        $this->_process($videoFeed);
 
        try {
            while ($videoFeed = $videoFeed->getNextFeed()) {
                $this->_process($videoFeed);
            }
        } catch (Zend_Gdata_App_Exception $e) {
            echo $e->getMessage();
        }
    }
}

Note: here you’ve to substitute the API key with the one you’ve for your development.

Custom Routes with Zend_Controller_Router_Route

Rewrite The Url?

Actually this is really a common task to do. You’ve to rewrite the url to be more “user friendly”. To be more clear I’ll give you an example. Let’s imagine you have a index controller and an index action. Thus if you have to load an Id from the database at least with the build in Zend Framework capabilities, you’ve to use this link:

www.example.com/index/index/id/33949

This is not good. It’s really bad. It will be great if you can use something like this:

www.example.com/33949

The solution in Zend Framework is called Zend_Controller_Router_Route. In a short snippet this will look like so:

$frontController->addRoute("my-route", new Zend_Controller_Router_Route("/:id",
    array("controller" => "index", "action" => "index", 'id' => 1),
    array('id' => '\d+')));

Here as you can see id is set to be 1. But don’t worry that’s not a hard code. The real work is done by the last parameter where the id is matched against a number value. Thus www.example.com/3 will be OK, but www.example.com/3a won’t.

Important Note

Don’t forget to add this rewrite rule in the .htaccess file.

Zend_Validate_Alnum Doesn’t Work Correctly

Zend Framework’s Zend_Validate

I’m used to validate the form in a typical Zend Framework application with Zend_Validate or course. It gives you the absolute power to use the build in classes for standard validation, as well as write your custom validation classes.

The problem I had was a bit odd! Zend_Validate_Alnum is supposed to filter all characters and numbers, but what about non Latin symbols!? The project I’m working on is multilingual and there are eight languages, including Arabic, Chinese and Russian! All these were incorrectly !not validated by Zend_Validate_Alnum, although there were only letters and numbers!

In fact whatever the string encoding was – it doesn’t seem to work! Perhaps I’m wrong, but so far this is the situation.

Recent Update

After few test I figured out the problem was not in Zend_Validate at all! My mistake the solution is:

iconv_set_encoding('input_encoding', 'UTF-8');
iconv_set_encoding('output_encoding', 'UTF-8');
iconv_set_encoding('internal_encoding', 'UTF-8');

Secure Forms with Zend Framework

Maybe the correct title is not “with Zend Framework”, but “with PHP”, because the general approach I used is purely PHP and no Zend Framework dependency is used. However let me mention that ZF allows you to build forms with Zend_Form, which gives you an abstraction over the HTML forms with many goodies like validation, filtering and protection.

Zend_Form and Zend_Form_Element_Hash

Although the technique I’m using is doing the same thing, note that in ZF there’s a Zend_Form_Element_Hash which generates and validates the form, thus protecting you from CSRF attacks. The thing is that I didn’t use it because the form I’m protecting is not generated with Zend_Form, and I cannot benefit from everything ZF is giving to me. However you can easily reproduce the basic strategy with every form and every framework till it’s written in PHP.

What’s the solution?

It’s pretty simple and it’s described many many times around the web, simply generate a random hash, a possible solution is to use uniqid in combination with mt_rand and md5, thus you’d get quite strong hash.

Step two is to pass this generated hash, also stored in the session in a hidden value of the form. Of course now the most asked question is: but that’s visible to the source and thus everybody will have a valid hash.

There’s the trick. OK everybody will have a valid hash, but on submit the hash is validated against the SESSION variable, and as you know the session is specified between the browser (client) and the web server. Although the attacker may have a valid hash he must execute the attacking script from the same domain, possibly with the same browser, which makes the task rather difficult.

An Example

Let me show a breve example, it may help make things clearer.

1. First step – start the session

<?php
session_start();
?>

2. Second step – validate the form against the $_SESSION and generate a valid token

<?php
if (isset($_POST['name']) && $_POST['token'] == $_SESSION['token'])
    echo $_POST['name'];
else
    echo 'dont hack';
 
$_SESSION['token'] = md5(uniqid('test', true));
?>

3. Third step – make a form

<form method="POST" action="">
<input type="hidden" value="<?php echo $_SESSION['token'] ?>" name="token" />
<input type="text" name="name" value="stoimen" />
<input type="submit" name="submit" />
</form>

Demo here.

For more to test this you may try to make the same form somewhere else on the web and to point the action to http://www.stoimen.com/projects/php.secure.forms/! Without the session validation it’s absolutely sure you can post on the attacked server.

P.S. Now I’ve to admit that this have nothing to do with Zend Framework, however it’s good practice and thus may be used with every framework.