< Previous | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | Next >

Javascript Error with Mootools, IE 7 and Google Adsense

I use firefox for the vast majority of my web browsing, with IE and Chrome occasionally thrown in. While using IE 7 the other day, I opened up this very site, and to my dismay, discovered a javascript error: Line 89, Object doesn't support this action.


I was surprised, since I tested the site on IE 7 not too long ago and am not using any plugins or 3rd party code (i.e. this isn't a wordpress site). At first, it appeared the Core MooTools was the culprit, as removing that file stopped the error. But that didn't explain why there was no error when I tested it on my development box, which had the MooTools JavaScript included. After a little more head scratching I realized the only difference between the site on my dev box and production box was the fact that I have Google Adsense ads on the live site, but not on the dev site.


Sure enough, removing the ads caused the error to go away. Trying to be a good web developer, I was loading my MooTools scripts at the bottom of the page to prevent locking the browser while rendering the page. When I moved the Core MooTools script into the head tag at the top of the page, the error went away. Not sure the exact details of the problem, but loading MooTools after Google Adsense was causing errors in IE 7...

Posted In: JavaScript | 1 comment

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

Mysql Error 1064 (4200) - Using BTREE

Trying to move a database from my development machine which is running MySQL 5.1.41 on Ubuntu to my server, which is Ubuntu but runs MySQL 5.0.51a and I keep getting an error:
ERROR 1064 (42000) at line 122: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'USING BTREE, KEY `FrtTP_Feature` (`featureId`), CONSTRAINT `FrtTP_Feature` F' at line 4

On my development machine, I can dump and upload the database just fine, but it won't import all the tables to MySQL on my production box. Obviously the differing MySQL versions are causing problems. I searched on the internets, but nothing much useful came up, as that error seems to be used for everything. I'm finding out that MySQL's errors are anything but informative.

After some digging on MySQL's site, I found the syntax USING BTREE has moved to after the key description in versions greater than 5.1. After changing my database dump file, I can now upload all my tables and data to my production server. You would think they would wait until major version numbers to choke on the placement of that syntax.... Below are the changes I made to get 5.1.41 to work with 5.0.51a:
UNIQUE KEY `url_unique` (`url`,`memberId`) USING BTREE becomes UNIQUE KEY `url_unique` USING BTREE (`url`,`memberId`) and
PRIMARY KEY (`memberId`,`tripreportPhotoId`) USING BTREE becomes PRIMARY KEY USING BTREE (`memberId`,`tripreportPhotoId`)

Posted In: mysql | 3 comments

Mysql Error 1005 - Foreign Key Contraint Woes

If you are trying to set up foreign key constraints in MySQL InnoDb table, and run into Error 1005, open up a mysql client on the command line and type show engine innodb status. Then scroll through the output until you reach:
------------------------
LATEST FOREIGN KEY ERROR
------------------------

This will give you more information about the error. The foreign key names have to be unique, so if you use something generic for the name, you may run into issues when setting up constraints on other tables. The other error I have experienced was trying to set the on delete action to set the field null, but null was not allowed on that field.

Posted In: mysql | No Comments

Google Maps v3 Multiple Markers and Infowindows in a Loop

My lack of javascript knowledge is really becoming a pain in the ass. I was trying to add multiple markers and infowindows via Google Maps v3 API, and whichever marker I clicked on, it would always open the infowindow of the last marker. Here is the code I was using:


//photoMarkers is a JavaScript array of objects that PHP spits out to the page, and the script below is from an external javascript file and is contained within a function
for (var i = 0; i < photoMarkers.length; i++) {
var p = photoMarkers[i];
var marker = new google.maps.Marker({position: new google.maps.LatLng(p.latitude, p.longitude), title: p.alt, map: map, draggable: true});
var infowindow = new google.maps.InfoWindow({content: p.content});
google.maps.event.addListener(marker, 'click', function() {
infowindow.open(map, marker);
});
}



I was baffled as to why this didn't work. I am creating new variables on every loop and then passing the marker to the infowindow via a closure. After some searching, I found a solution which worked. But it still didn't explain why this wasn't working. Surely the Google code must be doing something strange in the addListener function, making my life difficult? Some more searching resulted inthis article, explaining why you can't have closures in loops. The closure is using the scope of the function it was created in and not the loop.Therefore each closure is "sharing" the variables, and when the closure is executed, it has a reference to the last marker and infowindow. Shows how little I know about JavaScript.

Another way of dealing with this is to return an anonymous function that acts as a closure from within another function. Now the closure, e.g. the inner function, takes the environment of the outer function on each loop, and it doesn't "share" the scope/environment with the other closures. E.g.


function infoCallback(infowindow, marker) {
return function() {
infowindow.open(map, marker);
};
}

for (var i = 0; i < photoMarkers.length; i++) {
var p = photoMarkers[i];
var marker = new google.maps.Marker({position: new google.maps.LatLng(p.latitude, p.longitude), title: p.alt, map: map, draggable: true});
var infowindow = new google.maps.InfoWindow({content: p.content});
google.maps.event.addListener(marker, 'click', infoCallback(infowindow, marker));
}

Posted In: JavaScript | 9 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

Mocking Objects with Final Methods in PHPUnit

Having some issues with a mock in PHPUnit - the method on the mocked object was being called and the code run (bootstrap method on Zend_Application_Bootstrap_BootstrapAbstract). After some head scratching, I realized it was a final method, so PHPUnit can't override it, and thus, the code is executed. I extended Zend_Application_Bootstrap_BootstrapAbstract and overwrote the code that was cuasing problems (::bootstrap is final, but it calls ::_bootstrap, which you can override).

I 've been meaning to play around with Mockery, but until then, I've come up with some ways to deal with Mocks in PHPUnit (I personally don't think the implementation is too bad, but I'm not a die hard tester...). One of the issues I commonly run into is needing to return mocked objects from a mocked method. This is easy if the method is only called once, but what about if the same method is called a couple of times, and you need to return different mocks (e.g. ::bootstrap($name) will return different objects based on the $name parameter)?

I've used a closure with a callbackValue to get around this:

<?php
        $mapper 
$this->getMock('Bolton_MapperInterface');
        
$relatedMapper $this->getMock('Bolton_MapperInterface');
        
$callback = function($property)  use($mapper$relatedMapper) {
            if (
$property == 'model') {
               return 
$mapper;
            } else if (
$property == 'childModel') {
                return 
$relatedMapper;
            }
            throw new 
Exception(sprintf('Mapper factory mock passed an unexpected parameter (%s)',$property));
        };

        
$this->_mapperFactory->expects($this->any())->method('factory')->will($this->returnCallback($callback));
?>


What about needing to return a different value based on the number of times the method has been called? I'll use a callback function, but then have a static variable in the callback function that keeps track of how many times it has been called. In the test setUp() method, I will reset the static variable, so the function can be used across a number of different tests.

Posted In: Zend Framework | 1 comment

Google Webmaster Tools DNS verification with Slicehost

Google added a new way to verify your site in their Webmaster Tools: through a DNS TXT entry. It took me a couple of tries to figure out how to properly enter it through Slicehost's DNS GUI:

  1. Type: TXT

  2. Name: Enter the FQD name domain that you put in Google Webmaster Tools I.e. for this site, I would use www.robertbolton.com or robertbolton.com, depending on what I entered into Webmaster Tools.
  3. Data: Enter the value provided by Google (i.e. google-site-verification: waRANDbRgWxXfEBMKhl8c1v8fL1kcVvRtPFU-OmN9I1)


To see if it worked, you can use the command line "host -t txt robertbolton.com" and a result should come back. Or just cross your fingers and click the verify button in Google...

Posted In: Google Analytics | 5 comments

Save Nvidia display settings Ubuntu 9.10

I received a new monitor for xmas and wanted to set up dual display (twinview) for Ubuntu 9.10. I already had the proprietary Nvidia drivers install, and it was very easy to get the dual monitors up and running. However, I always got this error when trying to save the configuration: Can't parse /etc/X11/xorg.conf. And upon restarting, only one screen would show and I would have to set it up again.

Even when I launched Nvidia with sudo (sudo nvidia-settings), I still got this error on the command line:

VALIDATION ERROR: Data incomplete in file /etc/X11/xorg.conf.
Undefined Device "(null)" referenced by Screen "Default Screen".

I moved /etc/X11/xorg.conf to a new filename, ran sudo nvidia-settings and was able to save as new xorg.conf file and now I have both monitors on start up. Also looks like you can simply edit the existing xorg.conf file and you will be able to save your settings.

Posted In: Uncategorized, Ubuntu | No Comments

< Previous | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | Next >