Archive for 'PHP'

Installing APC Opcode cache

Today while trying to install the APC Opcode cache on my WiredTree account, I encountered the error “Cannot run code from this file in conjunction with non encoded files in…”  As it turns out, the APC Opcode cache has an incompatibility with Zend Optimizer.  The solution was to disable the Zend Optimizer (Which wasn’t really optimizing anything to begin with).  Just open your php.ini file and comment out the lines that look like the following:

zend_extension_manager.optimizer=/usr/local/Zend/lib/Optimizer-3.3.3
zend_extension_manager.optimizer_ts=/usr/local/Zend/lib/Optimizer_TS-3.3.3
zend_optimizer.version=3.3.3
zend_extension=/usr/local/Zend/lib/ZendExtensionManager.so
zend_extension_ts=/usr/local/Zend/lib/ZendExtensionManager_TS.so

Integrating Fed Ex Ship Manager with Magento

If you’ve ever wanted to get your shipping a bit more automated, look no further than the good folks on the Magento community forums. “mjohnsonperl” was good enough to write an article on how to do just that, using FedEx Ship Manager. I’ve added some code to his original query to bring the ship method over to Ship Manager as well. Below is the complete, modified query.

BTW, if you’ve ever tried to write/modify a query for a database built using EAV data modeling… well, you get to be friends with Jack Daniels really fast, because that’s the only way to understand the data when looking at ad hoc queries. Thank goodness for Morphine… the band. Look them up in iTunes.

Original FedEx Ship Manager Article

Original MySQL View for Ship Manager

