Magento goI officially signed up with Magento Go‘s Going Places plan for $25 / month and paid $99 for my SSL to be installed. It’s been 3 days and I wish I had better things to say about them.

And this is my review.

Uptime: 4.7 / 5

It’s too early to tell because I’m only with them for 10 days (in trial for 7 days). Sometimes it’s a bit slow. Magento is known to be resource-intensive. But as of now, Magento Go has been constantly up and responsive for me.

Price: 2.5 / 5

I would have given them 5 / 5 if I don’t have to pay $99 for my SSL to be installed – yes, that’s JUST for the installation service, not the SSL. You have to provide your own SSL certificate purchased from a CA to them. And this didn’t turn out to be very pleasant. I’ll come to that later.

The $1 million stimulus package that they promised to discount the monthly subscription fee by $15 for a year hasn’t been activated for me – and I contacted them about this twice – got NO responses of any kind. Waited nearly 24 hours and still no emails. So I logged back in to see the tickets. You know what I found? The tickets are all DELETED, like it’s never happened before.

What kind of support does that?

So the $1 million stimulus program is pretty much false advertising. Chances are, you won’t get it. Or you will. We are totally at their mercy.

Features: 4.1 / 5

If you are ever building an online store, once in your life time, you should use Magento Go. It simply makes sense.

After trying a few more online store builders, I think I’ll unsay the above saying.

Everything seems good, if not great. There are some parts that can be improved, such as the theming system, backup system, etc.

Their top plan for $125 / month offers a tingling of just 32GB monthly bandwidth. Anyone with decent SEO skills would easily hit that mark in half a year, especially if you’ve got lots of large images for the products. And extra bandwidth are charged $10 / GB. Pretty expensive. AND they don’t even have a bandwidth meter where you can see how much you’ve gone so far. So good luck…My tip is to use external website for hosting the product images.

Otherwise, Magento Go is simply NOT an magento go: not for growth. Be prepared to pay premium when you are locked in with them.

Support: 0.8 / 5

Appalling. If you are ready to pay $xxx per month for the top plan, you would probably be treated much better. But that’s just a theory.

I opened a total of 9 tickets, they DELETED 3 of them and responded to 3 of them.

They sent a very important message to *my* email. I didn’t receive it. Because that’s NOT my email, not even close. How hilarious is that!

Ticketing system is very hard to use. You would view the message and then click “Back” to return to the previous page to reply to it – if you have to quote something, you click “Forward” to view the message sent to you and then click “Back” again to continue writing. Very user-UNFRIENDLY ticketing system.

I posted a “Problem” message to the collaboration site (a collaboration support community to help dilute the workload of the REAL support team) about how my SSL hasn’t been installed after paying $99 and why my tickets got DELETED in the ticketing system. You know what they did? They changed the “Problem” status to “Question“. You know, it doesn’t look pretty in red.

Quick Facts about Go’s Support

People love interesting facts. Here are them.

  • A total of 3 tickets that got NO responses and simply got DELETED:
    1) A request for installing my SSL attached with my certificate files from GeoTrust
    2) A request to be enrolled in the $1 million stimulus package they promised – $15 monthly discount for next 12 billing cycles
    3) A question why my store home page doesn’t display the newest products after I added them in the backend – tried 2 different approaches but none of them worked.
  • After I complained about the SSL installation, they claimed to have sent an email to me at yanghit (@@@@@) gmail dot com. Apparently I didn’t receive it. Because that’s NOT my email, nor anything close.
  • For me, their support turnaround is about 12 hours, sometimes as long as 3 days, IF they respond at all. (I just recalculated the actual turnaround based on tickets’ and questions’ time stamps)

12 Hours Support Turnaround

Any support turnaround that’s 12 hours or longer is just unacceptable for mission critical sites such as eCommerce stores. Ordinary content sites have an eCPM of about $5 – $50 per thousand visits, however, online stores generally averages $200 – $2000 per thousand visits. Every hour of problem or down time causes substantial loss; the greater the traffic & conversion rate, the greater the damage.

People who choose Go are generally not technically oriented and would require a lot of help along the way. It would be a very painful experience for them should something get haywire yet they can’t get anything done in 12 hours.

Magento Go has got to seriously work on that.

Busted?

They got a final score of 60.5 / 100. Merely passed.

I will keep you updated on my experience with Magento Go. Even though their support isn’t the best in the world, I’d still recommend them to you. Hopefully they can see this review and give their support department a revamp.

