first
This commit is contained in:
@ -0,0 +1,90 @@
|
||||
<?php
|
||||
|
||||
namespace Nextend\Framework\Cache;
|
||||
|
||||
|
||||
use Nextend\Framework\Cache\Storage\AbstractStorage;
|
||||
|
||||
abstract class AbstractCache {
|
||||
|
||||
protected $group = '';
|
||||
protected $isAccessible = false;
|
||||
|
||||
/** @var AbstractStorage */
|
||||
public $storage;
|
||||
|
||||
protected $_storageEngine = 'filesystem';
|
||||
|
||||
/**
|
||||
* @param string $engine
|
||||
*
|
||||
* @return AbstractStorage
|
||||
*/
|
||||
public static function getStorage($engine = "filesystem") {
|
||||
static $storage = null;
|
||||
if ($storage === null) {
|
||||
$storage = array(
|
||||
'filesystem' => new Storage\Filesystem(),
|
||||
'database' => new Storage\Database()
|
||||
);
|
||||
}
|
||||
|
||||
return $storage[$engine];
|
||||
}
|
||||
|
||||
public static function clearAll() {
|
||||
self::getStorage('filesystem')
|
||||
->clearAll();
|
||||
self::getStorage('filesystem')
|
||||
->clearAll('web');
|
||||
}
|
||||
|
||||
public static function clearGroup($group) {
|
||||
self::getStorage('filesystem')
|
||||
->clear($group);
|
||||
self::getStorage('filesystem')
|
||||
->clear($group, 'web');
|
||||
self::getStorage('database')
|
||||
->clear($group);
|
||||
self::getStorage('database')
|
||||
->clear($group, 'web');
|
||||
}
|
||||
|
||||
public function __construct($group, $isAccessible = false) {
|
||||
$this->group = $group;
|
||||
$this->isAccessible = $isAccessible;
|
||||
$this->storage = self::getStorage($this->_storageEngine);
|
||||
}
|
||||
|
||||
protected function clearCurrentGroup() {
|
||||
$this->storage->clear($this->group, $this->getScope());
|
||||
}
|
||||
|
||||
protected function getScope() {
|
||||
if ($this->isAccessible) {
|
||||
return 'web';
|
||||
}
|
||||
|
||||
return 'notweb';
|
||||
}
|
||||
|
||||
protected function exists($key) {
|
||||
return $this->storage->exists($this->group, $key, $this->getScope());
|
||||
}
|
||||
|
||||
protected function get($key) {
|
||||
return $this->storage->get($this->group, $key, $this->getScope());
|
||||
}
|
||||
|
||||
protected function set($key, $value) {
|
||||
$this->storage->set($this->group, $key, $value, $this->getScope());
|
||||
}
|
||||
|
||||
protected function getPath($key) {
|
||||
return $this->storage->getPath($this->group, $key, $this->getScope());
|
||||
}
|
||||
|
||||
protected function remove($key) {
|
||||
return $this->storage->remove($this->group, $key, $this->getScope());
|
||||
}
|
||||
}
|
@ -0,0 +1,110 @@
|
||||
<?php
|
||||
|
||||
namespace Nextend\Framework\Cache;
|
||||
|
||||
use Nextend\Framework\Filesystem\Filesystem;
|
||||
use Nextend\Framework\Misc\HttpClient;
|
||||
|
||||
class CacheGoogleFont extends AbstractCache {
|
||||
|
||||
protected $_storageEngine = 'filesystem';
|
||||
private $fontExtension;
|
||||
|
||||
public function __construct() {
|
||||
parent::__construct('googlefonts', true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $url
|
||||
*
|
||||
* @return boolean|string The path of the cached file
|
||||
*/
|
||||
public function makeCache($url, $extension) {
|
||||
|
||||
$hash = $this->generateHash($url);
|
||||
|
||||
$fileName = $hash;
|
||||
$fileNameWithExtension = $fileName . '.' . $extension;
|
||||
|
||||
$isCached = $this->exists($fileNameWithExtension);
|
||||
|
||||
if ($isCached) {
|
||||
if (!$this->testManifestFile($fileName)) {
|
||||
$isCached = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$isCached) {
|
||||
|
||||
$cssContent = HttpClient::get($url);
|
||||
|
||||
if (!$cssContent) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($extension === 'css') {
|
||||
$fontExtensions = array(
|
||||
'woff2',
|
||||
'ttf'
|
||||
);
|
||||
|
||||
foreach ($fontExtensions as $this->fontExtension) {
|
||||
$cssContent = preg_replace_callback('/url\(["\']?(.*?\.' . $this->fontExtension . ')["\']?\)/i', function ($matches) {
|
||||
|
||||
$url = $matches[1];
|
||||
|
||||
$cache = new CacheGoogleFont();
|
||||
|
||||
$path = $cache->makeCache($url, $this->fontExtension);
|
||||
|
||||
if ($path) {
|
||||
$url = Filesystem::pathToAbsoluteURL($path);
|
||||
}
|
||||
|
||||
return 'url(' . $url . ')';
|
||||
}, $cssContent);
|
||||
}
|
||||
}
|
||||
|
||||
$this->set($fileNameWithExtension, $cssContent);
|
||||
|
||||
$this->createManifestFile($fileName);
|
||||
}
|
||||
|
||||
return $this->getPath($fileNameWithExtension);
|
||||
}
|
||||
|
||||
private function generateHash($url) {
|
||||
return md5($url);
|
||||
}
|
||||
|
||||
protected function testManifestFile($fileName) {
|
||||
$manifestKey = $this->getManifestKey($fileName);
|
||||
if ($this->exists($manifestKey)) {
|
||||
|
||||
$manifestData = json_decode($this->get($manifestKey), true);
|
||||
|
||||
if ($manifestData['mtime'] > strtotime('-30 days')) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected function createManifestFile($fileName) {
|
||||
|
||||
$this->set($this->getManifestKey($fileName), json_encode($this->getManifestData()));
|
||||
}
|
||||
|
||||
private function getManifestData() {
|
||||
|
||||
return array(
|
||||
'mtime' => time()
|
||||
);
|
||||
}
|
||||
|
||||
protected function getManifestKey($fileName) {
|
||||
return $fileName . '.manifest';
|
||||
}
|
||||
}
|
@ -0,0 +1,132 @@
|
||||
<?php
|
||||
|
||||
namespace Nextend\Framework\Cache;
|
||||
|
||||
use DateTime;
|
||||
|
||||
class CacheImage extends AbstractCache {
|
||||
|
||||
protected $_storageEngine = 'filesystem';
|
||||
|
||||
protected $lazy = false;
|
||||
|
||||
public function __construct($group) {
|
||||
parent::__construct($group, true);
|
||||
}
|
||||
|
||||
protected function getScope() {
|
||||
return 'image';
|
||||
}
|
||||
|
||||
public function setLazy($lazy) {
|
||||
$this->lazy = $lazy;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $fileExtension
|
||||
* @param callable $callable
|
||||
* @param array $parameters
|
||||
* @param bool $hash
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function makeCache($fileExtension, $callable, $parameters = array(), $hash = false) {
|
||||
|
||||
if (!$hash) {
|
||||
$hash = $this->generateHash($fileExtension, $callable, $parameters);
|
||||
}
|
||||
|
||||
if (strpos($parameters[1], '?') !== false) {
|
||||
$fileNameParts = explode('?', $parameters[1]);
|
||||
$keepFileName = pathinfo($fileNameParts[0], PATHINFO_FILENAME);
|
||||
} else {
|
||||
$keepFileName = pathinfo($parameters[1], PATHINFO_FILENAME);
|
||||
}
|
||||
|
||||
$fileName = $hash . (!empty($keepFileName) ? '/' . $keepFileName : '');
|
||||
$fileNameWithExtension = $fileName . '.' . $fileExtension;
|
||||
|
||||
$isCached = $this->exists($fileNameWithExtension);
|
||||
if ($isCached) {
|
||||
if (!$this->testManifestFile($fileName, $parameters[1])) {
|
||||
$isCached = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$isCached) {
|
||||
if ($this->lazy) {
|
||||
return $parameters[1];
|
||||
}
|
||||
|
||||
array_unshift($parameters, $this->getPath($fileNameWithExtension));
|
||||
call_user_func_array($callable, $parameters);
|
||||
|
||||
$this->createManifestFile($fileName, $parameters[2]);
|
||||
}
|
||||
|
||||
return $this->getPath($fileNameWithExtension);
|
||||
}
|
||||
|
||||
private function generateHash($fileExtension, $callable, $parameters) {
|
||||
return md5(json_encode(array(
|
||||
$fileExtension,
|
||||
$callable,
|
||||
$parameters
|
||||
)));
|
||||
}
|
||||
|
||||
protected function testManifestFile($fileName, $originalFile) {
|
||||
$manifestKey = $this->getManifestKey($fileName);
|
||||
if ($this->exists($manifestKey)) {
|
||||
|
||||
$manifestData = json_decode($this->get($manifestKey), true);
|
||||
|
||||
$newManifestData = $this->getManifestData($originalFile);
|
||||
if ($manifestData['mtime'] == $newManifestData['mtime']) {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
// Backward compatibility
|
||||
$this->createManifestFile($fileName, $originalFile);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected function createManifestFile($fileName, $originalFile) {
|
||||
|
||||
$this->set($this->getManifestKey($fileName), json_encode($this->getManifestData($originalFile)));
|
||||
}
|
||||
|
||||
private function getManifestData($originalFile) {
|
||||
$manifestData = array();
|
||||
if (strpos($originalFile, '//') !== false) {
|
||||
$manifestData['mtime'] = $this->getRemoteMTime($originalFile);
|
||||
} else {
|
||||
$manifestData['mtime'] = filemtime($originalFile);
|
||||
}
|
||||
|
||||
return $manifestData;
|
||||
}
|
||||
|
||||
private function getRemoteMTime($url) {
|
||||
if (ini_get('allow_url_fopen')) {
|
||||
$h = get_headers($url, 1);
|
||||
if (!$h || strpos($h[0], '200') !== false) {
|
||||
foreach ($h as $k => $v) {
|
||||
if (strtolower(trim($k)) == "last-modified") {
|
||||
return (new DateTime($v))->getTimestamp();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected function getManifestKey($fileName) {
|
||||
return $fileName . '.manifest';
|
||||
}
|
||||
}
|
@ -0,0 +1,103 @@
|
||||
<?php
|
||||
|
||||
namespace Nextend\Framework\Cache;
|
||||
|
||||
class Manifest extends AbstractCache {
|
||||
|
||||
private $isRaw = false;
|
||||
|
||||
private $manifestData;
|
||||
|
||||
public function __construct($group, $isAccessible = false, $isRaw = false) {
|
||||
parent::__construct($group, $isAccessible);
|
||||
$this->isRaw = $isRaw;
|
||||
}
|
||||
|
||||
protected function decode($data) {
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $fileName
|
||||
* @param $hash
|
||||
* @param callback $callable
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function makeCache($fileName, $hash, $callable) {
|
||||
if (!$this->isCached($fileName, $hash)) {
|
||||
|
||||
$return = call_user_func($callable, $this);
|
||||
if ($return === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->createCacheFile($fileName, $hash, $return);
|
||||
}
|
||||
if ($this->isAccessible) {
|
||||
return $this->getPath($fileName);
|
||||
}
|
||||
|
||||
return $this->decode($this->get($fileName));
|
||||
}
|
||||
|
||||
private function isCached($fileName, $hash) {
|
||||
|
||||
|
||||
$manifestKey = $this->getManifestKey($fileName);
|
||||
if ($this->exists($manifestKey)) {
|
||||
|
||||
$this->manifestData = json_decode($this->get($manifestKey), true);
|
||||
|
||||
if (!$this->isCacheValid($this->manifestData) || $this->manifestData['hash'] != $hash || !$this->exists($fileName)) {
|
||||
$this->clean($fileName);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected function createCacheFile($fileName, $hash, $content) {
|
||||
|
||||
$this->manifestData = array();
|
||||
|
||||
$this->manifestData['hash'] = $hash;
|
||||
$this->addManifestData($this->manifestData);
|
||||
|
||||
$this->set($this->getManifestKey($fileName), json_encode($this->manifestData));
|
||||
|
||||
$this->set($fileName, $this->isRaw ? $content : json_encode($content));
|
||||
|
||||
if ($this->isAccessible) {
|
||||
return $this->getPath($fileName);
|
||||
}
|
||||
|
||||
return $content;
|
||||
}
|
||||
|
||||
protected function isCacheValid(&$manifestData) {
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function addManifestData(&$manifestData) {
|
||||
|
||||
}
|
||||
|
||||
public function clean($fileName) {
|
||||
|
||||
$this->remove($this->getManifestKey($fileName));
|
||||
$this->remove($fileName);
|
||||
}
|
||||
|
||||
protected function getManifestKey($fileName) {
|
||||
return $fileName . '.manifest';
|
||||
}
|
||||
|
||||
public function getData($key, $default = 0) {
|
||||
return isset($this->manifestData[$key]) ? $this->manifestData[$key] : $default;
|
||||
}
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace Nextend\Framework\Cache\Storage;
|
||||
|
||||
|
||||
abstract class AbstractStorage {
|
||||
|
||||
protected $paths = array();
|
||||
|
||||
public function isFilesystem() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public abstract function clearAll($scope = 'notweb');
|
||||
|
||||
public abstract function clear($group, $scope = 'notweb');
|
||||
|
||||
public abstract function exists($group, $key, $scope = 'notweb');
|
||||
|
||||
public abstract function set($group, $key, $value, $scope = 'notweb');
|
||||
|
||||
public abstract function get($group, $key, $scope = 'notweb');
|
||||
|
||||
public abstract function remove($group, $key, $scope = 'notweb');
|
||||
|
||||
public abstract function getPath($group, $key, $scope = 'notweb');
|
||||
}
|
@ -0,0 +1,56 @@
|
||||
<?php
|
||||
|
||||
namespace Nextend\Framework\Cache\Storage;
|
||||
|
||||
use Nextend\Framework\Model\ApplicationSection;
|
||||
use Nextend\Framework\Platform\Platform;
|
||||
|
||||
class Database extends AbstractStorage {
|
||||
|
||||
protected $db;
|
||||
|
||||
public function __construct() {
|
||||
|
||||
$this->paths['web'] = 'web';
|
||||
$this->paths['notweb'] = 'notweb';
|
||||
$this->paths['image'] = 'image';
|
||||
|
||||
$this->db = new ApplicationSection('cache');
|
||||
}
|
||||
|
||||
public function clearAll($scope = 'notweb') {
|
||||
|
||||
}
|
||||
|
||||
public function clear($group, $scope = 'notweb') {
|
||||
|
||||
$this->db->delete($scope . '/' . $group);
|
||||
}
|
||||
|
||||
public function exists($group, $key, $scope = 'notweb') {
|
||||
|
||||
if ($this->db->get($scope . '/' . $group, $key)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function set($group, $key, $value, $scope = 'notweb') {
|
||||
|
||||
$this->db->set($scope . '/' . $group, $key, $value);
|
||||
}
|
||||
|
||||
public function get($group, $key, $scope = 'notweb') {
|
||||
return $this->db->get($scope . '/' . $group, $key);
|
||||
}
|
||||
|
||||
public function remove($group, $key, $scope = 'notweb') {
|
||||
$this->db->delete($scope . '/' . $group, $key);
|
||||
}
|
||||
|
||||
public function getPath($group, $key, $scope = 'notweb') {
|
||||
|
||||
return Platform::getSiteUrl() . '?nextendcache=1&g=' . urlencode($group) . '&k=' . urlencode($key);
|
||||
}
|
||||
}
|
@ -0,0 +1,62 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace Nextend\Framework\Cache\Storage;
|
||||
|
||||
|
||||
class Filesystem extends AbstractStorage {
|
||||
|
||||
public function __construct() {
|
||||
$this->paths['web'] = \Nextend\Framework\Filesystem\Filesystem::getWebCachePath();
|
||||
$this->paths['notweb'] = \Nextend\Framework\Filesystem\Filesystem::getNotWebCachePath();
|
||||
$this->paths['image'] = \Nextend\Framework\Filesystem\Filesystem::getImagesFolder();
|
||||
}
|
||||
|
||||
public function isFilesystem() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public function clearAll($scope = 'notweb') {
|
||||
if (\Nextend\Framework\Filesystem\Filesystem::existsFolder($this->paths[$scope])) {
|
||||
\Nextend\Framework\Filesystem\Filesystem::deleteFolder($this->paths[$scope]);
|
||||
}
|
||||
}
|
||||
|
||||
public function clear($group, $scope = 'notweb') {
|
||||
|
||||
if (\Nextend\Framework\Filesystem\Filesystem::existsFolder($this->paths[$scope] . '/' . $group)) {
|
||||
\Nextend\Framework\Filesystem\Filesystem::deleteFolder($this->paths[$scope] . '/' . $group);
|
||||
}
|
||||
}
|
||||
|
||||
public function exists($group, $key, $scope = 'notweb') {
|
||||
if (\Nextend\Framework\Filesystem\Filesystem::existsFile($this->paths[$scope] . '/' . $group . '/' . $key)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function set($group, $key, $value, $scope = 'notweb') {
|
||||
$path = $this->paths[$scope] . '/' . $group . '/' . $key;
|
||||
$dir = dirname($path);
|
||||
if (!\Nextend\Framework\Filesystem\Filesystem::existsFolder($dir)) {
|
||||
\Nextend\Framework\Filesystem\Filesystem::createFolder($dir);
|
||||
}
|
||||
\Nextend\Framework\Filesystem\Filesystem::createFile($path, $value);
|
||||
}
|
||||
|
||||
public function get($group, $key, $scope = 'notweb') {
|
||||
return \Nextend\Framework\Filesystem\Filesystem::readFile($this->paths[$scope] . '/' . $group . '/' . $key);
|
||||
}
|
||||
|
||||
public function remove($group, $key, $scope = 'notweb') {
|
||||
if ($this->exists($group, $key, $scope)) {
|
||||
@unlink($this->paths[$scope] . '/' . $group . '/' . $key);
|
||||
}
|
||||
}
|
||||
|
||||
public function getPath($group, $key, $scope = 'notweb') {
|
||||
return $this->paths[$scope] . DIRECTORY_SEPARATOR . $group . DIRECTORY_SEPARATOR . $key;
|
||||
}
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
namespace Nextend\Framework\Cache;
|
||||
|
||||
class StoreImage extends AbstractCache {
|
||||
|
||||
protected $_storageEngine = 'filesystem';
|
||||
|
||||
protected function getScope() {
|
||||
return 'image';
|
||||
}
|
||||
|
||||
public function makeCache($fileName, $content) {
|
||||
if (!$this->isImage($fileName)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!$this->exists($fileName)) {
|
||||
$this->set($fileName, $content);
|
||||
}
|
||||
|
||||
return $this->getPath($fileName);
|
||||
}
|
||||
|
||||
private function isImage($fileName) {
|
||||
$supported_image = array(
|
||||
'gif',
|
||||
'jpg',
|
||||
'jpeg',
|
||||
'png',
|
||||
'mp4',
|
||||
'mp3',
|
||||
'webp',
|
||||
'svg'
|
||||
);
|
||||
|
||||
$ext = strtolower(pathinfo($fileName, PATHINFO_EXTENSION));
|
||||
if (in_array($ext, $supported_image)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user