PHP

Authenticating A User With Zend_Auth

One of the nice things about the Zend Framework is being able to use it all, or only use individual parts that appeal to you. The Zend_Auth component is no exception, and makes it very easy to authenticate users. An important distinction needs to be made between authentication and authorization. Authentication is determining whether someone is who they say they are - in other words, assigning an identity to an end user. Authorization revolves around determining what actions a user can perform, and is typically handled by Zend_Acl.

Authenticate Against a Database

While using a 3rd party such as Facebook, Google, Twitter or OpenId is starting to gain a lot of traction, authenticating against a database is still one of the most common ways to authenticate a user. At it's most simplest (read the last paragraph to learn why you should never use this code), assuming we had a table called userTable with a field username for the username, and password for the password, we would have something like:

<?php
        $auth 
Zend_Auth::getInstance();
        
$db = new Zend_Db_Adapter_Pdo_Mysql(array(
            
'host' => 'localhost',
            
'username' => 'username',
            
'password' => 'password',
            
'dbname' => 'mydb'
        
));
         
$authAdapter Zend_Auth_Adapter_DbTable($db,'userTable','username','password');
        
$authAdapter->setIdentity($_POST['user'])->setCredential($_POST['password']);
        
$result $auth->authenticate($authAdapter);
        if(
$result->isValid()) {
            die(
'user authenticated');
        } else {
            die(
'user not authenticated');
        }
?>

In this example, we get the Zend_Auth instance using the static function getInstance. Zend_Auth is a singleton, meaning there should only be one instance of the class during request execution. The reason for this becomes apparent when you use Zend_Auth to get a user's identity. You want to ensure you are always accessing the same instance of Zend_Auth in your code.


We then set up the database connection with the variable $db, and set up the adapter used by Zend_Auth, referenced by the variable $authAdapter. $authAdapter takes the database adapter, then the name of the table that holds end users' credentials, then the field name of said table that has the username, and finally the field name of said table that stores the password. Finally, we set the identity and credential via a $_POST variable that would be supplied on a login form, and call authenticate on Zend_Auth while passing in the adapter and check if the result is valid. All in all, pretty straightforward.

Get My Identity


Once an end user has successfully logged in, we can get the end user's identity via Zend_Auth:


<?php
        $auth 
Zend_Auth::getInstance();
        if (
$auth->hasIdentity()) {
            
$identity $auth->getIdentity();
            
print_r($identity); // $authAdapter->setIdentity($_POST['user']);
        
}
?>

First, we grab the singleton Zend_Auth and then check if the user has an identity. If she does, then we get the identity. I can see the question bouncing around in your head - what is the identity. By default, when you log in with the code above, it will use the value from the setIdentity method, which is typically the user name. You can now tell whether a user is logged in, and you have their user name stored in a session.


What happens if you want to store something else besides a string as the identity? For example, you may be using Zend_Acl, and want to know the role of the user - let's create an object and store that as the identity. We have a couple of options to accomplish this, but first let's understand what Zend_Auth is doing when you call the authenticate method. Zend_Auth takes the identity returned by the Adapter (which in the case of the db adapter is a string) , and persists the identity in a session. Therefore, we could create our own adapter and return an object instead of a string, or we can interact directly with the db adapter and bypass Zend_Auth. The second option seems easiest to explain, so let's roll with that (subclassing db adapter would make a nice blog post...).

<?php
        $db 
= new Zend_Db_Adapter_Pdo_Mysql(array(
            
'host' => 'localhost',
            
'username' => 'root',
            
'password' => '',
            
'dbname' => 'bf'
        
));
        
$authAdapter = new Zend_Auth_Adapter_DbTable($db,'userTable','username','password');
        
$authAdapter->setIdentity($_POST['user'])->setCredential($_POST['password']);
        
$result $authAdapter->authenticate();
        if(
$result->isValid()) {
            echo 
'user authenticated<br />';
        } else {
            echo 
'user not authenticated<br />';
        }
        
$auth Zend_Auth::getInstance();
        
var_dump($auth->hasIdentity());
?>

We have similar code as before, except we are calling authenticate on the adapter. If you run this code in a browser, you would see that we authenticated the user (assuming you put in the right username and password), but we get false when calling $auth->hasIdentity(). Since we didn't use Zend_Auth to authenticate, the identity is not “saved.

To remedy this, we can update our code with the following lines:

<?php
        $auth 
Zend_Auth::getInstance();
        
$db = new Zend_Db_Adapter_Pdo_Mysql(array(
            
'host' => 'localhost',
            
'username' => 'root',
            
'password' => '',
            
'dbname' => 'bf'
        
));
        
$authAdapter = new Zend_Auth_Adapter_DbTable($db,'member','username','password');
        
$authAdapter->setIdentity($_POST['user'])->setCredential($_POST['password']);
        
$result $authAdapter->authenticate();
        if(
$result->isValid()) {
            echo 
'user authenticated<br />';
            
$auth->getStorage()->write($authAdapter->getResultRowObject(array(
                
'username''role'
            
)));
        } else {
            echo 
'user not authenticated<br />';
        }
        
        
var_dump($auth->hasIdentity()); //true
        
var_dump($auth->getIdentity()); // object(stdClass)#67 (2) { ["username"]=> string(3) "rob" ["role"]=> string(5) "admin" }
?>

Once the result is valid, we are getting the storage mechanism (usually a session) and telling the storage to save the result from the database as a standard object. The array of username and role are the fields we want to save. Notice we left out the password field, as that should not be persisted. For my applications, I actually have a user object that implements Zend_Acl_Role_Interface, so I instantiate my user object, and grab the values from the stdClass object that is returned from getResultRowObject.

Can You Say Insecure

What's so horrible about the above code? We are storing an end user's password in plain text within the database. If someone gains access to the database, that person now has access to all your users' password. Maybe that's not a big deal because you don't store any sensitive information like credit cards, but it's still a very bad idea. Not only will your street cred be ruined as the entire internet laughs at your folly of storing unencrypted passwords, but if you happen to store email addressees, a cracker would now have your user's email address and the password for your site. A decent percentage of your users will likely have the same password for your site and for their email account (who can remember unique passwords for every site...). You get the picture...

At a minimum, you need to encrypt the password stored in your database and add a salt to the password. You can read this article to brush up on the problems with storing passwords in a database. My next blog post will cover how to use a one way hash and a salt to make it more difficult for passwords to be cracked in the event your database is compromised.


Posted In: PHP, Zend Framework | 3 comments

How to Handle a date in PHP

Handling dates is an important part of many applications, and fortunately, it is relatively easy to work with dates in PHP.

Set the Timezone

Before jumping into how to handle dates, it is worth noting that PHP by default will use the date and time from the server. If the time zone of your server differs from your timezone, or the people using your website, you can have some unexpected results. To determine what your time zone is, you can use:

<?php
    
echo date_default_timezone_get();  // America/Los_Angeles for Western
?>

There are a couple of options available if you want to change the time zone. If you want to change the time zone in just your current PHP script, find your time zone, and then use:

<?php
    date_default_timezone_set
('America/Los_Angeles');
?>

If you would like to change it for all PHP scripts on the server, you can edit the php configuration file (php.ini) :


[Date]
; Defines the default timezone used by the date functions
date.timezone = America/New_York

Get the Current Date


Now that we have your time zone set correctly, let's look at the simple use case of echo'ing out the current date. To do this, you can use the date function.

<?php
    
echo date('m/d/y');  // 02/01/11
?>

It's easy to apply a different format to the date, just replace the characters in the above example with any of the following:


Important Full Date and Time:

  • r: Displays the full date, time and timezone offset. It is equivalent to manually entering date("D, d M Y H:i:s O")


