views:

1441

answers:

35

What features do you implement (how) in your PHP web applications because you deem it "more professional" in some way? Or do you have personal nitpicks and code hobbyhorses, specifically small things that might count? Which unsavoured code or minor functionality do you spend an inordinate amount of time on to get right?

.

Example coding hobbyhorses for Q&A illustration:

Configuration data not in database: Application data != configuration data, which is also a matter of necessity and efficiency.

URL fixing: Normalize all web addresses by appending the trailing slash, even if it's technically not required.

Human-readable cookies: For data privacy I try to avoid opaque session/database handles (for user options, not authorization usage).

Content negotiation: Makes sense for simple variations between e.g. RSS and Atom formats. But I see it infrequently used.

No database IDs in UI: Avoid leaking database internal surrogate keys into URLs. And with ORMs db-internal keys don't even had to leak into business logic.

.

Hints (not rules)

  • So, which functionality do you believe puts your web application above average?
  • Why is it uncommon?
  • Does it benefit users, but is likewise easy to overlook?
  • More professional and secure coding suggestions are very much on topic. They always are.
  • But the intended scope of this Q&A is actually uncommon/unique features, and possibly non-standard and controversial functionality. Big bonus for fascinating.
  • It's also about coding preferences and nitpicks that just happen to materialize in PHP.
  • Don't think too big or too high level. Small functionality counts too.
  • Show code if feasible.
  • Syntax and coding style / paradigms are however mostly off-topic.
  • And let's not argue about usefulness or code quality. It's purely a featuritis & code survey.

First featuritis research bounty round: It was difficult to decide on one of the many good ideas. Truth be told, I could only narrow it down to five favorites and left the decision to rand(). And the topic is definitely interesting enough to warrant a second bounty round. After a break. And maybe someone else takes over to refine the scope.

+3  A: 

Jus as example: URL "fixing"
For http-URLs I treat path fragments mandatory, like every browser does. So I make it a point to "fix" user input and imported data, and always add the trailing slash to e.g. http://example.org before displaying or storing such values. Probably not "uber professionalism", but normalizing URLs often simplifies dealing with them later on. And don't know, it just seems "better".

 $url = preg_replace("/^(http:..[-\w.\d]+)$/", "$1/", $url);

So I'll always have http://example.org/ in values, no matter what. This doesn't make your HTML any more standards compliant, but it's just one of my pet peeves.

mario
+3  A: 

WRT Config not in database, use memcache with, e.g., a five-minute expiry. A more sophisticated option is to touch a "reload config" page whenever the config changes; the trick is to make sure you touch the page on every app server instance in the farm (which is why I prefer memcache).

Marcelo Cantos
And if you don't want to set up mamcached, simply use APC ;)
nikic
+31  A: 

Documentation.

Imagine any open source project you can find with and without up-to-date documentation and feel the impact this has on how professional you think it is.

