Unbekannter Autor ;)

Programming & Webdesign Resources

By

The misconception of “free internet”

Or: is Google really bad? Is Facebook?

The successor of the medival ages´ witch hunt is up, make sure you don´t miss it! Information technology´s giants, like Google or Facebook, are about to be burned at the stake for gathering information about your preferences, analyzing your habits on the Net, and selling those profiles for profit. Duh!

But, have you ever wondered why you´re able to use Google for free? Or why Facebook provides you with the latest news from your friends, also for zilch? It´s not like those servers they run, the people they employ, or the traffic they generate, are free as well. They pay hard cash for it. And lots of it. And even small websites, where you seek information about programming, or surfing, or whatever, have to pay the hosting, even if the work itself is just enthusiasic… and for free.

But somehow, users of all the modern information technology expect those big companies to be Mother Theresa. And get all worked up when rumors have it that Facebook might or might not charge a small fee for their services. Are you afraid of Google tracking your every move on the Net? Well, they do, but does it hurt you to see ads about something you sought to buy, on another site, a couple of days after your original search?

Get real! The information, or rather, the entertainment you enjoy by surfing the Net, ain´t free. You have to give up some information about yourself, in order to gain information others have. If you´re not willing to, please don´t use modern technologies, turn off your computer, don´t buy a smart phone, and in general, hide on some mountain and don´t bother us. But if you like the entertainment all those free site provide, click some banners, strip down naked, and share your address book ;)

By

Top 4 jQuery slideshow and gallery plugins

I recently came across 4 very nice jQuery plugins for slideshows and galleries. Actually, I found a lot more, but those are my favorites:

  1. Nivo Slider (slideshow)
  2. jqFancyTransitions (slideshow)
  3. jQuery Cycle Plugin (slideshow)
  4. Fancybox (gallery zoom)

I decided on Nivo Slider for a new project (www.gaastra-store-fehmarn.de), simply because it offers beautiful captions with links and images, which I´ll need for the second project www.loftfehmarn.de.

If you don´t need those wild animations, but are looking for a cool Lightbox alternative, check out the Fancybox plugin, which I use on surfspot.de.

By

No-MVC Zend Framework: Filter Zend_Form input with HtmlPurifier

As my favorite Zend Framework guru Padraic Brady pointet out on his blog, most forms are just about an invitation for hackers and other subversive folks to (ab)use your forms, and PHPs “addslashes” or “striptags” just don´t get the job of protecting your site done. It is one thing to assume everybody is just nice, and submits exactly what you want them to, but expect it to be different, and be prepared… just in case. That´s the point where Zend_Filter should be implemented, and even those are not to trust entirely, as tests have shown.

To prevent cross site scripting, better known as XSS, Padraic recommends HtmlPurifier as preferred method of filtering user input on web forms, so I´d suggest we comply ;) Get the newest version of HtmlPurifier, and unzip the contents into a subdirectory “HTMLPurifier” of you “library/JD/” folder (or whatever your personal folder is called). Make sure you have the upper case characters correct, iX OS is not as forgiving as Windows ;) In the following code, I used upper case HTMLP* for original files, and HtmlP* for those I wrote, so don´t get mixed up here.

Next, create “HtmlPurifier.php” in a subfolder “Filter” (according to “addPrefixPath in your form controller settings). I chose to not make “Filter” a subfolder of “Forms” (unlike “Decorator” and “Validator”), because I might use the filter to clean output from databases or other sources, instead of only input from forms. In this file, find the code:

class JD_Filter_HtmlPurifier implements Zend_Filter_Interface
{
 /**
 * The HTMLPurifier instance
 *
 * @var HTMLPurifier
 */
 protected $_htmlPurifier;

 /**
 * Constructor
 *
 * @param mixed $config
 * @return void
 */
 public function __construct($config = null)
 {
   require_once 'JD/HMTLPurifier/HTMLPurifier.auto.php';
   $this->_htmlPurifier = new HTMLPurifier($config);
 }

