PHP Coding Standards (3) – Coding Style

1. PHP code must always be delimited by the full-form, standard PHP tags. Short tags are only allowed within view scripts.

 

For example : 

[codesyntax lang=”php”]

<?php
// Php code here
?>

[/codesyntax]

   

[codesyntax lang=”php”]

// index.phtml
<?= 'hello' ?>

[/codesyntax]

 

 

2. When a string is literal (contains no variable substitutions), the apostrophe or "single quote" must always used to demarcate the string.

 

For example : 

[codesyntax lang=”php”]

$a = 'Example String';
$b = `Excute Something`;

[/codesyntax]

 

 

3. When a literal string itself contains apostrophes, it is permitted to demarcate the string with quotation marks or "double quotes". This is especially encouraged for SQL statements.

 

For example : 

[codesyntax lang=”php”]

$sql = "SELECT `id`, `name` from `people` WHERE `name`='Fred' OR `name`='Susan'";

[/codesyntax]

 

 

4. Variable substitution is permitted only in the way that : $+variable name.

 

For example : 

[codesyntax lang=”php”]

$greeting = "Hello $name, welcome back!";   // permitted
$greeting = "Hello {$name}, welcome back!"; // permitted
$greeting = "Hello ${name}, welcome back!"; // not permitted

[/codesyntax]

 

 

5. Strings may be concatenated using the "." operator. A space must always be added before and after the "." operator to improve readability.

 

For example : 

$company = 'Zend' . 'Technologies';

 

 

6. When concatenating strings with the "." operator, it is permitted to break the statement into multiple lines to improve readability. In these cases, each successive line should be padded with whitespace such that the "." operator is aligned under the "=" operator.

 

For example : 

[codesyntax lang=”php”]

$sql = "SELECT `id`, `name` FROM `people` " 
. "WHERE `name` = 'Susan' "
. "ORDER BY `name` ASC ";

[/codesyntax]

 

 

7. Negative numbers are not permitted as array indices. An indexed array may be started with any non-negative number, however this is discouraged and it is recommended that all arrays have a base index of 0.

 

For example : 

[codesyntax lang=”php”]

$sampleArray = array(-1 => -1, 0 => 0); // wrong
$sampleArray = array(0 => -1, 1 => 0); // right
$sampleArray = array(1 => -1, 2 => 0); // right

[/codesyntax]

 

 

8. When declaring indexed arrays with the array construct, a trailing space must be added after each comma delimiter to improve readability.

 

For example : 

[codesyntax lang=”php”]

$sampleArray = array(1, 2, 3, 'Zend', 'Studio');

[/codesyntax]

 

 

9. It is also permitted to declare multi-line indexed arrays using the array construct. In this case, each successive line must be padded with spaces such that beginning of each line and each value is aligned.

 

For example : 

$sampleArray = array(1,        2,  3,  'Zend', 
'Studio', $a, $b, $c,
56.44,    $d, 500);

 

 

10. When declaring associative arrays with the array construct, it is encouraged to break the statement into multiple lines. In this case, each successive line must be padded with whitespace such that both the keys and the values are aligned.

 

For example : 

$sampleArray = array('firstKey'  => 'firstValue', 
 'secondKey' => 'secondValue');

 

 

11. The brace is always written on the line underneath the class name ("one true brace" form).

 

For example : 

class foo
{
// one true brace
}
class foo {
// wrong
}

 

 

12. Every class must have a documentation block that conforms to the phpDocumentor standard.

 

For example : 

/**
* Class Docblock Here
*/

class Zend_Class
{
}

 

 

13. Any code within a class must be indented the standard indent of four spaces.

 

For example : 

class Zend_Class
{
$spaces = '4 spaces';
if ($spaces == '4 spaces') {
echo 'is permitted !';
}
}
class Zend_Class
{
$spaces = 'less then 4 spaces';
if ($spaces != '4 spaces') {
echo 'is not permitted !';
}
}

 

 

14. Only one class is permitted per PHP file. Placing additional code in a class file is permitted but heavily discouraged. In these files, a blank line must separate the class from any additional PHP code in the file.

 

For example : 

<?php
// It's permitted but discouraged
class Zend_Class
{
static $foo = 'foo';
}
echo Zend_Class::$foo;

 

 

<?php
/**
* It's not permitted to
* declare more than one class
* in one php file
*/