create view vi_sales_order_shipping as
select   so.increment_id as 'order_no',
        (    select xsov.value
            from sales_order_varchar xsov
            inner join eav_attribute xea on xsov.attribute_id = xea.attribute_id
            where    xsov.entity_id = so.entity_id and
                    xea.attribute_code = 'customer_email'
        ) as 'customer_email',

        /* --- SHIP TO ADDRESS --- */

        (   select xsoev.value
            from sales_order_int soi_sa
            inner join eav_attribute soi_sa_ea on soi_sa.attribute_id = soi_sa_ea.attribute_id
            	and soi_sa_ea.attribute_code = 'shipping_address_id'
            inner join sales_order_entity_varchar xsoev on xsoev.entity_id = soi_sa.value
            inner join eav_attribute xea on xsoev.attribute_id = xea.attribute_id
            where    so.entity_id = soi_sa.entity_id and
                    xea.attribute_code = 'firstname'
        ) as 'shipto_firstname',
        (   select xsoev.value
            from sales_order_int soi_sa
            inner join eav_attribute soi_sa_ea on soi_sa.attribute_id = soi_sa_ea.attribute_id
            	and soi_sa_ea.attribute_code = 'shipping_address_id'
            inner join sales_order_entity_varchar xsoev on xsoev.entity_id = soi_sa.value
            inner join eav_attribute xea on xsoev.attribute_id = xea.attribute_id
            where    so.entity_id = soi_sa.entity_id and
                    xea.attribute_code = 'lastname'
        ) as 'shipto_lastname',
        concat(
            (       select xsoev.value
                from sales_order_int soi_sa
                inner join eav_attribute soi_sa_ea on soi_sa.attribute_id = soi_sa_ea.attribute_id
                	and soi_sa_ea.attribute_code = 'shipping_address_id'
                inner join sales_order_entity_varchar xsoev on xsoev.entity_id = soi_sa.value
                inner join eav_attribute xea on xsoev.attribute_id = xea.attribute_id
                where    so.entity_id = soi_sa.entity_id and
                        xea.attribute_code = 'firstname'
            ), ' ',
            (       select xsoev.value
                from sales_order_int soi_sa
                inner join eav_attribute soi_sa_ea on soi_sa.attribute_id = soi_sa_ea.attribute_id
                	and soi_sa_ea.attribute_code = 'shipping_address_id'
                inner join sales_order_entity_varchar xsoev on xsoev.entity_id = soi_sa.value
                inner join eav_attribute xea on xsoev.attribute_id = xea.attribute_id
                where    so.entity_id = soi_sa.entity_id and
                        xea.attribute_code = 'lastname'
            )
        ) as 'shipto_contact_name',
        (   select xsoev.value
            from sales_order_int soi_sa
            inner join eav_attribute soi_sa_ea on soi_sa.attribute_id = soi_sa_ea.attribute_id
            	and soi_sa_ea.attribute_code = 'shipping_address_id'
            inner join sales_order_entity_varchar xsoev on xsoev.entity_id = soi_sa.value
            inner join eav_attribute xea on xsoev.attribute_id = xea.attribute_id
            where    so.entity_id = soi_sa.entity_id and
                    xea.attribute_code = 'company'
        ) as 'shipto_company',
        (   select substring_index(xsoev.value, char(10), 1 )
            from sales_order_int soi_sa
            inner join eav_attribute soi_sa_ea on soi_sa.attribute_id = soi_sa_ea.attribute_id
            	and soi_sa_ea.attribute_code = 'shipping_address_id'
            inner join sales_order_entity_varchar xsoev on xsoev.entity_id = soi_sa.value
            inner join eav_attribute xea on xsoev.attribute_id = xea.attribute_id
            where    so.entity_id = soi_sa.entity_id and
                    xea.attribute_code = 'street'
        ) as 'shipto_street_line_1',
        (   select case when xsoev.value like concat('%', char(10), '%')
        	then substring_index(xsoev.value, char(10), -1 ) else '' end
            from sales_order_int soi_sa
            inner join eav_attribute soi_sa_ea on soi_sa.attribute_id = soi_sa_ea.attribute_id
            	and soi_sa_ea.attribute_code = 'shipping_address_id'
            inner join sales_order_entity_varchar xsoev on xsoev.entity_id = soi_sa.value
            inner join eav_attribute xea on xsoev.attribute_id = xea.attribute_id
            where    so.entity_id = soi_sa.entity_id and                    xea.attribute_code = 'street'
        ) as 'shipto_street_line_2',
        (   select xsoev.value
            from sales_order_int soi_sa
            inner join eav_attribute soi_sa_ea on soi_sa.attribute_id = soi_sa_ea.attribute_id
            	and soi_sa_ea.attribute_code = 'shipping_address_id'
            inner join sales_order_entity_varchar xsoev on xsoev.entity_id = soi_sa.value
            inner join eav_attribute xea on xsoev.attribute_id = xea.attribute_id
            where    so.entity_id = soi_sa.entity_id and                    xea.attribute_code = 'city'
        ) as 'shipto_city',
        (   select xsoev.value
            from sales_order_int soi_sa
            inner join eav_attribute soi_sa_ea on soi_sa.attribute_id = soi_sa_ea.attribute_id
            	and soi_sa_ea.attribute_code = 'shipping_address_id'
            inner join sales_order_entity_varchar xsoev on xsoev.entity_id = soi_sa.value
            inner join eav_attribute xea on xsoev.attribute_id = xea.attribute_id
            where    so.entity_id = soi_sa.entity_id and                    xea.attribute_code = 'region'
        ) as 'shipto_region',
        (   select     dcr.code
            from sales_order_int soi_sa
            inner join eav_attribute soi_sa_ea on soi_sa.attribute_id = soi_sa_ea.attribute_id
            	and soi_sa_ea.attribute_code = 'shipping_address_id'
            inner join sales_order_entity_int xsoev on xsoev.entity_id = soi_sa.value
            inner join eav_attribute xea on xsoev.attribute_id = xea.attribute_id
            inner join directory_country_region dcr on dcr.region_id = xsoev.value
            where     so.entity_id = soi_sa.entity_id and xea.attribute_code = 'region_id'
        ) as 'shipto_region_code',
        (   select xsoev.value
            from sales_order_int soi_sa
            inner join eav_attribute soi_sa_ea on soi_sa.attribute_id = soi_sa_ea.attribute_id
            	and soi_sa_ea.attribute_code = 'shipping_address_id'
            inner join sales_order_entity_varchar xsoev on xsoev.entity_id = soi_sa.value
            inner join eav_attribute xea on xsoev.attribute_id = xea.attribute_id
            where    so.entity_id = soi_sa.entity_id and
                    xea.attribute_code = 'postcode'
        ) as 'shipto_postcode',
        (   select xsoev.value
            from sales_order_int soi_sa
            inner join eav_attribute soi_sa_ea on soi_sa.attribute_id = soi_sa_ea.attribute_id
            	and soi_sa_ea.attribute_code = 'shipping_address_id'
            inner join sales_order_entity_varchar xsoev on xsoev.entity_id = soi_sa.value
            inner join eav_attribute xea on xsoev.attribute_id = xea.attribute_id
            where    so.entity_id = soi_sa.entity_id and
                    xea.attribute_code = 'country_id'
        ) as 'shipto_country_id',
        (    select xsoev.value
            from sales_order_int soi_sa
            inner join eav_attribute soi_sa_ea on soi_sa.attribute_id = soi_sa_ea.attribute_id
            	and soi_sa_ea.attribute_code = 'shipping_address_id'
            inner join sales_order_entity_varchar xsoev on xsoev.entity_id = soi_sa.value
            inner join eav_attribute xea on xsoev.attribute_id = xea.attribute_id
            where    so.entity_id = soi_sa.entity_id and
                    xea.attribute_code = 'telephone'
        ) as 'shipto_telephone',

        /* --- BILL TO ADDRESS --- */

        (   select xsoev.value
            from sales_order_int soi_sa
            inner join eav_attribute soi_sa_ea on soi_sa.attribute_id = soi_sa_ea.attribute_id
            	and soi_sa_ea.attribute_code = 'billing_address_id'
            inner join sales_order_entity_varchar xsoev on xsoev.entity_id = soi_sa.value
            inner join eav_attribute xea on xsoev.attribute_id = xea.attribute_id
            where    so.entity_id = soi_sa.entity_id and
                    xea.attribute_code = 'firstname'
        ) as 'billto_firstname',
        (   select xsoev.value
            from sales_order_int soi_sa
            inner join eav_attribute soi_sa_ea on soi_sa.attribute_id = soi_sa_ea.attribute_id
            	and soi_sa_ea.attribute_code = 'billing_address_id'
            inner join sales_order_entity_varchar xsoev on xsoev.entity_id = soi_sa.value
            inner join eav_attribute xea on xsoev.attribute_id = xea.attribute_id
            where    so.entity_id = soi_sa.entity_id and
                    xea.attribute_code = 'lastname'
        ) as 'billto_lastname',
        concat(
            (       select xsoev.value
                from sales_order_int soi_sa
                inner join eav_attribute soi_sa_ea on soi_sa.attribute_id = soi_sa_ea.attribute_id
                	and soi_sa_ea.attribute_code = 'billing_address_id'
                inner join sales_order_entity_varchar xsoev on xsoev.entity_id = soi_sa.value
                inner join eav_attribute xea on xsoev.attribute_id = xea.attribute_id
                where    so.entity_id = soi_sa.entity_id and
                        xea.attribute_code = 'firstname'
            ), ' ',
            (       select xsoev.value
                from sales_order_int soi_sa
                inner join eav_attribute soi_sa_ea on soi_sa.attribute_id = soi_sa_ea.attribute_id
                	and soi_sa_ea.attribute_code = 'billing_address_id'
                inner join sales_order_entity_varchar xsoev on xsoev.entity_id = soi_sa.value
                inner join eav_attribute xea on xsoev.attribute_id = xea.attribute_id
                where    so.entity_id = soi_sa.entity_id and
                        xea.attribute_code = 'lastname'
            )
        ) as 'billto_contact_name',
        (   select xsoev.value
            from sales_order_int soi_sa
            inner join eav_attribute soi_sa_ea on soi_sa.attribute_id = soi_sa_ea.attribute_id
            	and soi_sa_ea.attribute_code = 'billing_address_id'
            inner join sales_order_entity_varchar xsoev on xsoev.entity_id = soi_sa.value
            inner join eav_attribute xea on xsoev.attribute_id = xea.attribute_id
            where    so.entity_id = soi_sa.entity_id and
                    xea.attribute_code = 'company'
        ) as 'billto_company',
        (   select substring_index(xsoev.value, char(10), 1 )
            from sales_order_int soi_sa
            inner join eav_attribute soi_sa_ea on soi_sa.attribute_id = soi_sa_ea.attribute_id
            	and soi_sa_ea.attribute_code = 'billing_address_id'
            inner join sales_order_entity_varchar xsoev on xsoev.entity_id = soi_sa.value
            inner join eav_attribute xea on xsoev.attribute_id = xea.attribute_id
            where    so.entity_id = soi_sa.entity_id and
                    xea.attribute_code = 'street'
        ) as 'billto_street_line_1',
        (   select case when xsoev.value like concat('%', char(10), '%')
        	then substring_index(xsoev.value, char(10), -1 ) else '' end
            from sales_order_int soi_sa
            inner join eav_attribute soi_sa_ea on soi_sa.attribute_id = soi_sa_ea.attribute_id
            	and soi_sa_ea.attribute_code = 'billing_address_id'
            inner join sales_order_entity_varchar xsoev on xsoev.entity_id = soi_sa.value
            inner join eav_attribute xea on xsoev.attribute_id = xea.attribute_id
            where    so.entity_id = soi_sa.entity_id and                    xea.attribute_code = 'street'
        ) as 'billto_street_line_2',
        (   select xsoev.value
            from sales_order_int soi_sa
            inner join eav_attribute soi_sa_ea on soi_sa.attribute_id = soi_sa_ea.attribute_id
            	and soi_sa_ea.attribute_code = 'billing_address_id'
            inner join sales_order_entity_varchar xsoev on xsoev.entity_id = soi_sa.value
            inner join eav_attribute xea on xsoev.attribute_id = xea.attribute_id
            where    so.entity_id = soi_sa.entity_id and                    xea.attribute_code = 'city'
        ) as 'billto_city',
        (   select xsoev.value
            from sales_order_int soi_sa
            inner join eav_attribute soi_sa_ea on soi_sa.attribute_id = soi_sa_ea.attribute_id
            	and soi_sa_ea.attribute_code = 'billing_address_id'
            inner join sales_order_entity_varchar xsoev on xsoev.entity_id = soi_sa.value
            inner join eav_attribute xea on xsoev.attribute_id = xea.attribute_id
            where    so.entity_id = soi_sa.entity_id and                    xea.attribute_code = 'region'
        ) as 'billto_region',
        (   select     dcr.code
            from sales_order_int soi_sa
            inner join eav_attribute soi_sa_ea on soi_sa.attribute_id = soi_sa_ea.attribute_id
            	and soi_sa_ea.attribute_code = 'billing_address_id'
            inner join sales_order_entity_int xsoev on xsoev.entity_id = soi_sa.value
            inner join eav_attribute xea on xsoev.attribute_id = xea.attribute_id
            inner join directory_country_region dcr on dcr.region_id = xsoev.value
            where     so.entity_id = soi_sa.entity_id and xea.attribute_code = 'region_id'
        ) as 'billto_region_code',
        (   select xsoev.value
            from sales_order_int soi_sa
            inner join eav_attribute soi_sa_ea on soi_sa.attribute_id = soi_sa_ea.attribute_id
            	and soi_sa_ea.attribute_code = 'billing_address_id'
            inner join sales_order_entity_varchar xsoev on xsoev.entity_id = soi_sa.value
            inner join eav_attribute xea on xsoev.attribute_id = xea.attribute_id
            where    so.entity_id = soi_sa.entity_id and
                    xea.attribute_code = 'postcode'
        ) as 'billto_postcode',
        (   select xsoev.value
            from sales_order_int soi_sa
            inner join eav_attribute soi_sa_ea on soi_sa.attribute_id = soi_sa_ea.attribute_id
            	and soi_sa_ea.attribute_code = 'billing_address_id'
            inner join sales_order_entity_varchar xsoev on xsoev.entity_id = soi_sa.value
            inner join eav_attribute xea on xsoev.attribute_id = xea.attribute_id
            where    so.entity_id = soi_sa.entity_id and
                    xea.attribute_code = 'country_id'
        ) as 'billto_country_id',
        (    select xsoev.value
            from sales_order_int soi_sa
            inner join eav_attribute soi_sa_ea on soi_sa.attribute_id = soi_sa_ea.attribute_id
            	and soi_sa_ea.attribute_code = 'billing_address_id'
            inner join sales_order_entity_varchar xsoev on xsoev.entity_id = soi_sa.value
            inner join eav_attribute xea on xsoev.attribute_id = xea.attribute_id
            where    so.entity_id = soi_sa.entity_id and
                    xea.attribute_code = 'telephone'
        ) as 'billto_telephone',

        /* --- ORDER DETAILS --- */
	( select xsov.value
	from sales_order_varchar xsov
	inner join eav_attribute xea on xsov.attribute_id = xea.attribute_id
	where xsov.entity_id = so.entity_id and
	xea.attribute_code = 'shipping_description'
	) as 'order_ship_description', 

	( select xsov.value
	from sales_order_varchar xsov
	inner join eav_attribute xea on xsov.attribute_id = xea.attribute_id
	where xsov.entity_id = so.entity_id and
	xea.attribute_code = 'shipping_method'
	) as 'order_ship_method',

        (   select xsod.value
            from sales_order_decimal xsod
            inner join eav_attribute xea on xsod.attribute_id = xea.attribute_id
            where    xsod.entity_id = so.entity_id and
                    xea.attribute_code = 'weight'
        ) as 'order_weight',
        so.subtotal as 'order_subtotal',
        so.grand_total as 'order_total'