 /**
 * Defined by Zend_Filter_Interface
 *
 * Returns the string $value, purified by HTMLPurifier
 *
 * @param string $value
 * @return string
 */
 public function filter($value)
 {
   return $this->_htmlPurifier->purify($value);
 }
}

The $config will hold those tags allowed for this specific instance (pls refer to HtmlPurifier´s docs for details). Those values will come from the general config file, so edit your “/configs/application.ini”, and add the following lines to your “production” section:

/*Editor and Purifier*/
allowedHTML.Restrictive = "sup"
allowedHTML.Minimal = "p,em,strong"
allowedHTML.Standard = "p,em,strong,ul,ol,li"
allowedHTML.Extended = "p,em,strong,ul,ol,li,sub,sup,a[href]"

If you ever implement a WYSIWYG editor like CKEditor, you can re-use this part of your “application.ini” to set the toolbars allowed for the editor. As for the allowed tags, please adjust as you see fit.  The “restrictive” is just the tag I wouldn´t expect in any user input, so I will use that one to filter names and mail addresses.

If you´re getting impatient about how to use this, add the following line to a text element of your Zend_Form:

$form_element["comment_text"]->addFilter('HtmlPurifier', array(array('HTML.Allowed' => $this->registry->config->allowedHTML->Minimal)));

For now, this only filters the comment text element (which is a textarea, BTW). The smart thing to do would be, to check if the input is XSS, and return an error in form of “the finger” :D. Got to figure out how to do it sometime.

Anyway, you can download “Zend_Forms.zip”, containing the directory structure and files from this series, including the “bootstrap.php” in the “public” folder. Please note you need ZF in your “library/Zend/” and HtmlPurifier in your “JD/HTMLPurifier” folders!

The next article will show how to put all this stuff into use – a comment form. I´m already figuring out a smart way to do it without reloading the page, but still using the filters, so it looks like it´s going to need some AJAX.

By

No-MVC Zend Framework: Zend_Decorator and Zend_Validator

In the last article, we have already set some basic decorators for Zend_Form. The next one is a decorator for the label, appending an asterisk (*) to labels of required fields, and display error messages below the label instead of the field. In your “Form” subfolder, create a folder “Decorator”, and in it, a file named “Label.php”:

class JD_Form_Decorator_Label extends Zend_Form_Decorator_Label
{
 public function getLabel()
 {
   $element = $this->getElement();
   $label = trim($element->getLabel());
   if ($element->isRequired()) {
     $label .= ' *';
   }
   $errors = $element->getMessages();
   if (empty($errors)) {
     $element->setLabel($label);
     return parent::getLabel();
   }
   $label .= '<br /><span style="color:red;font-size:0.8em">'
   . implode('<br />', $errors)
   . '</span>';
   $element->setLabel($label);
   return parent::getLabel();
 }
}

The name “Label” corresponds to the settings for the ViewHelper in the decorators, and folder / name to the settings in the prefix path. Credits for this script, though, goes to Padraic Brady, where one can get a lot of good ideas of how to solve ZF problems ;)

Zend Framework comes with a lot of smart validators to use with Zend_Form. But with my goal in mind to create a page comment plugin for the relaunch of surfspot.de, I needed a validator to check if the user input contains foul language… no point in people abusing each other in the anonymity of the Internet ;) The old version of the site uses a validator, comparing user input to a string of bad bad words I don´t want to see on my site, so I needed to make that one “Zend_Form” compatible. Besides, over the years I added some of the most notorious spam words to the validator, so it acts as a low level spam filter as well… surfers just don´t need little blue pills to have some fun ;)

Anyway, create “JD/Form/Validator/Badwords.php”, and add the following lines:

class JD_Form_Validator_Badwords extends Zend_Validate_Abstract
{
 /**
 * Validation failure message key for when the value contains foul language
 */
 const BAD_WORDS = 'badWords';

 /**
 * Validation failure message template definitions
 *
 * @var array
 */
 protected $_messageTemplates = array(
   self::BAD_WORDS => "The text uses foul language"
 );

 /**
 * Badword array - change as required by your application
 */
 private $badwords = array('games', 'college', 'prewrcar', 'parrot', 'xx');