class Class_One
{
}
class Class_Two
{
}
?>

 

 

15. Any variables declared in a class must be listed at the top of the class, prior to declaring any functions.

 

For example : 

class right
{
public $foo = 'before function declaring';
public function fun()
{
}
}
class wrong
{
public function fun()
{
}
public $foo = 'after function declaring';
}

 

 

16. The var construct is not permitted. Member variables always declare their visibility by using one of the private, protected, or public constructs. Accessing member variables directly by making them public is permitted but discouraged in favor of accessor methods having the set and get prefixes.

 

For example :

 

class foo
{
var $unpermitted = "It's unpermitted!";
private $_privateVariable = "It's private";
protected $_protectedVariable = "It's protected";
public $publicVariable = "It's public";
public function setPrivateVariable($value)
{
$this->_privateVariable = $value;
}
public function getPrivateVariable()
(
return $this->_privateVariable;
)
}
$foo = new foo();
// Discouraged
echo $foo->publicVariable;
// Encouraged
echo $foo->getPrivateVariable();

 

 

 

17. Methods must always declare their visibility by using one of the private, protected, or public constructs.

 

For example : 

class foo
{
function goo()
{
// It's not permitted
}
private function bar()
{
// It's right
}
protected function baz()
{
// It's right
}
public function zoo()
{
// It's right
}
}

 

 

18. Following the more common usage in the PHP developer community, static methods should declare their visibility first.

 

For example : 

class foo
{
static function baz()
{
// It's not permitted
}
public static function bar()
{
// It's right
}
}

 

 

19. As for classes, the opening brace for a function or method is always written on the line underneath the function or method name ("one true brace" form).

 

For example : 

class foo
{
public function braceIsUnderneath()
{
// It's right
}
public function braceIsNotUnderneath() {
// It's wrong
}
}

 

 

20. There is no space between the function or method name and the opening parenthesis for the arguments.

 

For example : 

class foo
{
public function someSpacesAfterMe  ($a)
{
// It's wrong
}
public function noSpacesAfterMe($a)
{
// It's right
}
}

 

 

21. Passing function or method arguments by reference is only permitted by defining the reference in the function or method declaration. Call-time pass by-reference is prohibited.

 

For example : 

function defineRefInMethod(&$a)
{
$a = 'a';
}
function callTimePassRef($a)
{
$a = 'a';
}
$b = 'b';
$c = 'c';
// It's permitted
defineRefInMethod($b);
echo $b; // 'a'
// It's prohibited
callTimePassRef(&$c);
echo $c; // 'a'

 

 

22. The return value must not be enclosed in parentheses. This can hinder readability and can also break code if a function or method is later changed to return by reference.

 

For example : 

class foo
{
public $bar = 'bar';
public function goo()
{
return ($this->bar);
}
public function & zoo()
{
return ($this->bar);
}
}
$foo = new foo();
// Seems no problem
echo $foo->goo();
/**
* One notice will raise saying that :
* "Only variable references should be returned by reference"
*/

echo $foo->zoo();

 

 

23. The use of type hinting is encouraged where possible with respect to the component design.

 

For example : 

class Zend_Component
{
public function foo(SomeInterface $object)
{}
public function bar(array $options)
{}
}

 

 

24. Where possible, try to keep your use of exceptions vs. type hinting consistent, and not mix both approaches at the same time in the same method for validating argument types.

 

For example :

 

class Not_Zend_Class
{
}
class foo
{
public function bar(Zend_Class $zc)
{
}
public function goo($zc)
{
if (!$zc instanceof Zend_Class) {
throw new Exception('$zc is not instance of Zend_Class');
}
}
}
$foo = new foo();
$zc  = new Not_Zend_Class();
/**
* Catchable fatal error raised saying that :
* "Argument 1 passed to foo::bar() must be an instance of Zend_Class,
* instance of Not_Zend_Class given"
*/

$foo->bar($zc);
/**
* Message saying : '$zc is not instance of Zend_Class'
*/

try {
$foo->goo($zc);
} catch (Exception $e) {
echo $e->getMessage();
}

 

 

 

25. Function arguments are separated by a single trailing space after the comma delimiter.

 

For example : 

// Nice
threeArguments(1, 2, 3);
// Bad
threeArguments(1,2,3);

 

 

26. For functions whose arguments permit arrays, the function call may include the "array" construct and can be split into multiple lines to improve readability. In these cases, the standards for writing arrays still apply.

 