from sales_order so
/*where so.increment_id = '100000412';*/
/*use the above to filter by a specific order number*/

My Love Hate Relationship with Panic Coda

My open letter to Panic Software:
I’ve been using Panic Software’s Coda for several years now. As a web development program, it’s light years ahead of anything else out there. I can vaguely remember the dark days before Coda, there was a program called.. let me see if I can remember… oh yeah, BBEdit.

BBEdit was the de-facto standard text editor for the Mac. I was using it in Mac OS 9, and I still used it in Mac OS X. Back then, you’d build a web site locally, the upload it using your FTP client. Later, Panic Software introduced Transmit, a sexy FTP client that had it all. In fact, I could double click a file on an FTP share and it would open automagically into BBEdit. Then, in BBEdit I could hit Command-S to save the file, and Transmit would re-upload it. Remarkable. It totally changed how I worked on web sites.

Fast forward to 2007. That same little company who produced Transmit, an FTP app that changed the way web developers work, introduced something all together new… Coda. Coda was everything. It could FTP, it could SFTP, it could Edit PHP, HTML, CSS, Text, it would make you a pot of coffee in the morning and the afternoon. It had built in documentation, it had autocomplete, it had built in preview for your pages, it had built in terminal for shell access. Coda was the program that made every Mac web developer wonder what they’d been doing for the past 10 years without it.

