 |
|
Wednesday, June 25. 2008
 Most major websites nowadays have mobile versions. Some examples include Google, Yahoo, and Reddit. Up until recently, most mobile websites were built using the wap/wml (wireless application protocol) format. The WAP format can be thought of as a compressed version of HTML. If you view the source for the CNN site, you can see its header DOCTYPE set as so:
< ?xml version="1.0" ?>
< !DOCTYPE html PUBLIC "-//WAPFORUM//DTD XHTML Mobile 1.0//EN" "http://www.wapforum.org/DTD/xhtml-mobile10.dtd">
Most sites have a special URL dedicated to mobile devices (e.g. m.site.com, mobile.site.com). If the user decides to browse to site.com instead of m.site.com, some redirect code can be added to the main site to determine the user agent (browser), and redirect accordingly. Dev.mobi offers a PHP script to determine whether a browser comes from a mobile device, using variables such as php's $_SERVER['HTTP_USER_AGENT'].
Full HTML support is also being more widespread as more advanced mobile devices are hitting the market. Even as mobile browsers are becoming more indistinguishable from their full-size counterparts, and as cellular networks are getting faster, there are still several considerations to take seriously:
1. Download size is still an important issue.
There are people out there paying $2/MB for data usage. It's fine to show a small, compressed logo image, but if you stick on a useless 75KB stock image, you're going to inadvertently piss some people off. With that being said, code optimization is also extremely important. Many IA rules apply to both desktop and mobile websites (latest or featured content up top), but this matters more on mobile devices since it's often harder to scroll around and what not.
2. Design must be flexible
Mobile devices come in a myriad of different forms and screen sizes. Some browsers support javascript and/or Flash (lite), but not all. Fixed-width mobile sites are all but unheard of. If your site is complex in design and you'd prefer to keep it intact, then it may save headaches in the long-term by not supporting mobile versions and hoping that more iPhone-like devices (with full HTML support) roll their way onto shelves. To try out mobile versions without a lot of time invested, there are services such as MoFuse that'll automatically build a mobile website version for you.
Monday, June 23. 2008
This article is a valuable resource for clearly explaining how passwords, and other sensitive "secret" strings, can be stored in a database: A Hashing Primer. It may be useful in explaining non-technical users why we don't store passwords in the clear, that is, in a way that we easily know a user's password./p> A common task for any authentication system is to store and retrieve passwords. Doing this securely is key to building a system that is not only stable, but relatively safe in the even that it ever becomes unstable and allows potential attackers to view stored account information. Passwords should never (or rarely) be stored as plaintext: this is where one-way cryptographic hashing can save the day—or at least save plenty of difficult work.
Friday, June 20. 2008
Its amazing how simple this task is using PHP5, cURL, and SimpleXML
1:<?php
2:$ch = curl_init();
3:curl_setopt($ch, CURLOPT_URL, 'http://tech.forumone.com/atom.xml');
4:curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
5:if ($output = curl_exec($ch))
6:{
7: $xml = new SimpleXmlElement($output);
8:}
9:curl_close($ch);
10:?>
Monday, June 16. 2008
Sometimes it's just not wise to work on a database after midnight when your senses are not fully alert!
Anyhow, I don't know how I did this but I inserted 7,000+ records for a single content type (restaurants) half of which were duplicate entries.
After realizing that I can't perform a subquery against the same table to delete the duplicates I quickly turned to Temporary Tables (TT). The reason I used a TT was for the simple fact that I was temporarily using it and I was the only person who could use it. Additionally, once I was done fixing the issue I didn't want to have to worry about forgetting to drop the TT (keep in mind it is late, I'll forget anything). TT's are only accessible during a single db connection and drops when the connection is dropped reducing chances to pollute the db with garbage.
Some may be wondering, why didn't you just create a new table with a subquery selecting the distinct records to construct and populate a new table and then rename it. The reason being is that the 'records' table contains multiple content types with their own set of data and I didn't want to take any chances on messing them up.
So using a subquery SELECT DISTINCT tablefields FROM tablename WHERE criteria to select content type records I created a new TT along with the matching records.
CREATE TEMPORARY TABLE restaurants_temp
SELECT DISTINCT title,address,city,zipcode,state FROM records where datatype = 1;
Next, I dropped all of the original records from the 'records' table.
DELETE FROM records where datatype = 1;
Finally, I inserted all of the records from the 'restaurants_temp' table into the 'records' table via use of a subquery.
INSERT INTO records (title,address,city,zipcode,state)
SELECT title,address,city,zipcode,state FROM restaurants_temp;
Close connection and TT is dropped. Don't have to worry about the db being junked up with garbage.
Friday, June 13. 2008
Yahoo!'s Term Extraction Service can be used to extract significant words or phrases from some larger body of text. There are many uses for it, not the least of which is providing keywords, or tags in Web2.0 jargon, to help classify and organize a library of content. The following PHP script uses will use the Term Extraction service to analyze a PDF file. With a little more work, it could be expanded to work with Microsoft Word, Excel, and Powerpoint files. Extracting keywords automatically would be a helpful feature to build into your blog or CMS. There are modules to extract keywords for Drupal and Wordpress.
1:<?php
2:// discover where pdftotext tool is
3:$catpdf = trim(`which pdftotext`);
4:
5:// the PDF file to analyze
6:$source = 'http://example.com/my_file.pdf';
7:
8:// will copy file to a local temporary file
9:$temp_pdf_file = tempnam(sys_get_temp_dir(), "ek");
10:
11:// see below
12:download_file($source, $temp_pdf_file);
13:
14:// save text contents of pdf source to another temp file
15:$extract_file = tempnam(sys_get_temp_dir(), "ek");
16:exec($catpdf . ' ' . escapeshellarg($temp_pdf_file) . ' ' . escapeshellarg($extract_file));
17:
18:// fetch and output terms
19:$contents = file_get_contents($extract_file);
20:if ($terms = get_yahoo_terms($contents))
21:{
22: echo "\nYahoo terms for the file $source";
23: foreach ($terms as $term)
24: {
25: echo "\n$term";
26: }
27: echo "\n";
28:}
29:
30:// hide our footsteps
31:unlink($temp_pdf_file);
32:unlink($extract_file);
33:
34:/**
35: * Uses curl to copy $source to a local file $dest
36: * @param string
37: * @param string
38: */
39:function download_file($source, $dest)
40:{
41: $out = fopen($dest, 'wb');
42:
43: $ch = curl_init();
44:
45: curl_setopt($ch, CURLOPT_FILE, $out);
46: curl_setopt($ch, CURLOPT_HEADER, 0);
47: curl_setopt($ch, CURLOPT_URL, $source);
48:
49: curl_exec($ch);
50:
51: curl_close($ch);
52:}
53:
54:/**
55: * Uses curl to query yahoo term extraction service for meaninful terms
56: * @param string
57: * @return mixed, array on success or null on failure
58: */
59:function get_yahoo_terms($content)
60:{
61: $SERVICE_URL = 'http://api.search.yahoo.com/ContentAnalysisService/V1/termExtraction';
62: $app_id = 'F1_Testing';
63:
64: $ch = curl_init();
65: curl_setopt($ch, CURLOPT_URL, $SERVICE_URL);
66: curl_setopt($ch, CURLOPT_POST, 3);
67: curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
68:
69: curl_setopt( $ch, CURLOPT_POSTFIELDS, 'appid=' . $app_id . '&context=' . urlencode($content) . '&output=php');
70: $raw = curl_exec($ch);
71: curl_close($ch);
72:
73: if ($raw = unserialize($raw))
74: {
75: if (isset($raw['ResultSet']['Result']))
76: {
77: return $raw['ResultSet']['Result'];
78: }
79: }
80:}
81:?>
As a sample of what to expect, I used the script to look at Calculating CARMA: Global Estimation of CO2 Emissions from the Power Sector - Working Paper 145 and the list of terms returned is below. The list of words is fairly accurate, and even includes the name of one of the authors.
global estimation
geographical scales
carbon emissions
co2 emissions
global citizens
global poverty
david wheeler
rigorous research
power plants
power sector
fossil energy
poverty and inequality
solar wind
energy sources
monitoring system
keystrokes
groundwork
strengths and weaknesses
carbon dioxide
aggregation
Monday, June 9. 2008
At DCPHP, I saw several clever presentations about unit testing, which essentially reinforced what I already know: if I could go back in time and actually guide the development of the CMS we had built in-house, I'd structure it not to have clever self-references and three-level inheritance...which would, incidentally, make it something less than a three-year project to create unit tests for it.
But over the years, with many beginning developers coming through our doors, I've seen several things that the guys who advocate unit testing assume you, as a sane person, are doing...but mostly I've seen those things not being done. So here's an easy one:
<?php $sql = "SELECT id, name, type FROM people LIMIT 10 ORDER BY date_added DESC"; $result = mysql_query($sql); if (mysql_num_rows($result)) { // do stuff } ?>
Great, eh? Checking to see if there are actually rows returned before you do something, right?
But what if your query fails? Remember, you write code not just for right now, but for when you do things down the line. Just like you make unit tests to catch any screwups before you go to production, you can be testing any calls right inside your code. So later, when you add "just a quick fix" and screw up the query, it doesn't have to fail if, for example, it only fails when you pass a variable in and the tests you wrote originally don't cover that.
So always be paranoid about any queries you make:
<?php $sql = "SELECT id, name, type FROM people LIMIT 10 ORDER BY date_added DESC"; $result = mysql_query($sql); if (false === $result) { // handle gracefully } elseif (0 < mysql_num_rows($result)) { // do something } else { // handle the case of no data } ?>
Obviously, in the world of PHP 5 and OO, you should be using exceptions and try-catch, but it is amazing to me the number of developers who will blithely assume their queries are perfect and will remain so, and that there's no risk they'll ever see a production box. Testing is one of the first thing a schedule- or budget-pressed project will skimp on when resources go short. Most clients react less well to "we had to cut your feature, because the budget is running low" than "no problem with your feature, we'll just do some spot checks instead of the full-on testing process." That is, they will until you screw up and they discover a page is completely unusuable on a weekend when you're off paddling down a river.
So write fault-tolerant code. Make sure that even if your query fails, you handle it in a graceful way--and that you provide yourself enough information to quickly figure out what's going on on Monday and fix the thing.
|
|
Comments
Thu, 14.08.2008 16:58
Thanks for the tip. I made a slight mod you might be interested [...]
Mon, 28.07.2008 15:06
Solution (to my issue): Views > Tools > Flush Views Cache It explains that Views doesn't always keep up with changes [...]
Mon, 28.07.2008 14:52
Thanks for this helpful post. I've seen this effect too. I'm running into a different (but related?) issue - the Views [...]
Tue, 15.07.2008 20:25
Oscar, Krista from Calais here, writing to let you know that Calais 2.1 is live. In addition to our ongoing [...]
Tue, 01.07.2008 11:30
Dan, You are absolutely correct and I should have stated this within my post; the described steps within the post [...]
Mon, 30.06.2008 09:45
i wouldnt recomand this at all, because if something happens and the conection is lost u will have your data lost if the [...]
Mon, 09.06.2008 13:42
PDT syntax highlighting support does not seem to work when subclipse is installed, any one else had this problem?
Mon, 09.06.2008 11:56
I didn't mean to imply that you were bashing unit tests.
Mon, 09.06.2008 11:52
My point isn't to bash unit tests, but rather to say there are a bunch of things you should be doing before you get [...]
Mon, 09.06.2008 11:43
I agree with, what I think is, the gist of your argument. That is, if you don't write code that anticipates failure, [...]
Mon, 09.06.2008 08:58
clipse is an open source IDE — or as they put it themselves: “universal toolset for development”. It [...]
Tue, 27.05.2008 12:17
Navigation links should fill their container to ensure ease of selection. A good method for that is to make them [...]
Thu, 22.05.2008 10:35
One of the better comments I've seen in a while: "Although I like PHP, I agree the language is only as good as the [...]
Tue, 20.05.2008 14:03
Oscar, Yahoo's Term Extraction service takes an entire article and returns a few of (what it thinks are) the most [...]
Tue, 20.05.2008 13:13
Hi, Tom Tague from Calais here. First, thanks for taking note of Calais. And integrating an example right within the [...]