 /**
 * Defined by Zend_Validate_Interface
 *
 * Returns true if and only if $value does not contain bad words as defined by array
 *
 * @param  string $value
 * @return boolean
 */
 public function isValid($value)
 {
   $valueString = (string) $value;
   $this->_setValue($valueString);
   for($i=0; $i<count($this->badwords); $i++) {
     if(strstr(strtoupper($valueString), strtoupper($this->badwords[$i]))) {
       $this->_error();
       return false;
     }
   }
  return true;
 }
}

Whatever you personally consider “bad words”, add to the array, and rest assured that nobody can post those on your website. I omitted my selection out intentionally, but left some spam words in to show how it works. Make sure to add the f-word, and you can even add something like “<a href=” to the array to avoid having links posted, but that subject will be in the “filter” article up next.

By

No-MVC Zend Framework: Zend_Forms, Decorator, Validator and Filters

Managing Zend_Form in both MVC and no-MVC environments has a huge advantage, since Zend Framework comes with a load of decorators (HTML to display form fields), validators (functions to check user input) and filters (functions to filter user input). If you look for an easy way to handle all kinds of user input thru forms, ZF is the way to go… at least if you have a lot of different forms on you website, that is ;)

This articles is based on the first parts of the Star Rating series (which I still have to finish…), so it assumes you have managed to install ZF on your system, have your bootstrap.php up and running. Pls note: I changed the naming from “Mylib” to “JD”… using my initials is easier because I can copy&paste my classes ;) Just in case: here´s the bootstrap.php that you have to include, already with some new code:

<?php
// Define path to application directory
defined('APPLICATION_PATH')
 || define('APPLICATION_PATH', ($_SERVER['DOCUMENT_ROOT']));

// Define application environment
defined('APPLICATION_ENV')
 || define('APPLICATION_ENV', (getenv('APPLICATION_ENV') ? getenv('APPLICATION_ENV') : 'development'));

// Ensure library/ is on include_path
set_include_path(implode(PATH_SEPARATOR, array(
 realpath(APPLICATION_PATH . '/../library'),
 get_include_path(),
)));

/**
 * General PHP settings
 */
error_reporting(E_ALL|E_STRICT);
ini_set('display_errors', 1);
ini_set('default_charset', 'UTF-8');

/**
 * Autoloader
 */
require_once 'Zend/Loader/Autoloader.php';
$autoloader = Zend_Loader_Autoloader::getInstance();
// Register folder library/JD/ for own classes
$autoloader->registerNamespace('JD_');

/**
 * Load Zend Config from application.ini
 */
$config = new Zend_Config_Ini($_SERVER['DOCUMENT_ROOT'] . '/../library/JD/configs/application.ini', APPLICATION_ENV);
Zend_Registry::set('config', $config);

/**
 * Connect to default DB
 */
$db = Zend_Db::factory($config->database);
Zend_Db_Table::setDefaultAdapter($db);

/**
 * Get Zend View object (required for any view helpers, e.g. Form, Navigation)
 */
$view = new Zend_View;
$view->setEncoding('UTF-8');
$viewRenderer = new Zend_Controller_Action_Helper_ViewRenderer($view);
Zend_Controller_Action_HelperBroker::addHelper($viewRenderer);
// Doctype for Form Renderer
$doctypeHelper = new Zend_View_Helper_Doctype();
$doctypeHelper->doctype('XHTML1_TRANSITIONAL');

/**
 * Set default language for form errors etc
 */
$translate = new Zend_Translate('array', $_SERVER['DOCUMENT_ROOT'] . '/../library/JD/Languages/de.php', $config->language->default);
Zend_Form::setDefaultTranslator($translate);

In order to be able to use Zend_Form, you need to set the Zend_View, else it would not render it. The language part is optional, it´s a simple file replacing English error messages with (in this case) German ones. Refer to the ZF manual for language details.