I would love to see Magento Go becomes the go-to brand for online eCommerce solution. However, as of now, you would be better off with CE and do your own hosting, if you’ve got some technical nerves. In this case, I would like to recommend the Avalanche Magento theme.

What other folks are saying…

Seems I’m not alone on the bad experiences with Magento Go:

  1. http://www.shoppingcartsforwebsites.com/general/magento-go-review/
  2. http://www.commercestyle.com/e-commerce/magneto-sucks
  3. http://www.magentogoreview.com/list-of-magento-go-reviews~123

 

Update: I submitted a ticket and a *problem* at the collaboration site asking for a refund of the $99 SSL setup fee and they finally got back to me, addressing a question I asked 23 hours ago. After a few more tickets (each taking 2 – 3 hours for them to respond), my SSL is finally up and working.

 

{ Comments on this entry are closed }

4 Tips for Zend Studio 8 (Eclipse)

by Yang Yang on September 14, 2011

I coded a lot in Zend Studio 5.5.1, the gold old version that’s insanely popular because it made it so easy to code in PHP. As PHP evolves, ZS 5.5.1 gradually falls behind of the edge and it simply becomes imperative that you switch to the latest version of Zend Studio, the 8.

The IDE is built on Eclipse, which I have never used before. It’s great but one still needs some time to learn the curves before he or she can jump in and swim like a whale. Today I gave it a test drive and have some tips to share with you when you are just starting out with Zend Studio 8.

1. Change Default Character Encoding

Before you create your project or editing any existing PHP files, you may need to change the default encoding of the Zend Studio Workspace, or make sure it is what you usually work in.

By default, the encoding is that of the container (your operating system). I’m using a Chinese Windows 7 so the default encoding is GBK and it is everything but good because I primarily develop English projects.

For North America users, the default encoding should be ISO-8859-1. If you open up a file that’s encoded in UTF8 without changing the encoding accordingly, you may end up screwing up the file. And another victim.

To change the default encoding of Zend Studio: Windows –> Preferences –> General –> Workspace –> Text file encoding, switch to “Other” and select the encoding you normally use.

2. Display Function Parameters Hint on Demand

In 5.5.1, function parameters hint is automatically displayed when you place the cursor in the parentheses. However in 8, the hint is only automatically shown after you immediately finish typing the function name. When the focus moves away or you click anywhere else in the window, the hint disappears and if you don’t know the correct shortcut keys, you wouldn’t be able to get it back.

After a few searches, I found out the key combinations to get the parameters hint re-appear: Alt + Shift + /

Some pages say it’s Ctrl + Shift + Space but it didn’t work out for me. Maybe it’s a version thing?

3. Display Potential Function Candidates / Auto-complete Function Names

Along with the previous tip, this one is pretty important in modern IDE because they are essential in boosting one’s coding productivity. Can’t live without them.

When you are typing the function name, Zend Studio would guess what you mean and display a list of possible candidates for you to choose from.

If you want it to appear again, just place the cursor on the function name and use Alt + / to make Zend Studio makes a guess again.

4. Display All Shortcut Key Combinations

You can use a lot of shortcut keys in Zend Studio 8 to make things happen quickly and intuitively, just press Ctrl + Shift + L to bring up the key map to see the full list. Here’s a list of the commonly used commands:

zend studio 8 key assist - commonly used commands

{ Comments on this entry are closed }

Review: Why I love WiredTree hosting

by Yang Yang on September 7, 2011

wiredtreeThis is the second time I wrote a review of WiredTree and also the second time to have signed up a VPS account with them. The last time it was a 512MB VPS (VPS512) that has now been upgraded to VPS1000, doubling everything, RAM, disk storage and monthly bandwidth (tripled!), yet the price tag stays the same. Here are a few coupons that you can use to get 50% off the first 2 months should you want to sign up. The old coupons you may find elsewhere for VPS512 AND VPS 768 have been invalidated.

Okay, to the review part. After about 2 months I feel I should start using the VPS – I admit it’s a impulsive buy, just can’t resist the monster upgrade and 50% off offer – and the primary domain I provided when I signed up with it was somehow randomly picked, and now I want it changed into something else. So I sent the support team an email.

Note it’s about 2:30 A.M. CST. One of them, John, quickly responded to my help request, in less than 10 minutes, did the change and taught me how to debug DNS myself with a free tool intodns.com which by the way is a very cool tool.

The tool showed that I still needed to set the name servers for my domain at the registrar. I didn’t know how to do that so John asked me which registrar I was using, searched for the documents for me and then sent me the exact steps I needed to follow to accomplish the task.