Time:

  • a: am or pm depending on the time

  • A: AM or PM depending on the time

  • g: Hour without leading zeroes. Values are 1 through 12.

  • G: Hour in 24-hour format without leading zeroes. Values are 0 through 23.

  • h: Hour with leading zeroes. Values 01 through 12.

  • H: Hour in 24-hour format with leading zeroes. Values 00 through 23.

  • i: Minute with leading zeroes. Values 00 through 59.

  • s: Seconds with leading zeroes. Values 00 through 59.



Day:

  • d: Day of the month with leading zeroes. Values are 01 through 31.

  • j: Day of the month without leading zeroes. Values 1 through 31

  • D: Day of the week abbreviations. Sun through Sat

  • l: Day of the week. Values Sunday through Saturday

  • w: Day of the week without leading zeroes. Values 0 through 6.

  • z: Day of the year without leading zeroes. Values 0 through 365.



Month:

  • m: Month number with leading zeroes. Values 01 through 12

  • n: Month number without leading zeroes. Values 1 through 12

  • M: Abbreviation for the month. Values Jan through Dec

  • F: Normal month representation. Values January through December.

  • t: The number of days in the month. Values 28 through 31.



Year:

  • L: 1 if it's a leap year and 0 if it isn't.

  • Y: A four digit year format

  • y: A two digit year format. Values 00 through 99.




Other Formatting:

  • U: The number of seconds since the Unix Epoch (January 1, 1970)

  • O: This represents the Timezone offset, which is the difference from Greenwich Meridian Time (GMT). 100 = 1 hour, -600 = -6 hours


Timestamps and Dates

Echo'ing the current date is easy, but how about calculating dates in the future or past? In the above examples, we simply provided the formatting as the first parameter and the date function spit out the current date/time. If you want to work with dates other than the current one, you will need to use the second parameter of the date function, which is a timestamp.

A timestamp is UNIX speak for the number of seconds that have passed since January 1, 1970. To generate the current date and time via a timestamp, you can use the mktime function. When you call the date function, it is grabbing the current timestamp by default and you don't need to provide the timestamp:

<?php
    
echo date('m/d/y');
    echo 
date('m/d/y'mktime()); 
?>

Manipulating Dates

Manipulating dates is hard until you get the basics of timestamps. There are a couple of ways to generate dates in the part or future. One way is to simply add or subtract the number of seconds for a given duration. For example, there are 86,400 seconds in a day, so if we wanted to display the date for tomorrow, you could simply use the below code to generate the current timestamp, then add 86,400 seconds (a day) to the timestamp, which gives us the timestamp for tomorrow:

<?php
    
echo date('m/d/y', (mktime() + 86400));
?>

Calculating the number of seconds in a month or year can be a bit laborious, so let's take a look at some other functions to help with manipulating and calculating dates. First up is the strtotime function, which expects to be given a string containing an English date format and will return the timestamp for the given string. To get the date for tomorrow, and next month, and next year, we could use:

<?php
        
echo date('m/d/y'strtotime("+1 day")) . '<br />';
        echo 
date('m/d/y'strtotime("+1 month")). '<br />';
        echo 
date('m/d/y'strtotime("+1 year")). '<br />';
?>

The strtotime function can also come in handy if you are dealing with a date column from MySQL (e.g. it is formatted as YYYY-MM-DD):

<?php
     $mysqlDate 
'2011-01-20';
    echo 
date('F j, Y'strtotime($mysqlDate));
?>

Validating Dates

I can't believe you've made it this far... Since you have, let's look at validating a date that could come from a user. As any good coder knows, we never trust input that comes from 3rd parties, whether that is an end user entering a value into an HTML form, or data coming from a web service.

With that in mind, how do we validate that an end user entered in a correct date into a form field? If we use the strtotime function with an invalid date, it will return false. So it strtotime can’t parse the date, we know it is not a valid date!

<?php
        
if(!strtotime('2011-13-20')) {
            echo 
'That is a bad date';
        }
?>

In Conclusion

Hopefully, you know a bit more about how to work with dates in PHP. We've only scratched the surface, and there are a lot of other functions available, so keep on learning!

Posted In: PHP | No Comments

Uploading Large Files In PHP

Quite the coincidence... I happen to be working on a form for uploading large files, and an article on Sitepoint pops up in my RSS feeds describing some of the settings to use. Besides the point that a lot of those settings mentioned in the article can not be set using ini_set (check php.net for which directives can be used with ini_set), there is also an issue I just ran into. If you set both your upload_max_filesize and post_max_size the same number, you may be in for a surprise when someone tries to upload too large of a file.

What's the surprise? Your form variables will not be available in the php script processing the upload, or at least that is what's happening to me. Since the post_max_size has been exceeded, $_POST is empty. This is a problem if you need variables from the form/$_POST to do a redirect or take some other action. Setting your post_max_size above the upload_max_filesize doesn't seem to help either. It looks like you need to stick the variables you absolutely need in the url and use $_GET to ensure you reliably have them.

Posted In: Uncategorized, PHP | No Comments

PHPUnit and Mock Object Exactly Method

[php]
$mapper->expects($this->exactly('2'))->method('delete');
$mapper->expects($this->exactly(2))->method('delete');
[/php]
The two above lines of code don't behave the same. When passing in 2 as a string instead of a number, PHPUnit declares it a failure:

Em_Model_Collection_MapperTest::testDeleteCollectionWithJoinTable
Expectation failed for method name is equal to when invoked 2 time(s).
Method was expected to be called 2 times, actually called 2 times.

Posted In: PHP | No Comments

symlink with FTP

Apparently you can't use FTP for symlinks? It's been so long since I have mucked around with FTP, that I didn't realize you could not create symlinks. I have an old site I still maintain and had to move it to a new hosting provider and the new provider did not give SSH access (well at least without charging for it). PHP to the rescue:
[php]
symlink('../gallery','gallery');
[/php]
Use the symlink command in PHP. Obviously you need to have the proper permissions, and since PHP may be running as a different user, your mileage may very. But it worked for me...

Posted In: PHP, Linux | 2 comments

Zend_Acl with User Specific Permissions

There are many articles around explaining Zend_Acl and how to use it within a CMS like system where generic roles apply - i.e. an admin can do anything, a guest can leave a comment and an author can write articles. But I was having a hard time figuring out how to elegantly enforce user specific permissions in addition to generic permissions For example, an author can save a new article, but can only update or delete an article that they "own". I was trying to use assertions, but the role object in the assertion was turned into a generic Zend_Acl_Role object, even though I was using my own role object that implemented Zend_Acl_Role_Interface. Therefore, I couldn't check the userId of the role in the assertion and was trying to pass responsibility back onto the object that was checking the acl.

It looks like this has all been fixed in 1.9.1, and Ralph does a good job of explaining the details. I have yet to try the improvements, but looking forward to refactoring my code to use the new and improved assertions.

Posted In: PHP, Zend Framework | 1 comment

Slicehost VPS

I signed up for a VPS on Slicehost today, and am very impressed. The interface is refreshingly basic and I was up and running in no time. Their articles are absolutely amazing, and worth the read even if you don't use their services. I know Ubuntu somewhat, but am far from an expert. Using the Ubuntu set up guide, I was up and running in under an hour. I made a stupid mistake when copying my public key and had to rebuild my slice. But that's the beauty of the cloud, just hit a button, start with a fresh install and go again.