The next part is to set some rendering options, A.K.A decorators. With most websites, I use YAML as a CSS framework, and ZF renders form elements into dt/dd tags (didn´t know anyone uses those anymore…). Anyway, re-decorating a form is a piece of cake. Create a subfolder “Form” in your own “library” subfolder (mine is “JD” was “Mylib”), and create a form controller, named “Controller.php”.  If you´ve read the previous articles, you can guess the name of the class… JD_Form_Controller. Replace the “JD” part with anything you like, according to your directory structure (e.g. “library/somename/Form/Controller” translates to class name “somename_Form_Controller… just basic autoloading knowledge). Here´s what the controller looks like:

class JD_Form_Controller extends Zend_Form
{
 // COLUMNAR YFORM decorators

 // standard input type=text & textareas
 protected $_standardTextDecorator = array(
   'ViewHelper',
   array('Label', array('escape'=>false)),
   array('HtmlTag', array('tag'=>'div', 'class'=>'type-text')),
   // not used
   array('Description')
 );
 // standard input type=select
 protected $_standardSelectDecorator = array(
   'ViewHelper',
   array('Label', array('escape'=>false)),
   array('HtmlTag', array('tag'=>'div', 'class'=>'type-select')),
   // not used
   array('Description')
 );
 // standard checkbox type=checkbox
 protected $_standardCheckboxDecorator = array(
   'ViewHelper',
   array('Label', array('escape'=>false)),
   array('HtmlTag', array('tag'=>'div', 'class'=>'type-check')),
   // not used
   array('Description')
 );
 // special input type=captcha -> into type-text for styling
 protected $_standardCaptchaDecorator = array(
   'ViewHelper',
   array('Label', array('escape'=>false)),
   array('HtmlTag', array('tag'=>'div', 'class'=>'type-text')),
   // not used
   array('Description')
 );
 // standard input type=hidden w/out tags
 protected $_standardHiddenDecorator = array(
   'ViewHelper'
 );
 protected $_standardButtonDecorator = array(
   'ViewHelper',
   array('HtmlTag', array('class'=>'type-button'))
 );

 // Standard YFORM decorators
 protected $_leftTextDecorator = array(
   'ViewHelper',
   array('Label', array('escape'=>false)),
   array('HtmlTag', array('tag'=>'div', 'class'=>'type-textleft'))
 );
 protected $_fullTextDecorator = array(
   'ViewHelper',
   array('Label', array('escape'=>false)),
   array('HtmlTag', array('tag'=>'div', 'class'=>'type-textfull'))
 );
 protected $_leftCheckDecorator = array(
   'ViewHelper',
   array('Label', array('escape'=>false)),
   array('HtmlTag', array('tag'=>'div', 'class'=>'type-checkleft'))
 );
 protected $_leftButtonDecorator = array(
   'ViewHelper',
   array('HtmlTag', array('tag'=>'div', 'class'=>'type-buttonleft'))
 );

 /**
 * Class constructor
 *
 * @param array $options
 */
 public function __construct($options = null)
 {        
   // path setting for custom classes MUST ALWAYS be first!
   $this->addElementPrefixPath('JD_Form_Decorator','JD/Form/Decorator','decorator');
   $this->addElementPrefixPath('JD_Form_Validator','JD/Form/Validator','validate');
   $this->addElementPrefixPath('JD_Filter','JD/Filter','filter');
   parent::__construct($options);
   $this->setAttrib('class', 'yform columnar');
   $this->setDecorators(array(
     'FormElements',
     'Form'
   ));
 }    
}

This is a lot at once, but I already set everything up for decorators (defining them and adding the prefix path), validators (still to be defined, but prefixed) and filters (also not defined yet, but prefixed). By default, I use columnar forms on the website (label next to form field: all $_standard* decorators), but also have an option to use labels above their fields ($_left or $_full). E.g. the $_standardTextDecorator wraps an INPUT element, inluding the label, into a DIV with the class “type-text”, and wraps the label into a new decorator – one that appends an * to each required input field.

Next up: Zend_Decorator and Zend_Validator

By

Google Maps Geocoding with JSON and PHP