Blah blah blah.

Things kept going wrong because I had no idea what I was doing with the DNS. I wanted to use my own name servers. It was after about 20 emails that I finally got everything in place and the domain started working. They responded to EVERY message in less than 5 minutes. And it’s about 4:00 A.M. CST.

End of story? Not.

I suddenly changed my mind that I wanted to completely re-provision the slice, using the new domain / host name in the first place, because, you know, I have obsessive disorders that knowing the old domain is still somewhere in the box makes me uneasy. I could still find the old domain listed via traceroute and reverse-IP lookup.

So I’m compelled to send another support ticket. John kindly asked me why I needed to do that and I told him I just wanted to, because I feel compelled. He then suggested me that I back up everything I can and let him know when I was ready.

After about 5 hours, the rebuild was done. I had a brand new slice that was as new as just born. Not sure how much time they spent in the 5 hours just for easing my compulsive mentality, I am sure grateful for their dedicated support.

5/5.

Find more reviews of them here: http://www.wiredtreereviews.org/

{ Comments on this entry are closed }

SEOmoz Pro Review – Bad Bad Bad

by Yang Yang on September 5, 2011

So I’ve tried the Pro version of SEOmoz, an online SEO software application, for a few days and I think I’ve got to write a review. This would turn out to be very ugly.

Many years ago the features that this system brings to the table could have been useful for the SEO novice, but today almost everything that it does, other systems do better. In addition, most of the tools you need to duplicate this product are either free, or very inexpensive.

One of its primary features is that it crawls your website weekly, and lets you know if you have any broken links or other issues with your site. If you have a Google account, you can simply register your URL with them, and use their free webmaster tools to do the same thing, and it does not cost you $99 a month like this product does. Here’s the link for Google Webmasters Tools http://www.google.com/webmasters/.

The next claim to fame that this item promotes is on-page optimization. This is a very simple concept to understand and implement. There are many articles on the internet that you can read for free that will tell you exactly how to do this. And it’s quite easy.

Essentially, it just comes down to using your primary keywords in the title and a description of that post. There are a few other things you will need to do besides what was mentioned above, but not too many. Lots of WordPress plugins have been created to help you in this regard. Simply search for ‘wordpress SEO plugins’. Some of them are totally free while some of them may charge a humble one-time fee which is exponentially lower than $99 / month. And they do the job very well.

Thirdly, it keeps an eye on your competition for you. Great, like you could not just use Google, Yahoo, or Bing to accomplish the same thing. It will also tell you all of your competitor’s backlinks for only $99 a month. If you would like to find out that very same information, there are tons of free ways to do that. Just google.

The final item they would like to impress you with is that the software will continue to improve and evolve over time. Well, for $99 a month it better, because it is pretty close to being useless right now.

The only thing I appreciate is their blog. It’s the best SEO information outlet I’ve seen. No one ever comes close. You would learn a hell lot more about SEO from there in an hour than from any other sources combined in a whole year.

For this review of SEOmoz Pro, the paid SEO productivity application, we give it a big fat zero stars, with 5 stars being the best. What else can we say about this thing, it is pretty much as bad as it gets. There is nothing that it does now, that cannot be accomplished for free with another application, or by researching a few articles on the internet. But if you don’t mind spending a *premium* price for a premium *looking* application, by all means, go ahead and sign up with it.

{ Comments on this entry are closed }

HTML: Make a Page Refresh Every xx Seconds

by Yang Yang on August 28, 2011

A quick tip for those who just started learning HTML. It’s possible to add a line of code in your HTML page so that it’s automatically refreshed every few seconds when loaded in the user’s browser.

To make the page automatically refresh itself every 60 seconds, just insert the following code in the <head></head> section of your HTML source code:

<meta http-equiv="refresh" content="60">

This would be very useful to display information that is constantly changing.

This can also be used to redirect the user from the current page to another, just specify the destination URL:

<meta http-equiv="refresh" content="30; url=http://example.com/">

Which would redirect the browser to http://example.com/ 30 seconds after finishing loading the current page.

{ Comments on this entry are closed }

online software microsoft office365Office 365 is a set of team collaboration / productivity web applications for professionals, businesses, government agencies and education institutions. It currently offers 3 different plans:

  1. For professionals and small businesses, $6 / user / month, basic features
  2. For midsize businesses and enterprises, $12 and more / user / month, advanced features
  3. For education