Now, fast forward to the present day. It’s almost 2010 and Coda hasn’t changed since 2007. Sure there have been bug fixes here and there, but no new features. No changes. Nothing for three years. (Yes, they did create the Plugins system. Yawn. Plugins are VERY limited as to how they can interact with the Coda core program. Very limited.)

My inspiration for this article is a css file that I just lost while editing in Coda. If you’re a regular Coda user like me (Coda is open more hours in a day than Photoshop on my system) then you’ve no doubt hit this snag at some point. You’re cruising along, working on your files, you hit “SAVE” to save a file back to the FTP, Coda seems to hang. So you wait a few minutes.. still hanging. Hmm. So you hit force quit and find that Coda is not responding… so you kill it. You relaunch it and discover that your precious CSS file is empty. That’s right… the file is still there on the FTP, but it’s empty… If you’re a web developer, and this has happened to you, you know that feeling that you get in your stomach. Like you’ve just been punched in the gut. Now this has happened only 3 times in less than 3 years of using Coda, but that’s too much.

So this brings me to my point. In three years, why has Panic not made any real changes to Coda? Is Coda 2.0 hiding in the depths of Panic? Is it going to change the world like the first version did? Is it going to fix the aforementioned problem with loosing complete files? Will it allow you to organize your web sites into folders? Willing include code collapsing? Will it tie into Apples Time Machine API so as to include an automatic versioning and save a copy every minute? Will it make coffee and donuts?