When using maps on a website, Google is clearly the service to go with. If you are using JavaScript only, parsing a JSON response from Google shouldn´t be difficult, but how to use the response in PHP? In this article, I´ll describe how to use Zend Framework components, but with a link to How-To´s with standard PHP functions, to

  1. Send a request to Google Maps API
  2. Get the response in JSON format (no problem to switch to XML)
  3. Parse the response from Google to a more readable format
  4. And finally, use those values in a PHP script

I needed the response for the meta geotags on surfspot.de, where I use a lot of maps to show the locations of… surfspots, obviously. The geotag for a spot would be something like this:

<meta name="geo.region" content="COUNTRY_SHORT-REGION_SHORT" />
<meta name="geo.placename" content="CITY" />
<meta name="geo.position" content="LATITUDE;LONGITUDE" />
<meta name="ICBM" content="LATITUDE, LONGITUDE" />

… with latitude and longitude known (stored in database) , and city, region and country to find out from Google. Pls find details about HTML geotags on Wikipedia. The meaning of the ICBM tag is just hilarious :D For details on Google Geocoding, pls refer to their documentation.

Fist, we need the class to query Google:

class JD_Geocoder_Request
{
 /**
 * @class vars
 */

 // Google´s geocode URL
 public $url = 'http://maps.google.com/maps/api/geocode/json?';

 // Params for request
 public $sensor       = "false"; // REQUIRED FOR REQUEST!
 public $language     = "en";

 // Class vars
 public $response     = '';
 public $country_long = '';
 public $country_short= '';
 public $region_long  = '';
 public $region_short = '';
 public $city         = '';
 public $address      = '';
 public $lat          = '';
 public $lng          = '';
 public $location_type= '';

 /**
 * Constructor
 *
 * @param mixed $config
 * @return void
 */
 public function __construct($config = null)
 {

 }

} // end class

I prefer to store all results I may or may not need in class vars, so I can just echo them out.

Second, we need to know what kind of search we need to perform, forward geocoding with an address (say, from a form), or a reverse geocoding search, using lat and lng for the query. I implemented both methods, but pls be aware I didn´t test the forward search… since I don´t need it yet ;)

/**
 * Forward search: string must be an address
 *
 * @param string $address
 * @return obj $response
 */
 public function forwardSearch($address)
 {
   return $this->_sendRequest("address=" . urlencode(stripslashes($address)));
 } // end forward

 /**
 * Reverse search: string must be latitude and longitude
 *
 * @param float $lat
 * @param float $lng
 * @return obj $response
 */
 public function reverseSearch($lat, $lng)
 {
   return $this->_sendRequest("latlng=" . (float) $lat . ',' . (float) $lng);
 } // end reverse

Both methods handle formatting the parameters, as well. If you want to handle just the response object, you can skip ahead and ignore the next functions. As said earlier, I like to store the response in class vars in order to just echo them out, or store them in a database. The two functions set the defaults I need to know, and search for other values as well. Pls note that only the response object $address_components is used for the search, Google may or may not return a lot more – check their docs for this.

/**
 * Search Address Components Object
 *
 * @param string $type
 * @return object / false
 */
 public function searchAddressComponents($type) {
   foreach($this->response->results[0]->address_components as $k=>$found){
     if(in_array($type, $found->types)){
       return $found;
     }
   }
   return false;
 }

/**
 * Parse JSON default values: map object values to readable content
 *
 * @param none
 * @return none
 */
 private function _setDefaults()
 {
   $country = $this->searchAddressComponents("country");
   $this->country_long    = $country->long_name;
   $this->country_short    = $country->short_name;
   $region = $this->searchAddressComponents("administrative_area_level_1");
   $this->region_long = $region->long_name;
   $this->region_short    = $region->short_name;
   $city = $this->searchAddressComponents("locality");
   $this->city    = $city->short_name;
   $this->address = $this->response->results[0]->formatted_address;
   $this->lat = $this->response->results[0]->geometry->location->lat;
   $this->lng = $this->response->results[0]->geometry->location->lng;
   $this->location_type = $this->response->results[0]->geometry->location_type;
 } // end set

The JSON response from Google is likely to change, so you need to control the mapping every now and then. If you use the reverse geocoding, pls note that lat and lng may NOT be the same values you used to call the search with, but refer to the next best address, even if location_type is returned as “rooftop”. This doesn´t matter if you search on land, but surfspots might be 500m down a beach from a known location, at least, known to Google.