And I signed up with the first one which is meant for individual professionals, or businesses / organizations with up to 25 employees, at $6 / user / month. For now, I have yet to reach the end of my first month, and I have only one user in my organization which is myself. So this review would be pretty straightforward and very limited to those who are looking at the multi-user features in team collaboration / communication.

You will need a credit card to sign up. To verify the credit card, They billed me $1 when I signed up and that’s it. So I guess they bill clients at the end of every month instead of at the beginning.

What I get for $6 / month?

For $6 / month at Microsoft Office 365, I get these cool stuff:

  1. Online web applications of Microsoft Office: Word, Excel, PowerPoint and OneNote. You can create documents, edit and save them in your favorite web browser, and publish them to your team site so you and your colleagues can collaborate on them. You can also upload existing documents from your computer to Office 365.
    office-suite_thumb2
    Shared documents:
    office-365-shared-documents_thumb
    Word web app:
    office-365-word-app_thumb1
    Excel web app:
    office-365-excel-app_thumb
  2. Instant communication tool Lync 2010 enables you and your team members to send instant messages, easily set up online meetings and perform PC-to-PC audio / video calls.
  3. SharePoint Online. A public company website at http://yourcompany.sharepoint.com/ that you can edit from SharePoint. The default theme looks like this:
    sharepoint-public-website_thumb6
    You can re-create your public website by 3 editing panels, namely Home, Insert and Design:
    public-website-editor-in-sharepoint_
    From the content navigation sidebar on the left, you can add new content and remove existing content to the Recycle Bin: pages, documents, images, etc.
    And as always, you can also add your own top-level domain to SharePoint, from the Admin panel, rather than using a subdomain of sharepoint.com.
  4. Other than a public website, a private Team Site is pre-configured and ready to be edited when you (as the administrator) first sign in. This site is used as a portal for all team members where you can list contacts, shared documents, calendar entries / meeting schedules, announcements, discussion posts, and so forth. Much like editing the public website, you can freely edit the Team Site as if it’s a web page: lists, tables, images, links, etc.
    office-365-team-site_thumb2
  5. Exchange Online. Emails hosting under the domain @yourcompany.onmicrosoft.com. Likewise, you can add your own domain for the emails thus having @yourcompany.com hosted at Office 365. Everything looks like the desktop applications. You would be using a very similar online version of Outlook (web app) and it’s very intuitive. The learning curve is minimal.
    office-365-outlook_thumb3
    A calendar (Week view): (also are Day view, Work Week view and Month view)
    office-365-calendar_thumb2
    User self management:
    office-365-outlook-manage-myself-con[1]
    Organization management:
    office-365-outlook-users-management_
  6. Full administration panel and organization management features:
    office-365-administrator-panel_thumb

Some quick facts about Office 365

  1. It bills you at the end of each billing term. For instance, if you started the plan on Jan. 15th, it would first bill you $1 to verify credit card and then $6 / month each month on Feb. 15th and on.
  2. If you cancel the subscription, your subscription will remain active until the end of the billing term.
  3. You get 99.9% uptime guarantee.
  4. You can add multiple domains to your service. The default one is yourcompany.onmicrosoft.com for email and yourcompany.sharepoint.com for team site / public site.
  5. You can use different plans / multiple subscriptions under one administrator account.

Official tours

For administrators: http://office.microsoft.com/en-us/videos/office-365-for-professionals-and-small-businesses-a-tour-for-administrators-HA102653442.aspx?redir=0

For users: http://office.microsoft.com/en-us/videos/office-365-a-tour-for-users-HA102657904.aspx?redir=0

{ Comments on this entry are closed }

Buying a grandfathered .EDU domain?

by Yang Yang on June 17, 2011

Someone approached to sell me a grandfathered .EDU name. I never thought .EDU domain can be traded so I started to research a little bit. Ain’t they owned only by educational institutions of United States?

Turns out .EDU names in existence as of October 29, 2001 were more freely registered and thus many non-educational entities such as individuals and businesses owned them. However, after the management of the .EDU name space were transferred to EDUCAUSE and thus new regulations were introduced on and from October 29, 2001, .EDU names can only be distributed to certified higher educational institutions operating in the United States and cannot be traded or exchanged whatsoever. But the .EDU names created before Oct.29, 2001 remained in the hands of their original registrant. That’s why they are called “grandfathered”. They are out of the current rules but they can still exist.

While you cannot acquire a new .EDU name now – unless you purchase a small local college for couple of millions – can you get a grandfathered .EDU from its previous owner?

