diff --git a/common/framework/Cache.php b/common/framework/Cache.php
index f1e2dbe5b..83bfe13b9 100644
--- a/common/framework/Cache.php
+++ b/common/framework/Cache.php
@@ -239,6 +239,10 @@ class Cache
{
if (self::$_driver !== null)
{
+ if (self::$_driver instanceof Drivers\Cache\APC && \PHP_SAPI === 'cli')
+ {
+ self::sendClearRequest([$key]);
+ }
return self::$_driver->delete(self::getRealKey($key)) ? true : false;
}
else
@@ -323,6 +327,10 @@ class Cache
{
if (self::$_driver !== null)
{
+ if (self::$_driver instanceof Drivers\Cache\APC && \PHP_SAPI === 'cli')
+ {
+ self::sendClearRequest([$group_name . ':*']);
+ }
$success = self::$_driver->incr(self::$_prefix . $group_name . '#version', 1) ? true : false;
unset(self::$_group_versions[$group_name]);
return $success;
@@ -344,6 +352,10 @@ class Cache
{
if (self::$_driver !== null)
{
+ if (self::$_driver instanceof Drivers\Cache\APC && \PHP_SAPI === 'cli')
+ {
+ self::sendClearRequest(['*']);
+ }
return self::$_driver->clear() ? true : false;
}
else
@@ -396,4 +408,27 @@ class Cache
return self::$_prefix . $key;
}
+
+ /**
+ * Send a web request to clear the cache.
+ *
+ * @param array $keys
+ * @return void
+ */
+ public static function sendClearRequest(array $keys): void
+ {
+ if (!$keys)
+ {
+ return;
+ }
+
+ $keystring = implode('|', $keys);
+ $signature = Security::createSignature($keystring);
+ HTTP::post(\Context::getRequestUri(), [
+ 'module' => 'module',
+ 'act' => 'procModuleClearCache',
+ 'keys' => $keys,
+ 'signature' => $signature,
+ ]);
+ }
}
diff --git a/modules/module/conf/module.xml b/modules/module/conf/module.xml
index 01b315c99..4946fe04c 100644
--- a/modules/module/conf/module.xml
+++ b/modules/module/conf/module.xml
@@ -7,16 +7,17 @@
-
+
-
+
-
+
+
@@ -26,7 +27,7 @@
-
+
@@ -36,12 +37,12 @@
-
+
-
+
diff --git a/modules/module/module.controller.php b/modules/module/module.controller.php
index 93e76cfac..c2e9006eb 100644
--- a/modules/module/module.controller.php
+++ b/modules/module/module.controller.php
@@ -1266,6 +1266,62 @@ class ModuleController extends Module
return executeQuery('module.deleteModuleFileBox', $args);
}
+ /**
+ * API call to clear cache entries.
+ *
+ * This can be used to clear the APC cache from CLI scripts,
+ * such as async tasks run from crontab.
+ */
+ public function procModuleClearCache()
+ {
+ // This is a JSON API.
+ Context::setResponseMethod('JSON');
+ if (PHP_SAPI === 'cli')
+ {
+ throw new Rhymix\Framework\Exceptions\InvalidRequest;
+ }
+
+ // Get cache keys to clear.
+ $keys = Context::get('keys');
+ if (!$keys)
+ {
+ throw new Rhymix\Framework\Exceptions\InvalidRequest;
+ }
+ if (!is_array($keys))
+ {
+ $keys = [$keys];
+ }
+
+ // Verify the API signature.
+ $keystring = implode('|', $keys);
+ $signature = Context::get('signature');
+ if (!$signature)
+ {
+ throw new Rhymix\Framework\Exceptions\NotPermitted;
+ }
+ if (!Rhymix\Framework\Security::verifySignature($keystring, $signature))
+ {
+ throw new Rhymix\Framework\Exceptions\NotPermitted;
+ }
+
+ // Clear the requested cache keys.
+ foreach ($keys as $key)
+ {
+ if ($key === '*')
+ {
+ Rhymix\Framework\Cache::clearAll();
+ }
+ elseif (preg_match('/^([^:]+):\*$/', $key, $matches))
+ {
+ Rhymix\Framework\Cache::clearGroup($matches[1]);
+ }
+ else
+ {
+ Rhymix\Framework\Cache::delete($key);
+ }
+ }
+ }
+
/**
* @brief function of locking (timeout is in seconds)
*/