Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
I
Imldeployment
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Container registry
Model registry
Operate
Environments
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
IML Open Source
Imldeployment
Merge requests
!62
V2.0
Code
Review changes
Check out branch
Download
Patches
Plain diff
Merged
V2.0
v2.0
into
master
Overview
0
Commits
139
Pipelines
0
Changes
1
Merged
Hahn Axel (hahn)
requested to merge
v2.0
into
master
1 year ago
Overview
0
Commits
139
Pipelines
0
Changes
1
Expand
0
0
Merge request reports
Viewing commit
0bb100a0
Show latest version
1 file
+
806
−
412
Inline
Compare changes
Side-by-side
Inline
Show whitespace changes
Show one file at a time
0bb100a0
update ahcache class
· 0bb100a0
Hahn Axel (hahn)
authored
1 year ago
public_html/deployment/classes/cache.class.php
+
806
−
412
Options
<?php
/**
* --------------------------------------------------------------------------------<br>
* __ ______ __
* ____ _/ /_ / ____/___ ______/ /_ ___
* / __ `/ __ \/ / / __ `/ ___/ __ \/ _ \
* / /_/ / / / / /___/ /_/ / /__/ / / / __/
* \__,_/_/ /_/\____/\__,_/\___/_/ /_/\___/
*
* --------------------------------------------------------------------------------<br>
* AXELS CACHE CLASS<br>
* --------------------------------------------------------------------------------<br>
* <br>
* THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE <br>
* LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR <br>
@@ -25,469 +35,853 @@
* - _cleanup checks with file_exists<br>
* 2014-03-31 2.3 - added _setup() that to includes custom settings<br>
* - limit number of files in cache directory<br>
* 2019-11-24 2.4 - added getCachedItems() to get a filtered list of cache files<br>
* - added remove file to make complete cache of a module invalid<br>
* - rename var in cache.class_config.php to "$this->_sCacheDirDivider"<br>
* 2019-11-26 2.5 - added getModules() to get a list of existing modules that stored<br>
* a cached item<br>
* 2021-09-28 2.6 added a simple admin UI; the cache class got a few new methods
* - update: cleanup() now always deletes expired items
* - update: dump() styles output as table
* - added: getCurrentModule
* - added: deleteModule
* - added: loadCachefile
* - added: removefileDelete
* - added: setCacheId
* - added: setModule
* 2021-09-30 2.7 FIX: remove chdir() in _readCacheItem()
* 2021-10-07 2.8 FIX: remove chdir() in _readCacheItem()
* ADD reference file to expire a cache item
* - added: getRefFile
* - added: setRefFile
* - update: dump, isExpired, isNewerThanFile, write
* - update cache admin
* 2023-03-17 2.9 FIX: harden _getAllCacheData to prevent PHP warnings
* 2023-06-02 2.10 shorten code: defaults using ??; short array syntax
* 2023-11-20 2.11 check data subkey before writing
* --------------------------------------------------------------------------------<br>
* compatible to PHP 7 ... 8.2<br>
* --------------------------------------------------------------------------------<br>
* @version 2.
3
* @version 2.
11
* @author Axel Hahn
* @link http://www.axel-hahn.de/
php_contentcache
* @link http
s
://www.axel-hahn.de/
docs/ahcache/index.htm
* @license GPL
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL 3.0
* @package Axels Cache
*/
class
AhCache
{
/**
* a module name string is used as relative cache path
* @var string
*/
var
$sModule
=
''
;
/**
* id of cachefile (filename will be generated from it)
* @var string
*/
var
$sCacheID
=
''
;
/**
* where to store all cache data - it can be outside docRoot. If it is
* below docRoot think about forbidding access
* If empty it will be set in the constructor to [webroot]/~cache/
* or $TEMP/~cache/ for CLI
* @var string
*/
private
$_sCacheDir
=
''
;
// private $_sCacheDir='/tmp/';
/**
* absolute filename of cache file
* @var string
*/
private
$_sCacheFile
=
''
;
/**
* divider to limit count of cachefiles
* @var type
*/
private
$_sCacheDirDevider
=
false
;
/**
* fileextension for storing cachefiles (without ".")
* @var string
*/
private
$_sCacheExt
=
'cacheclass2'
;
/**
* Expiration timestamp;
* It will be calculated with current time + ttl in the write() method
* TTL can be read with getExpire()
* @var integer
*/
private
$_tsExpire
=
-
1
;
/**
* TTL (time to live) in s;
* TTL can be set in methods setTtl($iTtl) or write($data, $iTtl)
* TTL can be read with getTtl()
* @var integer
*/
private
$_iTtl
=
-
1
;
/**
* cachedata and file infos of cachefile (returned array of php function stat)
* @var array
*/
private
$_aCacheInfos
=
array
();
/* ----------------------------------------------------------------------
if
(
!
class_exists
(
"AhCache"
))
{
class
AhCache
{
/**
* a module name string is used as relative cache path
* @var string
*/
var
$sModule
=
''
;
/**
* id of cachefile (filename will be generated from it)
* @var string
*/
var
$sCacheID
=
''
;
/**
* where to store all cache data - it can be outside docRoot. If it is
* below docRoot think about forbidding access
* If empty it will be set in the constructor to [webroot]/~cache/
* or $TEMP/~cache/ for CLI
* @var string
*/
private
$_sCacheDir
=
''
;
/**
* absolute filename of cache file
* @var string
*/
private
$_sCacheFile
=
''
;
/**
* divider to limit count of cachefiles
* @var type
*/
private
$_sCacheDirDivider
=
false
;
/**
* fileextension for storing cachefiles (without ".")
* @var string
*/
private
$_sCacheExt
=
'cacheclass2'
;
/**
* Expiration timestamp;
* It will be calculated with current time + ttl in the write() method
* TTL can be read with getExpire()
* @var integer
*/
private
$_tsExpire
=
-
1
;
/**
* TTL (time to live) in s;
* TTL can be set in methods setTtl($iTtl) or write($data, $iTtl)
* TTL can be read with getTtl()
* @var integer
*/
private
$_iTtl
=
-
1
;
/**
* cachedata and file infos of cachefile (returned array of php function stat)
* @var array
*/
private
$_aCacheInfos
=
[];
/**
* Full path to a cache remove file for the current module
* @var string
*/
private
$_sCacheRemovefile
=
false
;
/**
* Reference file: a cache is outdated if the reference file is newer than
* the cache item.
* TTL can be set in methods setRefFile($sFile) or write($data, $iTtl, $sFile)
* TTL can be read with getRefFile()
* @var string
*/
private
$_sRefFile
=
false
;
/* ----------------------------------------------------------------------
constructor
---------------------------------------------------------------------- */
/**
* constructor
* @param string $sModule name of module or app that uses the cache
* @param string $sCacheID cache-id (must be uniq for a module; used to generate filename of cachefile)
* @return boolean
*/
public
function
__construct
(
$sModule
=
"."
,
$sCacheID
=
'.'
)
{
$this
->
_setup
();
if
(
!
$sModule
)
die
(
"ERROR: no module was given.<br>"
);
if
(
!
$sCacheID
)
die
(
"ERROR: no id was given.<br>"
);
$this
->
sModule
=
$sModule
;
$this
->
sCacheID
=
$sCacheID
;
$this
->
_getCacheFilename
();
$this
->
read
();
return
true
;
}
/**
* constructor
* @param string $sModule name of module or app that uses the cache
* @param string $sCacheID cache-id (must be uniq within a module; used to generate filename of cachefile)
* @return boolean
*/
public
function
__construct
(
$sModule
=
"."
,
$sCacheID
=
'.'
)
{
$this
->
setModule
(
$sModule
,
$sCacheID
);
return
true
;
}
/* ----------------------------------------------------------------------
/* ----------------------------------------------------------------------
private funtions
---------------------------------------------------------------------- */
// ----------------------------------------------------------------------
/**
* load custom config from cache.class_config.php and set a cache
* directory
*/
private
function
_setup
()
{
$sCfgfile
=
"cache.class_config.php"
;
if
(
file_exists
(
__DIR__
.
"/"
.
$sCfgfile
)){
include
(
$sCfgfile
);
}
if
(
!
$this
->
_sCacheDir
)
{
if
(
getenv
(
"TEMP"
))
$this
->
_sCacheDir
=
str_replace
(
"
\\
"
,
"/"
,
getenv
(
"TEMP"
));
if
(
$_SERVER
[
'DOCUMENT_ROOT'
])
$this
->
_sCacheDir
=
$_SERVER
[
'DOCUMENT_ROOT'
];
if
(
!
$this
->
_sCacheDir
)
$this
->
_sCacheDir
=
"."
;
$this
->
_sCacheDir
.
=
"/~cache"
;
}
}
// ----------------------------------------------------------------------
/**
* recursive cleanup of a given directory; this function is used by
* public function cleanup()
* @since 2.0
* @param string $sDir full path of a local directory
* @param string $iTS timestamp
* @return true
*/
private
function
_cleanupDir
(
$sDir
,
$iTS
)
{
echo
"<ul><li class=
\"
dir
\"
>DIR: <strong>
$sDir
</strong><ul>"
;
if
(
!
file_exists
(
$sDir
))
{
echo
"
\t
Directory does not exist - [
$sDir
]</ul></li></ul>"
;
return
;
}
if
(
!
(
$d
=
dir
(
$sDir
)))
{
echo
"
\t
Cannot open directory - [
$sDir
]</ul></li></ul>"
;
return
;
}
while
(
$entry
=
$d
->
read
())
{
$sEntry
=
$sDir
.
"/"
.
$entry
;
if
(
is_dir
(
$sEntry
)
&&
$entry
!=
'.'
&&
$entry
!=
'..'
)
{
$this
->
_cleanupDir
(
$sEntry
,
$iTS
);
}
if
(
file_exists
(
$sEntry
))
{
$ext
=
pathinfo
(
$sEntry
,
PATHINFO_EXTENSION
);
$ext
=
substr
(
$sEntry
,
strrpos
(
$sEntry
,
'.'
)
+
1
);
$exts
=
explode
(
"."
,
$sEntry
);
$n
=
count
(
$exts
)
-
1
;
$ext
=
$exts
[
$n
];
if
(
$ext
==
$this
->
_sCacheExt
)
{
$aTmp
=
stat
(
$sEntry
);
$iAge
=
date
(
"U"
)
-
$aTmp
[
'mtime'
];
if
(
$aTmp
[
'mtime'
]
<=
$iTS
)
{
echo
"<li class=
\"
delfile
\"
>delete cachefile:
$sEntry
(
$iAge
s)<br>"
;
unlink
(
$sEntry
);
}
else
{
echo
"<li class=
\"
keepfile
\"
>keep cachefile:
$sEntry
(
$iAge
s; "
.
(
$aTmp
[
'mtime'
]
-
$iTS
)
.
" s left)</li>"
;
// ----------------------------------------------------------------------
/**
* init
* - load custom config from cache.class_config.php
* - set a cache
* - set remove file (if does not exist)
* directory
*/
private
function
_setup
()
{
if
(
!
$this
->
sModule
)
{
die
(
"ERROR: no module was given.<br>"
);
}
if
(
!
$this
->
sCacheID
)
{
die
(
"ERROR: no id was given.<br>"
);
}
$sCfgfile
=
"cache.class_config.php"
;
if
(
file_exists
(
__DIR__
.
"/"
.
$sCfgfile
))
{
include
(
__DIR__
.
"/"
.
$sCfgfile
);
}
if
(
!
$this
->
_sCacheDir
)
{
if
(
getenv
(
"TEMP"
))
$this
->
_sCacheDir
=
str_replace
(
"
\\
"
,
"/"
,
getenv
(
"TEMP"
));
if
(
$_SERVER
[
'DOCUMENT_ROOT'
])
$this
->
_sCacheDir
=
$_SERVER
[
'DOCUMENT_ROOT'
];
if
(
!
$this
->
_sCacheDir
)
$this
->
_sCacheDir
=
"."
;
$this
->
_sCacheDir
.
=
"/~cache"
;
}
$this
->
_sCacheRemovefile
=
$this
->
_sCacheDir
.
'/'
.
$this
->
sModule
.
'/__remove_me_to_make_caches_invalid__'
;
if
(
!
file_exists
(
$this
->
_sCacheRemovefile
))
{
if
(
!
is_dir
(
$this
->
_sCacheDir
.
'/'
.
$this
->
sModule
))
{
if
(
!
mkdir
(
$this
->
_sCacheDir
.
'/'
.
$this
->
sModule
,
0750
,
true
))
{
die
(
"ERROR: unable to create directory "
.
$this
->
_sCacheDir
.
'/'
.
$this
->
sModule
);
}
}
touch
(
$this
->
_sCacheRemovefile
);
}
return
true
;
}
echo
"</ul></li></ul>"
;
// try to delete if it should be empty
@
rmdir
(
$sDir
);
return
true
;
}
// ----------------------------------------------------------------------
/**
* private function _getAllCacheData() - read cachedata and its meta infos
* @since 2.0
* @return array array with data, file stat
*/
private
function
_getAllCacheData
()
{
if
(
!
$this
->
_sCacheFile
)
{
return
false
;
}
$this
->
_aCacheInfos
=
[];
$aTmp
=
$this
->
_readCacheItem
(
$this
->
_sCacheFile
);
if
(
is_array
(
$aTmp
)
&&
count
(
$aTmp
))
{
$this
->
_aCacheInfos
[
'data'
]
=
$aTmp
[
'data'
]
??
false
;
$this
->
_iTtl
=
$aTmp
[
'iTtl'
]
?
$aTmp
[
'iTtl'
]
:
-
1
;
$this
->
_tsExpire
=
$aTmp
[
'tsExpire'
]
?
$aTmp
[
'tsExpire'
]
:
-
1
;
$this
->
_sRefFile
=
$aTmp
[
'sRefFile'
]
??
false
;
$this
->
_aCacheInfos
[
'stat'
]
=
stat
(
$this
->
_sCacheFile
);
// @see loadCachefile: it sets module + id to false
$this
->
sModule
=
$this
->
sModule
?
$this
->
sModule
:
$aTmp
[
'module'
];
$this
->
sCacheID
=
$this
->
sCacheID
?
$this
->
sCacheID
:
$aTmp
[
'cacheid'
];
}
return
$this
->
_aCacheInfos
;
}
// ----------------------------------------------------------------------
/**
* private function _getAllCacheData() - read cachedata and its meta infos
* @since 2.0
* @return array array with data, file stat
*/
private
function
_getAllCacheData
()
{
if
(
!
$this
->
_sCacheFile
)
/**
* read a raw cache item and return it as hash
*
* @param string $sFile filename with full path or relative to cache base path
* @return array|boolean
*/
private
function
_readCacheItem
(
$sFile
)
{
$sFull
=
file_exists
(
$sFile
)
?
$sFile
:
$this
->
_sCacheDir
.
'/'
.
$sFile
;
if
(
file_exists
(
$sFull
))
{
return
unserialize
(
file_get_contents
(
$sFull
));
}
return
false
;
$this
->
_aCacheInfos
=
array
();
if
(
file_exists
(
$this
->
_sCacheFile
))
{
$aTmp
=
unserialize
(
file_get_contents
(
$this
->
_sCacheFile
));
$this
->
_aCacheInfos
[
'data'
]
=
$aTmp
[
'data'
];
$this
->
_iTtl
=
$aTmp
[
'iTtl'
];
$this
->
_tsExpire
=
$aTmp
[
'tsExpire'
];
$this
->
_aCacheInfos
[
'stat'
]
=
stat
(
$this
->
_sCacheFile
);
}
return
$this
->
_aCacheInfos
;
}
}
// ----------------------------------------------------------------------
/**
* private function _getCacheFilename() - get full filename of cachefile
* @return string full filename of cachefile
*/
private
function
_getCacheFilename
()
{
$sMyFile
=
md5
(
$this
->
sCacheID
);
if
(
$this
->
_sCacheDirDevider
&&
$this
->
_sCacheDirDevider
>
0
){
$sMyFile
=
preg_replace
(
'/([0-9a-f]{'
.
$this
->
_sCacheDirDevider
.
'})/'
,
"$1/"
,
$sMyFile
);
}
$sMyFile
.
=
"."
.
$this
->
_sCacheExt
;
$sMyFile
=
str_replace
(
"/."
,
"."
,
$sMyFile
);
// $this->_sCacheFile = $this->_sCacheDir . "/" . $this->sModule . "/" . md5($this->sCacheID) . "." . $this->_sCacheExt;
$this
->
_sCacheFile
=
$this
->
_sCacheDir
.
"/"
.
$this
->
sModule
.
"/"
.
$sMyFile
;
return
$this
->
_sCacheFile
;
}
// ----------------------------------------------------------------------
/**
* private function _getCacheFilename() - get full filename of cachefile
* @return string full filename of cachefile
*/
private
function
_getCacheFilename
()
{
$sMyFile
=
md5
(
$this
->
sCacheID
);
if
(
$this
->
_sCacheDirDivider
&&
$this
->
_sCacheDirDivider
>
0
)
{
$sMyFile
=
preg_replace
(
'/([0-9a-f]{'
.
$this
->
_sCacheDirDivider
.
'})/'
,
"$1/"
,
$sMyFile
);
}
$sMyFile
.
=
"."
.
$this
->
_sCacheExt
;
$sMyFile
=
str_replace
(
"/."
,
"."
,
$sMyFile
);
// $this->_sCacheFile = $this->_sCacheDir . "/" . $this->sModule . "/" . md5($this->sCacheID) . "." . $this->_sCacheExt;
$this
->
_sCacheFile
=
$this
->
_sCacheDir
.
"/"
.
$this
->
sModule
.
"/"
.
$sMyFile
;
return
$this
->
_sCacheFile
;
}
/* ----------------------------------------------------------------------
/* ----------------------------------------------------------------------
public funtions
---------------------------------------------------------------------- */
// ----------------------------------------------------------------------
/**
* Cleanup cache directory; delete all cachefiles older than n seconds
* Other filetypes in the directory won't be touched.
* Empty directories will be deleted.
*
* Only the directory of the initialized module/ app will be deleted.
* $o=new Cache("my-app"); $o->cleanup(60*60*24*3);
*
* To delete all cachefles of all modules you can use
* $o=new Cache(); $o->cleanup(0);
*
* @since 2.0
* @param int $iSec max age of cachefile; older cachefiles will be deleted
* @return true
*/
public
function
cleanup
(
$iSec
=
false
)
{
echo
date
(
"d.m.y - H:i:s"
)
.
" START CLEANUP
$this->_sCacheDir
/"
.
$this
->
sModule
.
",
$iSec
s<br>
<style>
.dir
{
color:#888;
}
.delfile
{
color:#900;
}
.keepfile
{
color:#ccc;
}
</style>"
;
$this
->
_cleanupDir
(
$this
->
_sCacheDir
.
"/"
.
$this
->
sModule
,
date
(
"U"
)
-
$iSec
);
echo
date
(
"d.m.y - H:i:s"
)
.
" END CLEANUP <br>"
;
return
true
;
}
// ----------------------------------------------------------------------
/**
* public function delete - delete a single cachefile if it exist
* @return boolean
*/
public
function
delete
()
{
if
(
!
file_exists
(
$this
->
_sCacheFile
))
/**
* helper function - remove empty cache directories up to module cache dir
*
* @param string $sDir
* @param boolean $bShowOutput flag: show output? default: false (=no output)
* @return void
*/
private
function
_removeEmptyCacheDir
(
$sDir
,
$bShowOutput
=
false
)
{
// echo $bShowOutput ? __METHOD__."($sDir)<br>\n" : '';
if
(
$sDir
>
$this
->
_sCacheDir
.
"/"
.
$this
->
sModule
)
{
echo
$bShowOutput
?
"REMOVE DIR [
$sDir
] ... "
:
''
;
if
(
is_dir
(
$sDir
))
{
if
(
rmdir
(
$sDir
))
{
chdir
(
$this
->
_sCacheDir
);
echo
$bShowOutput
?
"OK<br>
\n
"
:
''
;
usleep
(
20000
);
// 0.02 sec
$this
->
_removeEmptyCacheDir
(
dirname
(
$sDir
),
$bShowOutput
);
}
else
{
echo
$bShowOutput
?
"failed.<br>
\n
"
:
''
;
return
false
;
}
}
else
{
echo
$bShowOutput
?
"skip: not a directory.<br>
\n
"
:
''
;
}
return
true
;
}
return
false
;
if
(
unlink
(
$this
->
_sCacheFile
))
{
$this
->
_aCacheInfos
[
'data'
]
=
false
;
$this
->
_aCacheInfos
[
'stat'
]
=
false
;
}
/* ----------------------------------------------------------------------
public funtions
---------------------------------------------------------------------- */
// ----------------------------------------------------------------------
/**
* Cleanup cache directory; It deletes all outdated cache items of current module.
* Additionally you can delete all cachefiles older than n seconds (because
* there are cache items that are not based on a TTL).
* Other filetypes in the cache directory won't be touched.
* Empty directories will be deleted.
*
* Only the directory of the initialized module/ app will be deleted.
* $o=new Cache("my-app"); $o->cleanup(60*60*24*3);
*
* To delete all cachefles of all modules you can use
* $o=new Cache(); $o->cleanup(0);
*
* @since 2.0
* @param int $iSec max age of cachefile; older cachefiles will be deleted
* @param boolean $bShowOutput flag: show output? default: false (=no output)
* @return true
*/
public
function
cleanup
(
$iSec
=
false
,
$bShowOutput
=
false
)
{
// quick and dirty
$aFilter
=
[
'lifetimeBelow'
=>
0
];
if
(
!
$iSec
===
false
)
{
$aFilter
[
'ageOlder'
]
=
$iSec
;
}
$aData
=
$this
->
getCachedItems
(
false
,
$aFilter
);
echo
$bShowOutput
?
'CLEANUP '
.
count
(
$aData
)
.
" files
\n
"
:
''
;
if
(
$aData
)
{
$aFiles
=
array_keys
(
$aData
);
rsort
(
$aFiles
);
foreach
(
array_keys
(
$aData
)
as
$sFile
)
{
echo
$bShowOutput
?
'DELETE '
.
$sFile
.
"<br>
\n
"
:
''
;
unlink
(
$sFile
);
$this
->
_removeEmptyCacheDir
(
dirname
(
$sFile
),
$bShowOutput
);
}
}
return
true
;
}
return
false
;
}
// ----------------------------------------------------------------------
/**
* public function dump() - dump variables of cache class
* @return true
*/
public
function
dump
()
{
echo
"
<hr>
<strong>cache->dump()<br></strong>
<strong>module: </strong>"
.
$this
->
sModule
.
"<br>
<strong>ID: </strong>"
.
$this
->
sCacheID
.
"<br>
<strong>filename: </strong>"
.
$this
->
_sCacheFile
;
if
(
!
file_exists
(
$this
->
_sCacheFile
))
echo
" (does not exist yet)"
;
echo
"<br>
<strong>age: </strong>"
.
$this
->
getAge
()
.
" s<br>
<strong>ttl: </strong>"
.
$this
->
getTtl
()
.
" s<br>
<strong>expires: </strong>"
.
$this
->
getExpire
()
.
" ("
.
date
(
"d.m.y - H:i:s"
,
$this
->
getExpire
())
.
")<br>
<pre>"
;
print_r
(
$this
->
_aCacheInfos
);
echo
"</pre><hr>"
;
return
true
;
}
// ----------------------------------------------------------------------
/**
* get an array with cached data elements
* @since 2.4
*
* @param string $sDir full path of cache dir; default: false (auto detect cache dir)
* @param array $aFilter filter; valid keys are
* - ageOlder integer return items that are older [n] sec
* - lifetimeBelow integer return items that expire in less [n] sec (or outdated)
* - lifetimeGreater integer return items that expire in more than [n] sec
* - ttlBelow integer return items with ttl less than [n] sec
* - ttlGreater integer return items with ttl more than [n] sec
* no filter returns all cached entries
* @return array
*/
public
function
getCachedItems
(
$sDir
=
false
,
$aFilter
=
[])
{
$aReturn
=
[];
$sDir
=
$sDir
?
$sDir
:
$this
->
_sCacheDir
.
"/"
.
$this
->
sModule
;
if
(
!
file_exists
(
$sDir
))
{
// echo "\t Directory does not exist - [$sDir]";
return
false
;
}
if
(
!
(
$d
=
dir
(
$sDir
)))
{
// echo "\t Cannot open directory - [$sDir]</ul></li></ul>";
return
;
}
while
(
$entry
=
$d
->
read
())
{
$sEntry
=
$sDir
.
"/"
.
$entry
;
if
(
is_dir
(
$sEntry
)
&&
$entry
!=
'.'
&&
$entry
!=
'..'
)
{
$aReturn
=
array_merge
(
$aReturn
,
$this
->
getCachedItems
(
$sEntry
,
$aFilter
));
}
// ----------------------------------------------------------------------
/**
* public function getCacheAge() - get age in seconds of exisiting cachefile
* @return int age in seconds; -1 if cachefiles does not exist
*/
public
function
getAge
()
{
if
(
!
isset
(
$this
->
_aCacheInfos
[
'stat'
]))
$this
->
_getAllCacheData
();
if
(
!
isset
(
$this
->
_aCacheInfos
[
'stat'
]))
return
-
1
;
return
date
(
"U"
)
-
$this
->
_aCacheInfos
[
'stat'
][
'mtime'
];
}
if
(
file_exists
(
$sEntry
))
{
$ext
=
pathinfo
(
$sEntry
,
PATHINFO_EXTENSION
);
$ext
=
substr
(
$sEntry
,
strrpos
(
$sEntry
,
'.'
)
+
1
);
$exts
=
explode
(
"."
,
$sEntry
);
$n
=
count
(
$exts
)
-
1
;
$ext
=
$exts
[
$n
];
if
(
$ext
==
$this
->
_sCacheExt
)
{
$aData
=
$this
->
_readCacheItem
(
$sEntry
);
unset
(
$aData
[
'data'
]);
$aData
[
'_lifetime'
]
=
$aData
[
'tsExpire'
]
-
date
(
'U'
);
$aData
[
'_age'
]
=
date
(
'U'
)
-
filemtime
(
$sEntry
);
$aData
[
'_lifetime'
]
=
filemtime
(
$sEntry
)
>
filemtime
(
$this
->
_sCacheRemovefile
)
?
$aData
[
'tsExpire'
]
-
date
(
'U'
)
:
-
1
;
$bAdd
=
false
;
if
(
isset
(
$aFilter
[
'ageOlder'
])
&&
(
$aData
[
'_age'
]
>
$aFilter
[
'ageOlder'
]))
{
$bAdd
=
true
;
}
if
(
isset
(
$aFilter
[
'lifetimeBelow'
])
&&
(
$aData
[
'_lifetime'
]
<
$aFilter
[
'lifetimeBelow'
]))
{
$bAdd
=
true
;
}
if
(
isset
(
$aFilter
[
'lifetimeGreater'
])
&&
(
$aData
[
'_lifetime'
]
>
$aFilter
[
'lifetimeGreater'
]))
{
$bAdd
=
true
;
}
if
(
isset
(
$aFilter
[
'ttlBelow'
])
&&
(
$aData
[
'iTtl'
]
<
$aFilter
[
'ttlBelow'
]))
{
$bAdd
=
true
;
}
if
(
isset
(
$aFilter
[
'ttlGreater'
])
&&
(
$aData
[
'iTtl'
]
>
$aFilter
[
'ttlGreater'
]))
{
$bAdd
=
true
;
}
if
(
!
is_array
(
$aFilter
)
||
!
count
(
$aFilter
))
{
$bAdd
=
true
;
}
if
(
$bAdd
)
{
$aReturn
[
$sEntry
]
=
$aData
;
}
}
}
}
return
$aReturn
;
}
// ----------------------------------------------------------------------
/**
* public function getExpire() - get TS of cache expiration
* @since 2.0
* @return int unix ts of cache expiration
*/
public
function
getExpire
()
{
return
$this
->
_tsExpire
;
}
// ----------------------------------------------------------------------
/**
* get currently activated module
* @since 2.6
* @return string
*/
public
function
getCurrentModule
()
{
return
$this
->
sModule
;
}
// ----------------------------------------------------------------------
/**
* public function getTtl() - get TTL of cache in seconds
* @since 2.0
* @return int get ttl of cache
*/
public
function
getTtl
()
{
return
$this
->
_iTtl
;
}
// ----------------------------------------------------------------------
/**
* get current cache id
* @since 2.6
* @return string
*/
public
function
getCurrentId
()
{
return
$this
->
sCacheID
;
}
// ----------------------------------------------------------------------
/**
* public function isExpired() - cache expired? To check it
* you must use ttl while writing data, i.e.
* $oCache->write($sData, $iTtl);
* @since 2.0
* @return bool cache is expired?
*/
public
function
isExpired
()
{
if
(
!
$this
->
_tsExpire
)
return
true
;
return
((
date
(
"U"
)
-
$this
->
_tsExpire
)
>
0
);
}
// ----------------------------------------------------------------------
/**
* public function iExpired() - get time in seconds when cachefile expires
* you must use ttl while writing data, i.e.
* $oCache->write($sData, $iTtl);
* @since 2.1
* @return int expired time in seconds; negative if cache is not expired
*/
public
function
iExpired
()
{
if
(
!
$this
->
_tsExpire
)
return
true
;
return
date
(
"U"
)
-
$this
->
_tsExpire
;
}
// ----------------------------------------------------------------------
/**
* get a flat array of module names that saved a cache item already
* @since 2.5
*
* @return array
*/
public
function
getModules
()
{
$aReturn
=
[];
foreach
(
glob
(
$this
->
_sCacheDir
.
'/*'
)
as
$sEntry
)
{
if
(
is_dir
(
$sEntry
))
{
$aReturn
[]
=
basename
(
$sEntry
);
}
}
return
$aReturn
;
}
// ----------------------------------------------------------------------
/**
* function isNewerThanFile($sRefFile) - is the cache (still) newer than
* a reference file? This function returns difference of mtime of both
* files.
* @since 2.0
* @param string $sRefFile local filename
* @return integer time in sec how much the cache file is newer; negative if reference file is newer
*/
public
function
isNewerThanFile
(
$sRefFile
)
{
if
(
!
file_exists
(
$sRefFile
))
return
false
;
if
(
!
isset
(
$this
->
_aCacheInfos
[
'stat'
]))
// ----------------------------------------------------------------------
/**
* delete a single cache item if it exist.
* It returns true if a cache item was deleted. It returns false if it
* does not exist (yet) or the deletion failed.
* @return boolean
*/
public
function
delete
()
{
if
(
!
file_exists
(
$this
->
_sCacheFile
))
{
return
false
;
}
if
(
unlink
(
$this
->
_sCacheFile
))
{
$this
->
_aCacheInfos
[
'data'
]
=
false
;
$this
->
_aCacheInfos
[
'stat'
]
=
false
;
return
true
;
}
return
false
;
}
// ----------------------------------------------------------------------
/**
* delete all existing cached items of the set module
* Remark: this method should be used in an admin interface or cronjob only.
* It makes a recursive filesystem scan and is quite slow.
*
* @since 2.6
* @param boolean $bShowOutput flag: show output? default: false (=no output)
* @return boolean
*/
public
function
deleteModule
(
$bShowOutput
=
false
)
{
if
(
!
$this
->
sModule
)
{
return
false
;
}
$this
->
cleanup
(
0
,
$bShowOutput
);
$this
->
removefileDelete
();
return
rmdir
(
$this
->
_sCacheDir
.
"/"
.
$this
->
sModule
);
}
$aTmp
=
stat
(
$sRefFile
);
$iTimeRef
=
$aTmp
[
'mtime'
];
//echo $this->_sCacheFile."<br>".$this->_aCacheInfos['stat']['mtime']."<br>".$iTimeRef."<br>".($this->_aCacheInfos['stat']['mtime'] - $iTimeRef);
return
$this
->
_aCacheInfos
[
'stat'
][
'mtime'
]
-
$iTimeRef
;
}
// ----------------------------------------------------------------------
/**
* public function dump() - dump variables of cache class
* @return true
*/
public
function
dump
()
{
$sReturn
=
''
;
$sReturn
.
=
"<table>
<!--<strong>"
.
__METHOD__
.
"()<br></strong>-->
<tr><td><strong>module: </strong></td><td>"
.
$this
->
sModule
.
"</td></tr>
<tr><td><strong>ID: </strong></td><td>"
.
$this
->
sCacheID
.
"</td></tr>
<tr><td><strong>filename: </strong></td><td>"
.
$this
->
_sCacheFile
.
"</td></tr>
"
;
if
(
file_exists
(
$this
->
_sCacheFile
))
{
$sReturn
.
=
"
<tr><td><strong>size: </strong></td><td>"
.
filesize
(
$this
->
_sCacheFile
)
.
" byte</td></tr>
<tr><td><strong>created: </strong></td><td>"
.
filemtime
(
$this
->
_sCacheFile
)
.
" ("
.
date
(
"d.m.y - H:i:s"
,
filemtime
(
$this
->
_sCacheFile
))
.
")</td></tr>
<tr><td><strong>ttl: </strong></td><td>"
.
$this
->
getTtl
()
.
" s</td></tr>
"
.
(
$this
->
getTtl
()
<
0
?
''
:
"<tr><td><strong>expires: </strong></td><td>"
.
$this
->
getExpire
()
.
" ("
.
date
(
"d.m.y - H:i:s"
,
$this
->
getExpire
())
.
") "
.
(
$this
->
iExpired
()
>
0
?
'<span class="outdated">'
.
$this
->
iExpired
()
.
' s EXPIRED</span>'
:
' ... <span class="ok">'
.
-
$this
->
iExpired
()
.
" s left"
)
.
"</td></tr>"
)
.
"<tr><td><strong>age: </strong></td><td>"
.
$this
->
getAge
()
.
" s</td></tr>"
.
"<tr><td><strong>reference file: </strong></td><td>"
.
(
$this
->
getRefFile
()
?
$this
->
getRefFile
()
:
'NONE'
)
.
" </td></tr>"
.
"<br>
</table>
<strong>data in the cache:</strong>
<pre>"
;
$sReturn
.
=
htmlentities
(
print_r
(
$this
->
_aCacheInfos
,
1
));
$sReturn
.
=
"</pre><hr>"
;
}
else
{
$sReturn
.
=
"</table>Cache file does not exist (yet).<br>
Maybe the _sDivider was changed in another cache instance.<br>
"
;
}
echo
$sReturn
;
return
true
;
}
// ----------------------------------------------------------------------
/**
* public function getCacheData() - read cachedata if it exist
* @return various cachedata or false if cache does not exist
*/
public
function
read
()
{
if
(
!
isset
(
$this
->
_aCacheInfos
[
'data'
]))
$this
->
_getAllCacheData
();
if
(
!
isset
(
$this
->
_aCacheInfos
[
'data'
]))
return
false
;
return
$this
->
_aCacheInfos
[
'data'
];
}
// ----------------------------------------------------------------------
/**
* public function getCacheAge() - get age in seconds of exisiting cachefile
* @return int age in seconds; -1 if cachefiles does not exist
*/
public
function
getAge
()
{
if
(
!
isset
(
$this
->
_aCacheInfos
[
'stat'
]))
{
$this
->
_getAllCacheData
();
}
if
(
!
isset
(
$this
->
_aCacheInfos
[
'stat'
]))
{
return
-
1
;
}
return
date
(
"U"
)
-
$this
->
_aCacheInfos
[
'stat'
][
'mtime'
];
}
// ----------------------------------------------------------------------
/**
* public function setData($data) - set cachedata into cache object
* data can be any serializable type, like string, array or object
* Remark: You additionally need to call the write() method to store data in the filesystem
* @since 2.0
* @param various $data data to store in cache
* @return boolean
*/
public
function
setData
(
$data
)
{
return
$this
->
_aCacheInfos
[
'data'
]
=
$data
;
}
// ----------------------------------------------------------------------
/**
* public function getExpire() - get TS of cache expiration
* @since 2.0
* @return int unix ts of cache expiration
*/
public
function
getExpire
()
{
return
$this
->
_tsExpire
;
}
// ----------------------------------------------------------------------
/**
* public function setTtl() - set TTL of cache in seconds
* You need to write the cache data to ap
* Remark: You additionally need to call the write() method to store a new ttl value with
* data in the filesystem
* @since 2.0
* @param type $iTtl ttl value in seconds
* @return int get ttl of cache
*/
public
function
setTtl
(
$iTtl
)
{
return
$this
->
_iTtl
=
$iTtl
;
}
// ----------------------------------------------------------------------
/**
* public function getRefFile() - get reference file that invalidates the
* cache item
* @since 2.8
* @return int get ttl of cache
*/
public
function
getRefFile
()
{
return
$this
->
_sRefFile
;
}
// ----------------------------------------------------------------------
/**
* public function touch() - touch cachefile if it exist
* For cachedata with a ttl a new expiration will be set
* @return boolean
*/
public
function
touch
()
{
if
(
!
file_exists
(
$this
->
_sCacheFile
))
return
false
;
// ----------------------------------------------------------------------
/**
* public function getTtl() - get TTL of cache in seconds
* @since 2.0
* @return int get ttl of cache
*/
public
function
getTtl
()
{
return
$this
->
_iTtl
;
}
// touch der Datei reicht nicht mehr, weil tsExpire verloren ginge
if
(
!
$this
->
_iTtl
)
$bReturn
=
touch
(
$this
->
_sCacheFile
);
else
$bReturn
=
$this
->
write
();
$this
->
_getAllCacheData
();
// ----------------------------------------------------------------------
/**
* public function isExpired() - cache expired? To check it
* you must use ttl while writing data, i.e.
* $oCache->write($sData, [$iTtl, [RefFile]]);
* A cache item is expired if
* - the module remove file is newer
* - if a ttl was set: the min. ttl
* @since 2.0
* @return bool cache is expired?
*/
public
function
isExpired
()
{
// cache data already exist? $this->_aCacheInfos is set by constructor
// in the read method
if
(
!
isset
(
$this
->
_aCacheInfos
[
'data'
]))
{
return
true
;
}
// check if remove file was touched
$iAgeOfCache
=
$this
->
getAge
();
if
(
$iAgeOfCache
>
(
date
(
"U"
)
-
filemtime
(
$this
->
_sCacheRemovefile
)))
{
return
true
;
}
// check if cahe item is expired
if
(
$this
->
_tsExpire
&&
(
date
(
"U"
)
>
$this
->
_tsExpire
))
{
return
true
;
}
// check timestamp of reference file (if one was set)
return
!
$this
->
isNewerThanFile
();
}
// ----------------------------------------------------------------------
/**
* public function iExpired() - get time in seconds when cachefile expires
* you must use ttl while writing data, i.e.
* $oCache->write($sData, $iTtl);
* @since 2.1
* @return int expired time in seconds; negative if cache is not expired
*/
public
function
iExpired
()
{
if
(
!
$this
->
_tsExpire
)
{
return
true
;
}
return
date
(
"U"
)
-
$this
->
_tsExpire
;
}
return
$bReturn
;
}
// ----------------------------------------------------------------------
/**
* function isNewerThanFile($sRefFile) - is the cache (still) newer than
* a reference file? This function returns difference of mtime of both
* files.
* @since 2.0
* @param string $sRefFile local filename
* @return integer time in sec how much the cache file is newer; negative if reference file is newer
*/
public
function
isNewerThanFile
(
$sRefFile
=
null
)
{
if
(
is_null
(
$sRefFile
))
{
$sRefFile
=
$this
->
_sRefFile
;
}
if
(
!
$sRefFile
||
!
file_exists
(
$sRefFile
))
{
return
true
;
}
if
(
!
isset
(
$this
->
_aCacheInfos
[
'stat'
]))
{
return
false
;
}
$aTmp
=
stat
(
$sRefFile
);
$iTimeRef
=
$aTmp
[
'mtime'
];
//echo $this->_sCacheFile."<br>".$this->_aCacheInfos['stat']['mtime']."<br>".$iTimeRef."<br>".($this->_aCacheInfos['stat']['mtime'] - $iTimeRef);
return
$this
->
_aCacheInfos
[
'stat'
][
'mtime'
]
-
$iTimeRef
;
}
// ----------------------------------------------------------------------
/**
* Write data into a cache.
* - data can be any serializable type, like string, array or object
* - set ttl in s (from now); optional parameter
* @param various $data data to store in cache
* @param int $iTtl time in s if content cache expires (min. 0)
* @return bool success of write action
*/
public
function
write
(
$data
=
false
,
$iTtl
=
-
1
)
{
if
(
!
$this
->
_sCacheFile
)
// ----------------------------------------------------------------------
/**
* load cache item from a given file - this is like reverse engineering
* by reading data file; needed for a admin interface only
*
* @since 2.6
* @param string $sFile filename with full path
* @return boolean
*/
public
function
loadCachefile
(
$sFile
)
{
$this
->
_sCacheFile
=
false
;
$this
->
sModule
=
false
;
$this
->
sCacheID
=
false
;
if
(
file_exists
(
$sFile
))
{
$this
->
_sCacheFile
=
$sFile
;
$this
->
_getAllCacheData
();
// reverse engineered _sCacheDirDivider
$sRelfile
=
str_replace
(
$this
->
_sCacheDir
.
"/"
.
$this
->
sModule
,
''
,
$this
->
_sCacheFile
);
$sTmp
=
preg_replace
(
'#^\/([0-9a-f]*)([/\.].*)#'
,
'$1'
,
$sRelfile
);
$this
->
_sCacheDirDivider
=
strlen
(
$sTmp
);
return
true
;
}
return
false
;
}
$sDir
=
dirname
(
$this
->
_sCacheFile
);
if
(
!
is_dir
(
$sDir
))
if
(
!
mkdir
(
$sDir
,
0750
,
true
))
die
(
"ERROR: unable to create directory "
.
$sDir
);
// ----------------------------------------------------------------------
/**
* public function getCacheData() - read cachedata if it exist
* @return various cachedata or false if cache does not exist
*/
public
function
read
()
{
if
(
!
isset
(
$this
->
_aCacheInfos
[
'data'
]))
{
$this
->
_getAllCacheData
();
}
if
(
!
isset
(
$this
->
_aCacheInfos
[
'data'
]))
{
return
false
;
}
return
$this
->
_aCacheInfos
[
'data'
];
}
// ----------------------------------------------------------------------
/**
* delete module based remove file
*
* @since 2.6
* @return boolean
*/
public
function
removefileDelete
()
{
if
(
file_exists
(
$this
->
_sCacheRemovefile
))
{
return
unlink
(
$this
->
_sCacheRemovefile
);
}
return
false
;
}
// ----------------------------------------------------------------------
/**
* make all cache items invalid by touching the remove file
*
* @since 2.6
* @return boolean
*/
public
function
removefileTouch
()
{
return
touch
(
$this
->
_sCacheRemovefile
);
}
// ----------------------------------------------------------------------
/**
* public function setData($data) - set cachedata into cache object
* data can be any serializable type, like string, array or object
* Remark: You additionally need to call the write() method to store data in the filesystem
* @since 2.0
* @param various $data data to store in cache
* @return boolean
*/
public
function
setData
(
$data
)
{
return
$this
->
_aCacheInfos
[
'data'
]
=
$data
;
}
/**
* set new cache id; it keeps current module
* @param string $sCacheID cache-id (must be uniq within a module; used to generate filename of cachefile)
* adding the cache id is recommendet, otherwise
* you addiionally need to call setCacheId()
* @return boolean
*/
public
function
setCacheId
(
$sCacheID
)
{
$this
->
sCacheID
=
$sCacheID
;
if
(
!
$data
===
false
)
$this
->
setData
(
$data
);
$this
->
_setup
();
if
(
!
$iTtl
>=
0
)
{
$this
->
setTtl
(
$iTtl
);
$this
->
_getCacheFilename
();
$this
->
read
();
return
true
;
}
/**
* set module
* @param string $sModule name of module or app that uses the cache
* @param string $sCacheID optional: cache-id (must be uniq within a module; used to generate filename of cachefile)
* adding the cache id is recommendet, otherwise
* you addiionally need to call setCacheId()
* @return boolean
*/
public
function
setModule
(
$sModule
,
$sCacheID
=
false
)
{
$this
->
sModule
=
$sModule
;
return
$this
->
setCacheId
(
$sCacheID
);
}
// ----------------------------------------------------------------------
/**
* public function setRefFile() - set a reference file that invalidates the
* cache if the file is newer than the stored item
* @since 2.8
* @param int $iTtl ttl value in seconds
* @return int get ttl of cache
*/
public
function
setRefFile
(
$sFile
)
{
return
$this
->
_sRefFile
=
$sFile
;
}
// ----------------------------------------------------------------------
/**
* public function setTtl() - set TTL of cache in seconds
* You need to write the cache data to ap
* Remark: You additionally need to call the write() method to store a new ttl value with
* data in the filesystem
* @since 2.0
* @param int $iTtl ttl value in seconds
* @return int get ttl of cache
*/
public
function
setTtl
(
$iTtl
)
{
return
$this
->
_iTtl
=
$iTtl
;
}
$aTmp
=
array
(
'iTtl'
=>
$this
->
_iTtl
,
'tsExpire'
=>
date
(
"U"
)
+
$this
->
_iTtl
,
'module'
=>
$this
->
sModule
,
'cacheid'
=>
$this
->
sCacheID
,
'data'
=>
$this
->
_aCacheInfos
[
'data'
],
);
return
file_put_contents
(
$this
->
_sCacheFile
,
serialize
(
$aTmp
));
}
// ----------------------------------------------------------------------
/**
* public function touch() - touch cachefile if it exist
* For cached data a new expiration based on existing ttl will be set
* @return boolean
*/
public
function
touch
()
{
if
(
!
file_exists
(
$this
->
_sCacheFile
))
{
return
false
;
}
// touch der Datei reicht nicht mehr, weil tsExpire verloren ginge
if
(
!
$this
->
_iTtl
)
{
$bReturn
=
touch
(
$this
->
_sCacheFile
);
}
else
{
$bReturn
=
$this
->
write
();
}
$this
->
_getAllCacheData
();
return
$bReturn
;
}
// ----------------------------------------------------------------------
/**
* Write data into a cache.
* - data can be any serializable type, like string, array or object
* - set ttl in s (from now); optional parameter
* @param various $data data to store in cache
* @param int $iTtl optional: time in s if content cache expires (min. 0)
* @param string $sRefFile optional: set a reference file that invalidates the cache if it is newer
* @return bool success of write action
*/
public
function
write
(
$data
=
false
,
$iTtl
=
null
,
$sRefFile
=
null
)
{
if
(
!
$this
->
_sCacheFile
)
{
return
false
;
}
$sDir
=
dirname
(
$this
->
_sCacheFile
);
if
(
!
is_dir
(
$sDir
))
{
if
(
!
mkdir
(
$sDir
,
0750
,
true
))
{
die
(
"ERROR: unable to create directory "
.
$sDir
);
}
}
if
(
!
$data
===
false
)
{
$this
->
setData
(
$data
);
}
if
(
!
is_null
(
$iTtl
))
{
$this
->
setTtl
(
$iTtl
);
}
if
(
!
is_null
(
$sRefFile
))
{
$this
->
setRefFile
(
$sRefFile
);
}
$aTmp
=
[
'iTtl'
=>
$this
->
_iTtl
,
'sRefFile'
=>
$this
->
_sRefFile
,
'tsExpire'
=>
date
(
"U"
)
+
$this
->
_iTtl
,
'module'
=>
$this
->
sModule
,
'cacheid'
=>
$this
->
sCacheID
,
'data'
=>
isset
(
$this
->
_aCacheInfos
[
'data'
])
?
$this
->
_aCacheInfos
[
'data'
]
:
''
,
];
return
file_put_contents
(
$this
->
_sCacheFile
,
serialize
(
$aTmp
));
}
}
}
// ----------------------------------------------------------------------
Loading