Add upstream plugins

Signed-off-by: Adrian Nöthlich <git@promasu.tech>
This commit is contained in:
2019-10-25 22:42:20 +02:00
parent 5d3c2ec184
commit 290736650a
1186 changed files with 302577 additions and 0 deletions

View File

@@ -0,0 +1,13 @@
<?php
/**
* Exception thrown when reading from cache.
*
* @author Time.ly Network, Inc.
* @since 2.0
* @package Ai1EC
* @subpackage Ai1EC.Cache.Exception
*/
class Ai1ec_Cache_Not_Set_Exception extends Ai1ec_Exception {
}

View File

@@ -0,0 +1,13 @@
<?php
/**
* Exception thrown when failing to write to cache.
*
* @author Time.ly Network, Inc.
* @since 2.0
* @package Ai1EC
* @subpackage Ai1EC.Cache.Exception
*/
class Ai1ec_Cache_Write_Exception extends Ai1ec_Exception {
}

View File

@@ -0,0 +1,52 @@
<?php
/**
* Interface for cache engines.
*
* @author Time.ly Network, Inc.
* @since 2.0
* @package Ai1EC
* @subpackage Ai1EC.Cache
*/
interface Ai1ec_Cache_Interface {
/**
* Set entry to cache.
*
* @param string $key Key for which value must be stored.
* @param mixed $value Actual value to store.
*
* @return bool Success.
*/
public function set( $key, $value );
/**
* Add entry to cache if one does not exist.
*
* @param string $key Key for which value must be stored.
* @param mixed $value Actual value to store.
*
* @return bool Success.
*/
public function add( $key, $value );
/**
* Retrieve value from cache.
*
* @param string $key Key for which to retrieve value.
* @param mixed $default Value to return if none found.
*
* @return mixed Previously stored or $default value.
*/
public function get( $key, $default = NULL );
/**
* Delete value from cache.
*
* @param string $key Key for value to remove.
*
* @return bool Success.
*/
public function delete( $key );
}

View File

@@ -0,0 +1,102 @@
<?php
/**
* In-memory cache storage engine.
*
* Store values in memory, for use in a single session scope.
*
* @instantiator new
* @author Time.ly Network, Inc.
* @since 2.0
* @package Ai1EC
* @subpackage Ai1EC.Cache
*/
final class Ai1ec_Cache_Memory implements Ai1ec_Cache_Interface {
/**
* @var array Map of memory entries.
*/
protected $_entries = array();
/**
* @var int Number of entries to hold in map.
*/
protected $_limit = 0;
/**
* Constructor initiates stack (memory) length.
*
* @param int $limit Number of entries specific to this location.
*
* @return void Constructor does not return.
*/
public function __construct( $limit = 50 ) {
$limit = (int)$limit;
if ( $limit < 10 ) {
$limit = 10;
}
$this->_limit = $limit;
}
/**
* Write data to memory under given key.
*
* @param string $key Key under which value must be written.
* @param mixed $value Value to associate with given key.
*
* @return bool Success.
*/
public function set( $key, $value ) {
if ( count( $this->_entries ) > $this->_limit ) {
array_shift( $this->_entries ); // discard
}
$this->_entries[$key] = $value;
return true;
}
/**
* Add data to memory under given key, if it does not exist.
*
* @param string $key Key under which value must be added.
* @param mixed $value Value to associate with given key.
*
* @return bool Success.
*/
public function add( $key, $value ) {
if ( isset( $this->_entries[$key] ) ) {
return false;
}
return $this->set( $key, $value );
}
/**
* Retrieve data from memory, stored under specified key.
*
* @param string $key Key under which value is expected to be.
* @param mixed $default Value to return if nothing is found.
*
* @return mixed Found value or {$default}.
*/
public function get( $key, $default = NULL ) {
if ( ! isset( $this->_entries[$key] ) ) {
return $default;
}
return $this->_entries[$key];
}
/**
* Remove entry from cache table.
*
* @param string $key Key to be removed.
*
* @return bool Success.
*/
public function delete( $key ) {
if ( ! isset( $this->_entries[$key] ) ) {
return false;
}
unset( $this->_entries[$key] );
return true;
}
}

View File

@@ -0,0 +1,47 @@
<?php
/**
* Base class for caching strategy.
*
*
* @author Time.ly Network, Inc.
* @since 2.0
* @package Ai1EC
* @subpackage Ai1EC.Cache.Strategy
*/
abstract class Ai1ec_Cache_Strategy extends Ai1ec_Base {
/**
* Retrieves the data store for the passed key
*
* @param string $key
* @throws Ai1ec_Cache_Not_Set_Exception if the key was not set
*/
abstract public function get_data( $key );
/**
* Write the data to the persistence Layer
*
* @throws Ai1ec_Cache_Write_Exception
* @param string $key
* @param string $value
*/
abstract public function write_data( $key, $value );
/**
* Deletes the data associated with the key from the persistence layer.
*
* @param string $key
*/
abstract public function delete_data( $key );
/**
* Delete multiple cache entries matching given pattern
*
* @param string $pattern Scalar pattern, which shall match key
*
* @return int Count of entries deleted
*/
abstract public function delete_matching( $pattern );
}

