Archive for 2010
10
Using the jQuery-UI Autocomplete Widget
1 Comment · Posted by SeanJA in Computer, Databases, Javascript, Open Source, PHP, Plugin, Programming, jQuery
The latest version of jQuery-ui has an autocomplete widget. No more looking for one that will work (you get the point) with the version of jQuery that you have.
All you have to do is pull the latest one down from the jQuery-ui site and you are good to go.
First the jQuery to use the autocomplete plugin:
//we will be using this to cache the responses from the server var ajaxCache = {}; //activate autocomplete on boxes that have the autocomplete class $("input.auto_complete").autocomplete({ source: function(request, response) { //what are we searching for var query_type = $(this).attr('element').attr('id'); //the cacheterm that we use to save it in the cache var cachedTerm = (request.term + '' + query_type) . toLowerCase(); //if the data is in the cache and the data is not too long, use it if (ajaxCache[cachedTerm] != undefined && ajaxCache[cachedTerm].length < 13) { //map the data into a response that will be understood by the autocomplete widget response($.map(ajaxCache[cachedTerm], function(item) { return { label: item.value, value: item.value } })); } //get the data from the server else { $.ajax({ url: "/ajax/auto_complete.php", dataType: "json", data: { query_type: query_type, q: request.term }, success: function(data) { //cache the data for later ajaxCache[cachedTerm] = data; //map the data into a response that will be understood by the autocomplete widget response($.map(data, function(item) { return { label: item.value, value: item.value } })); } }); } }, //start looking at 3 characters because mysql's limit is 4 minLength: 3, //when you have selected something select: function(event, ui) { //close the drop down this.close }, //show the drop down open: function() { $(this).removeClass("ui-corner-all").addClass("ui-corner-top"); }, //close the drop down close: function() { $(this).removeClass("ui-corner-top").addClass("ui-corner-all"); } });
The ajax/auto_complete.php would look something like this:
<?php <?php //make sure that we only allow valid query types /** * @var array */ $validQueryTypes = array( 'country', 'city', 'first_name', 'last_name', ); /** * @var string */ $column = (isset($_POST['query_type']) && in_array($_POST['query_type'], $validQueryTypes))? $_POST['query_type'] : null; /** * @var string */ $q = isset($_POST['q'])? $_POST['q'].'%':null; if($column && $q){ switch($column){ case 'country': case 'city': $q = new sQuery(); $results = $q->from('addresses') //to make things simpler for the javascript, always select as value ->column($column . ' as value') ->where($column, $q, 'LIKE') ->getAll(); //SELECT $column as value FROM addresses WHERE $column LIKE '$q%'; break; case 'first_name': case 'last_name': $q = new sQuery(); $results = $q->from('users') ->column($column . ' as value') ->where($column, $q, 'LIKE') ->getAll(); //SELECT $column as value FROM users WHERE $column LIKE '$q%'; break; } //$result is something like this: array( array('value'=>'Canada'), array('value'=>'America'), array('value'=>'Mexico'), array('value'=>'Netherlands'), ); //then return it to the javascript echo json_encode($results); } exit;
Then the simplest part of the exercise:
City: <input type="text" name="city" id="city" title="enter a city" class="auto_complete" /> Country: <input type="text" name="country" id="country" title="enter a country" class="auto_complete" /> First Name: <input type="text" name="first_name" id="first_name" title="enter a first_name" class="auto_complete" /> Last Name: <input type="text" name="last_name" id="last_name" title="enter a last_name" class="auto_complete" />
And if they don’t have javascript enabled it doesn’t detract from the form (go progressive enhancement!).
No tags
3
Finding corrupted images
1 Comment · Posted by SeanJA in Data Recovery, Linux, PHP, Programming
As zoe kindly pointed out, two Wednesdays have passed since I last posted. I blame the Olympics (I was in Vancouver for the first week, and I was still recovering from it the second week Go Canada!). You can see my photos on flickr.com as I post them here. Apparently you can only post 100 mb/month, so it might take a while.
Anyway, onto the post:
This month at work, one of our servers decided to act up and corrupt quite a few things. We had about 10000 images on that server, many of them were corrupted, many of them were not. Instead of going through all of the images one by one, opening them and checking if they were corrupted, I was tasked with writing a php script to find them. My first instinct was to do something like this:
<?php if ($handle = opendir('/path/to/files')) { echo "Directory handle: $handle\n"; echo "Files:\n"; /* loop over the directory. */ while (false !== ($file = readdir($handle))) { if(@getimagesize($file) === false){ echo "$file\n"; } } } ?>
Unfortunately, getimagesize only looks at the start of a png file to get the information, meaning that if the file was corrupted after those first few bits of information it would not show up on the list.
The second idea was to use this method:
<?php if ($handle = opendir('/path/to/files')) { echo "Directory handle: $handle\n"; echo "Files:\n"; /* Since they are all png files, this will work: */ while (false !== ($file = readdir($handle))) { if(@imagecreatefrompng($file) === false){ echo "$file\n"; } } }
Which, in theory, should have worked because it reads the whole file in and then returns false if the image could not be created. Unfortunately there was (is) something wrong with the libpng library so I kept getting errors like this locally:
libpng warning: Ignoring bad adaptive filter type
libpng warning: Extra compressed data.
libpng warning: Extra compression dataWhich would be fine if they were php errors. I could have ignored them because the script worked properly and listed all of the files that had problems. Unfortunately for what ever reason, the server was dying on these errors instead of continuing like it was doing locally.
In comes imagemagick to the rescue. Using the identify command (at the command line) it reads in the whole image file and then tells you what it is. Since you might have 10000 images like we did, it is probably also a good idea to send the output to a file instead:
identify "./path/to/files/*" >badImages.txt 2>&1
You will also want to make sure that the path has ” ” around it, because otherwise you will end up with an “Argument list too long” error. In the badImages.txt file you will have a list of images that are in the folder you specified. Any of the lines that start with identify are no good.
No tags
We all agree that testing code is better than not testing it right? So why do we tend to avoid writing unit tests to make sure that we are writing code that works? I’m looking at you PHP guys. Good thing there is PHPUnit and it is as easy as can be to get started with it.
First you have to discover the channel:
pear channel-discover pear.phpunit.de pear channel-discover pear.symfony-project.com
Sidenote: phpunit.de has many useful packages in it including phpcpd, phpdcd, and phploc.
Then you install it (I usually install all of the dependencies with PHPUnit, but you don’t really have to).
pear install phpunit/PHPUnit
After that you can start writing tests.
Say you have a simple class like this:
<?php class needsTesting{ public function divide($a, $b){ return $a/$b; } }
Your unit test file would be this (prior to adding any test cases to it):
<?php require_once 'PHPUnit/Framework.php'; require_once 'needsTesting.php'; class needsTestingTest extends PHPUnit_Framework_TestCase { /** * @var needsTesting */ protected $object; /** * This method is called before a test is executed. */ protected function setUp() { $this->object = new needsTesting; } /** * This method is called after a test is executed. */ protected function tearDown() { } public function testDivide() { } }
After you have added the obvious test cases, your testDivide() function should look something like this:
<?php //[...] public function testDivide() { $array_a = array( 10, 20, 30, 40, 50, ); $array_b = array( 2, 4, 6, 8, 0, ); $array_expected = array( 5, 5, 5, 5, 0, ); foreach($array_a as $k=>$a){ $b = $array_b[$k]; $expected = $array_expected[$k]; $result = $this->object->divide($a, $b); $this->assertEquals($expected, $result); } } //[...]
Running the code is quite easy, if your ide has a PHPUnit extension (like Netbeans does) you can run it from there, or you can run it from the command line (in the folder you are writing the tests in):
phpunit needsTesting
Since one of the tests will give you an error, you should get this:
PHPUnit 3.4.9 by Sebastian Bergmann. E Time: 0 seconds, Memory: 5.25Mb There was 1 error: 1) needsTesting::testDivide Division by zero [...]/needsTesting.php:4 [...]/needsTestingTest.php:56 FAILURES! Tests: 1, Assertions: 4, Errors: 1.
Now it is up to you to decide how your application handles the Divide by 0 error that you got (or any other errors for that matter). While testing first is a good way to define exactly how your app should work, testing after is good too (as long as you are testing it is a good thing).
Check it out:
http://www.phpunit.de/manual/current/en/
No tags
So, it turns out that having a blog is not of much use if you don’t actually post anything on it. Unfortunately I have been neglecting mine as of late, so I am going to try and remedy that by forcing myself to post something on every Wednesday. Why Wednesday? Why not.
No tags
|
|
New Post: Daily Digest for February 6th http://blog.seanja.com/2010/02/daily-digest-for-february-6th/ [SeanJA]
|
|
|
@chriscoyier That seems to be moving way too far in FF 3.6 [SeanJA]
|
|
|
@late2game Aren’t there enough monopoly games already? [SeanJA]
|
|
|
RT @donttrythis: This: http://www.youtube.com/watch?v=h-8PBx7isoM Is one of the loveliest PSAs I’ve ever seen. [SeanJA]
|
|
|
Little known fact about Christopher Walken: He can fly [SeanJA]
|
|
|
"An infinite set is countable" #ORLY http://scienceblogs.com/goodmath/2010/02/_so_remember_back_in.php [SeanJA]
|
|
|
"I am infinitely more intelligent than you can ever hope to be." http://vogons.zetafleet.com/files/orly.jpg [SeanJA]
|
|
|
I am going to start at infinity and count backwards until I have enumerated all of the values between it and 0 [SeanJA]
|
|
|
Infinity…. uhhh…. infinity minus one…. infinity minus two…. infinity minus three… #ThisCouldTakeAWhile [SeanJA]
|
|
|
People people people…. Representable != Enumerable [SeanJA]
|
|
|
Ok… I mean representable is not necessarily enumerable [SeanJA]
|
|
|
Time to kill some zombies [SeanJA]
|
|
|
Shared User Friendly – 7 February 2010.
|
|
|
Think of me as your parole officer with a mace. [SeanJA]
|
|
|
rt @mike_acton: Me: "Being a teenager is like being a newbie person." Daughter: "No, I *am* a person!" Me: "Whatever, noob." [SeanJA]
|
|
|
Remember when movie websites were not all flash? http://www2.warnerbros.com/spacejam/movie/jam.htm [SeanJA]
|
|
|
… and @levarburton as Black Lightning… awesome [SeanJA]
|
|
|
Screw you, I don’t want to log in to vote up an answer… I shouldn’t have to [SeanJA]
|
|
|
Ghost Hunters is a rather silly show… Just people walking around in the dark with cameras [SeanJA]
|
|
|
Oh my god! Fake heartbeat sound! Intense! #OhWaitGhostsArentReal [SeanJA]
|
|
|
100 episodes of this show?!?! [SeanJA]
|
|
|
@late2game When the Me generation grew up and earned a lot of money by being greedy? [SeanJA]
|
|
|
For professional ghost hunters… they really scare easily [SeanJA]
|
No tags