The owner / registrant name of the .EDU name must remain unchanged for its lifetime – no matter if it’s a grandfathered .EDU or a .EDU created after Oct. 29, 2001. So is this all a scam or is it really possible to buy a grandfathered .EDU name?

The way to trade a grandfathered .EDU is probably to trade the owner entity. You are not buying the name, instead, you are buying the business entity that owns the .EDU name. I never personally bought such an entity to get any .EDU name so I’m not saying this way would work. From my research, this is definitely a possible way. Quite a few domain name brokers said they knew such sales existed or even engaged in one.

To make sure, I approached the staff at EDUCAUSE.edu and these are the 2 official replies I got:

EDU domains cannot be given, sold, or in any other way transferred to another institution. EDU domains –even those grandfathered – must remain registered to the original registrant.

— Kate, Member Services Representative

Nothing seriously against the idea of obtaining the owner entity to obtain the .edu name. However the second reply from a Senior Policy Director comes much more serious:

Names in the .edu domain are made available to registrants under conditions and policies specified by the U.S. Department of Commerce. In particular they are not "owned" by the registrant and therefore may not be sold or otherwise transferred. The contract included in your most recent message is thus in error in stating "…that this Business Entity is the sole beneficial owner of the domain name xxxxxx.edu, that said domain name is not encumbered in any manner…".

In your original e-mail you said: "Someone approached me to sell me a grandfathered .edu name." Such a sale would be invalid regardless of any attempt to embed that sale within another transaction. EDUCAUSE will not hesitate to disable any .edu name we find to have been sold or otherwise transferred in violation of policy.

— Steven, Senior Policy Director

If you are ever buying a grandfathered .edu name, better make sure to stay low and never let EDUCAUSE knows about the deal. 😉

{ Comments on this entry are closed }

DreamHost Promo Invitations – $100 Off!

by Yang Yang on May 27, 2011

DreamHost just gave me 5 promo invitations that could be used for new accounts only. Whoever uses one of the invitation codes to sign up with them would get $100 off for a two-year plan.

Just use one of the 12-digit invitation code in the “Promo Code” field when signing up at DreamHost:

  • 737871080684
  • 599411300419
  • 843524772888
  • 995826163955
  • 163012137693

Each code can only be claimed ONCE and after it is claimed it’s gone forever. Here are some more promo codes for DreamHost:

{ Comments on this entry are closed }

Given a directory, how to display the contents (directories and files under it) of it recursively and exhaustively? Here’s the code:

$dir = '/path/to/directory'; // without trailing slash, can be absolute paths such as '/home/jim/public_html' or relative paths such as 'samples'

getDirContents($dir);

function getDirContents($dir) {
	if (is_dir($dir)) {
		$dirs = explode('/', $dir);
		$last_dir = $dirs[count($dirs) - 1];
		echo '<strong>'.$last_dir.'</strong>';
	    if ($dh = opendir($dir)) {
	    	echo '<ul>';
	        while (($file = readdir($dh)) !== false) {
	        	if ($file == '.' || $file == '..') {} else {
		        	echo '<li>';
		        	if (is_dir($dir.'/'.$file)) {
		        		getDirContents($dir.'/'.$file);
		        	} else {
		        		echo $file;
		        	}
		        	echo '</li>';
	        	}
	        }
	        echo '</ul>';
	        closedir($dh);
	    }
	}
	return false;
}

Recursively, the function getDirContents() explores every entry in the directory. If the entry is a file, it simply prints it; if it is a directory, it opens another subroutine of itself to explore that directory; and so forth, until every branch and sub-branches, etc. are all printed out.

{ Comments on this entry are closed }

I was trying to find a PHP function or class that can convert English words / nouns in plural form into their singular form so that wordcrow.com automatically detects and redirects plural lookup to the singular page. After a while searching on Google, I found this class.

This great class (Inflector) was ported from Ruby on Rails to PHP in the Akelos Framework by Akelos Media, S.L. http://www.akelos.com/.

List of Functions

