Chris Hope's LAMP Blog - The Electric ToolboxChris Hope's LAMP Blog - The Electric Toolbox

Linux Apache MySQL and PHP articles by Chris Hope

This is Chris Hope's blog for Linux, Apache, MySQL and PHP (known as LAMP) and Javascript/jQuery. "The Electric Toolbox" is the name of my company and I started this website several years ago with articles about web programming, Linux and Windows tips and tricks, howtos etc.

New posts are made every day; read my posting schedule for more details.

The ten most recent articles can be found below in their entirety. Navigating the sections in the right navigation (under Categories) will bring up all the other posts, and you can also use the search box at the top of the page to find what you might be looking for.

Disable textarea resizing for Safari and ChromeDisable textarea resizing for Safari and Chrome

Posted July 4th, 2009 in HTML and CSS

The wbekit based browsers Safari and Google Chrome allow the HTML textarea to be resized by default with a grab handle in the bottom right corner. There may be times when you want to disable this function so a textarea cannot be resized.

Screenshot example of resize grip

The following screenshot shows the resize grip; I've highlighted it with a red circle.

resizeable textarea in webkit based browsers

The user can make the textarea larger but cannot size it back down below the original size.

CSS to disable resizing

The CSS to disable resizing for all textareas looks like this:

textarea {
    resize: none;
}

You could instead just assign it to a single textarea by name (where the textarea HTML is <textarea name="foo">):

textarea[name=foo] {
    resize: none;
}

Or by id (where the textarea HTML is <textarea id="foo">):

#foo {
    resize: none;
}

Validation errors

The above is only supported by the webkit browsers. If you run it through a CSS validator (such as the W3C CSS validator) you'll get a warning like this:

Property resize doesn't exist in CSS level 2.1 but exists in [css3] : none

Count the words in a textarea or input with jQueryCount the words in a textarea or input with jQuery

Posted July 3rd, 2009 in Javascript

This post shows how to get a word count from an HTML textarea or text input using jQuery and display it on the page. The word count is updated as the user types.

Example

Here's a couple of examples. These won't work if you are reading this in a feed reader so you'll need to click through to read this post in a web browser.

The HTML

Here's the HTML form:

<form>

<div id="example1_count" style="display:none"></div>
<textarea id="example1" rows="5" cols="50" class="word_count">a b c</textarea>

<div id="example2_count" style="display:none"></div>
<input id="example2" type="text" size="50" class="word_count" />

</form>

Note that the textarea and input have the class "word_count" and need to have id="...". The area that contains the word count is the same id plus "_count". The divs containing the count are initially hidden (this would be better defined in a style sheet) and are made visible by the initialization code.

The jQuery / Javascript

When the document is ready all inputs with class word_count have an initial word count done to them and the word_count() function is bound to the keyup event. I tried this with the change event but that only fires when the user clicks/tabs out of the field.

$(document).ready(function() {

    $('.word_count').each(function() {
        var input = '#' + this.id;
        var count = input + '_count';
        $(count).show();
        word_count(input, count);
        $(this).keyup(function() { word_count(input, count) });
    });

});

function word_count(field, count) {

    var number = 0;
    var matches = $(field).val().match(/\b/g);
    if(matches) {
        number = matches.length/2;
    }
    $(count).text( number + ' word' + (number != 1 ? 's' : '') + ' approx');

}

The word counts seem to be quite accurate using the \b word boundary, although in all browsers I tested .length returns twice the actual number, hence the division by 2.

The result from .match() are returned into a variable instead of just getting .length to prevent Javascripts errors being triggered in the browser if there are no matches.

The only issue I have found is if the user uses their mouse to copy and paste, select and delete, etc then the word count isn't updated. I couldn't find a satisfactory way to fix this.

Browsers tested

I have tested the above code in IE6, IE7, IE8, FF1, FF3.5, Chrome 2. It worked in all of them. I tested with 9000 words generated from lipsum.com and it all worked nicely.

Quarterly Update - April to June 2009Quarterly Update - April to June 2009

Posted July 3rd, 2009 in Monthly Roundup