For example : 

threeArguments(array(1, 2, 3), 2, 3);
threeArguments(array(1,    2,  3,    'Zend',
 'Studio', $a, $b,   $c,
 56.44,    $d, 500), 2,  3);

 

 

27. Control statements based on the "if", "else", and "else if" constructs must have a single space before the opening parenthesis of the conditional, and a single space between the closing parenthesis and opening brace.

 

For example : 

// It's right
if ($spaceOutSide) {
// ...
} else if ($spaceOutSide) {
// ...
} else {
// ...
}
// It's wrong
if($noSpaceOutSide){
// ...
}else if($noSpaceOutSide){
// ...
}else{
// ...
}

 

 

28. Within the conditional statements between the parentheses, operators must be separated by spaces for readability. Inner parentheses are encouraged to improve logical grouping of larger conditionals.

 

For example : 

if (($a != 2) and ($b == 1)) {
$a = $b;
}

 

 

29. The opening brace is written on the same line as the conditional statement. The closing brace is always written on its own line. Any content within the braces must be indented four spaces.

 

For example : 

// It's right
if ($braceSameLine) {
echo 'Nice : indented 4 spaces';
}
// It's wrong
if ($braceNotSameLine)
{
echo 'Bad : indented 2 spaces';
}

 

 

30. PHP allows for these statements to be written without braces in some circumstances. The coding standard makes no differentiation and all "if", "else if", or "else" statements must use braces.

 

Example of formatted statement : 

// It's right to with braces
if ($a != 2) {
$a = 2;
} else if ($a == 3) {
$a = 4;
} else {
$a = 7;
}
// It's wrong to without braces
if ($a != 2)
$a = 2;
else if ($a == 3)
$a = 4;
else
$a = 7;

 

 

31. Use of the "elseif" construct is not allowed in favor of the "else if" combination.

 

For example : 

if (true) {
//
} else if {
// right
}
if (true) {
//
} elseif {
// wrong
}

 

 

32. Control statements written with the "switch" construct must have a single space before the opening parenthesis of the conditional statement, and also a single space between the closing parenthesis and the opening brace.

 

For example : 

switch ($num) {
// right
}
switch($num){
// wrong
}

 

 

33. All content within the "switch" statement must be indented four spaces. Content under each "case" statement must be indented an additional four spaces.

 

For example : 

switch ($indentedSpaces) {
case 2:
echo "It's wrong";
break;
case 4:
echo "It's right";
break;
default:
break;
}

 

 

34. The construct "default" may never be omitted from a "switch" statement.

 

For example : 

switch ($isWithDefault) {
case false:
break;
default:
echo "It's right to always with 'default'";
break;
}
switch ($isWithDefault) {
case false:
echo "It's wrong to without 'default'";
break;
}

 

 

35. It is sometimes useful to write a "case" statement which falls through to the next case by not including a "break" or "return". To distinguish these cases from bugs, such "case" statements must contain the comment "// break intentionally omitted".

 

For example : 

switch ($numPeople) {
case 1: // break intentionally omitted
case 2:
break;
default:
break;
}

 

 

36. Usage of the global keyword is not allowed. Use $GLOBALS[xxx] instead.

 

For example : 

$a = 'a';
function foo()
{
// It's wrong
global $a;
$foo = $a;
// It's right
$foo = $GLOBALS['a'];
return $foo;
}
echo foo();

 

 

Posted in Coding Standards | Tagged , | Leave a comment

Singleton Pattern in Zend Framework

The singleton provides a very good solution to the problem when you need an object to be handled as always single and global.

 

Singleton, which may usually merge up with other patterns (e.g. registry, factory), has been used in creating the independent objects for the application such as session and database connection etc..

 

Now let’s go and see how Zend_Controller_Front implements it in Zend Framework :

 

 

Code simplified :

 

[codesyntax lang=”php”]

class Zend_Controller_Front
{
    // Singleton instance
    protected static $_instance = null;

    // Constructor
    // Instantiate using {@link getInstance()}; front controller is a singleton object.
    protected function __construct()
    {
        ......
    }

    // Enforce singleton; disallow cloning
    private function __clone()
    {
    }

    // Singleton instance
    public static function getInstance()
    {
        if (null === self::$_instance) {
            self::$_instance = new self();
        }

        return self::$_instance;
    }