Other than pluralize and singularize, this class has some more functions to convert text strings by certain standards. List below are all the functions this class has:

  • Inflector::pluralize – return the plural form of the given English word, e.g. “search” to “searches”.
  • Inflector::singularize – return the singular form of the given English word, e.g. “searches” to “search”.
  • Inflector::titleize – create a title text from the given string, e.g. “WelcomePage”, “welcome_page” or “welcome page” to “Welcome Page”.
  • Inflector::camelize – return the CamelCased text from the given string, e.g. “send_email” to “SendEmail”, “who’s online” to “WhoSOnline”.
  • Inflector::underscore – return a underscored text from the given string, e.g. “CamelCased” or “ordinary Word” to “underscored_word” that is lowercased.
  • Inflector::humanize – return a human-readable text from the given string, e.g., by replacing underscores with spaces, and by upper-casing the initial character by default.
  • Inflector::variablize – same as camelize but first char is underscored.
  • Inflector::tableize – converts a class name to its table name by rails naming conventions.
  • Inflector::classify – converts a table name to its class name by rails naming conventions.
  • Inflector::ordinalize – converts a natural number to its ordinal form in English, e.g. “2” to “2nd”, “15” to “15th”, “31” to “31st”.

Inflector Class

<?php

/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */

// +----------------------------------------------------------------------+
// | Akelos PHP Application Framework                                     |
// +----------------------------------------------------------------------+
// | Copyright (c) 2002-2006, Akelos Media, S.L.  http://www.akelos.com/  |
// | Released under the GNU Lesser General Public License                 |
// +----------------------------------------------------------------------+
// | You should have received the following files along with this library |
// | - COPYRIGHT (Additional copyright notice)                            |
// | - DISCLAIMER (Disclaimer of warranty)                                |
// | - README (Important information regarding this library)              |
// +----------------------------------------------------------------------+

/**
* Inflector for pluralize and singularize English nouns.
*
* This Inflector is a port of Ruby on Rails Inflector.
*
* It can be really helpful for developers that want to
* create frameworks based on naming conventions rather than
* configurations.
*
* It was ported to PHP for the Akelos Framework, a
* multilingual Ruby on Rails like framework for PHP that will
* be launched soon.
*
* @author Bermi Ferrer Martinez 
* @copyright Copyright (c) 2002-2006, Akelos Media, S.L. http://www.akelos.org
* @license GNU Lesser General Public License 
* @since 0.1
* @version $Revision 0.1 $
*/
class Inflector
{
    // ------ CLASS METHODS ------ //

    // ---- Public methods ---- //

    // {{{ pluralize()

    /**
    * Pluralizes English nouns.
    *
    * @access public
    * @static
    * @param    string    $word    English noun to pluralize
    * @return string Plural noun
    */
    function pluralize($word)
    {
        $plural = array(
        '/(quiz)$/i' => '1zes',
        '/^(ox)$/i' => '1en',
        '/([m|l])ouse$/i' => '1ice',
        '/(matr|vert|ind)ix|ex$/i' => '1ices',
        '/(x|ch|ss|sh)$/i' => '1es',
        '/([^aeiouy]|qu)ies$/i' => '1y',
        '/([^aeiouy]|qu)y$/i' => '1ies',
        '/(hive)$/i' => '1s',
        '/(?:([^f])fe|([lr])f)$/i' => '12ves',
        '/sis$/i' => 'ses',
        '/([ti])um$/i' => '1a',
        '/(buffal|tomat)o$/i' => '1oes',
        '/(bu)s$/i' => '1ses',
        '/(alias|status)/i'=> '1es',
        '/(octop|vir)us$/i'=> '1i',
        '/(ax|test)is$/i'=> '1es',
        '/s$/i'=> 's',
        '/$/'=> 's');

        $uncountable = array('equipment', 'information', 'rice', 'money', 'species', 'series', 'fish', 'sheep');

        $irregular = array(
        'person' => 'people',
        'man' => 'men',
        'child' => 'children',
        'sex' => 'sexes',
        'move' => 'moves');

        $lowercased_word = strtolower($word);

        foreach ($uncountable as $_uncountable){
            if(substr($lowercased_word,(-1*strlen($_uncountable))) == $_uncountable){
                return $word;
            }
        }

        foreach ($irregular as $_plural=> $_singular){
            if (preg_match('/('.$_plural.')$/i', $word, $arr)) {
                return preg_replace('/('.$_plural.')$/i', substr($arr[0],0,1).substr($_singular,1), $word);
            }
        }

        foreach ($plural as $rule => $replacement) {
            if (preg_match($rule, $word)) {
                return preg_replace($rule, $replacement, $word);
            }
        }
        return false;

    }

    // }}}
    // {{{ singularize()