At the start of this year I outlined some goals for the year for this blog. This included gowing the numbers of monthly pageviews from 60k to 600k and the number of RSS subscribers from 100 to 1000. Now that we're two quarters of the way through the year it's time to have another look and see how it's all going and if I'm on target.

Please note there will be a second on-topic post (a jQuery one to do with counting words in a textarea or input field) later on today.

To achieve a tenfold gain like this requires a 21.15% increase month on month of pageviews and 21.65% month on month growth for RSS subscribers. As shown in the table below I'm getting it right with the RSS subscribers and I think the growth is realistic but I think it pretty unlikely I'll get to the 600k pageviews mark by the end of the year.

Traffic's been growing by around 15k pageviews per month since the start of the year so I've adjusted the "required" column for pageviews to a growth of 15k per month which results in 250k pageviews per month in December. I think this is more realistic.

  Pageviews RSS Subscribers
Month Required Actual Growth Required Actual Growth
December 2008   60,073     95  
January 2009 75,000 75,372 25.5% 116 115 21.1%
February 2009 90,000 90,009 19.4% 141 150 30.4%
March 2009 105,000 108,698 20.8% 172 165 10.0%
April 2009 120,000 114,942 5.74% 209 200 21.2%
May 2009 135,000 141,812 23.38%  254 240  20.0%
June 2009 150,000 158,369 11.68% 309 310 29.2%
July 2009 175,000      376    
August 2009 190,000      457    
September 2009 205,000      556    
October 2009 220,000      676    
November 2009 235,000      822    
December 2009 250,000      1000    

I'll update this again after the third quarter of the year, at the end of September.

Google Analytics Data Export API updates July 1st 2009Google Analytics Data Export API updates July 1st 2009

Posted July 2nd, 2009 in Miscellaneous Postings

Just a quick note for all you Google Analytics API users out there that Google have made some updates to the API. The post on Google Groups can be found here, and I've also copied the information below.

1. Some restrictions on dimension and metric combinations have been relaxed. You can now query most content and visitor level dimensions together, for example ga:pagePath and ga:source is now a valid combination. Please see the updated reference guide for these new combinations: http://code.google.com/apis/analytics/docs/gdata/gdataReferenceDimensionsMetrics.html#explore2Pair

2. The total number of rows that can be asked for in one request has been increased to 10,000. The default is still 1000, but can now be increased by setting the "max-results" query parameter.

3. The Account Feed now returns two new data elements for each table id (currency and timezone)
<dxp:property name='ga:currency' value='USD'/>
<dxp:property name='ga:timezone' value='America/Los_Angeles'/>

4. We're now enforcing that data queries must include at least one valid metric.

5. All previous deprecation changes have taken effect.

End of post from Google Groups.

I will check in the next few days to make sure none of these changes affect my Google Analytics API PHP Class and post any updates if there need to be any. I don't think off the top of my head that anything should need to be changed other than some of the documentation and examples.

Using PHP's glob() function to find files in a directoryUsing PHP's glob() function to find files in a directory

Posted July 2nd, 2009 in PHP

A couple of weeks ago I posted how to read through a directory with PHP using the opendir() readdir() and closedir() functions and now look at the glob() function. glob() returns the filenames into an array and supports pattern matching so it can be very easy to find e.g. jpg images in a particular directory.

Example directory

The examples below look at a directory with the following, the same example directory as used in the read through directory post:

bar.txt       A regular file
baz           A directory
foo.txt       A regular file
link2foo.txt  A symbolic link to foo.txt

Simple example

To find all the files in the directory /path/to/directory with a .txt file extension, you can do this:

$files = glob("/path/to/directory/*.txt");

The $files array contains the following from the example directory:

Array
(
    [0] => /path/to/directory/bar.txt
    [1] => /path/to/directory/foo.txt
    [2] => /path/to/directory/link2foo.txt
)

If no files matched the pattern then the array will be empty.

Example using braces

There are flags which can be passed as a second optional parameter. One of these is GLOB_BRACE which means that e.g. {jpg,gif,png} will be expanded to match jpg, gif and png which can be useful if you need to look for a particular set of files by their extension, in this example for image files.