I hate to bitch and moan about something without offering a solution, so I have one: Panic needs to charge more for CODA. A lot more. Charge $199, or $249. It’s worth it. There’s not a web designer out there using Coda who thinks MS Office or Photoshop is worth more than Coda. Hell, I paid Adobe $499 for a crappy Photoshop CS4 update that does absolutely nothing that CS3 didn’t already do. Talk about feeling like a first class heel. I give Adobe my money almost every year for a worthless update that offers no real forward progress. So Panic, why don’t you come out with an update to Coda every so often that offers some new features? You could make some money. Think about it.

Fact of the matter is… even with all it’s problems, Coda is still the best thing out there. I’m going to go rebuild my lost CSS file now. Ugh.

Fixing 500 Errors on Media Temple DV 3.5 Running FastCGI

I’ve gotten a lot of questions about 500 errors on Media Temple. I’m currently running a Media Temple DV 3.5 Extreme server with Magento. It’s been quite a process getting things tuned up, but I’ve got the performance to an acceptable level now. See for yourself… http://www.bcsports.com/. When I first switched to the FastCGI version of PHP, there were a few issues to deal with, the most important were the sporadic 500 errors that would pop up.

You know, it was odd, I thought I had everything running smoothly, but my client would call me and say “I’m getting a 500 error right now”. I’d hit the server myself and … no problems. Pages loaded fine. So I decided to load test the server with a service that hits the server from many locations around the world. Whamo… 500 errors popping up. I immediately switched back to mod_php and ran it that way for a while. It was much slower, but more reliable.