    /**
    * Singularizes English nouns.
    *
    * @access public
    * @static
    * @param    string    $word    English noun to singularize
    * @return string Singular noun.
    */
    function singularize($word)
    {
        $singular = array (
        '/(quiz)zes$/i' => '\1',
        '/(matr)ices$/i' => '\1ix',
        '/(vert|ind)ices$/i' => '\1ex',
        '/^(ox)en/i' => '\1',
        '/(alias|status)es$/i' => '\1',
        '/([octop|vir])i$/i' => '\1us',
        '/(cris|ax|test)es$/i' => '\1is',
        '/(shoe)s$/i' => '\1',
        '/(o)es$/i' => '\1',
        '/(bus)es$/i' => '\1',
        '/([m|l])ice$/i' => '\1ouse',
        '/(x|ch|ss|sh)es$/i' => '\1',
        '/(m)ovies$/i' => '\1ovie',
        '/(s)eries$/i' => '\1eries',
        '/([^aeiouy]|qu)ies$/i' => '\1y',
        '/([lr])ves$/i' => '\1f',
        '/(tive)s$/i' => '\1',
        '/(hive)s$/i' => '\1',
        '/([^f])ves$/i' => '\1fe',
        '/(^analy)ses$/i' => '\1sis',
        '/((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$/i' => '\1\2sis',
        '/([ti])a$/i' => '\1um',
        '/(n)ews$/i' => '\1ews',
        '/s$/i' => '',
        );

        $uncountable = array('equipment', 'information', 'rice', 'money', 'species', 'series', 'fish', 'sheep');

        $irregular = array(
        'person' => 'people',
        'man' => 'men',
        'child' => 'children',
        'sex' => 'sexes',
        'move' => 'moves');

        $lowercased_word = strtolower($word);
        foreach ($uncountable as $_uncountable){
            if(substr($lowercased_word,(-1*strlen($_uncountable))) == $_uncountable){
                return $word;
            }
        }

        foreach ($irregular as $_plural=> $_singular){
            if (preg_match('/('.$_singular.')$/i', $word, $arr)) {
                return preg_replace('/('.$_singular.')$/i', substr($arr[0],0,1).substr($_plural,1), $word);
            }
        }

        foreach ($singular as $rule => $replacement) {
            if (preg_match($rule, $word)) {
                return preg_replace($rule, $replacement, $word);
            }
        }

        return $word;
    }

    // }}}
    // {{{ titleize()

    /**
    * Converts an underscored or CamelCase word into a English
    * sentence.
    *
    * The titleize function converts text like "WelcomePage",
    * "welcome_page" or  "welcome page" to this "Welcome
    * Page".
    * If second parameter is set to 'first' it will only
    * capitalize the first character of the title.
    *
    * @access public
    * @static
    * @param    string    $word    Word to format as tile
    * @param    string    $uppercase    If set to 'first' it will only uppercase the
    * first character. Otherwise it will uppercase all
    * the words in the title.
    * @return string Text formatted as title
    */
    function titleize($word, $uppercase = '')
    {
        $uppercase = $uppercase == 'first' ? 'ucfirst' : 'ucwords';
        return $uppercase(Inflector::humanize(Inflector::underscore($word)));
    }

    // }}}
    // {{{ camelize()

    /**
    * Returns given word as CamelCased
    *
    * Converts a word like "send_email" to "SendEmail". It
    * will remove non alphanumeric character from the word, so
    * "who's online" will be converted to "WhoSOnline"
    *
    * @access public
    * @static
    * @see variablize
    * @param    string    $word    Word to convert to camel case
    * @return string UpperCamelCasedWord
    */
    function camelize($word)
    {
        return str_replace(' ','',ucwords(preg_replace('/[^A-Z^a-z^0-9]+/',' ',$word)));
    }

    // }}}
    // {{{ underscore()

    /**
    * Converts a word "into_it_s_underscored_version"
    *
    * Convert any "CamelCased" or "ordinary Word" into an
    * "underscored_word".
    *
    * This can be really useful for creating friendly URLs.
    *
    * @access public
    * @static
    * @param    string    $word    Word to underscore
    * @return string Underscored word
    */
    function underscore($word)
    {
        return  strtolower(preg_replace('/[^A-Z^a-z^0-9]+/','_',
        preg_replace('/([a-zd])([A-Z])/','1_2',
        preg_replace('/([A-Z]+)([A-Z][a-z])/','1_2',$word))));
    }

    // }}}
    // {{{ humanize()

    /**
    * Returns a human-readable string from $word
    *
    * Returns a human-readable string from $word, by replacing
    * underscores with a space, and by upper-casing the initial
    * character by default.
    *
    * If you need to uppercase all the words you just have to
    * pass 'all' as a second parameter.
    *
    * @access public
    * @static
    * @param    string    $word    String to "humanize"
    * @param    string    $uppercase    If set to 'all' it will uppercase all the words
    * instead of just the first one.
    * @return string Human-readable word
    */
    function humanize($word, $uppercase = '')
    {
        $uppercase = $uppercase == 'all' ? 'ucwords' : 'ucfirst';
        return $uppercase(str_replace('_',' ',preg_replace('/_id$/', '',$word)));
    }