koen
+1 for open source projects this is of utter importance. Undocumented projects are a pain to work with. I would like to contribute to Mozilla or to PHP, but they don't document and thus I can not :(
nikic
Also beware of the anti-pattern: lengthy phpDoc comments and autogenerated listings are no replacement for didactic documentation.
mario
I asked a [question](http://stackoverflow.com/questions/1775503/minimalistic-tools-for-developer-documentation) once about good developer documentation tools that yielded pretty good feedback.
Pekka
+18  A: 

for professional appearance, very important is clean and aesthetic graphic design as well. because the cover is what sells, these days. sad, but true. web application with a beautiful code and ugly appearance won't attract much attention.

mykhal
This is an area where many good programmers fall down. Especially when it comes to how the program flow works. Programmers are always sure what they write is intuitive because -they- think it is, often is is a strong case of creative bias.
Bill
This isn't as shallow as it sounds. Some people will kill me for saying this, but graphic design, UI, and UX tend to be related.
Ziplin
YES! Hire a **real** artist (or find a volunteer - not easy though, they have a different mindset when it comes to copyright). Heck, Jeff Atwood said so himself: the original version of Stackoverflow sucked until they hired a real artist to do the design.
slebetman
It's not sad but true. It's realistic. Good UI isn't just nice to look at, it's intuitive and easy to work with, two concepts which alone make for nice.
Paul Sasik
+6  A: 

Consistent programming style, variable naming, bracing, etc. Adherence to a coding standard (any coding standard.) Making sure file written by different people look the same so that maintaining the code doesn't require knowing who wrote it.

Adam Casey
Not sure whether the `any coding standard` part is right. You should used the coding style that is used by most projects written in this language. In PHP this would be the Zend Coding Guidelines. (Admittedly I do not strictly adhere to them :( )
nikic
I disagree. Coding standards are different from shop to shop. The goal is that all code matches the one being used, simplifying maintenance. This applies to all languages; I am lumping PHP into this. For example, we have a strong C coding standard, but had none for PHP. Our C standard was adapted as it makes our SW group more consistent.
Adam Casey
I'm with Adam; any standard (within reason) is fine, the important things are that a standard exists at all and that it is enforced (e.g. with PHP Code Sniffer etc).
El Yobo
@Adam: I do think that coding style shall be standardized within a project. I simply don't think that you mustn't choose some arbitrary standard you personally like for this, but the standard most common for the language. This way not only coding *within* the project is consistent, but *between* several projects, too. If you use the Zend Coding Standards you can be pretty sure that anyone may participate in the project without learning some new coding style - simply because it is the most popular standard. But maybe I'm too strict on that point.
nikic
mario
As much as I agree with Adam's point (and personally adhere to it), I think mario is right -- this isn't strictly on topic.
jwiscarson
+11  A: 

Password Strength/Match

Notify user interactively of the strength weakness of their password, when signing up or changing it. Also notify them when their confirmation matches when they are typing.

Realtime Form Validation

As with passwords, realtime validation of form entries is much less irritating than allowing the user to complete the entire form before they know they made a mistake, or omitted a mandatory field they skipped over.

Defensive programming with Friendly Exception / Error Handling

Never use cryptic error messages, and generally refer to the best case examples you can find for good friendly error messages. In best cases, this generally requires a talented copy-writer to be tasked with maintaining good tone of voice etc.

This goes hand in hand with solid exception handling and good defensive programming.

Defensive Design is a pretty decent book on this topic.

slomojo
+20  A: 

Care for security, especially of the user's private data.

Store passwords using a strong hash (not md5 or sha1). Furthermore salt and stretch them.

function hashPW($string, $salt, $runs = 100, $algorithm = 'sha512') {
    // some nice big salt
    $salt = hash($algorithm, $salt);

    // apply $algorithm $runs times for slowdown
    while ($runs--) {
        $string = hash($algorithm, $string . $salt, $raw);
    }

    return $string;
}

$salt should not be a static value. It should be different on per-user basis. For example the username is a good candidate for the salt.

Discussion why I use exactly this script.

nikic
+1 for multiple iterations which increase time taken to brute force.
Xeoncross
`$salt` should also be something that the user cannot change, as that would invalidate their password and they'd have to change a new one. So, if username is permanent, great; if not, maybe their row ID, creation time, etc.
mway
I prefer a random salt to something that could be inferred like a username or any user specific details
Jimmy
+8  A: 

Continuation Points

Example: You submit a form, you get redirected and now the landing page should cotain a notifications. Most sites simply store that notification in the session. This means: any page, that will be accessed next will display that message. No problem in most cases, but it's really messy to my mind. I think the session is for session data, not next request data.

My solution: Create an array, write data ( notifications and maybe more ) into it, save it in memcache using the sessionid + a unique identifier and on the redirect add the param __continuation={that unique identifier}. Then the next page loads that data again and processes it.

This becomes more handy, when you want to have more data than just a short message.

Questions?

Baju
I've used a simple `?msgid=5` scheme for form redirect/landing pages. But I see what you mean. For non-static and custom messages, you need a proper storage. And true, the session store is semantically not to be used as data dump or message queue in itself.
mario
Great way to make multi-tabbed continuation work!
giraff
The simplest solution for sites that need Javascript anyway would probably be to use HTML5 sessionStorage with some kind of fallback. (sessionStorage is like localStorage but is tab-local and doesn't persist across browser restarts)
ssokolow
+2  A: 

I know this is frightful code and deserves to be downvoted. Just wanted to give a example that Content Negotiation is actually easy to achieve.

function q_order($src) {
    $src = str_replace(",", ";q=0.99,", "$src;last;q=0.975");   // inject placeholder values
    foreach (explode(",", $src) as $prt) {   // split entries
        $q[trim(substr($prt, 0, strpos($prt, ";")))]   // append TOKEN until ";" 
        = floatval(substr($prt, strpos($prt, "q=") + 2));  // and first float after "q="
    }  
   arsort($q);
   return($q);
}   

This allows quick sorting of HTTP_ACCEPT headers, which is useful for automatic alternating between RSS and Atom feed formats. Or just for setting the default language. (You'll often need language flags/links anyway, but it's a better default than just defaulting to english.)

$lang = q_order($_SERVER["HTTP_ACCEPT_LANGUAGE"]);
if ($lang["de"] >= $lang["en"]) { ...
mario
+2  A: 

One of the important things that any 2.0 web app is expected to have is -

  1. Search - whether it's full text search, keyword search, whether you have auto-suggest or (one of the most latest) live search. Without this feature I feel stifled when I visit any site (especially sites which are closed to search engines). A definite must have for any modern 2.0 site PHP or not.
  2. MVC Framework - Since this is related to web-dev (not tied down to PHP), Model-View-Controller framework is a must. With excessive code base & faster iteration cycles proper structuring is a must to prevent future hassles & untraceable bugs.
  3. AJAX - Need I say about this :) It's changed the way most of us browse websites. An AJAX enables website is a cool feature to have.
  4. Debug Info - This is for the case when you app crashes. How do you find what went wrong? Do you maintain logs? Can you traceback the problem to it's source from logs (hours after it has occured)? How verbose should you let the logs be?
  5. Minified Javascript & CSS - Reduces loading time & makes the site more snappy, thereby user feeling more comfortable while browsing the site.
  6. Caching - Again tremendously increases the perceived response time for the user, thereby rendering the site more "professional".
MovieYoda
Good points. But let me quickly disagree on the "MVC" part. I'm maintining the php framework matrix, and there are no MVC frameworks. It's a misnomer. You cannot have real MVC in web apps (except with all-AJAX frameworks like Capuccino). Most PHP implementations are either PMVC or closer to MVP. And anyway, it's mostly coding style rathen than real functionality.
mario
MovieYoda
Disagree with your AJAX point, AJAX is rarely done well.
balupton
@balup what do you mean, "rarely done well"?
MovieYoda
@movieyoda "An AJAX enables website is a cool feature to have." - makes it seem like you overuse it just because it's "cool", rather than useful. For example, do your websites do validation correctly, error reporting for failed ajax requests, crawlable ajax, graceful ajax, nice errors if the request fails - overall barely any of these things are covered with ajax, and it's extremely rare for all - as such AJAX implementations are rarely "cool".
balupton
@balupton again I disagree. If someone is going for AJAX, it implies that he does all the other things that you mentioned. Basically keep the user in the loop. What kind of a programmer will write code but no error handling? What you are saying is more specific to a particular programmer(s). What I am saying is that this technology has got a great future in web. So I suppose you don't use GMail or Google Reader?
MovieYoda
The question is about professionalism. AJAX != professionalism. Just because you use Ajax because it's cool does not make you or your website more professional. If the question was about cool technologies then you would get a +1
balupton
MovieYoda
+16  A: 

A health check

A series of pre-configured tests that determine the basic "health" of a web application or web site that can be viewed (by the administrator / site owner) at any time, showing things like:

  • Is the database server reachable?
  • Are the necessary files and directories writable?
  • Are all data structures sane and complete?
  • Do all pages / dialogs / queries show up correctly?
  • Is enough disk space available?
  • etc. etc.

a simple status page shows the current "health" of the system with a green, orange or red background.

This is different from Unit Testing in that it deals with the health of a "real world" environment, and not abstract code integrity.

A health check also makes migrating an application to another server easy.

I have implemented this in several projects that need constant monitoring; I'm planning to make it into a small, extendable "drop in" open source app some time this year that can be used in all sorts of web applications and even web sites. Participation and input very welcome - see the related SO question for more details.

Pekka
What's curious about this point is that all major PHP applications come with installers that perform most of these checks. But it's universally missing in the admin backends.
mario
@mario yup, I've never understood that either.
Pekka
+7  A: 

Configuration data not in database

I disagree. If you have got well designed application that heavily relies on interfaces then it doesn't matter whether your configuration is being stored in database, text file (XML, INI, YAML etc.) or as a PHP array. Moreover things like global configuration could be cached in memory (Apc, xCache, Memcache).

Human-readable cookies

I don't think that it is important. Cookies aren't designed to be modify by user so you should look at them only from application's point of view. And for me it doesn't matter whether I've got pref = "a:1;b:0;c:1;d:'asc';e:150" or 5 different human-readable cookies.

No database IDs in UI

Once again, I disagree. A typical numeric ID is much more reliable and easy to maintain. Just imagine what happen if user will change his username? What happen with all links on external websites that links to some user profile? You should make URLs good for both, application and users: /user/123/crozin. Application got a nice numerical ID, user got a nice readable URL.


Write code that will be easy to maintain in feature. Think few times about object's interface before you start writing. Add many event triggers, even if you don't need them right now. They might be useful in the feature.

Write code as if it was an external library. Even if you're dealing with commercial, closed application treat it as open-source project. Think about other users that might want to change behavior of existing code without changing it. When you're using type hinting you should probably check for interface rather class, so:

public function add(Storable $resource);    # Good
public function add(SessionStore $session); # Bad

Do not use global namespace, and "global features". Defining global constants or using __autoload() (rather registering another autoloader using spl_autoload_register()) is a bad practice.

Use 3rd-party-code. There is a lot of libraries out there. Most of the time it makes no sense to develop own ORM or Mailer. It reduces the amount of time needed to develop an application -> it reduces costs.

Create API documentation. I don't think that any explanation is needed.

Make your code look clean and keep some coding conventions.

Don't create useless pages. There is nothing more annoying than 404 Not Found page with nothing more that just a big 404 NOT FOUND information. You should probably provide several not found pages for each resource. So if I visit /video/123/how-to-swim and such resource doesn't exist except We're sorry, that video doesn't exist or has been removed. add something like: Recent videos, Maybe you're looking for: "how to dace", "swimming: abc" (videos with title similar to title form URL (how-to-swim)) etc.

Allow users to customize the website. Imagine that you've got a homepage with several "boxes": recent videos, recent photos, recent active threads, news, promoted gallery etc. Allow users to hide some of these, to change their order - someone might be more interested in photos and videos rather than news and threads so he/she might want to got them on the top of the page, someone else might got different preferences and might want to have different order. Add preferences for each box like: "display: 5, 10, 20 recent videos".

Crozin
Hmm, I need to disqualify this answer. These are all very useful recommendations for higher application quality. But it's digressing too far into coding styles here. Good reminders, but only the last two points seem on topic about features/functionality.
mario
+1 for the first two comments on marios post.
nikic
+2  A: 

Configuration data not in database: Application data belongs into the database. But configuration settings do not. Why?

  • It's not efficient to query the database for runtime options on every PHP request.
  • Settings aren't changed on a daily basis, a static store is sufficient for most use cases.
  • The disparity between the a database configuration file, yet having the remainder of the runtime options in the database seems silly.
  • IMO it's often done due to lazyness, because setting up securely and modifying a file (ini) store is more involving than just another SQL table.
  • As exception, user settings and per-domain configurations are unmanageable without a database store.

While seldomly needed in practice, I do in fact want my users to be able to edit the runtime configuration (once per year). So in effect I spend more time on config file modification functions than it would require with a database. Pros: easier backup and versioning than with SQL config table.

Cons: If access/archiving/versioning is not an issue, then SQL makes a good config store if combined with APC or memcached (for efficient access). Cache files are also a possible solution.

mario
A: 

Human-readable cookies
I personally believe it's a bit artless to always resort to SESSIONs just because variables are easier to store there with PHP.

Session IDs are technically often cookies too, but not human-readable and opaque storage handles. So instead, if it's simple user-preferences (not autorization stuff), I like to send readable cookie names and values, e.g. product_order=desc, or fav_background=orange.

Usually I resort to sessions too. But for personal projects where I care about data privacy (meaning user rights) I put up with all the downsides:

  • More micromanaging overhead for multiple cookies.
  • Validity checking on each cookie separately, because it all becomes user input.
  • Might need to define an additional expiry cookie or otherwise random renewal. (Due to the fact that I find 2038 cookie expiry times likewise dissocial, and only use appropriate times.)
  • Cannot be used for anything authorization-related, but just user and display options.
  • I believe it's important to recognize a semantic difference between real cookies and session cookies. But is it important to take care here, if hardly anyone sees it?

However it makes my data privacy brain part happy. And for some use cases it's a simple no-brainer.

mario
-1 Well, I think that what you do, is a no-go. A session-cookie, with `PHPSESSID` as name and a md5 string as value needs 9+1+32=42 character to be transferred on every connection. Now imagine that instead of this one session cookie you have ten cookies. That are already 400 chars. And in a big application you normally don't have only 10 preferences...
nikic
Pros and cons. For more then 10 cookies I wouldn't go that route. But for one to three user options, this *is* the optimal way. Also session cookies are definitely never RESTful, while as-is Cookie data could very well qualify as request meta info.
mario
@mario: Who cares about REST? Honestly, people who visit a website want a) a nice design b) a fast loading of the page and c) good content. So who cares about REST - nobody.
nikic
mario
Well, I do pretty much care about user data privacy. But storing this data in cookies instead of in local files on the server doesn't increase security imho. The computers of normal users often are way less secured then your server and thus may be easier compromised. So I think that the probability that somebody steels data from the browser cookies is way higher then him stealing the data from the servers session files. Especially if those files are encrypted (Suhosin).
nikic
It's about privacy, not security. And I can't imagine why someone would *steel* cookies like `fav_background=orange` rather than session ids. My point being, it's necessary to differentiate between *real* preference cookies and opaque authorization/tracking ids, from the user rights point of view.
mario
@mario: Ah, sorry. I though that "privacy" were something like "private data security". My English isn't so good after all ;) Still I don't think that the user will ever use his "right" to manually modify the cookie in the browser. Thus I really don't see reason to make it possible ;)
nikic
Cookies allow croud-sourcing of data insuring that even small hosts will be able to give out sessions to every user on the planet. If using memcached or a database this would not be so. On another note, never trust `$_COOKIE` or `$_SERVER` and cookies should always be encrypted.
Xeoncross
+3  A: 