So after a while, I realized that I needed the performance of FastCGI to run Magento with a reasonable amount of speed. I spent some additional time looking into the source of the 500 errors, and through some tuning and testing, I believe I’ve got it nailed. It seems that the timeout settings were causing the CGI to die before PHP got a chance to respond. So, without further ado, below is the configuration that cured my server…

1. With your favorite text editor, edit /etc/httpd/conf.d/fcgid.conf to the following:

# added by psa-mod-fcgid-configurator
LoadModule fcgid_module /usr/lib/httpd/modules/mod_fcgid.so

<IfModule mod_fcgid.c>
  SocketPath /var/lib/httpd/fcgid/sock
</IfModule>

# added by psa-mod-fcgid-configurator
<IfModule mod_fcgid.c>
IdleTimeout 300
ProcessLifeTime 10000
MaxProcessCount 64
DefaultMaxClassProcessCount 15
IPCConnectTimeout 600
IPCCommTimeout 600
</IfModule>

2. Restart apache by running “/etc/init.d/httpd restart”

Run PHP as a FastCGI on a MediaTemple DV 3.5 Server

If you found this article, you probably have a reason to want to move away from mod_php.  Mine was because I was trying to operate a Magento install on a MediaTemple DV 3.5 server with periodic problems and outages.  The symptoms were that the site would slow down tremendously, to the point that requests would just hang… no response from the server.  Eventually, I was able to look at server resources in the Plesk interface and this is what I saw:

load_average_100

The CPU usage was through the roof.  And it stayed there too.  In case you’re not familiar with Plesk, you can find the CPU usage by logging into Plesk, then going to Virtuozzo >> Resources.  So I performed various upgrades to the server to try and get this system under control.  First, I installed APC (Alternative PHP Cache) which is a handy little program that caches the compiled PHP opcode to save the computer some processor cycles.  That helped a bit, but still didn’t solve the periodic problem of server slowdowns.  I decided to install php as a FastCGI to free up some resources.  Doing so on Media Temple was not as easy as I’d have liked, and the lack of documentation made it a bit of a challenge.  Here are the steps I took:

  1. You must enable root access on your Media Temple DV account.  This is required, since some of the files you’ll be creating need to go into directories where only root is allowed. Media Temple has a knowledgebase article on the subject.  Basically you click a button on your Media Temple Account Center page.
  2. Enable CGI and FastCGI on the domain where this will be applied.  Here’s how: 1. Log into Plesk  2. Click on Domains on the left side   3. Click the blue VR icon next to your domain   4. Under services check the boxes next to CGI support and FastCGI support  5. Click the OK button at the bottom
  3. Now your domain is ready to run FastCGI.  Log into your server via SSH as root.
  4. Run the commands below (without the quotes.  replace yourdomain.com with your actual domain name)
  5. “cd /var/www/vhosts/yourdomain.com/”
  6. “cp /usr/bin/php-cgi bin/”
  7. “chown -R username:psacln bin” (replace username with your FTP login name for this domain)
  8. “vi conf/vhost.conf”  (using vi or your favorite editor, create this file)
    AddHandler fcgid-script .php

    FCGIWrapper /var/www/vhosts/yourdomain.com/bin/php-cgi .php
    Options ExecCGI
    allow from all
  9. Save the file, then if you’re using SSL on this server, run this command: “cp conf/vhost.conf conf/vhost_ssl.conf”
  10. Now, restart the server: “/etc/init.d/httpd restart”
  11. If you want to see if it really worked, you can create a php page on your server with the line phpinfo();  Look through the page and you should see “Server API: CGI/FastCGI”  if so, you’re in business.
  12. Good luck.