Now for the slightly more difficult part… the actual request to Google Maps API, and parsing the JSON response. Using the Zend Framework, sending a request to Google is a tad bit easier than using pure PHP. If you don´t use ZF and/or use XML response format, check this article on phpRiot, and replace the $client code.

/**
 * Send Google geocoding request
 *
 * @param string $search
 * @return object response (body only)
 */
 private function _sendRequest($search)
 {
   $client = new Zend_Http_Client();
   $client->setUri($this->url . $search . '&language=' . strtolower($this->language) . '&sensor=' . strtolower($this->sensor));
   $client->setConfig(array(
     'maxredirects' => 0,
     'timeout'      => 30));
   $client->setHeaders(array(
     'Accept-encoding' => 'json',
     'X-Powered-By' => 'Zend Framework GEOCMS by Joerg Drzycimski'));
   $response = $client->request();
   $body = $response->getBody();
   $this->response = Zend_Json::decode($body, Zend_Json::TYPE_OBJECT);
   if ($this->response->status == "OK") {
     // set some default values for reading
     $defaults = $this->_setDefaults();
     return $this->response;
   } else {
     echo "Geocoding failed, server responded: " . $this->response->status;
     return false;
   }
 } // end request

Now that you have the request up and running, the code requirde to generate the meta geotags is quite simple:

$georequest = new JD_Geocoder_Request();
$lat = '54.424899';
$lng = '11.096671';
$georequest->reverseSearch($lat,$lng);
echo '<meta name="geo.region" content="' . $georequest->country_short . '-' . $georequest->region_short . '" />';
echo '<meta name="geo.placename" content="' . $georequest->city . '" />';
echo '<meta name="geo.position" content="' . $lat . ';' . $lng . '" />';
echo '<meta name="ICBM" content="' . $lat . ',' . $lng . '" />';

Links: Class File as ZIP.

By

Converting a MySQL database to UTF-8

I just spent about 2 days to convert my old MySQL database from latin1 / latin1_general_ci to UTF-8 character encoding. There are about a gazillion pitfalls, especially when you work on old PHP code mixed with ZF code, on a live site of a client. The first tip is… do NOT work on a live site ;) Backup everything to a local version or a testserver, and then start to code! Fortunately, I had the site including the database on a local XAMPP environment.

For a coarse orientation, you can use the article on wordpress.org to get an overview. There is no way to change the character encoding of an entire database with just a few keystrokes, so expect it to take a tad bit longer.

For me, the following steps did the trick, using phpMyAdmin and Notepad++ (on Windows):

  1. Create a backup of the entire database with phpMyAdmin.
  2. Change your database to UTF-8 (ALTER DATABASE mydb CHARACTER SET utf8;). This will only affect new tables, so you´re not thru yet.
  3. Select the table(s) to change, and use the export function of phpMyAdmin.
  4. Copy the exported data (INSERT INTO…) without the header (CREATE…) into Notepad++.
  5. Change the table´s charset (ALTER TABLE mytable DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;).
  6. Change all fields with latin charsets to utf8_general_ci (e.g. ALTER TABLE mytable CHANGE myfield myfield TEXT CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL;). Pls note that this SQL only works for TEXT fields, refer to the article on wordpress.org on how to convert ENUM, VARCHARS and so on, or use phpMyAdmin to do so for you. If you have a lot of columns with the same format to convert, just copy&paste one SQL line, and change the column names in each. Paste those lines into phpMyAdmin´s SQL editor, that´s a lot faster than doing it for each column.
  7. By now, you should have the table as well as all columns in UTF-8.
  8. Switch to Notepad++, where all you INSERTs for that table are, and convert those lines to UTF-8.
  9. Copy&paste it into phpMyAdmin´s SQL editor.
  10. Repeat steps 3 to 9 for each table, and you should have your database converted to UTF-8.

Now, that took an hour or two ;), but there´s still the website to change to the new encoding.

First, start with your meta tag:

<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

Next up, if applicable, change your database connection script in PHP:

mysql_set_charset("utf8");

And / or if you use Zend Framework, edit your config file:

database.params.charset = "utf8"

and your bootstrap:

ini_set('default_charset', 'UTF-8');

$view->setEncoding('UTF-8');

That should do the trick, and your entire site runs on UTF-8 instead of latin.

By

No-MVC Zend Framework: jQuery Ajax receiver / Part V

The jQuery JavaScript is up and running, but needs a PHP file to handle the Ajax data submitted by the rating script. This will be done with PHP in the receiver you defined in your JavaScript, named “rating.php” in the “public/includes” folder. It’s important to put this PHP file in your public folder, because if you pointed your webserver to “public”, anything outside (subfolders of  your document root) can’t be accessed by JavaScript.

Create the “rating.php”, and add the following lines:

<?php
require_once('bootstrap.php'); // Setup Zend Framework Environment
header("Cache-Control: no-cache");
$rating = new Mylib_Rating_Controller();
$score = $rating->setRatingById($_GET['id'], $_GET['val']); // rate object and get scores
echo Zend_Json::encode($score); // send response array in JSON format
?>

The setRatingById passes the values from your JavaScript to the (soon to be created) controller, and receives the updated values from your (soon to be created) database. When I started out using jQuery in combination with Ajax, I was kind of afraid to find it difficult… but it really is that easy ;-)

Next up: The rating controller

By

No-MVC Zend Framework: jQuery Star Rating code / Part IV

Now for the easy part: creating the page for our jQuery Star Rating plugin. It’s going to be just a bit of HTML, JavaScript with Ajax components, and PHP. If you want to integrate the Star Rating in an existing page, you can just copy the relevant parts into any HTML file.

The JavaScript

Before continuing (or if this doesn’t work for you), you might want to familiarize yourself with the Star Rating plugin at http://zensoftware.org/archives/483.

Add the following lines to the HEAD section of your “index.php”. This assumes that you already have one… if not, use you standard HTML template, and don’t forget to include your bootstrap ;-)

<script type="text/javascript" src="/js/jquery/js/jquery-1.4.2.min.js"></script>
<script type="text/javascript" src="/js/rating/jquery.rating.js"></script>
<link type="text/css" href="/js/rating/jquery.rating.css" rel="stylesheet" media="screen" />

<script type="text/javascript">
$(function(){

 $(".rating")
 .rating({"showCancel": false})
 .bind("change", function(){
   var id = $(this).attr("id");
   var rate = "id=" + id + "&val=" + $(this).val();
   var loading = 'Loading';
   // Or use image instead, looks prettier ;-)
   // var loading = '<img src="/images/loading.gif" />';
   $.ajax({
     type: "GET",
     url: "/includes/rating.php",
     dataType: "json",
     data: rate,
     timeout: 10000,
     beforeSend: function(){
       $("#rating_value_" + id).html(loading);
     },
     success: function(response){
       $("#rating_value_" + id).html(response.average + " points");
     },
     error: function(){
       $("#rating_value").html("Error!");
     }
    }); // end ajax
  }); // end rating / bind

}); // end $()
</script>

I used “loading” as a variable (as opposed to the direct output of “Error!”). You can Google the standard Ajax loading image, and put the HTML image tag in that variable to pretty things up, instead of that boring message.

BTW, I always use a leading slash and the complete path in relation to the root directory (e.g. “/images”) before each image, JS and CSS file. This way, I don’t have to worry about broken links when I split header and content sections into different files, and move them to different directories… which I favorize, because header sections are the same throughout the website, whereas content sections might use different templates.

The PHP / HTML code

You can put this code anywhere within your BODY section of your “index.php”, even in existing pages’ DIVs:

<?php
$id = 1;
$rating = new Mylib_Rating_Controller();
echo $rating->getRatingView($id);
?>

Set the variable “$id” to any unique id you want to rate. On my website surfspot.de, I use it to rate a page, so the id comes from my database, and represents the page id. If you have more than one rating on one page, say for a couple of images, instantiate the class once, and only use echo $rating->getRatingView($id) with a different id for each image.