    ......
}

[/codesyntax]

 

We store the instance in a static variable that usually called $_instance and declared with protected or private. Then the getInstance() function is called to get the instance which will only be initialized once at the first time. This is so called "one and only one".

 

What we should notice is that the __clone() function is forbidden in the way declared with private which means we can’t clone the object and it’s instance anymore. And this is the "real" singleton.

 

We can now get the instance of Zend_Controller_Front only through Zend_Controller_Front::getInstance().

 

Posted in Design Patterns | Tagged , | Leave a comment

Factory Pattern in Zend Framework

The factory pattern is a simple but powerful design pattern which makes it very easy to manage and maintain plenty of classes.

 

The factory pattern, as it means, is using some material to provide products. But what we call the factory pattern here is to create the objects by assigning parameters to the producer class. In fact the very basical function such as print() is the brief explanation of factory.

 

Now let’s take a look at Zend_Cache module and its explanation of factory pattern :

 

 

 

The source code of Zend_Cache below is simplified in order to keep clear :

 

<?php
abstract class Zend_Cache
{
    // Standard frontends
    public static $standardFrontends = array([]);

    // Standard backends
    public static $standardBackends = array([]);

    // Standard backends which implement the ExtendedInterface
    public static $standardExtendedBackends = array([]);

    // ……

    /**
     * Factory
     *
     * @param mixed  $frontend        frontend name (string) or Zend_Cache_Frontend_ object
     * @param mixed  $backend         backend name (string) or Zend_Cache_Backend_ object
     * @return Zend_Cache_Core|Zend_Cache_Frontend
     */

    public static function factory($frontend, $backend, [])
    {
        //……

        $backendClass = ‘Zend_Cache_Backend_’ . $backend;
        $backendObject = new backendClass;

        $frontendClass = ‘Zend_Cache_Frontend_’ . $frontend;
        $frontendObject = new frontendClass;

        $frontendObject->setBackend($backendObject);
        return $frontendObject;
    }

    // ……
}

 

 

We should pay attention to the fact that Zend_Cache is declared with abstract which means it’s an abstract class. This makes it impossible to be instantiated and only be used as a factory that provide objects you need. This is an effective mechanism to prevent mess from misapply the factory.

 

In the other hand, we can also see some static variables such as $standardFrontends which can be seen as the quality standard of the products. These standards are easy to maintain. Users can use or modify them everytime and everywhere.

 

Here are the products which Zend_Cache provides :

 

 

 

All the Zend_Cache_Frontend_Xxx are inherited from Zend_Cache_Core : 

 

<?php
class Zend_Cache_Core
{
}

class Zend_Cache_Frontend_Output extends Zend_Cache_Core
{
}

class Zend_Cache_Frontend_Function extends Zend_Cache_Core
{
}

class Zend_Cache_Frontend_File extends Zend_Cache_Core
{
}

class Zend_Cache_Frontend_Class extends Zend_Cache_Core
{
}

class Zend_Cache_Frontend_Page extends Zend_Cache_Core
{
}

 

 

We can get the instance of cache frontend by using the following code :

 

[codesyntax lang=”php”]

// We choose a backend (for example 'File' or 'Sqlite'...)
$backendName = '[...]';

// We choose a frontend (for example 'Core', 'Output', 'Page'...)
$frontendName = '[...]';

// We set an array of options for the choosen frontend
$frontendOptions = array([...]);

// We set an array of options for the choosen backend
$backendOptions = array([...]);

// We create an instance of Zend_Cache
// (of course, the two last arguments are optional)
$cache = Zend_Cache::factory($frontendName,
                             $backendName,
                             $frontendOptions,
                             $backendOptions);

[/codesyntax]

 

 

The factory is the strong guarantee for the maintenance of framework. You can find it everywhere within the Zend Framework.

 

Posted in Design Patterns | Tagged , | 1 Comment

PHP Coding Standards (2) – Naming Conventions

1. The Zend Framework employs a class naming convention whereby the names of the classes directly map to the directories in which they are stored.

 

Based on PEAR Coding Standards, we can easily find the right place where the file stored from the class name.

 

For example :

Zend_Acl_Role stands for Zend/Acl/Role.php

 

 

[codesyntax lang=”php”]

require_once 'Zend/Acl/Role/Interface.php';
class Zend_Acl_Role implements Zend_Acl_Role_Interface
{
......
}