No database IDs in UI
Most database objects are enumerated with some surrogate key. What I think looks unstylish (and might occasionally be a security pitfall) is leaking those into the UI, as in URLs. It's not a big deal to change any occourence of user.php?id=37310843 into user.php?name=title. And it makes little difference for the database to look up ids or names. So that's not about SEO sillyness, but about a sprucely exterior

  • With a proper ORM those database-internal IDs never even had to leak into application logic either.
  • Exhibit Wikipedia: imagine they used surrogate keys instead of page titles. (see CoWiki)
  • For having external links always point to idendical content, surrogate keys should be avoided still. If it's important enough to have exact allocations, then GUIDs should be used anyway.
mario
+8  A: 

To add a few more (less PHP orientated) points to the mix, which will enhance both the user experience and make your app more professional, but which handle the back-end:

Good compression/minification
Often Web Apps send a large number of requests both at load and through the course of their use. Minification can help reduce initial load weight as can the use of CSS sprites and GZipping content. A great way of helping you streamline and make your Application as quick as possible is Yahoo's YSlow plugin for Firefox's Firebug Extension:

Firebug: http://getfirebug.com/

YSlow: http://developer.yahoo.com/yslow/

Also- some good practices: http://developer.yahoo.com/performance/rules.html

YSlow will help identify how you can really make your Application neat and tidy, quick and clean. I'd also recommend PHP Minify to take care of much of the file compression, its a very capable tool:

PHP Minify: http://code.google.com/p/minify/

Plus another reason for getting Firebug is the huge benefits it gives when developing any Web App, not least of which is identifying exactly how secure the App is, as during operation as you can track the data flows created.

Obfuscation
---split out to more detailed answer below

Good use of Apache rewrite
Apart from the basic benefits of serving up clean URLs to enhance the browsing experience and giving the impression of logically filed content, a good .htaccess file can add additional layers of security to your site, compress content server side and add additional identifiers (E-Tags for example, though their benefit is arguable). Every Web App should also have a well written .htaccess.

Compatability/Validation
I would always strongly urge any developer to go to the most extensive (reasonable) lengths to make sure all their output code is Valid, Commented, Logical and Clean. The W3C do a fantastic job of clearly speccing not only HTML, but also how Web Apps should operate. Follow their guidance to increase the compatability of anything you write, to ensure it works for everyone how you envisage it to.

Some great tools:

HTML validator: http://validator.w3.org/

Other validation: http://validator.w3.org/unicorn/

Some specs to be aware of:

The W3C Web Applications (WebApps) Working Group: http://www.w3.org/2008/webapps/

W3C Accessibility Guidelines: http://www.w3.org/WAI/guid-tech.html

W3C WAI-ARIA initiative: http://www.w3.org/WAI/intro/aria.php

On the Javascript side, JS lint is a great tool to make sure any bugs in your JS (that may not impact performance when you check) are squashed:

JSLint: http://www.jslint.com/

And by proxy, to aid development, beautified JS can help you structure your code better for development, pre minification: http://jsbeautifier.org/

Or beautified PHP of course... http://beta.phpformatter.com/

Finally- something a little less black and white
Humanisation

Perhaps one of the greatest benefits of producing web based applications is the connectivity they can provide, not only between users (in order to encourage collaborative work), but also between users and the app itself as well as those responsible for its ongoing development and maintenance.

If you think of projects like 37 Signals- one of the appealing factors is they impart the feeling to the user that the project (code) itself has been humanised and has a character, helping to draw the user in and associate with the app, encouraging enjoyment of use and communication of it to others. I dont mean that the app seems 'alive', but more that it feels more 'approachable' and users can 'identify' with it.

However, this is only one side of the humanisation coin, the quest to almost make users 'empathise' with the app/code/framework/experience so they are drawn in an encouraged to use it. The other side is to break down the boundary between the app, and those behind it.

We all like to know the person, people etc behind what we use- as we impart much information from them and often illogically apply it to the app itself, and indeed our 'like' of it (i.e. like Steve Jobs, buy Apple etc..though admittedly a wayward example). Having a route by which we can contact a real person in event of difficulty is one simple step, having a developers blog, news stream etc- building out a humanised metaverse around the app gives it credibility and the feeling that it is perhaps greater than the sum of its parts.

Admittedly humanisation may be neither here or there- and it's certainly very difficult to build (in the same way different people have different friends), but any way a developer can sand down the edges of a more clinical, surgical app and make it more comfortable and approachable and fun for the every day user is a winner in my book.

Ergo Summary
Upvote, though I disagree with the anti-opensource obfuscation (often leads to a false sense of security). Validation and WAI/ARIA compliance is an excellent point.
mario
Would you care to show some more details of your obfuscation routine?
Industrial
I agree with the anti opensource comment re obfuscation, perhaps it is most suitable for certain applications only (I mainly code for the Financial Services industry, in which case it adds an extra layer of protection -even if minimal, to the clients IP as well as the Apps resilience to attack)
Ergo Summary
Re the obfuscation routine, Im more than happy to elucidate, though dont want to clutter the question- Im happy to PM you or answer elsewhere, as you prefer :)
Ergo Summary
-1. "Split up answers please."
mizipzor
@mizipzor: Regardless- arent up/down votes based more on the validity/quality of the answer provided as opposed to format (i.e. splitting?) - I appreciate this is a long answer, but it is not alone in this thread when it comes to answers with multiple points made. In addition- is it therefore not at the discretion of the original questioner (who made the comment re splitting and who has already voted on this answer)? There seems to be little unilateral method being applied for the arguments given with the down vote.
Ergo Summary
@Ergo: I agree that voting on formatting alone is harsch and it should be more about validity/quality. But the validity is hurt when answers are not split, I can only agree with everything or nothing. With unsplit answers the *median best* (within an answer) rather than *best* answer is at the top. I believe quite firmly in this. I would split this answer myself, making two separate answers but Im afraid that I might come across as making myself look knowledgable instead of the original author, credit must be given wherecredit is due. This is something I havent solved yet, so I simply downvote
mizipzor
Yes it's getting a bit too lengthy. There are many good points, but it's difficult to vote on multifaceted answers. The first few are too close to syntax/coding style rules. The Humanisation point seems interesting, though I'm unsure if it can count as *technical* feature.
mario
@mizipzor, @mario - answer split to make the thread a bit more user friendly (I see your point), thanks for the feedback :)
Ergo Summary
I would like to know more about the Obfuscation, please ;)
Aaron Hathaway
Ive added a more detailed answer re:obfuscation, below :)
Ergo Summary
A: 

Testability

I don't mean a quick script that "health checks" the application, those are mostly worthless. If most or all of your code is covered by strong tests, you and your customer are more likely to benefit from well designed, agile code.

Readability