UPDATE: Due to popular demand, I’ve written an article on how to cure 500 errors using this configuration. Click here to read.

Magento as a Supply Chain Application

Here are some random thoughts I’ve had about turning Magento into a Supply Chain application. The way I see it, Magento is only a few steps from being a supply chain application. With the addition of Inventory management, Purchasing and a handful of other modules, Magento would have all the flexibility needed to run a small business.

Look at it from this standpoint… as a Point of Sale system, you could use the Sales Order Entry system on the back-end to allow your checkout clerks to enter orders. That could be enhanced by interacting with a bar code scanner, however since there are USB scanners already available, a simple AJAX script would get the scanned numbers to enter products.

Another consideration is Magento’s lack of multiple payments on a single sales order. If you’ve ever worked retail, you know this comes up. A customer might ask to pay $50 cash and put the rest on his credit card… or split the purchase between two credit cards.

Purchasing would allow admins to write purchase orders and manage the receipt of goods. Come to think of it, this might be a feature best left to QuickBooks or similar (for small business).

Inventory management is a must. Multiple warehouses, store inventory, purchased inventory, received inventory. Going a step further, adding warehouse management to track inventory locations would make this system even better.

PHP code to check if a file is over 5 minutes old

Today I had a need to check the modification date of a file, and see if it was more than 5 minutes old. Here is the code I wrote for this:

(Update: I got a comment from my good friend Patrick Nelson with code to do this in fewer lines, shown below)

$file_time = filemtime("some_file_path.txt");
$expires = strtotime("-5 minutes");
if ($file_time &lt; $expires){
   // do something
}

MVC on PHP and a quick comparison to Ruby on Rails

I’ve read a few articles written by PHP developers who feel that Ruby on Rails represents the latest and greatest in web development languages. After learning about Ruby a bit more, I realize that it’s no better than using PHP with an MVC framework. With PHP, you can choose your favorite MVC framework. Depending on your needs, with PHP you can choose CodeIgniter, Zend Framework, CakePHP, MicroMVC or a variety of others. If you choose Ruby, you can also choose your favorite framework, however Rails is the most prominent and the one that most books and publications cover.

I can think of some advantages and disadvantages to having your choice of frameworks. Advantage — You can pick the framework that best suits your needs. Disadvantage — You have to take the time to learn enough about each framework to make a choice. Advantage — You can choose to NOT use a framework, thus making your code faster and more effecient. Disadvantage — It’s difficult to combine code from two different projects that are written on two different frameworks.

Ruby on Rails deserves much credit. Anyone who has ever developed a web site knows that there are bits of code you use over and over again. Ruby on Rails, being developed for the purpose of building web sites, makes available some great APIs for getting common tasks done quickly. Ruby Gems are a way of packaging code into a reusable, easily distributed bundle. Gems are great since developers can encapsulate their code easily, this making it easy for other developers to implement. Ruby on Rails is also fully object oriented, whereas PHP is not.

What it all boils down to is that Ruby on Rails is like the Hybrid car of tomorrow. Developers consider ROR to be the sexy new language of the future. Nevermind it’s features or how it works, it’s new. Where does that leave PHP? I suppose it’s place is as the old, outdated language that’s falling by the wayside. Quite the contrary, would one consider unix to be old and outdated? After all, it’s over 30 years old. Anything that old in the computer industry must be old and outdated. But it’s not. In the computer industry, we call unix “mature”.

That’s what PHP is. It’s a mature language. It has a robust set of APIs. It has a broad following. It has plenty of open source backing it. It runs on the majority of servers on the internet. It’s fast. It’s secure. It has all the things you would expect from a mature, robust language.

Delete files older than XX days using PHP

Here’s a chunk of code for deleting old files using PHP code.

$days = 180;
$dir = '/path/to/dir';
	if ($handle = opendir($dir)) {
	while (false !== ($file = readdir($handle))) {
		if ($file[0] == '.' || is_dir($dir.'/'.$file)) {
			continue;
		}
		if ((time() - filemtime($dir.'/'.$file)) &gt; ($days *86400)) {
			unlink($dir.'/'.$file);
		}
	}
	closedir($handle);
}