[/codesyntax]

 

This rule has provided a pseudo-namespace mechanism which will become real in php5.3 and php6.

 

 

2. Class names may only contain alphanumeric characters. Numbers are permitted in class names but are discouraged. Underscores are only permitted in place of the path separator.

 

Also came from PEAR Coding Standards, but Zend Framework has redefined it to become more stringent.

 

Examples are :

Zend_Db_Table is permitted.

Zend_Db_Table2 is not discouraged.

Zend-Db-Table is not allowed.

 

 

3. When creating an API for use by application developers (as opposed to Zend Framework internal developers), if application developers must identify abstractions using a compound name, separate the names using underscores, not camelCase.

 

It’s hard to understand this rule. So let’s take am example here. When we want to initialize an instance of Zend_Db_Adapter_xxx, we usually pass the adapter as string into Zend_Db::factory() in order to get the product of database adapter.

 

First we can initialize the MySQL PDO driver :

[codesyntax lang=”php”]

$db = Zend_Db::factory('PDO_MYSQL', $config);

[/codesyntax]

 

We can also make MsSQL PDO driver:

[codesyntax lang=”php”]

$db = Zend_Db::factory('PDO_MSSQL', $config);

[/codesyntax]

 

 

4. If a class name is comprised of more than one word, the first letter of each new word must be capitalized. Successive capitalized letters are not allowed.

 

For example :

Zend_PDF is not allowed.

Zend_Pdf is right.

 

 

5. Zend Framework classes that are authored by Zend or one of the participating partner companies and distributed with the Framework must always start with "Zend_" and must be stored under the "Zend/" directory hierarchy accordingly.

 

For example :

Zend_Db is authored by Zend, and it’s stored like "Zend/Db.php".

My_Db is authored by user so never start with "Zend_" and usually stored like "My/Db.php".

 

 

6. Interface classes must follow the same conventions as other classes (see above), but must end with "_Interface".

 

For example :

Zend_Controller_Dispatcher_Interface stands for Zend/Controller/Dispatcher/Interface.php

 

 

 

7. For all other files, only alphanumeric characters, underscores, and the dash character ("-") are permitted. Spaces are prohibited.

 

For example :

Zend/Controller/Front.php is right.

My/Controller/Common-Action_2.php is also allowed.

My/Controller/Common Action.php is not allowed.

 

 

8. Any file that contains any PHP code must end with the extension ".php" except for those view scripts which extension ".phtml" or ".html".

 

For example :

Zend/Controller/Front.php is the standard way that name php while index.phtml is the default view script name.

 

You must have seen these kind of extensions for php file :

.php4

.php5

.phpx

.class.php

.include.php

html (joking?)

 

But in Zend Framework you will see only one style, that is ".php".

 

 

9. Function names may only contain alphanumeric characters and start with a lowercase letter. Underscores and numbers are not allowed in function names. When consisted of more than one word, the first letter of each new word must be capitalized which is commonly called the "camelCaps" method.

 

For example :

[codesyntax lang=”php”]

filterInput()
getElementById()
widgetFactory()

[/codesyntax]

 

They are all right way to name the functions.

 

But :

[codesyntax lang=”php”]

FilterInput3()
getelementbyid()
widget_factory()

[/codesyntax]

 

These all are not allowed.

 

 

10. Verbosity is encouraged. Function names should be as illustrative as is practical to enhance understanding.

 

For example :

[codesyntax lang=”php”]

getOne($id) // is not clear.
getOneRecordById($id) // is perfect.

[/codesyntax]

 

 

11. For object-oriented programming, accessors for object members should always be prefixed with either "get" or "set".

 

For example :

 

[codesyntax lang=”php”]

class Foo
{
    protected $_testObj;

    public function getTestObj()
    {
        return $this->_testObj;
    }

    public function setTestObj($testObj)
    {
        $this->_testObj = $testObj;
    }
}

[/codesyntax]

 

 

12. When using design patterns, such as the Singleton or Factory patterns, the name of the method should contain the pattern name where practical to make the pattern more readily recognizable.

 

For example :

[codesyntax lang=”php”]

abstract class Zend_Cache
{
    // ......

    public static function factory($frontend, $backend,
        $frontendOptions = array(), $backendOptions = array(), 
        $customFrontendNaming = false, $customBackendNaming = false, 
        $autoload = false)
    {
        // ......
    }
}