Next up: The jQuery Ajax receiver

By

No-MVC Zend Framework: Bootstrapping ZF / Part III

For this article, you should be familiar with at least the basics of Zend Framework, especially naming conventions. If not, check out the ZF site for beginners tutorials and/or Quickstart.

If you don’t want to use ZF at all, but still need the Star Rating with PHP and Ajax, you can skip ahead to the model part.

Bootstraping Zend Framework

The bootstrap file is (simplified) the file where you set up your ZF environment. Bootstrapping ZF in a non-application environment is nothing more that to merely include the bootstrap file manually.

First step after installing ZF and the folder structure in the previous part is to create the “index.php” file in your “public” folder, and a second file in your “public/includes” folder, named “bootstrap.php”. Open “index.php” in your favorite PHP editor, and include your bootstrap:

require_once('includes/bootstrap.php');

Open your bootstrap and add the following lines:

<?php
// Define path to application directory
defined('APPLICATION_PATH')
 || define('APPLICATION_PATH', ($_SERVER['DOCUMENT_ROOT'] . '/../application'));

// Define application environment
defined('APPLICATION_ENV')
 || define('APPLICATION_ENV', (getenv('APPLICATION_ENV') ? getenv('APPLICATION_ENV') : 'development'));

set_include_path(implode(PATH_SEPARATOR, array(
 realpath(APPLICATION_PATH . '/../library'),
 get_include_path(),
)));

require_once 'Zend/Loader/Autoloader.php';
$autoloader = Zend_Loader_Autoloader::getInstance();
// Register folder library/Mylib/ for custom classes
$autoloader->registerNamespace('Mylib_');

Most lines are copied from the standard ZF bootstrap. We won’t need the APPLICATION_PATH constant for this… I just like to keep it there , in case I switch to application somewhen in the future ;-) Something to keep in mind is the APPLICATION_ENV. You need to change the “development” to “production” when you go live with your scripts – this will be explained in the configuration part.

The important part of the bootstrap is the Zend Autoloader, making sure all ZF components plus your own scripts are found. Nothing magical about it if you know the naming conventions. If not: the autoloader searches for a script by the parts of the class call. If you have a class named “Mylib_Rating_Controller”, Zend fetches it from “library/Mylib/Rating/Controller.php”. The class “Rating_Controller” won’t be found, because it is not defined in your namespace… unless you put $autoloader->registerNamespace('Rating_') in your bootstrap, that is.

Configuration

Next up is the configuration file, where you configure your database (and cache and about a million other things beyond the scope of this tutorial). Create a folder “configs” in your “Mylib” folder, and there a “application.ini” file. Add the following lines of code:

[production]
phpSettings.display_startup_errors = 0
phpSettings.display_errors = 0
includePaths.library = APPLICATION_PATH "/../library"
database.adapter = "pdo_mysql"
database.isDefaultTableAdapter = true
database.params.host = ""
database.params.username = ""
database.params.password =
database.params.dbname = ""

[staging : production]

[testing : production]
phpSettings.display_startup_errors = 1
phpSettings.display_errors = 1

[development : production]
phpSettings.display_startup_errors = 1
phpSettings.display_errors = 1
database.params.host = "localhost"
database.params.username = "root"
database.params.password =
database.params.dbname = "rating"

Each section inherits from the one before, so if you define your default DB adapter in the production section, your development section will use this default adapter as well. For more information on config files, pls. refer to the ZF manual.

Back to bootstraping

Now it’s time to tell ZF where to get the configuration and database options. Add the following lines to your “bootstrap.php”:

$config = new Zend_Config_Ini($_SERVER['DOCUMENT_ROOT'] . '/../library/Mylib/configs/application.ini', APPLICATION_ENV);
$registry = Zend_Registry::getInstance();
$registry->set('config', $config);

$db = Zend_Db::factory($config->database);
Zend_Db_Table::setDefaultAdapter($db);

Now you are ready to do some coding for the actual task at hand… the rating controller ;-)

Next up: jQuery Star Rating Rating HTML code