View File

@@ -0,0 +1,118 @@
<?php
/**
* Concrete class for APC caching strategy.
*
* @instantiator new
* @author Time.ly Network, Inc.
* @since 2.0
* @package Ai1EC
* @subpackage Ai1EC.Cache.Strategy
*/
class Ai1ec_Cache_Strategy_Apc extends Ai1ec_Cache_Strategy {
/**
* is_available method
*
* Checks if APC is available for use.
* Following pre-requisites are checked: APC functions availability,
* APC is enabled via configuration and PHP is not running in CGI.
*
* @return bool Availability
*/
static public function is_available() {
return function_exists( 'apc_store' ) &&
function_exists( 'apc_fetch' ) &&
ini_get( 'apc.enabled' ) &&
( false === strpos( php_sapi_name(), 'cgi' ) );
}
/**
*
* @see Ai1ec_Get_Data_From_Cache::get_data()
*
*/
public function get_data( $dist_key ) {
$key = $this->_key( $dist_key );
$data = apc_fetch( $key );
if ( false === $data ) {
throw new Ai1ec_Cache_Not_Set_Exception( "$dist_key not set" );
}
return $data;
}
/**
*
* @see Ai1ec_Write_Data_To_Cache::write_data()
*
*/
public function write_data( $dist_key, $value ) {
$key = $this->_key( $dist_key );
$store_method = 'apc_add';
if ( false !== ( $existing = apc_fetch( $key ) ) ) {
if ( $value === $existing ) {
return true;
}
$store_method = 'apc_store';
} elseif ( false === function_exists( $store_method ) ) {
$store_method = 'apc_store';
}
if ( false === $store_method( $key, $value ) ) {
try {
if ( $value !== $this->get_data( $key ) ) {
throw new Ai1ec_Cache_Not_Set_Exception( 'Data mis-match' );
}
} catch ( Ai1ec_Cache_Not_Set_Exception $excpt ) {
throw new Ai1ec_Cache_Not_Set_Exception(
'Failed to write ' . $dist_key . ' to APC cache'
);
}
}
return true;
}
/**
* (non-PHPdoc)
* @see Ai1ec_Write_Data_To_Cache::delete_data()
*/
public function delete_data( $key ) {
if ( false === apc_delete( $this->_key( $key ) ) ) {
return false;
}
return true;
}
/**
*
* @see Ai1ec_Write_Data_To_Cache::delete_matching()
*/
public function delete_matching( $pattern ) {
// not implemented - concider flushing APC cache
return 0;
}
/**
* _key method
*
* Make sure we are on the safe side - in case of multi-instances
* environment some prefix is required.
*
* @param string $key Key to be used against APC cache
*
* @return string Key with prefix prepended
*/
protected function _key( $key ) {
static $prefix = null;
if ( NULL === $prefix ) {
$prefix = substr( md5( ai1ec_get_site_url() ), 0, 8 );
}
if ( 0 !== strncmp( $key, $prefix, 8 ) ) {
$key = $prefix . $key;
}
return $key;
}
}

View File

