The Zend Framework documentation lacks when it comes to showing the ins of out of some of its components, the Zend Framework captcha seems to fall under that category. You would think there would be a ton of useful blog posts and if there are useful posts, I don’t think google is catching them. I did find some useful code on this blog, sankhomalik’s tutorial on using the zend image captcha. It does make some decent notes, so please go read this post first (and thank him, cause so far he has the best notes on the ZF captcha thus far), but the code did not seem to work with the current version of Zend that I have which is currently version 1.7.8. The other post is using some kind of Iterator and expecting the zend namespace to have a getIterator method, for some reason this was not working for me.
Here is the modified/refactored version that creates a static wrapper Captcha class using the image captcha. To reiterate what the other blog says, Make sure you have GD enabled, make sure you have a font file, make sure you have the file paths pointing to the right place, and make sure you have the right permissions for the folders that contain the images and font file.
PHP Captcha Class
class Capatcha
{
/**
* validates the last image captcha that was created
* and put into the current session.
*
* @param string $postPrefix the prefix of the post value i.e. 'captcha[id]'
* @return boolean
*/
public static function validate($postPrefix = "captcha")
{
$captcha = $_POST[$postPrefix];
$captchaId = $captcha['id'];
$captchaInput = $captcha['input'];
$captchaSession = new Zend_Session_Namespace('Zend_Form_Captcha_' . $captchaId);
$captchaWord = $captchaSession->word;
if( $captchaWord )
return $captchaInput == $captchaWord;
return false;
}
/**
* generates the captcha image and returns the image id.
*
* @param string $postPrefix the prefix of the post value i.e. 'captcha[id]'
* @return string
*/
public static function generate($postPrefix = "captcha")
{
// replace the path/to with the correct path...
// same with /images/captcha
$captcha = new Zend_Captcha_Image(array(
'name' => $postPrefix,
'wordLen' => 6,
'timeout' => 600,
'font' => "path/to/IMPACT.TTF",
'imgdir' => "path/to/images/captcha",
'imgurl' => "/images/captcha"
));
return $captcha->generate();
}
}
PHP ZF Controller
// in your action in the controller,
// it would look like some variation of this
if($this->getRequest()->isPost())
{
if(!Capatcha::validate())
{
$id = Capatcha::generate();
$this->view->captcha = $id;
$this->view->message = "captcha was invalid";
return;
} else {
$this->view->message = "saved!";
}
}
else
{
$this->view->message ="";
$id = Capatcha::generate();
$this->view->captcha = $id;
}
XHTML View
<!-- above your form using with short tags on -->
<div class="error"><?= $this->message ?></div>
<!-- somewhere in your form -->
<img src="/images/captcha/<?= $this->captcha ?>.png" alt="captcha" />
<input type="text" name="captcha[input]" value="" />
<input type="hidden" name="captcha[id]" value="<?= $this->captcha ?>" />
If you are not familiar with type/value boxing using objects, head over to wikipedia’s object_type article to grasp the concept. While languages such as Java and C# support this natively, PHP does not. However it can be accomplished, to some degree in PHP, just not eloquently as the language itself does not have constructs to support it. Having box types in PHP could help with chaining, keeping everything object oriented and allows for type hinting in method signatures. The downside is overhead and the fact that you now have extra checking to do using the “instanceof†construct. Having a type system is also a plus when using development tools that have intellisense or code assist like PDT. Rather than having to google/bing/yahoo for the method, it exists on the object, and you can use the tool to provide a drop down.
Boxing and Unboxing with Midori PHP
In Midori PHP I’ve add box types for native values in PHP. Granted not all the types are there yet, as i’m slowly porting them in, writing documentation, writing tests, and refactoring what currently exists from the prototype. The key classes to look at would be the Midori_Object, Midori_Nullable, and Midori_String. The Midori_Nullable class currently abstracts a nullable value into a class which is built on the Midori_Object and is the parent of Midori_String. So using these box classes might look like the follow:
PHP
// boxing example
$str = new Midori_String("my cool new value"); // value is now boxed
$str2 = $str->replace("value", "test");
// unboxing
$unboxedStr = $str2->value; // unboxed value
echo $unboxedStr; // my cool new test
echo $str // my cool new value
echo $str2 // my cool new test
Midori_String uses the magic method __toString to allow echo to called on the object and the Midori_String will even allow for dot concatination since it has __toString. The “value” property is the actual value inside of the Midori_String box object to which it wraps. The Midori_String also returns the new value and does not affect the original value, during each method call, so that actual object acts just like a value type.
Understanding Chaining Methods after Instantiation
Another problem in PHP is that when you instantiate an object, it does not allow for chaining right away, which can be bothersome.
PHP
// incorrect way to chain in PHP
$str = new Midori_String("don't objectify me, sidekick")->concat("!"); // epoch fail
// correct way to chain
$str = new Midori_String("don't objectify me, sidekick");
echo $str->concat("!"); // don't objectify me, sidekick!
So in hopes of getting around that and to use common box types often: I propose creating and using functions “box_x” to wrap the instantiation of a box type and to allow for chaining. I also thinking having an “unbox” function to allow for unboxing of values if the object is an instance of Midori_Nullable, would also be handy.
PHP
// boxing example with forth coming helper methods
// these methods are prototypes and would like feed back.
$str = box_str("my cool new value")
->replace("value", "test") //chain 1, replacing a value
->toUpper() // chain 2, uppercasing.
->value; // chain 3, returning the unboxed value
echo $str; // MY COOL NEW TEST
$str = box_str("my cool new value!")->trimEnd("!");
$unboxed = unbox($str);
echo $unboxed; // my cool new value!
PHP does not allow for operator operations on objects
// example of what you have to do to add two box objects in PHP
$grade = new Midori_Int32(90);
$grade2 = new Midori_Int32(60);
// correct way to add 2 boxed objects in PHP using Midori
$sum = unbox($grade) + unbox(grade2);
$sum = $grade->value + $grad2->value;
echo $sum; // 150
// incorrect way, though it would be nice if PHP could support it
$sum = $grade + $grade;
As most web developers know there is a difference between HTTP GET and HTTP POST and sometimes you end up using a combination of these items and take precedence depending on what are you are trying to accomplish. In the Zend Framework, when working with controllers there is a Zend_Controller_Request_Http object used in conjunction with controllers. The object has useful methods like determining what kind of HTTP Request it is (isPost, isXmlHttpRequest, isGet, etc), getting various request variables (_getParam, getParams, getPost,etc).
While working on a search page for a client, I came across a need to get POST values which could sometimes also be in the query string already, but needed the HTTP POST variables to take precedence in being loaded. When using $this->_request->_getParam() inside of the controller, the HTTP GET values were taking precedence. The reason why: there is no $this->_request->getGet() method on the request object, HTTP GET data must be acquired through $this->_request->_getParam() or by calling for the property (which invokes the magic method __get on the request object). The _getParam() method always checks GET data first. However there is a $this->_request->getPost() method which can be used to retrieved the post values.
PHP
// in the controller action method....
// too long to use a ternary.
// TIP:
// technically $this->_request->search should be the same as
// $this->_request->getPost('search');
if($this->_request->isPost())
$params = $this->_request->getPost('search'); // HTTP POST
else
$params = $this->_getParam("search", array()); // HTTP GET
// there is no $this->getGet('search')
While working with the Zend Framework and partial loops, I ran into a few issues. One was not getting the data to load, which was easily solved after looking at partials documentation. Make sure you set the object key in the controller for the partial loop. The other issue of trying to pass local variables into the partial loop took time to see there was really no current answer without extending or creating a new helper, or the evil global.
PHP
// in the action method
global $otherVariable;
$otherVariable = "should be the same through each iteration";
$this->view->partialLoop()->setObjectKey('model');
$this->view->paginator = Zend_Paginator::factory($array); //etc
// in the view
<?= $this->partialLoop('path/to/_partial.phtml', $this->paginator) ?>
// in the _partial.phtml
<?php
$model = $this->model
global $otherVariable; // just seems so hackish to have to do this.
?>
I have already added a task to Midori PHP to extend the Partial Loop Helper to overcome the lack of the ability to pass in local variables to the partial loop.
disclaimer: this is not to start a flame war but for me to rant on things that have cost me time out of my life but should not have.
PHP die hard fans galore and actual reputable programmers that use PHP press forward for how great a tool it is to build websites and that it is enterprise ready. While it is a moderately decent tool that does have it’s uses, I might argue that enterprise point one day once I get my house in order. Which is hard to do cause I lack time, because PHP and some technologies just suck my time. Vicious Cycle.
Even though method names slightly vary, today, its easier to be navigate and productively use 5 or 6 programing languages through common conventions and consistencies through those languages. Even more so with frameworks that pushes these common consistencies, it adds to that performance boost of just getting things done. However, while working on a PHP framework to help overcome its continual IE6 like blight on the web, I constantly run into little things that just make me writhe in mental anguish.
PHP has no common object types, though it looks like a pecl extension is working on this issue with SPL Types which sadly isn’t bundled inside of PHP5.3. PHP has a ton of functions to manipulate its values, str_x functions, array_x functions, etc. On top of that, those functions were aimed at low barrier to entry and suffer from the “I’m going to be so clever with this” design syndrom that it not only trains new programmers learning PHP to learn bad concepts. Its also hard to remember and guess functionality since quite a few of these functions deviate from common practice, thus leaving not so easy to remember caveats that makes it harder for developers to switch languages.
To demonstrate this issue, I bring up the almighty “indexOf” method that is typically found on a String object/class. “IndexOf” is known to take a string or char and search a string for the index of the specified value. It returns the index position of this search or a -1 if the value is not found…. ahh but not so in PHP. Even Javascript has a string class with an indexOf method that returns a -1, but not PHP, it has a strpos function that returns false instead of -1 inside of a language that has dynamic typing. <sarcasm>GENIUS</sarcasm>
This presents a problem for doing conditional statements because “false” equates to “0″ with dynamic typing. When using strpos or indexOf, any return value over -1, including 0, means that search found something.
So if you incorrectly check for false, which can also mean 0 in php, you can see where this would cause bugs in your software. Developers who do more than one language might easily overlook this.
c#
var index = "Don't objectify me, sidekick.".IndexOf("test"); // -1
if(index > -1)
Console.WriteLine("I've been objectified");
ruby
index = "Don't objectify me, sidekick.".index('test') // -1
if !!index # testing for null well nil is better than false
puts "I've been objectified"
Javascript
var index = "Don't objectify me, sidekick.".indexOf('test');
if(index > -1)
console.log("I've been objectified");
php
$index = strpos("Don't objectify me, sidekick.", 'test'); //false or equates to 0
if($index !== false) // um ick totally not easy to remember.
echo " I've been objectified ";
if($index != false)
echo " The index has to be 1, if the index is 0... epoch fail ";
if(index > -1) // could run the risk of being casted as a 0, if strpos returns false
echo " oops now i'm all buggy, cause i ducktyped false into 0 ";
There are other functions that do this same kind of scenario in PHP returning an unexpected value than what other languages are doing in some consistent fashion across the board. This kind of thing makes the barrier a little higher for programmers that do various languages, increases the room for bugs to be introduced and even increases the barrier to entry for hard core PHP programmers into other languages.