Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Opencart Admin Cron Jobs

I know about CRON and how to create/manage it. But this issue was different.

I want to develop a module to delete any (unpaid) order that exceeds the time frame given. Ex: I want to delete any unpaid order that has not been paid for 2 days after the order was placed.

I want to use existed model in opencart (and not use a new one). Let's say the module URL would be: http://www.yourstore.com/admin/index.php?route=module/modulename/function And will be called from CRON, and then all any unpaid order will be disappeared.

But the main problem is: when CRON wants to access that URL, it needs a security token or it will never be executed.

My question is: how to execute that module from CRON without security token (in case just for that module)?

Please help me, if you have a better idea or a more clean way, I would say many thanks to you.

like image 433
Aldry Wijaya Avatar asked Mar 04 '14 18:03

Aldry Wijaya


People also ask

How to set up cron job for OpenCart abandonedcarts?

Just follow below simple steps to configure cron job for your OpenCart AbandonedCarts: Open your cron job dashboard, click on "Cron Job" button. Enable scheduled tasks in your plugin: Enable Scheduled Tasks in OpenCart AbandonedCarts Copy Cron Job URL:

How to set cron jobs in cPanel?

Log on to your cPanel Interface. Go to 'Advanced' section. Click on "Cron Jobs". Select the specific time from the lists provided. You should enter the command to run in the "Command" field. You should make sure to enter the proper command and the full path to the file. If you are not sure the command path, you could ask your hosting angency.

How to access admin page without login in OpenCart?

By default opencart doesn't allow to access admin pages without login. The login and token validations are checked in login () method in admin/controller/common/home.php. it cant be set on frontend coz the model is in admin area.

What is a cron?

What is a cron? A cron is a service that allows a user to automatically execute a script at a specific time. For example, you can set a particular PHP script to be automatically executed everyday at midnight. Log on to your cPanel Interface.


4 Answers

Updated : For Opencart versions <= 1.5.6.4

For admin related cron jobs, Do like this.

  1. Copy the admin/index.php to admin/index_for_cron.php

  2. Now, in the admin/index_for_cron.php, search for these 2 lines and comment them out which are responsible for the login & the permissions.

    // Login
    // $controller->addPreAction(new Action('common/home/login'));
    
    // Permission
    // $controller->addPreAction(new Action('common/home/permission'));
    
  3. Now use this url for your cron job.

    http://www.yourstore.com/admin/index_for_cron.php?route=module/modulename/function

NOTE: it is highly recommended to changes the name of index_for_cron.php into an ugly, unpredictable name for the security reasons.

Hope this helps :)

like image 155
Ijas Ameenudeen Avatar answered Oct 16 '22 12:10

Ijas Ameenudeen


I've done something similar to IJas. Adjacent to admin and catalog, I've created a new folder called "cli".

This folder contains a php file for a specific function to be performed by cli (executing scripts via crontab on a set schedule, or manually in the command line), as well as a "bootstrap" of sorts for these types of scripts. The bootstrap is essentially a copy of the "index" found in catalog or admin, and includes some checks and removes the permission checking and some other unnecessary items. It calls whatever controller/action is set forth in the calling specific function script (in the example below, it calls the index method of the class defined in /admin/controller/common/cli_some_function.php).

Function-Specific Script:

<?php
$cli_action = 'common/cli_some_function';
require_once('cli_dispatch.php');
?>

CLI "Bootstrap"/Dispatcher:

<?php

// CLI must be called by cli php
if (php_sapi_name() != 'cli') {
    syslog(LOG_ERR, "cli $cli_action call attempted by non-cli.");
    http_response_code(400);
    exit;
}

// Ensure $cli_action is set
if (!isset($cli_action)) {
    echo 'ERROR: $cli_action must be set in calling script.';
    syslog(LOG_ERR, '$cli_action must be set in calling script');
    http_response_code(400);
    exit;
}

// Handle errors by writing to log
function cli_error_handler($log_level, $log_text, $error_file, $error_line) { 
    syslog(LOG_ERR, 'CLI Error: ' . $log_text . ' in ' . $error_file . ': ' . $error_line); 
    echo 'CLI Error: ' . $log_text . ' in ' . $error_file . ': ' . $error_line; 
}
set_error_handler('cli_error_handler');

// Configuration not present in CLI (vs web)
chdir(__DIR__.'/../admin');
set_include_path(get_include_path() . PATH_SEPARATOR . realpath(dirname(__FILE__)) . '../admin/');
$_SERVER['HTTP_HOST'] = '';

// Version
define('VERSION', '1.5.1');

// Configuration (note we're using the admin config)
require_once('../admin/config.php');

// Configuration check
if (!defined('DIR_APPLICATION')) {
    echo "ERROR: cli $cli_action call missing configuration.";
    $log->write("ERROR: cli $cli_action call missing configuration.");
    http_response_code(400);
    exit;
}

// Startup
require_once(DIR_SYSTEM . 'startup.php');

// Application Classes
require_once(DIR_SYSTEM . 'library/currency.php');
require_once(DIR_SYSTEM . 'library/user.php');
require_once(DIR_SYSTEM . 'library/weight.php');
require_once(DIR_SYSTEM . 'library/length.php');

// Registry
$registry = new Registry();