I am testing it out, as I have a dedicated server which costs too much for the small number of low traffic sites I maintain. After going through all the articles on getting the basics set up, I altered my /etc/hosts file on my desktop to point to the IP address of my new slice, updated the ServerAlias in the Apache vhosts file to include the "slice" domain name in my /etc/hosts file, and then finally enabled mod_rewite (sudo a2enmod rewrite) so I could test out a site that was running Zend_Framework without having to actual point production traffic at it.

I then set up rysnc and get some database permission set up and tables copied over, and it was live. Talk about easy....

I looked at Amazon, and while it offers a lot of flexibility and they are developing more and more tools (instead of APIs), it just seemed like way to much work for my limited needs. Anyways, really impressed with Slicehost after just one day, we'll see how it goes in the next week or so. This blog may be moving over next...

Posted In: PHP, Linux | 2 comments

Zend_Http_Client and Garbled Response Body

Using Zend_Http_Client to make a simple REST GET request to a web service and the body of the response I got back was completely mangled – i.e. the characters were not even remotely readable. That’s strange I thought, and pasted the url in my browser and it came back fine. Looking at the response headers, I saw the content encoding was gzip ([Content-encoding] => gzip), which made sense as my browser would uncompress the response, while PHP would not automatically do that.

Rather than trying to uncompress the response, I modified the request header to not accept gzip and it came back un-encoded and ready to use in PHP:

[php]
$client = new Zend_Http_Client($url);
$client->setHeaders(array('Accept-encoding' => ''));
$response = $client->request();
print_r($response);
[/php]

Posted In: PHP, Zend Framework | 1 comment

Zend_Service_Technorati, Exceptions and partialLoop

I am utilizing Zend_Service_Technorati to tag search and when I return the results and loop through it via a partialLoop, an exception is thrown occasionally. One of the results does not have a valid uri and Zend_Uri_Http is throwing the exception based on the path (not sure whether Tehnorati is returning a invalid url or Zend_Uri_Http is declaring a valid url invalid). The problem is I am using partialLoop to dynamically loop through result sets other than Technorati, such as Youtube and Flickr, and it is nice just to call the appropriate partial based on the result set object.

However, there is no easy way to catch the Exception. If I wrap the entire partial loop in a try/catch, then it doesn't display any results when there is an exception, even though there is only one offending result:
[php]
try {
echo $this->partialLoop('adminexternalmedia/_result' . $this->collection->type . '.phtml',$this->resultSet);
} catch(Exception $e) {
echo 'problem';
}
[/php]
I can't catch the exception in the partial that handles the display, because the exception is created once the individual result is grabbed from the set and before the partial is "rendered" - i.e. triggered in the foreach call. Since the result sets implement SeekableIterator, I can use a while loop and call partial, instead of relying on the partialLoop, and handle my exception as I deem fit:
[php]
$this->partial()->setObjectKey('model');
while($this->resultSet->valid()) {
try {
$result = $this->resultSet->current();
echo $this->partial('adminexternalmedia/_result' . $this->collection->type . '.phtml',$result);
} catch (Exception $e) {
echo 'problem

';
}
$this->resultSet->next();
}
[/php]

Posted In: PHP, Zend Framework | No Comments

Zend_Gdata and Fatal error: Allowed memory size

Querying Youtube for videos via Zend_Gdata and ran into memory issues when searching for up to 20 videos. It was a simple fix, just had to up my memory_limit in php.ini. It was at 8M and I set it to 12M and am not running into any more issues. If you are on a shared hosting environment, you can use init_set within the page:
[php]
ini_set("memory_limit","12M");
[/php]
Just be careful what you set it to, as too high a limit could cause problems.If you have a page that consumes a lot of memory and you set it high, say 50M, and along comes something that requests the page a lot, maybe a search spider gone bad or malicious user, you could run out of memory on your server...

Posted In: PHP, Zend Framework | No Comments

PHP 5.1.4 and Apache Problems

I know, I am behind the times. PHP 5.3 is almost ready for prime time, but I was still using PHP 5.1.4 I was having some major issues with Apache recently, although I don't think it was Apache that was the problem. I wasn't able to diagnose the problem, but I believe connections to MySQL were hanging and causing Apache to choke. It was very sporadic, but as I rolled out a couple sites that made heavy use of MySQL (and not enough use of caching), the problems became more frequent. My server was detecting too high a load on Apache and restarting it a couple of times a day, and every month of so, MySQL would completely choke and require a killall and restart.

My sites get such low traffic amounts, it wasn't like the server was getting crushed under the load. I upgraded to PHP 5.2.6 and MySQL 5.0.67, and no problems since the upgrade (its only been 48 hours). I have a feeling it was PHP, but don't know for sure. So if you have PHP 5.1.4 and are running into Apache choking, try upgrading to the latest PHP stable and see if that cures the problem.

Posted In: PHP, Apache | No Comments

Zend_Paginator and Zend_Paginator_Adapter_Null

I have been playing around with Zend_Paginator a little more, and came across a use case where I didn't want the Paginator to manage the data, i.e. I was feeling lazy and didn't feel like writing a custom adapter. You can use Zend_Paginator_Adapter_Null to manage the pagination controls and simply pass in the total number of results into the constructor. I.e
[php]
$paginator = new Zend_Paginator(new Zend_Paginator_Adapter_Null('43'));
$paginator->setCurrentPageNumber('1');
$paginator->setItemCountPerPage('20');
$this->view->paginator = $paginator;
[/php]
The 43 I am passing into the constructor is the total number of results, and would likelu not be a static number, but coming from some other data source. For example, if you were using Zend_Service Flickr, it would look like this, assuming the variable $flickr has already been set up:
[php]
$paginator = new Zend_Paginator(new Zend_Paginator_Adapter_Null($flickr->totalResultsAvailable));
$paginator->setCurrentPageNumber('1');
$paginator->setItemCountPerPage('20');
$this->view->paginator = $paginator;
[/php]
Follow the manual on setting up the actual display of the pagination. Now I need to get some more spare time and write a custom adapter for flickr and other Zend Services and also familiarize myself with caching of the paginator.

Posted In: PHP, Zend Framework | No Comments

Zend_Paginator

I needed some pagination for a website I am building, so I took a look at Zend_Paginator. It is pretty straightforward and easy to use, especially if you are using the rest of the framework. The code below assume the class Foo extends Zend_Db_Table_Abstract, and grabs a Zend_Db_Select object from the table to pass in the constructor of Zend_Paginator. Zend_Paginator uses that select object to run 2 queries, one to determine the overall count of objects, and one to grab the rowset used on the page. This rowset is then accessed via getItemsByPage();
[php]
$foo = new Foo();
$paginator = new Zend_Paginator(new Zend_Paginator_Adapter_DbTableSelect($foo->select()));
$paginator->setCurrentPageNumber($this->_getParam('page',1));
$paginator->setItemCountPerPage('2');
$this->view->paginator = $paginator;
$this->view->rowset = $paginator->getItemsByPage($this->_getParam('page',1));
[/php]
Of course, most of the time you wont be using a vanilla select statement, so your code may end up looking more like this:
[php]
$foo = new Foo();
$paginator = new Zend_Paginator(new Zend_Paginator_Adapter_DbTableSelect($foo->select()->where('publish = ?','yes')));
[/php]
I don't like to have my logic for grabbing a rowset spread throughout my controller class and try to isolate it within the object.
[php]
$foo->getLatest(); //return rowset with custom query
[/php]
My Foo object also doesn't directly extend Zend_Db_Table_Abstract. So, I contemplated creating a customized Zend_Paginator_Adapter, but opted instead to have an option on my "get" methods to return a select object instead of a rowset
[php]
$foo = new Foo();
$select = $foo->getLatest(array('paginator' => true));
$paginator = new Zend_Paginator(new Zend_Paginator_Adapter_DbTableSelect($select));
[/php]
I'm not entirely sold on this approach yet... We'll see how it pans out as more use cases are tested out. Is it bad that the getLatest method can return different types of objects based on an input parameter?

