PHP shell scripts for Magento

PHP shell scripts for Magento

There are times when it’s necessary to access Magento system from outside Magento. A way to do this is using PHP shell script that bootstraps Magento. An average PHP developer would just go to Magento root directory to create Magento bootstrap file with it’s own code at the bottom. As you’ve probably guessed, there are two ways to bootstrap Magento, regular way and Magento way. In this article I’ll provide an overview of Magento way of creating PHP shell scripts.

For starters, here’s regular way of bootstrapping Magento (the one that regular Magento’s index.php is using):

require_once 'app/Mage.php';
Mage::app();
 
// Our own code goes here

There’s nothing wrong with this approach, but there are some downsides when compared to Magento way.

The Magento way

Now let’s move on to the second way of creating PHP shell scripts intended to interact with Magento code. If you go to path_to_magento_root/shell you will find some PHP shell scripts created in “Magento way”. For example you have indexer.php you can use to reindex by selected indexers, or compiler.php to control Magento compiler feature status. If you take a look inside these PHP shell scripts, you’ll see that they include path_to_magento_root/shell/abstract.php file containing Mage_Shell_Abstract class and that they contain classes that extend Mage_Shell_Abstract class.

Some of you might wonder how’s this better than just simply requireing Mage.php, especially if you take a look at Mage_Shell_Abstract’s constructor that does pretty much the same thing?

One of upsides of using Magento way is that Mage_Shell_Abstract class provides you with tools for parsing command line arguments with ease. Seccond thing, the Mage_Shell_Abstract class constructor will call Mage_Shell_Abstract::__applyPhpVariables() function to parse .htaccess file and apply php settings to shell script.

Even though it’s pretty much obvious how to proceed from here, I’ll paste skeleton class for a Magento PHP shell script here:

<?php
require_once 'abstract.php';
 
class Inchoo_Shell_Myscript extends Mage_Shell_Abstract
{
protected $_argname = array();
 
public function __construct() {
parent::__construct();
 
// Time limit to infinity
set_time_limit(0);
 
// Get command line argument named "argname"
// Accepts multiple values (comma separated)
if($this->getArg('argname')) {
$this->_argname = array_merge(
$this->_argname,
array_map(
'trim',
explode(',', $this->getArg('argname'))
)
);
}
}
 
// Shell script point of entry
public function run() {
 
}
 
// Usage instructions
public function usageHelp()
{
return <<<USAGE
Usage: php -f scriptname.php -- [options]
 
--argname <argvalue> Argument description
 
help This help
 
USAGE;
}
}
// Instantiate
$shell = new Inchoo_Shell_Myscript();
 
// Initiate script
$shell->run();

Precache PHP shell script

I’ll also point you towards PHP shell script created as an exercise, after similar functionality was required for one of our projects. This is a PHP script intended to populate cache for Magento site. The idea was to visit all Magento URLs using Zend_Http_Client (both product canonical and category based URLs as well as all category URLs). This script allows you to select which stores and categories should be processed using command line arguments. Here’s download link:

Inchoo Precache Download

And here’s link to Inchoo_Precache Magento shell script’s GitHub repository.and link to Inchoo_Precache Magento shell script’s GitHub repository:

Inchoo Precache GitHub Repository

And here are the usage instructions available using php -f precache.php -- help command from terminal inside shell directory of your Magento root after adding precache.php to your Magento installation:

Usage: php -f precache.php -- [options]
 
--stores <names> Process only these stores (comma-separated)
--categories <names> Process only these categories (comma-separated)
 
help This help

Magento way is the way to go, don’t you agree? Happy coding!

You made it all the way down here so you must have enjoyed this post! You may also like:

Inchoo’s compatibility extension for Magento 1 and PHP 7 Ivan Curdinjakovic
Ivan Curdinjakovic, | 71

Inchoo’s compatibility extension for Magento 1 and PHP 7

Using Redis cache backend and session storage in Magento Marko Martinovic
Marko Martinovic, | 43

Using Redis cache backend and session storage in Magento

Magento, barbecue, archery and ATV driving  – Inchoo Learning Day 6 Maja Kardum
Maja Kardum, | 0

Magento, barbecue, archery and ATV driving – Inchoo Learning Day 6

11 comments

  1. HI Marko,
    I have made similar script and i have also used your script. but i have 1 problem. my website is only available for register customer so if customer is not logged in he will redirect to login page. so i get 302 or 401 Http status.

    Do you have any solution for this problem? i want to make login customer before run script. i have try to do by customer id but its not help.

    Thanks

    1. Thanks Sébastien,
      very kind of you to report, it’s fixed now.

      Regards,
      Marko

  2. @Marko

    Would it be possible to quicly re-write this script. Take all the good that is already here. But then replace the category indexing by sitemap indexing. This way the flow would be
    – get list of stores store
    – per store
    – find the corresponding sitemap.xml
    – visit every URL

    Do you think this can be done easily? Love to hear

  3. I am getting the following error while trying to run this script

    PHP Fatal error: Cannot break/continue 1 level in /var/www/html/shell/precache.php on line 150

    protected function _precacheProcessStore($store)
        {
            $storeName = $store->getName();
    
            if(!empty($this->_precacheStores) &&
                    !in_array($storeName, $this->_precacheStores)) {
                continue;
            }
    
            printf('Processing "%s" store'."\n", $storeName);
    
            $this->_precacheSCount++;
    
            Mage::app()->setCurrentStore($store->getId());
    
            $rootCategory = Mage::getModel('catalog/category')
                ->load($store->getRootCategoryId());
    
            $this->_precacheProcessCategory($rootCategory, $store);
    
            echo "\n";
        }

    I have looked up the error and it has been pointed out that you cannot break out of an IF statement.

  4. Nice Tutorial and working! It would be great, if the precache script could be run in background without using the webserver. Running the scripts without the httpd gives me error:
    Unable to Connect to tcp://mydomain.example:80. Error #111: Connection refused…

    The following snippet for example (reading order details) uses only Magento API and it can be started without runnning httpd:

        public function run()
        {
            $model   = Mage::getModel('sales/order_api');
            $results = $model->info(100000001); // order inc-id
            print_r($results);
        }
    1. @Markus

      Hello! What this script does is visits pages to generate cache and this isn’t possible without web server running.

      Regards,
      Marko

  5. And one more comment. Super thanks btw!!

    How do I know if it has been or is running? I dont see anything at the command line.

    Major thanks Marko

    1. @Overhemden

      Hi. The script should actually display verbose information on command line while running. If this isn’t the case then something is wrong.

      Regards

  6. Thanks – this is quite handy. To share some experiences. We have had such a script and realized that some pages have many rewrites. And as a result caching took hours for 99% of page urls that hardly generate any traffic.

    The solution was to capture the sitemap.xml (location can be grabbed dynamic per store from code) and this was parsed and every page grabbed.

    Let me know what you tink

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <blockquote cite=""> <code> <del datetime=""> <em> <s> <strike> <strong>. You may use following syntax for source code: <pre><code>$current = "Inchoo";</code></pre>.

Tell us about your project

Drop us a line. We'd love to know more about your project.