@@ -0,0 +1,102 @@
<?php
/**
* Concrete class for DB caching strategy.
*
* @instantiator new
* @author Time.ly Network, Inc.
* @since 2.0
* @package Ai1EC
* @subpackage Ai1EC.Cache.Strategy
*/
class Ai1ec_Cache_Strategy_Db extends Ai1ec_Cache_Strategy {
/**
* @var Ai1ec_Option Instance of database adapter
*/
private $model_option;
public function __construct( Ai1ec_Registry_Object $registry, Ai1ec_Option $option ) {
parent::__construct( $registry );
$this->model_option = $option;
}
/**
*
* @see Ai1ec_Get_Data_From_Cache::get_data()
*
*/
public function get_data( $key ) {
$key = $this->_key( $key );
$data = $this->model_option->get( $key );
if ( false === $data ) {
throw new Ai1ec_Cache_Not_Set_Exception(
'No data under \'' . $key . '\' present'
);
}
return maybe_unserialize( $data );
}
/**
*
* @see Ai1ec_Write_Data_To_Cache::write_data()
*
*/
public function write_data( $key, $value ) {
$result = $this->model_option->set(
$this->_key( $key ),
maybe_serialize( $value )
);
if ( false === $result ) {
throw new Ai1ec_Cache_Write_Exception(
'An error occured while saving data to \'' . $key . '\''
);
}
}
/**
* (non-PHPdoc)
* @see Ai1ec_Write_Data_To_Cache::delete_data()
*/
public function delete_data( $key ) {
return $this->model_option->delete(
$this->_key( $key )
);
}
/**
*
* @see Ai1ec_Write_Data_To_Cache::delete_matching()
*/
public function delete_matching( $pattern ) {
$db = $this->_registry->get( 'dbi.dbi' );
$sql_query = $db->prepare(
'SELECT option_name FROM ' . $db->get_table_name( 'options' ) .
' WHERE option_name LIKE %s',
'%%' . $pattern . '%%'
);
$keys = $db->get_col( $sql_query );
foreach ( $keys as $key ) {
$this->model_option->delete( $key );
}
return count( $keys );
}
/**
* _key method
*
* Get safe key name to use within options API
*
* @param string $key Key to sanitize
*
* @return string Safe to use key
*/
protected function _key( $key ) {
if ( strlen( $key ) > 53 ) {
$hash = md5( $key );
$key = substr( $key, 0, 16 ) . '_' . $hash;
}
return $key;
}
}

View File

@@ -0,0 +1,177 @@
<?php
/**
* Concrete class for file caching strategy.
*
* @instantiator new
* @author Time.ly Network, Inc.
* @since 2.0
* @package Ai1EC
* @subpackage Ai1EC.Cache.Strategy
*/
class Ai1ec_Cache_Strategy_File extends Ai1ec_Cache_Strategy {
/**
* @var string
*/
private $_cache_dir;
private $_cache_url;
public function __construct( Ai1ec_Registry_Object $registry, array $cache_dir ) {
parent::__construct( $registry );
$this->_cache_dir = $cache_dir['path'];
$this->_cache_url = $cache_dir['url'];
}
/**
*
* @see Ai1ec_Get_Data_From_Cache::get_data()
*
*/
public function get_data( $file ) {
$file = $this->_get_file_name( $file );
if ( ! $file || ! file_exists( $this->_cache_dir . $file ) ) {
throw new Ai1ec_Cache_Not_Set_Exception(
'File \'' . $file . '\' does not exist'
);
}
return maybe_unserialize(
file_get_contents( $this->_cache_dir . $file )
);
}
/**
*
* @see Ai1ec_Write_Data_To_Cache::write_data()
*
*/
public function write_data( $filename, $value ) {
$filename = $this->_safe_file_name( $filename );
$value = maybe_serialize( $value );
$result = $this->_registry->get( 'filesystem.checker' )->put_contents(
$this->_cache_dir . $filename,
$value
);
if ( false === $result ) {
$message = 'An error occured while saving data to \'' .
$this->_cache_dir . $filename . '\'';
throw new Ai1ec_Cache_Write_Exception( $message );
}
return array(
'path' => $this->_cache_dir . $filename,
'url' => $this->_cache_url . $filename,
'file' => $filename,
);
}
/**
* (non-PHPdoc)
* @see Ai1ec_Write_Data_To_Cache::delete_data()
*/
public function delete_data( $filename ) {
// Check if file exists. It might not exists if you switch themes
// twice without never rendering the CSS
$filename = $this->_safe_file_name( $filename );
if (
file_exists( $this->_cache_dir . $filename ) &&
false === unlink( $this->_cache_dir . $filename )
) {
return false;
}
return true;
}
/**
*
* @see Ai1ec_Write_Data_To_Cache::delete_matching()
*/
public function delete_matching( $pattern ) {
$dirhandle = opendir( $this->_cache_dir );
if ( false === $dirhandle ) {
return 0;
}
$count = 0;
while ( false !== ( $entry = readdir( $dirhandle ) ) ) {
if ( '.' !== $entry{0} && false !== strpos( $entry, $pattern ) ) {
if ( unlink( $this->_cache_dir . $entry ) ) {
++$count;
}
}
}
closedir( $dirhandle );
return $count;
}
/**
* Get the extension for the file if required
*
* @param string $file
*
* @return string
*/
protected function _get_extension_for_file( $file ) {
$extensions = array(
'ai1ec_parsed_css' => '.css'
);
if ( isset( $extensions[$file] ) ) {
return $extensions[$file];
}
return '';
}
/**
* Tries to get the stored filename
*
* @param string $file
*
* @return boolean | string
*/
protected function _get_file_name( $file ) {
static $file_map = array(
'ai1ec_parsed_css' => 'ai1ec_filename_css',
);
if ( isset ( $file_map[$file] ) ) {
return $this->_registry->get( 'model.option' )->get( $file_map[$file] );
}
return false;
}
/**
* _safe_file_name method
*
* Generate safe file name for any storage case.
*
* @param string $file File name currently supplied
*
* @return string Sanitized file name
*/
protected function _safe_file_name( $file ) {
static $prefix = null;
$extension = $this->_get_extension_for_file( $file );
if ( null === $prefix ) {
// always include site_url when there is more than one
$pref_string = ai1ec_site_url();
if ( ! AI1EC_DEBUG ) {
// address multiple re-saves for a single version
// i.e. when theme settings are being edited
$pref_string .= mt_rand();
}
$prefix = substr( md5( $pref_string ), 0, 8 );
}
$length = strlen( $file );
if ( ! ctype_alnum( $file ) ) {
$file = preg_replace(
'|_+|',
'_',
preg_replace( '|[^a-z0-9\-,_]|', '_', $file )
);
}
if ( 0 !== strncmp( $file, $prefix, 8 ) ) {
$file = $prefix . '_' . $file;
}
return $file . $extension;
}
}