Posted In: PHP, Zend Framework | No Comments

NetBeans, Subversion and Symlinks

I have been using NetBeans the past couple of weeks for PHP coding, and am generally happy with it. One small annoyance I have is with the Subversion plugin and symlinks. I have a project that has symlinks to other folders. After committing the symlinks to Subversion, when I issue svn status from the command line, there are no additional files. When I check the status in NetBeans, it says all the files in the symlinked directory are new, and need to be added to the repository. I know Subversion treats a symlink as a file and in essence ignores all the stuff in the directory the symlink points to, so why is NetBeans considering it differently? The only work around I have found is to manually ignore all the files:





I could set an svn property to ignore that symlink, but I want the symlinks there when I checkout the project on another computer...

Posted In: PHP | 1 comment

Install NetBeans 6.5 on Ubuntu 8.10

I have decided to play around with NetBeans 6.5. I used NetBeans 4 years ago for a little Java programming while getting my Master's degree and since they recently added PHP support and have a thriving development community, thought it would be a good time to give it a try again. IFirst, I need to get Java 6, so I used Add/Remove..., selected Show All Available Options and searched for Sun Java, and installed it.


Install Java 6

Next, I downloaded the PHP only version of NetBeans 6.5, issued "chmod +x ./netbeans-6.5-ml-php-linux.sh" to make the file executable, and then issued "bash ./netbeans-6.5-ml-php-linux.sh" to begin the installation (of course I could have right clicked on the file, selected properties and changed the permissions that way...). The installation screen popped up and sat there blank. Oh boy... I issued "java -version" and it came back with 1.5.0_11, instead of 1.6.0_10. In the far reaches of my brain, I remembered installing Sun Java before it was available in the repos, and manually overriding Ubuntu to use that. So I had to make sure I was using the latest version, and issued "sudo update-alternatives --config java" :


default version of Java

I swtiched to the newer version, and was able to install NetBeans 6.5. Looking forward to testing it out!



Posted In: PHP, Ubuntu | No Comments

Pass multi-dimensional array in ajax request with jQuery


I have a bunch of javascript objects flying around page that interacts with Google Maps, and I wanted to get the data out of some of the objects to pass via a jQery AJAX $.post call to a PHP script. jQuery seems to have everything, so I was surprised there wasn't any functionality built in to do this (at least as far as I am aware of). I found JSON stringify, which may come in very handy in the future, but seemed like overkill for this particular instance, as I needed a very limited set of data. Below is the code I came up with. My object lineM has an array of Line objects (lineM.lines), and I added a method getWaypoints to the Line object prototype (this method returns a regular javascript array). Then it's just a matter of creating an object literal, and adding properties with "[]" appended to the property name.

var params = {};
for(var i = 0; i < lineM.lines.length;i++) {
params['line'+i+'[]']=lineM.lines[i].getWaypoints();
}
$.post('/test.php',params,function(data) {
$("#ieTest").text(data);
});


When I spit out the results in PHP, I get :

Array ( [line0] => Array ( [0] => 47.399458084,-121.393484585 [1] => 47.405251153,-121.395479813 [2] => 47.412148202,-121.397021664 [3] => 47.419077186,-121.395984907 [4] => 47.422244288,-121.387493955 [5] => 47.427556822,-121.382973259 [6] => 47.431650627,-121.383301159 [7] => 47.433441086,-121.382011855 [8] => 47.432344733,-121.381145837 [9] => 47.431196412,-121.37981873 ) [line1] => Array ( [0] => 47.457933301545786,-121.42310857772827 [1] => 47.46124106812506,-121.41435384750366 [2] => 47.46318500928391,-121.40516996383667 [3] => 47.45874575472201,-121.40710115432739 [4] => 47.458716738753324,-121.41165018081665 ) [line2] => Array ( [0] => 47.45471721756243,-121.42242193222046 [1] => 47.45404979509893,-121.41409635543823 [2] => 47.4578510880274,-121.41624212265015 [3] => 47.45634221074817,-121.40671491622925 [4] => 47.459766139142666,-121.40469789505005 ) )

Posted In: PHP, JavaScript | 3 comments

Format a MySQL date in PHP


I was looking through some very old code of mine and saw the hoops I jumped through to format a MySQL date field into something a little more friendly. It wasn't pretty, involving explode() among other things. Being more familiar with PHP now, I thought it would be nice to post a snippet of code. It takes a start date and an end date and returns just one date (in the format you specify per PHP date format, or a default one if you don't pass in the parameter) if the dates are the same, or the two dates with a dash in between if they are different. Nothing crazy here, and it could be improved by say adding an optional parameter to determine the separator when the dates don't match, or allowing the end date to be null, etc.. I think this will work in PHP4 too.

[php]
function mysqlDateFormat($startDate,$endDate,$format = 'M jS')
{
if($startDate == $endDate) {
return date($format,strtotime($startDate));
}
return date($format,strtotime($startDate)) . ' - ' . date($format,strtotime($startDate));;
}
[/php]

Posted In: Uncategorized, PHP | No Comments

Zend_Acl, jQuery and HTTP Status Codes


In my controllers, I use Zend_Acl to check whether or not a user is allowed to perform an action (i.e. should the code in the method be executed). I also have to check permissions once in a method, as someone might be trying to access an object that does not belong to them - i.e. edit a blog post of someone else. In that case, I was forwarding to a method in the Error controller and adding a 403 to denote that the user could not access the page, as well as displaying a generic page saying the user does not have the proper permissions :
[php]
$this->getResponse()->setRawHeader('HTTP/1.1 403 Forbidden');
[/php]

I am using jQuery with AJAX to run methods on occasion, and whenever returning a 403, my jQuery callbacks never executed : $.post('/tripreport/admintr/saveroute',doThis);. In reading the jQuery documentation, I need to use the $.ajax function instead of $.post : $.ajax({type:"POST",url:"/tripreport/admintr/saveroute",error:handleError,success:handleSuccess});. In the handleError function, I can test whether or not the status code is a 403, and then take the appropriate action : XMLHttpRequest.status == '403'.

On a related note, if you are using $this->_forward in your methods in the Action Controllers like I mentioned above, be sure to use "return" right after, if you don't want to execute any more code in that method.

Posted In: PHP, JavaScript, Zend Framework | No Comments

Throw Exceptions


I pushed some changes out from my development server to my production server and ran into an issue with uploading/moving/resizing photos. It only took about 15 to 20 minutes to track down the issue, but it would have been a lot quicker if I hadn't been sloppy with my code. In using the Zend Framework a lot, I have really grown to rely on Exceptions being thrown. It really helps track down issues, as you can look through the stack and determine rather quickly and with a fair amount of accuracy where the true problem lies.

In my case, I had a class in my models directory that was creating a folder to store pictures. I wasn't checking if the folder was created, and when Zend_File_Transfer_Adapter_Http went to move the file from the /tmp directory to the target directory, it threw an exception. But since I didn't throw an exception when the folder was not created, I started troubleshooting by looking at the Zend Class and trying to determine why it wouldn't move the file on the production server, but would on the development server. I have since updated my model class to throw an Exception when it can't create the folder. I altered the permissions and tried it out on my development box, and viola, the Exception was thrown and displayed on screen (would log on prod site), making it very quick and easy to determine what the problem was.

Lesson learned. When you rely on certain actions to be taken, check if they succeed and throw an Exception if they don't. Now if I could get rid of all my other sloppy coding habits...

Posted In: PHP, Zend Framework | No Comments