// Loader
$loader = new Loader($registry);
$registry->set('load', $loader);

// Config
$config = new Config();
$registry->set('config', $config);

// Database
$db = new DB(DB_DRIVER, DB_HOSTNAME, DB_USERNAME, DB_PASSWORD, DB_DATABASE);
$registry->set('db', $db);

// Settings
$query = $db->query("SELECT * FROM " . DB_PREFIX . "setting WHERE store_id = '0'");

foreach ($query->rows as $setting) {
    if (!$setting['serialized']) {
        $config->set($setting['key'], $setting['value']);
    } else {
        $config->set($setting['key'], unserialize($setting['value']));
    }
}

// Url
$url = new Url(HTTP_SERVER, HTTPS_SERVER);  
$registry->set('url', $url);

// Log 
$log = new Log($config->get('config_error_filename'));
$registry->set('log', $log);

function error_handler($errno, $errstr, $errfile, $errline) {
    global $log, $config;

    switch ($errno) {
        case E_NOTICE:
        case E_USER_NOTICE:
            $error = 'Notice';
            break;
        case E_WARNING:
        case E_USER_WARNING:
            $error = 'Warning';
            break;
        case E_ERROR:
        case E_USER_ERROR:
            $error = 'Fatal Error';
            break;
        default:
            $error = 'Unknown';
            break;
    }

    if ($config->get('config_error_display')) {
        echo "\n".'PHP ' . $error . ':  ' . $errstr . ' in ' . $errfile . ' on line ' . $errline."\n";
    }

    if ($config->get('config_error_log')) {
        $log->write('PHP ' . $error . ':  ' . $errstr . ' in ' . $errfile . ' on line ' . $errline);
    }

    return true;
}
set_error_handler('error_handler');
$request = new Request();
$registry->set('request', $request);
$response = new Response();
$response->addHeader('Content-Type: text/html; charset=utf-8');
$registry->set('response', $response); 
$cache = new Cache();
$registry->set('cache', $cache); 
$session = new Session();
$registry->set('session', $session); 
$languages = array();

$query = $db->query("SELECT * FROM " . DB_PREFIX . "language"); 
foreach ($query->rows as $result) {
    $languages[$result['code']] = $result;
}
$config->set('config_language_id', $languages[$config->get('config_admin_language')]['language_id']);
$language = new Language($languages[$config->get('config_admin_language')]['directory']);
$language->load($languages[$config->get('config_admin_language')]['filename']); 
$registry->set('language', $language);      

$document = new Document();
$registry->set('document', $document);      

$registry->set('currency', new Currency($registry));        
$registry->set('weight', new Weight($registry));
$registry->set('length', new Length($registry));
$registry->set('user', new User($registry));

$controller = new Front($registry);
$action = new Action($cli_action);
$controller->dispatch($action, new Action('error/not_found'));

// Output
$response->output();
?>

Using this scheme, I can ensure the script won't be called from the web, and I can have it fired off automatically from the server itself using a cron job (eg: 0 1 0 0 0 /path/to/php /path/to/opencart/cli/cli_some_function.php)

Note that the error_handler function is using some config options that aren't out-of-the-box. You can either set those up or put your own check there.

EDIT made some changes for the error handling

like image 39
Mike T Avatar answered Oct 16 '22 13:10

Mike T


In 2.3.0.2 a very simple way I found was to add your controller function path into the ignored paths settings for login and permission restrictions. Then just add a url password or other check in that controller function to lock it down.

So first in admin/controller/startup/login.php add your controller function path to both $ignore arrays, eg 'common/cron/action'

And then in admin/controller/startup/permissions.php you want just the controller path, eg 'common/cron'

And then finally at start of your action() function do like:

if(!isset($_GET['pass']) || $_GET['pass'] != 'secretpassword')return;

Then i just added this to my cron:

php-cli -r 'echo file_get_contents("https://www.website.com/admin/index.php?route=common/cron/action&pass=secretpassword");'
like image 22
Hayden Thring Avatar answered Oct 16 '22 13:10

Hayden Thring


As I had a similar requirement several times, I put my ideas into a lightweight commandline tool called OCOK.

Especially the Cli Task Command allows you to call Opencart controllers via the commandline and thus lets you call them as cron jobs. Simply create a controller like this and save it as admin/controller/task/example.php:

class ControllerTaskExample extends Controller {
    public function index() {
        if (isset($this->is_cli) && $this->is_cli === true) {
            // work done by the controller

            if (isset($this->request->get['param1'])) {
                echo "param1 is " . $this->request->get['param1'] . "\n";
            }

            if (isset($this->request->get['param2'])) {
                echo "param2 is " . $this->request->get['param2'] . "\n";
            }

        }
    }
} 

Via the commandline it can be called with parameters:

ocok run task/example param1=foo param2=bar

The above stated command would output:

param1 is foo
param2 is bar

Adding this to crontab is as easy as adding the following line to your cron file:

* * * * * (cd /path/to/opencart/folder; /path/to/ocok run task/example param1=foo param2=bar)

the respective paths need to be set correctly of course.

Installation available with composer. All further documentation can be found inside the docs: OCOK

like image 25
Stefan Avatar answered Oct 16 '22 11:10

Stefan