我了解CRON以及如何创建/管理它。但这个问题不同。
我想开发一个模块来删除超出给定时间范围的任何(未付)订单。 例如:我想删除订单下达后2天内尚未支付的任何未付订单。
我想在opencart中使用现有模型(而不是使用新模型)。假设模块URL为:http://www.yourstore.com/admin/index.php?route=module/modulename/function 并且将从CRON调用,然后所有任何未付的订单都将消失。
但主要问题是:当CRON想要访问该URL时,它需要一个安全令牌,否则它将永远不会被执行。
我的问题是:如何在没有安全令牌的情况下从CRON执行该模块(仅限该模块)?
请帮助我,如果你有更好的想法或更干净的方式,我会说非常感谢你。
答案 0 :(得分:12)
更新:适用于Opencart版本< = 1.5.6.4
对于管理员相关的cron作业,请执行此操作。
将 admin/index.php
复制到 admin/index_for_cron.php
现在,在 admin/index_for_cron.php
中,搜索这2行并将其注释掉,这些行负责登录&权限。
// Login
// $controller->addPreAction(new Action('common/home/login'));
// Permission
// $controller->addPreAction(new Action('common/home/permission'));
现在使用此网址作为您的cron作业。
http://www.yourstore.com/admin/index_for_cron.php?route=module/modulename/function
注意:出于安全原因,强烈建议您将 index_for_cron.php
的名称更改为丑陋,不可预测的名称。
希望这会有所帮助:)
答案 1 :(得分:8)
我做过类似于IJas的事情。在管理员和目录旁边,我创建了一个名为“cli”的新文件夹。
此文件夹包含由cli执行的特定功能的php文件(在设定的时间表上通过crontab执行脚本,或在命令行中手动执行),以及这些类型的脚本的“引导程序” 。引导程序本质上是目录或管理员中的“索引”的副本,包括一些检查并删除权限检查和一些其他不必要的项目。它调用调用特定函数脚本中提出的任何控制器/操作(在下面的示例中,它调用/admin/controller/common/cli_some_function.php中定义的类的索引方法)。
特定于功能的脚本:
<?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();
?>
使用这个方案,我可以确保不会从Web调用脚本,我可以使用cron作业从服务器本身自动启动它(例如:0 1 0 0 0 / path / to / php /path/to/opencart/cli/cli_some_function.php)
注意,error_handler函数正在使用一些不是开箱即用的配置选项。你可以设置它们或在那里自己检查。
编辑对错误处理进行了一些更改
答案 2 :(得分:3)
由于我有过几次类似的要求,我将我的想法放入一个名为OCOK的轻量级命令行工具中。
特别是Cli Task Command允许您通过命令行调用Opencart控制器,因此可以将它们称为cron作业。只需创建一个这样的控制器并将其另存为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";
}
}
}
}
通过命令行可以使用参数调用它:
ocok run task/example param1=foo param2=bar
上述命令将输出:
param1 is foo
param2 is bar
将此添加到crontab就像在cron文件中添加以下行一样简单:
* * * * * (cd /path/to/opencart/folder; /path/to/ocok run task/example param1=foo param2=bar)
当然需要正确设置各自的路径。
Installation可与作曲家一起使用。所有进一步的文档都可以在文档中找到:OCOK
答案 3 :(得分:2)
我知道这是一个非常古老的问题,但是我花了很长时间试图在opencart版本2.x中做同样的事情。所以我在这里分享我的解决方案。(基于Mike T方法)
1 - 创建与admin和catalog相邻的cli文件夹 2 - 在同一文件夹中创建一个文件,您将通过cron或comandline运行该文件,例如runcron.php
#!/usr/bin/php
<?php
require_once('cli_dispatch.php');
3 - 在同一文件夹中创建cli_dispatch.php文件,该文件是admin文件夹中index.php文件的副本,但有一些更改(注意,这是安装VQMOD已激活,可能不是你的情况)< / p>
<?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 (note we're using the admin config)
require_once __DIR__.('/../admin/config.php');
// 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'] = '';
if (!defined('DIR_APPLICATION')) {
echo "ERROR: cli $cli_action call missing configuration.";
http_response_code(400);
exit;
}
// Version
define('VERSION', '2.3.0.3_rc');
// Configuration
if (is_file('config.php')) {
require_once('config.php');
}
// Install
if (!defined('DIR_APPLICATION')) {
header('Location: ../install/index.php');
exit;
}
//VirtualQMOD
require_once('../vqmod/vqmod.php');
VQMod::bootup();
// VQMODDED Startup
require_once(VQMod::modCheck(DIR_SYSTEM . 'startup.php'));
start('cli');
4 - 现在创建文件upload / system / config / cli.php,这将是opencart将用于从文件upload / system / framework.php读取新cli bootrasp配置的文件
<?php
// Site
$_['site_base'] = HTTP_SERVER;
$_['site_ssl'] = HTTPS_SERVER;
// Database
$_['db_autostart'] = true;
$_['db_type'] = DB_DRIVER; // mpdo, mssql, mysql, mysqli or postgre
$_['db_hostname'] = DB_HOSTNAME;
$_['db_username'] = DB_USERNAME;
$_['db_password'] = DB_PASSWORD;
$_['db_database'] = DB_DATABASE;
$_['db_port'] = DB_PORT;
// Session
//$_['session_autostart'] = true;
// Autoload Libraries
$_['library_autoload'] = array(
'openbay'
);
// Actions
$_['action_pre_action'] = array(
'startup/startup',
'startup/error',
'startup/event',
'startup/sass',
// 'startup/login',
// 'startup/permission'
);
// Actions
$_['action_default'] = 'sale/croninvoices';
// Action Events
$_['action_event'] = array(
'view/*/before' => 'event/theme'
);
正如您所看到的,我已经评论了与权限相关的所有会话和操作行 您将编辑该行
$_['action_default'] = 'sale/yourscript';
更改&#39; sale / yourscript&#39;使用控制器的路径和文件名。
在示例中,runnunig runcron.php文件将执行
中的索引函数upload/admin/controller/sale/yourscript.php file
答案 4 :(得分:1)
默认情况下,opencart不允许在没有登录的情况下访问管理页面。使用login()
中的admin/controller/common/home.php
方法检查登录和令牌验证。
it cant be set on frontend coz the model is in admin area.
- 你可以在管理面板中使用相同的功能为前端创建一个新的控制器和模型,并将其用于cronjob。
Opencart拥有用户组,可为用户设置访问权限。因此,未经许可,不会为用户加载管理页面。因此,您可能需要非常多地修改核心文件,以便在管理面板中设置cronjob,这可能会导致严重的安全问题。
我建议使用cronjob的前端控制器和模型文件。为了提高安全性,您可以在url中传递特定的key参数并编写条件来验证它。
度过美好的一天!!
答案 5 :(得分:0)
在2.3.0.2中,我发现一种非常简单的方法是将控制器功能路径添加到用于登录和权限限制的忽略路径设置中。然后只需在该控制器功能中添加网址密码或其他检查功能即可将其锁定。
因此,首先在admin / controller / startup / login.php中将您的控制器功能路径添加到两个$ ignore数组中,例如'common / cron / action'
然后在admin / controller / startup / permissions.php中,您只需要控制器路径,例如'common / cron'
然后最后在您的action()函数开始时执行以下操作:
if(!isset($_GET['pass']) || $_GET['pass'] != 'secretpassword')return;
然后我刚刚将其添加到我的cron中:
php-cli -r 'echo file_get_contents("https://www.website.com/admin/index.php?route=common/cron/action&pass=secretpassword");'
答案 6 :(得分:0)
在opencart 2.1.0.2中。 如果您在cron作业中需要数据库,但不需要任何opencart模型。 您可以创建文件系统/mycron/cron_task.php。 并将此类代码添加到此文件中:
// CLI
include_once 'config.php';
include_once DIR_SYSTEM.'library/db/mysqli.php';
include_once DIR_SYSTEM.'helper/general.php';
mb_internal_encoding('UTF-8');
if (php_sapi_name() != 'cli') { error_log('NOT CLI CALL');print 'NOT CLI CALL';http_response_code(400);exit; }
$db = new DB\MySQLi(DB_HOSTNAME,DB_USERNAME,DB_PASSWORD,DB_DATABASE,DB_PORT);
// END CLI
// Your actual code, and you CAN use opencart DB!
foreach ($db->query("SELECT * FROM oc_product")->rows as $row) {
//...
}
现在,您可以从Cron作业中运行它:
12 7 * * * cd /path/to/opencart/root/folder && php system/mycron/cron_task.php
答案 7 :(得分:0)
“我想开发一个模块来删除超过给定时间范围的任何(未付款)订单。例如:我想删除下达订单后两天未付款的任何未付款订单。” “我想在opencart中使用现有模型(而不是使用新模型)。”
因此,据我所知,问题是您必须登录到管理员才能访问其控制器和模型,但是cron作业在运行时将不会登录。
您可以看到目录模型是否可以满足您的需求,在这种情况下,没问题:
catalog/model/checkout/order.php
您可以在此处遵循其他答案-即找到一些登录方法。
或者您也可以编写运行简单SQL查询的独立PHP脚本。
您是对的,使用系统模型通常是正确的做法,但OpenCart非常简单,因此它应该是一个非常简单的查询(仅几行),它可以满足您的需求,因此我认为在这种情况下可以接受的选择。
答案 8 :(得分:0)
include_once($_SERVER['DOCUMENT_ROOT'].'/admin/model/module/ModelYourModel.php');
$mym = new ModelYourModel($this->registry);
$mym->yourFunction();
对于2.1版,可能更高。使用目录文件夹中admin文件夹中的模型。