Installing Imagick for PHP on Ubuntu through PECL


I need to work with editing some images programatically and have always favored ImageMagick over GD (to be fair, I haven't used GD in at least 3 years). In the past, I used php to pipe commands to the command line via exec(), which never felt right. I remember seeing some development work on an extension on planet-php.com, and after some searching landed on the Imagick extension for PHP. I tried to install is via sudo pecl install imagick , but ran into errors when I tried to find MagickWand-config, which I think is basically the API for PHP to ImageMagick. Reading the comments on php.net, and I was able to install it. Apparently I was missing libmagick9-dev. I didn't need to add the imagemagick.so, as the ini file was already in /etc/php5/apache2/conf.d.

Now I just have to familiarize myself with the class (And it is a class, not just some functions :)).One of the authors of the extension, Mikko, has some great tutorials on his blog. Just need to get some free time to read and play with it. But this is much better than building a huge command to execute via exec()!

Posted In: PHP, Ubuntu | No Comments

Technorati API Down?



I have been working with a couple of web services lately (see prior post on Zend framework and Gdata), and upon deploying my application found out the technorati part of my site wasn't working. I ran my unit tests, and multiple errors occured, saying the script wasn't able to connect to the url:

Fatal error: Uncaught exception 'Zend_Http_Client_Adapter_Exception' with message 'Unable to Connect to tcp://api.technorati.com:80. Error #110:
Connection timed out'

