Merge pull request #6648 from open-sausages/pulls/4.0/6252-psr-cache

PSR-16 cache
This commit is contained in:
Sam Minnée 2017-02-26 14:57:33 +13:00 committed by GitHub
commit dcd06dfc64
81 changed files with 535 additions and 14086 deletions

View File

@ -1,6 +1,6 @@
<?php
use SilverStripe\Core\Cache;
use Psr\SimpleCache\CacheInterface;
use SilverStripe\Dev\Deprecation;
use SilverStripe\View\Parsers\ShortcodeParser;
@ -32,12 +32,6 @@ ShortcodeParser::get('regenerator')
// @todo
// ->register('dbfile_link', array('DBFile', 'handle_shortcode'))
// Zend_Cache temp directory setting
$_ENV['TMPDIR'] = TEMP_FOLDER; // for *nix
$_ENV['TMP'] = TEMP_FOLDER; // for Windows
Cache::set_cache_lifetime('GDBackend_Manipulations', null, 100);
// If you don't want to see deprecation errors for the new APIs, change this to 3.2.0-dev.
Deprecation::notification_version('3.2.0');

22
_config/cache.yml Normal file
View File

@ -0,0 +1,22 @@
---
Name: corecache
---
SilverStripe\Core\Injector\Injector:
SilverStripe\Core\Cache\CacheFactory:
class: 'SilverStripe\Core\Cache\DefaultCacheFactory'
constructor:
directory: `TEMP_FOLDER`
Psr\SimpleCache\CacheInterface.GDBackend_Manipulations:
factory: SilverStripe\Core\Cache\CacheFactory
constructor:
namespace: "GDBackend_Manipulations"
defaultLifetime: 100
Psr\SimpleCache\CacheInterface.cacheblock:
factory: SilverStripe\Core\Cache\CacheFactory
constructor:
namespace: "cacheblock"
defaultLifetime: 600
Psr\SimpleCache\CacheInterface.LeftAndMain_CMSVersion:
factory: SilverStripe\Core\Cache\CacheFactory
constructor:
namespace: "LeftAndMain_CMSVersion"

View File

@ -17,7 +17,7 @@ use SilverStripe\Control\Controller;
use SilverStripe\Control\PjaxResponseNegotiator;
use SilverStripe\Core\Convert;
use SilverStripe\Core\Config\Config;
use SilverStripe\Core\Cache;
use Psr\SimpleCache\CacheInterface;
use SilverStripe\Core\ClassInfo;
use SilverStripe\Core\Injector\Injector;
use SilverStripe\Dev\Deprecation;
@ -2020,9 +2020,9 @@ class LeftAndMain extends Controller implements PermissionProvider
// Tries to obtain version number from composer.lock if it exists
$composerLockPath = BASE_PATH . '/composer.lock';
if (file_exists($composerLockPath)) {
$cache = Cache::factory('LeftAndMain_CMSVersion');
$cacheKey = filemtime($composerLockPath);
$versions = $cache->load($cacheKey);
$cache = Injector::inst()->get(CacheInterface::class . '.LeftAndMain_CMSVersion');
$cacheKey = (string)filemtime($composerLockPath);
$versions = $cache->get($cacheKey);
if ($versions) {
$versions = json_decode($versions, true);
} else {
@ -2038,7 +2038,7 @@ class LeftAndMain extends Controller implements PermissionProvider
$versions[$package->name] = $package->version;
}
}
$cache->save(json_encode($versions), $cacheKey);
$cache->set($cacheKey, json_encode($versions));
}
}
}

View File

@ -23,6 +23,7 @@
"symfony/yaml": "~2.7",
"embed/embed": "^2.6",
"swiftmailer/swiftmailer": "~5.4",
"symfony/cache": "^3.3@dev",
"symfony/config": "^2.8",
"symfony/translation": "^2.8",
"vlucas/phpdotenv": "^2.4"

View File

@ -30,8 +30,7 @@ When we render `$Counter` to the template we would expect the value to increase
## Partial caching
Partial caching is a feature that allows the caching of just a portion of a page. Instead of fetching the required data
from the database to display, the contents of the area are fetched from the `TEMP_FOLDER` file-system pre-rendered and
ready to go. More information about Partial caching is in the [Performance](../performance) guide.
from the database to display, the contents of the area are fetched from a [cache backend](../performance/caching).
:::ss
<% cached 'MyCachedContent', LastEdited %>

View File

@ -1,10 +1,10 @@
# Caching
## Built-In Caches
## Overview
The framework uses caches to store infrequently changing values.
By default, the storage mechanism is simply the filesystem, although
other cache backends can be configured. All caches use the [api:Cache] API.
By default, the storage mechanism chooses the most performant adapter available
(PHP7 opcache, APC, or filesystem). Other cache backends can be configured.
The most common caches are manifests of various resources:
@ -21,136 +21,170 @@ executing the action is limited to the following cases when performed via a web
* A user is logged in with ADMIN permissions
* An error occurs during startup
## The Cache API
## Configuration
The [api:Cache] class provides a bunch of static functions wrapping the Zend_Cache system
in something a little more easy to use with the SilverStripe config system.
We are using the [PSR-16](http://www.php-fig.org/psr/psr-16/) standard ("SimpleCache")
for caching, through the [symfony/cache](https://symfony.com/doc/current/components/cache.html) library.
Note that this library describes usage of [PSR-6](http://www.php-fig.org/psr/psr-6/) by default,
but also exposes caches following the PSR-16 interface.
A `Zend_Cache` has both a frontend (determines how to get the value to cache,
and how to serialize it for storage) and a backend (handles the actual
storage).
Cache objects are configured via YAML
and SilverStripe's [dependency injection](/developer-guides/extending/injector) system.
Rather than require library code to specify the backend directly, cache
consumers provide a name for the cache backend they want. The end developer
can then specify which backend to use for each name in their project's
configuration. They can also use 'all' to provide a backend for all named
caches.
:::yml
SilverStripe\Core\Injector\Injector:
Psr\SimpleCache\CacheInterface.myCache:
factory: SilverStripe\Core\Cache\CacheFactory
constructor:
namespace: "myCache"
End developers provide a set of named backends, then pick the specific
backend for each named cache. There is a default File cache set up as the
'default' named backend, which is assigned to 'all' named caches.
## Using Caches
Caches can be created and retrieved through the `Cache::factory()` method.
The returned object is of type `Zend_Cache`.
Cache objects are instantiated through a [CacheFactory](SilverStripe\Core\Cache\CacheFactory),
which determines which cache adapter is used (see "Adapters" below for details).
This factory allows us you to globally define an adapter for all cache instances.
:::php
// foo is any name (try to be specific), and is used to get configuration
// & storage info
$cache = Cache::factory('foo');
if (!($result = $cache->load($cachekey))) {
$result = caluate some how;
$cache->save($result, $cachekey);
use Psr\SimpleCache\CacheInterface
$cache = Injector::inst()->get(CacheInterface::class . '.myCache');
Caches are namespaced, which might allow granular clearing of a particular cache without affecting others.
In our example, the namespace is "myCache", expressed in the service name as
`Psr\SimpleCache\CacheInterface.myCache`. We recommend the `::class` short-hand to compose the full service name.
Clearing caches by namespace is dependant on the used adapter: While the `FilesystemCache` adapter clears only the namespaced cache,
a `MemcachedCache` adapter will clear all caches regardless of namespace, since the underlying memcached
service doesn't support this. See "Invalidation" for alternative strategies.
## Usage
Cache objects follow the [PSR-16](http://www.php-fig.org/psr/psr-16/) class interface.
:::php
use Psr\SimpleCache\CacheInterface
$cache = Injector::inst()->get(CacheInterface::class . '.myCache');
// create a new item by trying to get it from the cache
$myValue = $cache->get('myCacheKey');
// set a value and save it via the adapter
$cache->set('myCacheKey', 1234);
// retrieve the cache item
if (!$cache->has('myCacheKey')) {
// ... item does not exists in the cache
}
return $result;
Normally there's no need to remove things from the cache - the cache
backends clear out entries based on age and maximum allocated storage. If you
include the version of the object in the cache key, even object changes
don't need any invalidation. You can force disable the cache though,
e.g. in development mode.
## Invalidation
Caches can be invalidated in different ways. The easiest is to actively clear the
entire cache. If the adapter supports namespaced cache clearing,
this will only affect a subset of cache keys ("myCache" in this example):
:::php
// Disables all caches
Cache::set_cache_lifetime('any', -1, 100);
use Psr\SimpleCache\CacheInterface
$cache = Injector::inst()->get(CacheInterface::class . '.myCache');
You can also specifically clean a cache.
Keep in mind that `Zend_Cache::CLEANING_MODE_ALL` deletes all cache
entries across all caches, not just for the 'foo' cache in the example below.
// remove all items in this (namespaced) cache
$cache->clear();
You can also delete a single item based on it's cache key:
:::php
$cache = Cache::factory('foo');
$cache->clean(Zend_Cache::CLEANING_MODE_ALL);
use Psr\SimpleCache\CacheInterface
$cache = Injector::inst()->get(CacheInterface::class . '.myCache');
A single element can be invalidated through its cache key.
// remove the cache item
$cache->delete('myCacheKey');
Individual cache items can define a lifetime, after which the cached value is marked as expired:
:::php
$cache = Cache::factory('foo');
$cache->remove($cachekey);
use Psr\SimpleCache\CacheInterface
$cache = Injector::inst()->get(CacheInterface::class . '.myCache');
// remove the cache item
$cache->set('myCacheKey', 'myValue', 300); // cache for 300 seconds
If a lifetime isn't defined on the `set()` call, it'll use the adapter default.
In order to increase the chance of your cache actually being hit,
it often pays to increase the lifetime of caches ("TTL").
It defaults to 10 minutes (600s) in SilverStripe, which can be
quite short depending on how often your data changes.
Keep in mind that data expiry should primarily be handled by your cache key,
e.g. by including the `LastEdited` value when caching `DataObject` results.
it often pays to increase the lifetime of caches.
You can also set your lifetime to `0`, which means they won't expire.
Since many adapters don't have a way to actively remove expired caches,
you need to be careful with resources here (e.g. filesystem space).
:::yml
SilverStripe\Core\Injector\Injector:
Psr\SimpleCache\CacheInterface.cacheblock:
constructor:
defaultLifetime: 3600
In most cases, invalidation and expiry should be handled by your cache key.
For example, including the `LastEdited` value when caching `DataObject` results
will automatically create a new cache key when the object has been changed.
The following example caches a member's group names, and automatically
creates a new cache key when any group is edited. Depending on the used adapter,
old cache keys will be garbage collected as the cache fills up.
:::php
// set all caches to 3 hours
Cache::set_cache_lifetime('any', 60*60*3);
use Psr\SimpleCache\CacheInterface
$cache = Injector::inst()->get(CacheInterface::class . '.myCache');
## Alternative Cache Backends
// Automatically changes when any group is edited
$cacheKey = implode(['groupNames', $member->ID, Groups::get()->max('LastEdited')]);
$cache->set($cacheKey, $member->Groups()->column('Title'));
By default, SilverStripe uses a file-based caching backend.
Together with a file stat cache like [APC](http://us2.php.net/manual/en/book.apc.php)
this is reasonably quick, but still requires access to slow disk I/O.
The `Zend_Cache` API supports various caching backends ([list](http://framework.zend.com/manual/1.12/en/zend.cache.backends.html))
which can provide better performance, including APC, Xcache, ZendServer, Memcached and SQLite.
If `?flush=1` is requested in the URL, this will trigger a call to `flush()` on
any classes that implement the [Flushable](/developer_guides/execution_pipeline/flushable/)
interface. Use this interface to trigger `clear()` on your caches.
## Cleaning caches on flush=1 requests
## Adapters
If `?flush=1` is requested in the URL, e.g. http://mysite.com?flush=1, this will trigger a call to `flush()` on
any classes that implement the `Flushable` interface. Using this, you can trigger your caches to clean.
SilverStripe tries to identify the most performant cache available on your system
through the [DefaultCacheFactory](api:SilverStripe\Core\Cache\DefaultCacheFactory) implementation:
See [reference documentation on Flushable](/developer_guides/execution_pipeline/flushable/) for implementation details.
* - `PhpFilesCache` (PHP 5.6 or PHP 7 with [opcache](http://php.net/manual/en/book.opcache.php) enabled).
This cache has relatively low [memory defaults](http://php.net/manual/en/opcache.configuration.php#ini.opcache.memory-consumption).
We recommend increasing it for large applications, or enabling the
[file_cache fallback](http://php.net/manual/en/opcache.configuration.php#ini.opcache.file-cache)
* - `ApcuCache` (requires APC) with a `FilesystemCache` fallback (for larger cache volumes)
* - `FilesystemCache` if none of the above is available
### Memcached
The library supports various [cache adapters](https://github.com/symfony/cache/tree/master/Simple)
which can provide better performance, particularly in multi-server environments with shared caches like Memcached.
This backends stores cache records into a [memcached](http://www.danga.com/memcached/)
server. memcached is a high-performance, distributed memory object caching system.
To use this backend, you need a memcached daemon and the memcache PECL extension.
Since we're using dependency injection to create caches,
you need to define a factory for a particular adapter,
following the `SilverStripe\Core\Cache\CacheFactory` interface.
Different adapters will require different constructor arguments.
We've written factories for the most common cache scenarios:
`FilesystemCacheFactory`, `MemcachedCacheFactory` and `ApcuCacheFactory`.
:::php
// _config.php
Cache::add_backend(
'primary_memcached',
'Memcached',
array(
'servers' => array(
'host' => 'localhost',
'port' => 11211,
'persistent' => true,
'weight' => 1,
'timeout' => 5,
'retry_interval' => 15,
'status' => true,
'failure_callback' => null
)
)
);
Cache::pick_backend('primary_memcached', 'any', 10);
Example: Configure core caches to use [memcached](http://www.danga.com/memcached/),
which requires the [memcached PHP extension](http://php.net/memcached),
and takes a `MemcachedClient` instance as a constructor argument.
### APC
:::yml
---
After:
- '#corecache'
---
SilverStripe\Core\Injector\Injector:
MemcachedClient:
class: 'Memcached'
calls:
- [ addServer, [ 'localhost', 11211 ] ]
SilverStripe\Core\Cache\CacheFactory:
class: 'SilverStripe\Core\Cache\MemcachedCacheFactory'
constructor:
client: '%$MemcachedClient
This backends stores cache records in shared memory through the [APC](http://pecl.php.net/package/APC)
(Alternative PHP Cache) extension (which is of course need for using this backend).
## Additional Caches
:::php
Cache::add_backend('primary_apc', 'APC');
Cache::pick_backend('primary_apc', 'any', 10);
Unfortunately not all caches are configurable via cache adapters.
### Two-Levels
This backend is an hybrid one. It stores cache records in two other backends:
a fast one (but limited) like Apc, Memcache... and a "slow" one like File or Sqlite.
:::php
Cache::add_backend('two_level', 'Two-Levels', array(
'slow_backend' => 'File',
'fast_backend' => 'APC',
'slow_backend_options' => array(
'cache_dir' => TEMP_FOLDER . DIRECTORY_SEPARATOR . 'cache'
)
));
Cache::pick_backend('two_level', 'any', 10);
* [SSViewer](api:SilverStripe\View\SSViewer) writes compiled templates as PHP files to the filesystem
(in order to achieve opcode caching on `include()` calls)
* [ConfigManifest](api:SilverStripe\Core\Manifest\ConfigManifest) is hardcoded to use `FilesystemCache`
* [ClassManifest](api:SilverStripe\Core\Manifest\ClassManifest) and [ThemeManifest](api:SilverStripe\View\ThemeManifest)
are using a custom `ManifestCache`
* [i18n](api:SilverStripe\i18n\i18n) uses `Symfony\Component\Config\ConfigCacheFactoryInterface` (filesystem-based)

View File

@ -16,6 +16,7 @@ guide developers in preparing existing 3.x code for compatibility with 4.0
* [Filesystem API](#overview-filesystem)
* [Template and Form API](#overview-template)
* [i18n](#overview-i18n)
* [Cache](#overview-cache)
* [Email and Mailer](#overview-mailer)
* [Commit History](#commit-history)
@ -49,6 +50,7 @@ guide developers in preparing existing 3.x code for compatibility with 4.0
* Themes are now configured to cascade, where you can specify a list of themes, and have the template engine
search programatically through a prioritised list when resolving template and CSS file paths.
* i18n Updated to use symfony/translation over zend Framework 1. Zend_Translate has been removed.
* Replaced `Zend_Cache` and the `Cache` API with a PSR-16 implementation (symfony/cache)
* _ss_environment.php files have been removed in favour of `.env` and "real" environment variables.
## <a name="upgrading"></a>Upgrading
@ -1473,6 +1475,93 @@ New `TimeField` methods replace `getConfig()` / `setConfig()`
* `i18n::get_common_locales()` removed.
* `i18n.common_locales` config removed
### <a name="overview-cache"></a>Cache API
We have replaced the unsupported `Zend_Cache` library with [symfony/cache](https://github.com/symfony/cache).
This also allowed us to remove SilverStripe's `Cache` API and use dependency injection with a standard
[PSR-16](http://www.php-fig.org/psr/psr-16/) cache interface instead.
#### Usage Changes
Caches should be retrieved through `Injector` instead of `Cache::factory()`,
and have a slightly different API (e.g. `set()` instead of `save()`).
Before:
:::php
$cache = Cache::factory('myCache');
// create a new item by trying to get it from the cache
$myValue = $cache->load('myCacheKey');
// set a value and save it via the adapter
$cache->save(1234, 'myCacheKey');
// retrieve the cache item
if (!$cache->load('myCacheKey')) {
// ... item does not exists in the cache
}
// Remove a cache key
$cache->remove('myCacheKey');
After:
:::php
use Psr\SimpleCache\CacheInterface;
$cache = Injector::inst()->get(CacheInterface::class . '.myCache');
// create a new item by trying to get it from the cache
$myValue = $cache->get('myCacheKey');
// set a value and save it via the adapter
$cache->set('myCacheKey', 1234);
// retrieve the cache item
if (!$cache->has('myCacheKey')) {
// ... item does not exists in the cache
}
$cache->delete('myCacheKey');
#### Configuration Changes
Caches are now configured through dependency injection services instead of PHP.
See our ["Caching" docs](/developer-guides/performance/caching) for more details.
Before (`mysite/_config.php`):
:::php
Cache::add_backend(
'primary_memcached',
'Memcached',
array(
'servers' => array(
'host' => 'localhost',
'port' => 11211,
)
)
);
Cache::pick_backend('primary_memcached', 'any', 10);
After (`mysite/_config/config.yml`):
:::yml
---
After:
- '#corecache'
---
SilverStripe\Core\Injector\Injector:
MemcachedClient:
class: 'Memcached'
calls:
- [ addServer, [ 'localhost', 11211 ] ]
SilverStripe\Core\Cache\CacheFactory:
class: 'SilverStripe\Core\Cache\MemcachedCacheFactory'
constructor:
client: '%$MemcachedClient
### <a name="overview-mailer"></a>Email and Mailer
#### <a name="overview-mailer-api"></a>Email Additions / Changes

View File

@ -4,12 +4,11 @@ namespace SilverStripe\Assets;
use SilverStripe\Assets\Storage\AssetContainer;
use SilverStripe\Assets\Storage\AssetStore;
use SilverStripe\Core\Cache;
use Psr\SimpleCache\CacheInterface;
use SilverStripe\Core\Injector\Injector;
use SilverStripe\Core\Object;
use SilverStripe\Core\Flushable;
use InvalidArgumentException;
use Zend_Cache;
use Zend_Cache_Core;
/**
* A wrapper class for GD-based images, with lots of manipulation functions.
@ -25,7 +24,7 @@ class GDBackend extends Object implements Image_Backend, Flushable
protected $gd;
/**
* @var Zend_Cache_Core
* @var \Psr\SimpleCache\CacheInterface
*/
protected $cache;
@ -66,7 +65,7 @@ class GDBackend extends Object implements Image_Backend, Flushable
public function __construct(AssetContainer $assetContainer = null)
{
parent::__construct();
$this->cache = Cache::factory('GDBackend_Manipulations');
$this->cache = Injector::inst()->get(CacheInterface::class . '.GDBackend_Manipulations');
if ($assetContainer) {
$this->loadFromContainer($assetContainer);
@ -219,7 +218,7 @@ class GDBackend extends Object implements Image_Backend, Flushable
public function failedResample($arg = null)
{
$key = sha1(implode('|', func_get_args()));
return (bool)$this->cache->load($key);
return (bool)$this->cache->get($key);
}
/**
@ -259,7 +258,7 @@ class GDBackend extends Object implements Image_Backend, Flushable
protected function markFailed($arg = null)
{
$key = sha1(implode('|', func_get_args()));
$this->cache->save('1', $key);
$this->cache->set($key, '1');
}
/**
@ -270,7 +269,7 @@ class GDBackend extends Object implements Image_Backend, Flushable
protected function markSucceeded($arg = null)
{
$key = sha1(implode('|', func_get_args()));
$this->cache->save('0', $key);
$this->cache->set($key, '0');
}
@ -762,8 +761,7 @@ class GDBackend extends Object implements Image_Backend, Flushable
public static function flush()
{
// Clear factory
$cache = Cache::factory('GDBackend_Manipulations');
$cache->clean(Zend_Cache::CLEANING_MODE_ALL);
$cache = Injector::inst()->get(CacheInterface::class . '.GDBackend_Manipulations');
$cache->clear();
}
}

View File

@ -1,201 +0,0 @@
<?php
namespace SilverStripe\Core;
use Zend_Cache;
use Zend_Cache_Core;
/**
* The `[api:Cache]` class provides a bunch of static functions wrapping the Zend_Cache system
* in something a little more easy to use with the SilverStripe config system.
*
* @see https://docs.silverstripe.org/en/3.4/developer_guides/performance/caching/
*/
class Cache
{
/**
* @var array $backends
*/
protected static $backends = array();
/**
* @var array $backend_picks
*/
protected static $backend_picks = array();
/**
* @var array $cache_lifetime
*/
protected static $cache_lifetime = array();
/**
* Initialize the 'default' named cache backend.
*/
protected static function init()
{
if (!isset(self::$backends['default'])) {
$cachedir = TEMP_FOLDER . DIRECTORY_SEPARATOR . 'cache';
if (!is_dir($cachedir)) {
mkdir($cachedir);
}
/** @skipUpgrade */
self::$backends['default'] = array(
'File',
array(
'cache_dir' => $cachedir
)
);
self::$cache_lifetime['default'] = array(
'lifetime' => 600,
'priority' => 1
);
}
}
/**
* Add a new named cache backend.
*
* @see http://framework.zend.com/manual/en/zend.cache.html
*
* @param string $name The name of this backend as a freeform string
* @param string $type The Zend_Cache backend ('File' or 'Sqlite' or ...)
* @param array $options The Zend_Cache backend options
*/
public static function add_backend($name, $type, $options = array())
{
self::init();
self::$backends[$name] = array($type, $options);
}
/**
* Pick a named cache backend for a particular named cache.
*
* The priority call with the highest number will be the actual backend
* picked. A backend picked for a specific cache name will always be used
* instead of 'any' if it exists, no matter the priority.
*
* @param string $name The name of the backend, as passed as the first argument to add_backend
* @param string $for The name of the cache to pick this backend for (or 'any' for any backend)
* @param integer $priority The priority of this pick
*/
public static function pick_backend($name, $for, $priority = 1)
{
self::init();
$current = -1;
if (isset(self::$backend_picks[$for])) {
$current = self::$backend_picks[$for]['priority'];
}
if ($priority >= $current) {
self::$backend_picks[$for] = array(
'name' => $name,
'priority' => $priority
);
}
}
/**
* Return the cache lifetime for a particular named cache.
*
* @param string $for
*
* @return string
*/
public static function get_cache_lifetime($for)
{
if (isset(self::$cache_lifetime[$for])) {
return self::$cache_lifetime[$for];
}
return null;
}
/**
* Set the cache lifetime for a particular named cache
*
* @param string $for The name of the cache to set this lifetime for (or 'any' for all backends)
* @param integer $lifetime The lifetime of an item of the cache, in seconds, or -1 to disable caching
* @param integer $priority The priority. The highest priority setting is used. Unlike backends, 'any' is not
* special in terms of priority.
*/
public static function set_cache_lifetime($for, $lifetime = 600, $priority = 1)
{
self::init();
$current = -1;
if (isset(self::$cache_lifetime[$for])) {
$current = self::$cache_lifetime[$for]['priority'];
}
if ($priority >= $current) {
self::$cache_lifetime[$for] = array(
'lifetime' => $lifetime,
'priority' => $priority
);
}
}
/**
* Build a cache object.
*
* @see http://framework.zend.com/manual/en/zend.cache.html
*
* @param string $for The name of the cache to build
* @param string $frontend (optional) The type of Zend_Cache frontend
* @param array $frontendOptions (optional) Any frontend options to use.
* @return Zend_Cache_Core The cache object
*/
public static function factory($for, $frontend = 'Output', $frontendOptions = null)
{
self::init();
$backend_name = 'default';
$backend_priority = -1;
$cache_lifetime = self::$cache_lifetime['default']['lifetime'];
$lifetime_priority = -1;
foreach (array('any', $for) as $name) {
if (isset(self::$backend_picks[$name])) {
if (self::$backend_picks[$name]['priority'] > $backend_priority) {
$backend_name = self::$backend_picks[$name]['name'];
$backend_priority = self::$backend_picks[$name]['priority'];
}
}
if (isset(self::$cache_lifetime[$name])) {
if (self::$cache_lifetime[$name]['priority'] > $lifetime_priority) {
$cache_lifetime = self::$cache_lifetime[$name]['lifetime'];
$lifetime_priority = self::$cache_lifetime[$name]['priority'];
}
}
}
$backend = self::$backends[$backend_name];
$basicOptions = array('cache_id_prefix' => $for);
if ($cache_lifetime >= 0) {
$basicOptions['lifetime'] = $cache_lifetime;
} else {
$basicOptions['caching'] = false;
}
$frontendOptions = $frontendOptions ? array_merge($basicOptions, $frontendOptions) : $basicOptions;
require_once 'Zend/Cache.php';
return Zend_Cache::factory(
$frontend,
$backend[0],
$frontendOptions,
$backend[1]
);
}
}

View File

@ -0,0 +1,36 @@
<?php
namespace SilverStripe\Core\Cache;
use SilverStripe\Core\Injector\Injector;
use Symfony\Component\Cache\Simple\ApcuCache;
use Memcached;
class ApcuCacheFactory implements CacheFactory
{
/**
* @var string
*/
protected $version;
/**
* @param string $version
*/
public function __construct($version = null)
{
$this->version = $version;
}
/**
* @inheritdoc
*/
public function create($service, array $params = array())
{
return Injector::inst()->create(ApcuCache::class, false, [
(isset($args['namespace'])) ? $args['namespace'] : '',
(isset($args['defaultLifetime'])) ? $args['defaultLifetime'] : 0,
$this->version
]);
}
}

View File

@ -0,0 +1,20 @@
<?php
namespace SilverStripe\Core\Cache;
use Psr\SimpleCache\CacheInterface;
use SilverStripe\Core\Injector\Factory as InjectorFactory;
interface CacheFactory extends InjectorFactory
{
/**
* Note: While the returned object is used as a singleton (by the originating Injector->get() call),
* this cache object shouldn't be a singleton itself - it has varying constructor args for the same service name.
*
* @param string $class
* @param array $args
* @return CacheInterface
*/
public function create($service, array $params = array());
}

View File

@ -0,0 +1,79 @@
<?php
namespace SilverStripe\Core\Cache;
use SilverStripe\Core\Injector\Injector;
use Symfony\Component\Cache\Simple\FilesystemCache;
use Symfony\Component\Cache\Simple\ApcuCache;
use Symfony\Component\Cache\Simple\ChainCache;
use Symfony\Component\Cache\Simple\PhpFilesCache;
use Symfony\Component\Cache\Adapter\ApcuAdapter;
use Symfony\Component\Cache\Adapter\PhpFilesAdapter;
/**
* Returns the most performant combination of caches available on the system:
* - `PhpFilesCache` (PHP 7 with opcache enabled)
* - `ApcuCache` (requires APC) with a `FilesystemCache` fallback (for larger cache volumes)
* - `FilesystemCache` if none of the above is available
*
* Modelled after `Symfony\Component\Cache\Adapter\AbstractAdapter::createSystemCache()`
*/
class DefaultCacheFactory implements CacheFactory
{
/**
* @var string Absolute directory path
*/
protected $directory;
/**
* @var string APC version for apcu_add()
*/
protected $version;
/**
* @param string $directory
* @param string $version
*/
public function __construct($directory, $version = null)
{
$this->directory = $directory;
$this->version = $version;
}
/**
* @inheritdoc
*/
public function create($service, array $params = array())
{
$namespace = (isset($args['namespace'])) ? $args['namespace'] : '';
$defaultLifetime = (isset($args['defaultLifetime'])) ? $args['defaultLifetime'] : 0;
$version = $this->version;
$directory = $this->directory;
$apcuSupported = null;
$phpFilesSupported = null;
if (null === $apcuSupported) {
$apcuSupported = ApcuAdapter::isSupported();
}
if (!$apcuSupported && null === $phpFilesSupported) {
$phpFilesSupported = PhpFilesAdapter::isSupported();
}
if ($phpFilesSupported) {
$opcache = Injector::inst()->create(PhpFilesCache::class, false, [$namespace, $defaultLifetime, $directory]);
return $opcache;
}
$fs = Injector::inst()->create(FilesystemCache::class, false, [$namespace, $defaultLifetime, $directory]);
if (!$apcuSupported) {
return $fs;
}
$apcu = Injector::inst()->create(ApcuCache::class, false, [$namespace, (int) $defaultLifetime / 5, $version]);
return Injector::inst()->create(ChainCache::class, false, [[$apcu, $fs]]);
}
}

View File

@ -0,0 +1,35 @@
<?php
namespace SilverStripe\Core\Cache;
use SilverStripe\Core\Injector\Injector;
use Symfony\Component\Cache\Simple\FilesystemCache;
class FilesystemCacheFactory implements CacheFactory
{
/**
* @var string Absolute directory path
*/
protected $directory;
/**
* @param string $directory
*/
public function __construct($directory)
{
$this->directory = $directory;
}
/**
* @inheritdoc
*/
public function create($service, array $params = array())
{
return Injector::inst()->create(FilesystemCache::class, false, [
(isset($args['namespace'])) ? $args['namespace'] : '',
(isset($args['defaultLifetime'])) ? $args['defaultLifetime'] : 0,
$this->directory
]);
}
}

View File

@ -0,0 +1,36 @@
<?php
namespace SilverStripe\Core\Cache;
use SilverStripe\Core\Injector\Injector;
use Symfony\Component\Cache\Simple\MemcachedCache;
use Memcached;
class MemcachedCacheFactory implements CacheFactory
{
/**
* @var Memcached
*/
protected $memcachedClient;
/**
* @param Memcached $memcachedClient
*/
public function __construct(Memcached $memcachedClient)
{
$this->memcachedClient = $memcachedClient;
}
/**
* @inheritdoc
*/
public function create($service, array $params = array())
{
return Injector::inst()->create(MemcachedCache::class, false, [
$this->memcachedClient,
(isset($args['namespace'])) ? $args['namespace'] : '',
(isset($args['defaultLifetime'])) ? $args['defaultLifetime'] : 0
]);
}
}

View File

@ -54,14 +54,6 @@ mb_regex_encoding('UTF-8');
*/
gc_enable();
/**
* Include the Zend autoloader. This will be removed in the near future.
*/
if (file_exists('thirdparty/Zend/Loader/Autoloader.php')) {
require_once 'thirdparty/Zend/Loader/Autoloader.php';
Zend_Loader_Autoloader::getInstance();
}
// Initialise the dependency injector as soon as possible, as it is
// subsequently used by some of the following code
$injector = new Injector(array('locator' => 'SilverStripe\\Core\\Injector\\SilverStripeServiceConfigurationLocator'));

View File

@ -7,10 +7,9 @@ use SilverStripe\Core\ClassInfo;
use SilverStripe\Core\Config\DAG;
use SilverStripe\Core\Config\DAG_CyclicException;
use SilverStripe\Core\Config\Config;
use SilverStripe\Core\Cache;
use Symfony\Component\Cache\Simple\FilesystemCache;
use Symfony\Component\Yaml\Parser;
use Traversable;
use Zend_Cache_Core;
/**
* A utility class which builds a manifest of configuration items
@ -28,7 +27,7 @@ class ConfigManifest
protected $includeTests;
/**
* @var Zend_Cache_Core
* @var FilesystemCache
*/
protected $cache;
@ -114,15 +113,15 @@ class ConfigManifest
$this->key = sha1($base).'_';
$this->includeTests = $includeTests;
// Get the Zend Cache to load/store cache into
// Get a cache singleton
$this->cache = $this->getCache();
// Unless we're forcing regen, try loading from cache
if (!$forceRegen) {
// The PHP config sources are always needed
$this->phpConfigSources = $this->cache->load($this->key.'php_config_sources');
$this->phpConfigSources = $this->cache->get($this->key.'php_config_sources');
// Get the variant key spec
$this->variantKeySpec = $this->cache->load($this->key.'variant_key_spec');
$this->variantKeySpec = $this->cache->get($this->key.'variant_key_spec');
}
// If we don't have a variantKeySpec (because we're forcing regen, or it just wasn't in the cache), generate it
@ -136,14 +135,12 @@ class ConfigManifest
/**
* Provides a hook for mock unit tests despite no DI
* @return Zend_Cache_Core
* @return \Psr\SimpleCache\CacheInterface
*/
protected function getCache()
{
return Cache::factory('SS_Configuration', 'Core', array(
'automatic_serialization' => true,
'lifetime' => null
));
// TODO Replace with CoreConfigCreator, see https://github.com/silverstripe/silverstripe-framework/pull/6641/files#diff-f8c9b17e06432278197a7d5c3a1043cb
return new FilesystemCache('SS_Configuration', 0, getTempFolder());
}
/**
@ -264,9 +261,9 @@ class ConfigManifest
$this->buildVariantKeySpec();
if ($cache) {
$this->cache->save($this->phpConfigSources, $this->key.'php_config_sources');
$this->cache->save($this->yamlConfigFragments, $this->key.'yaml_config_fragments');
$this->cache->save($this->variantKeySpec, $this->key.'variant_key_spec');
$this->cache->set($this->key.'php_config_sources', $this->phpConfigSources);
$this->cache->set($this->key.'yaml_config_fragments', $this->yamlConfigFragments);
$this->cache->set($this->key.'variant_key_spec', $this->variantKeySpec);
}
}
@ -650,12 +647,12 @@ class ConfigManifest
// given variant is stale compared to the complete set of fragments
if (!$this->yamlConfigFragments) {
// First try and just load the exact variant
if ($this->yamlConfig = $this->cache->load($this->key.'yaml_config_'.$this->variantKey())) {
if ($this->yamlConfig = $this->cache->get($this->key.'yaml_config_'.$this->variantKey())) {
$this->yamlConfigVariantKey = $this->variantKey();
return;
} // Otherwise try and load the fragments so we can build the variant
else {
$this->yamlConfigFragments = $this->cache->load($this->key.'yaml_config_fragments');
$this->yamlConfigFragments = $this->cache->get($this->key.'yaml_config_fragments');
}
}
@ -684,7 +681,7 @@ class ConfigManifest
}
if ($cache) {
$this->cache->save($this->yamlConfig, $this->key.'yaml_config_'.$this->variantKey());
$this->cache->set($this->key.'yaml_config_'.$this->variantKey(), $this->yamlConfig);
}
// Since yamlConfig has changed, call any callbacks that are interested

View File

@ -743,10 +743,10 @@ class SSTemplateParser extends Parser implements TemplateParser
// Get any condition
$condition = isset($res['condition']) ? $res['condition'] : '';
$res['php'] .= 'if ('.$condition.'($partial = $cache->load('.$key.'))) $val .= $partial;' . PHP_EOL;
$res['php'] .= 'if ('.$condition.'($partial = $cache->get('.$key.'))) $val .= $partial;' . PHP_EOL;
$res['php'] .= 'else { $oldval = $val; $val = "";' . PHP_EOL;
$res['php'] .= $sub['php'] . PHP_EOL;
$res['php'] .= $condition . ' $cache->save($val); $val = $oldval . $val;' . PHP_EOL;
$res['php'] .= $condition . ' $cache->set('.$key.', $val); $val = $oldval . $val;' . PHP_EOL;
$res['php'] .= '}';
}

View File

@ -4020,10 +4020,10 @@ class SSTemplateParser extends Parser implements TemplateParser
// Get any condition
$condition = isset($res['condition']) ? $res['condition'] : '';
$res['php'] .= 'if ('.$condition.'($partial = $cache->load('.$key.'))) $val .= $partial;' . PHP_EOL;
$res['php'] .= 'if ('.$condition.'($partial = $cache->get('.$key.'))) $val .= $partial;' . PHP_EOL;
$res['php'] .= 'else { $oldval = $val; $val = "";' . PHP_EOL;
$res['php'] .= $sub['php'] . PHP_EOL;
$res['php'] .= $condition . ' $cache->save($val); $val = $oldval . $val;' . PHP_EOL;
$res['php'] .= $condition . ' $cache->set('.$key.', $val); $val = $oldval . $val;' . PHP_EOL;
$res['php'] .= '}';
}

View File

@ -4,7 +4,7 @@ namespace SilverStripe\View;
use SilverStripe\Core\Config\Configurable;
use SilverStripe\Core\ClassInfo;
use SilverStripe\Core\Cache;
use Psr\SimpleCache\CacheInterface;
use SilverStripe\Core\Convert;
use SilverStripe\Core\Flushable;
use SilverStripe\Core\Injector\Injector;
@ -14,9 +14,6 @@ use SilverStripe\ORM\FieldType\DBField;
use SilverStripe\ORM\FieldType\DBHTMLText;
use SilverStripe\Security\Permission;
use InvalidArgumentException;
use Zend_Cache_Backend_ExtendedInterface;
use Zend_Cache;
use Zend_Cache_Core;
/**
* Parses a template file with an *.ss file extension.
@ -466,17 +463,8 @@ class SSViewer implements Flushable
public static function flush_cacheblock_cache($force = false)
{
if (!self::$cacheblock_cache_flushed || $force) {
$cache = Cache::factory('cacheblock');
$backend = $cache->getBackend();
if ($backend instanceof Zend_Cache_Backend_ExtendedInterface
&& ($capabilities = $backend->getCapabilities())
&& $capabilities['tags']
) {
$cache->clean(Zend_Cache::CLEANING_MODE_MATCHING_TAG, $cache->getTags());
} else {
$cache->clean(Zend_Cache::CLEANING_MODE_ALL);
}
$cache = Injector::inst()->get(CacheInterface::class . '.cacheblock');
$cache->clear();
self::$cacheblock_cache_flushed = true;
@ -484,14 +472,14 @@ class SSViewer implements Flushable
}
/**
* @var Zend_Cache_Core
* @var CacheInterface
*/
protected $partialCacheStore = null;
/**
* Set the cache object to use when storing / retrieving partial cache blocks.
*
* @param Zend_Cache_Core $cache
* @param CacheInterface $cache
*/
public function setPartialCacheStore($cache)
{
@ -501,11 +489,11 @@ class SSViewer implements Flushable
/**
* Get the cache object to use when storing / retrieving partial cache blocks.
*
* @return Zend_Cache_Core
* @return CacheInterface
*/
public function getPartialCacheStore()
{
return $this->partialCacheStore ? $this->partialCacheStore : Cache::factory('cacheblock');
return $this->partialCacheStore ? $this->partialCacheStore : Injector::inst()->get(CacheInterface::class . '.cacheblock');
}
/**

View File

@ -39,7 +39,6 @@ class YamlReader implements Reader
// Normalise messages
return $this->normaliseMessages($yaml[$locale]);
} catch (ParseException $exception) {
var_dump($exception);
throw new InvalidResourceException(sprintf('Error parsing YAML, invalid file "%s"', $path), 0, $exception);
}
}

View File

@ -3,7 +3,8 @@
namespace SilverStripe\Assets\Tests;
use SilverStripe\Assets\GDBackend;
use SilverStripe\Core\Cache;
use Psr\SimpleCache\CacheInterface;
use SilverStripe\Core\Injector\Injector;
use SilverStripe\Dev\SapphireTest;
/**
@ -192,9 +193,9 @@ class GDTest extends SapphireTest
$gd->loadFrom($fullPath);
// Cache should refer to this file
$cache = Cache::factory('GDBackend_Manipulations');
$cache = Injector::inst()->get(CacheInterface::class . '.GDBackend_Manipulations');
$key = sha1(implode('|', array($fullPath, filemtime($fullPath))));
$data = $cache->load($key);
$data = $cache->get($key);
$this->assertEquals('1', $data);
}

View File

@ -1,77 +0,0 @@
<?php
namespace SilverStripe\Core\Tests;
use SilverStripe\Core\Cache;
use SilverStripe\Dev\SapphireTest;
class CacheTest extends SapphireTest
{
public function testCacheBasics()
{
$cache = Cache::factory('test');
$cache->save('Good', 'cachekey');
$this->assertEquals('Good', $cache->load('cachekey'));
}
public function testCacheCanBeDisabled()
{
Cache::set_cache_lifetime('test', -1, 10);
$cache = Cache::factory('test');
$cache->save('Good', 'cachekey');
$this->assertFalse($cache->load('cachekey'));
}
public function testCacheLifetime()
{
Cache::set_cache_lifetime('test', 0.5, 20);
$cache = Cache::factory('test');
$this->assertEquals(0.5, $cache->getOption('lifetime'));
$cache->save('Good', 'cachekey');
$this->assertEquals('Good', $cache->load('cachekey'));
// As per documentation, sleep may not sleep for the amount of time you tell it to sleep for
// This loop can make sure it *does* sleep for that long
$endtime = time() + 2;
while (time() < $endtime) {
// Sleep for another 2 seconds!
// This may end up sleeping for 4 seconds, but it's awwwwwwwright.
sleep(2);
}
$this->assertFalse($cache->load('cachekey'));
}
public function testCacheSeperation()
{
$cache1 = Cache::factory('test1');
$cache2 = Cache::factory('test2');
$cache1->save('Foo', 'cachekey');
$cache2->save('Bar', 'cachekey');
$this->assertEquals('Foo', $cache1->load('cachekey'));
$this->assertEquals('Bar', $cache2->load('cachekey'));
$cache1->remove('cachekey');
$this->assertFalse($cache1->load('cachekey'));
$this->assertEquals('Bar', $cache2->load('cachekey'));
}
public function testCacheDefault()
{
Cache::set_cache_lifetime('default', 1200);
$default = Cache::get_cache_lifetime('default');
$this->assertEquals(1200, $default['lifetime']);
$cache = Cache::factory('somethingnew');
$this->assertEquals(1200, $cache->getOption('lifetime'));
}
}

View File

@ -7,7 +7,7 @@ use SilverStripe\Core\Config\Config;
use SilverStripe\Core\Manifest\ConfigManifest;
use SilverStripe\Dev\SapphireTest;
use ReflectionProperty;
use Zend_Cache_Core;
use Symfony\Component\Cache\Simple\ArrayCache;
class ConfigManifestTest extends SapphireTest
{
@ -34,13 +34,13 @@ class ConfigManifestTest extends SapphireTest
/**
* A helper method to return a mock of the cache in order to test expectations and reduce dependency
*
* @return Zend_Cache_Core
* @return \PHPUnit_Framework_MockObject_MockObject
*/
protected function getCacheMock()
{
return $this->getMock(
'Zend_Cache_Core',
array('load', 'save'),
ArrayCache::class,
array('set', 'get'),
array(),
'',
false
@ -51,7 +51,7 @@ class ConfigManifestTest extends SapphireTest
* A helper method to return a mock of the manifest in order to test expectations and reduce dependency
*
* @param $methods
* @return ConfigManifest
* @return \PHPUnit_Framework_MockObject_MockObject
*/
protected function getManifestMock($methods)
{
@ -82,7 +82,7 @@ class ConfigManifestTest extends SapphireTest
// Set up a cache where we expect load to never be called
$cache = $this->getCacheMock();
$cache->expects($this->never())
->method('load');
->method('get');
$manifest->expects($this->any())
->method('getCache')
@ -95,7 +95,7 @@ class ConfigManifestTest extends SapphireTest
$cache = $this->getCacheMock();
$cache->expects($this->atLeastOnce())
->method('save');
->method('set');
$manifest->expects($this->any())
->method('getCache')
@ -119,7 +119,7 @@ class ConfigManifestTest extends SapphireTest
// Load should be called twice
$cache = $this->getCacheMock();
$cache->expects($this->exactly(2))
->method('load');
->method('get');
$manifest->expects($this->any())
->method('getCache')
@ -133,7 +133,7 @@ class ConfigManifestTest extends SapphireTest
$cache = $this->getCacheMock();
$cache->expects($this->exactly(2))
->method('load')
->method('get')
->will($this->onConsecutiveCalls(false, false));
$manifest->expects($this->any())
@ -151,7 +151,7 @@ class ConfigManifestTest extends SapphireTest
$cache = $this->getCacheMock();
$cache->expects($this->exactly(2))
->method('load')
->method('get')
->will($this->onConsecutiveCalls(array(), array()));
$manifest->expects($this->any())
@ -186,7 +186,7 @@ class ConfigManifestTest extends SapphireTest
$cache = $this->getCacheMock();
$cache->expects($this->exactly(2))
->will($this->returnValue(false))
->method('load');
->method('get');
$manifest->expects($this->any())
->method('getCache')
@ -204,7 +204,7 @@ class ConfigManifestTest extends SapphireTest
$cache = $this->getCacheMock();
$cache->expects($this->exactly(2))
->method('load')
->method('get')
->will($this->returnCallback(function ($parameter) {
if (strpos($parameter, 'variant_key_spec') !== false) {
return false;
@ -227,7 +227,7 @@ class ConfigManifestTest extends SapphireTest
$cache = $this->getCacheMock();
$cache->expects($this->exactly(2))
->method('load')
->method('get')
->will($this->returnCallback(function ($parameter) {
if (strpos($parameter, 'php_config_sources') !== false) {
return false;

View File

@ -5,8 +5,8 @@ namespace SilverStripe\ORM\Tests;
require_once __DIR__ . "/ImageTest.php";
use SilverStripe\Core\Config\Config;
use SilverStripe\Core\Cache;
use Zend_Cache;
use Psr\SimpleCache\CacheInterface;
use SilverStripe\Core\Injector\Injector;
class GDImageTest extends ImageTest
{
@ -32,8 +32,9 @@ class GDImageTest extends ImageTest
public function tearDown()
{
$cache = Cache::factory('GDBackend_Manipulations');
$cache->clean(Zend_Cache::CLEANING_MODE_ALL);
$cache = Injector::inst()->get(CacheInterface::class . '.GDBackend_Manipulations');
$cache->clear();
parent::tearDown();
}
}

View File

@ -2,11 +2,14 @@
namespace SilverStripe\View\Tests;
use SilverStripe\Core\Injector\Injector;
use SilverStripe\ORM\Versioning\Versioned;
use SilverStripe\Core\Cache;
use Psr\SimpleCache\CacheInterface;
use SilverStripe\Dev\SapphireTest;
use SilverStripe\Control\Director;
use SilverStripe\View\SSViewer;
use Symfony\Component\Cache\Simple\FilesystemCache;
use Symfony\Component\Cache\Simple\NullCache;
// Not actually a data object, we just want a ViewableData object that's just for us
@ -27,8 +30,15 @@ class SSViewerCacheBlockTest extends SapphireTest
{
$this->data = new SSViewerCacheBlockTest\TestModel();
Cache::factory('cacheblock')->clean();
Cache::set_cache_lifetime('cacheblock', $cacheOn ? 600 : -1);
$cache = null;
if ($cacheOn) {
$cache = new FilesystemCache('cacheblock', 0, getTempFolder()); // cache indefinitely
} else {
$cache = new NullCache();
}
Injector::inst()->registerService($cache, CacheInterface::class . '.cacheblock');
Injector::inst()->get(CacheInterface::class . '.cacheblock')->clear();
}
protected function _runtemplate($template, $data = null)

View File

@ -1,250 +0,0 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Cache
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Cache.php 23775 2011-03-01 17:25:24Z ralph $
*/
/**
* @package Zend_Cache
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
abstract class Zend_Cache
{
/**
* Standard frontends
*
* @var array
*/
public static $standardFrontends = array('Core', 'Output', 'Class', 'File', 'Function', 'Page');
/**
* Standard backends
*
* @var array
*/
public static $standardBackends = array('File', 'Sqlite', 'Memcached', 'Libmemcached', 'Apc', 'ZendPlatform',
'Xcache', 'TwoLevels', 'WinCache', 'ZendServer_Disk', 'ZendServer_ShMem');
/**
* Standard backends which implement the ExtendedInterface
*
* @var array
*/
public static $standardExtendedBackends = array('File', 'Apc', 'TwoLevels', 'Memcached', 'Libmemcached', 'Sqlite', 'WinCache');
/**
* Only for backward compatibility (may be removed in next major release)
*
* @var array
* @deprecated
*/
public static $availableFrontends = array('Core', 'Output', 'Class', 'File', 'Function', 'Page');
/**
* Only for backward compatibility (may be removed in next major release)
*
* @var array
* @deprecated
*/
public static $availableBackends = array('File', 'Sqlite', 'Memcached', 'Libmemcached', 'Apc', 'ZendPlatform', 'Xcache', 'WinCache', 'TwoLevels');
/**
* Consts for clean() method
*/
const CLEANING_MODE_ALL = 'all';
const CLEANING_MODE_OLD = 'old';
const CLEANING_MODE_MATCHING_TAG = 'matchingTag';
const CLEANING_MODE_NOT_MATCHING_TAG = 'notMatchingTag';
const CLEANING_MODE_MATCHING_ANY_TAG = 'matchingAnyTag';
/**
* Factory
*
* @param mixed $frontend frontend name (string) or Zend_Cache_Frontend_ object
* @param mixed $backend backend name (string) or Zend_Cache_Backend_ object
* @param array $frontendOptions associative array of options for the corresponding frontend constructor
* @param array $backendOptions associative array of options for the corresponding backend constructor
* @param boolean $customFrontendNaming if true, the frontend argument is used as a complete class name ; if false, the frontend argument is used as the end of "Zend_Cache_Frontend_[...]" class name
* @param boolean $customBackendNaming if true, the backend argument is used as a complete class name ; if false, the backend argument is used as the end of "Zend_Cache_Backend_[...]" class name
* @param boolean $autoload if true, there will no require_once for backend and frontend (useful only for custom backends/frontends)
* @throws Zend_Cache_Exception
* @return Zend_Cache_Core|Zend_Cache_Frontend
*/
public static function factory($frontend, $backend, $frontendOptions = array(), $backendOptions = array(), $customFrontendNaming = false, $customBackendNaming = false, $autoload = false)
{
if (is_string($backend)) {
$backendObject = self::_makeBackend($backend, $backendOptions, $customBackendNaming, $autoload);
} else {
if ((is_object($backend)) && (in_array('Zend_Cache_Backend_Interface', class_implements($backend)))) {
$backendObject = $backend;
} else {
self::throwException('backend must be a backend name (string) or an object which implements Zend_Cache_Backend_Interface');
}
}
if (is_string($frontend)) {
$frontendObject = self::_makeFrontend($frontend, $frontendOptions, $customFrontendNaming, $autoload);
} else {
if (is_object($frontend)) {
$frontendObject = $frontend;
} else {
self::throwException('frontend must be a frontend name (string) or an object');
}
}
$frontendObject->setBackend($backendObject);
return $frontendObject;
}
/**
* Backend Constructor
*
* @param string $backend
* @param array $backendOptions
* @param boolean $customBackendNaming
* @param boolean $autoload
* @return Zend_Cache_Backend
*/
public static function _makeBackend($backend, $backendOptions, $customBackendNaming = false, $autoload = false)
{
if (!$customBackendNaming) {
$backend = self::_normalizeName($backend);
}
if (in_array($backend, Zend_Cache::$standardBackends)) {
// we use a standard backend
$backendClass = 'Zend_Cache_Backend_' . $backend;
// security controls are explicit
require_once str_replace('_', DIRECTORY_SEPARATOR, $backendClass) . '.php';
} else {
// we use a custom backend
if (!preg_match('~^[\w]+$~D', $backend)) {
Zend_Cache::throwException("Invalid backend name [$backend]");
}
if (!$customBackendNaming) {
// we use this boolean to avoid an API break
$backendClass = 'Zend_Cache_Backend_' . $backend;
} else {
$backendClass = $backend;
}
if (!$autoload) {
$file = str_replace('_', DIRECTORY_SEPARATOR, $backendClass) . '.php';
if (!(self::_isReadable($file))) {
self::throwException("file $file not found in include_path");
}
require_once $file;
}
}
return new $backendClass($backendOptions);
}
/**
* Frontend Constructor
*
* @param string $frontend
* @param array $frontendOptions
* @param boolean $customFrontendNaming
* @param boolean $autoload
* @return Zend_Cache_Core|Zend_Cache_Frontend
*/
public static function _makeFrontend($frontend, $frontendOptions = array(), $customFrontendNaming = false, $autoload = false)
{
if (!$customFrontendNaming) {
$frontend = self::_normalizeName($frontend);
}
if (in_array($frontend, self::$standardFrontends)) {
// we use a standard frontend
// For perfs reasons, with frontend == 'Core', we can interact with the Core itself
$frontendClass = 'Zend_Cache_' . ($frontend != 'Core' ? 'Frontend_' : '') . $frontend;
// security controls are explicit
require_once str_replace('_', DIRECTORY_SEPARATOR, $frontendClass) . '.php';
} else {
// we use a custom frontend
if (!preg_match('~^[\w]+$~D', $frontend)) {
Zend_Cache::throwException("Invalid frontend name [$frontend]");
}
if (!$customFrontendNaming) {
// we use this boolean to avoid an API break
$frontendClass = 'Zend_Cache_Frontend_' . $frontend;
} else {
$frontendClass = $frontend;
}
if (!$autoload) {
$file = str_replace('_', DIRECTORY_SEPARATOR, $frontendClass) . '.php';
if (!(self::_isReadable($file))) {
self::throwException("file $file not found in include_path");
}
require_once $file;
}
}
return new $frontendClass($frontendOptions);
}
/**
* Throw an exception
*
* Note : for perf reasons, the "load" of Zend/Cache/Exception is dynamic
* @param string $msg Message for the exception
* @throws Zend_Cache_Exception
*/
public static function throwException($msg, Exception $e = null)
{
// For perfs reasons, we use this dynamic inclusion
require_once 'Zend/Cache/Exception.php';
throw new Zend_Cache_Exception($msg, 0, $e);
}
/**
* Normalize frontend and backend names to allow multiple words TitleCased
*
* @param string $name Name to normalize
* @return string
*/
protected static function _normalizeName($name)
{
$name = ucfirst(strtolower($name));
$name = str_replace(array('-', '_', '.'), ' ', $name);
$name = ucwords($name);
$name = str_replace(' ', '', $name);
if (stripos($name, 'ZendServer') === 0) {
$name = 'ZendServer_' . substr($name, strlen('ZendServer'));
}
return $name;
}
/**
* Returns TRUE if the $filename is readable, or FALSE otherwise.
* This function uses the PHP include_path, where PHP's is_readable()
* does not.
*
* Note : this method comes from Zend_Loader (see #ZF-2891 for details)
*
* @param string $filename
* @return boolean
*/
private static function _isReadable($filename)
{
if (!$fh = @fopen($filename, 'r', true)) {
return false;
}
@fclose($fh);
return true;
}
}

View File

@ -1,268 +0,0 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Cache
* @subpackage Zend_Cache_Backend
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Backend.php 23800 2011-03-10 20:52:08Z mabe $
*/
/**
* @package Zend_Cache
* @subpackage Zend_Cache_Backend
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Cache_Backend
{
/**
* Frontend or Core directives
*
* =====> (int) lifetime :
* - Cache lifetime (in seconds)
* - If null, the cache is valid forever
*
* =====> (int) logging :
* - if set to true, a logging is activated throw Zend_Log
*
* @var array directives
*/
protected $_directives = array(
'lifetime' => 3600,
'logging' => false,
'logger' => null
);
/**
* Available options
*
* @var array available options
*/
protected $_options = array();
/**
* Constructor
*
* @param array $options Associative array of options
* @throws Zend_Cache_Exception
* @return void
*/
public function __construct(array $options = array())
{
while (list($name, $value) = each($options)) {
$this->setOption($name, $value);
}
}
/**
* Set the frontend directives
*
* @param array $directives Assoc of directives
* @throws Zend_Cache_Exception
* @return void
*/
public function setDirectives($directives)
{
if (!is_array($directives)) Zend_Cache::throwException('Directives parameter must be an array');
while (list($name, $value) = each($directives)) {
if (!is_string($name)) {
Zend_Cache::throwException("Incorrect option name : $name");
}
$name = strtolower($name);
if (array_key_exists($name, $this->_directives)) {
$this->_directives[$name] = $value;
}
}
$this->_loggerSanity();
}
/**
* Set an option
*
* @param string $name
* @param mixed $value
* @throws Zend_Cache_Exception
* @return void
*/
public function setOption($name, $value)
{
if (!is_string($name)) {
Zend_Cache::throwException("Incorrect option name : $name");
}
$name = strtolower($name);
if (array_key_exists($name, $this->_options)) {
$this->_options[$name] = $value;
}
}
/**
* Get the life time
*
* if $specificLifetime is not false, the given specific life time is used
* else, the global lifetime is used
*
* @param int $specificLifetime
* @return int Cache life time
*/
public function getLifetime($specificLifetime)
{
if ($specificLifetime === false) {
return $this->_directives['lifetime'];
}
return $specificLifetime;
}
/**
* Return true if the automatic cleaning is available for the backend
*
* DEPRECATED : use getCapabilities() instead
*
* @deprecated
* @return boolean
*/
public function isAutomaticCleaningAvailable()
{
return true;
}
/**
* Determine system TMP directory and detect if we have read access
*
* inspired from Zend_File_Transfer_Adapter_Abstract
*
* @return string
* @throws Zend_Cache_Exception if unable to determine directory
*/
public function getTmpDir()
{
$tmpdir = array();
foreach (array($_ENV, $_SERVER) as $tab) {
foreach (array('TMPDIR', 'TEMP', 'TMP', 'windir', 'SystemRoot') as $key) {
if (isset($tab[$key])) {
if (($key == 'windir') or ($key == 'SystemRoot')) {
$dir = realpath($tab[$key] . '\\temp');
} else {
$dir = realpath($tab[$key]);
}
if ($this->_isGoodTmpDir($dir)) {
return $dir;
}
}
}
}
$upload = ini_get('upload_tmp_dir');
if ($upload) {
$dir = realpath($upload);
if ($this->_isGoodTmpDir($dir)) {
return $dir;
}
}
if (function_exists('sys_get_temp_dir')) {
$dir = sys_get_temp_dir();
if ($this->_isGoodTmpDir($dir)) {
return $dir;
}
}
// Attemp to detect by creating a temporary file
$tempFile = tempnam(md5(uniqid(rand(), TRUE)), '');
if ($tempFile) {
$dir = realpath(dirname($tempFile));
unlink($tempFile);
if ($this->_isGoodTmpDir($dir)) {
return $dir;
}
}
if ($this->_isGoodTmpDir('/tmp')) {
return '/tmp';
}
if ($this->_isGoodTmpDir('\\temp')) {
return '\\temp';
}
Zend_Cache::throwException('Could not determine temp directory, please specify a cache_dir manually');
}
/**
* Verify if the given temporary directory is readable and writable
*
* @param string $dir temporary directory
* @return boolean true if the directory is ok
*/
protected function _isGoodTmpDir($dir)
{
if (is_readable($dir)) {
if (is_writable($dir)) {
return true;
}
}
return false;
}
/**
* Make sure if we enable logging that the Zend_Log class
* is available.
* Create a default log object if none is set.
*
* @throws Zend_Cache_Exception
* @return void
*/
protected function _loggerSanity()
{
if (!isset($this->_directives['logging']) || !$this->_directives['logging']) {
return;
}
if (isset($this->_directives['logger'])) {
if ($this->_directives['logger'] instanceof Zend_Log) {
return;
}
Zend_Cache::throwException('Logger object is not an instance of Zend_Log class.');
}
// Create a default logger to the standard output stream
require_once 'Zend/Log.php';
require_once 'Zend/Log/Writer/Stream.php';
require_once 'Zend/Log/Filter/Priority.php';
$logger = new Zend_Log(new Zend_Log_Writer_Stream('php://output'));
$logger->addFilter(new Zend_Log_Filter_Priority(Zend_Log::WARN, '<='));
$this->_directives['logger'] = $logger;
}
/**
* Log a message at the WARN (4) priority.
*
* @param string $message
* @throws Zend_Cache_Exception
* @return void
*/
protected function _log($message, $priority = 4)
{
if (!$this->_directives['logging']) {
return;
}
if (!isset($this->_directives['logger'])) {
Zend_Cache::throwException('Logging is enabled but logger is not set.');
}
$logger = $this->_directives['logger'];
if (!$logger instanceof Zend_Log) {
Zend_Cache::throwException('Logger object is not an instance of Zend_Log class.');
}
$logger->log($message, $priority);
}
}

View File

@ -1,355 +0,0 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Cache
* @subpackage Zend_Cache_Backend
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Apc.php 23775 2011-03-01 17:25:24Z ralph $
*/
/**
* @see Zend_Cache_Backend_Interface
*/
require_once 'Zend/Cache/Backend/ExtendedInterface.php';
/**
* @see Zend_Cache_Backend
*/
require_once 'Zend/Cache/Backend.php';
/**
* @package Zend_Cache
* @subpackage Zend_Cache_Backend
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Cache_Backend_Apc extends Zend_Cache_Backend implements Zend_Cache_Backend_ExtendedInterface
{
/**
* Log message
*/
const TAGS_UNSUPPORTED_BY_CLEAN_OF_APC_BACKEND = 'Zend_Cache_Backend_Apc::clean() : tags are unsupported by the Apc backend';
const TAGS_UNSUPPORTED_BY_SAVE_OF_APC_BACKEND = 'Zend_Cache_Backend_Apc::save() : tags are unsupported by the Apc backend';
/**
* Constructor
*
* @param array $options associative array of options
* @throws Zend_Cache_Exception
* @return void
*/
public function __construct(array $options = array())
{
if (!extension_loaded('apc')) {
Zend_Cache::throwException('The apc extension must be loaded for using this backend !');
}
parent::__construct($options);
}
/**
* Test if a cache is available for the given id and (if yes) return it (false else)
*
* WARNING $doNotTestCacheValidity=true is unsupported by the Apc backend
*
* @param string $id cache id
* @param boolean $doNotTestCacheValidity if set to true, the cache validity won't be tested
* @return string cached datas (or false)
*/
public function load($id, $doNotTestCacheValidity = false)
{
$tmp = apc_fetch($id);
if (is_array($tmp)) {
return $tmp[0];
}
return false;
}
/**
* Test if a cache is available or not (for the given id)
*
* @param string $id cache id
* @return mixed false (a cache is not available) or "last modified" timestamp (int) of the available cache record
*/
public function test($id)
{
$tmp = apc_fetch($id);
if (is_array($tmp)) {
return $tmp[1];
}
return false;
}
/**
* Save some string datas into a cache record
*
* Note : $data is always "string" (serialization is done by the
* core not by the backend)
*
* @param string $data datas to cache
* @param string $id cache id
* @param array $tags array of strings, the cache record will be tagged by each string entry
* @param int $specificLifetime if != false, set a specific lifetime for this cache record (null => infinite lifetime)
* @return boolean true if no problem
*/
public function save($data, $id, $tags = array(), $specificLifetime = false)
{
$lifetime = $this->getLifetime($specificLifetime);
$result = apc_store($id, array($data, time(), $lifetime), $lifetime);
if (count($tags) > 0) {
$this->_log(self::TAGS_UNSUPPORTED_BY_SAVE_OF_APC_BACKEND);
}
return $result;
}
/**
* Remove a cache record
*
* @param string $id cache id
* @return boolean true if no problem
*/
public function remove($id)
{
return apc_delete($id);
}
/**
* Clean some cache records
*
* Available modes are :
* 'all' (default) => remove all cache entries ($tags is not used)
* 'old' => unsupported
* 'matchingTag' => unsupported
* 'notMatchingTag' => unsupported
* 'matchingAnyTag' => unsupported
*
* @param string $mode clean mode
* @param array $tags array of tags
* @throws Zend_Cache_Exception
* @return boolean true if no problem
*/
public function clean($mode = Zend_Cache::CLEANING_MODE_ALL, $tags = array())
{
switch ($mode) {
case Zend_Cache::CLEANING_MODE_ALL:
return apc_clear_cache('user');
break;
case Zend_Cache::CLEANING_MODE_OLD:
$this->_log("Zend_Cache_Backend_Apc::clean() : CLEANING_MODE_OLD is unsupported by the Apc backend");
break;
case Zend_Cache::CLEANING_MODE_MATCHING_TAG:
case Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG:
case Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG:
$this->_log(self::TAGS_UNSUPPORTED_BY_CLEAN_OF_APC_BACKEND);
break;
default:
Zend_Cache::throwException('Invalid mode for clean() method');
break;
}
}
/**
* Return true if the automatic cleaning is available for the backend
*
* DEPRECATED : use getCapabilities() instead
*
* @deprecated
* @return boolean
*/
public function isAutomaticCleaningAvailable()
{
return false;
}
/**
* Return the filling percentage of the backend storage
*
* @throws Zend_Cache_Exception
* @return int integer between 0 and 100
*/
public function getFillingPercentage()
{
$mem = apc_sma_info(true);
$memSize = $mem['num_seg'] * $mem['seg_size'];
$memAvailable= $mem['avail_mem'];
$memUsed = $memSize - $memAvailable;
if ($memSize == 0) {
Zend_Cache::throwException('can\'t get apc memory size');
}
if ($memUsed > $memSize) {
return 100;
}
return ((int) (100. * ($memUsed / $memSize)));
}
/**
* Return an array of stored tags
*
* @return array array of stored tags (string)
*/
public function getTags()
{
$this->_log(self::TAGS_UNSUPPORTED_BY_SAVE_OF_APC_BACKEND);
return array();
}
/**
* Return an array of stored cache ids which match given tags
*
* In case of multiple tags, a logical AND is made between tags
*
* @param array $tags array of tags
* @return array array of matching cache ids (string)
*/
public function getIdsMatchingTags($tags = array())
{
$this->_log(self::TAGS_UNSUPPORTED_BY_SAVE_OF_APC_BACKEND);
return array();
}
/**
* Return an array of stored cache ids which don't match given tags
*
* In case of multiple tags, a logical OR is made between tags
*
* @param array $tags array of tags
* @return array array of not matching cache ids (string)
*/
public function getIdsNotMatchingTags($tags = array())
{
$this->_log(self::TAGS_UNSUPPORTED_BY_SAVE_OF_APC_BACKEND);
return array();
}
/**
* Return an array of stored cache ids which match any given tags
*
* In case of multiple tags, a logical AND is made between tags
*
* @param array $tags array of tags
* @return array array of any matching cache ids (string)
*/
public function getIdsMatchingAnyTags($tags = array())
{
$this->_log(self::TAGS_UNSUPPORTED_BY_SAVE_OF_APC_BACKEND);
return array();
}
/**
* Return an array of stored cache ids
*
* @return array array of stored cache ids (string)
*/
public function getIds()
{
$res = array();
$array = apc_cache_info('user', false);
$records = $array['cache_list'];
foreach ($records as $record) {
$res[] = $record['info'];
}
return $res;
}
/**
* Return an array of metadatas for the given cache id
*
* The array must include these keys :
* - expire : the expire timestamp
* - tags : a string array of tags
* - mtime : timestamp of last modification time
*
* @param string $id cache id
* @return array array of metadatas (false if the cache id is not found)
*/
public function getMetadatas($id)
{
$tmp = apc_fetch($id);
if (is_array($tmp)) {
$data = $tmp[0];
$mtime = $tmp[1];
if (!isset($tmp[2])) {
// because this record is only with 1.7 release
// if old cache records are still there...
return false;
}
$lifetime = $tmp[2];
return array(
'expire' => $mtime + $lifetime,
'tags' => array(),
'mtime' => $mtime
);
}
return false;
}
/**
* Give (if possible) an extra lifetime to the given cache id
*
* @param string $id cache id
* @param int $extraLifetime
* @return boolean true if ok
*/
public function touch($id, $extraLifetime)
{
$tmp = apc_fetch($id);
if (is_array($tmp)) {
$data = $tmp[0];
$mtime = $tmp[1];
if (!isset($tmp[2])) {
// because this record is only with 1.7 release
// if old cache records are still there...
return false;
}
$lifetime = $tmp[2];
$newLifetime = $lifetime - (time() - $mtime) + $extraLifetime;
if ($newLifetime <=0) {
return false;
}
apc_store($id, array($data, time(), $newLifetime), $newLifetime);
return true;
}
return false;
}
/**
* Return an associative array of capabilities (booleans) of the backend
*
* The array must include these keys :
* - automatic_cleaning (is automating cleaning necessary)
* - tags (are tags supported)
* - expired_read (is it possible to read expired cache records
* (for doNotTestCacheValidity option for example))
* - priority does the backend deal with priority when saving
* - infinite_lifetime (is infinite lifetime can work with this backend)
* - get_list (is it possible to get the list of cache ids and the complete list of tags)
*
* @return array associative of with capabilities
*/
public function getCapabilities()
{
return array(
'automatic_cleaning' => false,
'tags' => false,
'expired_read' => false,
'priority' => false,
'infinite_lifetime' => false,
'get_list' => true
);
}
}

View File

@ -1,250 +0,0 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Cache
* @subpackage Zend_Cache_Backend
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: BlackHole.php 23775 2011-03-01 17:25:24Z ralph $
*/
/**
* @see Zend_Cache_Backend_Interface
*/
require_once 'Zend/Cache/Backend/ExtendedInterface.php';
/**
* @see Zend_Cache_Backend
*/
require_once 'Zend/Cache/Backend.php';
/**
* @package Zend_Cache
* @subpackage Zend_Cache_Backend
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Cache_Backend_BlackHole
extends Zend_Cache_Backend
implements Zend_Cache_Backend_ExtendedInterface
{
/**
* Test if a cache is available for the given id and (if yes) return it (false else)
*
* @param string $id cache id
* @param boolean $doNotTestCacheValidity if set to true, the cache validity won't be tested
* @return string|false cached datas
*/
public function load($id, $doNotTestCacheValidity = false)
{
return false;
}
/**
* Test if a cache is available or not (for the given id)
*
* @param string $id cache id
* @return mixed false (a cache is not available) or "last modified" timestamp (int) of the available cache record
*/
public function test($id)
{
return false;
}
/**
* Save some string datas into a cache record
*
* Note : $data is always "string" (serialization is done by the
* core not by the backend)
*
* @param string $data Datas to cache
* @param string $id Cache id
* @param array $tags Array of strings, the cache record will be tagged by each string entry
* @param int $specificLifetime If != false, set a specific lifetime for this cache record (null => infinite lifetime)
* @return boolean true if no problem
*/
public function save($data, $id, $tags = array(), $specificLifetime = false)
{
return true;
}
/**
* Remove a cache record
*
* @param string $id cache id
* @return boolean true if no problem
*/
public function remove($id)
{
return true;
}
/**
* Clean some cache records
*
* Available modes are :
* 'all' (default) => remove all cache entries ($tags is not used)
* 'old' => remove too old cache entries ($tags is not used)
* 'matchingTag' => remove cache entries matching all given tags
* ($tags can be an array of strings or a single string)
* 'notMatchingTag' => remove cache entries not matching one of the given tags
* ($tags can be an array of strings or a single string)
* 'matchingAnyTag' => remove cache entries matching any given tags
* ($tags can be an array of strings or a single string)
*
* @param string $mode clean mode
* @param tags array $tags array of tags
* @return boolean true if no problem
*/
public function clean($mode = Zend_Cache::CLEANING_MODE_ALL, $tags = array())
{
return true;
}
/**
* Return an array of stored cache ids
*
* @return array array of stored cache ids (string)
*/
public function getIds()
{
return array();
}
/**
* Return an array of stored tags
*
* @return array array of stored tags (string)
*/
public function getTags()
{
return array();
}
/**
* Return an array of stored cache ids which match given tags
*
* In case of multiple tags, a logical AND is made between tags
*
* @param array $tags array of tags
* @return array array of matching cache ids (string)
*/
public function getIdsMatchingTags($tags = array())
{
return array();
}
/**
* Return an array of stored cache ids which don't match given tags
*
* In case of multiple tags, a logical OR is made between tags
*
* @param array $tags array of tags
* @return array array of not matching cache ids (string)
*/
public function getIdsNotMatchingTags($tags = array())
{
return array();
}
/**
* Return an array of stored cache ids which match any given tags
*
* In case of multiple tags, a logical AND is made between tags
*
* @param array $tags array of tags
* @return array array of any matching cache ids (string)
*/
public function getIdsMatchingAnyTags($tags = array())
{
return array();
}
/**
* Return the filling percentage of the backend storage
*
* @return int integer between 0 and 100
* @throws Zend_Cache_Exception
*/
public function getFillingPercentage()
{
return 0;
}
/**
* Return an array of metadatas for the given cache id
*
* The array must include these keys :
* - expire : the expire timestamp
* - tags : a string array of tags
* - mtime : timestamp of last modification time
*
* @param string $id cache id
* @return array array of metadatas (false if the cache id is not found)
*/
public function getMetadatas($id)
{
return false;
}
/**
* Give (if possible) an extra lifetime to the given cache id
*
* @param string $id cache id
* @param int $extraLifetime
* @return boolean true if ok
*/
public function touch($id, $extraLifetime)
{
return false;
}
/**
* Return an associative array of capabilities (booleans) of the backend
*
* The array must include these keys :
* - automatic_cleaning (is automating cleaning necessary)
* - tags (are tags supported)
* - expired_read (is it possible to read expired cache records
* (for doNotTestCacheValidity option for example))
* - priority does the backend deal with priority when saving
* - infinite_lifetime (is infinite lifetime can work with this backend)
* - get_list (is it possible to get the list of cache ids and the complete list of tags)
*
* @return array associative of with capabilities
*/
public function getCapabilities()
{
return array(
'automatic_cleaning' => true,
'tags' => true,
'expired_read' => true,
'priority' => true,
'infinite_lifetime' => true,
'get_list' => true,
);
}
/**
* PUBLIC METHOD FOR UNIT TESTING ONLY !
*
* Force a cache record to expire
*
* @param string $id cache id
*/
public function ___expire($id)
{
}
}

View File

@ -1,126 +0,0 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Cache
* @subpackage Zend_Cache_Backend
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: ExtendedInterface.php 23775 2011-03-01 17:25:24Z ralph $
*/
/**
* @see Zend_Cache_Backend_Interface
*/
require_once 'Zend/Cache/Backend/Interface.php';
/**
* @package Zend_Cache
* @subpackage Zend_Cache_Backend
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
interface Zend_Cache_Backend_ExtendedInterface extends Zend_Cache_Backend_Interface
{
/**
* Return an array of stored cache ids
*
* @return array array of stored cache ids (string)
*/
public function getIds();
/**
* Return an array of stored tags
*
* @return array array of stored tags (string)
*/
public function getTags();
/**
* Return an array of stored cache ids which match given tags
*
* In case of multiple tags, a logical AND is made between tags
*
* @param array $tags array of tags
* @return array array of matching cache ids (string)
*/
public function getIdsMatchingTags($tags = array());
/**
* Return an array of stored cache ids which don't match given tags
*
* In case of multiple tags, a logical OR is made between tags
*
* @param array $tags array of tags
* @return array array of not matching cache ids (string)
*/
public function getIdsNotMatchingTags($tags = array());
/**
* Return an array of stored cache ids which match any given tags
*
* In case of multiple tags, a logical AND is made between tags
*
* @param array $tags array of tags
* @return array array of any matching cache ids (string)
*/
public function getIdsMatchingAnyTags($tags = array());
/**
* Return the filling percentage of the backend storage
*
* @return int integer between 0 and 100
*/
public function getFillingPercentage();
/**
* Return an array of metadatas for the given cache id
*
* The array must include these keys :
* - expire : the expire timestamp
* - tags : a string array of tags
* - mtime : timestamp of last modification time
*
* @param string $id cache id
* @return array array of metadatas (false if the cache id is not found)
*/
public function getMetadatas($id);
/**
* Give (if possible) an extra lifetime to the given cache id
*
* @param string $id cache id
* @param int $extraLifetime
* @return boolean true if ok
*/
public function touch($id, $extraLifetime);
/**
* Return an associative array of capabilities (booleans) of the backend
*
* The array must include these keys :
* - automatic_cleaning (is automating cleaning necessary)
* - tags (are tags supported)
* - expired_read (is it possible to read expired cache records
* (for doNotTestCacheValidity option for example))
* - priority does the backend deal with priority when saving
* - infinite_lifetime (is infinite lifetime can work with this backend)
* - get_list (is it possible to get the list of cache ids and the complete list of tags)
*
* @return array associative of with capabilities
*/
public function getCapabilities();
}

View File

@ -1,1007 +0,0 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Cache
* @subpackage Zend_Cache_Backend
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: File.php 24030 2011-05-09 22:10:00Z mabe $
*/
/**
* @see Zend_Cache_Backend_Interface
*/
require_once 'Zend/Cache/Backend/ExtendedInterface.php';
/**
* @see Zend_Cache_Backend
*/
require_once 'Zend/Cache/Backend.php';
/**
* @package Zend_Cache
* @subpackage Zend_Cache_Backend
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Cache_Backend_File extends Zend_Cache_Backend implements Zend_Cache_Backend_ExtendedInterface
{
/**
* Available options
*
* =====> (string) cache_dir :
* - Directory where to put the cache files
*
* =====> (boolean) file_locking :
* - Enable / disable file_locking
* - Can avoid cache corruption under bad circumstances but it doesn't work on multithread
* webservers and on NFS filesystems for example
*
* =====> (boolean) read_control :
* - Enable / disable read control
* - If enabled, a control key is embeded in cache file and this key is compared with the one
* calculated after the reading.
*
* =====> (string) read_control_type :
* - Type of read control (only if read control is enabled). Available values are :
* 'md5' for a md5 hash control (best but slowest)
* 'crc32' for a crc32 hash control (lightly less safe but faster, better choice)
* 'adler32' for an adler32 hash control (excellent choice too, faster than crc32)
* 'strlen' for a length only test (fastest)
*
* =====> (int) hashed_directory_level :
* - Hashed directory level
* - Set the hashed directory structure level. 0 means "no hashed directory
* structure", 1 means "one level of directory", 2 means "two levels"...
* This option can speed up the cache only when you have many thousands of
* cache file. Only specific benchs can help you to choose the perfect value
* for you. Maybe, 1 or 2 is a good start.
*
* =====> (int) hashed_directory_umask :
* - Umask for hashed directory structure
*
* =====> (string) file_name_prefix :
* - prefix for cache files
* - be really carefull with this option because a too generic value in a system cache dir
* (like /tmp) can cause disasters when cleaning the cache
*
* =====> (int) cache_file_umask :
* - Umask for cache files
*
* =====> (int) metatadatas_array_max_size :
* - max size for the metadatas array (don't change this value unless you
* know what you are doing)
*
* @var array available options
*/
protected $_options = array(
'cache_dir' => null,
'file_locking' => true,
'read_control' => true,
'read_control_type' => 'crc32',
'hashed_directory_level' => 0,
'hashed_directory_umask' => 0700,
'file_name_prefix' => 'zend_cache',
'cache_file_umask' => 0600,
'metadatas_array_max_size' => 100
);
/**
* Array of metadatas (each item is an associative array)
*
* @var array
*/
protected $_metadatasArray = array();
/**
* Constructor
*
* @param array $options associative array of options
* @throws Zend_Cache_Exception
* @return void
*/
public function __construct(array $options = array())
{
parent::__construct($options);
if ($this->_options['cache_dir'] !== null) { // particular case for this option
$this->setCacheDir($this->_options['cache_dir']);
} else {
$this->setCacheDir(self::getTmpDir() . DIRECTORY_SEPARATOR, false);
}
if (isset($this->_options['file_name_prefix'])) { // particular case for this option
if (!preg_match('~^[a-zA-Z0-9_]+$~D', $this->_options['file_name_prefix'])) {
Zend_Cache::throwException('Invalid file_name_prefix : must use only [a-zA-Z0-9_]');
}
}
if ($this->_options['metadatas_array_max_size'] < 10) {
Zend_Cache::throwException('Invalid metadatas_array_max_size, must be > 10');
}
if (isset($options['hashed_directory_umask']) && is_string($options['hashed_directory_umask'])) {
// See #ZF-4422
$this->_options['hashed_directory_umask'] = octdec($this->_options['hashed_directory_umask']);
}
if (isset($options['cache_file_umask']) && is_string($options['cache_file_umask'])) {
// See #ZF-4422
$this->_options['cache_file_umask'] = octdec($this->_options['cache_file_umask']);
}
}
/**
* Set the cache_dir (particular case of setOption() method)
*
* @param string $value
* @param boolean $trailingSeparator If true, add a trailing separator is necessary
* @throws Zend_Cache_Exception
* @return void
*/
public function setCacheDir($value, $trailingSeparator = true)
{
if (!is_dir($value)) {
Zend_Cache::throwException('cache_dir must be a directory');
}
if (!is_writable($value)) {
Zend_Cache::throwException('cache_dir is not writable');
}
if ($trailingSeparator) {
// add a trailing DIRECTORY_SEPARATOR if necessary
$value = rtrim(realpath($value), '\\/') . DIRECTORY_SEPARATOR;
}
$this->_options['cache_dir'] = $value;
}
/**
* Test if a cache is available for the given id and (if yes) return it (false else)
*
* @param string $id cache id
* @param boolean $doNotTestCacheValidity if set to true, the cache validity won't be tested
* @return string|false cached datas
*/
public function load($id, $doNotTestCacheValidity = false)
{
if (!($this->_test($id, $doNotTestCacheValidity))) {
// The cache is not hit !
return false;
}
$metadatas = $this->_getMetadatas($id);
$file = $this->_file($id);
$data = $this->_fileGetContents($file);
if ($this->_options['read_control']) {
$hashData = $this->_hash($data, $this->_options['read_control_type']);
$hashControl = $metadatas['hash'];
if ($hashData != $hashControl) {
// Problem detected by the read control !
$this->_log('Zend_Cache_Backend_File::load() / read_control : stored hash and computed hash do not match');
$this->remove($id);
return false;
}
}
return $data;
}
/**
* Test if a cache is available or not (for the given id)
*
* @param string $id cache id
* @return mixed false (a cache is not available) or "last modified" timestamp (int) of the available cache record
*/
public function test($id)
{
clearstatcache();
return $this->_test($id, false);
}
/**
* Save some string datas into a cache record
*
* Note : $data is always "string" (serialization is done by the
* core not by the backend)
*
* @param string $data Datas to cache
* @param string $id Cache id
* @param array $tags Array of strings, the cache record will be tagged by each string entry
* @param int $specificLifetime If != false, set a specific lifetime for this cache record (null => infinite lifetime)
* @return boolean true if no problem
*/
public function save($data, $id, $tags = array(), $specificLifetime = false)
{
clearstatcache();
$file = $this->_file($id);
$path = $this->_path($id);
if ($this->_options['hashed_directory_level'] > 0) {
if (!is_writable($path)) {
// maybe, we just have to build the directory structure
$this->_recursiveMkdirAndChmod($id);
}
if (!is_writable($path)) {
return false;
}
}
if ($this->_options['read_control']) {
$hash = $this->_hash($data, $this->_options['read_control_type']);
} else {
$hash = '';
}
$metadatas = array(
'hash' => $hash,
'mtime' => time(),
'expire' => $this->_expireTime($this->getLifetime($specificLifetime)),
'tags' => $tags
);
$res = $this->_setMetadatas($id, $metadatas);
if (!$res) {
$this->_log('Zend_Cache_Backend_File::save() / error on saving metadata');
return false;
}
$res = $this->_filePutContents($file, $data);
return $res;
}
/**
* Remove a cache record
*
* @param string $id cache id
* @return boolean true if no problem
*/
public function remove($id)
{
$file = $this->_file($id);
$boolRemove = $this->_remove($file);
$boolMetadata = $this->_delMetadatas($id);
return $boolMetadata && $boolRemove;
}
/**
* Clean some cache records
*
* Available modes are :
*
* Zend_Cache::CLEANING_MODE_ALL (default) => remove all cache entries ($tags is not used)
* Zend_Cache::CLEANING_MODE_OLD => remove too old cache entries ($tags is not used)
* Zend_Cache::CLEANING_MODE_MATCHING_TAG => remove cache entries matching all given tags
* ($tags can be an array of strings or a single string)
* Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG => remove cache entries not {matching one of the given tags}
* ($tags can be an array of strings or a single string)
* Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG => remove cache entries matching any given tags
* ($tags can be an array of strings or a single string)
*
* @param string $mode clean mode
* @param tags array $tags array of tags
* @return boolean true if no problem
*/
public function clean($mode = Zend_Cache::CLEANING_MODE_ALL, $tags = array())
{
// We use this protected method to hide the recursive stuff
clearstatcache();
return $this->_clean($this->_options['cache_dir'], $mode, $tags);
}
/**
* Return an array of stored cache ids
*
* @return array array of stored cache ids (string)
*/
public function getIds()
{
return $this->_get($this->_options['cache_dir'], 'ids', array());
}
/**
* Return an array of stored tags
*
* @return array array of stored tags (string)
*/
public function getTags()
{
return $this->_get($this->_options['cache_dir'], 'tags', array());
}
/**
* Return an array of stored cache ids which match given tags
*
* In case of multiple tags, a logical AND is made between tags
*
* @param array $tags array of tags
* @return array array of matching cache ids (string)
*/
public function getIdsMatchingTags($tags = array())
{
return $this->_get($this->_options['cache_dir'], 'matching', $tags);
}
/**
* Return an array of stored cache ids which don't match given tags
*
* In case of multiple tags, a logical OR is made between tags
*
* @param array $tags array of tags
* @return array array of not matching cache ids (string)
*/
public function getIdsNotMatchingTags($tags = array())
{
return $this->_get($this->_options['cache_dir'], 'notMatching', $tags);
}
/**
* Return an array of stored cache ids which match any given tags
*
* In case of multiple tags, a logical AND is made between tags
*
* @param array $tags array of tags
* @return array array of any matching cache ids (string)
*/
public function getIdsMatchingAnyTags($tags = array())
{
return $this->_get($this->_options['cache_dir'], 'matchingAny', $tags);
}
/**
* Return the filling percentage of the backend storage
*
* @throws Zend_Cache_Exception
* @return int integer between 0 and 100
*/
public function getFillingPercentage()
{
$free = disk_free_space($this->_options['cache_dir']);
$total = disk_total_space($this->_options['cache_dir']);
if ($total == 0) {
Zend_Cache::throwException('can\'t get disk_total_space');
} else {
if ($free >= $total) {
return 100;
}
return ((int) (100. * ($total - $free) / $total));
}
}
/**
* Return an array of metadatas for the given cache id
*
* The array must include these keys :
* - expire : the expire timestamp
* - tags : a string array of tags
* - mtime : timestamp of last modification time
*
* @param string $id cache id
* @return array array of metadatas (false if the cache id is not found)
*/
public function getMetadatas($id)
{
$metadatas = $this->_getMetadatas($id);
if (!$metadatas) {
return false;
}
if (time() > $metadatas['expire']) {
return false;
}
return array(
'expire' => $metadatas['expire'],
'tags' => $metadatas['tags'],
'mtime' => $metadatas['mtime']
);
}
/**
* Give (if possible) an extra lifetime to the given cache id
*
* @param string $id cache id
* @param int $extraLifetime
* @return boolean true if ok
*/
public function touch($id, $extraLifetime)
{
$metadatas = $this->_getMetadatas($id);
if (!$metadatas) {
return false;
}
if (time() > $metadatas['expire']) {
return false;
}
$newMetadatas = array(
'hash' => $metadatas['hash'],
'mtime' => time(),
'expire' => $metadatas['expire'] + $extraLifetime,
'tags' => $metadatas['tags']
);
$res = $this->_setMetadatas($id, $newMetadatas);
if (!$res) {
return false;
}
return true;
}
/**
* Return an associative array of capabilities (booleans) of the backend
*
* The array must include these keys :
* - automatic_cleaning (is automating cleaning necessary)
* - tags (are tags supported)
* - expired_read (is it possible to read expired cache records
* (for doNotTestCacheValidity option for example))
* - priority does the backend deal with priority when saving
* - infinite_lifetime (is infinite lifetime can work with this backend)
* - get_list (is it possible to get the list of cache ids and the complete list of tags)
*
* @return array associative of with capabilities
*/
public function getCapabilities()
{
return array(
'automatic_cleaning' => true,
'tags' => true,
'expired_read' => true,
'priority' => false,
'infinite_lifetime' => true,
'get_list' => true
);
}
/**
* PUBLIC METHOD FOR UNIT TESTING ONLY !
*
* Force a cache record to expire
*
* @param string $id cache id
*/
public function ___expire($id)
{
$metadatas = $this->_getMetadatas($id);
if ($metadatas) {
$metadatas['expire'] = 1;
$this->_setMetadatas($id, $metadatas);
}
}
/**
* Get a metadatas record
*
* @param string $id Cache id
* @return array|false Associative array of metadatas
*/
protected function _getMetadatas($id)
{
if (isset($this->_metadatasArray[$id])) {
return $this->_metadatasArray[$id];
} else {
$metadatas = $this->_loadMetadatas($id);
if (!$metadatas) {
return false;
}
$this->_setMetadatas($id, $metadatas, false);
return $metadatas;
}
}
/**
* Set a metadatas record
*
* @param string $id Cache id
* @param array $metadatas Associative array of metadatas
* @param boolean $save optional pass false to disable saving to file
* @return boolean True if no problem
*/
protected function _setMetadatas($id, $metadatas, $save = true)
{
if (count($this->_metadatasArray) >= $this->_options['metadatas_array_max_size']) {
$n = (int) ($this->_options['metadatas_array_max_size'] / 10);
$this->_metadatasArray = array_slice($this->_metadatasArray, $n);
}
if ($save) {
$result = $this->_saveMetadatas($id, $metadatas);
if (!$result) {
return false;
}
}
$this->_metadatasArray[$id] = $metadatas;
return true;
}
/**
* Drop a metadata record
*
* @param string $id Cache id
* @return boolean True if no problem
*/
protected function _delMetadatas($id)
{
if (isset($this->_metadatasArray[$id])) {
unset($this->_metadatasArray[$id]);
}
$file = $this->_metadatasFile($id);
return $this->_remove($file);
}
/**
* Clear the metadatas array
*
* @return void
*/
protected function _cleanMetadatas()
{
$this->_metadatasArray = array();
}
/**
* Load metadatas from disk
*
* @param string $id Cache id
* @return array|false Metadatas associative array
*/
protected function _loadMetadatas($id)
{
$file = $this->_metadatasFile($id);
$result = $this->_fileGetContents($file);
if (!$result) {
return false;
}
$tmp = @unserialize($result);
return $tmp;
}
/**
* Save metadatas to disk
*
* @param string $id Cache id
* @param array $metadatas Associative array
* @return boolean True if no problem
*/
protected function _saveMetadatas($id, $metadatas)
{
$file = $this->_metadatasFile($id);
$result = $this->_filePutContents($file, serialize($metadatas));
if (!$result) {
return false;
}
return true;
}
/**
* Make and return a file name (with path) for metadatas
*
* @param string $id Cache id
* @return string Metadatas file name (with path)
*/
protected function _metadatasFile($id)
{
$path = $this->_path($id);
$fileName = $this->_idToFileName('internal-metadatas---' . $id);
return $path . $fileName;
}
/**
* Check if the given filename is a metadatas one
*
* @param string $fileName File name
* @return boolean True if it's a metadatas one
*/
protected function _isMetadatasFile($fileName)
{
$id = $this->_fileNameToId($fileName);
if (substr($id, 0, 21) == 'internal-metadatas---') {
return true;
} else {
return false;
}
}
/**
* Remove a file
*
* If we can't remove the file (because of locks or any problem), we will touch
* the file to invalidate it
*
* @param string $file Complete file path
* @return boolean True if ok
*/
protected function _remove($file)
{
if (!is_file($file)) {
return false;
}
if (!@unlink($file)) {
# we can't remove the file (because of locks or any problem)
$this->_log("Zend_Cache_Backend_File::_remove() : we can't remove $file");
return false;
}
return true;
}
/**
* Clean some cache records (protected method used for recursive stuff)
*
* Available modes are :
* Zend_Cache::CLEANING_MODE_ALL (default) => remove all cache entries ($tags is not used)
* Zend_Cache::CLEANING_MODE_OLD => remove too old cache entries ($tags is not used)
* Zend_Cache::CLEANING_MODE_MATCHING_TAG => remove cache entries matching all given tags
* ($tags can be an array of strings or a single string)
* Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG => remove cache entries not {matching one of the given tags}
* ($tags can be an array of strings or a single string)
* Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG => remove cache entries matching any given tags
* ($tags can be an array of strings or a single string)
*
* @param string $dir Directory to clean
* @param string $mode Clean mode
* @param array $tags Array of tags
* @throws Zend_Cache_Exception
* @return boolean True if no problem
*/
protected function _clean($dir, $mode = Zend_Cache::CLEANING_MODE_ALL, $tags = array())
{
if (!is_dir($dir)) {
return false;
}
$result = true;
$prefix = $this->_options['file_name_prefix'];
$glob = @glob($dir . $prefix . '--*');
if ($glob === false) {
// On some systems it is impossible to distinguish between empty match and an error.
return true;
}
foreach ($glob as $file) {
if (is_file($file)) {
$fileName = basename($file);
if ($this->_isMetadatasFile($fileName)) {
// in CLEANING_MODE_ALL, we drop anything, even remainings old metadatas files
if ($mode != Zend_Cache::CLEANING_MODE_ALL) {
continue;
}
}
$id = $this->_fileNameToId($fileName);
$metadatas = $this->_getMetadatas($id);
if ($metadatas === FALSE) {
$metadatas = array('expire' => 1, 'tags' => array());
}
switch ($mode) {
case Zend_Cache::CLEANING_MODE_ALL:
$res = $this->remove($id);
if (!$res) {
// in this case only, we accept a problem with the metadatas file drop
$res = $this->_remove($file);
}
$result = $result && $res;
break;
case Zend_Cache::CLEANING_MODE_OLD:
if (time() > $metadatas['expire']) {
$result = $this->remove($id) && $result;
}
break;
case Zend_Cache::CLEANING_MODE_MATCHING_TAG:
$matching = true;
foreach ($tags as $tag) {
if (!in_array($tag, $metadatas['tags'])) {
$matching = false;
break;
}
}
if ($matching) {
$result = $this->remove($id) && $result;
}
break;
case Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG:
$matching = false;
foreach ($tags as $tag) {
if (in_array($tag, $metadatas['tags'])) {
$matching = true;
break;
}
}
if (!$matching) {
$result = $this->remove($id) && $result;
}
break;
case Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG:
$matching = false;
foreach ($tags as $tag) {
if (in_array($tag, $metadatas['tags'])) {
$matching = true;
break;
}
}
if ($matching) {
$result = $this->remove($id) && $result;
}
break;
default:
Zend_Cache::throwException('Invalid mode for clean() method');
break;
}
}
if ((is_dir($file)) and ($this->_options['hashed_directory_level']>0)) {
// Recursive call
$result = $this->_clean($file . DIRECTORY_SEPARATOR, $mode, $tags) && $result;
if ($mode == Zend_Cache::CLEANING_MODE_ALL) {
// we try to drop the structure too
@rmdir($file);
}
}
}
return $result;
}
protected function _get($dir, $mode, $tags = array())
{
if (!is_dir($dir)) {
return false;
}
$result = array();
$prefix = $this->_options['file_name_prefix'];
$glob = @glob($dir . $prefix . '--*');
if ($glob === false) {
// On some systems it is impossible to distinguish between empty match and an error.
return array();
}
foreach ($glob as $file) {
if (is_file($file)) {
$fileName = basename($file);
$id = $this->_fileNameToId($fileName);
$metadatas = $this->_getMetadatas($id);
if ($metadatas === FALSE) {
continue;
}
if (time() > $metadatas['expire']) {
continue;
}
switch ($mode) {
case 'ids':
$result[] = $id;
break;
case 'tags':
$result = array_unique(array_merge($result, $metadatas['tags']));
break;
case 'matching':
$matching = true;
foreach ($tags as $tag) {
if (!in_array($tag, $metadatas['tags'])) {
$matching = false;
break;
}
}
if ($matching) {
$result[] = $id;
}
break;
case 'notMatching':
$matching = false;
foreach ($tags as $tag) {
if (in_array($tag, $metadatas['tags'])) {
$matching = true;
break;
}
}
if (!$matching) {
$result[] = $id;
}
break;
case 'matchingAny':
$matching = false;
foreach ($tags as $tag) {
if (in_array($tag, $metadatas['tags'])) {
$matching = true;
break;
}
}
if ($matching) {
$result[] = $id;
}
break;
default:
Zend_Cache::throwException('Invalid mode for _get() method');
break;
}
}
if ((is_dir($file)) and ($this->_options['hashed_directory_level']>0)) {
// Recursive call
$recursiveRs = $this->_get($file . DIRECTORY_SEPARATOR, $mode, $tags);
if ($recursiveRs === false) {
$this->_log('Zend_Cache_Backend_File::_get() / recursive call : can\'t list entries of "'.$file.'"');
} else {
$result = array_unique(array_merge($result, $recursiveRs));
}
}
}
return array_unique($result);
}
/**
* Compute & return the expire time
*
* @return int expire time (unix timestamp)
*/
protected function _expireTime($lifetime)
{
if ($lifetime === null) {
return 9999999999;
}
return time() + $lifetime;
}
/**
* Make a control key with the string containing datas
*
* @param string $data Data
* @param string $controlType Type of control 'md5', 'crc32' or 'strlen'
* @throws Zend_Cache_Exception
* @return string Control key
*/
protected function _hash($data, $controlType)
{
switch ($controlType) {
case 'md5':
return md5($data);
case 'crc32':
return crc32($data);
case 'strlen':
return strlen($data);
case 'adler32':
return hash('adler32', $data);
default:
Zend_Cache::throwException("Incorrect hash function : $controlType");
}
}
/**
* Transform a cache id into a file name and return it
*
* @param string $id Cache id
* @return string File name
*/
protected function _idToFileName($id)
{
$prefix = $this->_options['file_name_prefix'];
$result = $prefix . '---' . $id;
return $result;
}
/**
* Make and return a file name (with path)
*
* @param string $id Cache id
* @return string File name (with path)
*/
protected function _file($id)
{
$path = $this->_path($id);
$fileName = $this->_idToFileName($id);
return $path . $fileName;
}
/**
* Return the complete directory path of a filename (including hashedDirectoryStructure)
*
* @param string $id Cache id
* @param boolean $parts if true, returns array of directory parts instead of single string
* @return string Complete directory path
*/
protected function _path($id, $parts = false)
{
$partsArray = array();
$root = $this->_options['cache_dir'];
$prefix = $this->_options['file_name_prefix'];
if ($this->_options['hashed_directory_level']>0) {
$hash = hash('adler32', $id);
for ($i=0 ; $i < $this->_options['hashed_directory_level'] ; $i++) {
$root = $root . $prefix . '--' . substr($hash, 0, $i + 1) . DIRECTORY_SEPARATOR;
$partsArray[] = $root;
}
}
if ($parts) {
return $partsArray;
} else {
return $root;
}
}
/**
* Make the directory strucuture for the given id
*
* @param string $id cache id
* @return boolean true
*/
protected function _recursiveMkdirAndChmod($id)
{
if ($this->_options['hashed_directory_level'] <=0) {
return true;
}
$partsArray = $this->_path($id, true);
foreach ($partsArray as $part) {
if (!is_dir($part)) {
@mkdir($part, $this->_options['hashed_directory_umask']);
@chmod($part, $this->_options['hashed_directory_umask']); // see #ZF-320 (this line is required in some configurations)
}
}
return true;
}
/**
* Test if the given cache id is available (and still valid as a cache record)
*
* @param string $id Cache id
* @param boolean $doNotTestCacheValidity If set to true, the cache validity won't be tested
* @return boolean|mixed false (a cache is not available) or "last modified" timestamp (int) of the available cache record
*/
protected function _test($id, $doNotTestCacheValidity)
{
$metadatas = $this->_getMetadatas($id);
if (!$metadatas) {
return false;
}
if ($doNotTestCacheValidity || (time() <= $metadatas['expire'])) {
return $metadatas['mtime'];
}
return false;
}
/**
* Return the file content of the given file
*
* @param string $file File complete path
* @return string File content (or false if problem)
*/
protected function _fileGetContents($file)
{
$result = false;
if (!is_file($file)) {
return false;
}
$f = @fopen($file, 'rb');
if ($f) {
if ($this->_options['file_locking']) @flock($f, LOCK_SH);
$result = stream_get_contents($f);
if ($this->_options['file_locking']) @flock($f, LOCK_UN);
@fclose($f);
}
return $result;
}
/**
* Put the given string into the given file
*
* @param string $file File complete path
* @param string $string String to put in file
* @return boolean true if no problem
*/
protected function _filePutContents($file, $string)
{
$result = false;
$f = @fopen($file, 'ab+');
if ($f) {
if ($this->_options['file_locking']) @flock($f, LOCK_EX);
fseek($f, 0);
ftruncate($f, 0);
$tmp = @fwrite($f, $string);
if (!($tmp === FALSE)) {
$result = true;
}
@fclose($f);
}
@chmod($file, $this->_options['cache_file_umask']);
return $result;
}
/**
* Transform a file name into cache id and return it
*
* @param string $fileName File name
* @return string Cache id
*/
protected function _fileNameToId($fileName)
{
$prefix = $this->_options['file_name_prefix'];
return preg_replace('~^' . $prefix . '---(.*)$~', '$1', $fileName);
}
}

View File

@ -1,99 +0,0 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Cache
* @subpackage Zend_Cache_Backend
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Interface.php 23775 2011-03-01 17:25:24Z ralph $
*/
/**
* @package Zend_Cache
* @subpackage Zend_Cache_Backend
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
interface Zend_Cache_Backend_Interface
{
/**
* Set the frontend directives
*
* @param array $directives assoc of directives
*/
public function setDirectives($directives);
/**
* Test if a cache is available for the given id and (if yes) return it (false else)
*
* Note : return value is always "string" (unserialization is done by the core not by the backend)
*
* @param string $id Cache id
* @param boolean $doNotTestCacheValidity If set to true, the cache validity won't be tested
* @return string|false cached datas
*/
public function load($id, $doNotTestCacheValidity = false);
/**
* Test if a cache is available or not (for the given id)
*
* @param string $id cache id
* @return mixed|false (a cache is not available) or "last modified" timestamp (int) of the available cache record
*/
public function test($id);
/**
* Save some string datas into a cache record
*
* Note : $data is always "string" (serialization is done by the
* core not by the backend)
*
* @param string $data Datas to cache
* @param string $id Cache id
* @param array $tags Array of strings, the cache record will be tagged by each string entry
* @param int $specificLifetime If != false, set a specific lifetime for this cache record (null => infinite lifetime)
* @return boolean true if no problem
*/
public function save($data, $id, $tags = array(), $specificLifetime = false);
/**
* Remove a cache record
*
* @param string $id Cache id
* @return boolean True if no problem
*/
public function remove($id);
/**
* Clean some cache records
*
* Available modes are :
* Zend_Cache::CLEANING_MODE_ALL (default) => remove all cache entries ($tags is not used)
* Zend_Cache::CLEANING_MODE_OLD => remove too old cache entries ($tags is not used)
* Zend_Cache::CLEANING_MODE_MATCHING_TAG => remove cache entries matching all given tags
* ($tags can be an array of strings or a single string)
* Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG => remove cache entries not {matching one of the given tags}
* ($tags can be an array of strings or a single string)
* Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG => remove cache entries matching any given tags
* ($tags can be an array of strings or a single string)
*
* @param string $mode Clean mode
* @param array $tags Array of tags
* @return boolean true if no problem
*/
public function clean($mode = Zend_Cache::CLEANING_MODE_ALL, $tags = array());
}

View File

@ -1,484 +0,0 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Cache
* @subpackage Zend_Cache_Backend
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Libmemcached.php 23775 2011-03-01 17:25:24Z ralph $
*/
/**
* @see Zend_Cache_Backend_Interface
*/
require_once 'Zend/Cache/Backend/ExtendedInterface.php';
/**
* @see Zend_Cache_Backend
*/
require_once 'Zend/Cache/Backend.php';
/**
* @package Zend_Cache
* @subpackage Zend_Cache_Backend
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Cache_Backend_Libmemcached extends Zend_Cache_Backend implements Zend_Cache_Backend_ExtendedInterface
{
/**
* Default Server Values
*/
const DEFAULT_HOST = '127.0.0.1';
const DEFAULT_PORT = 11211;
const DEFAULT_WEIGHT = 1;
/**
* Log message
*/
const TAGS_UNSUPPORTED_BY_CLEAN_OF_LIBMEMCACHED_BACKEND = 'Zend_Cache_Backend_Libmemcached::clean() : tags are unsupported by the Libmemcached backend';
const TAGS_UNSUPPORTED_BY_SAVE_OF_LIBMEMCACHED_BACKEND = 'Zend_Cache_Backend_Libmemcached::save() : tags are unsupported by the Libmemcached backend';
/**
* Available options
*
* =====> (array) servers :
* an array of memcached server ; each memcached server is described by an associative array :
* 'host' => (string) : the name of the memcached server
* 'port' => (int) : the port of the memcached server
* 'weight' => (int) : number of buckets to create for this server which in turn control its
* probability of it being selected. The probability is relative to the total
* weight of all servers.
* =====> (array) client :
* an array of memcached client options ; the memcached client is described by an associative array :
* @see http://php.net/manual/memcached.constants.php
* - The option name can be the name of the constant without the prefix 'OPT_'
* or the integer value of this option constant
*
* @var array available options
*/
protected $_options = array(
'servers' => array(array(
'host' => self::DEFAULT_HOST,
'port' => self::DEFAULT_PORT,
'weight' => self::DEFAULT_WEIGHT,
)),
'client' => array()
);
/**
* Memcached object
*
* @var mixed memcached object
*/
protected $_memcache = null;
/**
* Constructor
*
* @param array $options associative array of options
* @throws Zend_Cache_Exception
* @return void
*/
public function __construct(array $options = array())
{
if (!extension_loaded('memcached')) {
Zend_Cache::throwException('The memcached extension must be loaded for using this backend !');
}
// override default client options
$this->_options['client'] = array(
Memcached::OPT_DISTRIBUTION => Memcached::DISTRIBUTION_CONSISTENT,
Memcached::OPT_HASH => Memcached::HASH_MD5,
Memcached::OPT_LIBKETAMA_COMPATIBLE => true,
);
parent::__construct($options);
if (isset($this->_options['servers'])) {
$value = $this->_options['servers'];
if (isset($value['host'])) {
// in this case, $value seems to be a simple associative array (one server only)
$value = array(0 => $value); // let's transform it into a classical array of associative arrays
}
$this->setOption('servers', $value);
}
$this->_memcache = new Memcached;
// setup memcached client options
foreach ($this->_options['client'] as $name => $value) {
$optId = null;
if (is_int($name)) {
$optId = $name;
} else {
$optConst = 'Memcached::OPT_' . strtoupper($name);
if (defined($optConst)) {
$optId = constant($optConst);
} else {
$this->_log("Unknown memcached client option '{$name}' ({$optConst})");
}
}
if ($optId) {
if (!$this->_memcache->setOption($optId, $value)) {
$this->_log("Setting memcached client option '{$optId}' failed");
}
}
}
// setup memcached servers
$servers = array();
foreach ($this->_options['servers'] as $server) {
if (!array_key_exists('port', $server)) {
$server['port'] = self::DEFAULT_PORT;
}
if (!array_key_exists('weight', $server)) {
$server['weight'] = self::DEFAULT_WEIGHT;
}
$servers[] = array($server['host'], $server['port'], $server['weight']);
}
$this->_memcache->addServers($servers);
}
/**
* Test if a cache is available for the given id and (if yes) return it (false else)
*
* @param string $id Cache id
* @param boolean $doNotTestCacheValidity If set to true, the cache validity won't be tested
* @return string|false cached datas
*/
public function load($id, $doNotTestCacheValidity = false)
{
$tmp = $this->_memcache->get($id);
if (isset($tmp[0])) {
return $tmp[0];
}
return false;
}
/**
* Test if a cache is available or not (for the given id)
*
* @param string $id Cache id
* @return int|false (a cache is not available) or "last modified" timestamp (int) of the available cache record
*/
public function test($id)
{
$tmp = $this->_memcache->get($id);
if (isset($tmp[0], $tmp[1])) {
return (int)$tmp[1];
}
return false;
}
/**
* Save some string datas into a cache record
*
* Note : $data is always "string" (serialization is done by the
* core not by the backend)
*
* @param string $data Datas to cache
* @param string $id Cache id
* @param array $tags Array of strings, the cache record will be tagged by each string entry
* @param int $specificLifetime If != false, set a specific lifetime for this cache record (null => infinite lifetime)
* @return boolean True if no problem
*/
public function save($data, $id, $tags = array(), $specificLifetime = false)
{
$lifetime = $this->getLifetime($specificLifetime);
// ZF-8856: using set because add needs a second request if item already exists
$result = @$this->_memcache->set($id, array($data, time(), $lifetime), $lifetime);
if ($result === false) {
$rsCode = $this->_memcache->getResultCode();
$rsMsg = $this->_memcache->getResultMessage();
$this->_log("Memcached::set() failed: [{$rsCode}] {$rsMsg}");
}
if (count($tags) > 0) {
$this->_log(self::TAGS_UNSUPPORTED_BY_SAVE_OF_LIBMEMCACHED_BACKEND);
}
return $result;
}
/**
* Remove a cache record
*
* @param string $id Cache id
* @return boolean True if no problem
*/
public function remove($id)
{
return $this->_memcache->delete($id);
}
/**
* Clean some cache records
*
* Available modes are :
* 'all' (default) => remove all cache entries ($tags is not used)
* 'old' => unsupported
* 'matchingTag' => unsupported
* 'notMatchingTag' => unsupported
* 'matchingAnyTag' => unsupported
*
* @param string $mode Clean mode
* @param array $tags Array of tags
* @throws Zend_Cache_Exception
* @return boolean True if no problem
*/
public function clean($mode = Zend_Cache::CLEANING_MODE_ALL, $tags = array())
{
switch ($mode) {
case Zend_Cache::CLEANING_MODE_ALL:
return $this->_memcache->flush();
break;
case Zend_Cache::CLEANING_MODE_OLD:
$this->_log("Zend_Cache_Backend_Libmemcached::clean() : CLEANING_MODE_OLD is unsupported by the Libmemcached backend");
break;
case Zend_Cache::CLEANING_MODE_MATCHING_TAG:
case Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG:
case Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG:
$this->_log(self::TAGS_UNSUPPORTED_BY_CLEAN_OF_LIBMEMCACHED_BACKEND);
break;
default:
Zend_Cache::throwException('Invalid mode for clean() method');
break;
}
}
/**
* Return true if the automatic cleaning is available for the backend
*
* @return boolean
*/
public function isAutomaticCleaningAvailable()
{
return false;
}
/**
* Set the frontend directives
*
* @param array $directives Assoc of directives
* @throws Zend_Cache_Exception
* @return void
*/
public function setDirectives($directives)
{
parent::setDirectives($directives);
$lifetime = $this->getLifetime(false);
if ($lifetime > 2592000) {
// #ZF-3490 : For the memcached backend, there is a lifetime limit of 30 days (2592000 seconds)
$this->_log('memcached backend has a limit of 30 days (2592000 seconds) for the lifetime');
}
if ($lifetime === null) {
// #ZF-4614 : we tranform null to zero to get the maximal lifetime
parent::setDirectives(array('lifetime' => 0));
}
}
/**
* Return an array of stored cache ids
*
* @return array array of stored cache ids (string)
*/
public function getIds()
{
$this->_log("Zend_Cache_Backend_Libmemcached::save() : getting the list of cache ids is unsupported by the Libmemcached backend");
return array();
}
/**
* Return an array of stored tags
*
* @return array array of stored tags (string)
*/
public function getTags()
{
$this->_log(self::TAGS_UNSUPPORTED_BY_SAVE_OF_LIBMEMCACHED_BACKEND);
return array();
}
/**
* Return an array of stored cache ids which match given tags
*
* In case of multiple tags, a logical AND is made between tags
*
* @param array $tags array of tags
* @return array array of matching cache ids (string)
*/
public function getIdsMatchingTags($tags = array())
{
$this->_log(self::TAGS_UNSUPPORTED_BY_SAVE_OF_LIBMEMCACHED_BACKEND);
return array();
}
/**
* Return an array of stored cache ids which don't match given tags
*
* In case of multiple tags, a logical OR is made between tags
*
* @param array $tags array of tags
* @return array array of not matching cache ids (string)
*/
public function getIdsNotMatchingTags($tags = array())
{
$this->_log(self::TAGS_UNSUPPORTED_BY_SAVE_OF_LIBMEMCACHED_BACKEND);
return array();
}
/**
* Return an array of stored cache ids which match any given tags
*
* In case of multiple tags, a logical AND is made between tags
*
* @param array $tags array of tags
* @return array array of any matching cache ids (string)
*/
public function getIdsMatchingAnyTags($tags = array())
{
$this->_log(self::TAGS_UNSUPPORTED_BY_SAVE_OF_LIBMEMCACHED_BACKEND);
return array();
}
/**
* Return the filling percentage of the backend storage
*
* @throws Zend_Cache_Exception
* @return int integer between 0 and 100
*/
public function getFillingPercentage()
{
$mems = $this->_memcache->getStats();
if ($mems === false) {
return 0;
}
$memSize = null;
$memUsed = null;
foreach ($mems as $key => $mem) {
if ($mem === false) {
$this->_log('can\'t get stat from ' . $key);
continue;
}
$eachSize = $mem['limit_maxbytes'];
$eachUsed = $mem['bytes'];
if ($eachUsed > $eachSize) {
$eachUsed = $eachSize;
}
$memSize += $eachSize;
$memUsed += $eachUsed;
}
if ($memSize === null || $memUsed === null) {
Zend_Cache::throwException('Can\'t get filling percentage');
}
return ((int) (100. * ($memUsed / $memSize)));
}
/**
* Return an array of metadatas for the given cache id
*
* The array must include these keys :
* - expire : the expire timestamp
* - tags : a string array of tags
* - mtime : timestamp of last modification time
*
* @param string $id cache id
* @return array array of metadatas (false if the cache id is not found)
*/
public function getMetadatas($id)
{
$tmp = $this->_memcache->get($id);
if (isset($tmp[0], $tmp[1], $tmp[2])) {
$data = $tmp[0];
$mtime = $tmp[1];
$lifetime = $tmp[2];
return array(
'expire' => $mtime + $lifetime,
'tags' => array(),
'mtime' => $mtime
);
}
return false;
}
/**
* Give (if possible) an extra lifetime to the given cache id
*
* @param string $id cache id
* @param int $extraLifetime
* @return boolean true if ok
*/
public function touch($id, $extraLifetime)
{
$tmp = $this->_memcache->get($id);
if (isset($tmp[0], $tmp[1], $tmp[2])) {
$data = $tmp[0];
$mtime = $tmp[1];
$lifetime = $tmp[2];
$newLifetime = $lifetime - (time() - $mtime) + $extraLifetime;
if ($newLifetime <=0) {
return false;
}
// #ZF-5702 : we try replace() first becase set() seems to be slower
if (!($result = $this->_memcache->replace($id, array($data, time(), $newLifetime), $newLifetime))) {
$result = $this->_memcache->set($id, array($data, time(), $newLifetime), $newLifetime);
if ($result === false) {
$rsCode = $this->_memcache->getResultCode();
$rsMsg = $this->_memcache->getResultMessage();
$this->_log("Memcached::set() failed: [{$rsCode}] {$rsMsg}");
}
}
return $result;
}
return false;
}
/**
* Return an associative array of capabilities (booleans) of the backend
*
* The array must include these keys :
* - automatic_cleaning (is automating cleaning necessary)
* - tags (are tags supported)
* - expired_read (is it possible to read expired cache records
* (for doNotTestCacheValidity option for example))
* - priority does the backend deal with priority when saving
* - infinite_lifetime (is infinite lifetime can work with this backend)
* - get_list (is it possible to get the list of cache ids and the complete list of tags)
*
* @return array associative of with capabilities
*/
public function getCapabilities()
{
return array(
'automatic_cleaning' => false,
'tags' => false,
'expired_read' => false,
'priority' => false,
'infinite_lifetime' => false,
'get_list' => false
);
}
}

View File

@ -1,504 +0,0 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Cache
* @subpackage Zend_Cache_Backend
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Memcached.php 23775 2011-03-01 17:25:24Z ralph $
*/
/**
* @see Zend_Cache_Backend_Interface
*/
require_once 'Zend/Cache/Backend/ExtendedInterface.php';
/**
* @see Zend_Cache_Backend
*/
require_once 'Zend/Cache/Backend.php';
/**
* @package Zend_Cache
* @subpackage Zend_Cache_Backend
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Cache_Backend_Memcached extends Zend_Cache_Backend implements Zend_Cache_Backend_ExtendedInterface
{
/**
* Default Values
*/
const DEFAULT_HOST = '127.0.0.1';
const DEFAULT_PORT = 11211;
const DEFAULT_PERSISTENT = true;
const DEFAULT_WEIGHT = 1;
const DEFAULT_TIMEOUT = 1;
const DEFAULT_RETRY_INTERVAL = 15;
const DEFAULT_STATUS = true;
const DEFAULT_FAILURE_CALLBACK = null;
/**
* Log message
*/
const TAGS_UNSUPPORTED_BY_CLEAN_OF_MEMCACHED_BACKEND = 'Zend_Cache_Backend_Memcached::clean() : tags are unsupported by the Memcached backend';
const TAGS_UNSUPPORTED_BY_SAVE_OF_MEMCACHED_BACKEND = 'Zend_Cache_Backend_Memcached::save() : tags are unsupported by the Memcached backend';
/**
* Available options
*
* =====> (array) servers :
* an array of memcached server ; each memcached server is described by an associative array :
* 'host' => (string) : the name of the memcached server
* 'port' => (int) : the port of the memcached server
* 'persistent' => (bool) : use or not persistent connections to this memcached server
* 'weight' => (int) : number of buckets to create for this server which in turn control its
* probability of it being selected. The probability is relative to the total
* weight of all servers.
* 'timeout' => (int) : value in seconds which will be used for connecting to the daemon. Think twice
* before changing the default value of 1 second - you can lose all the
* advantages of caching if your connection is too slow.
* 'retry_interval' => (int) : controls how often a failed server will be retried, the default value
* is 15 seconds. Setting this parameter to -1 disables automatic retry.
* 'status' => (bool) : controls if the server should be flagged as online.
* 'failure_callback' => (callback) : Allows the user to specify a callback function to run upon
* encountering an error. The callback is run before failover
* is attempted. The function takes two parameters, the hostname
* and port of the failed server.
*
* =====> (boolean) compression :
* true if you want to use on-the-fly compression
*
* =====> (boolean) compatibility :
* true if you use old memcache server or extension
*
* @var array available options
*/
protected $_options = array(
'servers' => array(array(
'host' => self::DEFAULT_HOST,
'port' => self::DEFAULT_PORT,
'persistent' => self::DEFAULT_PERSISTENT,
'weight' => self::DEFAULT_WEIGHT,
'timeout' => self::DEFAULT_TIMEOUT,
'retry_interval' => self::DEFAULT_RETRY_INTERVAL,
'status' => self::DEFAULT_STATUS,
'failure_callback' => self::DEFAULT_FAILURE_CALLBACK
)),
'compression' => false,
'compatibility' => false,
);
/**
* Memcache object
*
* @var mixed memcache object
*/
protected $_memcache = null;
/**
* Constructor
*
* @param array $options associative array of options
* @throws Zend_Cache_Exception
* @return void
*/
public function __construct(array $options = array())
{
if (!extension_loaded('memcache')) {
Zend_Cache::throwException('The memcache extension must be loaded for using this backend !');
}
parent::__construct($options);
if (isset($this->_options['servers'])) {
$value= $this->_options['servers'];
if (isset($value['host'])) {
// in this case, $value seems to be a simple associative array (one server only)
$value = array(0 => $value); // let's transform it into a classical array of associative arrays
}
$this->setOption('servers', $value);
}
$this->_memcache = new Memcache;
foreach ($this->_options['servers'] as $server) {
if (!array_key_exists('port', $server)) {
$server['port'] = self::DEFAULT_PORT;
}
if (!array_key_exists('persistent', $server)) {
$server['persistent'] = self::DEFAULT_PERSISTENT;
}
if (!array_key_exists('weight', $server)) {
$server['weight'] = self::DEFAULT_WEIGHT;
}
if (!array_key_exists('timeout', $server)) {
$server['timeout'] = self::DEFAULT_TIMEOUT;
}
if (!array_key_exists('retry_interval', $server)) {
$server['retry_interval'] = self::DEFAULT_RETRY_INTERVAL;
}
if (!array_key_exists('status', $server)) {
$server['status'] = self::DEFAULT_STATUS;
}
if (!array_key_exists('failure_callback', $server)) {
$server['failure_callback'] = self::DEFAULT_FAILURE_CALLBACK;
}
if ($this->_options['compatibility']) {
// No status for compatibility mode (#ZF-5887)
$this->_memcache->addServer($server['host'], $server['port'], $server['persistent'],
$server['weight'], $server['timeout'],
$server['retry_interval']);
} else {
$this->_memcache->addServer($server['host'], $server['port'], $server['persistent'],
$server['weight'], $server['timeout'],
$server['retry_interval'],
$server['status'], $server['failure_callback']);
}
}
}
/**
* Test if a cache is available for the given id and (if yes) return it (false else)
*
* @param string $id Cache id
* @param boolean $doNotTestCacheValidity If set to true, the cache validity won't be tested
* @return string|false cached datas
*/
public function load($id, $doNotTestCacheValidity = false)
{
$tmp = $this->_memcache->get($id);
if (is_array($tmp) && isset($tmp[0])) {
return $tmp[0];
}
return false;
}
/**
* Test if a cache is available or not (for the given id)
*
* @param string $id Cache id
* @return mixed|false (a cache is not available) or "last modified" timestamp (int) of the available cache record
*/
public function test($id)
{
$tmp = $this->_memcache->get($id);
if (is_array($tmp)) {
return $tmp[1];
}
return false;
}
/**
* Save some string datas into a cache record
*
* Note : $data is always "string" (serialization is done by the
* core not by the backend)
*
* @param string $data Datas to cache
* @param string $id Cache id
* @param array $tags Array of strings, the cache record will be tagged by each string entry
* @param int $specificLifetime If != false, set a specific lifetime for this cache record (null => infinite lifetime)
* @return boolean True if no problem
*/
public function save($data, $id, $tags = array(), $specificLifetime = false)
{
$lifetime = $this->getLifetime($specificLifetime);
if ($this->_options['compression']) {
$flag = MEMCACHE_COMPRESSED;
} else {
$flag = 0;
}
// ZF-8856: using set because add needs a second request if item already exists
$result = @$this->_memcache->set($id, array($data, time(), $lifetime), $flag, $lifetime);
if (count($tags) > 0) {
$this->_log(self::TAGS_UNSUPPORTED_BY_SAVE_OF_MEMCACHED_BACKEND);
}
return $result;
}
/**
* Remove a cache record
*
* @param string $id Cache id
* @return boolean True if no problem
*/
public function remove($id)
{
return $this->_memcache->delete($id, 0);
}
/**
* Clean some cache records
*
* Available modes are :
* 'all' (default) => remove all cache entries ($tags is not used)
* 'old' => unsupported
* 'matchingTag' => unsupported
* 'notMatchingTag' => unsupported
* 'matchingAnyTag' => unsupported
*
* @param string $mode Clean mode
* @param array $tags Array of tags
* @throws Zend_Cache_Exception
* @return boolean True if no problem
*/
public function clean($mode = Zend_Cache::CLEANING_MODE_ALL, $tags = array())
{
switch ($mode) {
case Zend_Cache::CLEANING_MODE_ALL:
return $this->_memcache->flush();
break;
case Zend_Cache::CLEANING_MODE_OLD:
$this->_log("Zend_Cache_Backend_Memcached::clean() : CLEANING_MODE_OLD is unsupported by the Memcached backend");
break;
case Zend_Cache::CLEANING_MODE_MATCHING_TAG:
case Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG:
case Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG:
$this->_log(self::TAGS_UNSUPPORTED_BY_CLEAN_OF_MEMCACHED_BACKEND);
break;
default:
Zend_Cache::throwException('Invalid mode for clean() method');
break;
}
}
/**
* Return true if the automatic cleaning is available for the backend
*
* @return boolean
*/
public function isAutomaticCleaningAvailable()
{
return false;
}
/**
* Set the frontend directives
*
* @param array $directives Assoc of directives
* @throws Zend_Cache_Exception
* @return void
*/
public function setDirectives($directives)
{
parent::setDirectives($directives);
$lifetime = $this->getLifetime(false);
if ($lifetime > 2592000) {
// #ZF-3490 : For the memcached backend, there is a lifetime limit of 30 days (2592000 seconds)
$this->_log('memcached backend has a limit of 30 days (2592000 seconds) for the lifetime');
}
if ($lifetime === null) {
// #ZF-4614 : we tranform null to zero to get the maximal lifetime
parent::setDirectives(array('lifetime' => 0));
}
}
/**
* Return an array of stored cache ids
*
* @return array array of stored cache ids (string)
*/
public function getIds()
{
$this->_log("Zend_Cache_Backend_Memcached::save() : getting the list of cache ids is unsupported by the Memcache backend");
return array();
}
/**
* Return an array of stored tags
*
* @return array array of stored tags (string)
*/
public function getTags()
{
$this->_log(self::TAGS_UNSUPPORTED_BY_SAVE_OF_MEMCACHED_BACKEND);
return array();
}
/**
* Return an array of stored cache ids which match given tags
*
* In case of multiple tags, a logical AND is made between tags
*
* @param array $tags array of tags
* @return array array of matching cache ids (string)
*/
public function getIdsMatchingTags($tags = array())
{
$this->_log(self::TAGS_UNSUPPORTED_BY_SAVE_OF_MEMCACHED_BACKEND);
return array();
}
/**
* Return an array of stored cache ids which don't match given tags
*
* In case of multiple tags, a logical OR is made between tags
*
* @param array $tags array of tags
* @return array array of not matching cache ids (string)
*/
public function getIdsNotMatchingTags($tags = array())
{
$this->_log(self::TAGS_UNSUPPORTED_BY_SAVE_OF_MEMCACHED_BACKEND);
return array();
}
/**
* Return an array of stored cache ids which match any given tags
*
* In case of multiple tags, a logical AND is made between tags
*
* @param array $tags array of tags
* @return array array of any matching cache ids (string)
*/
public function getIdsMatchingAnyTags($tags = array())
{
$this->_log(self::TAGS_UNSUPPORTED_BY_SAVE_OF_MEMCACHED_BACKEND);
return array();
}
/**
* Return the filling percentage of the backend storage
*
* @throws Zend_Cache_Exception
* @return int integer between 0 and 100
*/
public function getFillingPercentage()
{
$mems = $this->_memcache->getExtendedStats();
$memSize = null;
$memUsed = null;
foreach ($mems as $key => $mem) {
if ($mem === false) {
$this->_log('can\'t get stat from ' . $key);
continue;
}
$eachSize = $mem['limit_maxbytes'];
$eachUsed = $mem['bytes'];
if ($eachUsed > $eachSize) {
$eachUsed = $eachSize;
}
$memSize += $eachSize;
$memUsed += $eachUsed;
}
if ($memSize === null || $memUsed === null) {
Zend_Cache::throwException('Can\'t get filling percentage');
}
return ((int) (100. * ($memUsed / $memSize)));
}
/**
* Return an array of metadatas for the given cache id
*
* The array must include these keys :
* - expire : the expire timestamp
* - tags : a string array of tags
* - mtime : timestamp of last modification time
*
* @param string $id cache id
* @return array array of metadatas (false if the cache id is not found)
*/
public function getMetadatas($id)
{
$tmp = $this->_memcache->get($id);
if (is_array($tmp)) {
$data = $tmp[0];
$mtime = $tmp[1];
if (!isset($tmp[2])) {
// because this record is only with 1.7 release
// if old cache records are still there...
return false;
}
$lifetime = $tmp[2];
return array(
'expire' => $mtime + $lifetime,
'tags' => array(),
'mtime' => $mtime
);
}
return false;
}
/**
* Give (if possible) an extra lifetime to the given cache id
*
* @param string $id cache id
* @param int $extraLifetime
* @return boolean true if ok
*/
public function touch($id, $extraLifetime)
{
if ($this->_options['compression']) {
$flag = MEMCACHE_COMPRESSED;
} else {
$flag = 0;
}
$tmp = $this->_memcache->get($id);
if (is_array($tmp)) {
$data = $tmp[0];
$mtime = $tmp[1];
if (!isset($tmp[2])) {
// because this record is only with 1.7 release
// if old cache records are still there...
return false;
}
$lifetime = $tmp[2];
$newLifetime = $lifetime - (time() - $mtime) + $extraLifetime;
if ($newLifetime <=0) {
return false;
}
// #ZF-5702 : we try replace() first becase set() seems to be slower
if (!($result = $this->_memcache->replace($id, array($data, time(), $newLifetime), $flag, $newLifetime))) {
$result = $this->_memcache->set($id, array($data, time(), $newLifetime), $flag, $newLifetime);
}
return $result;
}
return false;
}
/**
* Return an associative array of capabilities (booleans) of the backend
*
* The array must include these keys :
* - automatic_cleaning (is automating cleaning necessary)
* - tags (are tags supported)
* - expired_read (is it possible to read expired cache records
* (for doNotTestCacheValidity option for example))
* - priority does the backend deal with priority when saving
* - infinite_lifetime (is infinite lifetime can work with this backend)
* - get_list (is it possible to get the list of cache ids and the complete list of tags)
*
* @return array associative of with capabilities
*/
public function getCapabilities()
{
return array(
'automatic_cleaning' => false,
'tags' => false,
'expired_read' => false,
'priority' => false,
'infinite_lifetime' => false,
'get_list' => false
);
}
}

View File

@ -1,678 +0,0 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Cache
* @subpackage Zend_Cache_Backend
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Sqlite.php 24348 2011-08-04 17:51:24Z mabe $
*/
/**
* @see Zend_Cache_Backend_Interface
*/
require_once 'Zend/Cache/Backend/ExtendedInterface.php';
/**
* @see Zend_Cache_Backend
*/
require_once 'Zend/Cache/Backend.php';
/**
* @package Zend_Cache
* @subpackage Zend_Cache_Backend
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Cache_Backend_Sqlite extends Zend_Cache_Backend implements Zend_Cache_Backend_ExtendedInterface
{
/**
* Available options
*
* =====> (string) cache_db_complete_path :
* - the complete path (filename included) of the SQLITE database
*
* ====> (int) automatic_vacuum_factor :
* - Disable / Tune the automatic vacuum process
* - The automatic vacuum process defragment the database file (and make it smaller)
* when a clean() or delete() is called
* 0 => no automatic vacuum
* 1 => systematic vacuum (when delete() or clean() methods are called)
* x (integer) > 1 => automatic vacuum randomly 1 times on x clean() or delete()
*
* @var array Available options
*/
protected $_options = array(
'cache_db_complete_path' => null,
'automatic_vacuum_factor' => 10
);
/**
* DB ressource
*
* @var mixed $_db
*/
private $_db = null;
/**
* Boolean to store if the structure has benn checked or not
*
* @var boolean $_structureChecked
*/
private $_structureChecked = false;
/**
* Constructor
*
* @param array $options Associative array of options
* @throws Zend_cache_Exception
* @return void
*/
public function __construct(array $options = array())
{
parent::__construct($options);
if ($this->_options['cache_db_complete_path'] === null) {
Zend_Cache::throwException('cache_db_complete_path option has to set');
}
if (!extension_loaded('sqlite')) {
Zend_Cache::throwException("Cannot use SQLite storage because the 'sqlite' extension is not loaded in the current PHP environment");
}
$this->_getConnection();
}
/**
* Destructor
*
* @return void
*/
public function __destruct()
{
@sqlite_close($this->_getConnection());
}
/**
* Test if a cache is available for the given id and (if yes) return it (false else)
*
* @param string $id Cache id
* @param boolean $doNotTestCacheValidity If set to true, the cache validity won't be tested
* @return string|false Cached datas
*/
public function load($id, $doNotTestCacheValidity = false)
{
$this->_checkAndBuildStructure();
$sql = "SELECT content FROM cache WHERE id='$id'";
if (!$doNotTestCacheValidity) {
$sql = $sql . " AND (expire=0 OR expire>" . time() . ')';
}
$result = $this->_query($sql);
$row = @sqlite_fetch_array($result);
if ($row) {
return $row['content'];
}
return false;
}
/**
* Test if a cache is available or not (for the given id)
*
* @param string $id Cache id
* @return mixed|false (a cache is not available) or "last modified" timestamp (int) of the available cache record
*/
public function test($id)
{
$this->_checkAndBuildStructure();
$sql = "SELECT lastModified FROM cache WHERE id='$id' AND (expire=0 OR expire>" . time() . ')';
$result = $this->_query($sql);
$row = @sqlite_fetch_array($result);
if ($row) {
return ((int) $row['lastModified']);
}
return false;
}
/**
* Save some string datas into a cache record
*
* Note : $data is always "string" (serialization is done by the
* core not by the backend)
*
* @param string $data Datas to cache
* @param string $id Cache id
* @param array $tags Array of strings, the cache record will be tagged by each string entry
* @param int $specificLifetime If != false, set a specific lifetime for this cache record (null => infinite lifetime)
* @throws Zend_Cache_Exception
* @return boolean True if no problem
*/
public function save($data, $id, $tags = array(), $specificLifetime = false)
{
$this->_checkAndBuildStructure();
$lifetime = $this->getLifetime($specificLifetime);
$data = @sqlite_escape_string($data);
$mktime = time();
if ($lifetime === null) {
$expire = 0;
} else {
$expire = $mktime + $lifetime;
}
$this->_query("DELETE FROM cache WHERE id='$id'");
$sql = "INSERT INTO cache (id, content, lastModified, expire) VALUES ('$id', '$data', $mktime, $expire)";
$res = $this->_query($sql);
if (!$res) {
$this->_log("Zend_Cache_Backend_Sqlite::save() : impossible to store the cache id=$id");
return false;
}
$res = true;
foreach ($tags as $tag) {
$res = $this->_registerTag($id, $tag) && $res;
}
return $res;
}
/**
* Remove a cache record
*
* @param string $id Cache id
* @return boolean True if no problem
*/
public function remove($id)
{
$this->_checkAndBuildStructure();
$res = $this->_query("SELECT COUNT(*) AS nbr FROM cache WHERE id='$id'");
$result1 = @sqlite_fetch_single($res);
$result2 = $this->_query("DELETE FROM cache WHERE id='$id'");
$result3 = $this->_query("DELETE FROM tag WHERE id='$id'");
$this->_automaticVacuum();
return ($result1 && $result2 && $result3);
}
/**
* Clean some cache records
*
* Available modes are :
* Zend_Cache::CLEANING_MODE_ALL (default) => remove all cache entries ($tags is not used)
* Zend_Cache::CLEANING_MODE_OLD => remove too old cache entries ($tags is not used)
* Zend_Cache::CLEANING_MODE_MATCHING_TAG => remove cache entries matching all given tags
* ($tags can be an array of strings or a single string)
* Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG => remove cache entries not {matching one of the given tags}
* ($tags can be an array of strings or a single string)
* Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG => remove cache entries matching any given tags
* ($tags can be an array of strings or a single string)
*
* @param string $mode Clean mode
* @param array $tags Array of tags
* @return boolean True if no problem
*/
public function clean($mode = Zend_Cache::CLEANING_MODE_ALL, $tags = array())
{
$this->_checkAndBuildStructure();
$return = $this->_clean($mode, $tags);
$this->_automaticVacuum();
return $return;
}
/**
* Return an array of stored cache ids
*
* @return array array of stored cache ids (string)
*/
public function getIds()
{
$this->_checkAndBuildStructure();
$res = $this->_query("SELECT id FROM cache WHERE (expire=0 OR expire>" . time() . ")");
$result = array();
while ($id = @sqlite_fetch_single($res)) {
$result[] = $id;
}
return $result;
}
/**
* Return an array of stored tags
*
* @return array array of stored tags (string)
*/
public function getTags()
{
$this->_checkAndBuildStructure();
$res = $this->_query("SELECT DISTINCT(name) AS name FROM tag");
$result = array();
while ($id = @sqlite_fetch_single($res)) {
$result[] = $id;
}
return $result;
}
/**
* Return an array of stored cache ids which match given tags
*
* In case of multiple tags, a logical AND is made between tags
*
* @param array $tags array of tags
* @return array array of matching cache ids (string)
*/
public function getIdsMatchingTags($tags = array())
{
$first = true;
$ids = array();
foreach ($tags as $tag) {
$res = $this->_query("SELECT DISTINCT(id) AS id FROM tag WHERE name='$tag'");
if (!$res) {
return array();
}
$rows = @sqlite_fetch_all($res, SQLITE_ASSOC);
$ids2 = array();
foreach ($rows as $row) {
$ids2[] = $row['id'];
}
if ($first) {
$ids = $ids2;
$first = false;
} else {
$ids = array_intersect($ids, $ids2);
}
}
$result = array();
foreach ($ids as $id) {
$result[] = $id;
}
return $result;
}
/**
* Return an array of stored cache ids which don't match given tags
*
* In case of multiple tags, a logical OR is made between tags
*
* @param array $tags array of tags
* @return array array of not matching cache ids (string)
*/
public function getIdsNotMatchingTags($tags = array())
{
$res = $this->_query("SELECT id FROM cache");
$rows = @sqlite_fetch_all($res, SQLITE_ASSOC);
$result = array();
foreach ($rows as $row) {
$id = $row['id'];
$matching = false;
foreach ($tags as $tag) {
$res = $this->_query("SELECT COUNT(*) AS nbr FROM tag WHERE name='$tag' AND id='$id'");
if (!$res) {
return array();
}
$nbr = (int) @sqlite_fetch_single($res);
if ($nbr > 0) {
$matching = true;
}
}
if (!$matching) {
$result[] = $id;
}
}
return $result;
}
/**
* Return an array of stored cache ids which match any given tags
*
* In case of multiple tags, a logical AND is made between tags
*
* @param array $tags array of tags
* @return array array of any matching cache ids (string)
*/
public function getIdsMatchingAnyTags($tags = array())
{
$first = true;
$ids = array();
foreach ($tags as $tag) {
$res = $this->_query("SELECT DISTINCT(id) AS id FROM tag WHERE name='$tag'");
if (!$res) {
return array();
}
$rows = @sqlite_fetch_all($res, SQLITE_ASSOC);
$ids2 = array();
foreach ($rows as $row) {
$ids2[] = $row['id'];
}
if ($first) {
$ids = $ids2;
$first = false;
} else {
$ids = array_merge($ids, $ids2);
}
}
$result = array();
foreach ($ids as $id) {
$result[] = $id;
}
return $result;
}
/**
* Return the filling percentage of the backend storage
*
* @throws Zend_Cache_Exception
* @return int integer between 0 and 100
*/
public function getFillingPercentage()
{
$dir = dirname($this->_options['cache_db_complete_path']);
$free = disk_free_space($dir);
$total = disk_total_space($dir);
if ($total == 0) {
Zend_Cache::throwException('can\'t get disk_total_space');
} else {
if ($free >= $total) {
return 100;
}
return ((int) (100. * ($total - $free) / $total));
}
}
/**
* Return an array of metadatas for the given cache id
*
* The array must include these keys :
* - expire : the expire timestamp
* - tags : a string array of tags
* - mtime : timestamp of last modification time
*
* @param string $id cache id
* @return array array of metadatas (false if the cache id is not found)
*/
public function getMetadatas($id)
{
$tags = array();
$res = $this->_query("SELECT name FROM tag WHERE id='$id'");
if ($res) {
$rows = @sqlite_fetch_all($res, SQLITE_ASSOC);
foreach ($rows as $row) {
$tags[] = $row['name'];
}
}
$this->_query('CREATE TABLE cache (id TEXT PRIMARY KEY, content BLOB, lastModified INTEGER, expire INTEGER)');
$res = $this->_query("SELECT lastModified,expire FROM cache WHERE id='$id'");
if (!$res) {
return false;
}
$row = @sqlite_fetch_array($res, SQLITE_ASSOC);
return array(
'tags' => $tags,
'mtime' => $row['lastModified'],
'expire' => $row['expire']
);
}
/**
* Give (if possible) an extra lifetime to the given cache id
*
* @param string $id cache id
* @param int $extraLifetime
* @return boolean true if ok
*/
public function touch($id, $extraLifetime)
{
$sql = "SELECT expire FROM cache WHERE id='$id' AND (expire=0 OR expire>" . time() . ')';
$res = $this->_query($sql);
if (!$res) {
return false;
}
$expire = @sqlite_fetch_single($res);
$newExpire = $expire + $extraLifetime;
$res = $this->_query("UPDATE cache SET lastModified=" . time() . ", expire=$newExpire WHERE id='$id'");
if ($res) {
return true;
} else {
return false;
}
}
/**
* Return an associative array of capabilities (booleans) of the backend
*
* The array must include these keys :
* - automatic_cleaning (is automating cleaning necessary)
* - tags (are tags supported)
* - expired_read (is it possible to read expired cache records
* (for doNotTestCacheValidity option for example))
* - priority does the backend deal with priority when saving
* - infinite_lifetime (is infinite lifetime can work with this backend)
* - get_list (is it possible to get the list of cache ids and the complete list of tags)
*
* @return array associative of with capabilities
*/
public function getCapabilities()
{
return array(
'automatic_cleaning' => true,
'tags' => true,
'expired_read' => true,
'priority' => false,
'infinite_lifetime' => true,
'get_list' => true
);
}
/**
* PUBLIC METHOD FOR UNIT TESTING ONLY !
*
* Force a cache record to expire
*
* @param string $id Cache id
*/
public function ___expire($id)
{
$time = time() - 1;
$this->_query("UPDATE cache SET lastModified=$time, expire=$time WHERE id='$id'");
}
/**
* Return the connection resource
*
* If we are not connected, the connection is made
*
* @throws Zend_Cache_Exception
* @return resource Connection resource
*/
private function _getConnection()
{
if (is_resource($this->_db)) {
return $this->_db;
} else {
$this->_db = @sqlite_open($this->_options['cache_db_complete_path']);
if (!(is_resource($this->_db))) {
Zend_Cache::throwException("Impossible to open " . $this->_options['cache_db_complete_path'] . " cache DB file");
}
return $this->_db;
}
}
/**
* Execute an SQL query silently
*
* @param string $query SQL query
* @return mixed|false query results
*/
private function _query($query)
{
$db = $this->_getConnection();
if (is_resource($db)) {
$res = @sqlite_query($db, $query);
if ($res === false) {
return false;
} else {
return $res;
}
}
return false;
}
/**
* Deal with the automatic vacuum process
*
* @return void
*/
private function _automaticVacuum()
{
if ($this->_options['automatic_vacuum_factor'] > 0) {
$rand = rand(1, $this->_options['automatic_vacuum_factor']);
if ($rand == 1) {
$this->_query('VACUUM');
}
}
}
/**
* Register a cache id with the given tag
*
* @param string $id Cache id
* @param string $tag Tag
* @return boolean True if no problem
*/
private function _registerTag($id, $tag) {
$res = $this->_query("DELETE FROM TAG WHERE name='$tag' AND id='$id'");
$res = $this->_query("INSERT INTO tag (name, id) VALUES ('$tag', '$id')");
if (!$res) {
$this->_log("Zend_Cache_Backend_Sqlite::_registerTag() : impossible to register tag=$tag on id=$id");
return false;
}
return true;
}
/**
* Build the database structure
*
* @return false
*/
private function _buildStructure()
{
$this->_query('DROP INDEX tag_id_index');
$this->_query('DROP INDEX tag_name_index');
$this->_query('DROP INDEX cache_id_expire_index');
$this->_query('DROP TABLE version');
$this->_query('DROP TABLE cache');
$this->_query('DROP TABLE tag');
$this->_query('CREATE TABLE version (num INTEGER PRIMARY KEY)');
$this->_query('CREATE TABLE cache (id TEXT PRIMARY KEY, content BLOB, lastModified INTEGER, expire INTEGER)');
$this->_query('CREATE TABLE tag (name TEXT, id TEXT)');
$this->_query('CREATE INDEX tag_id_index ON tag(id)');
$this->_query('CREATE INDEX tag_name_index ON tag(name)');
$this->_query('CREATE INDEX cache_id_expire_index ON cache(id, expire)');
$this->_query('INSERT INTO version (num) VALUES (1)');
}
/**
* Check if the database structure is ok (with the good version)
*
* @return boolean True if ok
*/
private function _checkStructureVersion()
{
$result = $this->_query("SELECT num FROM version");
if (!$result) return false;
$row = @sqlite_fetch_array($result);
if (!$row) {
return false;
}
if (((int) $row['num']) != 1) {
// old cache structure
$this->_log('Zend_Cache_Backend_Sqlite::_checkStructureVersion() : old cache structure version detected => the cache is going to be dropped');
return false;
}
return true;
}
/**
* Clean some cache records
*
* Available modes are :
* Zend_Cache::CLEANING_MODE_ALL (default) => remove all cache entries ($tags is not used)
* Zend_Cache::CLEANING_MODE_OLD => remove too old cache entries ($tags is not used)
* Zend_Cache::CLEANING_MODE_MATCHING_TAG => remove cache entries matching all given tags
* ($tags can be an array of strings or a single string)
* Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG => remove cache entries not {matching one of the given tags}
* ($tags can be an array of strings or a single string)
* Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG => remove cache entries matching any given tags
* ($tags can be an array of strings or a single string)
*
* @param string $mode Clean mode
* @param array $tags Array of tags
* @return boolean True if no problem
*/
private function _clean($mode = Zend_Cache::CLEANING_MODE_ALL, $tags = array())
{
switch ($mode) {
case Zend_Cache::CLEANING_MODE_ALL:
$res1 = $this->_query('DELETE FROM cache');
$res2 = $this->_query('DELETE FROM tag');
return $res1 && $res2;
break;
case Zend_Cache::CLEANING_MODE_OLD:
$mktime = time();
$res1 = $this->_query("DELETE FROM tag WHERE id IN (SELECT id FROM cache WHERE expire>0 AND expire<=$mktime)");
$res2 = $this->_query("DELETE FROM cache WHERE expire>0 AND expire<=$mktime");
return $res1 && $res2;
break;
case Zend_Cache::CLEANING_MODE_MATCHING_TAG:
$ids = $this->getIdsMatchingTags($tags);
$result = true;
foreach ($ids as $id) {
$result = $this->remove($id) && $result;
}
return $result;
break;
case Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG:
$ids = $this->getIdsNotMatchingTags($tags);
$result = true;
foreach ($ids as $id) {
$result = $this->remove($id) && $result;
}
return $result;
break;
case Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG:
$ids = $this->getIdsMatchingAnyTags($tags);
$result = true;
foreach ($ids as $id) {
$result = $this->remove($id) && $result;
}
return $result;
break;
default:
break;
}
return false;
}
/**
* Check if the database structure is ok (with the good version), if no : build it
*
* @throws Zend_Cache_Exception
* @return boolean True if ok
*/
private function _checkAndBuildStructure()
{
if (!($this->_structureChecked)) {
if (!$this->_checkStructureVersion()) {
$this->_buildStructure();
if (!$this->_checkStructureVersion()) {
Zend_Cache::throwException("Impossible to build cache structure in " . $this->_options['cache_db_complete_path']);
}
}
$this->_structureChecked = true;
}
return true;
}
}

View File

@ -1,564 +0,0 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Cache
* @subpackage Zend_Cache_Backend
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Static.php 23775 2011-03-01 17:25:24Z ralph $
*/
/**
* @see Zend_Cache_Backend_Interface
*/
require_once 'Zend/Cache/Backend/Interface.php';
/**
* @see Zend_Cache_Backend
*/
require_once 'Zend/Cache/Backend.php';
/**
* @package Zend_Cache
* @subpackage Zend_Cache_Backend
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Cache_Backend_Static
extends Zend_Cache_Backend
implements Zend_Cache_Backend_Interface
{
const INNER_CACHE_NAME = 'zend_cache_backend_static_tagcache';
/**
* Static backend options
* @var array
*/
protected $_options = array(
'public_dir' => null,
'sub_dir' => 'html',
'file_extension' => '.html',
'index_filename' => 'index',
'file_locking' => true,
'cache_file_umask' => 0600,
'cache_directory_umask' => 0700,
'debug_header' => false,
'tag_cache' => null,
'disable_caching' => false
);
/**
* Cache for handling tags
* @var Zend_Cache_Core
*/
protected $_tagCache = null;
/**
* Tagged items
* @var array
*/
protected $_tagged = null;
/**
* Interceptor child method to handle the case where an Inner
* Cache object is being set since it's not supported by the
* standard backend interface
*
* @param string $name
* @param mixed $value
* @return Zend_Cache_Backend_Static
*/
public function setOption($name, $value)
{
if ($name == 'tag_cache') {
$this->setInnerCache($value);
} else {
parent::setOption($name, $value);
}
return $this;
}
/**
* Retrieve any option via interception of the parent's statically held
* options including the local option for a tag cache.
*
* @param string $name
* @return mixed
*/
public function getOption($name)
{
if ($name == 'tag_cache') {
return $this->getInnerCache();
} else {
if (in_array($name, $this->_options)) {
return $this->_options[$name];
}
if ($name == 'lifetime') {
return parent::getLifetime();
}
return null;
}
}
/**
* Test if a cache is available for the given id and (if yes) return it (false else)
*
* Note : return value is always "string" (unserialization is done by the core not by the backend)
*
* @param string $id Cache id
* @param boolean $doNotTestCacheValidity If set to true, the cache validity won't be tested
* @return string|false cached datas
*/
public function load($id, $doNotTestCacheValidity = false)
{
if (($id = (string)$id) === '') {
$id = $this->_detectId();
} else {
$id = $this->_decodeId($id);
}
if (!$this->_verifyPath($id)) {
Zend_Cache::throwException('Invalid cache id: does not match expected public_dir path');
}
if ($doNotTestCacheValidity) {
$this->_log("Zend_Cache_Backend_Static::load() : \$doNotTestCacheValidity=true is unsupported by the Static backend");
}
$fileName = basename($id);
if ($fileName === '') {
$fileName = $this->_options['index_filename'];
}
$pathName = $this->_options['public_dir'] . dirname($id);
$file = rtrim($pathName, '/') . '/' . $fileName . $this->_options['file_extension'];
if (file_exists($file)) {
$content = file_get_contents($file);
return $content;
}
return false;
}
/**
* Test if a cache is available or not (for the given id)
*
* @param string $id cache id
* @return bool
*/
public function test($id)
{
$id = $this->_decodeId($id);
if (!$this->_verifyPath($id)) {
Zend_Cache::throwException('Invalid cache id: does not match expected public_dir path');
}
$fileName = basename($id);
if ($fileName === '') {
$fileName = $this->_options['index_filename'];
}
if ($this->_tagged === null && $tagged = $this->getInnerCache()->load(self::INNER_CACHE_NAME)) {
$this->_tagged = $tagged;
} elseif (!$this->_tagged) {
return false;
}
$pathName = $this->_options['public_dir'] . dirname($id);
// Switch extension if needed
if (isset($this->_tagged[$id])) {
$extension = $this->_tagged[$id]['extension'];
} else {
$extension = $this->_options['file_extension'];
}
$file = $pathName . '/' . $fileName . $extension;
if (file_exists($file)) {
return true;
}
return false;
}
/**
* Save some string datas into a cache record
*
* Note : $data is always "string" (serialization is done by the
* core not by the backend)
*
* @param string $data Datas to cache
* @param string $id Cache id
* @param array $tags Array of strings, the cache record will be tagged by each string entry
* @param int $specificLifetime If != false, set a specific lifetime for this cache record (null => infinite lifetime)
* @return boolean true if no problem
*/
public function save($data, $id, $tags = array(), $specificLifetime = false)
{
if ($this->_options['disable_caching']) {
return true;
}
$extension = null;
if ($this->_isSerialized($data)) {
$data = unserialize($data);
$extension = '.' . ltrim($data[1], '.');
$data = $data[0];
}
clearstatcache();
if (($id = (string)$id) === '') {
$id = $this->_detectId();
} else {
$id = $this->_decodeId($id);
}
$fileName = basename($id);
if ($fileName === '') {
$fileName = $this->_options['index_filename'];
}
$pathName = realpath($this->_options['public_dir']) . dirname($id);
$this->_createDirectoriesFor($pathName);
if ($id === null || strlen($id) == 0) {
$dataUnserialized = unserialize($data);
$data = $dataUnserialized['data'];
}
$ext = $this->_options['file_extension'];
if ($extension) $ext = $extension;
$file = rtrim($pathName, '/') . '/' . $fileName . $ext;
if ($this->_options['file_locking']) {
$result = file_put_contents($file, $data, LOCK_EX);
} else {
$result = file_put_contents($file, $data);
}
@chmod($file, $this->_octdec($this->_options['cache_file_umask']));
if ($this->_tagged === null && $tagged = $this->getInnerCache()->load(self::INNER_CACHE_NAME)) {
$this->_tagged = $tagged;
} elseif ($this->_tagged === null) {
$this->_tagged = array();
}
if (!isset($this->_tagged[$id])) {
$this->_tagged[$id] = array();
}
if (!isset($this->_tagged[$id]['tags'])) {
$this->_tagged[$id]['tags'] = array();
}
$this->_tagged[$id]['tags'] = array_unique(array_merge($this->_tagged[$id]['tags'], $tags));
$this->_tagged[$id]['extension'] = $ext;
$this->getInnerCache()->save($this->_tagged, self::INNER_CACHE_NAME);
return (bool) $result;
}
/**
* Recursively create the directories needed to write the static file
*/
protected function _createDirectoriesFor($path)
{
if (!is_dir($path)) {
$oldUmask = umask(0);
if ( !@mkdir($path, $this->_octdec($this->_options['cache_directory_umask']), true)) {
$lastErr = error_get_last();
umask($oldUmask);
Zend_Cache::throwException("Can't create directory: {$lastErr['message']}");
}
umask($oldUmask);
}
}
/**
* Detect serialization of data (cannot predict since this is the only way
* to obey the interface yet pass in another parameter).
*
* In future, ZF 2.0, check if we can just avoid the interface restraints.
*
* This format is the only valid one possible for the class, so it's simple
* to just run a regular expression for the starting serialized format.
*/
protected function _isSerialized($data)
{
return preg_match("/a:2:\{i:0;s:\d+:\"/", $data);
}
/**
* Remove a cache record
*
* @param string $id Cache id
* @return boolean True if no problem
*/
public function remove($id)
{
if (!$this->_verifyPath($id)) {
Zend_Cache::throwException('Invalid cache id: does not match expected public_dir path');
}
$fileName = basename($id);
if ($this->_tagged === null && $tagged = $this->getInnerCache()->load(self::INNER_CACHE_NAME)) {
$this->_tagged = $tagged;
} elseif (!$this->_tagged) {
return false;
}
if (isset($this->_tagged[$id])) {
$extension = $this->_tagged[$id]['extension'];
} else {
$extension = $this->_options['file_extension'];
}
if ($fileName === '') {
$fileName = $this->_options['index_filename'];
}
$pathName = $this->_options['public_dir'] . dirname($id);
$file = realpath($pathName) . '/' . $fileName . $extension;
if (!file_exists($file)) {
return false;
}
return unlink($file);
}
/**
* Remove a cache record recursively for the given directory matching a
* REQUEST_URI based relative path (deletes the actual file matching this
* in addition to the matching directory)
*
* @param string $id Cache id
* @return boolean True if no problem
*/
public function removeRecursively($id)
{
if (!$this->_verifyPath($id)) {
Zend_Cache::throwException('Invalid cache id: does not match expected public_dir path');
}
$fileName = basename($id);
if ($fileName === '') {
$fileName = $this->_options['index_filename'];
}
$pathName = $this->_options['public_dir'] . dirname($id);
$file = $pathName . '/' . $fileName . $this->_options['file_extension'];
$directory = $pathName . '/' . $fileName;
if (file_exists($directory)) {
if (!is_writable($directory)) {
return false;
}
if (is_dir($directory)) {
foreach (new DirectoryIterator($directory) as $file) {
if (true === $file->isFile()) {
if (false === unlink($file->getPathName())) {
return false;
}
}
}
}
rmdir($directory);
}
if (file_exists($file)) {
if (!is_writable($file)) {
return false;
}
return unlink($file);
}
return true;
}
/**
* Clean some cache records
*
* Available modes are :
* Zend_Cache::CLEANING_MODE_ALL (default) => remove all cache entries ($tags is not used)
* Zend_Cache::CLEANING_MODE_OLD => remove too old cache entries ($tags is not used)
* Zend_Cache::CLEANING_MODE_MATCHING_TAG => remove cache entries matching all given tags
* ($tags can be an array of strings or a single string)
* Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG => remove cache entries not {matching one of the given tags}
* ($tags can be an array of strings or a single string)
* Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG => remove cache entries matching any given tags
* ($tags can be an array of strings or a single string)
*
* @param string $mode Clean mode
* @param array $tags Array of tags
* @return boolean true if no problem
*/
public function clean($mode = Zend_Cache::CLEANING_MODE_ALL, $tags = array())
{
$result = false;
switch ($mode) {
case Zend_Cache::CLEANING_MODE_MATCHING_TAG:
case Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG:
if (empty($tags)) {
throw new Zend_Exception('Cannot use tag matching modes as no tags were defined');
}
if ($this->_tagged === null && $tagged = $this->getInnerCache()->load(self::INNER_CACHE_NAME)) {
$this->_tagged = $tagged;
} elseif (!$this->_tagged) {
return true;
}
foreach ($tags as $tag) {
$urls = array_keys($this->_tagged);
foreach ($urls as $url) {
if (isset($this->_tagged[$url]['tags']) && in_array($tag, $this->_tagged[$url]['tags'])) {
$this->remove($url);
unset($this->_tagged[$url]);
}
}
}
$this->getInnerCache()->save($this->_tagged, self::INNER_CACHE_NAME);
$result = true;
break;
case Zend_Cache::CLEANING_MODE_ALL:
if ($this->_tagged === null) {
$tagged = $this->getInnerCache()->load(self::INNER_CACHE_NAME);
$this->_tagged = $tagged;
}
if ($this->_tagged === null || empty($this->_tagged)) {
return true;
}
$urls = array_keys($this->_tagged);
foreach ($urls as $url) {
$this->remove($url);
unset($this->_tagged[$url]);
}
$this->getInnerCache()->save($this->_tagged, self::INNER_CACHE_NAME);
$result = true;
break;
case Zend_Cache::CLEANING_MODE_OLD:
$this->_log("Zend_Cache_Backend_Static : Selected Cleaning Mode Currently Unsupported By This Backend");
break;
case Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG:
if (empty($tags)) {
throw new Zend_Exception('Cannot use tag matching modes as no tags were defined');
}
if ($this->_tagged === null) {
$tagged = $this->getInnerCache()->load(self::INNER_CACHE_NAME);
$this->_tagged = $tagged;
}
if ($this->_tagged === null || empty($this->_tagged)) {
return true;
}
$urls = array_keys($this->_tagged);
foreach ($urls as $url) {
$difference = array_diff($tags, $this->_tagged[$url]['tags']);
if (count($tags) == count($difference)) {
$this->remove($url);
unset($this->_tagged[$url]);
}
}
$this->getInnerCache()->save($this->_tagged, self::INNER_CACHE_NAME);
$result = true;
break;
default:
Zend_Cache::throwException('Invalid mode for clean() method');
break;
}
return $result;
}
/**
* Set an Inner Cache, used here primarily to store Tags associated
* with caches created by this backend. Note: If Tags are lost, the cache
* should be completely cleaned as the mapping of tags to caches will
* have been irrevocably lost.
*
* @param Zend_Cache_Core
* @return void
*/
public function setInnerCache(Zend_Cache_Core $cache)
{
$this->_tagCache = $cache;
$this->_options['tag_cache'] = $cache;
}
/**
* Get the Inner Cache if set
*
* @return Zend_Cache_Core
*/
public function getInnerCache()
{
if ($this->_tagCache === null) {
Zend_Cache::throwException('An Inner Cache has not been set; use setInnerCache()');
}
return $this->_tagCache;
}
/**
* Verify path exists and is non-empty
*
* @param string $path
* @return bool
*/
protected function _verifyPath($path)
{
$path = realpath($path);
$base = realpath($this->_options['public_dir']);
return strncmp($path, $base, strlen($base)) !== 0;
}
/**
* Determine the page to save from the request
*
* @return string
*/
protected function _detectId()
{
return $_SERVER['REQUEST_URI'];
}
/**
* Validate a cache id or a tag (security, reliable filenames, reserved prefixes...)
*
* Throw an exception if a problem is found
*
* @param string $string Cache id or tag
* @throws Zend_Cache_Exception
* @return void
* @deprecated Not usable until perhaps ZF 2.0
*/
protected static function _validateIdOrTag($string)
{
if (!is_string($string)) {
Zend_Cache::throwException('Invalid id or tag : must be a string');
}
// Internal only checked in Frontend - not here!
if (substr($string, 0, 9) == 'internal-') {
return;
}
// Validation assumes no query string, fragments or scheme included - only the path
if (!preg_match(
'/^(?:\/(?:(?:%[[:xdigit:]]{2}|[A-Za-z0-9-_.!~*\'()\[\]:@&=+$,;])*)?)+$/',
$string
)
) {
Zend_Cache::throwException("Invalid id or tag '$string' : must be a valid URL path");
}
}
/**
* Detect an octal string and return its octal value for file permission ops
* otherwise return the non-string (assumed octal or decimal int already)
*
* @param string $val The potential octal in need of conversion
* @return int
*/
protected function _octdec($val)
{
if (is_string($val) && decoct(octdec($val)) == $val) {
return octdec($val);
}
return $val;
}
/**
* Decode a request URI from the provided ID
*
* @param string $id
* @return string
*/
protected function _decodeId($id)
{
return pack('H*', $id);
}
}

View File

@ -1,413 +0,0 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Cache
* @subpackage Zend_Cache_Backend
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Test.php 23775 2011-03-01 17:25:24Z ralph $
*/
/**
* @see Zend_Cache_Backend_Interface
*/
require_once 'Zend/Cache/Backend/ExtendedInterface.php';
/**
* @see Zend_Cache_Backend
*/
require_once 'Zend/Cache/Backend.php';
/**
* @package Zend_Cache
* @subpackage Zend_Cache_Backend
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Cache_Backend_Test extends Zend_Cache_Backend implements Zend_Cache_Backend_ExtendedInterface
{
/**
* Available options
*
* @var array available options
*/
protected $_options = array();
/**
* Frontend or Core directives
*
* @var array directives
*/
protected $_directives = array();
/**
* Array to log actions
*
* @var array $_log
*/
private $_log = array();
/**
* Current index for log array
*
* @var int $_index
*/
private $_index = 0;
/**
* Constructor
*
* @param array $options associative array of options
* @return void
*/
public function __construct($options = array())
{
$this->_addLog('construct', array($options));
}
/**
* Set the frontend directives
*
* @param array $directives assoc of directives
* @return void
*/
public function setDirectives($directives)
{
$this->_addLog('setDirectives', array($directives));
}
/**
* Test if a cache is available for the given id and (if yes) return it (false else)
*
* For this test backend only, if $id == 'false', then the method will return false
* if $id == 'serialized', the method will return a serialized array
* ('foo' else)
*
* @param string $id Cache id
* @param boolean $doNotTestCacheValidity If set to true, the cache validity won't be tested
* @return string Cached datas (or false)
*/
public function load($id, $doNotTestCacheValidity = false)
{
$this->_addLog('get', array($id, $doNotTestCacheValidity));
if ( $id == 'false'
|| $id == 'd8523b3ee441006261eeffa5c3d3a0a7'
|| $id == 'e83249ea22178277d5befc2c5e2e9ace'
|| $id == '40f649b94977c0a6e76902e2a0b43587'
|| $id == '88161989b73a4cbfd0b701c446115a99'
|| $id == '205fc79cba24f0f0018eb92c7c8b3ba4'
|| $id == '170720e35f38150b811f68a937fb042d')
{
return false;
}
if ($id=='serialized') {
return serialize(array('foo'));
}
if ($id=='serialized2') {
return serialize(array('headers' => array(), 'data' => 'foo'));
}
if ( $id == '71769f39054f75894288e397df04e445' || $id == '615d222619fb20b527168340cebd0578'
|| $id == '8a02d218a5165c467e7a5747cc6bd4b6' || $id == '648aca1366211d17cbf48e65dc570bee'
|| $id == '4a923ef02d7f997ca14d56dfeae25ea7') {
return serialize(array('foo', 'bar'));
}
return 'foo';
}
/**
* Test if a cache is available or not (for the given id)
*
* For this test backend only, if $id == 'false', then the method will return false
* (123456 else)
*
* @param string $id Cache id
* @return mixed|false false (a cache is not available) or "last modified" timestamp (int) of the available cache record
*/
public function test($id)
{
$this->_addLog('test', array($id));
if ($id=='false') {
return false;
}
if (($id=='3c439c922209e2cb0b54d6deffccd75a')) {
return false;
}
return 123456;
}
/**
* Save some string datas into a cache record
*
* For this test backend only, if $id == 'false', then the method will return false
* (true else)
*
* @param string $data Datas to cache
* @param string $id Cache id
* @param array $tags Array of strings, the cache record will be tagged by each string entry
* @param int $specificLifetime If != false, set a specific lifetime for this cache record (null => infinite lifetime)
* @return boolean True if no problem
*/
public function save($data, $id, $tags = array(), $specificLifetime = false)
{
$this->_addLog('save', array($data, $id, $tags));
if (substr($id,-5)=='false') {
return false;
}
return true;
}
/**
* Remove a cache record
*
* For this test backend only, if $id == 'false', then the method will return false
* (true else)
*
* @param string $id Cache id
* @return boolean True if no problem
*/
public function remove($id)
{
$this->_addLog('remove', array($id));
if (substr($id,-5)=='false') {
return false;
}
return true;
}
/**
* Clean some cache records
*
* For this test backend only, if $mode == 'false', then the method will return false
* (true else)
*
* Available modes are :
* Zend_Cache::CLEANING_MODE_ALL (default) => remove all cache entries ($tags is not used)
* Zend_Cache::CLEANING_MODE_OLD => remove too old cache entries ($tags is not used)
* Zend_Cache::CLEANING_MODE_MATCHING_TAG => remove cache entries matching all given tags
* ($tags can be an array of strings or a single string)
* Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG => remove cache entries not {matching one of the given tags}
* ($tags can be an array of strings or a single string)
*
* @param string $mode Clean mode
* @param array $tags Array of tags
* @return boolean True if no problem
*/
public function clean($mode = Zend_Cache::CLEANING_MODE_ALL, $tags = array())
{
$this->_addLog('clean', array($mode, $tags));
if ($mode=='false') {
return false;
}
return true;
}
/**
* Get the last log
*
* @return string The last log
*/
public function getLastLog()
{
return $this->_log[$this->_index - 1];
}
/**
* Get the log index
*
* @return int Log index
*/
public function getLogIndex()
{
return $this->_index;
}
/**
* Get the complete log array
*
* @return array Complete log array
*/
public function getAllLogs()
{
return $this->_log;
}
/**
* Return true if the automatic cleaning is available for the backend
*
* @return boolean
*/
public function isAutomaticCleaningAvailable()
{
return true;
}
/**
* Return an array of stored cache ids
*
* @return array array of stored cache ids (string)
*/
public function getIds()
{
return array(
'prefix_id1', 'prefix_id2'
);
}
/**
* Return an array of stored tags
*
* @return array array of stored tags (string)
*/
public function getTags()
{
return array(
'tag1', 'tag2'
);
}
/**
* Return an array of stored cache ids which match given tags
*
* In case of multiple tags, a logical AND is made between tags
*
* @param array $tags array of tags
* @return array array of matching cache ids (string)
*/
public function getIdsMatchingTags($tags = array())
{
if ($tags == array('tag1', 'tag2')) {
return array('prefix_id1', 'prefix_id2');
}
return array();
}
/**
* Return an array of stored cache ids which don't match given tags
*
* In case of multiple tags, a logical OR is made between tags
*
* @param array $tags array of tags
* @return array array of not matching cache ids (string)
*/
public function getIdsNotMatchingTags($tags = array())
{
if ($tags == array('tag3', 'tag4')) {
return array('prefix_id3', 'prefix_id4');
}
return array();
}
/**
* Return an array of stored cache ids which match any given tags
*
* In case of multiple tags, a logical AND is made between tags
*
* @param array $tags array of tags
* @return array array of any matching cache ids (string)
*/
public function getIdsMatchingAnyTags($tags = array())
{
if ($tags == array('tag5', 'tag6')) {
return array('prefix_id5', 'prefix_id6');
}
return array();
}
/**
* Return the filling percentage of the backend storage
*
* @return int integer between 0 and 100
*/
public function getFillingPercentage()
{
return 50;
}
/**
* Return an array of metadatas for the given cache id
*
* The array must include these keys :
* - expire : the expire timestamp
* - tags : a string array of tags
* - mtime : timestamp of last modification time
*
* @param string $id cache id
* @return array array of metadatas (false if the cache id is not found)
*/
public function getMetadatas($id)
{
return false;
}
/**
* Give (if possible) an extra lifetime to the given cache id
*
* @param string $id cache id
* @param int $extraLifetime
* @return boolean true if ok
*/
public function touch($id, $extraLifetime)
{
return true;
}
/**
* Return an associative array of capabilities (booleans) of the backend
*
* The array must include these keys :
* - automatic_cleaning (is automating cleaning necessary)
* - tags (are tags supported)
* - expired_read (is it possible to read expired cache records
* (for doNotTestCacheValidity option for example))
* - priority does the backend deal with priority when saving
* - infinite_lifetime (is infinite lifetime can work with this backend)
* - get_list (is it possible to get the list of cache ids and the complete list of tags)
*
* @return array associative of with capabilities
*/
public function getCapabilities()
{
return array(
'automatic_cleaning' => true,
'tags' => true,
'expired_read' => false,
'priority' => true,
'infinite_lifetime' => true,
'get_list' => true
);
}
/**
* Add an event to the log array
*
* @param string $methodName MethodName
* @param array $args Arguments
* @return void
*/
private function _addLog($methodName, $args)
{
$this->_log[$this->_index] = array(
'methodName' => $methodName,
'args' => $args
);
$this->_index = $this->_index + 1;
}
}

View File

@ -1,536 +0,0 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Cache
* @subpackage Zend_Cache_Backend
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: TwoLevels.php 24254 2011-07-22 12:04:41Z mabe $
*/
/**
* @see Zend_Cache_Backend_ExtendedInterface
*/
require_once 'Zend/Cache/Backend/ExtendedInterface.php';
/**
* @see Zend_Cache_Backend
*/
require_once 'Zend/Cache/Backend.php';
/**
* @package Zend_Cache
* @subpackage Zend_Cache_Backend
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Cache_Backend_TwoLevels extends Zend_Cache_Backend implements Zend_Cache_Backend_ExtendedInterface
{
/**
* Available options
*
* =====> (string) slow_backend :
* - Slow backend name
* - Must implement the Zend_Cache_Backend_ExtendedInterface
* - Should provide a big storage
*
* =====> (string) fast_backend :
* - Flow backend name
* - Must implement the Zend_Cache_Backend_ExtendedInterface
* - Must be much faster than slow_backend
*
* =====> (array) slow_backend_options :
* - Slow backend options (see corresponding backend)
*
* =====> (array) fast_backend_options :
* - Fast backend options (see corresponding backend)
*
* =====> (int) stats_update_factor :
* - Disable / Tune the computation of the fast backend filling percentage
* - When saving a record into cache :
* 1 => systematic computation of the fast backend filling percentage
* x (integer) > 1 => computation of the fast backend filling percentage randomly 1 times on x cache write
*
* =====> (boolean) slow_backend_custom_naming :
* =====> (boolean) fast_backend_custom_naming :
* =====> (boolean) slow_backend_autoload :
* =====> (boolean) fast_backend_autoload :
* - See Zend_Cache::factory() method
*
* =====> (boolean) auto_refresh_fast_cache
* - If true, auto refresh the fast cache when a cache record is hit
*
* @var array available options
*/
protected $_options = array(
'slow_backend' => 'File',
'fast_backend' => 'Apc',
'slow_backend_options' => array(),
'fast_backend_options' => array(),
'stats_update_factor' => 10,
'slow_backend_custom_naming' => false,
'fast_backend_custom_naming' => false,
'slow_backend_autoload' => false,
'fast_backend_autoload' => false,
'auto_refresh_fast_cache' => true
);
/**
* Slow Backend
*
* @var Zend_Cache_Backend_ExtendedInterface
*/
protected $_slowBackend;
/**
* Fast Backend
*
* @var Zend_Cache_Backend_ExtendedInterface
*/
protected $_fastBackend;
/**
* Cache for the fast backend filling percentage
*
* @var int
*/
protected $_fastBackendFillingPercentage = null;
/**
* Constructor
*
* @param array $options Associative array of options
* @throws Zend_Cache_Exception
* @return void
*/
public function __construct(array $options = array())
{
parent::__construct($options);
if ($this->_options['slow_backend'] === null) {
Zend_Cache::throwException('slow_backend option has to set');
} elseif ($this->_options['slow_backend'] instanceof Zend_Cache_Backend_ExtendedInterface) {
$this->_slowBackend = $this->_options['slow_backend'];
} else {
$this->_slowBackend = Zend_Cache::_makeBackend(
$this->_options['slow_backend'],
$this->_options['slow_backend_options'],
$this->_options['slow_backend_custom_naming'],
$this->_options['slow_backend_autoload']
);
if (!in_array('Zend_Cache_Backend_ExtendedInterface', class_implements($this->_slowBackend))) {
Zend_Cache::throwException('slow_backend must implement the Zend_Cache_Backend_ExtendedInterface interface');
}
}
if ($this->_options['fast_backend'] === null) {
Zend_Cache::throwException('fast_backend option has to set');
} elseif ($this->_options['fast_backend'] instanceof Zend_Cache_Backend_ExtendedInterface) {
$this->_fastBackend = $this->_options['fast_backend'];
} else {
$this->_fastBackend = Zend_Cache::_makeBackend(
$this->_options['fast_backend'],
$this->_options['fast_backend_options'],
$this->_options['fast_backend_custom_naming'],
$this->_options['fast_backend_autoload']
);
if (!in_array('Zend_Cache_Backend_ExtendedInterface', class_implements($this->_fastBackend))) {
Zend_Cache::throwException('fast_backend must implement the Zend_Cache_Backend_ExtendedInterface interface');
}
}
$this->_slowBackend->setDirectives($this->_directives);
$this->_fastBackend->setDirectives($this->_directives);
}
/**
* Test if a cache is available or not (for the given id)
*
* @param string $id cache id
* @return mixed|false (a cache is not available) or "last modified" timestamp (int) of the available cache record
*/
public function test($id)
{
$fastTest = $this->_fastBackend->test($id);
if ($fastTest) {
return $fastTest;
} else {
return $this->_slowBackend->test($id);
}
}
/**
* Save some string datas into a cache record
*
* Note : $data is always "string" (serialization is done by the
* core not by the backend)
*
* @param string $data Datas to cache
* @param string $id Cache id
* @param array $tags Array of strings, the cache record will be tagged by each string entry
* @param int $specificLifetime If != false, set a specific lifetime for this cache record (null => infinite lifetime)
* @param int $priority integer between 0 (very low priority) and 10 (maximum priority) used by some particular backends
* @return boolean true if no problem
*/
public function save($data, $id, $tags = array(), $specificLifetime = false, $priority = 8)
{
$usage = $this->_getFastFillingPercentage('saving');
$boolFast = true;
$lifetime = $this->getLifetime($specificLifetime);
$preparedData = $this->_prepareData($data, $lifetime, $priority);
if (($priority > 0) && (10 * $priority >= $usage)) {
$fastLifetime = $this->_getFastLifetime($lifetime, $priority);
$boolFast = $this->_fastBackend->save($preparedData, $id, array(), $fastLifetime);
$boolSlow = $this->_slowBackend->save($preparedData, $id, $tags, $lifetime);
} else {
$boolSlow = $this->_slowBackend->save($preparedData, $id, $tags, $lifetime);
if ($boolSlow === true) {
$boolFast = $this->_fastBackend->remove($id);
if (!$boolFast && !$this->_fastBackend->test($id)) {
// some backends return false on remove() even if the key never existed. (and it won't if fast is full)
// all we care about is that the key doesn't exist now
$boolFast = true;
}
}
}
return ($boolFast && $boolSlow);
}
/**
* Test if a cache is available for the given id and (if yes) return it (false else)
*
* Note : return value is always "string" (unserialization is done by the core not by the backend)
*
* @param string $id Cache id
* @param boolean $doNotTestCacheValidity If set to true, the cache validity won't be tested
* @return string|false cached datas
*/
public function load($id, $doNotTestCacheValidity = false)
{
$res = $this->_fastBackend->load($id, $doNotTestCacheValidity);
if ($res === false) {
$res = $this->_slowBackend->load($id, $doNotTestCacheValidity);
if ($res === false) {
// there is no cache at all for this id
return false;
}
}
$array = unserialize($res);
// maybe, we have to refresh the fast cache ?
if ($this->_options['auto_refresh_fast_cache']) {
if ($array['priority'] == 10) {
// no need to refresh the fast cache with priority = 10
return $array['data'];
}
$newFastLifetime = $this->_getFastLifetime($array['lifetime'], $array['priority'], time() - $array['expire']);
// we have the time to refresh the fast cache
$usage = $this->_getFastFillingPercentage('loading');
if (($array['priority'] > 0) && (10 * $array['priority'] >= $usage)) {
// we can refresh the fast cache
$preparedData = $this->_prepareData($array['data'], $array['lifetime'], $array['priority']);
$this->_fastBackend->save($preparedData, $id, array(), $newFastLifetime);
}
}
return $array['data'];
}
/**
* Remove a cache record
*
* @param string $id Cache id
* @return boolean True if no problem
*/
public function remove($id)
{
$boolFast = $this->_fastBackend->remove($id);
$boolSlow = $this->_slowBackend->remove($id);
return $boolFast && $boolSlow;
}
/**
* Clean some cache records
*
* Available modes are :
* Zend_Cache::CLEANING_MODE_ALL (default) => remove all cache entries ($tags is not used)
* Zend_Cache::CLEANING_MODE_OLD => remove too old cache entries ($tags is not used)
* Zend_Cache::CLEANING_MODE_MATCHING_TAG => remove cache entries matching all given tags
* ($tags can be an array of strings or a single string)
* Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG => remove cache entries not {matching one of the given tags}
* ($tags can be an array of strings or a single string)
* Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG => remove cache entries matching any given tags
* ($tags can be an array of strings or a single string)
*
* @param string $mode Clean mode
* @param array $tags Array of tags
* @throws Zend_Cache_Exception
* @return boolean true if no problem
*/
public function clean($mode = Zend_Cache::CLEANING_MODE_ALL, $tags = array())
{
switch($mode) {
case Zend_Cache::CLEANING_MODE_ALL:
$boolFast = $this->_fastBackend->clean(Zend_Cache::CLEANING_MODE_ALL);
$boolSlow = $this->_slowBackend->clean(Zend_Cache::CLEANING_MODE_ALL);
return $boolFast && $boolSlow;
break;
case Zend_Cache::CLEANING_MODE_OLD:
return $this->_slowBackend->clean(Zend_Cache::CLEANING_MODE_OLD);
case Zend_Cache::CLEANING_MODE_MATCHING_TAG:
$ids = $this->_slowBackend->getIdsMatchingTags($tags);
$res = true;
foreach ($ids as $id) {
$bool = $this->remove($id);
$res = $res && $bool;
}
return $res;
break;
case Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG:
$ids = $this->_slowBackend->getIdsNotMatchingTags($tags);
$res = true;
foreach ($ids as $id) {
$bool = $this->remove($id);
$res = $res && $bool;
}
return $res;
break;
case Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG:
$ids = $this->_slowBackend->getIdsMatchingAnyTags($tags);
$res = true;
foreach ($ids as $id) {
$bool = $this->remove($id);
$res = $res && $bool;
}
return $res;
break;
default:
Zend_Cache::throwException('Invalid mode for clean() method');
break;
}
}
/**
* Return an array of stored cache ids
*
* @return array array of stored cache ids (string)
*/
public function getIds()
{
return $this->_slowBackend->getIds();
}
/**
* Return an array of stored tags
*
* @return array array of stored tags (string)
*/
public function getTags()
{
return $this->_slowBackend->getTags();
}
/**
* Return an array of stored cache ids which match given tags
*
* In case of multiple tags, a logical AND is made between tags
*
* @param array $tags array of tags
* @return array array of matching cache ids (string)
*/
public function getIdsMatchingTags($tags = array())
{
return $this->_slowBackend->getIdsMatchingTags($tags);
}
/**
* Return an array of stored cache ids which don't match given tags
*
* In case of multiple tags, a logical OR is made between tags
*
* @param array $tags array of tags
* @return array array of not matching cache ids (string)
*/
public function getIdsNotMatchingTags($tags = array())
{
return $this->_slowBackend->getIdsNotMatchingTags($tags);
}
/**
* Return an array of stored cache ids which match any given tags
*
* In case of multiple tags, a logical AND is made between tags
*
* @param array $tags array of tags
* @return array array of any matching cache ids (string)
*/
public function getIdsMatchingAnyTags($tags = array())
{
return $this->_slowBackend->getIdsMatchingAnyTags($tags);
}
/**
* Return the filling percentage of the backend storage
*
* @return int integer between 0 and 100
*/
public function getFillingPercentage()
{
return $this->_slowBackend->getFillingPercentage();
}
/**
* Return an array of metadatas for the given cache id
*
* The array must include these keys :
* - expire : the expire timestamp
* - tags : a string array of tags
* - mtime : timestamp of last modification time
*
* @param string $id cache id
* @return array array of metadatas (false if the cache id is not found)
*/
public function getMetadatas($id)
{
return $this->_slowBackend->getMetadatas($id);
}
/**
* Give (if possible) an extra lifetime to the given cache id
*
* @param string $id cache id
* @param int $extraLifetime
* @return boolean true if ok
*/
public function touch($id, $extraLifetime)
{
return $this->_slowBackend->touch($id, $extraLifetime);
}
/**
* Return an associative array of capabilities (booleans) of the backend
*
* The array must include these keys :
* - automatic_cleaning (is automating cleaning necessary)
* - tags (are tags supported)
* - expired_read (is it possible to read expired cache records
* (for doNotTestCacheValidity option for example))
* - priority does the backend deal with priority when saving
* - infinite_lifetime (is infinite lifetime can work with this backend)
* - get_list (is it possible to get the list of cache ids and the complete list of tags)
*
* @return array associative of with capabilities
*/
public function getCapabilities()
{
$slowBackendCapabilities = $this->_slowBackend->getCapabilities();
return array(
'automatic_cleaning' => $slowBackendCapabilities['automatic_cleaning'],
'tags' => $slowBackendCapabilities['tags'],
'expired_read' => $slowBackendCapabilities['expired_read'],
'priority' => $slowBackendCapabilities['priority'],
'infinite_lifetime' => $slowBackendCapabilities['infinite_lifetime'],
'get_list' => $slowBackendCapabilities['get_list']
);
}
/**
* Prepare a serialized array to store datas and metadatas informations
*
* @param string $data data to store
* @param int $lifetime original lifetime
* @param int $priority priority
* @return string serialize array to store into cache
*/
private function _prepareData($data, $lifetime, $priority)
{
$lt = $lifetime;
if ($lt === null) {
$lt = 9999999999;
}
return serialize(array(
'data' => $data,
'lifetime' => $lifetime,
'expire' => time() + $lt,
'priority' => $priority
));
}
/**
* Compute and return the lifetime for the fast backend
*
* @param int $lifetime original lifetime
* @param int $priority priority
* @param int $maxLifetime maximum lifetime
* @return int lifetime for the fast backend
*/
private function _getFastLifetime($lifetime, $priority, $maxLifetime = null)
{
if ($lifetime <= 0) {
// if no lifetime, we have an infinite lifetime
// we need to use arbitrary lifetimes
$fastLifetime = (int) (2592000 / (11 - $priority));
} else {
// prevent computed infinite lifetime (0) by ceil
$fastLifetime = (int) ceil($lifetime / (11 - $priority));
}
if ($maxLifetime >= 0 && $fastLifetime > $maxLifetime) {
return $maxLifetime;
}
return $fastLifetime;
}
/**
* PUBLIC METHOD FOR UNIT TESTING ONLY !
*
* Force a cache record to expire
*
* @param string $id cache id
*/
public function ___expire($id)
{
$this->_fastBackend->remove($id);
$this->_slowBackend->___expire($id);
}
private function _getFastFillingPercentage($mode)
{
if ($mode == 'saving') {
// mode saving
if ($this->_fastBackendFillingPercentage === null) {
$this->_fastBackendFillingPercentage = $this->_fastBackend->getFillingPercentage();
} else {
$rand = rand(1, $this->_options['stats_update_factor']);
if ($rand == 1) {
// we force a refresh
$this->_fastBackendFillingPercentage = $this->_fastBackend->getFillingPercentage();
}
}
} else {
// mode loading
// we compute the percentage only if it's not available in cache
if ($this->_fastBackendFillingPercentage === null) {
$this->_fastBackendFillingPercentage = $this->_fastBackend->getFillingPercentage();
}
}
return $this->_fastBackendFillingPercentage;
}
}

View File

@ -1,349 +0,0 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Cache
* @subpackage Zend_Cache_Backend
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id$
*/
/**
* @see Zend_Cache_Backend_Interface
*/
require_once 'Zend/Cache/Backend/ExtendedInterface.php';
/**
* @see Zend_Cache_Backend
*/
require_once 'Zend/Cache/Backend.php';
/**
* @package Zend_Cache
* @subpackage Zend_Cache_Backend
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Cache_Backend_WinCache extends Zend_Cache_Backend implements Zend_Cache_Backend_ExtendedInterface
{
/**
* Log message
*/
const TAGS_UNSUPPORTED_BY_CLEAN_OF_WINCACHE_BACKEND = 'Zend_Cache_Backend_WinCache::clean() : tags are unsupported by the WinCache backend';
const TAGS_UNSUPPORTED_BY_SAVE_OF_WINCACHE_BACKEND = 'Zend_Cache_Backend_WinCache::save() : tags are unsupported by the WinCache backend';
/**
* Constructor
*
* @param array $options associative array of options
* @throws Zend_Cache_Exception
* @return void
*/
public function __construct(array $options = array())
{
if (!extension_loaded('wincache')) {
Zend_Cache::throwException('The wincache extension must be loaded for using this backend !');
}
parent::__construct($options);
}
/**
* Test if a cache is available for the given id and (if yes) return it (false else)
*
* WARNING $doNotTestCacheValidity=true is unsupported by the WinCache backend
*
* @param string $id cache id
* @param boolean $doNotTestCacheValidity if set to true, the cache validity won't be tested
* @return string cached datas (or false)
*/
public function load($id, $doNotTestCacheValidity = false)
{
$tmp = wincache_ucache_get($id);
if (is_array($tmp)) {
return $tmp[0];
}
return false;
}
/**
* Test if a cache is available or not (for the given id)
*
* @param string $id cache id
* @return mixed false (a cache is not available) or "last modified" timestamp (int) of the available cache record
*/
public function test($id)
{
$tmp = wincache_ucache_get($id);
if (is_array($tmp)) {
return $tmp[1];
}
return false;
}
/**
* Save some string datas into a cache record
*
* Note : $data is always "string" (serialization is done by the
* core not by the backend)
*
* @param string $data datas to cache
* @param string $id cache id
* @param array $tags array of strings, the cache record will be tagged by each string entry
* @param int $specificLifetime if != false, set a specific lifetime for this cache record (null => infinite lifetime)
* @return boolean true if no problem
*/
public function save($data, $id, $tags = array(), $specificLifetime = false)
{
$lifetime = $this->getLifetime($specificLifetime);
$result = wincache_ucache_set($id, array($data, time(), $lifetime), $lifetime);
if (count($tags) > 0) {
$this->_log(self::TAGS_UNSUPPORTED_BY_SAVE_OF_WINCACHE_BACKEND);
}
return $result;
}
/**
* Remove a cache record
*
* @param string $id cache id
* @return boolean true if no problem
*/
public function remove($id)
{
return wincache_ucache_delete($id);
}
/**
* Clean some cache records
*
* Available modes are :
* 'all' (default) => remove all cache entries ($tags is not used)
* 'old' => unsupported
* 'matchingTag' => unsupported
* 'notMatchingTag' => unsupported
* 'matchingAnyTag' => unsupported
*
* @param string $mode clean mode
* @param array $tags array of tags
* @throws Zend_Cache_Exception
* @return boolean true if no problem
*/
public function clean($mode = Zend_Cache::CLEANING_MODE_ALL, $tags = array())
{
switch ($mode) {
case Zend_Cache::CLEANING_MODE_ALL:
return wincache_ucache_clear();
break;
case Zend_Cache::CLEANING_MODE_OLD:
$this->_log("Zend_Cache_Backend_WinCache::clean() : CLEANING_MODE_OLD is unsupported by the WinCache backend");
break;
case Zend_Cache::CLEANING_MODE_MATCHING_TAG:
case Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG:
case Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG:
$this->_log(self::TAGS_UNSUPPORTED_BY_CLEAN_OF_WINCACHE_BACKEND);
break;
default:
Zend_Cache::throwException('Invalid mode for clean() method');
break;
}
}
/**
* Return true if the automatic cleaning is available for the backend
*
* DEPRECATED : use getCapabilities() instead
*
* @deprecated
* @return boolean
*/
public function isAutomaticCleaningAvailable()
{
return false;
}
/**
* Return the filling percentage of the backend storage
*
* @throws Zend_Cache_Exception
* @return int integer between 0 and 100
*/
public function getFillingPercentage()
{
$mem = wincache_ucache_meminfo();
$memSize = $mem['memory_total'];
$memUsed = $mem['memory_free'];
if ($memSize == 0) {
Zend_Cache::throwException('can\'t get WinCache memory size');
}
if ($memUsed > $memSize) {
return 100;
}
return ((int) (100. * ($memUsed / $memSize)));
}
/**
* Return an array of stored tags
*
* @return array array of stored tags (string)
*/
public function getTags()
{
$this->_log(self::TAGS_UNSUPPORTED_BY_SAVE_OF_WINCACHE_BACKEND);
return array();
}
/**
* Return an array of stored cache ids which match given tags
*
* In case of multiple tags, a logical AND is made between tags
*
* @param array $tags array of tags
* @return array array of matching cache ids (string)
*/
public function getIdsMatchingTags($tags = array())
{
$this->_log(self::TAGS_UNSUPPORTED_BY_SAVE_OF_WINCACHE_BACKEND);
return array();
}
/**
* Return an array of stored cache ids which don't match given tags
*
* In case of multiple tags, a logical OR is made between tags
*
* @param array $tags array of tags
* @return array array of not matching cache ids (string)
*/
public function getIdsNotMatchingTags($tags = array())
{
$this->_log(self::TAGS_UNSUPPORTED_BY_SAVE_OF_WINCACHE_BACKEND);
return array();
}
/**
* Return an array of stored cache ids which match any given tags
*
* In case of multiple tags, a logical AND is made between tags
*
* @param array $tags array of tags
* @return array array of any matching cache ids (string)
*/
public function getIdsMatchingAnyTags($tags = array())
{
$this->_log(self::TAGS_UNSUPPORTED_BY_SAVE_OF_WINCACHE_BACKEND);
return array();
}
/**
* Return an array of stored cache ids
*
* @return array array of stored cache ids (string)
*/
public function getIds()
{
$res = array();
$array = wincache_ucache_info();
$records = $array['ucache_entries'];
foreach ($records as $record) {
$res[] = $record['key_name'];
}
return $res;
}
/**
* Return an array of metadatas for the given cache id
*
* The array must include these keys :
* - expire : the expire timestamp
* - tags : a string array of tags
* - mtime : timestamp of last modification time
*
* @param string $id cache id
* @return array array of metadatas (false if the cache id is not found)
*/
public function getMetadatas($id)
{
$tmp = wincache_ucache_get($id);
if (is_array($tmp)) {
$data = $tmp[0];
$mtime = $tmp[1];
if (!isset($tmp[2])) {
return false;
}
$lifetime = $tmp[2];
return array(
'expire' => $mtime + $lifetime,
'tags' => array(),
'mtime' => $mtime
);
}
return false;
}
/**
* Give (if possible) an extra lifetime to the given cache id
*
* @param string $id cache id
* @param int $extraLifetime
* @return boolean true if ok
*/
public function touch($id, $extraLifetime)
{
$tmp = wincache_ucache_get($id);
if (is_array($tmp)) {
$data = $tmp[0];
$mtime = $tmp[1];
if (!isset($tmp[2])) {
return false;
}
$lifetime = $tmp[2];
$newLifetime = $lifetime - (time() - $mtime) + $extraLifetime;
if ($newLifetime <=0) {
return false;
}
return wincache_ucache_set($id, array($data, time(), $newLifetime), $newLifetime);
}
return false;
}
/**
* Return an associative array of capabilities (booleans) of the backend
*
* The array must include these keys :
* - automatic_cleaning (is automating cleaning necessary)
* - tags (are tags supported)
* - expired_read (is it possible to read expired cache records
* (for doNotTestCacheValidity option for example))
* - priority does the backend deal with priority when saving
* - infinite_lifetime (is infinite lifetime can work with this backend)
* - get_list (is it possible to get the list of cache ids and the complete list of tags)
*
* @return array associative of with capabilities
*/
public function getCapabilities()
{
return array(
'automatic_cleaning' => false,
'tags' => false,
'expired_read' => false,
'priority' => false,
'infinite_lifetime' => false,
'get_list' => true
);
}
}

View File

@ -1,221 +0,0 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Cache
* @subpackage Zend_Cache_Backend
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Xcache.php 23775 2011-03-01 17:25:24Z ralph $
*/
/**
* @see Zend_Cache_Backend_Interface
*/
require_once 'Zend/Cache/Backend/Interface.php';
/**
* @see Zend_Cache_Backend
*/
require_once 'Zend/Cache/Backend.php';
/**
* @package Zend_Cache
* @subpackage Zend_Cache_Backend
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Cache_Backend_Xcache extends Zend_Cache_Backend implements Zend_Cache_Backend_Interface
{
/**
* Log message
*/
const TAGS_UNSUPPORTED_BY_CLEAN_OF_XCACHE_BACKEND = 'Zend_Cache_Backend_Xcache::clean() : tags are unsupported by the Xcache backend';
const TAGS_UNSUPPORTED_BY_SAVE_OF_XCACHE_BACKEND = 'Zend_Cache_Backend_Xcache::save() : tags are unsupported by the Xcache backend';
/**
* Available options
*
* =====> (string) user :
* xcache.admin.user (necessary for the clean() method)
*
* =====> (string) password :
* xcache.admin.pass (clear, not MD5) (necessary for the clean() method)
*
* @var array available options
*/
protected $_options = array(
'user' => null,
'password' => null
);
/**
* Constructor
*
* @param array $options associative array of options
* @throws Zend_Cache_Exception
* @return void
*/
public function __construct(array $options = array())
{
if (!extension_loaded('xcache')) {
Zend_Cache::throwException('The xcache extension must be loaded for using this backend !');
}
parent::__construct($options);
}
/**
* Test if a cache is available for the given id and (if yes) return it (false else)
*
* WARNING $doNotTestCacheValidity=true is unsupported by the Xcache backend
*
* @param string $id cache id
* @param boolean $doNotTestCacheValidity if set to true, the cache validity won't be tested
* @return string cached datas (or false)
*/
public function load($id, $doNotTestCacheValidity = false)
{
if ($doNotTestCacheValidity) {
$this->_log("Zend_Cache_Backend_Xcache::load() : \$doNotTestCacheValidity=true is unsupported by the Xcache backend");
}
$tmp = xcache_get($id);
if (is_array($tmp)) {
return $tmp[0];
}
return false;
}
/**
* Test if a cache is available or not (for the given id)
*
* @param string $id cache id
* @return mixed false (a cache is not available) or "last modified" timestamp (int) of the available cache record
*/
public function test($id)
{
if (xcache_isset($id)) {
$tmp = xcache_get($id);
if (is_array($tmp)) {
return $tmp[1];
}
}
return false;
}
/**
* Save some string datas into a cache record
*
* Note : $data is always "string" (serialization is done by the
* core not by the backend)
*
* @param string $data datas to cache
* @param string $id cache id
* @param array $tags array of strings, the cache record will be tagged by each string entry
* @param int $specificLifetime if != false, set a specific lifetime for this cache record (null => infinite lifetime)
* @return boolean true if no problem
*/
public function save($data, $id, $tags = array(), $specificLifetime = false)
{
$lifetime = $this->getLifetime($specificLifetime);
$result = xcache_set($id, array($data, time()), $lifetime);
if (count($tags) > 0) {
$this->_log(self::TAGS_UNSUPPORTED_BY_SAVE_OF_XCACHE_BACKEND);
}
return $result;
}
/**
* Remove a cache record
*
* @param string $id cache id
* @return boolean true if no problem
*/
public function remove($id)
{
return xcache_unset($id);
}
/**
* Clean some cache records
*
* Available modes are :
* 'all' (default) => remove all cache entries ($tags is not used)
* 'old' => unsupported
* 'matchingTag' => unsupported
* 'notMatchingTag' => unsupported
* 'matchingAnyTag' => unsupported
*
* @param string $mode clean mode
* @param array $tags array of tags
* @throws Zend_Cache_Exception
* @return boolean true if no problem
*/
public function clean($mode = Zend_Cache::CLEANING_MODE_ALL, $tags = array())
{
switch ($mode) {
case Zend_Cache::CLEANING_MODE_ALL:
// Necessary because xcache_clear_cache() need basic authentification
$backup = array();
if (isset($_SERVER['PHP_AUTH_USER'])) {
$backup['PHP_AUTH_USER'] = $_SERVER['PHP_AUTH_USER'];
}
if (isset($_SERVER['PHP_AUTH_PW'])) {
$backup['PHP_AUTH_PW'] = $_SERVER['PHP_AUTH_PW'];
}
if ($this->_options['user']) {
$_SERVER['PHP_AUTH_USER'] = $this->_options['user'];
}
if ($this->_options['password']) {
$_SERVER['PHP_AUTH_PW'] = $this->_options['password'];
}
$cnt = xcache_count(XC_TYPE_VAR);
for ($i=0; $i < $cnt; $i++) {
xcache_clear_cache(XC_TYPE_VAR, $i);
}
if (isset($backup['PHP_AUTH_USER'])) {
$_SERVER['PHP_AUTH_USER'] = $backup['PHP_AUTH_USER'];
$_SERVER['PHP_AUTH_PW'] = $backup['PHP_AUTH_PW'];
}
return true;
break;
case Zend_Cache::CLEANING_MODE_OLD:
$this->_log("Zend_Cache_Backend_Xcache::clean() : CLEANING_MODE_OLD is unsupported by the Xcache backend");
break;
case Zend_Cache::CLEANING_MODE_MATCHING_TAG:
case Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG:
case Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG:
$this->_log(self::TAGS_UNSUPPORTED_BY_CLEAN_OF_XCACHE_BACKEND);
break;
default:
Zend_Cache::throwException('Invalid mode for clean() method');
break;
}
}
/**
* Return true if the automatic cleaning is available for the backend
*
* @return boolean
*/
public function isAutomaticCleaningAvailable()
{
return false;
}
}

View File

@ -1,317 +0,0 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Cache
* @subpackage Zend_Cache_Backend
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: ZendPlatform.php 23775 2011-03-01 17:25:24Z ralph $
*/
/**
* @see Zend_Cache_Backend_Interface
*/
require_once 'Zend/Cache/Backend.php';
/**
* @see Zend_Cache_Backend_Interface
*/
require_once 'Zend/Cache/Backend/Interface.php';
/**
* Impementation of Zend Cache Backend using the Zend Platform (Output Content Caching)
*
* @package Zend_Cache
* @subpackage Zend_Cache_Backend
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Cache_Backend_ZendPlatform extends Zend_Cache_Backend implements Zend_Cache_Backend_Interface
{
/**
* internal ZP prefix
*/
const TAGS_PREFIX = "internal_ZPtag:";
/**
* Constructor
* Validate that the Zend Platform is loaded and licensed
*
* @param array $options Associative array of options
* @throws Zend_Cache_Exception
* @return void
*/
public function __construct(array $options = array())
{
if (!function_exists('accelerator_license_info')) {
Zend_Cache::throwException('The Zend Platform extension must be loaded for using this backend !');
}
if (!function_exists('accelerator_get_configuration')) {
$licenseInfo = accelerator_license_info();
Zend_Cache::throwException('The Zend Platform extension is not loaded correctly: '.$licenseInfo['failure_reason']);
}
$accConf = accelerator_get_configuration();
if (@!$accConf['output_cache_licensed']) {
Zend_Cache::throwException('The Zend Platform extension does not have the proper license to use content caching features');
}
if (@!$accConf['output_cache_enabled']) {
Zend_Cache::throwException('The Zend Platform content caching feature must be enabled for using this backend, set the \'zend_accelerator.output_cache_enabled\' directive to On !');
}
if (!is_writable($accConf['output_cache_dir'])) {
Zend_Cache::throwException('The cache copies directory \''. ini_get('zend_accelerator.output_cache_dir') .'\' must be writable !');
}
parent:: __construct($options);
}
/**
* Test if a cache is available for the given id and (if yes) return it (false else)
*
* @param string $id Cache id
* @param boolean $doNotTestCacheValidity If set to true, the cache validity won't be tested
* @return string Cached data (or false)
*/
public function load($id, $doNotTestCacheValidity = false)
{
// doNotTestCacheValidity implemented by giving zero lifetime to the cache
if ($doNotTestCacheValidity) {
$lifetime = 0;
} else {
$lifetime = $this->_directives['lifetime'];
}
$res = output_cache_get($id, $lifetime);
if($res) {
return $res[0];
} else {
return false;
}
}
/**
* Test if a cache is available or not (for the given id)
*
* @param string $id Cache id
* @return mixed|false false (a cache is not available) or "last modified" timestamp (int) of the available cache record
*/
public function test($id)
{
$result = output_cache_get($id, $this->_directives['lifetime']);
if ($result) {
return $result[1];
}
return false;
}
/**
* Save some string datas into a cache record
*
* Note : $data is always "string" (serialization is done by the
* core not by the backend)
*
* @param string $data Data to cache
* @param string $id Cache id
* @param array $tags Array of strings, the cache record will be tagged by each string entry
* @param int $specificLifetime If != false, set a specific lifetime for this cache record (null => infinite lifetime)
* @return boolean true if no problem
*/
public function save($data, $id, $tags = array(), $specificLifetime = false)
{
if (!($specificLifetime === false)) {
$this->_log("Zend_Cache_Backend_ZendPlatform::save() : non false specifc lifetime is unsuported for this backend");
}
$lifetime = $this->_directives['lifetime'];
$result1 = output_cache_put($id, array($data, time()));
$result2 = (count($tags) == 0);
foreach ($tags as $tag) {
$tagid = self::TAGS_PREFIX.$tag;
$old_tags = output_cache_get($tagid, $lifetime);
if ($old_tags === false) {
$old_tags = array();
}
$old_tags[$id] = $id;
output_cache_remove_key($tagid);
$result2 = output_cache_put($tagid, $old_tags);
}
return $result1 && $result2;
}
/**
* Remove a cache record
*
* @param string $id Cache id
* @return boolean True if no problem
*/
public function remove($id)
{
return output_cache_remove_key($id);
}
/**
* Clean some cache records
*
* Available modes are :
* Zend_Cache::CLEANING_MODE_ALL (default) => remove all cache entries ($tags is not used)
* Zend_Cache::CLEANING_MODE_OLD => remove too old cache entries ($tags is not used)
* This mode is not supported in this backend
* Zend_Cache::CLEANING_MODE_MATCHING_TAG => remove cache entries matching all given tags
* ($tags can be an array of strings or a single string)
* Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG => unsupported
* Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG => remove cache entries matching any given tags
* ($tags can be an array of strings or a single string)
*
* @param string $mode Clean mode
* @param array $tags Array of tags
* @throws Zend_Cache_Exception
* @return boolean True if no problem
*/
public function clean($mode = Zend_Cache::CLEANING_MODE_ALL, $tags = array())
{
switch ($mode) {
case Zend_Cache::CLEANING_MODE_ALL:
case Zend_Cache::CLEANING_MODE_OLD:
$cache_dir = ini_get('zend_accelerator.output_cache_dir');
if (!$cache_dir) {
return false;
}
$cache_dir .= '/.php_cache_api/';
return $this->_clean($cache_dir, $mode);
break;
case Zend_Cache::CLEANING_MODE_MATCHING_TAG:
$idlist = null;
foreach ($tags as $tag) {
$next_idlist = output_cache_get(self::TAGS_PREFIX.$tag, $this->_directives['lifetime']);
if ($idlist) {
$idlist = array_intersect_assoc($idlist, $next_idlist);
} else {
$idlist = $next_idlist;
}
if (count($idlist) == 0) {
// if ID list is already empty - we may skip checking other IDs
$idlist = null;
break;
}
}
if ($idlist) {
foreach ($idlist as $id) {
output_cache_remove_key($id);
}
}
return true;
break;
case Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG:
$this->_log("Zend_Cache_Backend_ZendPlatform::clean() : CLEANING_MODE_NOT_MATCHING_TAG is not supported by the Zend Platform backend");
return false;
break;
case Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG:
$idlist = null;
foreach ($tags as $tag) {
$next_idlist = output_cache_get(self::TAGS_PREFIX.$tag, $this->_directives['lifetime']);
if ($idlist) {
$idlist = array_merge_recursive($idlist, $next_idlist);
} else {
$idlist = $next_idlist;
}
if (count($idlist) == 0) {
// if ID list is already empty - we may skip checking other IDs
$idlist = null;
break;
}
}
if ($idlist) {
foreach ($idlist as $id) {
output_cache_remove_key($id);
}
}
return true;
break;
default:
Zend_Cache::throwException('Invalid mode for clean() method');
break;
}
}
/**
* Clean a directory and recursivly go over it's subdirectories
*
* Remove all the cached files that need to be cleaned (according to mode and files mtime)
*
* @param string $dir Path of directory ot clean
* @param string $mode The same parameter as in Zend_Cache_Backend_ZendPlatform::clean()
* @return boolean True if ok
*/
private function _clean($dir, $mode)
{
$d = @dir($dir);
if (!$d) {
return false;
}
$result = true;
while (false !== ($file = $d->read())) {
if ($file == '.' || $file == '..') {
continue;
}
$file = $d->path . $file;
if (is_dir($file)) {
$result = ($this->_clean($file .'/', $mode)) && ($result);
} else {
if ($mode == Zend_Cache::CLEANING_MODE_ALL) {
$result = ($this->_remove($file)) && ($result);
} else if ($mode == Zend_Cache::CLEANING_MODE_OLD) {
// Files older than lifetime get deleted from cache
if ($this->_directives['lifetime'] !== null) {
if ((time() - @filemtime($file)) > $this->_directives['lifetime']) {
$result = ($this->_remove($file)) && ($result);
}
}
}
}
}
$d->close();
return $result;
}
/**
* Remove a file
*
* If we can't remove the file (because of locks or any problem), we will touch
* the file to invalidate it
*
* @param string $file Complete file path
* @return boolean True if ok
*/
private function _remove($file)
{
if (!@unlink($file)) {
# If we can't remove the file (because of locks or any problem), we will touch
# the file to invalidate it
$this->_log("Zend_Cache_Backend_ZendPlatform::_remove() : we can't remove $file => we are going to try to invalidate it");
if ($this->_directives['lifetime'] === null) {
return false;
}
if (!file_exists($file)) {
return false;
}
return @touch($file, time() - 2*abs($this->_directives['lifetime']));
}
return true;
}
}

View File

@ -1,207 +0,0 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Cache
* @subpackage Zend_Cache_Backend
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: ZendServer.php 23775 2011-03-01 17:25:24Z ralph $
*/
/** @see Zend_Cache_Backend_Interface */
require_once 'Zend/Cache/Backend/Interface.php';
/** @see Zend_Cache_Backend */
require_once 'Zend/Cache/Backend.php';
/**
* @package Zend_Cache
* @subpackage Zend_Cache_Backend
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
abstract class Zend_Cache_Backend_ZendServer extends Zend_Cache_Backend implements Zend_Cache_Backend_Interface
{
/**
* Available options
*
* =====> (string) namespace :
* Namespace to be used for chaching operations
*
* @var array available options
*/
protected $_options = array(
'namespace' => 'zendframework'
);
/**
* Store data
*
* @param mixed $data Object to store
* @param string $id Cache id
* @param int $timeToLive Time to live in seconds
* @throws Zend_Cache_Exception
*/
abstract protected function _store($data, $id, $timeToLive);
/**
* Fetch data
*
* @param string $id Cache id
* @throws Zend_Cache_Exception
*/
abstract protected function _fetch($id);
/**
* Unset data
*
* @param string $id Cache id
*/
abstract protected function _unset($id);
/**
* Clear cache
*/
abstract protected function _clear();
/**
* Test if a cache is available for the given id and (if yes) return it (false else)
*
* @param string $id cache id
* @param boolean $doNotTestCacheValidity if set to true, the cache validity won't be tested
* @return string cached datas (or false)
*/
public function load($id, $doNotTestCacheValidity = false)
{
$tmp = $this->_fetch($id);
if ($tmp !== null) {
return $tmp;
}
return false;
}
/**
* Test if a cache is available or not (for the given id)
*
* @param string $id cache id
* @return mixed false (a cache is not available) or "last modified" timestamp (int) of the available cache record
* @throws Zend_Cache_Exception
*/
public function test($id)
{
$tmp = $this->_fetch('internal-metadatas---' . $id);
if ($tmp !== false) {
if (!is_array($tmp) || !isset($tmp['mtime'])) {
Zend_Cache::throwException('Cache metadata for \'' . $id . '\' id is corrupted' );
}
return $tmp['mtime'];
}
return false;
}
/**
* Compute & return the expire time
*
* @return int expire time (unix timestamp)
*/
private function _expireTime($lifetime)
{
if ($lifetime === null) {
return 9999999999;
}
return time() + $lifetime;
}
/**
* Save some string datas into a cache record
*
* Note : $data is always "string" (serialization is done by the
* core not by the backend)
*
* @param string $data datas to cache
* @param string $id cache id
* @param array $tags array of strings, the cache record will be tagged by each string entry
* @param int $specificLifetime if != false, set a specific lifetime for this cache record (null => infinite lifetime)
* @return boolean true if no problem
*/
public function save($data, $id, $tags = array(), $specificLifetime = false)
{
$lifetime = $this->getLifetime($specificLifetime);
$metadatas = array(
'mtime' => time(),
'expire' => $this->_expireTime($lifetime),
);
if (count($tags) > 0) {
$this->_log('Zend_Cache_Backend_ZendServer::save() : tags are unsupported by the ZendServer backends');
}
return $this->_store($data, $id, $lifetime) &&
$this->_store($metadatas, 'internal-metadatas---' . $id, $lifetime);
}
/**
* Remove a cache record
*
* @param string $id cache id
* @return boolean true if no problem
*/
public function remove($id)
{
$result1 = $this->_unset($id);
$result2 = $this->_unset('internal-metadatas---' . $id);
return $result1 && $result2;
}
/**
* Clean some cache records
*
* Available modes are :
* 'all' (default) => remove all cache entries ($tags is not used)
* 'old' => unsupported
* 'matchingTag' => unsupported
* 'notMatchingTag' => unsupported
* 'matchingAnyTag' => unsupported
*
* @param string $mode clean mode
* @param array $tags array of tags
* @throws Zend_Cache_Exception
* @return boolean true if no problem
*/
public function clean($mode = Zend_Cache::CLEANING_MODE_ALL, $tags = array())
{
switch ($mode) {
case Zend_Cache::CLEANING_MODE_ALL:
$this->_clear();
return true;
break;
case Zend_Cache::CLEANING_MODE_OLD:
$this->_log("Zend_Cache_Backend_ZendServer::clean() : CLEANING_MODE_OLD is unsupported by the Zend Server backends.");
break;
case Zend_Cache::CLEANING_MODE_MATCHING_TAG:
case Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG:
case Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG:
$this->_clear();
$this->_log('Zend_Cache_Backend_ZendServer::clean() : tags are unsupported by the Zend Server backends.');
break;
default:
Zend_Cache::throwException('Invalid mode for clean() method');
break;
}
}
}

View File

@ -1,100 +0,0 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Cache
* @subpackage Zend_Cache_Backend
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Disk.php 23775 2011-03-01 17:25:24Z ralph $
*/
/** @see Zend_Cache_Backend_Interface */
require_once 'Zend/Cache/Backend/Interface.php';
/** @see Zend_Cache_Backend_ZendServer */
require_once 'Zend/Cache/Backend/ZendServer.php';
/**
* @package Zend_Cache
* @subpackage Zend_Cache_Backend
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Cache_Backend_ZendServer_Disk extends Zend_Cache_Backend_ZendServer implements Zend_Cache_Backend_Interface
{
/**
* Constructor
*
* @param array $options associative array of options
* @throws Zend_Cache_Exception
*/
public function __construct(array $options = array())
{
if (!function_exists('zend_disk_cache_store')) {
Zend_Cache::throwException('Zend_Cache_ZendServer_Disk backend has to be used within Zend Server environment.');
}
parent::__construct($options);
}
/**
* Store data
*
* @param mixed $data Object to store
* @param string $id Cache id
* @param int $timeToLive Time to live in seconds
* @return boolean true if no problem
*/
protected function _store($data, $id, $timeToLive)
{
if (zend_disk_cache_store($this->_options['namespace'] . '::' . $id,
$data,
$timeToLive) === false) {
$this->_log('Store operation failed.');
return false;
}
return true;
}
/**
* Fetch data
*
* @param string $id Cache id
*/
protected function _fetch($id)
{
return zend_disk_cache_fetch($this->_options['namespace'] . '::' . $id);
}
/**
* Unset data
*
* @param string $id Cache id
* @return boolean true if no problem
*/
protected function _unset($id)
{
return zend_disk_cache_delete($this->_options['namespace'] . '::' . $id);
}
/**
* Clear cache
*/
protected function _clear()
{
zend_disk_cache_clear($this->_options['namespace']);
}
}

View File

@ -1,100 +0,0 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Cache
* @subpackage Zend_Cache_Backend
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: ShMem.php 23775 2011-03-01 17:25:24Z ralph $
*/
/** @see Zend_Cache_Backend_Interface */
require_once 'Zend/Cache/Backend/Interface.php';
/** @see Zend_Cache_Backend_ZendServer */
require_once 'Zend/Cache/Backend/ZendServer.php';
/**
* @package Zend_Cache
* @subpackage Zend_Cache_Backend
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Cache_Backend_ZendServer_ShMem extends Zend_Cache_Backend_ZendServer implements Zend_Cache_Backend_Interface
{
/**
* Constructor
*
* @param array $options associative array of options
* @throws Zend_Cache_Exception
*/
public function __construct(array $options = array())
{
if (!function_exists('zend_shm_cache_store')) {
Zend_Cache::throwException('Zend_Cache_ZendServer_ShMem backend has to be used within Zend Server environment.');
}
parent::__construct($options);
}
/**
* Store data
*
* @param mixed $data Object to store
* @param string $id Cache id
* @param int $timeToLive Time to live in seconds
*
*/
protected function _store($data, $id, $timeToLive)
{
if (zend_shm_cache_store($this->_options['namespace'] . '::' . $id,
$data,
$timeToLive) === false) {
$this->_log('Store operation failed.');
return false;
}
return true;
}
/**
* Fetch data
*
* @param string $id Cache id
*/
protected function _fetch($id)
{
return zend_shm_cache_fetch($this->_options['namespace'] . '::' . $id);
}
/**
* Unset data
*
* @param string $id Cache id
* @return boolean true if no problem
*/
protected function _unset($id)
{
return zend_shm_cache_delete($this->_options['namespace'] . '::' . $id);
}
/**
* Clear cache
*/
protected function _clear()
{
zend_shm_cache_clear($this->_options['namespace']);
}
}

View File

@ -1,764 +0,0 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Cache
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Core.php 23800 2011-03-10 20:52:08Z mabe $
*/
/**
* @package Zend_Cache
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Cache_Core
{
/**
* Messages
*/
const BACKEND_NOT_SUPPORTS_TAG = 'tags are not supported by the current backend';
const BACKEND_NOT_IMPLEMENTS_EXTENDED_IF = 'Current backend doesn\'t implement the Zend_Cache_Backend_ExtendedInterface, so this method is not available';
/**
* Backend Object
*
* @var Zend_Cache_Backend_Interface $_backend
*/
protected $_backend = null;
/**
* Available options
*
* ====> (boolean) write_control :
* - Enable / disable write control (the cache is read just after writing to detect corrupt entries)
* - Enable write control will lightly slow the cache writing but not the cache reading
* Write control can detect some corrupt cache files but maybe it's not a perfect control
*
* ====> (boolean) caching :
* - Enable / disable caching
* (can be very useful for the debug of cached scripts)
*
* =====> (string) cache_id_prefix :
* - prefix for cache ids (namespace)
*
* ====> (boolean) automatic_serialization :
* - Enable / disable automatic serialization
* - It can be used to save directly datas which aren't strings (but it's slower)
*
* ====> (int) automatic_cleaning_factor :
* - Disable / Tune the automatic cleaning process
* - The automatic cleaning process destroy too old (for the given life time)
* cache files when a new cache file is written :
* 0 => no automatic cache cleaning
* 1 => systematic cache cleaning
* x (integer) > 1 => automatic cleaning randomly 1 times on x cache write
*
* ====> (int) lifetime :
* - Cache lifetime (in seconds)
* - If null, the cache is valid forever.
*
* ====> (boolean) logging :
* - If set to true, logging is activated (but the system is slower)
*
* ====> (boolean) ignore_user_abort
* - If set to true, the core will set the ignore_user_abort PHP flag inside the
* save() method to avoid cache corruptions in some cases (default false)
*
* @var array $_options available options
*/
protected $_options = array(
'write_control' => true,
'caching' => true,
'cache_id_prefix' => null,
'automatic_serialization' => false,
'automatic_cleaning_factor' => 10,
'lifetime' => 3600,
'logging' => false,
'logger' => null,
'ignore_user_abort' => false
);
/**
* Array of options which have to be transfered to backend
*
* @var array $_directivesList
*/
protected static $_directivesList = array('lifetime', 'logging', 'logger');
/**
* Not used for the core, just a sort a hint to get a common setOption() method (for the core and for frontends)
*
* @var array $_specificOptions
*/
protected $_specificOptions = array();
/**
* Last used cache id
*
* @var string $_lastId
*/
private $_lastId = null;
/**
* True if the backend implements Zend_Cache_Backend_ExtendedInterface
*
* @var boolean $_extendedBackend
*/
protected $_extendedBackend = false;
/**
* Array of capabilities of the backend (only if it implements Zend_Cache_Backend_ExtendedInterface)
*
* @var array
*/
protected $_backendCapabilities = array();
/**
* Constructor
*
* @param array|Zend_Config $options Associative array of options or Zend_Config instance
* @throws Zend_Cache_Exception
* @return void
*/
public function __construct($options = array())
{
if ($options instanceof Zend_Config) {
$options = $options->toArray();
}
if (!is_array($options)) {
Zend_Cache::throwException("Options passed were not an array"
. " or Zend_Config instance.");
}
while (list($name, $value) = each($options)) {
$this->setOption($name, $value);
}
$this->_loggerSanity();
}
/**
* Set options using an instance of type Zend_Config
*
* @param Zend_Config $config
* @return Zend_Cache_Core
*/
public function setConfig(Zend_Config $config)
{
$options = $config->toArray();
while (list($name, $value) = each($options)) {
$this->setOption($name, $value);
}
return $this;
}
/**
* Set the backend
*
* @param Zend_Cache_Backend $backendObject
* @throws Zend_Cache_Exception
* @return void
*/
public function setBackend(Zend_Cache_Backend $backendObject)
{
$this->_backend= $backendObject;
// some options (listed in $_directivesList) have to be given
// to the backend too (even if they are not "backend specific")
$directives = array();
foreach (Zend_Cache_Core::$_directivesList as $directive) {
$directives[$directive] = $this->_options[$directive];
}
$this->_backend->setDirectives($directives);
if (in_array('Zend_Cache_Backend_ExtendedInterface', class_implements($this->_backend))) {
$this->_extendedBackend = true;
$this->_backendCapabilities = $this->_backend->getCapabilities();
}
}
/**
* Returns the backend
*
* @return Zend_Cache_Backend backend object
*/
public function getBackend()
{
return $this->_backend;
}
/**
* Public frontend to set an option
*
* There is an additional validation (relatively to the protected _setOption method)
*
* @param string $name Name of the option
* @param mixed $value Value of the option
* @throws Zend_Cache_Exception
* @return void
*/
public function setOption($name, $value)
{
if (!is_string($name)) {
Zend_Cache::throwException("Incorrect option name : $name");
}
$name = strtolower($name);
if (array_key_exists($name, $this->_options)) {
// This is a Core option
$this->_setOption($name, $value);
return;
}
if (array_key_exists($name, $this->_specificOptions)) {
// This a specic option of this frontend
$this->_specificOptions[$name] = $value;
return;
}
}
/**
* Public frontend to get an option value
*
* @param string $name Name of the option
* @throws Zend_Cache_Exception
* @return mixed option value
*/
public function getOption($name)
{
if (is_string($name)) {
$name = strtolower($name);
if (array_key_exists($name, $this->_options)) {
// This is a Core option
return $this->_options[$name];
}
if (array_key_exists($name, $this->_specificOptions)) {
// This a specic option of this frontend
return $this->_specificOptions[$name];
}
}
Zend_Cache::throwException("Incorrect option name : $name");
}
/**
* Set an option
*
* @param string $name Name of the option
* @param mixed $value Value of the option
* @throws Zend_Cache_Exception
* @return void
*/
private function _setOption($name, $value)
{
if (!is_string($name) || !array_key_exists($name, $this->_options)) {
Zend_Cache::throwException("Incorrect option name : $name");
}
if ($name == 'lifetime' && empty($value)) {
$value = null;
}
$this->_options[$name] = $value;
}
/**
* Force a new lifetime
*
* The new value is set for the core/frontend but for the backend too (directive)
*
* @param int $newLifetime New lifetime (in seconds)
* @return void
*/
public function setLifetime($newLifetime)
{
$this->_options['lifetime'] = $newLifetime;
$this->_backend->setDirectives(array(
'lifetime' => $newLifetime
));
}
/**
* Test if a cache is available for the given id and (if yes) return it (false else)
*
* @param string $id Cache id
* @param boolean $doNotTestCacheValidity If set to true, the cache validity won't be tested
* @param boolean $doNotUnserialize Do not serialize (even if automatic_serialization is true) => for internal use
* @return mixed|false Cached datas
*/
public function load($id, $doNotTestCacheValidity = false, $doNotUnserialize = false)
{
if (!$this->_options['caching']) {
return false;
}
$id = $this->_id($id); // cache id may need prefix
$this->_lastId = $id;
self::_validateIdOrTag($id);
$this->_log("Zend_Cache_Core: load item '{$id}'", 7);
$data = $this->_backend->load($id, $doNotTestCacheValidity);
if ($data===false) {
// no cache available
return false;
}
if ((!$doNotUnserialize) && $this->_options['automatic_serialization']) {
// we need to unserialize before sending the result
return unserialize($data);
}
return $data;
}
/**
* Test if a cache is available for the given id
*
* @param string $id Cache id
* @return int|false Last modified time of cache entry if it is available, false otherwise
*/
public function test($id)
{
if (!$this->_options['caching']) {
return false;
}
$id = $this->_id($id); // cache id may need prefix
self::_validateIdOrTag($id);
$this->_lastId = $id;
$this->_log("Zend_Cache_Core: test item '{$id}'", 7);
return $this->_backend->test($id);
}
/**
* Save some data in a cache
*
* @param mixed $data Data to put in cache (can be another type than string if automatic_serialization is on)
* @param string $id Cache id (if not set, the last cache id will be used)
* @param array $tags Cache tags
* @param int $specificLifetime If != false, set a specific lifetime for this cache record (null => infinite lifetime)
* @param int $priority integer between 0 (very low priority) and 10 (maximum priority) used by some particular backends
* @throws Zend_Cache_Exception
* @return boolean True if no problem
*/
public function save($data, $id = null, $tags = array(), $specificLifetime = false, $priority = 8)
{
if (!$this->_options['caching']) {
return true;
}
if ($id === null) {
$id = $this->_lastId;
} else {
$id = $this->_id($id);
}
self::_validateIdOrTag($id);
self::_validateTagsArray($tags);
if ($this->_options['automatic_serialization']) {
// we need to serialize datas before storing them
$data = serialize($data);
} else {
if (!is_string($data)) {
Zend_Cache::throwException("Datas must be string or set automatic_serialization = true");
}
}
// automatic cleaning
if ($this->_options['automatic_cleaning_factor'] > 0) {
$rand = rand(1, $this->_options['automatic_cleaning_factor']);
if ($rand==1) {
// new way || deprecated way
if ($this->_extendedBackend || method_exists($this->_backend, 'isAutomaticCleaningAvailable')) {
$this->_log("Zend_Cache_Core::save(): automatic cleaning running", 7);
$this->clean(Zend_Cache::CLEANING_MODE_OLD);
} else {
$this->_log("Zend_Cache_Core::save(): automatic cleaning is not available/necessary with current backend", 4);
}
}
}
$this->_log("Zend_Cache_Core: save item '{$id}'", 7);
if ($this->_options['ignore_user_abort']) {
$abort = ignore_user_abort(true);
}
if (($this->_extendedBackend) && ($this->_backendCapabilities['priority'])) {
$result = $this->_backend->save($data, $id, $tags, $specificLifetime, $priority);
} else {
$result = $this->_backend->save($data, $id, $tags, $specificLifetime);
}
if ($this->_options['ignore_user_abort']) {
ignore_user_abort($abort);
}
if (!$result) {
// maybe the cache is corrupted, so we remove it !
$this->_log("Zend_Cache_Core::save(): failed to save item '{$id}' -> removing it", 4);
$this->_backend->remove($id);
return false;
}
if ($this->_options['write_control']) {
$data2 = $this->_backend->load($id, true);
if ($data!=$data2) {
$this->_log("Zend_Cache_Core::save(): write control of item '{$id}' failed -> removing it", 4);
$this->_backend->remove($id);
return false;
}
}
return true;
}
/**
* Remove a cache
*
* @param string $id Cache id to remove
* @return boolean True if ok
*/
public function remove($id)
{
if (!$this->_options['caching']) {
return true;
}
$id = $this->_id($id); // cache id may need prefix
self::_validateIdOrTag($id);
$this->_log("Zend_Cache_Core: remove item '{$id}'", 7);
return $this->_backend->remove($id);
}
/**
* Clean cache entries
*
* Available modes are :
* 'all' (default) => remove all cache entries ($tags is not used)
* 'old' => remove too old cache entries ($tags is not used)
* 'matchingTag' => remove cache entries matching all given tags
* ($tags can be an array of strings or a single string)
* 'notMatchingTag' => remove cache entries not matching one of the given tags
* ($tags can be an array of strings or a single string)
* 'matchingAnyTag' => remove cache entries matching any given tags
* ($tags can be an array of strings or a single string)
*
* @param string $mode
* @param array|string $tags
* @throws Zend_Cache_Exception
* @return boolean True if ok
*/
public function clean($mode = 'all', $tags = array())
{
if (!$this->_options['caching']) {
return true;
}
if (!in_array($mode, array(Zend_Cache::CLEANING_MODE_ALL,
Zend_Cache::CLEANING_MODE_OLD,
Zend_Cache::CLEANING_MODE_MATCHING_TAG,
Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG,
Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG))) {
Zend_Cache::throwException('Invalid cleaning mode');
}
self::_validateTagsArray($tags);
return $this->_backend->clean($mode, $tags);
}
/**
* Return an array of stored cache ids which match given tags
*
* In case of multiple tags, a logical AND is made between tags
*
* @param array $tags array of tags
* @return array array of matching cache ids (string)
*/
public function getIdsMatchingTags($tags = array())
{
if (!$this->_extendedBackend) {
Zend_Cache::throwException(self::BACKEND_NOT_IMPLEMENTS_EXTENDED_IF);
}
if (!($this->_backendCapabilities['tags'])) {
Zend_Cache::throwException(self::BACKEND_NOT_SUPPORTS_TAG);
}
$ids = $this->_backend->getIdsMatchingTags($tags);
// we need to remove cache_id_prefix from ids (see #ZF-6178, #ZF-7600)
if (isset($this->_options['cache_id_prefix']) && $this->_options['cache_id_prefix'] !== '') {
$prefix = & $this->_options['cache_id_prefix'];
$prefixLen = strlen($prefix);
foreach ($ids as &$id) {
if (strpos($id, $prefix) === 0) {
$id = substr($id, $prefixLen);
}
}
}
return $ids;
}
/**
* Return an array of stored cache ids which don't match given tags
*
* In case of multiple tags, a logical OR is made between tags
*
* @param array $tags array of tags
* @return array array of not matching cache ids (string)
*/
public function getIdsNotMatchingTags($tags = array())
{
if (!$this->_extendedBackend) {
Zend_Cache::throwException(self::BACKEND_NOT_IMPLEMENTS_EXTENDED_IF);
}
if (!($this->_backendCapabilities['tags'])) {
Zend_Cache::throwException(self::BACKEND_NOT_SUPPORTS_TAG);
}
$ids = $this->_backend->getIdsNotMatchingTags($tags);
// we need to remove cache_id_prefix from ids (see #ZF-6178, #ZF-7600)
if (isset($this->_options['cache_id_prefix']) && $this->_options['cache_id_prefix'] !== '') {
$prefix = & $this->_options['cache_id_prefix'];
$prefixLen = strlen($prefix);
foreach ($ids as &$id) {
if (strpos($id, $prefix) === 0) {
$id = substr($id, $prefixLen);
}
}
}
return $ids;
}
/**
* Return an array of stored cache ids which match any given tags
*
* In case of multiple tags, a logical OR is made between tags
*
* @param array $tags array of tags
* @return array array of matching any cache ids (string)
*/
public function getIdsMatchingAnyTags($tags = array())
{
if (!$this->_extendedBackend) {
Zend_Cache::throwException(self::BACKEND_NOT_IMPLEMENTS_EXTENDED_IF);
}
if (!($this->_backendCapabilities['tags'])) {
Zend_Cache::throwException(self::BACKEND_NOT_SUPPORTS_TAG);
}
$ids = $this->_backend->getIdsMatchingAnyTags($tags);
// we need to remove cache_id_prefix from ids (see #ZF-6178, #ZF-7600)
if (isset($this->_options['cache_id_prefix']) && $this->_options['cache_id_prefix'] !== '') {
$prefix = & $this->_options['cache_id_prefix'];
$prefixLen = strlen($prefix);
foreach ($ids as &$id) {
if (strpos($id, $prefix) === 0) {
$id = substr($id, $prefixLen);
}
}
}
return $ids;
}
/**
* Return an array of stored cache ids
*
* @return array array of stored cache ids (string)
*/
public function getIds()
{
if (!$this->_extendedBackend) {
Zend_Cache::throwException(self::BACKEND_NOT_IMPLEMENTS_EXTENDED_IF);
}
$ids = $this->_backend->getIds();
// we need to remove cache_id_prefix from ids (see #ZF-6178, #ZF-7600)
if (isset($this->_options['cache_id_prefix']) && $this->_options['cache_id_prefix'] !== '') {
$prefix = & $this->_options['cache_id_prefix'];
$prefixLen = strlen($prefix);
foreach ($ids as &$id) {
if (strpos($id, $prefix) === 0) {
$id = substr($id, $prefixLen);
}
}
}
return $ids;
}
/**
* Return an array of stored tags
*
* @return array array of stored tags (string)
*/
public function getTags()
{
if (!$this->_extendedBackend) {
Zend_Cache::throwException(self::BACKEND_NOT_IMPLEMENTS_EXTENDED_IF);
}
if (!($this->_backendCapabilities['tags'])) {
Zend_Cache::throwException(self::BACKEND_NOT_SUPPORTS_TAG);
}
return $this->_backend->getTags();
}
/**
* Return the filling percentage of the backend storage
*
* @return int integer between 0 and 100
*/
public function getFillingPercentage()
{
if (!$this->_extendedBackend) {
Zend_Cache::throwException(self::BACKEND_NOT_IMPLEMENTS_EXTENDED_IF);
}
return $this->_backend->getFillingPercentage();
}
/**
* Return an array of metadatas for the given cache id
*
* The array will include these keys :
* - expire : the expire timestamp
* - tags : a string array of tags
* - mtime : timestamp of last modification time
*
* @param string $id cache id
* @return array array of metadatas (false if the cache id is not found)
*/
public function getMetadatas($id)
{
if (!$this->_extendedBackend) {
Zend_Cache::throwException(self::BACKEND_NOT_IMPLEMENTS_EXTENDED_IF);
}
$id = $this->_id($id); // cache id may need prefix
return $this->_backend->getMetadatas($id);
}
/**
* Give (if possible) an extra lifetime to the given cache id
*
* @param string $id cache id
* @param int $extraLifetime
* @return boolean true if ok
*/
public function touch($id, $extraLifetime)
{
if (!$this->_extendedBackend) {
Zend_Cache::throwException(self::BACKEND_NOT_IMPLEMENTS_EXTENDED_IF);
}
$id = $this->_id($id); // cache id may need prefix
$this->_log("Zend_Cache_Core: touch item '{$id}'", 7);
return $this->_backend->touch($id, $extraLifetime);
}
/**
* Validate a cache id or a tag (security, reliable filenames, reserved prefixes...)
*
* Throw an exception if a problem is found
*
* @param string $string Cache id or tag
* @throws Zend_Cache_Exception
* @return void
*/
protected static function _validateIdOrTag($string)
{
if (!is_string($string)) {
Zend_Cache::throwException('Invalid id or tag : must be a string');
}
if (substr($string, 0, 9) == 'internal-') {
Zend_Cache::throwException('"internal-*" ids or tags are reserved');
}
if (!preg_match('~^[a-zA-Z0-9_]+$~D', $string)) {
Zend_Cache::throwException("Invalid id or tag '$string' : must use only [a-zA-Z0-9_]");
}
}
/**
* Validate a tags array (security, reliable filenames, reserved prefixes...)
*
* Throw an exception if a problem is found
*
* @param array $tags Array of tags
* @throws Zend_Cache_Exception
* @return void
*/
protected static function _validateTagsArray($tags)
{
if (!is_array($tags)) {
Zend_Cache::throwException('Invalid tags array : must be an array');
}
foreach($tags as $tag) {
self::_validateIdOrTag($tag);
}
reset($tags);
}
/**
* Make sure if we enable logging that the Zend_Log class
* is available.
* Create a default log object if none is set.
*
* @throws Zend_Cache_Exception
* @return void
*/
protected function _loggerSanity()
{
if (!isset($this->_options['logging']) || !$this->_options['logging']) {
return;
}
if (isset($this->_options['logger']) && $this->_options['logger'] instanceof Zend_Log) {
return;
}
// Create a default logger to the standard output stream
require_once 'Zend/Log.php';
require_once 'Zend/Log/Writer/Stream.php';
require_once 'Zend/Log/Filter/Priority.php';
$logger = new Zend_Log(new Zend_Log_Writer_Stream('php://output'));
$logger->addFilter(new Zend_Log_Filter_Priority(Zend_Log::WARN, '<='));
$this->_options['logger'] = $logger;
}
/**
* Log a message at the WARN (4) priority.
*
* @param string $message
* @throws Zend_Cache_Exception
* @return void
*/
protected function _log($message, $priority = 4)
{
if (!$this->_options['logging']) {
return;
}
if (!(isset($this->_options['logger']) || $this->_options['logger'] instanceof Zend_Log)) {
Zend_Cache::throwException('Logging is enabled but logger is not set');
}
$logger = $this->_options['logger'];
$logger->log($message, $priority);
}
/**
* Make and return a cache id
*
* Checks 'cache_id_prefix' and returns new id with prefix or simply the id if null
*
* @param string $id Cache id
* @return string Cache id (with or without prefix)
*/
protected function _id($id)
{
if (($id !== null) && isset($this->_options['cache_id_prefix'])) {
return $this->_options['cache_id_prefix'] . $id; // return with prefix
}
return $id; // no prefix, just return the $id passed
}
}

View File

@ -1,32 +0,0 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Cache
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Exception.php 23775 2011-03-01 17:25:24Z ralph $
*/
/**
* @see Zend_Exception
*/
require_once 'Zend/Exception.php';
/**
* @package Zend_Cache
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Cache_Exception extends Zend_Exception {}

View File

@ -1,88 +0,0 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Cache
* @subpackage Zend_Cache_Frontend
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Capture.php 23775 2011-03-01 17:25:24Z ralph $
*/
/**
* @see Zend_Cache_Core
*/
require_once 'Zend/Cache/Core.php';
/**
* @package Zend_Cache
* @subpackage Zend_Cache_Frontend
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Cache_Frontend_Capture extends Zend_Cache_Core
{
/**
* Page identifiers
* @var array
*/
protected $_idStack = array();
/**
* Tags
* @var array
*/
protected $_tags = array();
protected $_extension = null;
/**
* Start the cache
*
* @param string $id Cache id
* @return mixed True if the cache is hit (false else) with $echoData=true (default) ; string else (datas)
*/
public function start($id, array $tags, $extension = null)
{
$this->_tags = $tags;
$this->_extension = $extension;
ob_start(array($this, '_flush'));
ob_implicit_flush(false);
$this->_idStack[] = $id;
return false;
}
/**
* callback for output buffering
* (shouldn't really be called manually)
*
* @param string $data Buffered output
* @return string Data to send to browser
*/
public function _flush($data)
{
$id = array_pop($this->_idStack);
if ($id === null) {
Zend_Cache::throwException('use of _flush() without a start()');
}
if ($this->_extension) {
$this->save(serialize(array($data, $this->_extension)), $id, $this->_tags);
} else {
$this->save($data, $id, $this->_tags);
}
return $data;
}
}

View File

@ -1,265 +0,0 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Cache
* @subpackage Zend_Cache_Frontend
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Class.php 24032 2011-05-10 21:08:20Z mabe $
*/
/**
* @see Zend_Cache_Core
*/
require_once 'Zend/Cache/Core.php';
/**
* @package Zend_Cache
* @subpackage Zend_Cache_Frontend
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Cache_Frontend_Class extends Zend_Cache_Core
{
/**
* Available options
*
* ====> (mixed) cached_entity :
* - if set to a class name, we will cache an abstract class and will use only static calls
* - if set to an object, we will cache this object methods
*
* ====> (boolean) cache_by_default :
* - if true, method calls will be cached by default
*
* ====> (array) cached_methods :
* - an array of method names which will be cached (even if cache_by_default = false)
*
* ====> (array) non_cached_methods :
* - an array of method names which won't be cached (even if cache_by_default = true)
*
* @var array available options
*/
protected $_specificOptions = array(
'cached_entity' => null,
'cache_by_default' => true,
'cached_methods' => array(),
'non_cached_methods' => array()
);
/**
* Tags array
*
* @var array
*/
private $_tags = array();
/**
* SpecificLifetime value
*
* false => no specific life time
*
* @var int
*/
private $_specificLifetime = false;
/**
* The cached object or the name of the cached abstract class
*
* @var mixed
*/
private $_cachedEntity = null;
/**
* The class name of the cached object or cached abstract class
*
* Used to differentiate between different classes with the same method calls.
*
* @var string
*/
private $_cachedEntityLabel = '';
/**
* Priority (used by some particular backends)
*
* @var int
*/
private $_priority = 8;
/**
* Constructor
*
* @param array $options Associative array of options
* @throws Zend_Cache_Exception
* @return void
*/
public function __construct(array $options = array())
{
while (list($name, $value) = each($options)) {
$this->setOption($name, $value);
}
if ($this->_specificOptions['cached_entity'] === null) {
Zend_Cache::throwException('cached_entity must be set !');
}
$this->setCachedEntity($this->_specificOptions['cached_entity']);
$this->setOption('automatic_serialization', true);
}
/**
* Set a specific life time
*
* @param int $specificLifetime
* @return void
*/
public function setSpecificLifetime($specificLifetime = false)
{
$this->_specificLifetime = $specificLifetime;
}
/**
* Set the priority (used by some particular backends)
*
* @param int $priority integer between 0 (very low priority) and 10 (maximum priority)
*/
public function setPriority($priority)
{
$this->_priority = $priority;
}
/**
* Public frontend to set an option
*
* Just a wrapper to get a specific behaviour for cached_entity
*
* @param string $name Name of the option
* @param mixed $value Value of the option
* @throws Zend_Cache_Exception
* @return void
*/
public function setOption($name, $value)
{
if ($name == 'cached_entity') {
$this->setCachedEntity($value);
} else {
parent::setOption($name, $value);
}
}
/**
* Specific method to set the cachedEntity
*
* if set to a class name, we will cache an abstract class and will use only static calls
* if set to an object, we will cache this object methods
*
* @param mixed $cachedEntity
*/
public function setCachedEntity($cachedEntity)
{
if (!is_string($cachedEntity) && !is_object($cachedEntity)) {
Zend_Cache::throwException('cached_entity must be an object or a class name');
}
$this->_cachedEntity = $cachedEntity;
$this->_specificOptions['cached_entity'] = $cachedEntity;
if (is_string($this->_cachedEntity)){
$this->_cachedEntityLabel = $this->_cachedEntity;
} else {
$ro = new ReflectionObject($this->_cachedEntity);
$this->_cachedEntityLabel = $ro->getName();
}
}
/**
* Set the cache array
*
* @param array $tags
* @return void
*/
public function setTagsArray($tags = array())
{
$this->_tags = $tags;
}
/**
* Main method : call the specified method or get the result from cache
*
* @param string $name Method name
* @param array $parameters Method parameters
* @return mixed Result
*/
public function __call($name, $parameters)
{
$callback = array($this->_cachedEntity, $name);
if (!is_callable($callback, false)) {
Zend_Cache::throwException('Invalid callback');
}
$cacheBool1 = $this->_specificOptions['cache_by_default'];
$cacheBool2 = in_array($name, $this->_specificOptions['cached_methods']);
$cacheBool3 = in_array($name, $this->_specificOptions['non_cached_methods']);
$cache = (($cacheBool1 || $cacheBool2) && (!$cacheBool3));
if (!$cache) {
// We do not have not cache
return call_user_func_array($callback, $parameters);
}
$id = $this->_makeId($name, $parameters);
if ( ($rs = $this->load($id)) && isset($rs[0], $rs[1]) ) {
// A cache is available
$output = $rs[0];
$return = $rs[1];
} else {
// A cache is not available (or not valid for this frontend)
ob_start();
ob_implicit_flush(false);
try {
$return = call_user_func_array($callback, $parameters);
$output = ob_get_clean();
$data = array($output, $return);
$this->save($data, $id, $this->_tags, $this->_specificLifetime, $this->_priority);
} catch (Exception $e) {
ob_end_clean();
throw $e;
}
}
echo $output;
return $return;
}
/**
* ZF-9970
*
* @deprecated
*/
private function _makeId($name, $args)
{
return $this->makeId($name, $args);
}
/**
* Make a cache id from the method name and parameters
*
* @param string $name Method name
* @param array $args Method parameters
* @return string Cache id
*/
public function makeId($name, array $args = array())
{
return md5($this->_cachedEntityLabel . '__' . $name . '__' . serialize($args));
}
}

View File

@ -1,222 +0,0 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Cache
* @subpackage Zend_Cache_Frontend
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: File.php 24218 2011-07-10 01:22:58Z ramon $
*/
/**
* @see Zend_Cache_Core
*/
require_once 'Zend/Cache/Core.php';
/**
* @package Zend_Cache
* @subpackage Zend_Cache_Frontend
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Cache_Frontend_File extends Zend_Cache_Core
{
/**
* Consts for master_files_mode
*/
const MODE_AND = 'AND';
const MODE_OR = 'OR';
/**
* Available options
*
* ====> (string) master_file :
* - a complete path of the master file
* - deprecated (see master_files)
*
* ====> (array) master_files :
* - an array of complete path of master files
* - this option has to be set !
*
* ====> (string) master_files_mode :
* - Zend_Cache_Frontend_File::MODE_AND or Zend_Cache_Frontend_File::MODE_OR
* - if MODE_AND, then all master files have to be touched to get a cache invalidation
* - if MODE_OR (default), then a single touched master file is enough to get a cache invalidation
*
* ====> (boolean) ignore_missing_master_files
* - if set to true, missing master files are ignored silently
* - if set to false (default), an exception is thrown if there is a missing master file
* @var array available options
*/
protected $_specificOptions = array(
'master_file' => null,
'master_files' => null,
'master_files_mode' => 'OR',
'ignore_missing_master_files' => false
);
/**
* Master file mtimes
*
* Array of int
*
* @var array
*/
private $_masterFile_mtimes = null;
/**
* Constructor
*
* @param array $options Associative array of options
* @throws Zend_Cache_Exception
* @return void
*/
public function __construct(array $options = array())
{
while (list($name, $value) = each($options)) {
$this->setOption($name, $value);
}
if (!isset($this->_specificOptions['master_files'])) {
Zend_Cache::throwException('master_files option must be set');
}
}
/**
* Change the master_files option
*
* @param array $masterFiles the complete paths and name of the master files
*/
public function setMasterFiles(array $masterFiles)
{
$this->_specificOptions['master_file'] = null; // to keep a compatibility
$this->_specificOptions['master_files'] = null;
$this->_masterFile_mtimes = array();
clearstatcache();
$i = 0;
foreach ($masterFiles as $masterFile) {
if (file_exists($masterFile)) {
$mtime = filemtime($masterFile);
} else {
$mtime = false;
}
if (!$this->_specificOptions['ignore_missing_master_files'] && !$mtime) {
Zend_Cache::throwException('Unable to read master_file : ' . $masterFile);
}
$this->_masterFile_mtimes[$i] = $mtime;
$this->_specificOptions['master_files'][$i] = $masterFile;
if ($i === 0) { // to keep a compatibility
$this->_specificOptions['master_file'] = $masterFile;
}
$i++;
}
}
/**
* Change the master_file option
*
* To keep the compatibility
*
* @deprecated
* @param string $masterFile the complete path and name of the master file
*/
public function setMasterFile($masterFile)
{
$this->setMasterFiles(array($masterFile));
}
/**
* Public frontend to set an option
*
* Just a wrapper to get a specific behaviour for master_file
*
* @param string $name Name of the option
* @param mixed $value Value of the option
* @throws Zend_Cache_Exception
* @return void
*/
public function setOption($name, $value)
{
if ($name == 'master_file') {
$this->setMasterFile($value);
} else if ($name == 'master_files') {
$this->setMasterFiles($value);
} else {
parent::setOption($name, $value);
}
}
/**
* Test if a cache is available for the given id and (if yes) return it (false else)
*
* @param string $id Cache id
* @param boolean $doNotTestCacheValidity If set to true, the cache validity won't be tested
* @param boolean $doNotUnserialize Do not serialize (even if automatic_serialization is true) => for internal use
* @return mixed|false Cached datas
*/
public function load($id, $doNotTestCacheValidity = false, $doNotUnserialize = false)
{
if (!$doNotTestCacheValidity) {
if ($this->test($id)) {
return parent::load($id, true, $doNotUnserialize);
}
return false;
}
return parent::load($id, true, $doNotUnserialize);
}
/**
* Test if a cache is available for the given id
*
* @param string $id Cache id
* @return int|false Last modified time of cache entry if it is available, false otherwise
*/
public function test($id)
{
$lastModified = parent::test($id);
if ($lastModified) {
if ($this->_specificOptions['master_files_mode'] == self::MODE_AND) {
// MODE_AND
foreach($this->_masterFile_mtimes as $masterFileMTime) {
if ($masterFileMTime) {
if ($lastModified > $masterFileMTime) {
return $lastModified;
}
}
}
} else {
// MODE_OR
$res = true;
foreach($this->_masterFile_mtimes as $masterFileMTime) {
if ($masterFileMTime) {
if ($lastModified <= $masterFileMTime) {
return false;
}
}
}
return $lastModified;
}
}
return false;
}
}

View File

@ -1,179 +0,0 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Cache
* @subpackage Zend_Cache_Frontend
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Function.php 23775 2011-03-01 17:25:24Z ralph $
*/
/**
* @see Zend_Cache_Core
*/
require_once 'Zend/Cache/Core.php';
/**
* @package Zend_Cache
* @subpackage Zend_Cache_Frontend
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Cache_Frontend_Function extends Zend_Cache_Core
{
/**
* This frontend specific options
*
* ====> (boolean) cache_by_default :
* - if true, function calls will be cached by default
*
* ====> (array) cached_functions :
* - an array of function names which will be cached (even if cache_by_default = false)
*
* ====> (array) non_cached_functions :
* - an array of function names which won't be cached (even if cache_by_default = true)
*
* @var array options
*/
protected $_specificOptions = array(
'cache_by_default' => true,
'cached_functions' => array(),
'non_cached_functions' => array()
);
/**
* Constructor
*
* @param array $options Associative array of options
* @return void
*/
public function __construct(array $options = array())
{
while (list($name, $value) = each($options)) {
$this->setOption($name, $value);
}
$this->setOption('automatic_serialization', true);
}
/**
* Main method : call the specified function or get the result from cache
*
* @param callback $callback A valid callback
* @param array $parameters Function parameters
* @param array $tags Cache tags
* @param int $specificLifetime If != false, set a specific lifetime for this cache record (null => infinite lifetime)
* @param int $priority integer between 0 (very low priority) and 10 (maximum priority) used by some particular backends
* @return mixed Result
*/
public function call($callback, array $parameters = array(), $tags = array(), $specificLifetime = false, $priority = 8)
{
if (!is_callable($callback, true, $name)) {
Zend_Cache::throwException('Invalid callback');
}
$cacheBool1 = $this->_specificOptions['cache_by_default'];
$cacheBool2 = in_array($name, $this->_specificOptions['cached_functions']);
$cacheBool3 = in_array($name, $this->_specificOptions['non_cached_functions']);
$cache = (($cacheBool1 || $cacheBool2) && (!$cacheBool3));
if (!$cache) {
// Caching of this callback is disabled
return call_user_func_array($callback, $parameters);
}
$id = $this->_makeId($callback, $parameters);
if ( ($rs = $this->load($id)) && isset($rs[0], $rs[1])) {
// A cache is available
$output = $rs[0];
$return = $rs[1];
} else {
// A cache is not available (or not valid for this frontend)
ob_start();
ob_implicit_flush(false);
$return = call_user_func_array($callback, $parameters);
$output = ob_get_clean();
$data = array($output, $return);
$this->save($data, $id, $tags, $specificLifetime, $priority);
}
echo $output;
return $return;
}
/**
* ZF-9970
*
* @deprecated
*/
private function _makeId($callback, array $args)
{
return $this->makeId($callback, $args);
}
/**
* Make a cache id from the function name and parameters
*
* @param callback $callback A valid callback
* @param array $args Function parameters
* @throws Zend_Cache_Exception
* @return string Cache id
*/
public function makeId($callback, array $args = array())
{
if (!is_callable($callback, true, $name)) {
Zend_Cache::throwException('Invalid callback');
}
// functions, methods and classnames are case-insensitive
$name = strtolower($name);
// generate a unique id for object callbacks
if (is_object($callback)) { // Closures & __invoke
$object = $callback;
} elseif (isset($callback[0])) { // array($object, 'method')
$object = $callback[0];
}
if (isset($object)) {
try {
$tmp = @serialize($callback);
} catch (Exception $e) {
Zend_Cache::throwException($e->getMessage());
}
if (!$tmp) {
$lastErr = error_get_last();
Zend_Cache::throwException("Can't serialize callback object to generate id: {$lastErr['message']}");
}
$name.= '__' . $tmp;
}
// generate a unique id for arguments
$argsStr = '';
if ($args) {
try {
$argsStr = @serialize(array_values($args));
} catch (Exception $e) {
Zend_Cache::throwException($e->getMessage());
}
if (!$argsStr) {
$lastErr = error_get_last();
throw Zend_Cache::throwException("Can't serialize arguments to generate id: {$lastErr['message']}");
}
}
return md5($name . $argsStr);
}
}

View File

@ -1,105 +0,0 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Cache
* @subpackage Zend_Cache_Frontend
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Output.php 23775 2011-03-01 17:25:24Z ralph $
*/
/**
* @see Zend_Cache_Core
*/
require_once 'Zend/Cache/Core.php';
/**
* @package Zend_Cache
* @subpackage Zend_Cache_Frontend
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Cache_Frontend_Output extends Zend_Cache_Core
{
private $_idStack = array();
/**
* Constructor
*
* @param array $options Associative array of options
* @return void
*/
public function __construct(array $options = array())
{
parent::__construct($options);
$this->_idStack = array();
}
/**
* Start the cache
*
* @param string $id Cache id
* @param boolean $doNotTestCacheValidity If set to true, the cache validity won't be tested
* @param boolean $echoData If set to true, datas are sent to the browser if the cache is hit (simpy returned else)
* @return mixed True if the cache is hit (false else) with $echoData=true (default) ; string else (datas)
*/
public function start($id, $doNotTestCacheValidity = false, $echoData = true)
{
$data = $this->load($id, $doNotTestCacheValidity);
if ($data !== false) {
if ( $echoData ) {
echo($data);
return true;
} else {
return $data;
}
}
ob_start();
ob_implicit_flush(false);
$this->_idStack[] = $id;
return false;
}
/**
* Stop the cache
*
* @param array $tags Tags array
* @param int $specificLifetime If != false, set a specific lifetime for this cache record (null => infinite lifetime)
* @param string $forcedDatas If not null, force written datas with this
* @param boolean $echoData If set to true, datas are sent to the browser
* @param int $priority integer between 0 (very low priority) and 10 (maximum priority) used by some particular backends
* @return void
*/
public function end($tags = array(), $specificLifetime = false, $forcedDatas = null, $echoData = true, $priority = 8)
{
if ($forcedDatas === null) {
$data = ob_get_clean();
} else {
$data =& $forcedDatas;
}
$id = array_pop($this->_idStack);
if ($id === null) {
Zend_Cache::throwException('use of end() without a start()');
}
$this->save($data, $id, $tags, $specificLifetime, $priority);
if ($echoData) {
echo($data);
}
}
}

View File

@ -1,404 +0,0 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Cache
* @subpackage Zend_Cache_Frontend
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Page.php 23775 2011-03-01 17:25:24Z ralph $
*/
/**
* @see Zend_Cache_Core
*/
require_once 'Zend/Cache/Core.php';
/**
* @package Zend_Cache
* @subpackage Zend_Cache_Frontend
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Cache_Frontend_Page extends Zend_Cache_Core
{
/**
* This frontend specific options
*
* ====> (boolean) http_conditional :
* - if true, http conditional mode is on
* WARNING : http_conditional OPTION IS NOT IMPLEMENTED FOR THE MOMENT (TODO)
*
* ====> (boolean) debug_header :
* - if true, a debug text is added before each cached pages
*
* ====> (boolean) content_type_memorization :
* - deprecated => use memorize_headers instead
* - if the Content-Type header is sent after the cache was started, the
* corresponding value can be memorized and replayed when the cache is hit
* (if false (default), the frontend doesn't take care of Content-Type header)
*
* ====> (array) memorize_headers :
* - an array of strings corresponding to some HTTP headers name. Listed headers
* will be stored with cache datas and "replayed" when the cache is hit
*
* ====> (array) default_options :
* - an associative array of default options :
* - (boolean) cache : cache is on by default if true
* - (boolean) cacheWithXXXVariables (XXXX = 'Get', 'Post', 'Session', 'Files' or 'Cookie') :
* if true, cache is still on even if there are some variables in this superglobal array
* if false, cache is off if there are some variables in this superglobal array
* - (boolean) makeIdWithXXXVariables (XXXX = 'Get', 'Post', 'Session', 'Files' or 'Cookie') :
* if true, we have to use the content of this superglobal array to make a cache id
* if false, the cache id won't be dependent of the content of this superglobal array
* - (int) specific_lifetime : cache specific lifetime
* (false => global lifetime is used, null => infinite lifetime,
* integer => this lifetime is used), this "lifetime" is probably only
* usefull when used with "regexps" array
* - (array) tags : array of tags (strings)
* - (int) priority : integer between 0 (very low priority) and 10 (maximum priority) used by
* some particular backends
*
* ====> (array) regexps :
* - an associative array to set options only for some REQUEST_URI
* - keys are (pcre) regexps
* - values are associative array with specific options to set if the regexp matchs on $_SERVER['REQUEST_URI']
* (see default_options for the list of available options)
* - if several regexps match the $_SERVER['REQUEST_URI'], only the last one will be used
*
* @var array options
*/
protected $_specificOptions = array(
'http_conditional' => false,
'debug_header' => false,
'content_type_memorization' => false,
'memorize_headers' => array(),
'default_options' => array(
'cache_with_get_variables' => false,
'cache_with_post_variables' => false,
'cache_with_session_variables' => false,
'cache_with_files_variables' => false,
'cache_with_cookie_variables' => false,
'make_id_with_get_variables' => true,
'make_id_with_post_variables' => true,
'make_id_with_session_variables' => true,
'make_id_with_files_variables' => true,
'make_id_with_cookie_variables' => true,
'cache' => true,
'specific_lifetime' => false,
'tags' => array(),
'priority' => null
),
'regexps' => array()
);
/**
* Internal array to store some options
*
* @var array associative array of options
*/
protected $_activeOptions = array();
/**
* If true, the page won't be cached
*
* @var boolean
*/
protected $_cancel = false;
/**
* Constructor
*
* @param array $options Associative array of options
* @param boolean $doNotTestCacheValidity If set to true, the cache validity won't be tested
* @throws Zend_Cache_Exception
* @return void
*/
public function __construct(array $options = array())
{
while (list($name, $value) = each($options)) {
$name = strtolower($name);
switch ($name) {
case 'regexps':
$this->_setRegexps($value);
break;
case 'default_options':
$this->_setDefaultOptions($value);
break;
case 'content_type_memorization':
$this->_setContentTypeMemorization($value);
break;
default:
$this->setOption($name, $value);
}
}
if (isset($this->_specificOptions['http_conditional'])) {
if ($this->_specificOptions['http_conditional']) {
Zend_Cache::throwException('http_conditional is not implemented for the moment !');
}
}
$this->setOption('automatic_serialization', true);
}
/**
* Specific setter for the 'default_options' option (with some additional tests)
*
* @param array $options Associative array
* @throws Zend_Cache_Exception
* @return void
*/
protected function _setDefaultOptions($options)
{
if (!is_array($options)) {
Zend_Cache::throwException('default_options must be an array !');
}
foreach ($options as $key=>$value) {
if (!is_string($key)) {
Zend_Cache::throwException("invalid option [$key] !");
}
$key = strtolower($key);
if (isset($this->_specificOptions['default_options'][$key])) {
$this->_specificOptions['default_options'][$key] = $value;
}
}
}
/**
* Set the deprecated contentTypeMemorization option
*
* @param boolean $value value
* @return void
* @deprecated
*/
protected function _setContentTypeMemorization($value)
{
$found = null;
foreach ($this->_specificOptions['memorize_headers'] as $key => $value) {
if (strtolower($value) == 'content-type') {
$found = $key;
}
}
if ($value) {
if (!$found) {
$this->_specificOptions['memorize_headers'][] = 'Content-Type';
}
} else {
if ($found) {
unset($this->_specificOptions['memorize_headers'][$found]);
}
}
}
/**
* Specific setter for the 'regexps' option (with some additional tests)
*
* @param array $options Associative array
* @throws Zend_Cache_Exception
* @return void
*/
protected function _setRegexps($regexps)
{
if (!is_array($regexps)) {
Zend_Cache::throwException('regexps option must be an array !');
}
foreach ($regexps as $regexp=>$conf) {
if (!is_array($conf)) {
Zend_Cache::throwException('regexps option must be an array of arrays !');
}
$validKeys = array_keys($this->_specificOptions['default_options']);
foreach ($conf as $key=>$value) {
if (!is_string($key)) {
Zend_Cache::throwException("unknown option [$key] !");
}
$key = strtolower($key);
if (!in_array($key, $validKeys)) {
unset($regexps[$regexp][$key]);
}
}
}
$this->setOption('regexps', $regexps);
}
/**
* Start the cache
*
* @param string $id (optional) A cache id (if you set a value here, maybe you have to use Output frontend instead)
* @param boolean $doNotDie For unit testing only !
* @return boolean True if the cache is hit (false else)
*/
public function start($id = false, $doNotDie = false)
{
$this->_cancel = false;
$lastMatchingRegexp = null;
if (isset($_SERVER['REQUEST_URI'])) {
foreach ($this->_specificOptions['regexps'] as $regexp => $conf) {
if (preg_match("`$regexp`", $_SERVER['REQUEST_URI'])) {
$lastMatchingRegexp = $regexp;
}
}
}
$this->_activeOptions = $this->_specificOptions['default_options'];
if ($lastMatchingRegexp !== null) {
$conf = $this->_specificOptions['regexps'][$lastMatchingRegexp];
foreach ($conf as $key=>$value) {
$this->_activeOptions[$key] = $value;
}
}
if (!($this->_activeOptions['cache'])) {
return false;
}
if (!$id) {
$id = $this->_makeId();
if (!$id) {
return false;
}
}
$array = $this->load($id);
if ($array !== false) {
$data = $array['data'];
$headers = $array['headers'];
if (!headers_sent()) {
foreach ($headers as $key=>$headerCouple) {
$name = $headerCouple[0];
$value = $headerCouple[1];
header("$name: $value");
}
}
if ($this->_specificOptions['debug_header']) {
echo 'DEBUG HEADER : This is a cached page !';
}
echo $data;
if ($doNotDie) {
return true;
}
die();
}
ob_start(array($this, '_flush'));
ob_implicit_flush(false);
return false;
}
/**
* Cancel the current caching process
*/
public function cancel()
{
$this->_cancel = true;
}
/**
* callback for output buffering
* (shouldn't really be called manually)
*
* @param string $data Buffered output
* @return string Data to send to browser
*/
public function _flush($data)
{
if ($this->_cancel) {
return $data;
}
$contentType = null;
$storedHeaders = array();
$headersList = headers_list();
foreach($this->_specificOptions['memorize_headers'] as $key=>$headerName) {
foreach ($headersList as $headerSent) {
$tmp = explode(':', $headerSent);
$headerSentName = trim(array_shift($tmp));
if (strtolower($headerName) == strtolower($headerSentName)) {
$headerSentValue = trim(implode(':', $tmp));
$storedHeaders[] = array($headerSentName, $headerSentValue);
}
}
}
$array = array(
'data' => $data,
'headers' => $storedHeaders
);
$this->save($array, null, $this->_activeOptions['tags'], $this->_activeOptions['specific_lifetime'], $this->_activeOptions['priority']);
return $data;
}
/**
* Make an id depending on REQUEST_URI and superglobal arrays (depending on options)
*
* @return mixed|false a cache id (string), false if the cache should have not to be used
*/
protected function _makeId()
{
$tmp = $_SERVER['REQUEST_URI'];
$array = explode('?', $tmp, 2);
$tmp = $array[0];
foreach (array('Get', 'Post', 'Session', 'Files', 'Cookie') as $arrayName) {
$tmp2 = $this->_makePartialId($arrayName, $this->_activeOptions['cache_with_' . strtolower($arrayName) . '_variables'], $this->_activeOptions['make_id_with_' . strtolower($arrayName) . '_variables']);
if ($tmp2===false) {
return false;
}
$tmp = $tmp . $tmp2;
}
return md5($tmp);
}
/**
* Make a partial id depending on options
*
* @param string $arrayName Superglobal array name
* @param bool $bool1 If true, cache is still on even if there are some variables in the superglobal array
* @param bool $bool2 If true, we have to use the content of the superglobal array to make a partial id
* @return mixed|false Partial id (string) or false if the cache should have not to be used
*/
protected function _makePartialId($arrayName, $bool1, $bool2)
{
switch ($arrayName) {
case 'Get':
$var = $_GET;
break;
case 'Post':
$var = $_POST;
break;
case 'Session':
if (isset($_SESSION)) {
$var = $_SESSION;
} else {
$var = null;
}
break;
case 'Cookie':
if (isset($_COOKIE)) {
$var = $_COOKIE;
} else {
$var = null;
}
break;
case 'Files':
$var = $_FILES;
break;
default:
return false;
}
if ($bool1) {
if ($bool2) {
return serialize($var);
}
return '';
}
if (count($var) > 0) {
return false;
}
return '';
}
}

View File

@ -1,298 +0,0 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Cache
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Manager.php 23775 2011-03-01 17:25:24Z ralph $
*/
/** @see Zend_Cache_Exception */
require_once 'Zend/Cache/Exception.php';
/** @see Zend_Cache */
require_once 'Zend/Cache.php';
/**
* @category Zend
* @package Zend_Cache
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Cache_Manager
{
/**
* Constant holding reserved name for default Page Cache
*/
const PAGECACHE = 'page';
/**
* Constant holding reserved name for default Page Tag Cache
*/
const PAGETAGCACHE = 'pagetag';
/**
* Array of caches stored by the Cache Manager instance
*
* @var array
*/
protected $_caches = array();
/**
* Array of ready made configuration templates for lazy
* loading caches.
*
* @var array
*/
protected $_optionTemplates = array(
// Simple Common Default
'default' => array(
'frontend' => array(
'name' => 'Core',
'options' => array(
'automatic_serialization' => true,
),
),
'backend' => array(
'name' => 'File',
'options' => array(
// use system temp dir by default of file backend
// 'cache_dir' => '../cache',
),
),
),
// Static Page HTML Cache
'page' => array(
'frontend' => array(
'name' => 'Capture',
'options' => array(
'ignore_user_abort' => true,
),
),
'backend' => array(
'name' => 'Static',
'options' => array(
'public_dir' => '../public',
),
),
),
// Tag Cache
'pagetag' => array(
'frontend' => array(
'name' => 'Core',
'options' => array(
'automatic_serialization' => true,
'lifetime' => null
),
),
'backend' => array(
'name' => 'File',
'options' => array(
// use system temp dir by default of file backend
// 'cache_dir' => '../cache',
// use default umask of file backend
// 'cache_file_umask' => 0644
),
),
),
);
/**
* Set a new cache for the Cache Manager to contain
*
* @param string $name
* @param Zend_Cache_Core $cache
* @return Zend_Cache_Manager
*/
public function setCache($name, Zend_Cache_Core $cache)
{
$this->_caches[$name] = $cache;
return $this;
}
/**
* Check if the Cache Manager contains the named cache object, or a named
* configuration template to lazy load the cache object
*
* @param string $name
* @return bool
*/
public function hasCache($name)
{
if (isset($this->_caches[$name])
|| $this->hasCacheTemplate($name)
) {
return true;
}
return false;
}
/**
* Fetch the named cache object, or instantiate and return a cache object
* using a named configuration template
*
* @param string $name
* @return Zend_Cache_Core
*/
public function getCache($name)
{
if (isset($this->_caches[$name])) {
return $this->_caches[$name];
}
if (isset($this->_optionTemplates[$name])) {
if ($name == self::PAGECACHE
&& (!isset($this->_optionTemplates[$name]['backend']['options']['tag_cache'])
|| !$this->_optionTemplates[$name]['backend']['options']['tag_cache'] instanceof Zend_Cache_Core)
) {
$this->_optionTemplates[$name]['backend']['options']['tag_cache']
= $this->getCache(self::PAGETAGCACHE);
}
$this->_caches[$name] = Zend_Cache::factory(
$this->_optionTemplates[$name]['frontend']['name'],
$this->_optionTemplates[$name]['backend']['name'],
isset($this->_optionTemplates[$name]['frontend']['options']) ? $this->_optionTemplates[$name]['frontend']['options'] : array(),
isset($this->_optionTemplates[$name]['backend']['options']) ? $this->_optionTemplates[$name]['backend']['options'] : array(),
isset($this->_optionTemplates[$name]['frontend']['customFrontendNaming']) ? $this->_optionTemplates[$name]['frontend']['customFrontendNaming'] : false,
isset($this->_optionTemplates[$name]['backend']['customBackendNaming']) ? $this->_optionTemplates[$name]['backend']['customBackendNaming'] : false,
isset($this->_optionTemplates[$name]['frontendBackendAutoload']) ? $this->_optionTemplates[$name]['frontendBackendAutoload'] : false
);
return $this->_caches[$name];
}
}
/**
* Fetch all available caches
*
* @return array An array of all available caches with it's names as key
*/
public function getCaches()
{
$caches = $this->_caches;
foreach ($this->_optionTemplates as $name => $tmp) {
if (!isset($caches[$name])) {
$caches[$name] = $this->getCache($name);
}
}
return $caches;
}
/**
* Set a named configuration template from which a cache object can later
* be lazy loaded
*
* @param string $name
* @param array $options
* @return Zend_Cache_Manager
*/
public function setCacheTemplate($name, $options)
{
if ($options instanceof Zend_Config) {
$options = $options->toArray();
} elseif (!is_array($options)) {
require_once 'Zend/Cache/Exception.php';
throw new Zend_Cache_Exception('Options passed must be in'
. ' an associative array or instance of Zend_Config');
}
$this->_optionTemplates[$name] = $options;
return $this;
}
/**
* Check if the named configuration template
*
* @param string $name
* @return bool
*/
public function hasCacheTemplate($name)
{
if (isset($this->_optionTemplates[$name])) {
return true;
}
return false;
}
/**
* Get the named configuration template
*
* @param string $name
* @return array
*/
public function getCacheTemplate($name)
{
if (isset($this->_optionTemplates[$name])) {
return $this->_optionTemplates[$name];
}
}
/**
* Pass an array containing changes to be applied to a named
* configuration
* template
*
* @param string $name
* @param array $options
* @return Zend_Cache_Manager
* @throws Zend_Cache_Exception for invalid options format or if option templates do not have $name
*/
public function setTemplateOptions($name, $options)
{
if ($options instanceof Zend_Config) {
$options = $options->toArray();
} elseif (!is_array($options)) {
require_once 'Zend/Cache/Exception.php';
throw new Zend_Cache_Exception('Options passed must be in'
. ' an associative array or instance of Zend_Config');
}
if (!isset($this->_optionTemplates[$name])) {
throw new Zend_Cache_Exception('A cache configuration template'
. 'does not exist with the name "' . $name . '"');
}
$this->_optionTemplates[$name]
= $this->_mergeOptions($this->_optionTemplates[$name], $options);
return $this;
}
/**
* Simple method to merge two configuration arrays
*
* @param array $current
* @param array $options
* @return array
*/
protected function _mergeOptions(array $current, array $options)
{
if (isset($options['frontend']['name'])) {
$current['frontend']['name'] = $options['frontend']['name'];
}
if (isset($options['backend']['name'])) {
$current['backend']['name'] = $options['backend']['name'];
}
if (isset($options['frontend']['options'])) {
foreach ($options['frontend']['options'] as $key=>$value) {
$current['frontend']['options'][$key] = $value;
}
}
if (isset($options['backend']['options'])) {
foreach ($options['backend']['options'] as $key=>$value) {
$current['backend']['options'][$key] = $value;
}
}
return $current;
}
}

View File

@ -1,96 +0,0 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Exception.php 23775 2011-03-01 17:25:24Z ralph $
*/
/**
* @category Zend
* @package Zend
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Exception extends Exception
{
/**
* @var null|Exception
*/
private $_previous = null;
/**
* Construct the exception
*
* @param string $msg
* @param int $code
* @param Exception $previous
* @return void
*/
public function __construct($msg = '', $code = 0, Exception $previous = null)
{
if (version_compare(PHP_VERSION, '5.3.0', '<')) {
parent::__construct($msg, (int) $code);
$this->_previous = $previous;
} else {
parent::__construct($msg, (int) $code, $previous);
}
}
/**
* Overloading
*
* For PHP < 5.3.0, provides access to the getPrevious() method.
*
* @param string $method
* @param array $args
* @return mixed
*/
public function __call($method, array $args)
{
if ('getprevious' == strtolower($method)) {
return $this->_getPrevious();
}
return null;
}
/**
* String representation of the exception
*
* @return string
*/
public function __toString()
{
if (version_compare(PHP_VERSION, '5.3.0', '<')) {
if (null !== ($e = $this->getPrevious())) {
return $e->__toString()
. "\n\nNext "
. parent::__toString();
}
}
return parent::__toString();
}
/**
* Returns previous Exception
*
* @return Exception|null
*/
protected function _getPrevious()
{
return $this->_previous;
}
}

View File

@ -1,27 +0,0 @@
Copyright (c) 2005-2008, Zend Technologies USA, Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of Zend Technologies USA, Inc. nor the names of its
contributors may be used to endorse or promote products derived from this
software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@ -1,329 +0,0 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Loader
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Loader.php 23775 2011-03-01 17:25:24Z ralph $
*/
/**
* Static methods for loading classes and files.
*
* @category Zend
* @package Zend_Loader
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Loader
{
/**
* Loads a class from a PHP file. The filename must be formatted
* as "$class.php".
*
* If $dirs is a string or an array, it will search the directories
* in the order supplied, and attempt to load the first matching file.
*
* If $dirs is null, it will split the class name at underscores to
* generate a path hierarchy (e.g., "Zend_Example_Class" will map
* to "Zend/Example/Class.php").
*
* If the file was not found in the $dirs, or if no $dirs were specified,
* it will attempt to load it from PHP's include_path.
*
* @param string $class - The full class name of a Zend component.
* @param string|array $dirs - OPTIONAL Either a path or an array of paths
* to search.
* @return void
* @throws Zend_Exception
*/
public static function loadClass($class, $dirs = null)
{
if (class_exists($class, false) || interface_exists($class, false)) {
return;
}
if ((null !== $dirs) && !is_string($dirs) && !is_array($dirs)) {
require_once 'Zend/Exception.php';
throw new Zend_Exception('Directory argument must be a string or an array');
}
// Autodiscover the path from the class name
// Implementation is PHP namespace-aware, and based on
// Framework Interop Group reference implementation:
// http://groups.google.com/group/php-standards/web/psr-0-final-proposal
$className = ltrim($class, '\\');
$file = '';
$namespace = '';
if ($lastNsPos = strripos($className, '\\')) {
$namespace = substr($className, 0, $lastNsPos);
$className = substr($className, $lastNsPos + 1);
$file = str_replace('\\', DIRECTORY_SEPARATOR, $namespace) . DIRECTORY_SEPARATOR;
}
$file .= str_replace('_', DIRECTORY_SEPARATOR, $className) . '.php';
if (!empty($dirs)) {
// use the autodiscovered path
$dirPath = dirname($file);
if (is_string($dirs)) {
$dirs = explode(PATH_SEPARATOR, $dirs);
}
foreach ($dirs as $key => $dir) {
if ($dir == '.') {
$dirs[$key] = $dirPath;
} else {
$dir = rtrim($dir, '\\/');
$dirs[$key] = $dir . DIRECTORY_SEPARATOR . $dirPath;
}
}
$file = basename($file);
self::loadFile($file, $dirs, true);
} else {
self::loadFile($file, null, true);
}
if (!class_exists($class, false) && !interface_exists($class, false)) {
require_once 'Zend/Exception.php';
throw new Zend_Exception("File \"$file\" does not exist or class \"$class\" was not found in the file");
}
}
/**
* Loads a PHP file. This is a wrapper for PHP's include() function.
*
* $filename must be the complete filename, including any
* extension such as ".php". Note that a security check is performed that
* does not permit extended characters in the filename. This method is
* intended for loading Zend Framework files.
*
* If $dirs is a string or an array, it will search the directories
* in the order supplied, and attempt to load the first matching file.
*
* If the file was not found in the $dirs, or if no $dirs were specified,
* it will attempt to load it from PHP's include_path.
*
* If $once is TRUE, it will use include_once() instead of include().
*
* @param string $filename
* @param string|array $dirs - OPTIONAL either a path or array of paths
* to search.
* @param boolean $once
* @return boolean
* @throws Zend_Exception
*/
public static function loadFile($filename, $dirs = null, $once = false)
{
self::_securityCheck($filename);
/**
* Search in provided directories, as well as include_path
*/
$incPath = false;
if (!empty($dirs) && (is_array($dirs) || is_string($dirs))) {
if (is_array($dirs)) {
$dirs = implode(PATH_SEPARATOR, $dirs);
}
$incPath = get_include_path();
set_include_path($dirs . PATH_SEPARATOR . $incPath);
}
/**
* Try finding for the plain filename in the include_path.
*/
if ($once) {
include_once $filename;
} else {
include $filename;
}
/**
* If searching in directories, reset include_path
*/
if ($incPath) {
set_include_path($incPath);
}
return true;
}
/**
* Returns TRUE if the $filename is readable, or FALSE otherwise.
* This function uses the PHP include_path, where PHP's is_readable()
* does not.
*
* Note from ZF-2900:
* If you use custom error handler, please check whether return value
* from error_reporting() is zero or not.
* At mark of fopen() can not suppress warning if the handler is used.
*
* @param string $filename
* @return boolean
*/
public static function isReadable($filename)
{
if (is_readable($filename)) {
// Return early if the filename is readable without needing the
// include_path
return true;
}
if (strtoupper(substr(PHP_OS, 0, 3)) == 'WIN'
&& preg_match('/^[a-z]:/i', $filename)
) {
// If on windows, and path provided is clearly an absolute path,
// return false immediately
return false;
}
foreach (self::explodeIncludePath() as $path) {
if ($path == '.') {
if (is_readable($filename)) {
return true;
}
continue;
}
$file = $path . '/' . $filename;
if (is_readable($file)) {
return true;
}
}
return false;
}
/**
* Explode an include path into an array
*
* If no path provided, uses current include_path. Works around issues that
* occur when the path includes stream schemas.
*
* @param string|null $path
* @return array
*/
public static function explodeIncludePath($path = null)
{
if (null === $path) {
$path = get_include_path();
}
if (PATH_SEPARATOR == ':') {
// On *nix systems, include_paths which include paths with a stream
// schema cannot be safely explode'd, so we have to be a bit more
// intelligent in the approach.
$paths = preg_split('#:(?!//)#', $path);
} else {
$paths = explode(PATH_SEPARATOR, $path);
}
return $paths;
}
/**
* spl_autoload() suitable implementation for supporting class autoloading.
*
* Attach to spl_autoload() using the following:
* <code>
* spl_autoload_register(array('Zend_Loader', 'autoload'));
* </code>
*
* @deprecated Since 1.8.0
* @param string $class
* @return string|false Class name on success; false on failure
*/
public static function autoload($class)
{
trigger_error(__CLASS__ . '::' . __METHOD__ . ' is deprecated as of 1.8.0 and will be removed with 2.0.0; use Zend_Loader_Autoloader instead', E_USER_NOTICE);
try {
@self::loadClass($class);
return $class;
} catch (Exception $e) {
return false;
}
}
/**
* Register {@link autoload()} with spl_autoload()
*
* @deprecated Since 1.8.0
* @param string $class (optional)
* @param boolean $enabled (optional)
* @return void
* @throws Zend_Exception if spl_autoload() is not found
* or if the specified class does not have an autoload() method.
*/
public static function registerAutoload($class = 'Zend_Loader', $enabled = true)
{
trigger_error(__CLASS__ . '::' . __METHOD__ . ' is deprecated as of 1.8.0 and will be removed with 2.0.0; use Zend_Loader_Autoloader instead', E_USER_NOTICE);
require_once 'Zend/Loader/Autoloader.php';
$autoloader = Zend_Loader_Autoloader::getInstance();
$autoloader->setFallbackAutoloader(true);
if ('Zend_Loader' != $class) {
self::loadClass($class);
$methods = get_class_methods($class);
if (!in_array('autoload', (array) $methods)) {
require_once 'Zend/Exception.php';
throw new Zend_Exception("The class \"$class\" does not have an autoload() method");
}
$callback = array($class, 'autoload');
if ($enabled) {
$autoloader->pushAutoloader($callback);
} else {
$autoloader->removeAutoloader($callback);
}
}
}
/**
* Ensure that filename does not contain exploits
*
* @param string $filename
* @return void
* @throws Zend_Exception
*/
protected static function _securityCheck($filename)
{
/**
* Security check
*/
if (preg_match('/[^a-z0-9\\/\\\\_.:-]/i', $filename)) {
require_once 'Zend/Exception.php';
throw new Zend_Exception('Security check: Illegal character in filename');
}
}
/**
* Attempt to include() the file.
*
* include() is not prefixed with the @ operator because if
* the file is loaded and contains a parse error, execution
* will halt silently and this is difficult to debug.
*
* Always set display_errors = Off on production servers!
*
* @param string $filespec
* @param boolean $once
* @return boolean
* @deprecated Since 1.5.0; use loadFile() instead
*/
protected static function _includeFile($filespec, $once = false)
{
if ($once) {
return include_once $filespec;
} else {
return include $filespec ;
}
}
}

View File

@ -1,589 +0,0 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Loader
* @subpackage Autoloader
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @version $Id: Autoloader.php 23953 2011-05-03 05:47:39Z ralph $
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
/** Zend_Loader */
require_once 'Zend/Loader.php';
/**
* Autoloader stack and namespace autoloader
*
* @uses Zend_Loader_Autoloader
* @package Zend_Loader
* @subpackage Autoloader
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Loader_Autoloader
{
/**
* @var Zend_Loader_Autoloader Singleton instance
*/
protected static $_instance;
/**
* @var array Concrete autoloader callback implementations
*/
protected $_autoloaders = array();
/**
* @var array Default autoloader callback
*/
protected $_defaultAutoloader = array('Zend_Loader', 'loadClass');
/**
* @var bool Whether or not to act as a fallback autoloader
*/
protected $_fallbackAutoloader = false;
/**
* @var array Callback for internal autoloader implementation
*/
protected $_internalAutoloader;
/**
* @var array Supported namespaces 'Zend' and 'ZendX' by default.
*/
protected $_namespaces = array(
'Zend_' => true,
'ZendX_' => true,
);
/**
* @var array Namespace-specific autoloaders
*/
protected $_namespaceAutoloaders = array();
/**
* @var bool Whether or not to suppress file not found warnings
*/
protected $_suppressNotFoundWarnings = false;
/**
* @var null|string
*/
protected $_zfPath;
/**
* Retrieve singleton instance
*
* @return Zend_Loader_Autoloader
*/
public static function getInstance()
{
if (null === self::$_instance) {
self::$_instance = new self();
}
return self::$_instance;
}
/**
* Reset the singleton instance
*
* @return void
*/
public static function resetInstance()
{
self::$_instance = null;
}
/**
* Autoload a class
*
* @param string $class
* @return bool
*/
public static function autoload($class)
{
$self = self::getInstance();
foreach ($self->getClassAutoloaders($class) as $autoloader) {
if ($autoloader instanceof Zend_Loader_Autoloader_Interface) {
if ($autoloader->autoload($class)) {
return true;
}
} elseif (is_array($autoloader)) {
if (call_user_func($autoloader, $class)) {
return true;
}
} elseif (is_string($autoloader) || is_callable($autoloader)) {
if ($autoloader($class)) {
return true;
}
}
}
return false;
}
/**
* Set the default autoloader implementation
*
* @param string|array $callback PHP callback
* @return void
*/
public function setDefaultAutoloader($callback)
{
if (!is_callable($callback)) {
throw new Zend_Loader_Exception('Invalid callback specified for default autoloader');
}
$this->_defaultAutoloader = $callback;
return $this;
}
/**
* Retrieve the default autoloader callback
*
* @return string|array PHP Callback
*/
public function getDefaultAutoloader()
{
return $this->_defaultAutoloader;
}
/**
* Set several autoloader callbacks at once
*
* @param array $autoloaders Array of PHP callbacks (or Zend_Loader_Autoloader_Interface implementations) to act as autoloaders
* @return Zend_Loader_Autoloader
*/
public function setAutoloaders(array $autoloaders)
{
$this->_autoloaders = $autoloaders;
return $this;
}
/**
* Get attached autoloader implementations
*
* @return array
*/
public function getAutoloaders()
{
return $this->_autoloaders;
}
/**
* Return all autoloaders for a given namespace
*
* @param string $namespace
* @return array
*/
public function getNamespaceAutoloaders($namespace)
{
$namespace = (string) $namespace;
if (!array_key_exists($namespace, $this->_namespaceAutoloaders)) {
return array();
}
return $this->_namespaceAutoloaders[$namespace];
}
/**
* Register a namespace to autoload
*
* @param string|array $namespace
* @return Zend_Loader_Autoloader
*/
public function registerNamespace($namespace)
{
if (is_string($namespace)) {
$namespace = (array) $namespace;
} elseif (!is_array($namespace)) {
throw new Zend_Loader_Exception('Invalid namespace provided');
}
foreach ($namespace as $ns) {
if (!isset($this->_namespaces[$ns])) {
$this->_namespaces[$ns] = true;
}
}
return $this;
}
/**
* Unload a registered autoload namespace
*
* @param string|array $namespace
* @return Zend_Loader_Autoloader
*/
public function unregisterNamespace($namespace)
{
if (is_string($namespace)) {
$namespace = (array) $namespace;
} elseif (!is_array($namespace)) {
throw new Zend_Loader_Exception('Invalid namespace provided');
}
foreach ($namespace as $ns) {
if (isset($this->_namespaces[$ns])) {
unset($this->_namespaces[$ns]);
}
}
return $this;
}
/**
* Get a list of registered autoload namespaces
*
* @return array
*/
public function getRegisteredNamespaces()
{
return array_keys($this->_namespaces);
}
public function setZfPath($spec, $version = 'latest')
{
$path = $spec;
if (is_array($spec)) {
if (!isset($spec['path'])) {
throw new Zend_Loader_Exception('No path specified for ZF');
}
$path = $spec['path'];
if (isset($spec['version'])) {
$version = $spec['version'];
}
}
$this->_zfPath = $this->_getVersionPath($path, $version);
set_include_path(implode(PATH_SEPARATOR, array(
$this->_zfPath,
get_include_path(),
)));
return $this;
}
public function getZfPath()
{
return $this->_zfPath;
}
/**
* Get or set the value of the "suppress not found warnings" flag
*
* @param null|bool $flag
* @return bool|Zend_Loader_Autoloader Returns boolean if no argument is passed, object instance otherwise
*/
public function suppressNotFoundWarnings($flag = null)
{
if (null === $flag) {
return $this->_suppressNotFoundWarnings;
}
$this->_suppressNotFoundWarnings = (bool) $flag;
return $this;
}
/**
* Indicate whether or not this autoloader should be a fallback autoloader
*
* @param bool $flag
* @return Zend_Loader_Autoloader
*/
public function setFallbackAutoloader($flag)
{
$this->_fallbackAutoloader = (bool) $flag;
return $this;
}
/**
* Is this instance acting as a fallback autoloader?
*
* @return bool
*/
public function isFallbackAutoloader()
{
return $this->_fallbackAutoloader;
}
/**
* Get autoloaders to use when matching class
*
* Determines if the class matches a registered namespace, and, if so,
* returns only the autoloaders for that namespace. Otherwise, it returns
* all non-namespaced autoloaders.
*
* @param string $class
* @return array Array of autoloaders to use
*/
public function getClassAutoloaders($class)
{
$namespace = false;
$autoloaders = array();
// Add concrete namespaced autoloaders
foreach (array_keys($this->_namespaceAutoloaders) as $ns) {
if ('' == $ns) {
continue;
}
if (0 === strpos($class, $ns)) {
if ((false === $namespace) || (strlen($ns) > strlen($namespace))) {
$namespace = $ns;
$autoloaders = $this->getNamespaceAutoloaders($ns);
}
}
}
// Add internal namespaced autoloader
foreach ($this->getRegisteredNamespaces() as $ns) {
if (0 === strpos($class, $ns)) {
$namespace = $ns;
$autoloaders[] = $this->_internalAutoloader;
break;
}
}
// Add non-namespaced autoloaders
$autoloadersNonNamespace = $this->getNamespaceAutoloaders('');
if (count($autoloadersNonNamespace)) {
foreach ($autoloadersNonNamespace as $ns) {
$autoloaders[] = $ns;
}
unset($autoloadersNonNamespace);
}
// Add fallback autoloader
if (!$namespace && $this->isFallbackAutoloader()) {
$autoloaders[] = $this->_internalAutoloader;
}
return $autoloaders;
}
/**
* Add an autoloader to the beginning of the stack
*
* @param object|array|string $callback PHP callback or Zend_Loader_Autoloader_Interface implementation
* @param string|array $namespace Specific namespace(s) under which to register callback
* @return Zend_Loader_Autoloader
*/
public function unshiftAutoloader($callback, $namespace = '')
{
$autoloaders = $this->getAutoloaders();
array_unshift($autoloaders, $callback);
$this->setAutoloaders($autoloaders);
$namespace = (array) $namespace;
foreach ($namespace as $ns) {
$autoloaders = $this->getNamespaceAutoloaders($ns);
array_unshift($autoloaders, $callback);
$this->_setNamespaceAutoloaders($autoloaders, $ns);
}
return $this;
}
/**
* Append an autoloader to the autoloader stack
*
* @param object|array|string $callback PHP callback or Zend_Loader_Autoloader_Interface implementation
* @param string|array $namespace Specific namespace(s) under which to register callback
* @return Zend_Loader_Autoloader
*/
public function pushAutoloader($callback, $namespace = '')
{
$autoloaders = $this->getAutoloaders();
array_push($autoloaders, $callback);
$this->setAutoloaders($autoloaders);
$namespace = (array) $namespace;
foreach ($namespace as $ns) {
$autoloaders = $this->getNamespaceAutoloaders($ns);
array_push($autoloaders, $callback);
$this->_setNamespaceAutoloaders($autoloaders, $ns);
}
return $this;
}
/**
* Remove an autoloader from the autoloader stack
*
* @param object|array|string $callback PHP callback or Zend_Loader_Autoloader_Interface implementation
* @param null|string|array $namespace Specific namespace(s) from which to remove autoloader
* @return Zend_Loader_Autoloader
*/
public function removeAutoloader($callback, $namespace = null)
{
if (null === $namespace) {
$autoloaders = $this->getAutoloaders();
if (false !== ($index = array_search($callback, $autoloaders, true))) {
unset($autoloaders[$index]);
$this->setAutoloaders($autoloaders);
}
foreach ($this->_namespaceAutoloaders as $ns => $autoloaders) {
if (false !== ($index = array_search($callback, $autoloaders, true))) {
unset($autoloaders[$index]);
$this->_setNamespaceAutoloaders($autoloaders, $ns);
}
}
} else {
$namespace = (array) $namespace;
foreach ($namespace as $ns) {
$autoloaders = $this->getNamespaceAutoloaders($ns);
if (false !== ($index = array_search($callback, $autoloaders, true))) {
unset($autoloaders[$index]);
$this->_setNamespaceAutoloaders($autoloaders, $ns);
}
}
}
return $this;
}
/**
* Constructor
*
* Registers instance with spl_autoload stack
*
* @return void
*/
protected function __construct()
{
spl_autoload_register(array(__CLASS__, 'autoload'));
$this->_internalAutoloader = array($this, '_autoload');
}
/**
* Internal autoloader implementation
*
* @param string $class
* @return bool
*/
protected function _autoload($class)
{
$callback = $this->getDefaultAutoloader();
try {
if ($this->suppressNotFoundWarnings()) {
@call_user_func($callback, $class);
} else {
call_user_func($callback, $class);
}
return $class;
} catch (Zend_Exception $e) {
return false;
}
}
/**
* Set autoloaders for a specific namespace
*
* @param array $autoloaders
* @param string $namespace
* @return Zend_Loader_Autoloader
*/
protected function _setNamespaceAutoloaders(array $autoloaders, $namespace = '')
{
$namespace = (string) $namespace;
$this->_namespaceAutoloaders[$namespace] = $autoloaders;
return $this;
}
/**
* Retrieve the filesystem path for the requested ZF version
*
* @param string $path
* @param string $version
* @return void
*/
protected function _getVersionPath($path, $version)
{
$type = $this->_getVersionType($version);
if ($type == 'latest') {
$version = 'latest';
}
$availableVersions = $this->_getAvailableVersions($path, $version);
if (empty($availableVersions)) {
throw new Zend_Loader_Exception('No valid ZF installations discovered');
}
$matchedVersion = array_pop($availableVersions);
return $matchedVersion;
}
/**
* Retrieve the ZF version type
*
* @param string $version
* @return string "latest", "major", "minor", or "specific"
* @throws Zend_Loader_Exception if version string contains too many dots
*/
protected function _getVersionType($version)
{
if (strtolower($version) == 'latest') {
return 'latest';
}
$parts = explode('.', $version);
$count = count($parts);
if (1 == $count) {
return 'major';
}
if (2 == $count) {
return 'minor';
}
if (3 < $count) {
throw new Zend_Loader_Exception('Invalid version string provided');
}
return 'specific';
}
/**
* Get available versions for the version type requested
*
* @param string $path
* @param string $version
* @return array
*/
protected function _getAvailableVersions($path, $version)
{
if (!is_dir($path)) {
throw new Zend_Loader_Exception('Invalid ZF path provided');
}
$path = rtrim($path, '/');
$path = rtrim($path, '\\');
$versionLen = strlen($version);
$versions = array();
$dirs = glob("$path/*", GLOB_ONLYDIR);
foreach ((array) $dirs as $dir) {
$dirName = substr($dir, strlen($path) + 1);
if (!preg_match('/^(?:ZendFramework-)?(\d+\.\d+\.\d+((a|b|pl|pr|p|rc)\d+)?)(?:-minimal)?$/i', $dirName, $matches)) {
continue;
}
$matchedVersion = $matches[1];
if (('latest' == $version)
|| ((strlen($matchedVersion) >= $versionLen)
&& (0 === strpos($matchedVersion, $version)))
) {
$versions[$matchedVersion] = $dir . '/library';
}
}
uksort($versions, 'version_compare');
return $versions;
}
}

View File

@ -1,43 +0,0 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Loader
* @subpackage Autoloader
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @version $Id: Interface.php 23775 2011-03-01 17:25:24Z ralph $
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
/**
* Autoloader interface
*
* @package Zend_Loader
* @subpackage Autoloader
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
interface Zend_Loader_Autoloader_Interface
{
/**
* Autoload a class
*
* @abstract
* @param string $class
* @return mixed
* False [if unable to load $class]
* get_class($class) [if $class is successfully loaded]
*/
public function autoload($class);
}

View File

@ -1,472 +0,0 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Loader
* @subpackage Autoloader
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @version $Id: Resource.php 23860 2011-04-14 17:03:28Z matthew $
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
/** Zend_Loader_Autoloader_Interface */
require_once 'Zend/Loader/Autoloader/Interface.php';
/**
* Resource loader
*
* @uses Zend_Loader_Autoloader_Interface
* @package Zend_Loader
* @subpackage Autoloader
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Loader_Autoloader_Resource implements Zend_Loader_Autoloader_Interface
{
/**
* @var string Base path to resource classes
*/
protected $_basePath;
/**
* @var array Components handled within this resource
*/
protected $_components = array();
/**
* @var string Default resource/component to use when using object registry
*/
protected $_defaultResourceType;
/**
* @var string Namespace of classes within this resource
*/
protected $_namespace;
/**
* @var array Available resource types handled by this resource autoloader
*/
protected $_resourceTypes = array();
/**
* Constructor
*
* @param array|Zend_Config $options Configuration options for resource autoloader
* @return void
*/
public function __construct($options)
{
if ($options instanceof Zend_Config) {
$options = $options->toArray();
}
if (!is_array($options)) {
require_once 'Zend/Loader/Exception.php';
throw new Zend_Loader_Exception('Options must be passed to resource loader constructor');
}
$this->setOptions($options);
$namespace = $this->getNamespace();
if ((null === $namespace)
|| (null === $this->getBasePath())
) {
require_once 'Zend/Loader/Exception.php';
throw new Zend_Loader_Exception('Resource loader requires both a namespace and a base path for initialization');
}
if (!empty($namespace)) {
$namespace .= '_';
}
require_once 'Zend/Loader/Autoloader.php';
Zend_Loader_Autoloader::getInstance()->unshiftAutoloader($this, $namespace);
}
/**
* Overloading: methods
*
* Allow retrieving concrete resource object instances using 'get<Resourcename>()'
* syntax. Example:
* <code>
* $loader = new Zend_Loader_Autoloader_Resource(array(
* 'namespace' => 'Stuff_',
* 'basePath' => '/path/to/some/stuff',
* ))
* $loader->addResourceType('Model', 'models', 'Model');
*
* $foo = $loader->getModel('Foo'); // get instance of Stuff_Model_Foo class
* </code>
*
* @param string $method
* @param array $args
* @return mixed
* @throws Zend_Loader_Exception if method not beginning with 'get' or not matching a valid resource type is called
*/
public function __call($method, $args)
{
if ('get' == substr($method, 0, 3)) {
$type = strtolower(substr($method, 3));
if (!$this->hasResourceType($type)) {
require_once 'Zend/Loader/Exception.php';
throw new Zend_Loader_Exception("Invalid resource type $type; cannot load resource");
}
if (empty($args)) {
require_once 'Zend/Loader/Exception.php';
throw new Zend_Loader_Exception("Cannot load resources; no resource specified");
}
$resource = array_shift($args);
return $this->load($resource, $type);
}
require_once 'Zend/Loader/Exception.php';
throw new Zend_Loader_Exception("Method '$method' is not supported");
}
/**
* Helper method to calculate the correct class path
*
* @param string $class
* @return False if not matched other wise the correct path
*/
public function getClassPath($class)
{
$segments = explode('_', $class);
$namespaceTopLevel = $this->getNamespace();
$namespace = '';
if (!empty($namespaceTopLevel)) {
$namespace = array();
$topLevelSegments = count(explode('_', $namespaceTopLevel));
for ($i = 0; $i < $topLevelSegments; $i++) {
$namespace[] = array_shift($segments);
}
$namespace = implode('_', $namespace);
if ($namespace != $namespaceTopLevel) {
// wrong prefix? we're done
return false;
}
}
if (count($segments) < 2) {
// assumes all resources have a component and class name, minimum
return false;
}
$final = array_pop($segments);
$component = $namespace;
$lastMatch = false;
do {
$segment = array_shift($segments);
$component .= empty($component) ? $segment : '_' . $segment;
if (isset($this->_components[$component])) {
$lastMatch = $component;
}
} while (count($segments));
if (!$lastMatch) {
return false;
}
$final = substr($class, strlen($lastMatch) + 1);
$path = $this->_components[$lastMatch];
$classPath = $path . '/' . str_replace('_', '/', $final) . '.php';
if (Zend_Loader::isReadable($classPath)) {
return $classPath;
}
return false;
}
/**
* Attempt to autoload a class
*
* @param string $class
* @return mixed False if not matched, otherwise result if include operation
*/
public function autoload($class)
{
$classPath = $this->getClassPath($class);
if (false !== $classPath) {
return include $classPath;
}
return false;
}
/**
* Set class state from options
*
* @param array $options
* @return Zend_Loader_Autoloader_Resource
*/
public function setOptions(array $options)
{
// Set namespace first, see ZF-10836
if (isset($options['namespace'])) {
$this->setNamespace($options['namespace']);
unset($options['namespace']);
}
$methods = get_class_methods($this);
foreach ($options as $key => $value) {
$method = 'set' . ucfirst($key);
if (in_array($method, $methods)) {
$this->$method($value);
}
}
return $this;
}
/**
* Set namespace that this autoloader handles
*
* @param string $namespace
* @return Zend_Loader_Autoloader_Resource
*/
public function setNamespace($namespace)
{
$this->_namespace = rtrim((string) $namespace, '_');
return $this;
}
/**
* Get namespace this autoloader handles
*
* @return string
*/
public function getNamespace()
{
return $this->_namespace;
}
/**
* Set base path for this set of resources
*
* @param string $path
* @return Zend_Loader_Autoloader_Resource
*/
public function setBasePath($path)
{
$this->_basePath = (string) $path;
return $this;
}
/**
* Get base path to this set of resources
*
* @return string
*/
public function getBasePath()
{
return $this->_basePath;
}
/**
* Add resource type
*
* @param string $type identifier for the resource type being loaded
* @param string $path path relative to resource base path containing the resource types
* @param null|string $namespace sub-component namespace to append to base namespace that qualifies this resource type
* @return Zend_Loader_Autoloader_Resource
*/
public function addResourceType($type, $path, $namespace = null)
{
$type = strtolower($type);
if (!isset($this->_resourceTypes[$type])) {
if (null === $namespace) {
require_once 'Zend/Loader/Exception.php';
throw new Zend_Loader_Exception('Initial definition of a resource type must include a namespace');
}
$namespaceTopLevel = $this->getNamespace();
$namespace = ucfirst(trim($namespace, '_'));
$this->_resourceTypes[$type] = array(
'namespace' => empty($namespaceTopLevel) ? $namespace : $namespaceTopLevel . '_' . $namespace,
);
}
if (!is_string($path)) {
require_once 'Zend/Loader/Exception.php';
throw new Zend_Loader_Exception('Invalid path specification provided; must be string');
}
$this->_resourceTypes[$type]['path'] = $this->getBasePath() . '/' . rtrim($path, '\/');
$component = $this->_resourceTypes[$type]['namespace'];
$this->_components[$component] = $this->_resourceTypes[$type]['path'];
return $this;
}
/**
* Add multiple resources at once
*
* $types should be an associative array of resource type => specification
* pairs. Each specification should be an associative array containing
* minimally the 'path' key (specifying the path relative to the resource
* base path) and optionally the 'namespace' key (indicating the subcomponent
* namespace to append to the resource namespace).
*
* As an example:
* <code>
* $loader->addResourceTypes(array(
* 'model' => array(
* 'path' => 'models',
* 'namespace' => 'Model',
* ),
* 'form' => array(
* 'path' => 'forms',
* 'namespace' => 'Form',
* ),
* ));
* </code>
*
* @param array $types
* @return Zend_Loader_Autoloader_Resource
*/
public function addResourceTypes(array $types)
{
foreach ($types as $type => $spec) {
if (!is_array($spec)) {
require_once 'Zend/Loader/Exception.php';
throw new Zend_Loader_Exception('addResourceTypes() expects an array of arrays');
}
if (!isset($spec['path'])) {
require_once 'Zend/Loader/Exception.php';
throw new Zend_Loader_Exception('addResourceTypes() expects each array to include a paths element');
}
$paths = $spec['path'];
$namespace = null;
if (isset($spec['namespace'])) {
$namespace = $spec['namespace'];
}
$this->addResourceType($type, $paths, $namespace);
}
return $this;
}
/**
* Overwrite existing and set multiple resource types at once
*
* @see Zend_Loader_Autoloader_Resource::addResourceTypes()
* @param array $types
* @return Zend_Loader_Autoloader_Resource
*/
public function setResourceTypes(array $types)
{
$this->clearResourceTypes();
return $this->addResourceTypes($types);
}
/**
* Retrieve resource type mappings
*
* @return array
*/
public function getResourceTypes()
{
return $this->_resourceTypes;
}
/**
* Is the requested resource type defined?
*
* @param string $type
* @return bool
*/
public function hasResourceType($type)
{
return isset($this->_resourceTypes[$type]);
}
/**
* Remove the requested resource type
*
* @param string $type
* @return Zend_Loader_Autoloader_Resource
*/
public function removeResourceType($type)
{
if ($this->hasResourceType($type)) {
$namespace = $this->_resourceTypes[$type]['namespace'];
unset($this->_components[$namespace]);
unset($this->_resourceTypes[$type]);
}
return $this;
}
/**
* Clear all resource types
*
* @return Zend_Loader_Autoloader_Resource
*/
public function clearResourceTypes()
{
$this->_resourceTypes = array();
$this->_components = array();
return $this;
}
/**
* Set default resource type to use when calling load()
*
* @param string $type
* @return Zend_Loader_Autoloader_Resource
*/
public function setDefaultResourceType($type)
{
if ($this->hasResourceType($type)) {
$this->_defaultResourceType = $type;
}
return $this;
}
/**
* Get default resource type to use when calling load()
*
* @return string|null
*/
public function getDefaultResourceType()
{
return $this->_defaultResourceType;
}
/**
* Object registry and factory
*
* Loads the requested resource of type $type (or uses the default resource
* type if none provided). If the resource has been loaded previously,
* returns the previous instance; otherwise, instantiates it.
*
* @param string $resource
* @param string $type
* @return object
* @throws Zend_Loader_Exception if resource type not specified or invalid
*/
public function load($resource, $type = null)
{
if (null === $type) {
$type = $this->getDefaultResourceType();
if (empty($type)) {
require_once 'Zend/Loader/Exception.php';
throw new Zend_Loader_Exception('No resource type specified');
}
}
if (!$this->hasResourceType($type)) {
require_once 'Zend/Loader/Exception.php';
throw new Zend_Loader_Exception('Invalid resource type specified');
}
$namespace = $this->_resourceTypes[$type]['namespace'];
$class = $namespace . '_' . ucfirst($resource);
if (!isset($this->_resources[$class])) {
$this->_resources[$class] = new $class;
}
return $this->_resources[$class];
}
}

View File

@ -1,35 +0,0 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Loader
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Exception.php 23775 2011-03-01 17:25:24Z ralph $
*/
/**
* @see Zend_Exception
*/
require_once 'Zend/Exception.php';
/**
* @category Zend
* @package Zend_Loader
* @uses Zend_Exception
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Loader_Exception extends Zend_Exception
{}

View File

@ -1,484 +0,0 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Loader
* @subpackage PluginLoader
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: PluginLoader.php 23775 2011-03-01 17:25:24Z ralph $
*/
/** Zend_Loader_PluginLoader_Interface */
require_once 'Zend/Loader/PluginLoader/Interface.php';
/** Zend_Loader */
require_once 'Zend/Loader.php';
/**
* Generic plugin class loader
*
* @category Zend
* @package Zend_Loader
* @subpackage PluginLoader
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Loader_PluginLoader implements Zend_Loader_PluginLoader_Interface
{
/**
* Class map cache file
* @var string
*/
protected static $_includeFileCache;
/**
* Instance loaded plugin paths
*
* @var array
*/
protected $_loadedPluginPaths = array();
/**
* Instance loaded plugins
*
* @var array
*/
protected $_loadedPlugins = array();
/**
* Instance registry property
*
* @var array
*/
protected $_prefixToPaths = array();
/**
* Statically loaded plugin path mappings
*
* @var array
*/
protected static $_staticLoadedPluginPaths = array();
/**
* Statically loaded plugins
*
* @var array
*/
protected static $_staticLoadedPlugins = array();
/**
* Static registry property
*
* @var array
*/
protected static $_staticPrefixToPaths = array();
/**
* Whether to use a statically named registry for loading plugins
*
* @var string|null
*/
protected $_useStaticRegistry = null;
/**
* Constructor
*
* @param array $prefixToPaths
* @param string $staticRegistryName OPTIONAL
*/
public function __construct(Array $prefixToPaths = array(), $staticRegistryName = null)
{
if (is_string($staticRegistryName) && !empty($staticRegistryName)) {
$this->_useStaticRegistry = $staticRegistryName;
if(!isset(self::$_staticPrefixToPaths[$staticRegistryName])) {
self::$_staticPrefixToPaths[$staticRegistryName] = array();
}
if(!isset(self::$_staticLoadedPlugins[$staticRegistryName])) {
self::$_staticLoadedPlugins[$staticRegistryName] = array();
}
}
foreach ($prefixToPaths as $prefix => $path) {
$this->addPrefixPath($prefix, $path);
}
}
/**
* Format prefix for internal use
*
* @param string $prefix
* @return string
*/
protected function _formatPrefix($prefix)
{
if($prefix == "") {
return $prefix;
}
$last = strlen($prefix) - 1;
if ($prefix{$last} == '\\') {
return $prefix;
}
return rtrim($prefix, '_') . '_';
}
/**
* Add prefixed paths to the registry of paths
*
* @param string $prefix
* @param string $path
* @return Zend_Loader_PluginLoader
*/
public function addPrefixPath($prefix, $path)
{
if (!is_string($prefix) || !is_string($path)) {
require_once 'Zend/Loader/PluginLoader/Exception.php';
throw new Zend_Loader_PluginLoader_Exception('Zend_Loader_PluginLoader::addPrefixPath() method only takes strings for prefix and path.');
}
$prefix = $this->_formatPrefix($prefix);
$path = rtrim($path, '/\\') . '/';
if ($this->_useStaticRegistry) {
self::$_staticPrefixToPaths[$this->_useStaticRegistry][$prefix][] = $path;
} else {
if (!isset($this->_prefixToPaths[$prefix])) {
$this->_prefixToPaths[$prefix] = array();
}
if (!in_array($path, $this->_prefixToPaths[$prefix])) {
$this->_prefixToPaths[$prefix][] = $path;
}
}
return $this;
}
/**
* Get path stack
*
* @param string $prefix
* @return false|array False if prefix does not exist, array otherwise
*/
public function getPaths($prefix = null)
{
if ((null !== $prefix) && is_string($prefix)) {
$prefix = $this->_formatPrefix($prefix);
if ($this->_useStaticRegistry) {
if (isset(self::$_staticPrefixToPaths[$this->_useStaticRegistry][$prefix])) {
return self::$_staticPrefixToPaths[$this->_useStaticRegistry][$prefix];
}
return false;
}
if (isset($this->_prefixToPaths[$prefix])) {
return $this->_prefixToPaths[$prefix];
}
return false;
}
if ($this->_useStaticRegistry) {
return self::$_staticPrefixToPaths[$this->_useStaticRegistry];
}
return $this->_prefixToPaths;
}
/**
* Clear path stack
*
* @param string $prefix
* @return bool False only if $prefix does not exist
*/
public function clearPaths($prefix = null)
{
if ((null !== $prefix) && is_string($prefix)) {
$prefix = $this->_formatPrefix($prefix);
if ($this->_useStaticRegistry) {
if (isset(self::$_staticPrefixToPaths[$this->_useStaticRegistry][$prefix])) {
unset(self::$_staticPrefixToPaths[$this->_useStaticRegistry][$prefix]);
return true;
}
return false;
}
if (isset($this->_prefixToPaths[$prefix])) {
unset($this->_prefixToPaths[$prefix]);
return true;
}
return false;
}
if ($this->_useStaticRegistry) {
self::$_staticPrefixToPaths[$this->_useStaticRegistry] = array();
} else {
$this->_prefixToPaths = array();
}
return true;
}
/**
* Remove a prefix (or prefixed-path) from the registry
*
* @param string $prefix
* @param string $path OPTIONAL
* @return Zend_Loader_PluginLoader
*/
public function removePrefixPath($prefix, $path = null)
{
$prefix = $this->_formatPrefix($prefix);
if ($this->_useStaticRegistry) {
$registry =& self::$_staticPrefixToPaths[$this->_useStaticRegistry];
} else {
$registry =& $this->_prefixToPaths;
}
if (!isset($registry[$prefix])) {
require_once 'Zend/Loader/PluginLoader/Exception.php';
throw new Zend_Loader_PluginLoader_Exception('Prefix ' . $prefix . ' was not found in the PluginLoader.');
}
if ($path != null) {
$pos = array_search($path, $registry[$prefix]);
if (false === $pos) {
require_once 'Zend/Loader/PluginLoader/Exception.php';
throw new Zend_Loader_PluginLoader_Exception('Prefix ' . $prefix . ' / Path ' . $path . ' was not found in the PluginLoader.');
}
unset($registry[$prefix][$pos]);
} else {
unset($registry[$prefix]);
}
return $this;
}
/**
* Normalize plugin name
*
* @param string $name
* @return string
*/
protected function _formatName($name)
{
return ucfirst((string) $name);
}
/**
* Whether or not a Plugin by a specific name is loaded
*
* @param string $name
* @return Zend_Loader_PluginLoader
*/
public function isLoaded($name)
{
$name = $this->_formatName($name);
if ($this->_useStaticRegistry) {
return isset(self::$_staticLoadedPlugins[$this->_useStaticRegistry][$name]);
}
return isset($this->_loadedPlugins[$name]);
}
/**
* Return full class name for a named plugin
*
* @param string $name
* @return string|false False if class not found, class name otherwise
*/
public function getClassName($name)
{
$name = $this->_formatName($name);
if ($this->_useStaticRegistry
&& isset(self::$_staticLoadedPlugins[$this->_useStaticRegistry][$name])
) {
return self::$_staticLoadedPlugins[$this->_useStaticRegistry][$name];
} elseif (isset($this->_loadedPlugins[$name])) {
return $this->_loadedPlugins[$name];
}
return false;
}
/**
* Get path to plugin class
*
* @param mixed $name
* @return string|false False if not found
*/
public function getClassPath($name)
{
$name = $this->_formatName($name);
if ($this->_useStaticRegistry
&& !empty(self::$_staticLoadedPluginPaths[$this->_useStaticRegistry][$name])
) {
return self::$_staticLoadedPluginPaths[$this->_useStaticRegistry][$name];
} elseif (!empty($this->_loadedPluginPaths[$name])) {
return $this->_loadedPluginPaths[$name];
}
if ($this->isLoaded($name)) {
$class = $this->getClassName($name);
$r = new ReflectionClass($class);
$path = $r->getFileName();
if ($this->_useStaticRegistry) {
self::$_staticLoadedPluginPaths[$this->_useStaticRegistry][$name] = $path;
} else {
$this->_loadedPluginPaths[$name] = $path;
}
return $path;
}
return false;
}
/**
* Load a plugin via the name provided
*
* @param string $name
* @param bool $throwExceptions Whether or not to throw exceptions if the
* class is not resolved
* @return string|false Class name of loaded class; false if $throwExceptions
* if false and no class found
* @throws Zend_Loader_Exception if class not found
*/
public function load($name, $throwExceptions = true)
{
$name = $this->_formatName($name);
if ($this->isLoaded($name)) {
return $this->getClassName($name);
}
if ($this->_useStaticRegistry) {
$registry = self::$_staticPrefixToPaths[$this->_useStaticRegistry];
} else {
$registry = $this->_prefixToPaths;
}
$registry = array_reverse($registry, true);
$found = false;
$classFile = str_replace('_', DIRECTORY_SEPARATOR, $name) . '.php';
$incFile = self::getIncludeFileCache();
foreach ($registry as $prefix => $paths) {
$className = $prefix . $name;
if (class_exists($className, false)) {
$found = true;
break;
}
$paths = array_reverse($paths, true);
foreach ($paths as $path) {
$loadFile = $path . $classFile;
if (Zend_Loader::isReadable($loadFile)) {
include_once $loadFile;
if (class_exists($className, false)) {
if (null !== $incFile) {
self::_appendIncFile($loadFile);
}
$found = true;
break 2;
}
}
}
}
if (!$found) {
if (!$throwExceptions) {
return false;
}
$message = "Plugin by name '$name' was not found in the registry; used paths:";
foreach ($registry as $prefix => $paths) {
$message .= "\n$prefix: " . implode(PATH_SEPARATOR, $paths);
}
require_once 'Zend/Loader/PluginLoader/Exception.php';
throw new Zend_Loader_PluginLoader_Exception($message);
}
if ($this->_useStaticRegistry) {
self::$_staticLoadedPlugins[$this->_useStaticRegistry][$name] = $className;
} else {
$this->_loadedPlugins[$name] = $className;
}
return $className;
}
/**
* Set path to class file cache
*
* Specify a path to a file that will add include_once statements for each
* plugin class loaded. This is an opt-in feature for performance purposes.
*
* @param string $file
* @return void
* @throws Zend_Loader_PluginLoader_Exception if file is not writeable or path does not exist
*/
public static function setIncludeFileCache($file)
{
if (null === $file) {
self::$_includeFileCache = null;
return;
}
if (!file_exists($file) && !file_exists(dirname($file))) {
require_once 'Zend/Loader/PluginLoader/Exception.php';
throw new Zend_Loader_PluginLoader_Exception('Specified file does not exist and/or directory does not exist (' . $file . ')');
}
if (file_exists($file) && !is_writable($file)) {
require_once 'Zend/Loader/PluginLoader/Exception.php';
throw new Zend_Loader_PluginLoader_Exception('Specified file is not writeable (' . $file . ')');
}
if (!file_exists($file) && file_exists(dirname($file)) && !is_writable(dirname($file))) {
require_once 'Zend/Loader/PluginLoader/Exception.php';
throw new Zend_Loader_PluginLoader_Exception('Specified file is not writeable (' . $file . ')');
}
self::$_includeFileCache = $file;
}
/**
* Retrieve class file cache path
*
* @return string|null
*/
public static function getIncludeFileCache()
{
return self::$_includeFileCache;
}
/**
* Append an include_once statement to the class file cache
*
* @param string $incFile
* @return void
*/
protected static function _appendIncFile($incFile)
{
if (!file_exists(self::$_includeFileCache)) {
$file = '<?php';
} else {
$file = file_get_contents(self::$_includeFileCache);
}
if (!strstr($file, $incFile)) {
$file .= "\ninclude_once '$incFile';";
file_put_contents(self::$_includeFileCache, $file);
}
}
}

View File

@ -1,39 +0,0 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Loader
* @subpackage PluginLoader
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Exception.php 23775 2011-03-01 17:25:24Z ralph $
*/
/**
* @see Zend_Loader_Exception
*/
require_once 'Zend/Loader/Exception.php';
/**
* Plugin class loader exceptions
*
* @category Zend
* @package Zend_Loader
* @subpackage PluginLoader
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Loader_PluginLoader_Exception extends Zend_Loader_Exception
{
}

View File

@ -1,75 +0,0 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Loader
* @subpackage PluginLoader
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Interface.php 23775 2011-03-01 17:25:24Z ralph $
*/
/**
* Plugin class loader interface
*
* @category Zend
* @package Zend_Loader
* @subpackage PluginLoader
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
interface Zend_Loader_PluginLoader_Interface
{
/**
* Add prefixed paths to the registry of paths
*
* @param string $prefix
* @param string $path
* @return Zend_Loader_PluginLoader
*/
public function addPrefixPath($prefix, $path);
/**
* Remove a prefix (or prefixed-path) from the registry
*
* @param string $prefix
* @param string $path OPTIONAL
* @return Zend_Loader_PluginLoader
*/
public function removePrefixPath($prefix, $path = null);
/**
* Whether or not a Helper by a specific name
*
* @param string $name
* @return Zend_Loader_PluginLoader
*/
public function isLoaded($name);
/**
* Return full class name for a named helper
*
* @param string $name
* @return string
*/
public function getClassName($name);
/**
* Load a helper via the name provided
*
* @param string $name
* @return string
*/
public function load($name);
}

View File

@ -1,2 +0,0 @@
All subfolders like Cache/ are piston-managed, but the main *.php files need to be manually inserted.
See http://framework.zend.com/svn/framework/standard/tags/

View File

@ -1,209 +0,0 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Registry
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Registry.php 23775 2011-03-01 17:25:24Z ralph $
*/
/**
* Generic storage class helps to manage global data.
*
* @category Zend
* @package Zend_Registry
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Registry extends ArrayObject
{
/**
* Class name of the singleton registry object.
* @var string
*/
private static $_registryClassName = 'Zend_Registry';
/**
* Registry object provides storage for shared objects.
* @var Zend_Registry
*/
private static $_registry = null;
/**
* Retrieves the default registry instance.
*
* @return Zend_Registry
*/
public static function getInstance()
{
if (self::$_registry === null) {
self::init();
}
return self::$_registry;
}
/**
* Set the default registry instance to a specified instance.
*
* @param Zend_Registry $registry An object instance of type Zend_Registry,
* or a subclass.
* @return void
* @throws Zend_Exception if registry is already initialized.
*/
public static function setInstance(Zend_Registry $registry)
{
if (self::$_registry !== null) {
require_once 'Zend/Exception.php';
throw new Zend_Exception('Registry is already initialized');
}
self::setClassName(get_class($registry));
self::$_registry = $registry;
}
/**
* Initialize the default registry instance.
*
* @return void
*/
protected static function init()
{
self::setInstance(new self::$_registryClassName());
}
/**
* Set the class name to use for the default registry instance.
* Does not affect the currently initialized instance, it only applies
* for the next time you instantiate.
*
* @param string $registryClassName
* @return void
* @throws Zend_Exception if the registry is initialized or if the
* class name is not valid.
*/
public static function setClassName($registryClassName = 'Zend_Registry')
{
if (self::$_registry !== null) {
require_once 'Zend/Exception.php';
throw new Zend_Exception('Registry is already initialized');
}
if (!is_string($registryClassName)) {
require_once 'Zend/Exception.php';
throw new Zend_Exception("Argument is not a class name");
}
/**
* @see Zend_Loader
*/
if (!class_exists($registryClassName)) {
require_once 'Zend/Loader.php';
Zend_Loader::loadClass($registryClassName);
}
self::$_registryClassName = $registryClassName;
}
/**
* Unset the default registry instance.
* Primarily used in tearDown() in unit tests.
* @returns void
*/
public static function _unsetInstance()
{
self::$_registry = null;
}
/**
* getter method, basically same as offsetGet().
*
* This method can be called from an object of type Zend_Registry, or it
* can be called statically. In the latter case, it uses the default
* static instance stored in the class.
*
* @param string $index - get the value associated with $index
* @return mixed
* @throws Zend_Exception if no entry is registerd for $index.
*/
public static function get($index)
{
$instance = self::getInstance();
if (!$instance->offsetExists($index)) {
require_once 'Zend/Exception.php';
throw new Zend_Exception("No entry is registered for key '$index'");
}
return $instance->offsetGet($index);
}
/**
* setter method, basically same as offsetSet().
*
* This method can be called from an object of type Zend_Registry, or it
* can be called statically. In the latter case, it uses the default
* static instance stored in the class.
*
* @param string $index The location in the ArrayObject in which to store
* the value.
* @param mixed $value The object to store in the ArrayObject.
* @return void
*/
public static function set($index, $value)
{
$instance = self::getInstance();
$instance->offsetSet($index, $value);
}
/**
* Returns TRUE if the $index is a named value in the registry,
* or FALSE if $index was not found in the registry.
*
* @param string $index
* @return boolean
*/
public static function isRegistered($index)
{
if (self::$_registry === null) {
return false;
}
return self::$_registry->offsetExists($index);
}
/**
* Constructs a parent ArrayObject with default
* ARRAY_AS_PROPS to allow acces as an object
*
* @param array $array data array
* @param integer $flags ArrayObject flags
*/
public function __construct($array = array(), $flags = parent::ARRAY_AS_PROPS)
{
parent::__construct($array, $flags);
}
/**
* @param string $index
* @returns mixed
*
* Workaround for http://bugs.php.net/bug.php?id=40442 (ZF-960).
*/
public function offsetExists($index)
{
return array_key_exists($index, $this);
}
}

View File

@ -1,8 +0,0 @@
---
format: 1
handler:
commit: 2d5f2164b200309f6643f8f8486e0cdbbcae348d
branch: master
lock: false
repository_class: Piston::Git::Repository
repository_url: git://github.com/chillu/zend_translate_railsyaml.git

View File

@ -1,24 +0,0 @@
* Copyright (c) 2011, Ingo Schommer
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the <organization> nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY Ingo Schommer. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL Silverstripe Ltd. BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@ -1,61 +0,0 @@
# Zend_Translate Adapter for Rails-style YAML files #
## Overview ##
Adds support for translations in YAML to [Zend_Translate](http://framework.zend.com/manual/en/zend.translate.html).
As Yaml is a very flexible format, the translation files need some conventions.
These conventions are adopted from Ruby on Rails (see [Rails' i18n docs](http://guides.rubyonrails.org/i18n.html)).
Note: You don't need Ruby or Rails to run this code, its just PHP with the same YAML conventions.
## Requirements ##
* Zend Framework (tested with 1.11.6)
* PHP 5.2
## Installation and Usage ##
Assumes a working `include_path` setup for Zend (see [tutorial](http://framework.zend.com/manual/en/learning.quickstart.create-project.html)).
Copy the files into your Zend directory (replace `<zend_path>` below):
cp -r library/Translate/Adapter/* <zend_path>/Zend/Translate/Adapter
cp -r tests/Translate/Adapter/* <zend_path>/Zend/tests/Translate/Adapter
Usage:
require_once 'Zend/Translate/Adapater/RailsYaml.php';
$adapter = new Zend_Translate_Adapter_RailsYaml('en.yml', 'en');
$adapter->addTranslation('de.yml', 'de');
Does not support namespace "fallbacks", as `Zend_Translate`
doesn't have built-in support for them - it just flattens nested keys.
Does not support multiple locales per translation file.
## Sample translation files
en.yml
en:
Message1: Message 1 (en)
Message2: Message 2 (en)
Namespace1:
Message1: Namespace 1 Message 2 (en)
Namespace1Message1: Namespace 1 Message 2 (en)
de.yml
de:
Message1: Message 1 (de)
Namespace1:
Message1: Namespace 1 Message 2 (de)
Namespace1Message1: Namespace 1 Message 2 (de)
## Running the unit tests ##
The tests assume the Zend Framework in a very specific location. See `tests/TestHelper.php` for details.
Its recommended that you copy the relevant files directly into the Zend directory structure.
## Links ##
* [`Zend_Translate_Yaml` Proposal on zend.com](http://framework.zend.com/wiki/display/ZFPROP/Zend_Translate_Yaml+-+Thomas+Weidner) - not actively pursued any longer
* [`Zend_Translate_Yaml` sample code](http://framework.zend.com/issues/browse/ZF-2152)

View File

@ -1,114 +0,0 @@
<?php
/** Zend_Locale */
require_once 'Zend/Locale.php';
/** Zend_Translate_Adapter */
require_once 'Zend/Translate/Adapter.php';
// ischommer CUSTOM Check required because SS core also includes the lib, from a different location
if(!class_exists('sfYaml')) {
require_once __DIR__ .'/thirdparty/sfYaml/lib/sfYaml.php';
}
if(!class_exists('sfYamlParser')) {
require_once __DIR__ . '/thirdparty/sfYaml/lib/sfYamlParser.php';
}
if(!class_exists('sfYamlDumper')) {
require_once __DIR__ . '/thirdparty/sfYaml/lib/sfYamlDumper.php';
}
// ischommer END_CUSTOM
class Translate_Adapter_RailsYaml extends Zend_Translate_Adapter {
/**
* Generates the adapter
*
* @param array|Zend_Config $options Translation content
*/
public function __construct($options = array()) {
$this->_options['keyDelimiter'] = ".";
parent::__construct($options);
}
/**
* Load translation data
*
* @param string|array $data Filename and full path to the translation source
* @param string $locale Locale/Language to add data for, identical with locale identifier,
* see Zend_Locale for more information
* @param array $option OPTIONAL Options to use
*/
protected function _loadTranslationData($data, $locale, array $options = array())
{
$options = array_merge($this->_options, $options);
if ($options['clear'] || !isset($this->_translate[$locale])) {
$this->_translate[$locale] = array();
}
if(is_array($data)) return array($locale => $data);
$this->_filename = $data;
if (!is_readable($this->_filename)) {
require_once 'Zend/Translate/Exception.php';
throw new Zend_Translate_Exception('Error opening translation file \'' . $this->_filename . '\'.');
}
$content = sfYaml::load(file_get_contents($this->_filename));
if($locale != 'auto' && $content && !array_key_exists($locale, $content)) {
require_once 'Zend/Translate/Exception.php';
throw new Zend_Translate_Exception(sprintf('Locale "%s" not found in file %s', $locale, $this->_filename));
}
// Rails YML files supported arbitrarily nested keys, Zend_Translate doesn't - so we flatten them.
// See http://stackoverflow.com/questions/7011451/transaprently-flatten-an-array/7011675
$flattened = array();
if($content && $content[$locale]) {
$iterator = new Translate_Adapter_RailsYaml_Iterator(new RecursiveArrayIterator($content[$locale]));
foreach($iterator as $k => $v) {
$flattened[implode($options['keyDelimiter'], $iterator->getKeyStack())] = $v;
}
}
return array($locale => $flattened);
}
/**
* returns the adapters name
*
* @return string
*/
public function toString()
{
return "RailsYaml";
}
}
class Translate_Adapter_RailsYaml_Iterator extends RecursiveIteratorIterator
{
protected $keyStack = array();
public function callGetChildren()
{
$this->keyStack[] = parent::key();
return parent::callGetChildren();
}
public function endChildren()
{
array_pop($this->keyStack);
parent::endChildren();
}
public function key()
{
return json_encode($this->getKeyStack());
}
public function getKeyStack()
{
return array_merge($this->keyStack, array(parent::key()));
}
}

View File

@ -1,19 +0,0 @@
Copyright (c) 2008-2009 Fabien Potencier
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@ -1,15 +0,0 @@
Symfony YAML: A PHP library that speaks YAML
============================================
Symfony YAML is a PHP library that parses YAML strings and converts them to
PHP arrays. It can also converts PHP arrays to YAML strings. Its official
website is at http://components.symfony-project.org/yaml/.
The documentation is to be found in the `doc/` directory.
Symfony YAML is licensed under the MIT license (see LICENSE file).
The Symfony YAML library is developed and maintained by the
[symfony](http://www.symfony-project.org/) project team. It has been extracted
from symfony to be used as a standalone library. Symfony YAML is part of the
[symfony components project](http://components.symfony-project.org/).

View File

@ -1,135 +0,0 @@
<?php
/*
* This file is part of the symfony package.
* (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* sfYaml offers convenience methods to load and dump YAML.
*
* @package symfony
* @subpackage yaml
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @version SVN: $Id: sfYaml.class.php 8988 2008-05-15 20:24:26Z fabien $
*/
class sfYaml
{
static protected
$spec = '1.2';
/**
* Sets the YAML specification version to use.
*
* @param string $version The YAML specification version
*/
static public function setSpecVersion($version)
{
if (!in_array($version, array('1.1', '1.2')))
{
throw new InvalidArgumentException(sprintf('Version %s of the YAML specifications is not supported', $version));
}
self::$spec = $version;
}
/**
* Gets the YAML specification version to use.
*
* @return string The YAML specification version
*/
static public function getSpecVersion()
{
return self::$spec;
}
/**
* Loads YAML into a PHP array.
*
* The load method, when supplied with a YAML stream (string or file),
* will do its best to convert YAML in a file into a PHP array.
*
* Usage:
* <code>
* $array = sfYaml::load('config.yml');
* print_r($array);
* </code>
*
* @param string $input Path of YAML file or string containing YAML
*
* @return array The YAML converted to a PHP array
*
* @throws InvalidArgumentException If the YAML is not valid
*/
public static function load($input)
{
$file = '';
// if input is a file, process it
if (strpos($input, "\n") === false && is_file($input))
{
$file = $input;
ob_start();
$retval = include($input);
$content = ob_get_clean();
// if an array is returned by the config file assume it's in plain php form else in YAML
$input = is_array($retval) ? $retval : $content;
}
// if an array is returned by the config file assume it's in plain php form else in YAML
if (is_array($input))
{
return $input;
}
require_once dirname(__FILE__).'/sfYamlParser.php';
$yaml = new sfYamlParser();
try
{
$ret = $yaml->parse($input);
}
catch (Exception $e)
{
throw new InvalidArgumentException(sprintf('Unable to parse %s: %s', $file ? sprintf('file "%s"', $file) : 'string', $e->getMessage()));
}
return $ret;
}
/**
* Dumps a PHP array to a YAML string.
*
* The dump method, when supplied with an array, will do its best
* to convert the array into friendly YAML.
*
* @param array $array PHP array
* @param integer $inline The level where you switch to inline YAML
*
* @return string A YAML string representing the original PHP array
*/
public static function dump($array, $inline = 2)
{
require_once dirname(__FILE__).'/sfYamlDumper.php';
$yaml = new sfYamlDumper();
return $yaml->dump($array, $inline);
}
}
/**
* Wraps echo to automatically provide a newline.
*
* @param string $string The string to echo with new line
*/
function echoln($string)
{
echo $string."\n";
}

View File

@ -1,60 +0,0 @@
<?php
/*
* This file is part of the symfony package.
* (c) Fabien Potencier <fabien.potencier@symfony-project.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
require_once(dirname(__FILE__).'/sfYamlInline.php');
/**
* sfYamlDumper dumps PHP variables to YAML strings.
*
* @package symfony
* @subpackage yaml
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @version SVN: $Id: sfYamlDumper.class.php 10575 2008-08-01 13:08:42Z nicolas $
*/
class sfYamlDumper
{
/**
* Dumps a PHP value to YAML.
*
* @param mixed $input The PHP value
* @param integer $inline The level where you switch to inline YAML
* @param integer $indent The level o indentation indentation (used internally)
*
* @return string The YAML representation of the PHP value
*/
public function dump($input, $inline = 0, $indent = 0)
{
$output = '';
$prefix = $indent ? str_repeat(' ', $indent) : '';
if ($inline <= 0 || !is_array($input) || empty($input))
{
$output .= $prefix.sfYamlInline::dump($input);
}
else
{
$isAHash = array_keys($input) !== range(0, count($input) - 1);
foreach ($input as $key => $value)
{
$willBeInlined = $inline - 1 <= 0 || !is_array($value) || empty($value);
$output .= sprintf('%s%s%s%s',
$prefix,
$isAHash ? sfYamlInline::dump($key).':' : '-',
$willBeInlined ? ' ' : "\n",
$this->dump($value, $inline - 1, $willBeInlined ? 0 : $indent + 2)
).($willBeInlined ? "\n" : '');
}
}
return $output;
}
}

View File

@ -1,442 +0,0 @@
<?php
/*
* This file is part of the symfony package.
* (c) Fabien Potencier <fabien.potencier@symfony-project.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
require_once dirname(__FILE__).'/sfYaml.php';
/**
* sfYamlInline implements a YAML parser/dumper for the YAML inline syntax.
*
* @package symfony
* @subpackage yaml
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @version SVN: $Id: sfYamlInline.class.php 16177 2009-03-11 08:32:48Z fabien $
*/
class sfYamlInline
{
const REGEX_QUOTED_STRING = '(?:"([^"\\\\]*(?:\\\\.[^"\\\\]*)*)"|\'([^\']*(?:\'\'[^\']*)*)\')';
/**
* Convert a YAML string to a PHP array.
*
* @param string $value A YAML string
*
* @return array A PHP array representing the YAML string
*/
static public function load($value)
{
$value = trim($value);
if (0 == strlen($value))
{
return '';
}
if (function_exists('mb_internal_encoding') && ((int) ini_get('mbstring.func_overload')) & 2)
{
$mbEncoding = mb_internal_encoding();
mb_internal_encoding('ASCII');
}
switch ($value[0])
{
case '[':
$result = self::parseSequence($value);
break;
case '{':
$result = self::parseMapping($value);
break;
default:
$result = self::parseScalar($value);
}
if (isset($mbEncoding))
{
mb_internal_encoding($mbEncoding);
}
return $result;
}
/**
* Dumps a given PHP variable to a YAML string.
*
* @param mixed $value The PHP variable to convert
*
* @return string The YAML string representing the PHP array
*/
static public function dump($value)
{
if ('1.1' === sfYaml::getSpecVersion())
{
$trueValues = array('true', 'on', '+', 'yes', 'y');
$falseValues = array('false', 'off', '-', 'no', 'n');
}
else
{
$trueValues = array('true');
$falseValues = array('false');
}
switch (true)
{
case is_resource($value):
throw new InvalidArgumentException('Unable to dump PHP resources in a YAML file.');
case is_object($value):
return '!!php/object:'.serialize($value);
case is_array($value):
return self::dumpArray($value);
case null === $value:
return 'null';
case true === $value:
return 'true';
case false === $value:
return 'false';
case ctype_digit($value):
return is_string($value) ? "'$value'" : (int) $value;
case is_numeric($value):
return is_infinite($value) ? str_ireplace('INF', '.Inf', strval($value)) : (is_string($value) ? "'$value'" : $value);
case false !== strpos($value, "\n") || false !== strpos($value, "\r"):
return sprintf('"%s"', str_replace(array('"', "\n", "\r"), array('\\"', '\n', '\r'), $value));
case preg_match('/[ \s \' " \: \{ \} \[ \] , & \* \# \?] | \A[ - ? | < > = ! % @ ` ]/x', $value):
return sprintf("'%s'", str_replace('\'', '\'\'', $value));
case '' == $value:
return "''";
case preg_match(self::getTimestampRegex(), $value):
return "'$value'";
case in_array(strtolower($value), $trueValues):
return "'$value'";
case in_array(strtolower($value), $falseValues):
return "'$value'";
case in_array(strtolower($value), array('null', '~')):
return "'$value'";
default:
return $value;
}
}
/**
* Dumps a PHP array to a YAML string.
*
* @param array $value The PHP array to dump
*
* @return string The YAML string representing the PHP array
*/
static protected function dumpArray($value)
{
// array
$keys = array_keys($value);
if (
(1 == count($keys) && '0' == $keys[0])
||
(count($keys) > 1 && array_reduce($keys, create_function('$v,$w', 'return (integer) $v + $w;'), 0) == count($keys) * (count($keys) - 1) / 2))
{
$output = array();
foreach ($value as $val)
{
$output[] = self::dump($val);
}
return sprintf('[%s]', implode(', ', $output));
}
// mapping
$output = array();
foreach ($value as $key => $val)
{
$output[] = sprintf('%s: %s', self::dump($key), self::dump($val));
}
return sprintf('{ %s }', implode(', ', $output));
}
/**
* Parses a scalar to a YAML string.
*
* @param scalar $scalar
* @param string $delimiters
* @param array $stringDelimiter
* @param integer $i
* @param boolean $evaluate
*
* @return string A YAML string
*/
static public function parseScalar($scalar, $delimiters = null, $stringDelimiters = array('"', "'"), &$i = 0, $evaluate = true)
{
if (in_array($scalar[$i], $stringDelimiters))
{
// quoted scalar
$output = self::parseQuotedScalar($scalar, $i);
}
else
{
// "normal" string
if (!$delimiters)
{
$output = substr($scalar, $i);
$i += strlen($output);
// remove comments
if (false !== $strpos = strpos($output, ' #'))
{
$output = rtrim(substr($output, 0, $strpos));
}
}
else if (preg_match('/^(.+?)('.implode('|', $delimiters).')/', substr($scalar, $i), $match))
{
$output = $match[1];
$i += strlen($output);
}
else
{
throw new InvalidArgumentException(sprintf('Malformed inline YAML string (%s).', $scalar));
}
$output = $evaluate ? self::evaluateScalar($output) : $output;
}
return $output;
}
/**
* Parses a quoted scalar to YAML.
*
* @param string $scalar
* @param integer $i
*
* @return string A YAML string
*/
static protected function parseQuotedScalar($scalar, &$i)
{
if (!preg_match('/'.self::REGEX_QUOTED_STRING.'/Au', substr($scalar, $i), $match))
{
throw new InvalidArgumentException(sprintf('Malformed inline YAML string (%s).', substr($scalar, $i)));
}
$output = substr($match[0], 1, strlen($match[0]) - 2);
if ('"' == $scalar[$i])
{
// evaluate the string
$output = str_replace(array('\\"', '\\n', '\\r'), array('"', "\n", "\r"), $output);
}
else
{
// unescape '
$output = str_replace('\'\'', '\'', $output);
}
$i += strlen($match[0]);
return $output;
}
/**
* Parses a sequence to a YAML string.
*
* @param string $sequence
* @param integer $i
*
* @return string A YAML string
*/
static protected function parseSequence($sequence, &$i = 0)
{
$output = array();
$len = strlen($sequence);
$i += 1;
// [foo, bar, ...]
while ($i < $len)
{
switch ($sequence[$i])
{
case '[':
// nested sequence
$output[] = self::parseSequence($sequence, $i);
break;
case '{':
// nested mapping
$output[] = self::parseMapping($sequence, $i);
break;
case ']':
return $output;
case ',':
case ' ':
break;
default:
$isQuoted = in_array($sequence[$i], array('"', "'"));
$value = self::parseScalar($sequence, array(',', ']'), array('"', "'"), $i);
if (!$isQuoted && false !== strpos($value, ': '))
{
// embedded mapping?
try
{
$value = self::parseMapping('{'.$value.'}');
}
catch (InvalidArgumentException $e)
{
// no, it's not
}
}
$output[] = $value;
--$i;
}
++$i;
}
throw new InvalidArgumentException(sprintf('Malformed inline YAML string %s', $sequence));
}
/**
* Parses a mapping to a YAML string.
*
* @param string $mapping
* @param integer $i
*
* @return string A YAML string
*/
static protected function parseMapping($mapping, &$i = 0)
{
$output = array();
$len = strlen($mapping);
$i += 1;
// {foo: bar, bar:foo, ...}
while ($i < $len)
{
switch ($mapping[$i])
{
case ' ':
case ',':
++$i;
continue 2;
case '}':
return $output;
}
// key
$key = self::parseScalar($mapping, array(':', ' '), array('"', "'"), $i, false);
// value
$done = false;
while ($i < $len)
{
switch ($mapping[$i])
{
case '[':
// nested sequence
$output[$key] = self::parseSequence($mapping, $i);
$done = true;
break;
case '{':
// nested mapping
$output[$key] = self::parseMapping($mapping, $i);
$done = true;
break;
case ':':
case ' ':
break;
default:
$output[$key] = self::parseScalar($mapping, array(',', '}'), array('"', "'"), $i);
$done = true;
--$i;
}
++$i;
if ($done)
{
continue 2;
}
}
}
throw new InvalidArgumentException(sprintf('Malformed inline YAML string %s', $mapping));
}
/**
* Evaluates scalars and replaces magic values.
*
* @param string $scalar
*
* @return string A YAML string
*/
static protected function evaluateScalar($scalar)
{
$scalar = trim($scalar);
if ('1.1' === sfYaml::getSpecVersion())
{
$trueValues = array('true', 'on', '+', 'yes', 'y');
$falseValues = array('false', 'off', '-', 'no', 'n');
}
else
{
$trueValues = array('true');
$falseValues = array('false');
}
switch (true)
{
case 'null' == strtolower($scalar):
case '' == $scalar:
case '~' == $scalar:
return null;
case 0 === strpos($scalar, '!str'):
return (string) substr($scalar, 5);
case 0 === strpos($scalar, '! '):
return intval(self::parseScalar(substr($scalar, 2)));
case 0 === strpos($scalar, '!!php/object:'):
return unserialize(substr($scalar, 13));
case ctype_digit($scalar):
$raw = $scalar;
$cast = intval($scalar);
return '0' == $scalar[0] ? octdec($scalar) : (((string) $raw == (string) $cast) ? $cast : $raw);
case in_array(strtolower($scalar), $trueValues):
return true;
case in_array(strtolower($scalar), $falseValues):
return false;
case is_numeric($scalar):
return '0x' == $scalar[0].$scalar[1] ? hexdec($scalar) : floatval($scalar);
case 0 == strcasecmp($scalar, '.inf'):
case 0 == strcasecmp($scalar, '.NaN'):
return -log(0);
case 0 == strcasecmp($scalar, '-.inf'):
return log(0);
case preg_match('/^(-|\+)?[0-9,]+(\.[0-9]+)?$/', $scalar):
return floatval(str_replace(',', '', $scalar));
case preg_match(self::getTimestampRegex(), $scalar):
return strtotime($scalar);
default:
return (string) $scalar;
}
}
static protected function getTimestampRegex()
{
return <<<EOF
~^
(?P<year>[0-9][0-9][0-9][0-9])
-(?P<month>[0-9][0-9]?)
-(?P<day>[0-9][0-9]?)
(?:(?:[Tt]|[ \t]+)
(?P<hour>[0-9][0-9]?)
:(?P<minute>[0-9][0-9])
:(?P<second>[0-9][0-9])
(?:\.(?P<fraction>[0-9]*))?
(?:[ \t]*(?P<tz>Z|(?P<tz_sign>[-+])(?P<tz_hour>[0-9][0-9]?)
(?::(?P<tz_minute>[0-9][0-9]))?))?)?
$~x
EOF;
}
}

View File

@ -1,622 +0,0 @@
<?php
/*
* This file is part of the symfony package.
* (c) Fabien Potencier <fabien.potencier@symfony-project.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
require_once(dirname(__FILE__).'/sfYamlInline.php');
if (!defined('PREG_BAD_UTF8_OFFSET_ERROR'))
{
define('PREG_BAD_UTF8_OFFSET_ERROR', 5);
}
/**
* sfYamlParser parses YAML strings to convert them to PHP arrays.
*
* @package symfony
* @subpackage yaml
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @version SVN: $Id: sfYamlParser.class.php 10832 2008-08-13 07:46:08Z fabien $
*/
class sfYamlParser
{
protected
$offset = 0,
$lines = array(),
$currentLineNb = -1,
$currentLine = '',
$refs = array();
/**
* Constructor
*
* @param integer $offset The offset of YAML document (used for line numbers in error messages)
*/
public function __construct($offset = 0)
{
$this->offset = $offset;
}
/**
* Parses a YAML string to a PHP value.
*
* @param string $value A YAML string
*
* @return mixed A PHP value
*
* @throws InvalidArgumentException If the YAML is not valid
*/
public function parse($value)
{
$this->currentLineNb = -1;
$this->currentLine = '';
$this->lines = explode("\n", $this->cleanup($value));
if (function_exists('mb_internal_encoding') && ((int) ini_get('mbstring.func_overload')) & 2)
{
$mbEncoding = mb_internal_encoding();
mb_internal_encoding('UTF-8');
}
$data = array();
while ($this->moveToNextLine())
{
if ($this->isCurrentLineEmpty())
{
continue;
}
// tab?
if (preg_match('#^\t+#', $this->currentLine))
{
throw new InvalidArgumentException(sprintf('A YAML file cannot contain tabs as indentation at line %d (%s).', $this->getRealCurrentLineNb() + 1, $this->currentLine));
}
$isRef = $isInPlace = $isProcessed = false;
if (preg_match('#^\-((?P<leadspaces>\s+)(?P<value>.+?))?\s*$#u', $this->currentLine, $values))
{
if (isset($values['value']) && preg_match('#^&(?P<ref>[^ ]+) *(?P<value>.*)#u', $values['value'], $matches))
{
$isRef = $matches['ref'];
$values['value'] = $matches['value'];
}
// array
if (!isset($values['value']) || '' == trim($values['value'], ' ') || 0 === strpos(ltrim($values['value'], ' '), '#'))
{
$c = $this->getRealCurrentLineNb() + 1;
$parser = new sfYamlParser($c);
$parser->refs =& $this->refs;
$data[] = $parser->parse($this->getNextEmbedBlock());
}
else
{
if (isset($values['leadspaces'])
&& ' ' == $values['leadspaces']
&& preg_match('#^(?P<key>'.sfYamlInline::REGEX_QUOTED_STRING.'|[^ \'"\{].*?) *\:(\s+(?P<value>.+?))?\s*$#u', $values['value'], $matches))
{
// this is a compact notation element, add to next block and parse
$c = $this->getRealCurrentLineNb();
$parser = new sfYamlParser($c);
$parser->refs =& $this->refs;
$block = $values['value'];
if (!$this->isNextLineIndented())
{
$block .= "\n".$this->getNextEmbedBlock($this->getCurrentLineIndentation() + 2);
}
$data[] = $parser->parse($block);
}
else
{
$data[] = $this->parseValue($values['value']);
}
}
}
else if (preg_match('#^(?P<key>'.sfYamlInline::REGEX_QUOTED_STRING.'|[^ \'"].*?) *\:(\s+(?P<value>.+?))?\s*$#u', $this->currentLine, $values))
{
$key = sfYamlInline::parseScalar($values['key']);
if ('<<' === $key)
{
if (isset($values['value']) && '*' === substr($values['value'], 0, 1))
{
$isInPlace = substr($values['value'], 1);
if (!array_key_exists($isInPlace, $this->refs))
{
throw new InvalidArgumentException(sprintf('Reference "%s" does not exist at line %s (%s).', $isInPlace, $this->getRealCurrentLineNb() + 1, $this->currentLine));
}
}
else
{
if (isset($values['value']) && $values['value'] !== '')
{
$value = $values['value'];
}
else
{
$value = $this->getNextEmbedBlock();
}
$c = $this->getRealCurrentLineNb() + 1;
$parser = new sfYamlParser($c);
$parser->refs =& $this->refs;
$parsed = $parser->parse($value);
$merged = array();
if (!is_array($parsed))
{
throw new InvalidArgumentException(sprintf("YAML merge keys used with a scalar value instead of an array at line %s (%s)", $this->getRealCurrentLineNb() + 1, $this->currentLine));
}
else if (isset($parsed[0]))
{
// Numeric array, merge individual elements
foreach (array_reverse($parsed) as $parsedItem)
{
if (!is_array($parsedItem))
{
throw new InvalidArgumentException(sprintf("Merge items must be arrays at line %s (%s).", $this->getRealCurrentLineNb() + 1, $parsedItem));
}
$merged = array_merge($parsedItem, $merged);
}
}
else
{
// Associative array, merge
$merged = array_merge($merged, $parsed);
}
$isProcessed = $merged;
}
}
else if (isset($values['value']) && preg_match('#^&(?P<ref>[^ ]+) *(?P<value>.*)#u', $values['value'], $matches))
{
$isRef = $matches['ref'];
$values['value'] = $matches['value'];
}
if ($isProcessed)
{
// Merge keys
$data = $isProcessed;
}
// hash
else if (!isset($values['value']) || '' == trim($values['value'], ' ') || 0 === strpos(ltrim($values['value'], ' '), '#'))
{
// if next line is less indented or equal, then it means that the current value is null
if ($this->isNextLineIndented())
{
$data[$key] = null;
}
else
{
$c = $this->getRealCurrentLineNb() + 1;
$parser = new sfYamlParser($c);
$parser->refs =& $this->refs;
$data[$key] = $parser->parse($this->getNextEmbedBlock());
}
}
else
{
if ($isInPlace)
{
$data = $this->refs[$isInPlace];
}
else
{
$data[$key] = $this->parseValue($values['value']);
}
}
}
else
{
// 1-liner followed by newline
if (2 == count($this->lines) && empty($this->lines[1]))
{
$value = sfYamlInline::load($this->lines[0]);
if (is_array($value))
{
$first = reset($value);
if ('*' === substr($first, 0, 1))
{
$data = array();
foreach ($value as $alias)
{
$data[] = $this->refs[substr($alias, 1)];
}
$value = $data;
}
}
if (isset($mbEncoding))
{
mb_internal_encoding($mbEncoding);
}
return $value;
}
switch (preg_last_error())
{
case PREG_INTERNAL_ERROR:
$error = 'Internal PCRE error on line';
break;
case PREG_BACKTRACK_LIMIT_ERROR:
$error = 'pcre.backtrack_limit reached on line';
break;
case PREG_RECURSION_LIMIT_ERROR:
$error = 'pcre.recursion_limit reached on line';
break;
case PREG_BAD_UTF8_ERROR:
$error = 'Malformed UTF-8 data on line';
break;
case PREG_BAD_UTF8_OFFSET_ERROR:
$error = 'Offset doesn\'t correspond to the begin of a valid UTF-8 code point on line';
break;
default:
$error = 'Unable to parse line';
}
throw new InvalidArgumentException(sprintf('%s %d (%s).', $error, $this->getRealCurrentLineNb() + 1, $this->currentLine));
}
if ($isRef)
{
$this->refs[$isRef] = end($data);
}
}
if (isset($mbEncoding))
{
mb_internal_encoding($mbEncoding);
}
return empty($data) ? null : $data;
}
/**
* Returns the current line number (takes the offset into account).
*
* @return integer The current line number
*/
protected function getRealCurrentLineNb()
{
return $this->currentLineNb + $this->offset;
}
/**
* Returns the current line indentation.
*
* @return integer The current line indentation
*/
protected function getCurrentLineIndentation()
{
return strlen($this->currentLine) - strlen(ltrim($this->currentLine, ' '));
}
/**
* Returns the next embed block of YAML.
*
* @param integer $indentation The indent level at which the block is to be read, or null for default
*
* @return string A YAML string
*/
protected function getNextEmbedBlock($indentation = null)
{
$this->moveToNextLine();
if (null === $indentation)
{
$newIndent = $this->getCurrentLineIndentation();
if (!$this->isCurrentLineEmpty() && 0 == $newIndent)
{
throw new InvalidArgumentException(sprintf('Indentation problem at line %d (%s)', $this->getRealCurrentLineNb() + 1, $this->currentLine));
}
}
else
{
$newIndent = $indentation;
}
$data = array(substr($this->currentLine, $newIndent));
while ($this->moveToNextLine())
{
if ($this->isCurrentLineEmpty())
{
if ($this->isCurrentLineBlank())
{
$data[] = substr($this->currentLine, $newIndent);
}
continue;
}
$indent = $this->getCurrentLineIndentation();
if (preg_match('#^(?P<text> *)$#', $this->currentLine, $match))
{
// empty line
$data[] = $match['text'];
}
else if ($indent >= $newIndent)
{
$data[] = substr($this->currentLine, $newIndent);
}
else if (0 == $indent)
{
$this->moveToPreviousLine();
break;
}
else
{
throw new InvalidArgumentException(sprintf('Indentation problem at line %d (%s)', $this->getRealCurrentLineNb() + 1, $this->currentLine));
}
}
return implode("\n", $data);
}
/**
* Moves the parser to the next line.
*/
protected function moveToNextLine()
{
if ($this->currentLineNb >= count($this->lines) - 1)
{
return false;
}
$this->currentLine = $this->lines[++$this->currentLineNb];
return true;
}
/**
* Moves the parser to the previous line.
*/
protected function moveToPreviousLine()
{
$this->currentLine = $this->lines[--$this->currentLineNb];
}
/**
* Parses a YAML value.
*
* @param string $value A YAML value
*
* @return mixed A PHP value
*/
protected function parseValue($value)
{
if ('*' === substr($value, 0, 1))
{
if (false !== $pos = strpos($value, '#'))
{
$value = substr($value, 1, $pos - 2);
}
else
{
$value = substr($value, 1);
}
if (!array_key_exists($value, $this->refs))
{
throw new InvalidArgumentException(sprintf('Reference "%s" does not exist (%s).', $value, $this->currentLine));
}
return $this->refs[$value];
}
if (preg_match('/^(?P<separator>\||>)(?P<modifiers>\+|\-|\d+|\+\d+|\-\d+|\d+\+|\d+\-)?(?P<comments> +#.*)?$/', $value, $matches))
{
$modifiers = isset($matches['modifiers']) ? $matches['modifiers'] : '';
return $this->parseFoldedScalar($matches['separator'], preg_replace('#\d+#', '', $modifiers), intval(abs($modifiers)));
}
else
{
return sfYamlInline::load($value);
}
}
/**
* Parses a folded scalar.
*
* @param string $separator The separator that was used to begin this folded scalar (| or >)
* @param string $indicator The indicator that was used to begin this folded scalar (+ or -)
* @param integer $indentation The indentation that was used to begin this folded scalar
*
* @return string The text value
*/
protected function parseFoldedScalar($separator, $indicator = '', $indentation = 0)
{
$separator = '|' == $separator ? "\n" : ' ';
$text = '';
$notEOF = $this->moveToNextLine();
while ($notEOF && $this->isCurrentLineBlank())
{
$text .= "\n";
$notEOF = $this->moveToNextLine();
}
if (!$notEOF)
{
return '';
}
if (!preg_match('#^(?P<indent>'.($indentation ? str_repeat(' ', $indentation) : ' +').')(?P<text>.*)$#u', $this->currentLine, $matches))
{
$this->moveToPreviousLine();
return '';
}
$textIndent = $matches['indent'];
$previousIndent = 0;
$text .= $matches['text'].$separator;
while ($this->currentLineNb + 1 < count($this->lines))
{
$this->moveToNextLine();
if (preg_match('#^(?P<indent> {'.strlen($textIndent).',})(?P<text>.+)$#u', $this->currentLine, $matches))
{
if (' ' == $separator && $previousIndent != $matches['indent'])
{
$text = substr($text, 0, -1)."\n";
}
$previousIndent = $matches['indent'];
$text .= str_repeat(' ', $diff = strlen($matches['indent']) - strlen($textIndent)).$matches['text'].($diff ? "\n" : $separator);
}
else if (preg_match('#^(?P<text> *)$#', $this->currentLine, $matches))
{
$text .= preg_replace('#^ {1,'.strlen($textIndent).'}#', '', $matches['text'])."\n";
}
else
{
$this->moveToPreviousLine();
break;
}
}
if (' ' == $separator)
{
// replace last separator by a newline
$text = preg_replace('/ (\n*)$/', "\n$1", $text);
}
switch ($indicator)
{
case '':
$text = preg_replace('#\n+$#s', "\n", $text);
break;
case '+':
break;
case '-':
$text = preg_replace('#\n+$#s', '', $text);
break;
}
return $text;
}
/**
* Returns true if the next line is indented.
*
* @return Boolean Returns true if the next line is indented, false otherwise
*/
protected function isNextLineIndented()
{
$currentIndentation = $this->getCurrentLineIndentation();
$notEOF = $this->moveToNextLine();
while ($notEOF && $this->isCurrentLineEmpty())
{
$notEOF = $this->moveToNextLine();
}
if (false === $notEOF)
{
return false;
}
$ret = false;
if ($this->getCurrentLineIndentation() <= $currentIndentation)
{
$ret = true;
}
$this->moveToPreviousLine();
return $ret;
}
/**
* Returns true if the current line is blank or if it is a comment line.
*
* @return Boolean Returns true if the current line is empty or if it is a comment line, false otherwise
*/
protected function isCurrentLineEmpty()
{
return $this->isCurrentLineBlank() || $this->isCurrentLineComment();
}
/**
* Returns true if the current line is blank.
*
* @return Boolean Returns true if the current line is blank, false otherwise
*/
protected function isCurrentLineBlank()
{
return '' == trim($this->currentLine, ' ');
}
/**
* Returns true if the current line is a comment line.
*
* @return Boolean Returns true if the current line is a comment line, false otherwise
*/
protected function isCurrentLineComment()
{
//checking explicitly the first char of the trim is faster than loops or strpos
$ltrimmedLine = ltrim($this->currentLine, ' ');
return $ltrimmedLine[0] === '#';
}
/**
* Cleanups a YAML string to be parsed.
*
* @param string $value The input YAML string
*
* @return string A cleaned up YAML string
*/
protected function cleanup($value)
{
$value = str_replace(array("\r\n", "\r"), "\n", $value);
if (!preg_match("#\n$#", $value))
{
$value .= "\n";
}
// strip YAML header
$count = 0;
$value = preg_replace('#^\%YAML[: ][\d\.]+.*\n#su', '', $value, -1, $count);
$this->offset += $count;
// remove leading comments
$trimmedValue = preg_replace('#^(\#.*?\n)+#s', '', $value, -1, $count);
if ($count == 1)
{
// items have been removed, update the offset
$this->offset += substr_count($value, "\n") - substr_count($trimmedValue, "\n");
$value = $trimmedValue;
}
// remove start of the document marker (---)
$trimmedValue = preg_replace('#^\-\-\-.*?\n#s', '', $value, -1, $count);
if ($count == 1)
{
// items have been removed, update the offset
$this->offset += substr_count($value, "\n") - substr_count($trimmedValue, "\n");
$value = $trimmedValue;
// remove end of the document marker (...)
$value = preg_replace('#\.\.\.\s*$#s', '', $value);
}
return $value;
}
}

View File

@ -1,172 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<package version="2.1" xmlns="http://pear.php.net/dtd/package-2.1" xmlns:tasks="http://pear.php.net/dtd/tasks-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://pear.php.net/dtd/tasks-1.0 http://pear.php.net/dtd/tasks-1.0.xsd http://pear.php.net/dtd/package-2.1 http://pear.php.net/dtd/package-2.1.xsd">
<name>YAML</name>
<channel>pear.symfony-project.com</channel>
<summary>The Symfony YAML Component.</summary>
<description>The Symfony YAML Component.</description>
<lead>
<name>Fabien Potencier</name>
<user>fabpot</user>
<email>fabien.potencier@symfony-project.org</email>
<active>yes</active>
</lead>
<date>2011-02-22</date>
<version>
<release>1.0.6</release>
<api>1.0.0</api>
</version>
<stability>
<release>stable</release>
<api>stable</api>
</stability>
<license uri="http://www.symfony-project.com/license">MIT license</license>
<notes>-</notes>
<contents>
<dir name="/">
<file name="SF_README.markdown" role="doc" />
<file name="SF_LICENSE" role="doc" />
<dir name="lib">
<file name="sfYaml.php" role="php" />
<file name="sfYamlDumper.php" role="php" />
<file name="sfYamlInline.php" role="php" />
<file name="sfYamlParser.php" role="php" />
</dir>
</dir>
</contents>
<dependencies>
<required>
<php>
<min>5.2.4</min>
</php>
<pearinstaller>
<min>1.4.1</min>
</pearinstaller>
</required>
</dependencies>
<phprelease>
<filelist>
<install as="SymfonyComponents/YAML/sfYaml.php" name="lib/sfYaml.php" />
<install as="SymfonyComponents/YAML/sfYamlDumper.php" name="lib/sfYamlDumper.php" />
<install as="SymfonyComponents/YAML/sfYamlInline.php" name="lib/sfYamlInline.php" />
<install as="SymfonyComponents/YAML/sfYamlParser.php" name="lib/sfYamlParser.php" />
</filelist>
</phprelease>
<changelog>
<release>
<version>
<release>1.0.6</release>
<api>1.0.0</api>
</version>
<stability>
<release>stable</release>
<api>stable</api>
</stability>
<date>2010-02-22</date>
<license>MIT</license>
<notes>
* fabien: renamed doc files to avoid collision with pecl/yaml
</notes>
</release>
<release>
<version>
<release>1.0.5</release>
<api>1.0.0</api>
</version>
<stability>
<release>stable</release>
<api>stable</api>
</stability>
<date>2010-02-22</date>
<license>MIT</license>
<notes>
* indiyets: fixed package.xml
</notes>
</release>
<release>
<version>
<release>1.0.4</release>
<api>1.0.0</api>
</version>
<stability>
<release>stable</release>
<api>stable</api>
</stability>
<date>2010-11-29</date>
<license>MIT</license>
<notes>
* fabien: fixed parsing of simple inline documents
</notes>
</release>
<release>
<version>
<release>1.0.3</release>
<api>1.0.0</api>
</version>
<stability>
<release>stable</release>
<api>stable</api>
</stability>
<date>2010-04-06</date>
<license>MIT</license>
<notes>
* fabien: fixed YAML parser when mbstring.func_overload is used with an mbstring.internal_encoding different from ASCII
* fabien: fixed offset when the document use --- or the %YAML element
* fabien: added ? in the list of characters that trigger quoting (for compatibility with libyaml)
* fabien: added backtick to the list of characters that trigger quotes as it is reserved for future use
* FabianLange: fixed missing newline in sfYamlParser when parsing certain symfony core files
* FabianLange: removed the unused value property from Parser
* fabien: changed Exception to InvalidArgumentException
* fabien: fixed YAML dump when a string contains a \r without a \n
</notes>
</release>
<release>
<version>
<release>1.0.2</release>
<api>1.0.0</api>
</version>
<stability>
<release>stable</release>
<api>stable</api>
</stability>
<date>2009-12-01</date>
<license>MIT</license>
<notes>
* fabien: fixed \ usage in quoted string
</notes>
</release>
<release>
<version>
<release>1.0.1</release>
<api>1.0.0</api>
</version>
<stability>
<release>stable</release>
<api>stable</api>
</stability>
<date>2009-12-01</date>
<license>MIT</license>
<notes>
* fabien: fixed a possible loop in parsing a non-valid quoted string
</notes>
</release>
<release>
<version>
<release>1.0.0</release>
<api>1.0.0</api>
</version>
<stability>
<release>stable</release>
<api>stable</api>
</stability>
<date>2009-11-30</date>
<license>MIT</license>
<notes>
* fabien: first stable release as a Symfony Component
</notes>
</release>
</changelog>
</package>

View File

@ -1,88 +0,0 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend
* @subpackage UnitTests
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: TestHelper.php 23772 2011-02-28 21:35:29Z ralph $
*/
/**
* Include PHPUnit dependencies
*/
require_once 'PHPUnit/Runner/Version.php';
$phpunitVersion = PHPUnit_Runner_Version::id();
if ($phpunitVersion == '@package_version@' || version_compare($phpunitVersion, '3.5.5', '>=')) {
if (version_compare($phpunitVersion, '3.6.0', '>=')) {
echo 'This verison of PHPUnit is not supported in Zend Framework 1.x unit tests.';
exit(1);
}
require_once 'PHPUnit/Autoload.php'; // >= PHPUnit 3.5.5
} else {
require_once 'PHPUnit/Framework.php'; // < PHPUnit 3.5.5
}
/*
* Set error reporting to the level to which Zend Framework code must comply.
*/
error_reporting(E_ALL | E_STRICT);
/*
* Determine the root, library, and tests directories of the framework
* distribution.
*/
$ds = DIRECTORY_SEPARATOR;
$zfRoot = realpath(dirname(dirname(dirname(__FILE__)))) . $ds . 'framework' . $ds . 'thirdparty';
$zfCoreLibrary = "$zfRoot";
$zfCoreTests = "$zfRoot/tests";
$zfCustomLibrary = realpath(dirname(dirname(__FILE__))) . $ds . 'library';
/*
* Prepend the Zend Framework library/ and tests/ directories to the
* include_path. This allows the tests to run out of the box and helps prevent
* loading other copies of the framework code and tests that would supersede
* this copy.
*/
$path = array(
$zfCoreLibrary,
$zfCustomLibrary,
$zfCoreTests,
get_include_path()
);
set_include_path(implode(PATH_SEPARATOR, $path));
// /*
// * Load the user-defined test configuration file, if it exists; otherwise, load
// * the default configuration.
// */
// if (is_readable($zfCoreTests . DIRECTORY_SEPARATOR . 'TestConfiguration.php')) {
// require_once $zfCoreTests . DIRECTORY_SEPARATOR . 'TestConfiguration.php';
// } else {
// require_once $zfCoreTests . DIRECTORY_SEPARATOR . 'TestConfiguration.php.dist';
// }
/**
* Start output buffering, if enabled
*/
if (defined('TESTS_ZEND_OB_ENABLED') && constant('TESTS_ZEND_OB_ENABLED')) {
ob_start();
}
/*
* Unset global variables that are no longer needed.
*/
unset($zfRoot, $zfCoreLibrary, $zfCoreTests, $path);

View File

@ -1,239 +0,0 @@
<?php
if (!defined('PHPUnit_MAIN_METHOD')) {
define('PHPUnit_MAIN_METHOD', 'Translate_Adapter_RailsYAMLTest::main');
}
/**
* Translate_Adapter_RailsYAML
*/
require_once dirname(__FILE__) . '/../../../library/Translate/Adapter/RailsYAML.php';
/**
* @category Zend
* @package Zend_Translate
* @subpackage UnitTests
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @group Zend_Translate
*/
class Translate_Adapter_RailsYAMLTest extends PHPUnit_Framework_TestCase
{
/**
* Error flag
*
* @var boolean
*/
protected $_errorOccurred = false;
/**
* Runs the test methods of this class.
*
* @return void
*/
public static function main()
{
$suite = new PHPUnit_Framework_TestSuite("Translate_Adapter_RailsYAMLTest");
$result = PHPUnit_TextUI_TestRunner::run($suite);
}
public function setUp()
{
if (Translate_Adapter_RailsYAML::hasCache()) {
Translate_Adapter_RailsYAML::clearCache();
Translate_Adapter_RailsYAML::removeCache();
}
}
public function tearDown()
{
if (Translate_Adapter_RailsYAML::hasCache()) {
Translate_Adapter_RailsYAML::clearCache();
Translate_Adapter_RailsYAML::removeCache();
}
}
public function testCreate()
{
try {
$adapter = new Translate_Adapter_RailsYAML('hastofail', 'en');
$this->fail('Exception expected');
} catch (Zend_Translate_Exception $e) {
$this->assertContains('Error opening translation file', $e->getMessage());
}
}
public function testToString()
{
$adapter = $this->getDefaultAdapter();
$this->assertEquals('RailsYaml', $adapter->toString());
}
public function testTranslate()
{
$adapter = $this->getDefaultAdapter();
$this->assertEquals('Message1 (en)', $adapter->translate('Message1'),
'Message without namespace through translate()'
);
$this->assertEquals('Message1 (en)', $adapter->_('Message1'),
'Message without namespace through _()'
);
$this->assertEquals('Namespace1 Message1 (en)', $adapter->translate('Namespace1.Message1'),
'Message with namespace'
);
}
public function testIsTranslated()
{
$adapter = $this->getDefaultAdapter();
$this->assertTrue($adapter->isTranslated('Message1'));
$this->assertFalse($adapter->isTranslated('NonExistent'));
$this->assertTrue($adapter->isTranslated('Message1', true));
$this->assertFalse($adapter->isTranslated('Message1', true, 'en_US'));
$this->assertTrue($adapter->isTranslated('Message1', false, 'en_US'));
$this->assertFalse($adapter->isTranslated('Message1', false, 'es'));
$this->assertFalse($adapter->isTranslated('Message1', 'es'));
$this->assertFalse($adapter->isTranslated('Message1', 'xx_XX'));
$this->assertTrue($adapter->isTranslated('Message1', 'en_XX'));
}
public function testLoadTranslationData()
{
$adapter = $this->getDefaultAdapter();
$this->assertEquals('Message1 (en)', $adapter->translate('Message1'));
$this->assertEquals('Message2', $adapter->translate('Message2', 'ru'));
$this->assertEquals('Message1', $adapter->translate('Message1', 'xx'));
$this->assertEquals('Message1 (en)', $adapter->translate('Message1', 'en_US'));
try {
$adapter->addTranslation(dirname(__FILE__) . '/_files/translation_en.yml', 'xx');
$this->fail("exception expected");
} catch (Zend_Translate_Exception $e) {
$this->assertContains('does not exist', $e->getMessage());
}
$adapter->addTranslation(dirname(__FILE__) . '/_files/translation_de.yml', 'de', array('clear' => true));
$this->assertEquals('Message1 (de)', $adapter->translate('Message1'));
}
public function testOptions()
{
$adapter = $this->getDefaultAdapter();
$adapter->setOptions(array('testoption' => 'testkey'));
$expected = array(
'testoption' => 'testkey',
'clear' => false,
'content' => dirname(__FILE__) . '/_files/translation_en.yml',
'scan' => null,
'locale' => 'en',
'ignore' => '.',
// 'disableNotices' => false,
'log' => false,
'logMessage' => 'Untranslated message within \'%locale%\': %message%',
'logUntranslated' => false,
'reload' => false,
);
$options = $adapter->getOptions();
foreach ($expected as $key => $value) {
$this->assertArrayHasKey($key, $options);
$this->assertEquals($value, $options[$key], $key);
}
$this->assertEquals('testkey', $adapter->getOptions('testoption'));
$this->assertTrue(is_null($adapter->getOptions('nooption')));
}
public function testClearing()
{
$adapter = $this->getDefaultAdapter();
$this->assertEquals('Message1 (en)', $adapter->translate('Message1'));
$adapter->addTranslation(dirname(__FILE__) . '/_files/translation_de.yml', 'de', array('clear' => true));
$this->assertEquals('Message1 (de)', $adapter->translate('Message1'));
$this->assertEquals('Message4', $adapter->translate('Message4'));
}
public function testCaching()
{
require_once 'Zend/Cache.php';
$cache = Zend_Cache::factory('Core', 'File',
array('lifetime' => 120, 'automatic_serialization' => true),
array('cache_dir' => dirname(__FILE__) . '/_files/'));
$this->assertFalse(Translate_Adapter_RailsYAML::hasCache());
Translate_Adapter_RailsYAML::setCache($cache);
$this->assertTrue(Translate_Adapter_RailsYAML::hasCache());
$adapter = $this->getDefaultAdapter();
$cache = Translate_Adapter_RailsYAML::getCache();
$this->assertTrue($cache instanceof Zend_Cache_Core);
unset ($adapter);
$adapter = $this->getDefaultAdapter();
$cache = Translate_Adapter_RailsYAML::getCache();
$this->assertTrue($cache instanceof Zend_Cache_Core);
Translate_Adapter_RailsYAML::removeCache();
$this->assertFalse(Translate_Adapter_RailsYAML::hasCache());
$cache->save('testdata', 'testid');
Translate_Adapter_RailsYAML::setCache($cache);
$adapter = $this->getDefaultAdapter();
Translate_Adapter_RailsYAML::removeCache();
$temp = $cache->load('testid');
$this->assertEquals('testdata', $temp);
}
public function testLoadingFilesIntoCacheAfterwards()
{
require_once 'Zend/Cache.php';
$cache = Zend_Cache::factory('Core', 'File',
array('lifetime' => 120, 'automatic_serialization' => true),
array('cache_dir' => dirname(__FILE__) . '/_files/'));
$this->assertFalse(Translate_Adapter_RailsYAML::hasCache());
Translate_Adapter_RailsYAML::setCache($cache);
$this->assertTrue(Translate_Adapter_RailsYAML::hasCache());
$adapter = $this->getDefaultAdapter();
$cache = Translate_Adapter_RailsYAML::getCache();
$this->assertTrue($cache instanceof Zend_Cache_Core);
$adapter->addTranslation(dirname(__FILE__) . '/_files/translation_de.yml', 'de', array('reload' => true));
$test = $adapter->getMessages('all');
$this->assertEquals(4, count($test['de']));
}
/**
* Ignores a raised PHP error when in effect, but throws a flag to indicate an error occurred
*
* @param integer $errno
* @param string $errstr
* @param string $errfile
* @param integer $errline
* @param array $errcontext
* @return void
*/
public function errorHandlerIgnore($errno, $errstr, $errfile, $errline, array $errcontext)
{
$this->_errorOccurred = true;
}
/**
* @return Translate_Adapter_RailsYAML
*/
protected function getDefaultAdapter()
{
return new Translate_Adapter_RailsYAML(
dirname(__FILE__) . '/_files/translation_en.yml',
'en',
array('disableNotices' => true)
);
}
}
// Call Translate_Adapter_RailsYAMLTest::main() if this source file is executed directly.
if (PHPUnit_MAIN_METHOD == "Translate_Adapter_RailsYAMLTest::main") {
Translate_Adapter_RailsYAMLTest::main();
}

View File

@ -1,6 +0,0 @@
de:
Message1: Message1 (de)
Message2: Message2 (de)
Namespace1:
Message1: Namespace1 Message2 (de)
Namespace1Message1: Namespace1 Message2 (de)

View File

@ -1,9 +0,0 @@
en:
Message1: Message1 (en)
Message2: Message2 (en)
Namespace1:
Message1: Namespace1 Message1 (en)
Namespace1Message1: Namespace1 Message2 (en)
Namespace2:
Message1: Namespace2 Message1 (en)
Namespace2Message2: Namespace2 Message2 (en)

View File

@ -1,5 +0,0 @@
<phpunit bootstrap="./TestHelper.php">
<testsuite name="Zend Framework - Zend_Translate_Adapater_RailsYML Testsuite">
<directory>./</directory>
</testsuite>
</phpunit>