[/codesyntax]

 

 

13. Though function names may not contain the underscore character, class methods that are declared as protected or private must begin with a single underscore.

 

For example :

[codesyntax lang=”php”]

class Zend_Foo
{
    protected function _fooBar()
    {
        // ...
    }
}

[/codesyntax]

 

 

14. Functions in the global scope, or "floating functions," are permitted but heavily discouraged. It is recommended that these functions be wrapped in a class and declared static.

 

For example :

[codesyntax lang=”php”]

class Zend_Debug
{
    // ......

    public static function dump($var, $label = null, $echo = true)
    {
        // ......
    }
}

[/codesyntax]

 

 

15. Functions or variables declared with a "static" scope in a class generally should not be "private", but protected instead. Use "final" if the function should not be extended.

 

For example :

[codesyntax lang=”php”]

class Foo
{
    final public static function fooFinally()
    {
    }
}

class Bar extends Foo
{
}

// This is wrong
Bar::fooFinally();

// Use Foo::fooFinally() instead
Foo::fooFinally();

[/codesyntax]

 

 

16. The opening brace of functions and methods has to be in the next line.

 

For example :

[codesyntax lang=”php”]

function Myfunction($parameter1)
{
}

[/codesyntax]

 

 

17. Use "null" as the default value instead of "false" when $optional does not have or need a particular default value. However, if an optional parameter is boolean, and its logical default value should be true, or false, then using true or false is acceptable.

 

Consider the code below :

[codesyntax lang=”php”]

public function foo($required, $optional = null)
{
    if (isset($optional)) {
        echo 'Echo something only when $optional is set and != null';
    }
}

public function foo($required, $optional = false)
{
    if (isset($optional)) {
        echo 'Always echo something';
    }
}

[/codesyntax]

 

 

18. Variable names may only contain alphanumeric characters. Underscores or numbers are not permitted.

 

For example : 

[codesyntax lang=”php”]

$foo // is right
$foo_foo // is wrong
$foo2 // is also wrong

[/codesyntax]

 

 

19. For class member variables that are declared with the private or protected construct, the first character of the variable name must be a single underscore. This is the only acceptable usage of an underscore in a variable name. Member variables declared as "public" may never start with an underscore.

 

For example :

[codesyntax lang=”php”]

class Zend_Foo
{
    private $_barPrivate;
    protected $_barProtected;
    public $barPublic;
}

[/codesyntax]

 

 

20. Like function names, variable names must always start with a lowercase letter and follow the "camelCaps" capitalization convention.

 

For example :

[codesyntax lang=”php”]

$compatibilityMode
$registryClassName

[/codesyntax]

 

 

21. Verbosity is encouraged. Variable names should always be as verbose as practical. Terse variable names such as "$i" and "$n" are discouraged for anything other than the smallest loop contexts. If a loop contains more than 20 lines of code, variables for such indices or counters need to have more descriptive names.

 

For example the code below came from Zend_Search_Lucene :

[codesyntax lang=”php”]

// read segmentInfos
for ($count = 0; $count < $segments; $count++) {
$segName = $segmentsFile->readString();
......
}

[/codesyntax]

 

 

22. Constants may contain both alphanumeric characters and the underscore. Numbers are permitted in constant names. Constant names must always have all letters capitalized. Words in constant names must be separated by underscore characters.

 

For example :

[codesyntax lang=”php”]

"MY_CONSTANT_ONE" // is allowed
"MYCONSTANTTWO" // is not allowed
"my_constant_two" // also not allowed

[/codesyntax]

 

 

23. Constants must be defined as class members by using the "const" construct. Defining constants in the global scope with "define" is permitted but heavily discouraged.

 

For example :

 

[codesyntax lang=”php”]

class Zend_Acl
{
const TYPE_ALLOW = 'TYPE_ALLOW';
const TYPE_DENY  = 'TYPE_DENY';
......
}

[/codesyntax]

 

 

24. Unlike PHP’s documentation, the Zend Framework uses lowercase for both boolean values and the "null" value.

 

Code came from Zend_Mail :

[codesyntax lang=”php”]

public function setMessageId($id = true)
{
if ($id === null || $id === false) {
return $this;
} elseif ($id === true) {
$id = $this->createMessageId();
}
......
}

[/codesyntax]

 

Posted in Coding Standards | Tagged , | Leave a comment