View File

@@ -0,0 +1,106 @@
<?php
/**
* The context class which handles the caching strategy.
*
* @instantiator Ai1ec_Factory_Strategy.create_persistence_context
* @author Time.ly Network, Inc.
* @since 2.0
* @package Ai1EC
* @subpackage Ai1EC.Cache.Strategy
*/
class Ai1ec_Persistence_Context {
/**
* @var string
*/
private $key_for_persistance;
/**
*
* @var Ai1ec_Cache_Strategy
*/
private $cache_strategy;
/**
*
* @param string $key_for_peristance
* @param Ai1ec_Cache_Strategy $cache_strategy
*/
public function __construct(
$key_for_persistance,
Ai1ec_Cache_Strategy $cache_strategy
) {
$this->cache_strategy = $cache_strategy;
$this->key_for_persistance = $key_for_persistance;
}
/**
* @throws Ai1ec_Cache_Not_Set_Exception
* @return string
*/
public function get_data_from_persistence() {
try {
$data = $this->cache_strategy->get_data( $this->key_for_persistance );
}
catch ( Ai1ec_Cache_Not_Set_Exception $e ) {
throw $e;
}
return $data;
}
/**
* Are we using file cache?
*
* @return boolean
*/
public function is_file_cache() {
return $this->cache_strategy instanceof Ai1ec_Cache_Strategy_File;
}
/**
* write_data_to_persistence method
*
* Write data to persistance layer. If that fails - false is returned.
* Exceptions are suspended, as cache write is not a fatal error by no
* mean, thus shall not be escalated further. If you want exception to
* be escalated - use lower layer method directly.
*
* @param mixed $data Unserialized data to write
*
* @return boll Success
*/
public function write_data_to_persistence( $data ) {
$return = true;
try {
$return = $this->cache_strategy->write_data(
$this->key_for_persistance,
$data
);
} catch ( Ai1ec_Cache_Write_Exception $e ) {
$return = false;
}
return $return;
}
/**
* Deletes the data stored in cache.
*/
public function delete_data_from_persistence() {
$this->cache_strategy->delete_data( $this->key_for_persistance );
}
/**
* delete_matching_entries_from_persistence method
*
* Delete matching entries from persistance.
*
* @param string $pattern Expected pattern, to be contained within key
*
* @return int Count of entries deleted
*/
public function delete_matching_entries_from_persistence( $pattern ) {
return $this->cache_strategy->delete_matching( $pattern );
}
}

View File

@@ -0,0 +1,59 @@
<?php
/**
* Concrete class for void caching strategy.
*
* @instantiator new
* @author Time.ly Network, Inc.
* @since 2.0
* @package Ai1EC
* @subpackage Ai1EC.Cache.Strategy
*/
class Ai1ec_Cache_Strategy_Void extends Ai1ec_Cache_Strategy {
/**
* Checks if engine is available
*
* @return bool Always true
*/
static public function is_available() {
return true;
}
/**
*
* @see Ai1ec_Get_Data_From_Cache::get_data()
*
*/
public function get_data( $dist_key ) {
throw new Ai1ec_Cache_Not_Set_Exception( "'$dist_key' not set" );
}
/**
*
* @see Ai1ec_Write_Data_To_Cache::write_data()
*
*/
public function write_data( $dist_key, $value ) {
throw new Ai1ec_Cache_Not_Set_Exception(
'Failed to write \'' . $dist_key . '\' to void cache'
);
}
/**
* (non-PHPdoc)
* @see Ai1ec_Write_Data_To_Cache::delete_data()
*/
public function delete_data( $key ) {
return false;
}
/**
*
* @see Ai1ec_Write_Data_To_Cache::delete_matching()
*/
public function delete_matching( $pattern ) {
return 0;
}
}