This happened last night, and again this morning. I tried to access the API straight through the browser (http://api.technorati.com/search?key=[apikey]&query=[words]), and the service is unavailable. So fairly sure it isn't a result of the Zend Framework or my code. Can't find any info on the web, so not sure what is going on... I'll have to check in another day or two and see if it is back up or any other info is available.

Posted In: PHP, Zend Framework | 1 comment

Zend Framework and Youtube API



I have been messing around with the different Zend_Service components available in the framework, and in general am very pleased with the ease of use and functionality. However, Zend_Gdata seems somewhat complicated. Now I must admit that I have not spent much time with classes, and I am sure the structure is set up to accommodate the large amount of services that Google provides, but there is very little documentation and the API doesn't seem easily comprehensible, atleast compared to the Yahoo and Technorati APIs.

It appears that Google staff wrote the code, and I guess that is why it breaks with the naming convention - i.e. all the other Services fall under Zend_Services_***, while Google's is Zend_Gdata. I am interested in the Youtube API, and it was easy to construct the query and get the result set back, but I found the result set to contain a lot of information (most of which was extraneous from my point of view), with many classes in it. Again, I was quickly trying to get it working and not at all interested in spending a lot of time learning the ins and outs of Google's API's. I am sure it will all click as I learn the other parts of Zend_Gdata, but for now, it is a pain.

For example, using the code from the documentation, when you grab a result set and iterate through it, how do you grab the src for the flash movie? Digging through the code, I found it was $videoEntry->mediaGroup->content[0]->getUrl(). That's not to difficult, but then I noticed some of the results didn't have any data for $videoEntry->mediaGroup->content. Is that a fluke, or by design? What do the values in the content object mean? I can guess what isDefault means and most of them are obvious, but the comments in the code are completely worthless (well not completely, as it does tell me that the channels property of the MediaContent object is a integer...). What's the deal with the array of values - is the first value in the thumbnail array the preferable image, or just the first frame from the movie? I tried looking at the Google API docs, but that surprisingly didn't seem to shed much light either.

I guess I should get off my ass, learn the API and contribute to the documentation. But its just so much easier to complain. Anyways, here is what I have quickly worked out. Once I start playing with the other Google services and have a better understanding of how all the classes fit together, I'll let you know...

[php]
$yt = new Zend_Gdata_YouTube();
$query = $yt->newVideoQuery();
$query->videoQuery = 'cat';
$query->startIndex = 10;
$query->maxResults = 20;
$query->orderBy = 'viewCount';

echo $query->queryUrl . "\n";
$videoFeed = $yt->getVideoFeed($query);

foreach ($videoFeed as $videoEntry) {
echo "---------VIDEO----------\n";
echo "Title: " . $videoEntry->mediaGroup->title->text . "\n";
echo "Description:" . $videoEntry->mediaGroup->description->text . "\n";
echo "Url to the Youtube page: " . $videoEntry->mediaGroup->player[0]->getUrl() . "\n";
echo "Thumbnail image of the video: " . $videoEntry->mediaGroup->thumbnail[0]->getUrl() . "\n";
if(!empty($videoEntry->mediaGroup->content[0])) {
echo "Src to the video : " . $videoEntry->mediaGroup->content[0]->getUrl() . "\n";
}
echo "\n\n\n";
}
[/php]

Posted In: PHP, Zend Framework | 5 comments

Book Review : Zend Framework in Action



I signed up for the Manning early access program for Zend Framework in Action to get information on the ACL functionality in the framework and the book provided some useful examples. I was a bit underwhelmed by the content in the first release, but I guess that is to be expected when viewing a rough cut.

This release (the 2nd) is a vast improvement, and the book is really starting to come together. I like how the authors go into detail about testing, showing not only how to test your models, but also how to test controllers, and showing some common set up steps. It doesn’t cover all the details of testing, nor should it, but the book provides a solid background to build upon. This is refreshing compared to most books which simply mention testing and say whole books have been written about it.

The book does a good job of logically building upon previous examples, and I felt the flow was good when introducing more complex topics like Plugins and ActionHelpers. This version was updated to include Zend_Layout, including info on partials and ActionStack plugin, but the chapter on forms is not complete yet – looking forward to reading that when it comes out.

I thought the AJAX chapter was a little shaky. Maybe it’s me, but I felt the authors spent too much time going over a general ajax request sans the framework. By the time they work the framework into the equation, they are using an include file in a controller action to bring in some procedural code written earlier. And that procedural code lives in the models folder – it just doesn’t seem right to me. I think this would have been a good opportunity to use Zend_Filter, although it is used in later in the book when discussing Zend_Search_Lucene (the chapter on this is very thorough and easy to understand). Also, they recommend using separate controllers/actions for Ajax requests and not rendering the view in each action method. That’s fine, but I would also like to have seen using a Plugin in the dispatch loop to detect an Ajax request and automatically turn off Zend_View/Zend_Layout.

I like how the authors occasionally work in design patters, such as the registry, and the observer pattern in the search chapter. The authors describe using the observer pattern with hooks in the DB class (hooks which I didn’t know existed) to update the search index.

The chapter on deployment was good; most books don’t seem to tackle this. My only quibble is when discussing setting up virtual hosts, they say to make sure to enable AllowOverride to use .htaccess. I don’t have any problem with this, but since the book is talking about Virtual Hosts, they should recommend putting the redirects in the httpd.conf file, rather than relying on .htaccess, as it is more efficient due to the fact that Apache doesn’t need to read a file on every request.

At times I felt like there may be too much ancillary topics covered, however, after finishing the book, I felt overall it was good that topics such as testing, deployment, and version control were covered. While there isn’t enough information to provide in depth coverage, it exposures the reader to these topics and provides enough information to get started, rather than just briefly mentioning it. And the coverage of the different components with the Zend Framework is comprehensive and understandable. If you are looking at working with the Zend Framework, I would definitely recommend this book.

Posted In: PHP, Book Review, Zend Framework | 2 comments

Loading Zend Config file for a Cron Job

The other day I talked about using Apache Environment variables to determine which section of a config file to use for a Zend Framework website. That works swimmingly, however, I had a cron job that was running for the same site, and since it was piped directly to php, Apache Environment variables were not an option. Fortunately, PHP has the function php_uname('n') which will output the hostname of the computer. You can then load the appropriate config section based on that:

[php]
$environment = (php_uname('n') == 'rlbolton-desktop') ? 'development' : 'production';
$config = new Zend_Config_Ini(APP_PATH . 'configs/config.ini', $environment);
[/php]

Posted In: PHP, Zend Framework | No Comments

Traits for PHP

Via blog, found a link to a proposal for Traits in PHP. I wasn't familiar with the practice, but as I read the proposal it struck a cord with me. I have been grappling with how to reuse certain functionality throughout disparate classes.

I looked at Mixins, which I also have been playing around with in JavaScript. Problem is, how do you combine a couple of mixins together. Say I am using the Zend Framework, and I have some classes that inherit from the Zend_Db_Table_Row and I want a couple to use some Mixin classes. Do I extend the Zend class for my Mixin, and extend my other classes off the Mixin? What happens if some of the classes need other functionality found in a different Mixin? Needless to say, it doesn't seem like a great solution.

Lets jump into an example. I have a number of classes extending Zend_Db_Table_Row, and they all have a user entered attribute, like title or name, which gets turned into a SEO friendly url and saved to the database. Additionally, I don't want the url to change, so there has to be code from preventing another developer from updating the url.For example,
[php]
class Article extends Zend_Db_Table_Row
{
public function insert() {
$this->url = $this->_createUrl();
parent::insert()
}

protected function _createUrl($name) {
//code to create the url - remove spaces, etc...
return $url
}
}
[/php]
How do I share that functionality across multiple classes, without using inheritance??

Posted In: PHP, Zend Framework | No Comments

State of Performance Optimization of PHP


I have seen a number of articles popping up over the last couple of months detailing performance optimization for PHP. There seemed to be a spurt of articles two or three years ago covering the same topic. However, back then, the articles dealt with trivial (in my opinion) practices, such as not enclosing variables in double parentheses or not putting count($array) in a for loop, since it is counted each time. Ahhh, PHP is growing up....

Posted In: PHP | No Comments

Order By On findManyToManyRowset method for Zend Framework

Select statements (via Zend_Db_Table_Select) can now be passed into the findManyToManyRowset method of Zend_Db_Table_Row_Abstract. In ZF 1.0, I couldn't order my result sets coming back from MySQL, which was a pain. Now, I can use the following code, where $m is a Row object:

[php]
$select = $m->select()->order(array('startDate DESC','endDate ASC'));
$tripreportRowset = $m->findManyToManyRowset('Tripreport', 'TripreportMountain',NULL,NULL,$select);
[/php]

If you don't need to order by multiple columns, then don't pass an array...

Posted In: PHP, Zend Framework | 2 comments

Deploying the Zend Framework with Apache Environment Variables



I have recently set up my development environment in a way that mimics my production environment as closely as possible, which is easy even though I develop on Kubuntu and deploy on centOS. For example, I utulize the exact same directory structure and I make use of php.ini file for settings specific to dev, like displaying errors instead of logging them to a file. Additionally, Zend_Config is a nice place to store stuff that may differ, such as displaying placeholders for ads and throwing exceptions in a dev environment.

The one thing I hadn't worked out, was calling the appropriate section of the config file. In my bootsrap file, I had previously used:
$config = new Zend_Config_Ini(APP_PATH . 'configs/config.ini', 'development');
I didn't update the bootstrap very often and when I did, I had to remember to change 'development' to 'production'. I am also running small sites, so a small amount of down time caused by a mess up really doesn't matter.

But I have started working with rsync to deploy my site out to production, and didn't want to have to deal with hand editing the bootstrap every time a change was made. Enter Apache Environment Variables, which allow you to set variables in apache that are available to PHP. in my configuration file specific to one of my dev websites, I put in: SetEnv DEV_ENVIRONMENT development, while in the production server I have SetEnv DEV_ENVIRONMENT production. Now my bootstrap file has a config call like:
$environment = getenv('DEV_ENVIRONMENT');
$config = new Zend_Config_Ini(APP_PATH . 'configs/config.ini', $environment);

Now I don't have to worry about hand editing my bootstrap when I upload a new copy. I think you can put the SetEnv in an .htaccess file if you can't access the main apache configuration file. I just have to learn rsync a little better, and then I will have a nice deployment process, combing Zend Studio for Eclipse, subversion and rsync.

Posted In: PHP, Apache | No Comments

Saving time on code





I attended a course from Net Objectives for work. The focus of the course was on lean development from a managerial and non-technical perspective. The course was very interesting and one anecdote I took away up really struck a chord with me. He asked how long we thought it would take to type the code for a development project that took 6 months to complete. In other words, if you were given the source code for a project that took 6 months to do, how long would it take you to re-type that exact same code? Obviously, it wouldn’t take very long, most likely under a month.

The purpose of this question of course is to show how little time is actually spent typing, and therefore, shortcuts that seem to save time are mostly pointless. Typing $bal, instead of $bankAccountBalance may seem like a good idea at the time, but it really doesn’t save you time over the long run. Code formatting, intention revealing names and inline documentation take a little extra time, but on the grand scheme of things, probably add negligible time to the project and may in fact decrease the time as you go back and refactor the code at later stages in the project.

Posted In: PHP | No Comments

Zend Framework Cache and Empty Arrays

I remember the days when I was learning PHP and small problems would take inordinate amounts of time to figure out. Luckily, those days are long gone. I still make stupid mistakes, but I have learned systematically approach the problem and typically can resolve it fairly quickly. An example of a stupid mistake - I forgot that an empty array in PHP evaluates to false with the equal comparison.

I was caching some data using Flickr, Technorati and YouTube's API's and Zend Framework's Caching Classes. I was taking the resulting XML and turning into an array, and caching the array. If there was no data, I was caching an empty array – that way a foreach loop would not complain, as is the case if you return an empty string instead of any empty array. Copying the code from the Zend manual, it evaluates the cached data with the standard equal comparison:


if(!$result = $cache->load('myresult'))

Since there was an empty array, it was evaluating to false and re-querying the API. The equal comparison on an empty array, '==', evaluates to false (which makes sense), while the identical comparison, “===”, evaluates to true.

Posted In: PHP | No Comments

Installing Eclipse, PDT & Subclipse on Ubuntu

I already had Eclipse installed, so I decided to install all the dependencies and then install PDT. Ben Ramsey has put together a nice list of urls. After getting all the deps installed through Eclipse, I installed PDT and started a new project. I quickly ran into some problems – the PHP Explorer was not working and sometimes the auto complete would fail to work.

I'm not sure what was causing the problems (I have Sun's Java installed, as I know other versions of the Java VM can cause problems), but I un-installed Eclipse through apt-get and downloaded the PDT all-in-one package. I unzipped the file, fired up Eclipse, and it worked fine.

Next on my list was Subclipse. Installing it was a breeze. It took a little while to figure out how to use it, but I was able to connect to the repository on my dev server and checkout a project in a short amount of time. After making a token change, I attempted to commit the changed file back to the repo, That's where the fun started. I kept getting various error messages about “Option Expected” in the svnserve.conf. I changed the svnserve.conf numerous times to no avail. After almost an hour, I finally figured out the problem. I was uncommenting the lines in svnserve.conf and NOT removing the extra whitespace before the declaration. I finally removed the whitespace and viola, it worked...

Posted In: PHP, Ubuntu | 2 comments

Installing PEAR for PHP 5.2 on Windows