Create Captcha Image with Zend_Dojo

Users usually see the captcha and are asked to type the same in order to prove their truth when they are just going to take the registration.

 

Zend_Captcha in Zend Framework provides this kind of functionalities. Especially Zend_Captcha_Image which allow to show the words within an image has really made it easy.

 

See example below :

 

 

Now what I want to achieve is to change the image and its words on every time we click on the image without reloading the whole page. Just like what we do on the registration of BBS.

 

We have to prepare some things before start doing anything. First of all is to download your favourite font (.ttf) from any free of charge font-site. And here I choose a font called Faktos and put it under "public/fonts/faktos/" :

 

 

It’s the default font style of the words.

 

Second, we need the folder to store the images. For example in "public/img/captcha/" :

 

 

Ok let’s start coding. The script below is based on Zend_Dojo, which provide the powerful ajax support from Dojo toolkit. The first script is IndexController.php, the other one is index.phtml and that’s all we need.

 

[codesyntax lang=”php”]

// IndexController.php
class IndexController extends Zend_Controller_Action
{
    // create the form and its captcha image
    public function indexAction()
    {
        $form = new Zend_Form();
        $captcha = $this->createCaptcha();
        $form->addElement($captcha);
        $this->view->captchaImageUrl = $captcha->getCaptcha()->getImgUrl()
                                     . $captcha->getCaptcha()->getId()
                                     . $captcha->getCaptcha()->getSuffix();

        $this->view->formLogin = $form->render();
    }

    // Ajax : echo the new src of new image
    public function ajaxAction()
    {
        $captcha = $this->createCaptcha()->getCaptcha();
        $captcha->generate();
        echo $captcha->getImgUrl() . $captcha->getId() . $captcha->getSuffix();
        die;
    }

    // create the captcha element
    public function createCaptcha()
    {
        // decorator of captcha image, we add id and onclick()
        $decorators = array(
            array('HtmlTag', array('tag' => 'div',
                                   'id' => 'captchaId',
                                   'onclick' => 'changeImage()'))
        );

        $form = new Zend_Form();

        // Zend_Captcha_Image : images are saved in public/img/captcha/
        $captcha = $form->createElement('captcha', 'captcha', array(
            'captcha' => array(  
                'captcha' => 'Image',
                'wordLen' => 6,
                'fontsize' => 20,
                'width' => 200,
                'height' => 100,
                'dotNoiseLevel' => 2,
                'timeout' => 300,  
                'font' => 'fonts/faktos/Faktos.ttf',
                'imgDir' => './img/captcha/',
                'imgUrl' => '/img/captcha/',
            ),
            'decorators' => $decorators
        ));

        return $captcha;
    }
}

[/codesyntax]

 

We use CDN 1.3.1 ver. of Dojo and as a result no need for other operations, just copy and paste then you will see the result.

 

[codesyntax lang=”php”]

// index.phtml
<?php
// use latest version of Dojo through CDN, and make some configs
$this->dojo()->enable()
             ->setCdnVersion('1.3.1')
             ->setDjConfigOption('parseOnLoad', true)
             ->setDjConfigOption('isDebug', false)
             ->setDjConfigOption('locale', 'zh');

// echo the Dojo, we can also put it to the top of page 
echo $this->dojo();
?>

<script type="text/javascript">
    // change image
    function changeImage()
    {
        // do not change it if we click the input box
        if (document.activeElement.id == 'captcha-input') {
            return false;         
        }

        // Dojo - ajax get
        dojo.xhrGet( {
            // Url called
            url: "/index/ajax",

            // handle the response as text
            handleAs: "text",

            // timeout in microseconds
            timeout: 5000,

            // call load function when successful
            load: function(response, ioArgs) {
                // find the original image src and replace it by new one
                dojo.query("img", document.getElementById("captchaId")).forEach(
                    function(selectTag) {
                        if (selectTag.src.indexOf("<?php echo $this->captchaImageUrl; ?>")) {
                            selectTag.src = response;
                        }
                    }
                );
                return response;
            },

            // when error occurs
            error: function(response, ioArgs) {
                console.error("HTTP status code: ", ioArgs.xhr.status);
                return response;
            }
        });
    }
</script>

<?php
// echo the form
echo $this->formLogin;
?>

[/codesyntax]

 

It’s very simple and practical !

 

Posted in Zend Framework | Tagged , | Leave a comment