Others will be using your code, and you will be updating it later on. If you can't read your code, it's worthless (comments don't count by the way). Variables should be named properly and the flow of context to context should be easy to identify.

for ( $i=0; $i < count($myList); $i++)  // obviously an index
foreach ( $k as $a => $b ) // wtf?
foreach ( $definitions as $word => $definition ) // better
Scott
+3  A: 

The delve function in PHP, allows you to:

$a = delve($array,'a.b.c.d','default'); // $a->b['c']->a
$b = delve($object,'a.b.c.d','default'); // $a->b['c']->a

Without this, you would have to do painful issets and empties and datatype checks all the bloody time. This is by far my most favourite function.

In regards to what makes more professional code is unit tests, documentation version control and do first (then if you fail to do, then revert to stack overflow).

/**
 * Delve into an array or object to return the value of a set of keys
 * @version 1, December 24, 2009
 * @param mixed $holder
 * @param mixed $keys
 * @param mixed $default
 * @return mixed
 * @package balphp
 * @author Benjamin "balupton" Lupton <[email protected]> - {@link http://www.balupton.com/}
 * @copyright Copyright (c) 2009-2010, Benjamin Arthur Lupton - {@link http://www.balupton.com/}
 * @license http://www.gnu.org/licenses/agpl.html GNU Affero General Public License
 */
function delve ( $holder, $keys, $default = null) {
    # Prepare
    $result = null;
    $end = false;

    # Prepare Keys
    ensure_keys($keys, $holder);

    # Handle
    $key = array_shift($keys);
    if ( $key === null ) {
        # Reched the end of our key array, so holder must be what we want
        $result = $holder;
        $end = true;
    } else {
        switch ( gettype($holder) ) {
            case 'array':
                if ( array_key_exists($key, $holder) ) {
                    # We exist, so recurse
                    $result = delve($holder[$key], $keys, $default);
                } else {
                    $end = true;
                }
                break;

            case 'object':
                if (
                    /* Already accessible via normal object means */
                    isset($holder->$key)
                    /* Is Doctrine Record */
                    ||  (   ($holder instanceOf Doctrine_Record)
                            &&  ($holder->hasAccessor($key)
                                    ||  $holder->getTable()->hasField($key)
                                    ||  ($holder->hasRelation($key) && (!empty($holder->$key) || $holder->refreshRelated($key) /* < returns null, hence the OR and extra check > */ || isset($holder->$key)) ) // && $holder->$key->exists())
                                )
                        )
                    /* Is normal object */
                    ||  (   !($holder instanceOf Doctrine_Record)
                            &&  method_exists($holder, 'get')
                            &&  $holder->get($key) !== null
                        )
                ) {
                    # We exist, so recurse
                    $result = delve($holder->$key, $keys, $default);
                } else {
                    $end = true;
                }
                break;

            default:
                $end = true;
                break;
        }
    }

    # Check Default
    if ( $end && $result === null ) {
        $result = $default;
    }

    # Done
    return $result;
}

Full file (and library) available here: http://github.com/balupton/balphp/blob/master/lib/core/functions/_arrays.funcs.php

balupton
Oh, very nice for tree traversal and deeply nested objects. And your licenses obliges you to also show us the ensure_keys() function! :}
mario
Hehe thanks! :D Actually as the copyright holder I'm not obliged to do anything, if you were to modify any code however I am allowed to request the same privilege from you - which you can deny and stop using, or provide and keep using ;-) Anyway I've added the link as the entire library is open-source for all to enjoy :-)
balupton
A: 

do you have personal nitpicks and code hobbyhorses, specifically small things that might count? Which unsavoured code or minor functionality do you spend an inordinate amount of time on to get right?

Correctly Reference Array Keys

Any non numeric Array Key (i.e. not an index) should be enclosed in single quotation marks to ensure it is handled by PHP correctly under all circumstances, and syntax is detected in most good code editors. e.g:

$array['key'];

NOT

$array[key];

Require/Include Once

Always ask yourself why you are using require_once and include_once. Most of the time it is to prevent duplicating code that you may or may not have already pulled- if this is a possiblity, have you really written your PHP in the most efficient and effective way?

Buffer output for Clean Loading and Improved Speed

Adding:

ob_start('ob_gzhandler'); 

To the beggining of scripts and:

ob_end_flush();

To the end will compress and buffer the output of your scripts so they are more rapidly loaded and not displayed incrementally as content is served.

Predefined Loops

Every time a loop is run the maximum value should be set before it initiates. I see too many incidences where functions are referenced (despite this being fairly widely covered) i.e.:

for($=0;$i<count($x);$i++){
// code
}

This means the count function is run each time the code loops, which is inefficient. It is much better to do the following:

$stop=count($x);
for($=0;$i<$stop);$i++){
// code
}

RegEx vs PHP String/Numeric Handlers

Reduce reliance on RegEx's if you are handling strings and there is a PHP equivalent, stripos, strncasecmp and strpbrk are faster. strtr is faster than preg_replace by around 5x. ctype_alnum,ctype_alpha and ctype_digit can be used to help form validation in place of a RegExp.

Clean your Workspace

Always close your DB connections when you are finished with them, and always unset your variables. Its good, if perfectionistic, practice.

Consistent use of Quotes

Use single and double quotes CONSISTENTLY. i.e. if you use:

echo "this is a 'string' not a number";

Dont then use:

echo 'this is a "string" not a number';

If you need to reverse the order, dont- keep it the same and escape the recursive quotation mark. Also, PHP works with strings encapsulated with double quotation marks far better, you can encapsulate a variable without the need for concatination. eg:

echo "this and $thisvariable here";
// instead of
echo 'this and '.$thisvariable.' here';
Ergo Summary
So, have another upvote then ;) Though it's bordering on coding style, I like a few of the suggestions because they seem based on *factual* preferences and enhancement experience.
mario
I downvote because I think that this is largely off-topic. Furthermore direct variable interpolation is considered a bad practice. Thus you should use the "instead of" variant. Furthermore I don't know how much you should make the quotes consistent. For example, I normally only use `'` quotes, because they do not allow variable interpolation and because any HTML places within the quotes doesn't need attribute escaping (`"`). But if I need to work with a string with loads of `'` and little `"` then I think I'm better of with either NOWDOC or double quotes ;)
nikic
A: 

Password Hijacking
We've initially had an answer here which was about for- and anti-user security. The suggestion was about user registrations, and checking the supplied password against the users SMTP/POP3(?) server using the supplied registration email, giving a rude error message should the user lazily reuse his email/pop3 account password.

It was downvoted, obviously, because breaking into users email account is questionable (even though the intention was clearly to educate). So answer was deleted. But I liked the meta concept of being rude to the user if it helps his security.

And secondly I thought, while this feature is a legal misfeature for public websites (and if there isn't a clear warning or something about beforehand), it is a very probable concept for intranet web applications. I would think it's even a common thing for company-internal IT policy to ensure passwords are unique among the more sensitive systems.

mario
-1 again. I think that being rude to somebody is never good. Especially if this somebody is a person willing to pay for you products or services. By being rude to him he might change his mind ;)
nikic
I am not sure that your concept is even workable for company internal IT systems, since the security policy usually forbids to use credential that are not assigned to you (audit-ability). I expect that companies will rather go with a identity and access management solutions that allow you to define rules for passwords, associate accounts of diff. systems, and define access rules to your apps. E.g. this can be a combination of the IBM tools Tivoly Directory Server (TDS), Tivoly Access Manager (TAM), and Tivoly Identity Manager (TIM). Depending on your use case you might need more components.
Peter Schuetze
+7  A: 

No forced registration
This is a common problem with everyday web applications. Forced account registrations are not user friendly. It's nowadays a necessity to prevent spam and misuse. But it hampers adoption.

I guess everyone has heard of Stackoverflow. They don't force registrations. You can paritipate without account. Instead of forcing registrations it systematically encourages it. The main point however being, that there is at least the option to gradually get accustomed before committing.

It's a simple concept. But it's likewise difficult to implement. Seldomly can you tack on temporal and optional user accounts, the base application logic and database structure must be prepared for it. Regardless of the implementation effort, I believe this is an important and undercherished feature.

mario
Huzzah! Even better is accepting open auth. I LOVE open auth sites!
Ziplin
Web shops are the worst for this. Sometimes, people just want to buy something.
Alan
+2  A: 

Automated Unit tests

Important, much in the way a healthcheck page is important. Once my code grows past 800 lines of code, I can't remember what I was doing at line 100 and I will likely break it without realizing it.

Ziplin
+1 unit tests are very important.
nikic
+2  A: 

A Registry System.

I have spoken many times before in regards to storing objects and scope issues and the best way I know of to over come this is by using a Static / Abstract class with getters and setters that can help you transport objects around your application and save you having to modify classes so that you can specifically import objects for usage.

the class can be as simple as an abstract static class with 2 methods and 1 array, these are the basic ingredients to over come the great scope issue without effecting anything else within the oven.

Here's a small example of what i am talking about:

abstract class Registry
{
    private static $objects = array();

    public static function set($name,$object)
    {
        self::$objects[$name] = $object;
    }

    public static function get($name)
    {
        return self::$objects[$name];
    }
}

looking at the simplicity of that class there's nothing to be afraid of, nothing to make you modify your current framework / application to adopt this method, but if your unsure how it works let me give you some examples

Firsty lets say we have index.php that includes startup.php, and within startup.php your including your libraries and core framework code, but in startup your loading the following

  • Database
  • Session
  • FileWriter
  • Input
  • Output

now if you wanted to use the FileWriter object as a tool for logging within Database object you would usually have a variable called $FileWriter and you would use the global keyword in Database object

But by doing the following:

Registry::add('Database', new Database())
Registry::add('Session', new Session())
Registry::add('FileWriter', new FileWriter())
Registry::add('Input', new Input())
Registry::add('Output', new Output())

Your storing everything within your Registry object so lets take a look at our Database object / class

class Database
{
    //..

    public function connect()
    {
        if(!$this->connected())
        {
            try
            {
                $this->connect();
            }catch(Exception $e)
            {
                Registry::get('FileWriter')->Write('db_logs',array($this,$e),'unable to connect to database');
            }
        }
    }

    //..
}

Now as you can see that Registry is available within the scope of the class, and its clean, safe, your not taking up extra variables or using more likes of code with globalization, just clean simple and safe

Hope you enjoyed the read.

RobertPitt
+9  A: 

Source Control. Specifically Git (Though not specifically GitHub)

OK, It's not uncommon.
But when I outsource code and get back a neat repo, with all the history and twists and turns, I am far more impressed than with a folder full of php files.
And it demonstrates how much extra work was put into the project that isn't seen.

I use GitFlow, which takes a bit longer during use, but makes up for itself in being that much more impressive in the finished project. Make sure the client sees the github graph (or equiv.) All of those branches look neat and impressive. (Besides actually being useful!)

Related:
An Issue Tracking System.
Both for before the code is completed (while client is reviewing), and afterwords, to allow them to add new tasks.
It is not only a way of demarcating tasks and getting more work, it makes the client feel that the project is still on my mind. Even though Ive moved on.
I use Collabtive, which is absolutely horrendous as these systems go, but is more impressive looking then anything else I've tried, Things that look impressive are assumed to be professional.

SamGoody
Git + Github = +10. Sorry that I can only give +1 :(
nikic
Git rocks.. +1..
Hanseh
+1 for GitFlow. To me, all other ways of using git is doing it wrong.
slebetman
+2  A: 

Conglomerated application

Ask yourself - if you're running a online commerce system and your card payment supplier goes offline, shouldn't your customers be able to still browse your products and even check out using different payment alternatives?

Applications should be built in a way where "switches" can be toggled which doesn't take the whole site into "maintenance mode", but just makes the pages or parts in your application unavailable in a graceful way, while the rest of your app stil is available to other users.

Conglomerated application might be a cheesy name but I am totally sure that there's something better out there for it, but it's definitely one of the approaches that many people tend to forget when it comes to developing available applications.

Smart brute-force protection

Let's say that you have an administration part in your application that holds quite a lot of customer information. Definitely data that you wouldn't want anyone to get their hands on. Even if you have a nice salt and good algorithms to hash your passwords, an evil user could still perform a DOS/rainbow-table (brute force?) attack on your login forms.

The first option is obviously to use automated software to perform these attacks and secondary by doing it manually by making qualified guesses of a password. It's really easy to find out enough information about a user to guess his or her password, considering how much information that's available out there by just using Google. Also, if you're living in a country such as Sweden - there isn't much information that you can't find out about a person with a single phonecall to the authorities - Social security numbers, names of partner, marriage status, children names, pets and much more information that all comes together as very qualified guesses of passwords for the ordinary user.

If we would have a look on how ordinary people choose their passwords, the security should be really easy to compromise. Sure, we could setup restrictions on users passwords in length, special chars and so on, but that wouldn't affect the situation. Brute-force attacks could still be made.

If a user tries to login and fails his/her second attempt from an unknown IP, a recaptcha should appear to prevent automated logins. After another (n) failed attempts, the account should become locked completely and need re-activation before login could be done.

To prevent automated attacks from eating performance, a good idea would probably be to completely block an IP that has made (n) failed login attempts within a set timespan, from accessing the login page, until it has been manually whitelisted again.

Industrial
+1  A: 

Obfuscation (extended comment)

This is to extend on a comment I made previously which has attracted a number of comments from users wishing to know more. As such I've split it out from the previous answer.

A large number of Web Apps are Javascript based (centric) and as such the ability for reverse engineering is huge as the client has access to the really important part of the code, which typically handles the UI and directs the backend in most of its tasks. At some point the script is likely to handle, or fire, traffic containing much of the data the App deals with, and as such it is easy to expose a lot of the underlying structure of the wider application. One often overlooked technique to protect your own IP is to obfuscate the code, hiding the true purpose of the variables, functions and objects you've written.

Obfuscation is a technique used to complicate code. Obfuscation makes code harder to understand when it is de-compiled, but it typically has no affect on the functionality of the code. Obfuscation programs can be used to protect Java programs by making them harder to reverse-engineer.

Obfuscation: http://en.wikipedia.org/wiki/Obfuscated_code

Using PHP to obfuscate your Javascript (JS) is relatively easy, you can simply create an index of terms to replace, use PHP to open your script replace those terms with their obfuscated counterparts and write the result.

Obfuscating code on the fly in PHP is also easy, though it creates some delay (depending on the size of your files/index). Obfuscating your JS on the fly means values change between visits/page views, adding an additional layer of noise, as the underlying code appears to alter every time the page is loaded.

To illustrate how one may introduce obfuscation into their app, I will examine one possible implementation, this utilises a great great PHP script, PHP Minify, which offers further benefits that will be explained.

Say we have 3 Javascript files, JS1, JS2 and JS3. These scripts have to appear in the order 1, 2, 3- and at present are linked seperately in the header of the master HTML (or PHP) file which delivers our application to the user. JS1 and JS2 are off the shelf external frameworks, such as (eg) jQuery and Prototype (ignore the fact you likely wouldnt have both in your App). JS3 is YOUR javascript, where you utilise the functionality in JS1 and JS2 using your own functions, variables, objects, classes etc. It is your intellectual property (IP) and/or must be obfuscated for legal, financial or selfish(!) reasons.

Obviously, it isnt helpful for us to obfuscate our JS, then have to develop it further. There is a reason we call our functions things like 'function_to_save_secret_info', it makes it easier when we are writing our code (though this highlights why one may want to obfuscate). The ideal would therefore be to keep our JS file that we develop, with the common sense naming, then every time a user requests the master HTML/PHP page, an obfuscated version of this is created on the fly and served. But how do we do this?

One of the best ways is using PHP Minify (http://code.google.com/p/minify/). PHP Minify has a number of advantages. One of these is the ability to group and serve scripts as a single bundle. So, instead of linking to JS1, JS2 and JS3 in our header, we use PHP Minify to set up a group which comprises these three, we link to this group in the header so only have a single reference. Advantages of this include:

  1. Less HTTP requests, faster loading and better caching (one not three)
  2. PHP Minify automatically YUI compresses scripts within groups, making load times far faster (also a type of obfuscation in its way)
  3. Easier management of our JS, altering groups is a breeze
  4. Less straight forward to inspect our code.

Once we do this, our master page links to our PHP Minify group, which is great- but we effectively are still serving the same content (all be it in a better way).

However, what we can do now is build our obfuscation routine for JS3. In the groupsConfig.php script where we define our script groups in PHP Minify, we change the group, replacing JS3.js with JS3.obfuscated.js. However, we still have the plain english version of JS3.js, JS3.obfuscated.js does not exist.

So basically our main/master HTML/PHP page links to our JS group in its header, which is a reference to PHP Minify where the group is defined as :

JS1.js
JS2.js
JS3.obfuscated.js

What we now need to do is build a key table/function to obfuscate JS3 and outputs JS3.obfuscated.js. At the simplest level, what we do is write PHP which contains the following (for example, this is not the best code):

$terms_to_obfuscate=array(
   'my_secret_function',
   'my_secret_object',
   'my_secret_variable'
)

foreach ($terms_to_obfuscate as $key => $value) {
   //replace base64_encode(md5(rand(0,999))) with whatever you want to produce an obfuscated term
   $obfuscated_terms[]=base64_encode(md5(rand(0,999)));
}

$source_js=file_get_contents('JS3.js');
$fh = fopen('JS3.obfuscated.js', 'w+') or die("can't open file");
$obfuscated_js = str_replace($terms_to_obfuscate, $obfuscated_terms, $source_js);
fwrite($fh, $obfuscated_js);
fclose($fh);

What this script will do, is open our english language version of JS3, look for the terms we want to obfuscate and replace with randomised content, writing the output to JS3.obfuscated.js. If we place this code ABOVE the group definition in PHP Minify, it will run each time the JS group is called...so each time the underlying master HTML/PHP page for our application loads, our script is randomly obfuscated. Note, this may not be the best implementation in all cases, this is illustrative only.

This is only one possible way of accomplishing obfuscation, but what we now have is compressed JS served faster to our users, randomly obfuscated, and we can still develop our script in 'plain english'. All we have to do is update our list of terms to obfuscate. There are better ways of doing this, this is meant only as an illustration and not a definite, of the general ideas behind the concept.

It is important to note, that obfuscation may only be appropriate for certain projects (it is not particularly open source by any means), and is not a total protection against reverse engineering, but should be viewed as more of a stumbling block for those less determined.

Ergo Summary
Hi Ergo. Thanks for your explanation on the obfuscation!
Industrial
No problem- let me know if I can provide more detail or explain other ideas/concepts/approaches- though this may not be the best forum for it!
Ergo Summary
-1. I don't think that obfuscation really adds another layer of security. If you really want to know what the code does you will take the time to reverse engineer it. Furthermore I disagree that bundling jQuery, Mootools and your Script into one file is good. Both jQuery and Mootools should be served from Google, because this way you have the highest chance that they are already in cache.
nikic
This is great! Thanks Ergo! Of course it adds another layer of security, it's one extra step other people have to take if they do want to reverse engineer it.
Aaron Hathaway
Ergo Summary
YSlow really tells you to bundle scripts like jQuery and Prototype and serve them from one resource, even if there is high probability that they are already in cache by their own but not in a bundled variant? Well, then they simply are wrong or you have misunderstood them.
nikic
@security: At least here in Germany any code you write is your intellectual property (exceptions are not of importance here.) Thus nobody has the right to make use of your code without your written approval. Thus there is no need to obfuscate it, if you are concerned about intellectual property. Really, I don't get why you would ever want to do this, apart from the minification effect (but you should call that either minification or compression.)
nikic
+1  A: 

Human-UNREADABLE and very secure session cookies

I believe that human-readable cookies, when they refer to session things (ie autologin) are a security threat. From the experience with PHP-Nuke, which was full (years ago, around version 7) of admin login exploits, I became to encrypt cookies. Also, since cookies are almost all transmitted in clear, I became to bind them to the IP, or better the subnet.

I18n, l10n

Localization is important. I never write human-readable text in pages, I prefer making the website in English and Italian using a shared string library. Usually I override with English words those strings that are not yet translated to avoid displaying bad string IDs

Theming support

A web application looks very professional to my eyes if user can change theme during their browsing. Theming means not only CSS, but also all the graphics (icons, buttons) must be changeable without touching the core. When I wrote phpMyBitTorrent up to 1.2 version I paid lots and lots of attention to theming, which unfortunately resulted in the same exact layout being exposed with different colours/fonts/images. The next-generation theming is templating, so you can completely change the appearence of your website. I believe it's easier to template your website when you use MVC pattern.

Cross-database support

Or, better, DB idependence. I don't like calling explicitly mysql_query() in my code. I prefer running queries onto an abstraction layer that allows me to change DBMS (ie. to SQLite or Oracle) without rewriting the code of the core components.

Logging

Logging is the best way to ease debugging and to collect useful information for FFDA (field failure data analysis). Apache log4php does the trick but you must properly instrument your code with adequate logging statements to get usable information. Lots of academic studies demonstrate that developers never achieve an adequate level of logging: they log too much or not enough, and often faults remain unclear because of missing or unclear logging statements. Unfortunately, logs grow fat with time, so you must be able to keep only those records that may help you find issues about your applications. Logs can also be used for performance purposes, but never forget the overhead logging introduces. Finally, my current senior grade thesis is about a scientifically-proven set of logging rules that are suitable for FFDA in complex applications, to which every developer should take a look.

ORM

Well, this final point is more about cross-database support. To tell you the truth, I became to use NHibernate ORM when I abandoned PHP for ASP.NET. If I had to resume PHP, I would first find a suitable ORM to avoid queries in my code.

These are my smart ideas

djechelon
+1 for the Logging part. You should elaborate on that, seems the most interesting issue and you being the expert and all. The other features are slightly too common, and point 1 seems a rebuttal missing the original topic (sessions vs privacy).
mario
The logging part is definitely complex to elaborate in these comments, and even in an answer. Too complex i we wanna talk about ffda... but if somebody more is interested we might all meet in a SO chatroom and discuss about it, so I can introduce you all to my current open source project that can be integrated into PHP applications. Next month I'll complete my thesis and I think I'll publish it (lots of benchmarks, test cases and research work) on Sourceforge together with code and documentation.
djechelon
A: 

Readable code :

Source code must be well written and easily understandable by other developers. They must have short functions and discrete classes. They must have descriptive function and class names which will result less comments. A function or a class must have single responsibility. Limited number of parameters per function. An intelligently written code requires less factoring, easy upgrading, extensibility and more.

Hanseh
+1  A: 

Whole-site SSL/TLS encryption

As the recent release of Firesheep shows, it's trivial to steal session cookies in open WiFi environments (such as offered by many libraries, hotels, and other venues) and any un-switched Ethernet segments still kicking around. (In theory, on switched ones too)

With Firesheep now making it a two-click operation for even the average Joe, whole-site encryption is no longer something to be treated as a luxury. (Along with setting the secure flag on session cookies to ensure compatible browsers won't accidentally leak them into unsecured requests) Neither the extension nor the problem are going away.

According to Adam Langly's blog, Google found that SSL/TLS isn't as bad as people tend to guess and, with a little tweaking (which they're building on in Chrome), even the latency component of setting up a connection with extra round-trips can be effectively eliminated.

Even certificate costs aren't as big an issue as many people think, given that StartCom offers free SSL certs and their root cert is already present in all major browsers.

ssokolow
I'd agree, but SSL is not without its own issues like null character spoofing for example.
Nev Stokes
True... and problems like compelled certificates. It's always a trade-off.
ssokolow
+6  A: 

One that often gets overlooked: Printable CSS. Its a pain to write but makes a lot of difference to users who want to get a printout of some data in your application.

<link href="print.css" rel="stylesheet" type="text/css" media="print"> 
Steven de Salas
+1  A: 

Using Good Naming Conventions for classes, methods and function names.

This not only makes your life easier in the long run, if the code is easily readable then any programmer can pick up where you left off.

Steven de Salas
+1  A: 

I once spent an inordinate amount of time implementing Temporary Account Locking for repeated failed attempts to enter a password. This would essentially provide users with some measure of security towards dictionary attacks but without the downside of entering "memorable information" into the database or using email to unlock the account.

Steven de Salas
+2  A: 

Internationalization/Locale Support

Provide application translations for different languages, and serve the appropriate language based on a user's locale settings.

Mobile Version

Detect a user-agent string and serve a mobile/touch-friendly version of your app. This is pretty easy to do using xhtml mobile profiles.

Use an ORM that supports multiple backends

Both as a developer and a user, its nice to be able to swap out database backends by editing a config file. That way, you can run on something like SQLite for dev/single-user uses, and something like PostgreSQL or MySQL for production.

(unobtrusive) Notification if Javascript is disabled

Ever been to Stack Overflow with JS turned off or disabled? Sometimes I forget that noscript is turned on, and SO helpfully tells me. Then I can make a decision about whether or not I want to turn it back on; but at least I know that I'm missing functionality, rather than just thinking the app is lame.

Firebug/Javascript logging

Providing lots of logging helps debug ajax issues. just doing console.log(message) in javascript will log the message to firebug. Have a Production/Development switch in your application config file that turns this on or off (have the php not generate the log messages in production mode)

Alex
+1  A: 

Using threads to make as much work in background as possible. So that user interface will never freeze. And when process takes logger than one second to complete show nice progress bar.

Hooch
+1  A: 

Auto Permalinks

With this function anyone can set it as the href of a link and it will automatically get the url of the page for easy permalinking.

//Gets the URL of the current page
//set $p to yes to echo the urlturn the url or no to re
function page_url($p)
{
    $s = empty($_SERVER["HTTPS"]) ? ''
        : ($_SERVER["HTTPS"] == "on") ? "s"
        : "";
    $protocol = strleft(strtolower($_SERVER["SERVER_PROTOCOL"]), "/").$s;
    $port = ($_SERVER["SERVER_PORT"] == "80") ? ""
        : (":".$_SERVER["SERVER_PORT"]);
    switch ($p)
        {
        case 'yes':
            echo ($protocol."://".$_SERVER['SERVER_NAME'].$port.$_SERVER['REQUEST_URI']);
            break;
        case 'no':
            return $protocol."://".$_SERVER['SERVER_NAME'].$port.$_SERVER['REQUEST_URI'];
            break;
        default:
            echo('javascript:alert(\'invalid Argument in function page_url($p)\')');
        }
}
function strleft($s1, $s2)
{
    return substr($s1, 0, strpos($s1, $s2));
}
ellisgeek