For windows installations of PHP, PEAR does NOT come installed. Reading through the documentation, it looks like you can just click go-pear batch file in the directory where PHP is installed. However, I have come across errors with this both times I have tried to use it. The method I found successful is to open a windows command prompt and move into the directory where php is installed (that's assuming you know the change directory command "cd" to move through directories).



Once there, issue "php -r "readfile('http://pear.php.net/go-pear');" > go-pear" to grab the latest instructions and save the file to go-pear. Then, issue "php go-pear" to install PEAR on your windows box. It will ask you a series of questions, which should be fairly easy to answer. Finally, it will create a file in your php directory to update your environment variables. Double click on this file to add PEAR to your path, and you can start using it!

Posted In: PHP | 3 comments

Preventing Contact Form Spam with PHP

Gone are the days of posting email addresses on websites with “mailto:” for spiders to pick up. I typically use a contact form instead, or sometimes encode the email address with special characters. But a new problem has arisen with forms – form spam. From what I can tell, almost all of the spam appears to be from automatic programs trying to obtain links, i.e comment spam.



The messages typically have some random text with copious amounts href or [url] tags sprinkled in. What I have come up with is pretty simple, and could easily be defeated with a little ingenuity. However, it seems to do the trick in stopping the vast majority of contact form spam.

Since I am dealing with contact forms, I don’t expect any tags to be submitted through the form. I suppose it is possible someone would have a legitimate reason to submit a tag, but I haven’t seen it happen yet. Therefore, I check each field to see if any href or [url] tags exist. I also delineate fields that should be one line, like email and name, versus fields that can contain multiple lines, like a comment text box. I have noticed the spammers typically use new line characters, and then insert the link payload. A normal person would not have newline characters in an input textbox – so I don’t allow a form to go through if contains them. Enough of the talk, here is the code. It is for a simple form with two text inputs, email and name, and textarea, comments:

[php]
$singleLine = array("\\n","[url=","href=");
$singleFields = array("name","email");
$multiLine = array("[url=","href=");

foreach($singleLine as $needle) {
foreach($singleFields as $field) {
if(strpos($_POST[$field],$needle) !== false) {
echo 'There was a problem sending your email, please try again';
exit();
}
}
}

foreach($multiLine as $needle) {
if(strpos($_POST['comments'],$needle) !== false) {
echo 'There was a problem sending your email, please try again';
exit();
}
}
[/php]

It isn’t very sophisticated, but it seems to work…. One other thing, checking for the newline characters in general is good practice, especially for the email address. If you use php’s mail function, and put an unfiltered email address in the header, you are opening yourself up to email injection problems (where spammers use new line characters to add cc: and bcc: recipients to your email).

Happy spam blocking!

Posted In: PHP | 2 comments

Regular Expressions, PHP and Newline Characters

Ahhhh, regular expressions. They are so handy, but can be such a pain in the ass to use. While coding up a basic script to do a small amount of screen scraping, I remembered a problem I encountered a couple of years ago; one that I was unable to solve at the time. It involves using regular expressions to match data in a string with newline characters. For the initiated, newline characters ("\n" on *NIX) create multiple lines . I.E., the newline character tells the browser or software program to begin a new line. In PHP, you can use echo "\n" to create a new line in the browser output (would not be viewable on the screen, only when viewing source), which can be handy when you are iterating through an array and spewing out lots of data to the screen.

Back to the problem at hand! if you are using PHP's PCRE (Perl Compatible Regular Expressions - i.e. preg_match) to match text, you need to realize that the pattern will only match on a single line, even if you pass in a string that contains many lines.
<?php
$string 
"<div>\\n<b>This is the second line</b>\\n</div>";
echo 
$string;
?>

The above code shows this. If you look at your browser, you will see the bold text. If you view source, you will see separate three lines.
<?php
$string 
"<div>\\n<b>This is the second line</b>\\n</div>";
preg_match('|<div>.*</div>|',$string,$matches);
print_r($matches);
?>


If we try to match the entire div like the code above, it fails and outputs an empty array. This is because the regular expression is only looking at the first line in the string, and therefore does not see the div closed out in the third line.
<?php
$string 
"<div>\\n<b>This is the second line</b>\\n</div>";
preg_match('|<div>.*</div>|s',$string,$matches);
print_r($matches);
?>

The code above adds a trailing option. There are a variety of trailing options available, but the "s" above (at the end of the pattern) tells the regular expression to make periods match any character, including newline. Now, $matches[0] contains the code for the entire div.

Posted In: PHP, regular expressions | 15 comments

Zend Framework 0.2, Incubator, RewriteRouter and FontController

After time away from the Zend Framework, I dove back in yesterday to play around with 0.2 version. I decided to use the incubator, as there as some fairly significant changes in the works, and I wanted to see what was in store for later releases. By setting your include path to check the incubator directory first in your index.php file, you can make use of the newer classes:
[php]
set_include_path('/__shared/incubator/library' . PATH_SEPARATOR . '/__shared/lib');
[/php]



I copied over the general structure from another site that was using v0.1.5 and immediately ran into problems with the controller. Using the incubator means I can't rely on the manual, so I searched through some emails from the Zend mailing list and found some new code instantiating the FrontController and RewriteRouter (FYI - the emails are archived, and this is an extremely useful resource to search if you are having trouble and can't find the answers in the manual).

I hadn't used the RewriteRouter before and I must say it is nice. Before, I was employing hackish code to simplify my urls, like
[php]
//for url www.example.com/article/view/article-about-zend
$params = $this->_getAllParams();
$url = key($params); //$url is now 'article-about-zend'
[/php]

Now, I can use the RewriteRouter in index.php to simplify my urls and code:
[php]
//for url www.example.com/article/article-about-zend
$router = new Zend_Controller_RewriteRouter();
$article = new Zend_Controller_Router_Route(
"article/:url",
array( "url" => null,
"controller"=>"article",
"action"=>"view"
)
);
$router->addRoute("article",$article);
[/php]

And in my controller method (article controller, view method per the code above), grabbing the params is easy, because the ":url" sets it up:

[php]
$url = $this->_getParam('url');
[/php]

I still have some questions about the RewriteRouter, but I'm sure I'll figure them out as I continue to use it. There are a bunch of other neat classes I am playing with right now, like the caching and logging. I am really impressed with the framework so far and look forward to using other parts of it!

Posted In: PHP | No Comments

MSN SOAP Error in PHP Version Less Than 5.1.4?

Awhile back, I copied a script from IBM's website that used MSN, Yahoo and Google's API to fetch search results and store them in a database. Much to my chagrin, after tweaking the script to accommodate my needs, I found that I couldn't get MSN to return more than 10 results. I spent over an hour trying to figure whether it was a problem I had induced while making my changes. I finally gave up, as it was a side project and not that important. I couldn't find anything on PHP Bugs site and this anomaly occurred on both Windows and Linux, both running PHP <5.1 with SOAP enabled.

Recently, I leased a new dedicated server and have PHP 5.1.4 running on CentOS and the problem has disappeared. I am using the exact same code, so all I can assume is that versions prior to 5.1.4 (could be a lower release will work, but I know for sure 5.1.4 works) have a bug in the SOAP implementation that fails to get the correct number of results for MSN.

Posted In: PHP | No Comments

A New Use of Sleep() in PHP

I have been working on a website that allows photo uploading and manipulation via a web interface. The webpage uses a hidden iframe so that uploading can take place without refreshing the page and AJAX that allows users to rotate and delete photos, again without refreshing the page. I am developing the application on my linux desktop and I thought it would be useful to simulate delays and normal response times if the application where on the internet, hence the use of the sleep function.