If the example directory also had the files 1.jpg, 2.gif and 3.png then you can do this to get glob to return just the image files:

$files = glob("/path/to/directory/*.{jpg,gif,png}", GLOB_BRACE);

print_r($files) would echo:

Array
(
    [0] => /path/to/directory/1.jpg
    [1] => /path/to/directory/2.gif
    [2] => /path/to/directory/3.png
)

Further reading

This serves as an introduction to using glob() to find files with PHP. Read the glob manual page for more details and for information about the other flags.

Monthly Roundup - June 2009 - StatisticsMonthly Roundup - June 2009 - Statistics

Posted July 2nd, 2009 in Monthly Roundup

My monthly stats round up posts a summary of the most read posts over the previous month, numbers of visitors to the blog and any changes I have made over the month that may have affected visitor numbers etc. This is the monthly stats roundup for June 2009.

Please note there will be a second post later on today with regular on-topic content.

25 most popular articles in June 2009

The following were the top 25 most accessed articles on this blog in June 2009, along with the original post date. The list is compiled using my PHP Class for the Google Analytics API to get the unique pageviews for posts in the month. Last month's rank is shown in square brackets after the post title, or [-] if it wasn't in the top 25 last month.

Note that unique pageviews means it's only counted once for each visitor so if someone views the page multiple times it's still only counted once for that user. If I sorted by pageviews the list would be slightly different with the Google Analytics API and PHP post in second position because people refer back to that page multiple times.

  1. How to get and set form element values with jQuery [1] (November 13th 2008)
  2. Howto Restart Apache [2] (December 22nd 2004)
  3. Using the HTTP_REFERER variable with PHP [4] (April 18th 2008)
  4. How to check and uncheck a checkbox with jQuery [5] (November 14th 2008)
  5. Delete All Data in a MySQL Table [3] (July 16th 2004)
  6. Setting cookies with jQuery [-] (June 9th 2009)
  7. Cross Table Update with MySQL [7] (March 1st 2004)
  8. Open firewall ports for MSN Messenger and ICQ [8] (February 13th 2004)
  9. Install yum with rpm on CentOS [11] (October 16th 2007)
  10. Windows Vista Black Screen After Login - Resolved [14] (June 26th 2008)
  11. jQuery: show plain text in a password field and then make it a regular password field on focus [-] (June 2nd 2009)
  12. How to check an MD5 hash on a file [9] (January 19th 2004)
  13. The Google Analytics API and PHP: A series [6] (April 28th 2009)
  14. Windows Vista Black Screen After Login [17] (May 29th 2008)
  15. Upper case and lower case strings with MySQL [16] (July 29th 2008)
  16. Formatting Dates and Times with MySQL [13] (July 17th 2004)
  17. Loading content with jQuery AJAX - using a loading image [15] (February 3rd 2009)
  18. Test if a file exists with the BASH shell [19] (August 27th 2008)
  19. Backup/export bookmarks with Mozilla Firefox 3 [22] (June 24th 2008)
  20. The user is not associated with a trusted SQL Server connection [20] (June 21st 2008)
  21. Describe table structure with MS SQL Server [-] (July 23rd 2008)
  22. Create RSA and DSA Keys for SSH [18] (March 5th 2004)
  23. Style an HTML form input with CSS and jQuery [-] (July 26th 2008)
  24. PHP Error Class 'SoapClient' not found [21] (September 25th 2007)
  25. Always show a vertical scrollbar in Firefox, Chrome, Safari and Opera [-] (June 20th 2009)

Visitor numbers

I get the visitor numbers from Google Analytics and saw an increase of 12.9% in visits and 11.7% in pageviews between May and June. The following table shows visits and pageviews for the six months from January 2009 to June 2009.

Month Visits Pageviews PV Per Visit
January 2009 63,176 75,372 1.19
February 2009 74,367 90,009 1.21
March 2009 88,737 108,747 1.23
April 2009 94,083 114,969 1.22
May 2009 114,250 141,812 1.24
June 2009 129,030 158,369 1.23