    // }}}
    // {{{ variablize()

    /**
    * Same as camelize but first char is underscored
    *
    * Converts a word like "send_email" to "sendEmail". It
    * will remove non alphanumeric character from the word, so
    * "who's online" will be converted to "whoSOnline"
    *
    * @access public
    * @static
    * @see camelize
    * @param    string    $word    Word to lowerCamelCase
    * @return string Returns a lowerCamelCasedWord
    */
    function variablize($word)
    {
        $word = Inflector::camelize($word);
        return strtolower($word[0]).substr($word,1);
    }

    // }}}
    // {{{ tableize()

    /**
    * Converts a class name to its table name according to rails
    * naming conventions.
    *
    * Converts "Person" to "people"
    *
    * @access public
    * @static
    * @see classify
    * @param    string    $class_name    Class name for getting related table_name.
    * @return string plural_table_name
    */
    function tableize($class_name)
    {
        return Inflector::pluralize(Inflector::underscore($class_name));
    }

    // }}}
    // {{{ classify()

    /**
    * Converts a table name to its class name according to rails
    * naming conventions.
    *
    * Converts "people" to "Person"
    *
    * @access public
    * @static
    * @see tableize
    * @param    string    $table_name    Table name for getting related ClassName.
    * @return string SingularClassName
    */
    function classify($table_name)
    {
        return Inflector::camelize(Inflector::singularize($table_name));
    }

    // }}}
    // {{{ ordinalize()

    /**
    * Converts number to its ordinal English form.
    *
    * This method converts 13 to 13th, 2 to 2nd ...
    *
    * @access public
    * @static
    * @param    integer    $number    Number to get its ordinal value
    * @return string Ordinal representation of given string.
    */
    function ordinalize($number)
    {
        if (in_array(($number % 100),range(11,13))){
            return $number.'th';
        }else{
            switch (($number % 10)) {
                case 1:
                return $number.'st';
                break;
                case 2:
                return $number.'nd';
                break;
                case 3:
                return $number.'rd';
                default:
                return $number.'th';
                break;
            }
        }
    }

    // }}}

}

?>

Usage Examples

/* Singular to plural / Plural to singular */

echo Inflector::pluralize('search'); // outputs searches
echo Inflector::singularize('cases'); // outputs case
echo Inflector::pluralize('query'); // outputs queries
echo Inflector::singularize('queries'); // outputs query
echo Inflector::pluralize('ability'); // outputs abilities
echo Inflector::singularize('abilities'); // outputs ability
echo Inflector::pluralize('analysis'); // outputs analyses
echo Inflector::singularize('analyses'); // outputs analysis
echo Inflector::pluralize('information'); // outputs information
echo Inflector::singularize('information'); // outputs information
echo Inflector::pluralize('mouse'); // outputs mice
echo Inflector::singularize('mice'); // outputs mouse

/* CamelCase to underscore / underscore to CamelCase */

echo Inflector::underscore('SpecialGuest'); // outputs special_guest
echo Inflector::camelize('special_guest'); // outputs SpecialGuest
echo Inflector::underscore('FreeBSD'); // outputs free_bsd
echo Inflector::camelize('free_bsd'); // outputs FreeBsd
echo Inflector::underscore('HTML'); // outputs html
echo Inflector::camelize('html'); // outputs Html

/* Underscore to "human-text" / "Human-text" to Underscore */

echo Inflector::humanize('employee_salary'); // outputs Employee salary
echo Inflector::underscore('Employee salary'); // outputs employee_salary

/* Examples of titleize() */

echo Inflector::titleize('ActiveRecord'); // outputs Active Record
echo Inflector::titleize('action web service'); // outputs Action Web Service

/* Examples of ordinalize() */

echo Inflector::ordinalize(1); // outputs 1st
echo Inflector::ordinalize(2); // outputs 2nd
echo Inflector::ordinalize(3); // outputs 3rd
echo Inflector::ordinalize(4); // outputs 4th
echo Inflector::ordinalize(5); // outputs 5th
echo Inflector::ordinalize(20); // outputs 20th
echo Inflector::ordinalize(21); // outputs 21st

{ Comments on this entry are closed }