Nothing too spectacular here, but it is useful to throw sleep(10) into all your methods on the controller and see what happens. I found I had forgot to provide any user notification on delete of a photo. If the request was processed fast, as it always was on my desktop and usually was live on the internet, it wasn’t a problem because the JavaScript removed the photo. But if the request took 5 seconds to delete the photo, then the user would site there for 5 seconds wondering what was going on. Worse, they may hit the delete link again, causing another request to be sent, running a method to delete a possibly non-existent image. I guess the more I get used to AJAX and its idiosyncrasies, the less need I will have for this. But for now, it is a useful way to quickly simulate lag time on your desktop and ensure you are providing proper user notification.

On a different note, this application quickly became complex. I have wrapped all my JavaScript code into nice functions, but I was left wondering how I can better organize my code? Obviously using objects would help, and I need to become more familiar with JavaScript objects (It doesn’t seem worth the effort to just wrap the functions in an object). I was also left wondering what is the best way to organize code when your application becomes complex. Is the MVC paradigm somehow malleable to client side code? Something I need to investigate further….

Posted In: PHP, JavaScript | No Comments

The PHP Job Market

For the past couple of years, I have actively looked at seattle.craigslist.org's internet engineers and web /info design job postings. I have noticed a slow but steady increase in the number of postings for PHP jobs. I must mention that I think there are more job postings in general, but the ratio of job postings to job postings for PHP programmers appears to be on the rise. This seems especially true in the last couple of months.





You see, in the hometown of Microsoft, a job posting with the title of "web Developer" on seattle.craigslist.org used to be synonomous with an ASP/.NET developer. If you were looking for a PHP developer, you put it in the title... But this fact of life isn't holding true anymore. Admittedly, a lot of the new job postings seem to be for "the next big" web 2.0 start-ups, but there are also a good deal of PHP jobs for established companies. And the pay for most of the jobs is reasonable. Too bad I have my own company and am not looking for employment anymore. I never seem to time things right...

Posted In: PHP | No Comments

SEO Friendly URL's with PHP

I had to come up with a quick little snippet of code to create some SEO friendly urls for dynamic content. What constitutes a SEO friendly url? Basically, just a url with a bunch of words and dashes, nothing to scientific about that. But it does make sense, as the url of this page will have a better chance of ranking well than a corresponding url of www.robertlbolton.com/articleId=21.

I could have hunted through Word Press’s code to find what they use, but I figured it would be quicker to just write it myself. I was trying to get away with using just one regular expression, but couldn’t make it happen. Without further ado,

$temp = “This blog is really lame, and I mean lame!”;
$temp = preg_replace('/(\W){1,}/','-',$temp);
$temp = preg_replace('/-$/','',$temp);
echo $temp;


Here is the regular expression breakdown:

'/
(\W) //match any non-word character
{1,} //match it one or more times (greedy matching)
/'


The second regular expression takes care of the trailing dash at the end that results when the string has spaces or non-word characters like exclamation points at the end. I think you could use a lookahead in the first reg exp to detect the end of the word and then not add a dash, but that is above my head.

Posted In: PHP, regular expressions | 4 comments

Setting up Fedora Core 5 for Zend Framework

I installed Apache and MySQL through yum without a hitch and decided I needed to compile my own version of PHP 5. I ran into some problems compiling PHP5, but after resolving those, I had a working LAMP platform. The way ZF is currently set up, it really only works from the root directory of a site (you can use modified controller to get around this), although they are going to change the controller structure so it works in sub-directories in future releases. I have two different sites I want to build using ZF, so I decided to edit my /etc/hosts file to tell my computer to look at itself for two domains:

www.bolton.com localhost
www.tripvera.com localhost



Fedora checks /etc/hosts first when a domain is requested, so a matching line here will prevent it from querying a DNS server and allows you set up any domain you want, even if you don’t own it. You can also use the GUI in System->Administration->Network to add the same entry.
Now I had to modify httpd.conf (use “locate httpd.conf” if you are unsure where yours is) and I uncommented the virtual hosting line in the file, added the virtual directory and placed the mod_rewrite rules into the virtual host, rather than using an .htaccess file in the directory:


ServerAdmin your@email.com
DocumentRoot /var/www/html/bolton
ServerName www.bolton.com
ErrorLog logs/bolton.com-error_log
CustomLog logs/bolton.com-access_log common

RewriteEngine on
RewriteRule !\.(js|ico|gif|jpg|png|css)$ index.php
AllowOverride All



Make sure to restart Apache to have the changes to httpd.conf take effect. Finally, I created a new file called .vimrc in my home directory and added “:set tabstop=4”. This is a config file vi opens whenever it is loaded and that command sets the tabs to 4 spaces, which is the recommended amount by ZF. Vi defaults 8 spaces, which I think it way too much and I use vi a lot for coding. I have been playing around with Eclipse, but that is a topic for another posting…

Posted In: PHP, Linux, Fedora Core 5 | 2 comments

Credit Card Validation In PHP With Regular Expressions

I had to do some credit card validation in both JavaScript and PHP recently. Looking around the net, I found some decent information but no scripts that fit the business rules I was given. There are a lot of different ways to approach validating a credit card. You can go with the loose rule of making sure it is only numbers and between 15 and 16 characters (or only numbers if you are accepting a wide array of cards). You can make the user select the card, and then make sure the number matches a regular expression for that type of card. That is basically what I did:
$credit_card holds the type of card the user selected, and $cc_number has the credit card number the user entered. It then runs a switch statement to assign a regular expression based on the card, and has a default of 15 to 16 digits if there is no card match.

[php]
switch($credit_card) {
case 'AMEX':
$goodCC = '/^3[47]{1}[0-9]{13}$/';
break;
case 'Visa':
$goodCC = '/^4[0-9]{15}$/';
break;
case 'Mastercard':
$goodCC = '/^5[1-5]{1}[0-9]{14}$/';
break;
case 'Discover':
$goodCC = '/^6011[0-9]{12}$/';
break;
default:
$goodCC = '/^[0-9]{15,16}$/';
}
if (!preg_match($goodCC,$cc_number)) {
$errors = 'Your credit card number does not seem to match the card type you selected';
}
[/php]

Posted In: PHP, regular expressions | No Comments

Buzz Game

I signed up for Yahoo and O’Reilly’s Buzz Game. It simulates the stock market, except you are buying shares for high tech products, ideas and trends. I guess they want to see if searche trends and buzz can be predicted by people. I know large multinational companies allow their employees to trade stock in products and or ideas and they are able to predict with good accuracy which ones will fail and succeed.

Anyways, I am up almost a percent today. Put most of my money into PHP. Hopefully there will be a lot of buzz created once Zend releases a beta for their framework. Yesterday I listened to PHP Architect’s podcast with Andi Gutmans and he indicated that there would be some initial code released pretty soon for developers to play with. It looks promising, so let’s hope it more substance than buzz!

Posted In: PHP | No Comments

PHP Architect:: Andi Gutman's Talk

I tuned into the webcast, but it was cut short by technical difficulties. Ahhh, technology: you have to love it. Anyways, I was excited to hear about the progress Zend and its collaborators have made. The initial presentation Andi gave whetted my appetite. They had some interesting features in the framework and I liked the fact that they want to keep it simple and target the 20% of code that gets used 80% of the time. You can't incorporate everything into a framework, or else it ends up bloated and worthless.

Today, Andi briefly talked about PHP's main competitor(s), whom he feels is .NET. He also talked about the difference between the Zend Collaboration project and the Zend framework. He said the collaboration encompassed the framework and essentially consisted of three parts:

  1. The aforementioned Framework

  2. Enrich the development tools:: Eclipse IDE

  3. Best Practices:: Enable authors to contribute more content



Hopefully, they will post the complete talk on the site soon so I can hear the rest of what he had to say. Interested to find out when a version will be out.

Posted In: PHP | No Comments