RSS Subscribers

I use Feedburner/Google to serve my RSS feed and give an indication of visitor numbers. I curently have around 310 RSS subscribers, 70 more than last month.

Changes made this month

I've switched out the ad next to the Google Adsense block for a Buy Sell Ads square and added an advertising block utilising the same service in the right sidebar. If you are interested in advertising here please see my ads page on Buy Sell Ads.

Change the full text index minimum word length with MySQLChange the full text index minimum word length with MySQL

Posted July 1st, 2009 in MySql

The MySQL full text index by default only indexes words which are 4 characters or longer, which means on a blog like mine if you search for "PHP" nothing will be returned. This post shows how to change minimum word length in MySQL so words or 3 characters (or even 2 if you want) can be indexed as well.

Edit the MySQL configuration file my.cnf which is usually located on a *nix box at /etc/my.cnf or /etc/mysql/my.cnf and add the following line under the [mysqld] section to change the default to 3:

ft_min_word_len = 3

If the ft_min_word_len value is already in the file then change the number to the minimum length required.

After making this change the MySQL server must be restarted for it to take effect. It is not possible to change the size with a set query (e.g. "SET ft_min_word_len = 3" which will result in the error "#1193 - Unknown system variable 'ft_min_word_len'").

Now that the minimum word length has changed, and new or updated records will use the new minimum word length, but existing records will not be affected. To rebuild the full text index on a column for an example table called my_table, run this query:

REPAIR TABLE my_table QUICK;

I have seen comments by some people who have suggested that on large tables it may be faster to drop the index and create it again depending on the size, and also that the repairing it may mean the query cache is not flushed whereas dropping and re-indexing will solve this.

Note however that if you drop the index and then re-create it you may get SQL query errors on your website. As always it is advisable to test this sort of thing out on a development server configured in the same way as a production server before doing it to the production server to ensure you don't have any issues.

Monthly Roundup - June 2009 - Post SummaryMonthly Roundup - June 2009 - Post Summary

Posted July 1st, 2009 in Monthly Roundup

At the start of each month I post a complete list of articles posted in the previous month. This is the monthly summary for June 2009. This is followed up on the second day of the month (i.e. tomorrow) with statistics relating to visitor numbers and most popular posts for the previous month.

Please note there will be a second post later on today with regular on-topic content.

The posts made in June 2009 are as follows, broken down into categories. Note that some posts appear in more than one category so appear below more than once.

Apache

Applications

HTML and CSS

Javascript

Miscellaneous Postings

MySql

PHP

VMWare

The second part of this monthly roundup, tomorrow, will look at the most popular posts read on the blog in June and some other stats. The next day will see a quarterly summary to see how my aims to date this year are going.

Advertise on Chris Hope's LAMP BlogAdvertise on Chris Hope's LAMP Blog

Posted June 30th, 2009

I have added some ad spots on my blog through Buy Sell Ads. If you are interested in advertising here please click here to view the advertiser information and statistics on my blog and click here to go through to my listing at Buy Sell Ads to advertise.

Advertiser Information and StatisticsAdvertiser Information and Statistics

Posted June 30th, 2009 (Updated July 4th, 2009)

Advertisers can advertise on my blog in two different positions. The first is 1 of 6 125x125 ad spots in the right sidebar, between the subscription information and the list of categories. This appears on all pages on this blog. The second is a single 300x250 ad spot that appears after the first paragraph on every page (which you can see directly below this paragraph).

This blog is currently getting around 150k+ pagviews per month and is currently getting around 5% to 10% growth each month. The statistics for the last 30 days and last six months are available below. These are automatically updated each day from Google Analytics using my PHP Class for the GA API and do not include my own visits, which are filtered out.

Month Visits Pageviews
Last 30 days133,623163,820
June 2009129,030158,389
May 2009114,250141,812
April 200994,083114,969
March 200988,737108,747
February 200974,36790,009
January 200963,17675,372

If you would like to advertise on my blog please click through here to my listing on Buy Sell Ads.