Merge branch '2014.09' into 2015.07
authorPhilipp Schüle <p.schuele@metaways.de>
Thu, 16 Jul 2015 10:01:21 +0000 (12:01 +0200)
committerPhilipp Schüle <p.schuele@metaways.de>
Thu, 16 Jul 2015 10:01:21 +0000 (12:01 +0200)
100 files changed:
tine20/Zend/Cache/Backend/Memcached.php
tine20/Zend/Filter/Input.php [deleted file]
tine20/Zend/OpenId/Provider.php
tine20/library/Zend/Cache.php
tine20/library/Zend/Cache/Backend.php
tine20/library/Zend/Cache/Backend/Apc.php
tine20/library/Zend/Cache/Backend/BlackHole.php [new file with mode: 0644]
tine20/library/Zend/Cache/Backend/ExtendedInterface.php
tine20/library/Zend/Cache/Backend/File.php
tine20/library/Zend/Cache/Backend/Interface.php
tine20/library/Zend/Cache/Backend/Libmemcached.php [new file with mode: 0644]
tine20/library/Zend/Cache/Backend/Memcached.php
tine20/library/Zend/Cache/Backend/Sqlite.php
tine20/library/Zend/Cache/Backend/Static.php [new file with mode: 0644]
tine20/library/Zend/Cache/Backend/Test.php
tine20/library/Zend/Cache/Backend/TwoLevels.php
tine20/library/Zend/Cache/Backend/WinCache.php [new file with mode: 0644]
tine20/library/Zend/Cache/Backend/Xcache.php
tine20/library/Zend/Cache/Backend/ZendPlatform.php
tine20/library/Zend/Cache/Backend/ZendServer.php
tine20/library/Zend/Cache/Backend/ZendServer/Disk.php
tine20/library/Zend/Cache/Backend/ZendServer/ShMem.php
tine20/library/Zend/Cache/Core.php
tine20/library/Zend/Cache/Exception.php
tine20/library/Zend/Cache/Frontend/Capture.php [new file with mode: 0644]
tine20/library/Zend/Cache/Frontend/Class.php
tine20/library/Zend/Cache/Frontend/File.php
tine20/library/Zend/Cache/Frontend/Function.php
tine20/library/Zend/Cache/Frontend/Output.php
tine20/library/Zend/Cache/Frontend/Page.php
tine20/library/Zend/Cache/Manager.php [new file with mode: 0644]
tine20/library/Zend/Filter.php
tine20/library/Zend/Filter/Alnum.php
tine20/library/Zend/Filter/Alpha.php
tine20/library/Zend/Filter/BaseName.php
tine20/library/Zend/Filter/Boolean.php [new file with mode: 0644]
tine20/library/Zend/Filter/Callback.php
tine20/library/Zend/Filter/Compress.php [new file with mode: 0644]
tine20/library/Zend/Filter/Compress/Bz2.php [new file with mode: 0644]
tine20/library/Zend/Filter/Compress/CompressAbstract.php [new file with mode: 0644]
tine20/library/Zend/Filter/Compress/CompressInterface.php [new file with mode: 0644]
tine20/library/Zend/Filter/Compress/Gz.php [new file with mode: 0644]
tine20/library/Zend/Filter/Compress/Lzf.php [new file with mode: 0644]
tine20/library/Zend/Filter/Compress/Rar.php [new file with mode: 0644]
tine20/library/Zend/Filter/Compress/Tar.php [new file with mode: 0644]
tine20/library/Zend/Filter/Compress/Zip.php [new file with mode: 0644]
tine20/library/Zend/Filter/Decompress.php [new file with mode: 0644]
tine20/library/Zend/Filter/Decrypt.php
tine20/library/Zend/Filter/Digits.php
tine20/library/Zend/Filter/Dir.php
tine20/library/Zend/Filter/Encrypt.php
tine20/library/Zend/Filter/Encrypt/Interface.php
tine20/library/Zend/Filter/Encrypt/Mcrypt.php
tine20/library/Zend/Filter/Encrypt/Openssl.php
tine20/library/Zend/Filter/Exception.php
tine20/library/Zend/Filter/File/Decrypt.php
tine20/library/Zend/Filter/File/Encrypt.php
tine20/library/Zend/Filter/File/LowerCase.php
tine20/library/Zend/Filter/File/Rename.php
tine20/library/Zend/Filter/File/UpperCase.php
tine20/library/Zend/Filter/HtmlEntities.php
tine20/library/Zend/Filter/Inflector.php
tine20/library/Zend/Filter/Input.php
tine20/library/Zend/Filter/Int.php
tine20/library/Zend/Filter/Interface.php
tine20/library/Zend/Filter/LocalizedToNormalized.php
tine20/library/Zend/Filter/NormalizedToLocalized.php
tine20/library/Zend/Filter/Null.php [new file with mode: 0644]
tine20/library/Zend/Filter/PregReplace.php
tine20/library/Zend/Filter/RealPath.php
tine20/library/Zend/Filter/StringToLower.php
tine20/library/Zend/Filter/StringToUpper.php
tine20/library/Zend/Filter/StringTrim.php
tine20/library/Zend/Filter/StripNewlines.php
tine20/library/Zend/Filter/StripTags.php
tine20/library/Zend/Filter/Word/CamelCaseToDash.php
tine20/library/Zend/Filter/Word/CamelCaseToSeparator.php
tine20/library/Zend/Filter/Word/CamelCaseToUnderscore.php
tine20/library/Zend/Filter/Word/DashToCamelCase.php
tine20/library/Zend/Filter/Word/DashToSeparator.php
tine20/library/Zend/Filter/Word/DashToUnderscore.php
tine20/library/Zend/Filter/Word/Separator/Abstract.php
tine20/library/Zend/Filter/Word/SeparatorToCamelCase.php
tine20/library/Zend/Filter/Word/SeparatorToDash.php
tine20/library/Zend/Filter/Word/SeparatorToSeparator.php
tine20/library/Zend/Filter/Word/UnderscoreToCamelCase.php
tine20/library/Zend/Filter/Word/UnderscoreToDash.php
tine20/library/Zend/Filter/Word/UnderscoreToSeparator.php
tine20/library/Zend/OpenId.php
tine20/library/Zend/OpenId/Consumer.php
tine20/library/Zend/OpenId/Consumer/Storage.php
tine20/library/Zend/OpenId/Consumer/Storage/File.php
tine20/library/Zend/OpenId/Exception.php
tine20/library/Zend/OpenId/Extension.php
tine20/library/Zend/OpenId/Extension/Sreg.php
tine20/library/Zend/OpenId/Provider.php
tine20/library/Zend/OpenId/Provider/Storage.php
tine20/library/Zend/OpenId/Provider/Storage/File.php
tine20/library/Zend/OpenId/Provider/User.php
tine20/library/Zend/OpenId/Provider/User/Session.php

index b2c8f5f..6a7f1f8 100644 (file)
  * @category   Zend
  * @package    Zend_Cache
  * @subpackage Zend_Cache_Backend
- * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @copyright  Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
  * @license    http://framework.zend.com/license/new-bsd     New BSD License
  * @version    $Id$
  * 
  * NOTE: overwritten to always clear the cache even if a CLEANING_MODE_TAG_* mode is used (-> @see clean())
+ * @todo check if still needed / clearing by tag should not be used any more
  */
 
 
@@ -37,7 +38,7 @@ require_once 'Zend/Cache/Backend.php';
 /**
  * @package    Zend_Cache
  * @subpackage Zend_Cache_Backend
- * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @copyright  Copyright (c) 2005-2015 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
@@ -135,25 +136,25 @@ class Zend_Cache_Backend_Memcached extends Zend_Cache_Backend implements Zend_Ca
         }
         $this->_memcache = new Memcache;
         foreach ($this->_options['servers'] as $server) {
-            if (!(isset($server['port']) || array_key_exists('port', $server))) {
+            if (!array_key_exists('port', $server)) {
                 $server['port'] = self::DEFAULT_PORT;
             }
-            if (!(isset($server['persistent']) || array_key_exists('persistent', $server))) {
+            if (!array_key_exists('persistent', $server)) {
                 $server['persistent'] = self::DEFAULT_PERSISTENT;
             }
-            if (!(isset($server['weight']) || array_key_exists('weight', $server))) {
+            if (!array_key_exists('weight', $server)) {
                 $server['weight'] = self::DEFAULT_WEIGHT;
             }
-            if (!(isset($server['timeout']) || array_key_exists('timeout', $server))) {
+            if (!array_key_exists('timeout', $server)) {
                 $server['timeout'] = self::DEFAULT_TIMEOUT;
             }
-            if (!(isset($server['retry_interval']) || array_key_exists('retry_interval', $server))) {
+            if (!array_key_exists('retry_interval', $server)) {
                 $server['retry_interval'] = self::DEFAULT_RETRY_INTERVAL;
             }
-            if (!(isset($server['status']) || array_key_exists('status', $server))) {
+            if (!array_key_exists('status', $server)) {
                 $server['status'] = self::DEFAULT_STATUS;
             }
-            if (!(isset($server['failure_callback']) || array_key_exists('failure_callback', $server))) {
+            if (!array_key_exists('failure_callback', $server)) {
                 $server['failure_callback'] = self::DEFAULT_FAILURE_CALLBACK;
             }
             if ($this->_options['compatibility']) {
@@ -180,7 +181,7 @@ class Zend_Cache_Backend_Memcached extends Zend_Cache_Backend implements Zend_Ca
     public function load($id, $doNotTestCacheValidity = false)
     {
         $tmp = $this->_memcache->get($id);
-        if (is_array($tmp)) {
+        if (is_array($tmp) && isset($tmp[0])) {
             return $tmp[0];
         }
         return false;
@@ -221,13 +222,14 @@ class Zend_Cache_Backend_Memcached extends Zend_Cache_Backend implements Zend_Ca
         } else {
             $flag = 0;
         }
-        // #ZF-5702 : we try add() first becase set() seems to be slower
-        if (!($result = $this->_memcache->add($id, array($data, time(), $lifetime), $flag, $lifetime))) {
-            $result = $this->_memcache->set($id, array($data, time(), $lifetime), $flag, $lifetime);
-        }
+
+        // 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("Zend_Cache_Backend_Memcached::save() : tags are unsupported by the Memcached backend");
+            $this->_log(self::TAGS_UNSUPPORTED_BY_SAVE_OF_MEMCACHED_BACKEND);
         }
+
         return $result;
     }
 
@@ -239,13 +241,11 @@ class Zend_Cache_Backend_Memcached extends Zend_Cache_Backend implements Zend_Ca
      */
     public function remove($id)
     {
-        return $this->_memcache->delete($id);
+        return $this->_memcache->delete($id, 0);
     }
 
     /**
      * Clean some cache records
-     * 
-     * NOTE: we always clear the cache even if a CLEANING_MODE_TAG_* mode is used
      *
      * Available modes are :
      * 'all' (default)  => remove all cache entries ($tags is not used)
@@ -266,6 +266,7 @@ class Zend_Cache_Backend_Memcached extends Zend_Cache_Backend implements Zend_Ca
             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);
+                // fall through / clear all entries
             case Zend_Cache::CLEANING_MODE_ALL:
                 return $this->_memcache->flush();
                 break;
@@ -383,25 +384,31 @@ class Zend_Cache_Backend_Memcached extends Zend_Cache_Backend implements Zend_Ca
     {
         $mems = $this->_memcache->getExtendedStats();
 
-        $memSize = 0;
-        $memUsed = 0;
+        $memSize = null;
+        $memUsed = null;
         foreach ($mems as $key => $mem) {
             if ($mem === false) {
-                Zend_Cache::throwException('can\'t get stat from ' . $key);
-            } else {
-                $eachSize = $mem['limit_maxbytes'];
-                if ($eachSize == 0) {
-                    Zend_Cache::throwException('can\'t get memory size from ' . $key);
-                }
-
-                $eachUsed = $mem['bytes'];
-                if ($eachUsed > $eachSize) {
-                    $eachUsed = $eachSize;
-                }
-
-                $memSize += $eachSize;
-                $memUsed += $eachUsed;
+                $this->_log('can\'t get stat from ' . $key);
+                continue;
             }
+
+            $eachSize = $mem['limit_maxbytes'];
+
+            /**
+             * Couchbase 1.x uses 'mem_used' instead of 'bytes'
+             * @see https://www.couchbase.com/issues/browse/MB-3466
+             */
+            $eachUsed = isset($mem['bytes']) ? $mem['bytes'] : $mem['mem_used'];
+            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)));
diff --git a/tine20/Zend/Filter/Input.php b/tine20/Zend/Filter/Input.php
deleted file mode 100644 (file)
index 47bb53c..0000000
+++ /dev/null
@@ -1,1026 +0,0 @@
-<?php
-
-/**
- * 
- * Copied from library/Zend/Filter/Input.php and fixed null value validation bug  * 
- * (see http://framework.zend.com/issues/browse/ZF-7135) in line 834 (if ((isset($this->_data[$field]) || array_key_exists($field, $this->_data))) {) 
- * 
- * 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_Filter
- * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
- * @license    http://framework.zend.com/license/new-bsd     New BSD License
- * @version    $Id: Input.php 15683 2009-05-22 15:50:36Z alexander $
- */
-
-/**
- * @see Zend_Loader
- */
-require_once 'Zend/Loader.php';
-
-/**
- * @see Zend_Filter
- */
-require_once 'Zend/Filter.php';
-
-/**
- * @see Zend_Validate
- */
-require_once 'Zend/Validate.php';
-
-/**
- * @category   Zend
- * @package    Zend_Filter
- * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
- * @license    http://framework.zend.com/license/new-bsd     New BSD License
- */
-class Zend_Filter_Input
-{
-
-    const ALLOW_EMPTY           = 'allowEmpty';
-    const BREAK_CHAIN           = 'breakChainOnFailure';
-    const DEFAULT_VALUE         = 'default';
-    const MESSAGES              = 'messages';
-    const ESCAPE_FILTER         = 'escapeFilter';
-    const FIELDS                = 'fields';
-    const FILTER                = 'filter';
-    const FILTER_CHAIN          = 'filterChain';
-    const MISSING_MESSAGE       = 'missingMessage';
-    const INPUT_NAMESPACE       = 'inputNamespace';
-    const VALIDATOR_NAMESPACE   = 'validatorNamespace';
-    const FILTER_NAMESPACE      = 'filterNamespace';
-    const NOT_EMPTY_MESSAGE     = 'notEmptyMessage';
-    const PRESENCE              = 'presence';
-    const PRESENCE_OPTIONAL     = 'optional';
-    const PRESENCE_REQUIRED     = 'required';
-    const RULE                  = 'rule';
-    const RULE_WILDCARD         = '*';
-    const VALIDATE              = 'validate';
-    const VALIDATOR             = 'validator';
-    const VALIDATOR_CHAIN       = 'validatorChain';
-    const VALIDATOR_CHAIN_COUNT = 'validatorChainCount';
-
-    /**
-     * @var array Input data, before processing.
-     */
-    protected $_data = array();
-
-    /**
-     * @var array Association of rules to filters.
-     */
-    protected $_filterRules = array();
-
-    /**
-     * @var array Association of rules to validators.
-     */
-    protected $_validatorRules = array();
-
-    /**
-     * @var array After processing data, this contains mapping of valid fields
-     * to field values.
-     */
-    protected $_validFields = array();
-
-    /**
-     * @var array After processing data, this contains mapping of validation
-     * rules that did not pass validation to the array of messages returned
-     * by the validator chain.
-     */
-    protected $_invalidMessages = array();
-
-    /**
-     * @var array After processing data, this contains mapping of validation
-     * rules that did not pass validation to the array of error identifiers
-     * returned by the validator chain.
-     */
-    protected $_invalidErrors = array();
-
-    /**
-     * @var array After processing data, this contains mapping of validation
-     * rules in which some fields were missing to the array of messages
-     * indicating which fields were missing.
-     */
-    protected $_missingFields = array();
-
-    /**
-     * @var array After processing, this contains a copy of $_data elements
-     * that were not mentioned in any validation rule.
-     */
-    protected $_unknownFields = array();
-
-    /**
-     * @var Zend_Filter_Interface The filter object that is run on values
-     * returned by the getEscaped() method.
-     */
-    protected $_defaultEscapeFilter = null;
-
-    /**
-     * Plugin loaders
-     * @var array
-     */
-    protected $_loaders = array();
-
-    /**
-     * @var array Default values to use when processing filters and validators.
-     */
-    protected $_defaults = array(
-        self::ALLOW_EMPTY         => false,
-        self::BREAK_CHAIN         => false,
-        self::ESCAPE_FILTER       => 'HtmlEntities',
-        self::MISSING_MESSAGE     => "Field '%field%' is required by rule '%rule%', but the field is missing",
-        self::NOT_EMPTY_MESSAGE   => "You must give a non-empty value for field '%field%'",
-        self::PRESENCE            => self::PRESENCE_OPTIONAL
-    );
-
-    /**
-     * @var boolean Set to False initially, this is set to True after the
-     * input data have been processed.  Reset to False in setData() method.
-     */
-    protected $_processed = false;
-
-    /**
-     * @param array $filterRules
-     * @param array $validatorRules
-     * @param array $data       OPTIONAL
-     * @param array $options    OPTIONAL
-     */
-    public function __construct($filterRules, $validatorRules, array $data = null, array $options = null)
-    {
-        if ($options) {
-            $this->setOptions($options);
-        }
-
-        $this->_filterRules = (array) $filterRules;
-        $this->_validatorRules = (array) $validatorRules;
-
-        if ($data) {
-            $this->setData($data);
-        }
-    }
-
-    /**
-     * @param mixed $namespaces
-     * @return Zend_Filter_Input
-     * @deprecated since 1.5.0RC1 - use addFilterPrefixPath() or addValidatorPrefixPath instead.
-     */
-    public function addNamespace($namespaces)
-    {
-        if (!is_array($namespaces)) {
-            $namespaces = array($namespaces);
-        }
-
-        foreach ($namespaces as $namespace) {
-            $prefix = $namespace;
-            $path = str_replace('_', DIRECTORY_SEPARATOR, $prefix);
-            $this->addFilterPrefixPath($prefix, $path);
-            $this->addValidatorPrefixPath($prefix, $path);
-        }
-
-        return $this;
-    }
-
-    /**
-     * Add prefix path for all elements
-     *
-     * @param  string $prefix
-     * @param  string $path
-     * @return Zend_Filter_Input
-     */
-    public function addFilterPrefixPath($prefix, $path)
-    {
-        $this->getPluginLoader(self::FILTER)->addPrefixPath($prefix, $path);
-
-        return $this;
-    }
-
-    /**
-     * Add prefix path for all elements
-     *
-     * @param  string $prefix
-     * @param  string $path
-     * @return Zend_Filter_Input
-     */
-    public function addValidatorPrefixPath($prefix, $path)
-    {
-        $this->getPluginLoader(self::VALIDATE)->addPrefixPath($prefix, $path);
-
-        return $this;
-    }
-
-    /**
-     * Set plugin loaders for use with decorators and elements
-     *
-     * @param  Zend_Loader_PluginLoader_Interface $loader
-     * @param  string $type 'filter' or 'validate'
-     * @return Zend_Filter_Input
-     * @throws Zend_Filter_Exception on invalid type
-     */
-    public function setPluginLoader(Zend_Loader_PluginLoader_Interface $loader, $type)
-    {
-        $type = strtolower($type);
-        switch ($type) {
-            case self::FILTER:
-            case self::VALIDATE:
-                $this->_loaders[$type] = $loader;
-                return $this;
-            default:
-                require_once 'Zend/Filter/Exception.php';
-                throw new Zend_Filter_Exception(sprintf('Invalid type "%s" provided to setPluginLoader()', $type));
-        }
-
-        return $this;
-    }
-
-    /**
-     * Retrieve plugin loader for given type
-     *
-     * $type may be one of:
-     * - filter
-     * - validator
-     *
-     * If a plugin loader does not exist for the given type, defaults are
-     * created.
-     *
-     * @param  string $type 'filter' or 'validate'
-     * @return Zend_Loader_PluginLoader_Interface
-     * @throws Zend_Filter_Exception on invalid type
-     */
-    public function getPluginLoader($type)
-    {
-        $type = strtolower($type);
-        if (!isset($this->_loaders[$type])) {
-            switch ($type) {
-                case self::FILTER:
-                    $prefixSegment = 'Zend_Filter_';
-                    $pathSegment   = 'Zend/Filter/';
-                    break;
-                case self::VALIDATE:
-                    $prefixSegment = 'Zend_Validate_';
-                    $pathSegment   = 'Zend/Validate/';
-                    break;
-                default:
-                    require_once 'Zend/Filter/Exception.php';
-                    throw new Zend_Filter_Exception(sprintf('Invalid type "%s" provided to getPluginLoader()', $type));
-            }
-
-            require_once 'Zend/Loader/PluginLoader.php';
-            $this->_loaders[$type] = new Zend_Loader_PluginLoader(
-                array($prefixSegment => $pathSegment)
-            );
-        }
-
-        return $this->_loaders[$type];
-    }
-
-    /**
-     * @return array
-     */
-    public function getMessages()
-    {
-        $this->_process();
-        return array_merge($this->_invalidMessages, $this->_missingFields);
-    }
-
-    /**
-     * @return array
-     */
-    public function getErrors()
-    {
-        $this->_process();
-        return $this->_invalidErrors;
-    }
-
-    /**
-     * @return array
-     */
-    public function getInvalid()
-    {
-        $this->_process();
-        return $this->_invalidMessages;
-    }
-
-    /**
-     * @return array
-     */
-    public function getMissing()
-    {
-        $this->_process();
-        return $this->_missingFields;
-    }
-
-    /**
-     * @return array
-     */
-    public function getUnknown()
-    {
-        $this->_process();
-        return $this->_unknownFields;
-    }
-
-    /**
-     * @param string $fieldName OPTIONAL
-     * @return mixed
-     */
-    public function getEscaped($fieldName = null)
-    {
-        $this->_process();
-        $this->_getDefaultEscapeFilter();
-
-        if ($fieldName === null) {
-            return $this->_escapeRecursive($this->_validFields);
-        }
-        if ((isset($this->_validFields[$fieldName]) || array_key_exists($fieldName, $this->_validFields))) {
-            return $this->_escapeRecursive($this->_validFields[$fieldName]);
-        }
-        return null;
-    }
-
-    /**
-     * @param mixed $value
-     * @return mixed
-     */
-    protected function _escapeRecursive($data)
-    {
-        if($data === null) {
-            return $data;
-        }
-
-        if (!is_array($data)) {
-            return $this->_getDefaultEscapeFilter()->filter($data);
-        }
-        foreach ($data as &$element) {
-            $element = $this->_escapeRecursive($element);
-        }
-        return $data;
-    }
-
-    /**
-     * @param string $fieldName OPTIONAL
-     * @return mixed
-     */
-    public function getUnescaped($fieldName = null)
-    {
-        $this->_process();
-        if ($fieldName === null) {
-            return $this->_validFields;
-        }
-        if ((isset($this->_validFields[$fieldName]) || array_key_exists($fieldName, $this->_validFields))) {
-            return $this->_validFields[$fieldName];
-        }
-        return null;
-    }
-
-    /**
-     * @param string $fieldName
-     * @return mixed
-     */
-    public function __get($fieldName)
-    {
-        return $this->getEscaped($fieldName);
-    }
-
-    /**
-     * @return boolean
-     */
-    public function hasInvalid()
-    {
-        $this->_process();
-        return !(empty($this->_invalidMessages));
-    }
-
-    /**
-     * @return boolean
-     */
-    public function hasMissing()
-    {
-        $this->_process();
-        return !(empty($this->_missingFields));
-    }
-
-    /**
-     * @return boolean
-     */
-    public function hasUnknown()
-    {
-        $this->_process();
-        return !(empty($this->_unknownFields));
-    }
-
-    /**
-     * @return boolean
-     */
-    public function hasValid()
-    {
-        $this->_process();
-        return !(empty($this->_validFields));
-    }
-
-    /**
-     * @param string $fieldName
-     * @return boolean
-     */
-    public function isValid($fieldName = null)
-    {
-        $this->_process();
-        if ($fieldName === null) {
-            return !($this->hasMissing() || $this->hasInvalid());
-        }
-        return (isset($this->_validFields[$fieldName]) || array_key_exists($fieldName, $this->_validFields));
-    }
-
-    /**
-     * @param string $fieldName
-     * @return boolean
-     */
-    public function __isset($fieldName)
-    {
-        $this->_process();
-        return isset($this->_validFields[$fieldName]);
-    }
-
-    /**
-     * @return Zend_Filter_Input
-     * @throws Zend_Filter_Exception
-     */
-    public function process()
-    {
-        $this->_process();
-        if ($this->hasInvalid()) {
-            require_once 'Zend/Filter/Exception.php';
-            throw new Zend_Filter_Exception("Input has invalid fields");
-        }
-        if ($this->hasMissing()) {
-            require_once 'Zend/Filter/Exception.php';
-            throw new Zend_Filter_Exception("Input has missing fields");
-        }
-
-        return $this;
-    }
-
-    /**
-     * @param array $data
-     * @return Zend_Filter_Input
-     */
-    public function setData(array $data)
-    {
-        $this->_data = $data;
-
-        /**
-         * Reset to initial state
-         */
-        $this->_validFields = array();
-        $this->_invalidMessages = array();
-        $this->_invalidErrors = array();
-        $this->_missingFields = array();
-        $this->_unknownFields = array();
-
-        $this->_processed = false;
-
-        return $this;
-    }
-
-    /**
-     * @param mixed $escapeFilter
-     * @return Zend_Filter_Interface
-     */
-    public function setDefaultEscapeFilter($escapeFilter)
-    {
-        if (is_string($escapeFilter) || is_array($escapeFilter)) {
-            $escapeFilter = $this->_getFilter($escapeFilter);
-        }
-        if (!$escapeFilter instanceof Zend_Filter_Interface) {
-            require_once 'Zend/Filter/Exception.php';
-            throw new Zend_Filter_Exception('Escape filter specified does not implement Zend_Filter_Interface');
-        }
-        $this->_defaultEscapeFilter = $escapeFilter;
-        return $escapeFilter;
-    }
-
-    /**
-     * @param array $options
-     * @return Zend_Filter_Input
-     * @throws Zend_Filter_Exception if an unknown option is given
-     */
-    public function setOptions(array $options)
-    {
-        foreach ($options as $option => $value) {
-            switch ($option) {
-                case self::ESCAPE_FILTER:
-                    $this->setDefaultEscapeFilter($value);
-                    break;
-                case self::INPUT_NAMESPACE:
-                    $this->addNamespace($value);
-                    break;
-                case self::VALIDATOR_NAMESPACE:
-                    if(is_string($value)) {
-                        $value = array($value);
-                    }
-
-                    foreach($value AS $prefix) {
-                        $this->addValidatorPrefixPath(
-                                $prefix,
-                                str_replace('_', DIRECTORY_SEPARATOR, $prefix)
-                        );
-                    }
-                    break;
-                case self::FILTER_NAMESPACE:
-                    if(is_string($value)) {
-                        $value = array($value);
-                    }
-
-                    foreach($value AS $prefix) {
-                        $this->addFilterPrefixPath(
-                                $prefix,
-                                str_replace('_', DIRECTORY_SEPARATOR, $prefix)
-                        );
-                    }
-                    break;
-                case self::ALLOW_EMPTY:
-                case self::BREAK_CHAIN:
-                case self::MISSING_MESSAGE:
-                case self::NOT_EMPTY_MESSAGE:
-                case self::PRESENCE:
-                    $this->_defaults[$option] = $value;
-                    break;
-                default:
-                    require_once 'Zend/Filter/Exception.php';
-                    throw new Zend_Filter_Exception("Unknown option '$option'");
-                    break;
-            }
-        }
-
-        return $this;
-    }
-
-    /*
-     * Protected methods
-     */
-
-    /**
-     * @return void
-     */
-    protected function _filter()
-    {
-        foreach ($this->_filterRules as $ruleName => &$filterRule) {
-            /**
-             * Make sure we have an array representing this filter chain.
-             * Don't typecast to (array) because it might be a Zend_Filter object
-             */
-            if (!is_array($filterRule)) {
-                $filterRule = array($filterRule);
-            }
-
-            /**
-             * Filters are indexed by integer, metacommands are indexed by string.
-             * Pick out the filters.
-             */
-            $filterList = array();
-            foreach ($filterRule as $key => $value) {
-                if (is_int($key)) {
-                    $filterList[] = $value;
-                }
-            }
-
-            /**
-             * Use defaults for filter metacommands.
-             */
-            $filterRule[self::RULE] = $ruleName;
-            if (!isset($filterRule[self::FIELDS])) {
-                $filterRule[self::FIELDS] = $ruleName;
-            }
-
-            /**
-             * Load all the filter classes and add them to the chain.
-             */
-            if (!isset($filterRule[self::FILTER_CHAIN])) {
-                $filterRule[self::FILTER_CHAIN] = new Zend_Filter();
-                foreach ($filterList as $filter) {
-                    if (is_string($filter) || is_array($filter)) {
-                        $filter = $this->_getFilter($filter);
-                    }
-                    $filterRule[self::FILTER_CHAIN]->addFilter($filter);
-                }
-            }
-
-            /**
-             * If the ruleName is the special wildcard rule,
-             * then apply the filter chain to all input data.
-             * Else just process the field named by the rule.
-             */
-            if ($ruleName == self::RULE_WILDCARD) {
-                foreach (array_keys($this->_data) as $field)  {
-                    $this->_filterRule(array_merge($filterRule, array(self::FIELDS => $field)));
-                }
-            } else {
-                $this->_filterRule($filterRule);
-            }
-        }
-    }
-
-    /**
-     * @param array $filterRule
-     * @return void
-     */
-    protected function _filterRule(array $filterRule)
-    {
-        $field = $filterRule[self::FIELDS];
-        if (!(isset($this->_data[$field]) || array_key_exists($field, $this->_data))) {
-            return;
-        }
-        if (is_array($this->_data[$field])) {
-            foreach ($this->_data[$field] as $key => $value) {
-                $this->_data[$field][$key] = $filterRule[self::FILTER_CHAIN]->filter($value);
-            }
-        } else {
-            $this->_data[$field] =
-                $filterRule[self::FILTER_CHAIN]->filter($this->_data[$field]);
-        }
-    }
-
-    /**
-     * @return Zend_Filter_Interface
-     */
-    protected function _getDefaultEscapeFilter()
-    {
-        if ($this->_defaultEscapeFilter !== null) {
-            return $this->_defaultEscapeFilter;
-        }
-        return $this->setDefaultEscapeFilter($this->_defaults[self::ESCAPE_FILTER]);
-    }
-
-    /**
-     * @param string $rule
-     * @param string $field
-     * @return string
-     */
-    protected function _getMissingMessage($rule, $field)
-    {
-        $message = $this->_defaults[self::MISSING_MESSAGE];
-        $message = str_replace('%rule%', $rule, $message);
-        $message = str_replace('%field%', $field, $message);
-        return $message;
-    }
-
-    /**
-     * @return string
-     */
-    protected function _getNotEmptyMessage($rule, $field)
-    {
-        $message = $this->_defaults[self::NOT_EMPTY_MESSAGE];
-        $message = str_replace('%rule%', $rule, $message);
-        $message = str_replace('%field%', $field, $message);
-        return $message;
-    }
-
-    /**
-     * @return void
-     */
-    protected function _process()
-    {
-        if ($this->_processed === false) {
-            $this->_filter();
-            $this->_validate();
-            $this->_processed = true;
-        }
-    }
-
-    /**
-     * @return void
-     */
-    protected function _validate()
-    {
-        /**
-         * Special case: if there are no validators, treat all fields as valid.
-         */
-        if (!$this->_validatorRules) {
-            $this->_validFields = $this->_data;
-            $this->_data = array();
-            return;
-        }
-
-        foreach ($this->_validatorRules as $ruleName => &$validatorRule) {
-            /**
-             * Make sure we have an array representing this validator chain.
-             * Don't typecast to (array) because it might be a Zend_Validate object
-             */
-            if (!is_array($validatorRule)) {
-                $validatorRule = array($validatorRule);
-            }
-
-            /**
-             * Validators are indexed by integer, metacommands are indexed by string.
-             * Pick out the validators.
-             */
-            $validatorList = array();
-            foreach ($validatorRule as $key => $value) {
-                if (is_int($key)) {
-                    $validatorList[$key] = $value;
-                }
-            }
-
-            /**
-             * Use defaults for validation metacommands.
-             */
-            $validatorRule[self::RULE] = $ruleName;
-            if (!isset($validatorRule[self::FIELDS])) {
-                $validatorRule[self::FIELDS] = $ruleName;
-            }
-            if (!isset($validatorRule[self::BREAK_CHAIN])) {
-                $validatorRule[self::BREAK_CHAIN] = $this->_defaults[self::BREAK_CHAIN];
-            }
-            if (!isset($validatorRule[self::PRESENCE])) {
-                $validatorRule[self::PRESENCE] = $this->_defaults[self::PRESENCE];
-            }
-            if (!isset($validatorRule[self::ALLOW_EMPTY])) {
-                $validatorRule[self::ALLOW_EMPTY] = $this->_defaults[self::ALLOW_EMPTY];
-            }
-            if (!isset($validatorRule[self::MESSAGES])) {
-                $validatorRule[self::MESSAGES] = array();
-            } else if (!is_array($validatorRule[self::MESSAGES])) {
-                $validatorRule[self::MESSAGES] = array($validatorRule[self::MESSAGES]);
-            } else if (!array_intersect_key($validatorList, $validatorRule[self::MESSAGES])) {
-                // There are now corresponding numeric keys in the validation rule messages array
-                // Treat it as a named messages list for all rule validators
-                /** @todo Update documentation to describe this possibility */
-                $unifiedMessages = $validatorRule[self::MESSAGES];
-                $validatorRule[self::MESSAGES] = array();
-
-                foreach ($validatorList as $key => $validator) {
-                    $validatorRule[self::MESSAGES][$key] = $unifiedMessages;
-                }
-            }
-
-            /**
-             * Load all the validator classes and add them to the chain.
-             */
-            if (!isset($validatorRule[self::VALIDATOR_CHAIN])) {
-                $validatorRule[self::VALIDATOR_CHAIN] = new Zend_Validate();
-
-                foreach ($validatorList as $key => $validator) {
-                    if (is_string($validator) || is_array($validator)) {
-                        $validator = $this->_getValidator($validator);
-                    }
-                    if (isset($validatorRule[self::MESSAGES][$key])) {
-                        $value = $validatorRule[self::MESSAGES][$key];
-                        if (is_array($value)) {
-                            $validator->setMessages($value);
-                        } else {
-                            $validator->setMessage($value);
-                        }
-                    }
-
-                    $validatorRule[self::VALIDATOR_CHAIN]->addValidator($validator, $validatorRule[self::BREAK_CHAIN]);
-                }
-                $validatorRule[self::VALIDATOR_CHAIN_COUNT] = count($validatorList);
-            }
-
-            /**
-             * If the ruleName is the special wildcard rule,
-             * then apply the validator chain to all input data.
-             * Else just process the field named by the rule.
-             */
-            if ($ruleName == self::RULE_WILDCARD) {
-                foreach (array_keys($this->_data) as $field)  {
-                    $this->_validateRule(array_merge($validatorRule, array(self::FIELDS => $field)));
-                }
-            } else {
-                $this->_validateRule($validatorRule);
-            }
-        }
-
-        /**
-         * Unset fields in $_data that have been added to other arrays.
-         * We have to wait until all rules have been processed because
-         * a given field may be referenced by multiple rules.
-         */
-        foreach (array_merge(array_keys($this->_missingFields), array_keys($this->_invalidMessages)) as $rule) {
-            foreach ((array) $this->_validatorRules[$rule][self::FIELDS] as $field) {
-                unset($this->_data[$field]);
-            }
-        }
-        foreach ($this->_validFields as $field => $value) {
-            unset($this->_data[$field]);
-        }
-
-        /**
-         * Anything left over in $_data is an unknown field.
-         */
-        $this->_unknownFields = $this->_data;
-    }
-
-    /**
-     * @param array $validatorRule
-     * @return void
-     */
-    protected function _validateRule(array $validatorRule)
-    {
-        /**
-         * Get one or more data values from input, and check for missing fields.
-         * Apply defaults if fields are missing.
-         */
-        $data = array();
-        foreach ((array) $validatorRule[self::FIELDS] as $key => $field) {
-            if ((isset($this->_data[$field]) || array_key_exists($field, $this->_data))) {
-                $data[$field] = $this->_data[$field];
-            } else if (isset($validatorRule[self::DEFAULT_VALUE])) {
-                /** @todo according to this code default value can't be an array. It has to be reviewed */
-                if (!is_array($validatorRule[self::DEFAULT_VALUE])) {
-                    // Default value is a scalar
-                    $data[$field] = $validatorRule[self::DEFAULT_VALUE];
-                } else {
-                    // Default value is an array. Search for corresponding key
-                    if (isset($validatorRule[self::DEFAULT_VALUE][$key])) {
-                        $data[$field] = $validatorRule[self::DEFAULT_VALUE][$key];
-                    } else if ($validatorRule[self::PRESENCE] == self::PRESENCE_REQUIRED) {
-                        // Default value array is provided, but it doesn't have an entry for current field
-                        // and presence is required
-                        $this->_missingFields[$validatorRule[self::RULE]][] =
-                           $this->_getMissingMessage($validatorRule[self::RULE], $field);
-                    }
-                }
-            } else if ($validatorRule[self::PRESENCE] == self::PRESENCE_REQUIRED) {
-                $this->_missingFields[$validatorRule[self::RULE]][] =
-                    $this->_getMissingMessage($validatorRule[self::RULE], $field);
-            }
-        }
-
-        /**
-         * If any required fields are missing, break the loop.
-         */
-        if (isset($this->_missingFields[$validatorRule[self::RULE]]) && count($this->_missingFields[$validatorRule[self::RULE]]) > 0) {
-            return;
-        }
-
-        /**
-         * Evaluate the inputs against the validator chain.
-         */
-        if (count((array) $validatorRule[self::FIELDS]) > 1) {
-            if (!$validatorRule[self::ALLOW_EMPTY]) {
-                $emptyFieldsFound = false;
-                $errorsList       = array();
-                $messages         = array();
-
-                foreach ($data as $fieldKey => $field) {
-                    $notEmptyValidator = $this->_getValidator('NotEmpty');
-                    $notEmptyValidator->setMessage($this->_getNotEmptyMessage($validatorRule[self::RULE], $fieldKey));
-
-                    if (!$notEmptyValidator->isValid($field)) {
-                        foreach ($notEmptyValidator->getMessages() as $messageKey => $message) {
-                            if (!isset($messages[$messageKey])) {
-                                $messages[$messageKey] = $message;
-                            } else {
-                                $messages[] = $message;
-                            }
-                        }
-                        $errorsList[] = $notEmptyValidator->getErrors();
-                        $emptyFieldsFound = true;
-                    }
-                }
-                if ($emptyFieldsFound) {
-                    $this->_invalidMessages[$validatorRule[self::RULE]] = $messages;
-                    $this->_invalidErrors[$validatorRule[self::RULE]]   = array_unique(call_user_func_array('array_merge', $errorsList));
-                    return;
-                }
-            }
-            if (!$validatorRule[self::VALIDATOR_CHAIN]->isValid($data)) {
-                $this->_invalidMessages[$validatorRule[self::RULE]] = $validatorRule[self::VALIDATOR_CHAIN]->getMessages();
-                $this->_invalidErrors[$validatorRule[self::RULE]] = $validatorRule[self::VALIDATOR_CHAIN]->getErrors();
-                return;
-            }
-        } else if (count($data) > 0) {
-            // $data is actually a one element array
-            $fieldNames = array_keys($data);
-            $fieldName = reset($fieldNames);
-            $field     = reset($data);
-
-
-            $failed = false;
-            if (!is_array($field)) {
-                $field = array($field);
-            }
-
-
-            $notEmptyValidator = $this->_getValidator('NotEmpty');
-            $notEmptyValidator->setMessage($this->_getNotEmptyMessage($validatorRule[self::RULE], $fieldName));
-            if ($validatorRule[self::ALLOW_EMPTY]) {
-                $validatorChain = $validatorRule[self::VALIDATOR_CHAIN];
-            } else {
-                $validatorChain = new Zend_Validate();
-                $validatorChain->addValidator($notEmptyValidator, true /* Always break on failure */);
-                $validatorChain->addValidator($validatorRule[self::VALIDATOR_CHAIN]);
-            }
-
-            foreach ($field as $value) {
-                if ($validatorRule[self::ALLOW_EMPTY]  &&  !$notEmptyValidator->isValid($value)) {
-                    // Field is empty AND it's allowed. Do nothing.
-                    continue;
-                }
-
-                if (!$validatorChain->isValid($value)) {
-                    if (isset($this->_invalidMessages[$validatorRule[self::RULE]])) {
-                        $collectedMessages = $this->_invalidMessages[$validatorRule[self::RULE]];
-                    } else {
-                        $collectedMessages = array();
-                    }
-
-                    foreach ($validatorChain->getMessages() as $messageKey => $message) {
-                        if (!isset($collectedMessages[$messageKey])) {
-                            $collectedMessages[$messageKey] = $message;
-                        } else {
-                            $collectedMessages[] = $message;
-                        }
-                    }
-
-                    $this->_invalidMessages[$validatorRule[self::RULE]] = $collectedMessages;
-                    if (isset($this->_invalidErrors[$validatorRule[self::RULE]])) {
-                        $this->_invalidErrors[$validatorRule[self::RULE]] = array_merge($this->_invalidErrors[$validatorRule[self::RULE]],
-                                                                                        $validatorChain->getErrors());
-                    } else {
-                        $this->_invalidErrors[$validatorRule[self::RULE]] = $validatorChain->getErrors();
-                    }
-                    unset($this->_validFields[$fieldName]);
-                    $failed = true;
-                    if ($validatorRule[self::BREAK_CHAIN]) {
-                        return;
-                    }
-                }
-            }
-            if ($failed) {
-                return;
-            }
-        }
-
-        /**
-         * If we got this far, the inputs for this rule pass validation.
-         */
-        foreach ((array) $validatorRule[self::FIELDS] as $field) {
-            if ((isset($data[$field]) || array_key_exists($field, $data))) {
-                $this->_validFields[$field] = $data[$field];
-            }
-        }
-    }
-
-    /**
-     * @param mixed $classBaseName
-     * @return Zend_Filter_Interface
-     */
-    protected function _getFilter($classBaseName)
-    {
-        return $this->_getFilterOrValidator(self::FILTER, $classBaseName);
-    }
-
-    /**
-     * @param mixed $classBaseName
-     * @return Zend_Validate_Interface
-     */
-    protected function _getValidator($classBaseName)
-    {
-        return $this->_getFilterOrValidator(self::VALIDATE, $classBaseName);
-    }
-
-    /**
-     * @param string $type
-     * @param mixed $classBaseName
-     * @return Zend_Filter_Interface|Zend_Validate_Interface
-     * @throws Zend_Filter_Exception
-     */
-    protected function _getFilterOrValidator($type, $classBaseName)
-    {
-        $args = array();
-
-        if (is_array($classBaseName)) {
-            $args = $classBaseName;
-            $classBaseName = array_shift($args);
-        }
-
-        $interfaceName = 'Zend_' . ucfirst($type) . '_Interface';
-        $className = $this->getPluginLoader($type)->load(ucfirst($classBaseName));
-
-        $class = new ReflectionClass($className);
-
-        if (!$class->implementsInterface($interfaceName)) {
-            require_once 'Zend/Filter/Exception.php';
-            throw new Zend_Filter_Exception("Class '$className' based on basename '$classBaseName' must implement the '$interfaceName' interface");
-        }
-
-        if ($class->hasMethod('__construct')) {
-            $object = $class->newInstanceArgs($args);
-        } else {
-            $object = $class->newInstance();
-        }
-
-        return $object;
-    }
-
-}
\ No newline at end of file
index d270be6..ccd3764 100644 (file)
@@ -16,9 +16,9 @@
  * @category   Zend
  * @package    Zend_OpenId
  * @subpackage Zend_OpenId_Provider
- * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @copyright  Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
  * @license    http://framework.zend.com/license/new-bsd     New BSD License
- * @version    $Id: Provider.php 10020 2009-08-18 14:34:09Z j.fischer@metaways.de $
+ * @version    $Id$
  */
 
 /**
@@ -37,7 +37,7 @@ require_once "Zend/OpenId/Extension.php";
  * @category   Zend
  * @package    Zend_OpenId
  * @subpackage Zend_OpenId_Provider
- * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @copyright  Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
  * @license    http://framework.zend.com/license/new-bsd     New BSD License
  */
 class Zend_OpenId_Provider
@@ -770,12 +770,34 @@ class Zend_OpenId_Provider
                 $data .= $params['openid_' . strtr($key,'.','_')]."\n";
             }
         }
-        if (base64_decode($params['openid_sig']) ===
-            Zend_OpenId::hashHmac($macFunc, $data, $secret)) {
+        if ($this->_secureStringCompare(base64_decode($params['openid_sig']),
+            Zend_OpenId::hashHmac($macFunc, $data, $secret))) {
             $ret['is_valid'] = 'true';
         } else {
             $ret['is_valid'] = 'false';
         }
         return $ret;
     }
+
+    /**
+     * Securely compare two strings for equality while avoided C level memcmp()
+     * optimisations capable of leaking timing information useful to an attacker
+     * attempting to iteratively guess the unknown string (e.g. password) being
+     * compared against.
+     *
+     * @param string $a
+     * @param string $b
+     * @return bool
+     */
+    protected function _secureStringCompare($a, $b)
+    {
+        if (strlen($a) !== strlen($b)) {
+            return false;
+        }
+        $result = 0;
+        for ($i = 0; $i < strlen($a); $i++) {
+            $result |= ord($a[$i]) ^ ord($b[$i]);
+        }
+        return $result == 0;
+    }
 }
index 508b5a1..dc818f3 100644 (file)
  *
  * @category   Zend
  * @package    Zend_Cache
- * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @copyright  Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
  * @license    http://framework.zend.com/license/new-bsd     New BSD License
- * @version    $Id: Cache.php 10020 2009-08-18 14:34:09Z j.fischer@metaways.de $
+ * @version    $Id$
  */
 
 
 /**
  * @package    Zend_Cache
- * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @copyright  Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
  * @license    http://framework.zend.com/license/new-bsd     New BSD License
  */
 abstract class Zend_Cache
@@ -40,17 +40,18 @@ abstract class Zend_Cache
      *
      * @var array
      */
-    public static $standardBackends = array('File', 'Sqlite', 'Memcached', 'Apc', 'ZendPlatform', 'Xcache', 'TwoLevels');
+    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', 'Sqlite');
-    
+    public static $standardExtendedBackends = array('File', 'Apc', 'TwoLevels', 'Memcached', 'Libmemcached', 'Sqlite', 'WinCache');
+
     /**
-     * Only for backward compatibily (may be removed in next major release)
+     * Only for backward compatibility (may be removed in next major release)
      *
      * @var array
      * @deprecated
@@ -58,12 +59,12 @@ abstract class Zend_Cache
     public static $availableFrontends = array('Core', 'Output', 'Class', 'File', 'Function', 'Page');
 
     /**
-     * Only for backward compatibily (may be removed in next major release)
+     * Only for backward compatibility (may be removed in next major release)
      *
      * @var array
      * @deprecated
      */
-    public static $availableBackends = array('File', 'Sqlite', 'Memcached', 'Apc', 'ZendPlatform', 'Xcache', 'TwoLevels');
+    public static $availableBackends = array('File', 'Sqlite', 'Memcached', 'Libmemcached', 'Apc', 'ZendPlatform', 'Xcache', 'WinCache', 'TwoLevels');
 
     /**
      * Consts for clean() method
@@ -73,7 +74,7 @@ abstract class Zend_Cache
     const CLEANING_MODE_MATCHING_TAG     = 'matchingTag';
     const CLEANING_MODE_NOT_MATCHING_TAG = 'notMatchingTag';
     const CLEANING_MODE_MATCHING_ANY_TAG = 'matchingAnyTag';
-    
+
     /**
      * Factory
      *
@@ -83,7 +84,7 @@ abstract class Zend_Cache
      * @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 (usefull only for custom backends/frontends)
+     * @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
      */
@@ -110,9 +111,9 @@ abstract class Zend_Cache
         $frontendObject->setBackend($backendObject);
         return $frontendObject;
     }
-    
+
     /**
-     * Frontend Constructor
+     * Backend Constructor
      *
      * @param string  $backend
      * @param array   $backendOptions
@@ -132,7 +133,7 @@ abstract class Zend_Cache
             require_once str_replace('_', DIRECTORY_SEPARATOR, $backendClass) . '.php';
         } else {
             // we use a custom backend
-            if (!preg_match('~^[\w]+$~D', $backend)) {
+            if (!preg_match('~^[\w\\\\]+$~D', $backend)) {
                 Zend_Cache::throwException("Invalid backend name [$backend]");
             }
             if (!$customBackendNaming) {
@@ -151,9 +152,9 @@ abstract class Zend_Cache
         }
         return new $backendClass($backendOptions);
     }
-    
+
     /**
-     * Backend Constructor
+     * Frontend Constructor
      *
      * @param string  $frontend
      * @param array   $frontendOptions
@@ -174,7 +175,7 @@ abstract class Zend_Cache
             require_once str_replace('_', DIRECTORY_SEPARATOR, $frontendClass) . '.php';
         } else {
             // we use a custom frontend
-            if (!preg_match('~^[\w]+$~D', $frontend)) {
+            if (!preg_match('~^[\w\\\\]+$~D', $frontend)) {
                 Zend_Cache::throwException("Invalid frontend name [$frontend]");
             }
             if (!$customFrontendNaming) {
@@ -201,11 +202,11 @@ abstract class Zend_Cache
      * @param  string $msg  Message for the exception
      * @throws Zend_Cache_Exception
      */
-    public static function throwException($msg)
+    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);
+        throw new Zend_Cache_Exception($msg, 0, $e);
     }
 
     /**
@@ -220,6 +221,10 @@ abstract class Zend_Cache
         $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;
     }
 
index befcac8..83f1af5 100644 (file)
  * @category   Zend
  * @package    Zend_Cache
  * @subpackage Zend_Cache_Backend
- * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @copyright  Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
  * @license    http://framework.zend.com/license/new-bsd     New BSD License
- * @version    $Id: Backend.php 10020 2009-08-18 14:34:09Z j.fischer@metaways.de $
+ * @version    $Id$
  */
 
 
 /**
  * @package    Zend_Cache
  * @subpackage Zend_Cache_Backend
- * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @copyright  Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
  * @license    http://framework.zend.com/license/new-bsd     New BSD License
  */
 class Zend_Cache_Backend
@@ -58,12 +58,10 @@ class Zend_Cache_Backend
      * 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)) {
+        foreach ($options as $name => $value) {
             $this->setOption($name, $value);
         }
     }
@@ -112,6 +110,28 @@ class Zend_Cache_Backend
     }
 
     /**
+     * Returns an option
+     *
+     * @param string $name Optional, the options name to return
+     * @throws Zend_Cache_Exceptions
+     * @return mixed
+     */
+    public function getOption($name)
+    {
+        $name = strtolower($name);
+
+        if (array_key_exists($name, $this->_options)) {
+            return $this->_options[$name];
+        }
+
+        if (array_key_exists($name, $this->_directives)) {
+            return $this->_directives[$name];
+        }
+
+        Zend_Cache::throwException("Incorrect option name : {$name}");
+    }
+
+    /**
      * Get the life time
      *
      * if $specificLifetime is not false, the given specific life time is used
@@ -140,77 +160,77 @@ class Zend_Cache_Backend
     {
         return true;
     }
-   
+
     /**
      * Determine system TMP directory and detect if we have read access
      *
-     * inspired from Zend_File_Transfer_Adapter_Abstract 
+     * inspired from Zend_File_Transfer_Adapter_Abstract
      *
      * @return string
      * @throws Zend_Cache_Exception if unable to determine directory
      */
     public function getTmpDir()
     {
-       $tmpdir = array();
+        $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')) {
+            foreach (array('TMPDIR', 'TEMP', 'TMP', 'windir', 'SystemRoot') as $key) {
+                if (isset($tab[$key]) && is_string($tab[$key])) {
+                    if (($key == 'windir') or ($key == 'SystemRoot')) {
                         $dir = realpath($tab[$key] . '\\temp');
                     } else {
-                       $dir = realpath($tab[$key]);
+                        $dir = realpath($tab[$key]);
+                    }
+                    if ($this->_isGoodTmpDir($dir)) {
+                        return $dir;
                     }
-                               if ($this->_isGoodTmpDir($dir)) {
-                                       return $dir;
-                               }
-                       }
-               }
+                }
+            }
         }
         $upload = ini_get('upload_tmp_dir');
         if ($upload) {
             $dir = realpath($upload);
-               if ($this->_isGoodTmpDir($dir)) {
-                       return $dir;
-               }
+            if ($this->_isGoodTmpDir($dir)) {
+                return $dir;
+            }
         }
         if (function_exists('sys_get_temp_dir')) {
             $dir = sys_get_temp_dir();
-               if ($this->_isGoodTmpDir($dir)) {
-                       return $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));
+            $dir = realpath(dirname($tempFile));
             unlink($tempFile);
             if ($this->_isGoodTmpDir($dir)) {
                 return $dir;
             }
         }
         if ($this->_isGoodTmpDir('/tmp')) {
-               return '/tmp';
+            return '/tmp';
         }
         if ($this->_isGoodTmpDir('\\temp')) {
-               return '\\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 $dir temporary directory
+     *
+     * @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;
+        if (is_readable($dir)) {
+            if (is_writable($dir)) {
+                return true;
+            }
+        }
+        return false;
     }
 
     /**
@@ -226,24 +246,20 @@ class Zend_Cache_Backend
         if (!isset($this->_directives['logging']) || !$this->_directives['logging']) {
             return;
         }
-        try {
-            /**
-             * @see Zend_Log
-             */
-            require_once 'Zend/Log.php';
-        } catch (Zend_Exception $e) {
-            Zend_Cache::throwException('Logging feature is enabled but the Zend_Log class is not available');
-        }
+
         if (isset($this->_directives['logger'])) {
             if ($this->_directives['logger'] instanceof Zend_Log) {
                 return;
-            } else {
-                Zend_Cache::throwException('Logger object is not an instance of Zend_Log class.');
             }
+            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;
     }
 
@@ -251,7 +267,7 @@ class Zend_Cache_Backend
      * Log a message at the WARN (4) priority.
      *
      * @param  string $message
-     * @throws Zend_Cache_Exception
+     * @param  int    $priority
      * @return void
      */
     protected function _log($message, $priority = 4)
@@ -261,7 +277,7 @@ class Zend_Cache_Backend
         }
 
         if (!isset($this->_directives['logger'])) {
-               Zend_Cache::throwException('Logging is enabled but logger is not set.');
+            Zend_Cache::throwException('Logging is enabled but logger is not set.');
         }
         $logger = $this->_directives['logger'];
         if (!$logger instanceof Zend_Log) {
index 0034d21..5a09bec 100644 (file)
@@ -15,9 +15,9 @@
  * @category   Zend
  * @package    Zend_Cache
  * @subpackage Zend_Cache_Backend
- * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @copyright  Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
  * @license    http://framework.zend.com/license/new-bsd     New BSD License
- * @version    $Id: Apc.php 10020 2009-08-18 14:34:09Z j.fischer@metaways.de $
+ * @version    $Id$
  */
 
 
@@ -35,7 +35,7 @@ require_once 'Zend/Cache/Backend.php';
 /**
  * @package    Zend_Cache
  * @subpackage Zend_Cache_Backend
- * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @copyright  Copyright (c) 2005-2015 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
@@ -166,18 +166,18 @@ class Zend_Cache_Backend_Apc extends Zend_Cache_Backend implements Zend_Cache_Ba
      * Return true if the automatic cleaning is available for the backend
      *
      * DEPRECATED : use getCapabilities() instead
-     * 
-     * @deprecated 
+     *
+     * @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
      */
@@ -195,21 +195,21 @@ class Zend_Cache_Backend_Apc extends Zend_Cache_Backend implements Zend_Cache_Ba
         }
         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
@@ -218,26 +218,26 @@ class Zend_Cache_Backend_Apc extends Zend_Cache_Backend implements Zend_Cache_Ba
     public function getIdsMatchingTags($tags = array())
     {
         $this->_log(self::TAGS_UNSUPPORTED_BY_SAVE_OF_APC_BACKEND);
-        return 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())
     {
         $this->_log(self::TAGS_UNSUPPORTED_BY_SAVE_OF_APC_BACKEND);
-        return 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
@@ -246,25 +246,25 @@ class Zend_Cache_Backend_Apc extends Zend_Cache_Backend implements Zend_Cache_Ba
     public function getIdsMatchingAnyTags($tags = array())
     {
         $this->_log(self::TAGS_UNSUPPORTED_BY_SAVE_OF_APC_BACKEND);
-        return array();         
+        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'];
+        $ids      = array();
+        $iterator = new APCIterator('user', null, APC_ITER_KEY);
+        foreach ($iterator as $item) {
+            $ids[] = $item['key'];
         }
-        return $res;
+
+        return $ids;
     }
-    
+
     /**
      * Return an array of metadatas for the given cache id
      *
@@ -272,7 +272,7 @@ class Zend_Cache_Backend_Apc extends Zend_Cache_Backend implements Zend_Cache_Ba
      * - 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)
      */
@@ -294,9 +294,9 @@ class Zend_Cache_Backend_Apc extends Zend_Cache_Backend implements Zend_Cache_Ba
                 'mtime' => $mtime
             );
         }
-        return false;  
+        return false;
     }
-    
+
     /**
      * Give (if possible) an extra lifetime to the given cache id
      *
@@ -318,17 +318,17 @@ class Zend_Cache_Backend_Apc extends Zend_Cache_Backend implements Zend_Cache_Ba
             $lifetime = $tmp[2];
             $newLifetime = $lifetime - (time() - $mtime) + $extraLifetime;
             if ($newLifetime <=0) {
-                return false; 
+                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)
@@ -337,7 +337,7 @@ class Zend_Cache_Backend_Apc extends Zend_Cache_Backend implements Zend_Cache_Ba
      * - 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()
diff --git a/tine20/library/Zend/Cache/Backend/BlackHole.php b/tine20/library/Zend/Cache/Backend/BlackHole.php
new file mode 100644 (file)
index 0000000..0fe1c9d
--- /dev/null
@@ -0,0 +1,250 @@
+<?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-2015 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-2015 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)
+    {
+    }
+}
index fff53e3..0dd8bdf 100644 (file)
@@ -15,9 +15,9 @@
  * @category   Zend
  * @package    Zend_Cache
  * @subpackage Zend_Cache_Backend
- * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @copyright  Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
  * @license    http://framework.zend.com/license/new-bsd     New BSD License
- * @version    $Id: ExtendedInterface.php 10020 2009-08-18 14:34:09Z j.fischer@metaways.de $
+ * @version    $Id$
  */
 
 /**
@@ -28,7 +28,7 @@ require_once 'Zend/Cache/Backend/Interface.php';
 /**
  * @package    Zend_Cache
  * @subpackage Zend_Cache_Backend
- * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @copyright  Copyright (c) 2005-2015 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
@@ -36,21 +36,21 @@ interface Zend_Cache_Backend_ExtendedInterface extends Zend_Cache_Backend_Interf
 
     /**
      * 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
@@ -60,24 +60,24 @@ interface Zend_Cache_Backend_ExtendedInterface extends Zend_Cache_Backend_Interf
 
     /**
      * 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
      *
@@ -92,12 +92,12 @@ interface Zend_Cache_Backend_ExtendedInterface extends Zend_Cache_Backend_Interf
      * - 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
      *
@@ -106,10 +106,10 @@ interface Zend_Cache_Backend_ExtendedInterface extends Zend_Cache_Backend_Interf
      * @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)
@@ -118,9 +118,9 @@ interface Zend_Cache_Backend_ExtendedInterface extends Zend_Cache_Backend_Interf
      * - 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();
-    
+
 }
index dbfc03a..4e395da 100644 (file)
@@ -15,9 +15,9 @@
  * @category   Zend
  * @package    Zend_Cache
  * @subpackage Zend_Cache_Backend
- * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @copyright  Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
  * @license    http://framework.zend.com/license/new-bsd     New BSD License
- * @version    $Id: File.php 10020 2009-08-18 14:34:09Z j.fischer@metaways.de $
+ * @version    $Id$
  */
 
 /**
@@ -34,7 +34,7 @@ require_once 'Zend/Cache/Backend.php';
 /**
  * @package    Zend_Cache
  * @subpackage Zend_Cache_Backend
- * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @copyright  Copyright (c) 2005-2015 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
@@ -71,7 +71,11 @@ class Zend_Cache_Backend_File extends Zend_Cache_Backend implements Zend_Cache_B
      * for you. Maybe, 1 or 2 is a good start.
      *
      * =====> (int) hashed_directory_umask :
-     * - Umask for hashed directory structure
+     * - deprecated
+     * - Permissions for hashed directory structure
+     *
+     * =====> (int) hashed_directory_perm :
+     * - Permissions for hashed directory structure
      *
      * =====> (string) file_name_prefix :
      * - prefix for cache files
@@ -79,7 +83,11 @@ class Zend_Cache_Backend_File extends Zend_Cache_Backend implements Zend_Cache_B
      *   (like /tmp) can cause disasters when cleaning the cache
      *
      * =====> (int) cache_file_umask :
-     * - Umask for cache files
+     * - deprecated
+     * - Permissions for cache files
+     *
+     * =====> (int) cache_file_perm :
+     * - Permissions for cache files
      *
      * =====> (int) metatadatas_array_max_size :
      * - max size for the metadatas array (don't change this value unless you
@@ -93,9 +101,9 @@ class Zend_Cache_Backend_File extends Zend_Cache_Backend implements Zend_Cache_B
         'read_control' => true,
         'read_control_type' => 'crc32',
         'hashed_directory_level' => 0,
-        'hashed_directory_umask' => 0700,
+        'hashed_directory_perm' => 0700,
         'file_name_prefix' => 'zend_cache',
-        'cache_file_umask' => 0600,
+        'cache_file_perm' => 0600,
         'metadatas_array_max_size' => 100
     );
 
@@ -112,7 +120,6 @@ class Zend_Cache_Backend_File extends Zend_Cache_Backend implements Zend_Cache_B
      *
      * @param  array $options associative array of options
      * @throws Zend_Cache_Exception
-     * @return void
      */
     public function __construct(array $options = array())
     {
@@ -123,20 +130,36 @@ class Zend_Cache_Backend_File extends Zend_Cache_Backend implements Zend_Cache_B
             $this->setCacheDir(self::getTmpDir() . DIRECTORY_SEPARATOR, false);
         }
         if (isset($this->_options['file_name_prefix'])) { // particular case for this option
-            if (!preg_match('~^[\w]+$~', $this->_options['file_name_prefix'])) {
-                Zend_Cache::throwException('Invalid file_name_prefix : must use only [a-zA-A0-9_]');
+            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'])) {
+
+        if (isset($options['hashed_directory_umask'])) {
+            // See #ZF-12047
+            trigger_error("'hashed_directory_umask' is deprecated -> please use 'hashed_directory_perm' instead", E_USER_NOTICE);
+            if (!isset($options['hashed_directory_perm'])) {
+                $options['hashed_directory_perm'] = $options['hashed_directory_umask'];
+            }
+        }
+        if (isset($options['hashed_directory_perm']) && is_string($options['hashed_directory_perm'])) {
             // See #ZF-4422
-            $this->_options['hashed_directory_umask'] = octdec($this->_options['hashed_directory_umask']);
+            $this->_options['hashed_directory_perm'] = octdec($this->_options['hashed_directory_perm']);
+        }
+
+        if (isset($options['cache_file_umask'])) {
+            // See #ZF-12047
+            trigger_error("'cache_file_umask' is deprecated -> please use 'cache_file_perm' instead", E_USER_NOTICE);
+            if (!isset($options['cache_file_perm'])) {
+                $options['cache_file_perm'] = $options['cache_file_umask'];
+            }
         }
-        if (isset($options['cache_file_umask']) && is_string($options['cache_file_umask'])) {
+        if (isset($options['cache_file_perm']) && is_string($options['cache_file_perm'])) {
             // See #ZF-4422
-            $this->_options['cache_file_umask'] = octdec($this->_options['cache_file_umask']);
+            $this->_options['cache_file_perm'] = octdec($this->_options['cache_file_perm']);
         }
     }
 
@@ -151,10 +174,10 @@ class Zend_Cache_Backend_File extends Zend_Cache_Backend implements Zend_Cache_B
     public function setCacheDir($value, $trailingSeparator = true)
     {
         if (!is_dir($value)) {
-            Zend_Cache::throwException('cache_dir must be a directory');
+            Zend_Cache::throwException(sprintf('cache_dir "%s" must be a directory', $value));
         }
         if (!is_writable($value)) {
-            Zend_Cache::throwException('cache_dir is not writable');
+            Zend_Cache::throwException(sprintf('cache_dir "%s" is not writable', $value));
         }
         if ($trailingSeparator) {
             // add a trailing DIRECTORY_SEPARATOR if necessary
@@ -210,10 +233,10 @@ class Zend_Cache_Backend_File extends Zend_Cache_Backend implements Zend_Cache_B
      * 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  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  boolean|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)
@@ -259,24 +282,27 @@ class Zend_Cache_Backend_File extends Zend_Cache_Backend implements Zend_Cache_B
     public function remove($id)
     {
         $file = $this->_file($id);
-        return ($this->_delMetadatas($id) && $this->_remove($file));
+        $boolRemove   = $this->_remove($file);
+        $boolMetadata = $this->_delMetadatas($id);
+        return $boolMetadata && $boolRemove;
     }
 
     /**
      * 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)
+     *
+     * 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
+     * @param array $tags array of tags
      * @return boolean true if no problem
      */
     public function clean($mode = Zend_Cache::CLEANING_MODE_ALL, $tags = array())
@@ -645,16 +671,20 @@ class Zend_Cache_Backend_File extends Zend_Cache_Backend implements Zend_Cache_B
         $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;
         }
+        $metadataFiles = array();
         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;
+                    // In CLEANING_MODE_ALL, we drop anything, even remainings old metadatas files.
+                    // To do that, we need to save the list of the metadata files first.
+                    if ($mode == Zend_Cache::CLEANING_MODE_ALL) {
+                        $metadataFiles[] = $file;
                     }
+                    continue;
                 }
                 $id = $this->_fileNameToId($fileName);
                 $metadatas = $this->_getMetadatas($id);
@@ -663,16 +693,11 @@ class Zend_Cache_Backend_File extends Zend_Cache_Backend implements Zend_Cache_B
                 }
                 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;
+                        $result = $result && $this->remove($id);
                         break;
                     case Zend_Cache::CLEANING_MODE_OLD:
                         if (time() > $metadatas['expire']) {
-                            $result = ($result) && ($this->remove($id));
+                            $result = $this->remove($id) && $result;
                         }
                         break;
                     case Zend_Cache::CLEANING_MODE_MATCHING_TAG:
@@ -684,7 +709,7 @@ class Zend_Cache_Backend_File extends Zend_Cache_Backend implements Zend_Cache_B
                             }
                         }
                         if ($matching) {
-                            $result = ($result) && ($this->remove($id));
+                            $result = $this->remove($id) && $result;
                         }
                         break;
                     case Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG:
@@ -696,7 +721,7 @@ class Zend_Cache_Backend_File extends Zend_Cache_Backend implements Zend_Cache_B
                             }
                         }
                         if (!$matching) {
-                            $result = ($result) && $this->remove($id);
+                            $result = $this->remove($id) && $result;
                         }
                         break;
                     case Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG:
@@ -708,7 +733,7 @@ class Zend_Cache_Backend_File extends Zend_Cache_Backend implements Zend_Cache_B
                             }
                         }
                         if ($matching) {
-                            $result = ($result) && ($this->remove($id));
+                            $result = $this->remove($id) && $result;
                         }
                         break;
                     default:
@@ -718,13 +743,21 @@ class Zend_Cache_Backend_File extends Zend_Cache_Backend implements Zend_Cache_B
             }
             if ((is_dir($file)) and ($this->_options['hashed_directory_level']>0)) {
                 // Recursive call
-                $result = ($result) && ($this->_clean($file . DIRECTORY_SEPARATOR, $mode, $tags));
-                if ($mode=='all') {
-                    // if mode=='all', we try to drop the structure too
+                $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);
                 }
             }
         }
+
+        // cycle through metadataFiles and delete orphaned ones
+        foreach ($metadataFiles as $file) {
+            if (file_exists($file)) {
+                $result = $this->_remove($file) && $result;
+            }
+        }
+
         return $result;
     }
 
@@ -737,7 +770,8 @@ class Zend_Cache_Backend_File extends Zend_Cache_Backend implements Zend_Cache_B
         $prefix = $this->_options['file_name_prefix'];
         $glob = @glob($dir . $prefix . '--*');
         if ($glob === false) {
-            return true;
+            // On some systems it is impossible to distinguish between empty match and an error.
+            return array();
         }
         foreach ($glob as $file)  {
             if (is_file($file)) {
@@ -800,7 +834,12 @@ class Zend_Cache_Backend_File extends Zend_Cache_Backend implements Zend_Cache_B
             }
             if ((is_dir($file)) and ($this->_options['hashed_directory_level']>0)) {
                 // Recursive call
-                $result = array_unique(array_merge($result, $this->_get($file . DIRECTORY_SEPARATOR, $mode, $tags)));
+                $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);
@@ -809,6 +848,7 @@ class Zend_Cache_Backend_File extends Zend_Cache_Backend implements Zend_Cache_B
     /**
      * Compute & return the expire time
      *
+     * @param  int $lifetime
      * @return int expire time (unix timestamp)
      */
     protected function _expireTime($lifetime)
@@ -909,8 +949,8 @@ class Zend_Cache_Backend_File extends Zend_Cache_Backend implements Zend_Cache_B
         $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)
+                @mkdir($part, $this->_options['hashed_directory_perm']);
+                @chmod($part, $this->_options['hashed_directory_perm']); // see #ZF-320 (this line is required in some configurations)
             }
         }
         return true;
@@ -978,7 +1018,7 @@ class Zend_Cache_Backend_File extends Zend_Cache_Backend implements Zend_Cache_B
             }
             @fclose($f);
         }
-        @chmod($file, $this->_options['cache_file_umask']);
+        @chmod($file, $this->_options['cache_file_perm']);
         return $result;
     }
 
index 9d8608e..1bd72d8 100644 (file)
  * @category   Zend
  * @package    Zend_Cache
  * @subpackage Zend_Cache_Backend
- * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @copyright  Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
  * @license    http://framework.zend.com/license/new-bsd     New BSD License
- * @version    $Id: Interface.php 10020 2009-08-18 14:34:09Z j.fischer@metaways.de $
+ * @version    $Id$
  */
 
 
 /**
  * @package    Zend_Cache
  * @subpackage Zend_Cache_Backend
- * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @copyright  Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
  * @license    http://framework.zend.com/license/new-bsd     New BSD License
  */
 interface Zend_Cache_Backend_Interface
diff --git a/tine20/library/Zend/Cache/Backend/Libmemcached.php b/tine20/library/Zend/Cache/Backend/Libmemcached.php
new file mode 100644 (file)
index 0000000..623e757
--- /dev/null
@@ -0,0 +1,484 @@
+<?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-2015 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-2015 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 (null !== $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
+        );
+    }
+
+}
index 2e6c439..9cb9916 100644 (file)
@@ -15,9 +15,9 @@
  * @category   Zend
  * @package    Zend_Cache
  * @subpackage Zend_Cache_Backend
- * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @copyright  Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
  * @license    http://framework.zend.com/license/new-bsd     New BSD License
- * @version    $Id: Memcached.php 10020 2009-08-18 14:34:09Z j.fischer@metaways.de $
+ * @version    $Id$
  */
 
 
@@ -35,7 +35,7 @@ require_once 'Zend/Cache/Backend.php';
 /**
  * @package    Zend_Cache
  * @subpackage Zend_Cache_Backend
- * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @copyright  Copyright (c) 2005-2015 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
@@ -155,16 +155,16 @@ class Zend_Cache_Backend_Memcached extends Zend_Cache_Backend implements Zend_Ca
                 $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'],
+                // 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'],
+            } else {
+                $this->_memcache->addServer($server['host'], $server['port'], $server['persistent'],
                                         $server['weight'], $server['timeout'],
                                         $server['retry_interval'],
                                         $server['status'], $server['failure_callback']);
-                       }
+            }
         }
     }
 
@@ -178,7 +178,7 @@ class Zend_Cache_Backend_Memcached extends Zend_Cache_Backend implements Zend_Ca
     public function load($id, $doNotTestCacheValidity = false)
     {
         $tmp = $this->_memcache->get($id);
-        if (is_array($tmp)) {
+        if (is_array($tmp) && isset($tmp[0])) {
             return $tmp[0];
         }
         return false;
@@ -219,13 +219,14 @@ class Zend_Cache_Backend_Memcached extends Zend_Cache_Backend implements Zend_Ca
         } else {
             $flag = 0;
         }
-        // #ZF-5702 : we try add() first becase set() seems to be slower
-        if (!($result = $this->_memcache->add($id, array($data, time(), $lifetime), $flag, $lifetime))) {
-            $result = $this->_memcache->set($id, array($data, time(), $lifetime), $flag, $lifetime);
-        }
+
+        // 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("Zend_Cache_Backend_Memcached::save() : tags are unsupported by the Memcached backend");
+            $this->_log(self::TAGS_UNSUPPORTED_BY_SAVE_OF_MEMCACHED_BACKEND);
         }
+
         return $result;
     }
 
@@ -237,7 +238,7 @@ class Zend_Cache_Backend_Memcached extends Zend_Cache_Backend implements Zend_Ca
      */
     public function remove($id)
     {
-        return $this->_memcache->delete($id);
+        return $this->_memcache->delete($id, 0);
     }
 
     /**
@@ -380,25 +381,31 @@ class Zend_Cache_Backend_Memcached extends Zend_Cache_Backend implements Zend_Ca
     {
         $mems = $this->_memcache->getExtendedStats();
 
-        $memSize = 0;
-        $memUsed = 0;
+        $memSize = null;
+        $memUsed = null;
         foreach ($mems as $key => $mem) {
-               if ($mem === false) {
-                Zend_Cache::throwException('can\'t get stat from ' . $key);
-               } else {
-                       $eachSize = $mem['limit_maxbytes'];
-                       if ($eachSize == 0) {
-                    Zend_Cache::throwException('can\'t get memory size from ' . $key);
-                       }
-
-                       $eachUsed = $mem['bytes'];
-                       if ($eachUsed > $eachSize) {
-                           $eachUsed = $eachSize;
-                       }
-
-                       $memSize += $eachSize;
-                       $memUsed += $eachUsed;
-               }
+            if ($mem === false) {
+                $this->_log('can\'t get stat from ' . $key);
+                continue;
+            }
+
+            $eachSize = $mem['limit_maxbytes'];
+
+            /**
+             * Couchbase 1.x uses 'mem_used' instead of 'bytes'
+             * @see https://www.couchbase.com/issues/browse/MB-3466
+             */
+            $eachUsed = isset($mem['bytes']) ? $mem['bytes'] : $mem['mem_used'];
+            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)));
@@ -466,7 +473,7 @@ class Zend_Cache_Backend_Memcached extends Zend_Cache_Backend implements Zend_Ca
             }
             // #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);
+                $result = $this->_memcache->set($id, array($data, time(), $newLifetime), $flag, $newLifetime);
             }
             return $result;
         }
index 07728cc..3e8ac82 100644 (file)
@@ -15,9 +15,9 @@
  * @category   Zend
  * @package    Zend_Cache
  * @subpackage Zend_Cache_Backend
- * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @copyright  Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
  * @license    http://framework.zend.com/license/new-bsd     New BSD License
- * @version    $Id: Sqlite.php 10020 2009-08-18 14:34:09Z j.fischer@metaways.de $
+ * @version    $Id$
  */
 
 
@@ -34,7 +34,7 @@ require_once 'Zend/Cache/Backend.php';
 /**
  * @package    Zend_Cache
  * @subpackage Zend_Cache_Backend
- * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @copyright  Copyright (c) 2005-2015 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
@@ -176,7 +176,7 @@ class Zend_Cache_Backend_Sqlite extends Zend_Cache_Backend implements Zend_Cache
         }
         $res = true;
         foreach ($tags as $tag) {
-            $res = $res && $this->_registerTag($id, $tag);
+            $res = $this->_registerTag($id, $tag) && $res;
         }
         return $res;
     }
@@ -530,7 +530,6 @@ class Zend_Cache_Backend_Sqlite extends Zend_Cache_Backend implements Zend_Cache
             $rand = rand(1, $this->_options['automatic_vacuum_factor']);
             if ($rand == 1) {
                 $this->_query('VACUUM');
-                @sqlite_close($this->_getConnection());
             }
         }
     }
@@ -630,7 +629,7 @@ class Zend_Cache_Backend_Sqlite extends Zend_Cache_Backend implements Zend_Cache
                 $ids = $this->getIdsMatchingTags($tags);
                 $result = true;
                 foreach ($ids as $id) {
-                    $result = $result && ($this->remove($id));
+                    $result = $this->remove($id) && $result;
                 }
                 return $result;
                 break;
@@ -638,7 +637,7 @@ class Zend_Cache_Backend_Sqlite extends Zend_Cache_Backend implements Zend_Cache
                 $ids = $this->getIdsNotMatchingTags($tags);
                 $result = true;
                 foreach ($ids as $id) {
-                    $result = $result && ($this->remove($id));
+                    $result = $this->remove($id) && $result;
                 }
                 return $result;
                 break;
@@ -646,7 +645,7 @@ class Zend_Cache_Backend_Sqlite extends Zend_Cache_Backend implements Zend_Cache
                 $ids = $this->getIdsMatchingAnyTags($tags);
                 $result = true;
                 foreach ($ids as $id) {
-                    $result = $result && ($this->remove($id));
+                    $result = $this->remove($id) && $result;
                 }
                 return $result;
                 break;
diff --git a/tine20/library/Zend/Cache/Backend/Static.php b/tine20/library/Zend/Cache/Backend/Static.php
new file mode 100644 (file)
index 0000000..9e3c990
--- /dev/null
@@ -0,0 +1,579 @@
+<?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-2015 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/Interface.php';
+
+/**
+ * @see Zend_Cache_Backend
+ */
+require_once 'Zend/Cache/Backend.php';
+
+/**
+ * @package    Zend_Cache
+ * @subpackage Zend_Cache_Backend
+ * @copyright  Copyright (c) 2005-2015 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_perm'      => 0600,
+        'cache_directory_perm' => 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 {
+            // See #ZF-12047 and #GH-91
+            if ($name == 'cache_file_umask') {
+                trigger_error(
+                    "'cache_file_umask' is deprecated -> please use 'cache_file_perm' instead",
+                    E_USER_NOTICE
+                );
+
+                $name = 'cache_file_perm';
+            }
+            if ($name == 'cache_directory_umask') {
+                trigger_error(
+                    "'cache_directory_umask' is deprecated -> please use 'cache_directory_perm' instead",
+                    E_USER_NOTICE
+                );
+
+                $name = 'cache_directory_perm';
+            }
+
+            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)
+    {
+        $name = strtolower($name);
+
+        if ($name == 'tag_cache') {
+            return $this->getInnerCache();
+        }
+
+        return parent::getOption($name);
+    }
+
+    /**
+     * 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_perm']));
+
+        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_perm']), 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
+     * @throws Zend_Exception
+     */
+    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);
+    }
+}
index 38bcdef..d94e973 100644 (file)
  * @category   Zend
  * @package    Zend_Cache
  * @subpackage Zend_Cache_Backend
- * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @copyright  Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
  * @license    http://framework.zend.com/license/new-bsd     New BSD License
- * @version    $Id: Test.php 10020 2009-08-18 14:34:09Z j.fischer@metaways.de $
+ * @version    $Id$
  */
 
 
 /**
  * @see Zend_Cache_Backend_Interface
  */
-require_once 'Zend/Cache/Backend/Interface.php';
+require_once 'Zend/Cache/Backend/ExtendedInterface.php';
 
 /**
  * @see Zend_Cache_Backend
@@ -34,10 +34,10 @@ require_once 'Zend/Cache/Backend.php';
 /**
  * @package    Zend_Cache
  * @subpackage Zend_Cache_Backend
- * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @copyright  Copyright (c) 2005-2015 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_Interface
+class Zend_Cache_Backend_Test extends Zend_Cache_Backend implements Zend_Cache_Backend_ExtendedInterface
 {
     /**
      * Available options
@@ -103,7 +103,15 @@ class Zend_Cache_Backend_Test extends Zend_Cache_Backend implements Zend_Cache_B
     public function load($id, $doNotTestCacheValidity = false)
     {
         $this->_addLog('get', array($id, $doNotTestCacheValidity));
-        if ($id=='false') {
+
+        if ( $id == 'false'
+          || $id == 'd8523b3ee441006261eeffa5c3d3a0a7'
+          || $id == 'e83249ea22178277d5befc2c5e2e9ace'
+          || $id == '40f649b94977c0a6e76902e2a0b43587'
+          || $id == '88161989b73a4cbfd0b701c446115a99'
+          || $id == '205fc79cba24f0f0018eb92c7c8b3ba4'
+          || $id == '170720e35f38150b811f68a937fb042d')
+        {
             return false;
         }
         if ($id=='serialized') {
@@ -112,11 +120,13 @@ class Zend_Cache_Backend_Test extends Zend_Cache_Backend implements Zend_Cache_B
         if ($id=='serialized2') {
             return serialize(array('headers' => array(), 'data' => 'foo'));
         }
-        if (($id=='71769f39054f75894288e397df04e445') or ($id=='615d222619fb20b527168340cebd0578')) {
+        if ( $id == '71769f39054f75894288e397df04e445' || $id == '615d222619fb20b527168340cebd0578'
+          || $id == '8a02d218a5165c467e7a5747cc6bd4b6' || $id == '648aca1366211d17cbf48e65dc570bee'
+          || $id == '4a923ef02d7f997ca14d56dfeae25ea7') {
             return serialize(array('foo', 'bar'));
         }
-        if (($id=='8a02d218a5165c467e7a5747cc6bd4b6') or ($id=='648aca1366211d17cbf48e65dc570bee')) {
-            return serialize(array('foo', 'bar'));
+        if ( $id == 'f53c7d912cc523d9a65834c8286eceb9') {
+            return serialize(array('foobar'));
         }
         return 'foo';
     }
@@ -136,10 +146,7 @@ class Zend_Cache_Backend_Test extends Zend_Cache_Backend implements Zend_Cache_B
         if ($id=='false') {
             return false;
         }
-        if (($id=='d8523b3ee441006261eeffa5c3d3a0a7') or ($id=='3c439c922209e2cb0b54d6deffccd75a')) {
-            return false;
-        }
-        if (($id=='40f649b94977c0a6e76902e2a0b43587') or ($id=='e83249ea22178277d5befc2c5e2e9ace')) {
+        if (($id=='3c439c922209e2cb0b54d6deffccd75a')) {
             return false;
         }
         return 123456;
@@ -160,7 +167,7 @@ class Zend_Cache_Backend_Test extends Zend_Cache_Backend implements Zend_Cache_B
     public function save($data, $id, $tags = array(), $specificLifetime = false)
     {
         $this->_addLog('save', array($data, $id, $tags));
-        if ($id=='false') {
+        if (substr($id,-5)=='false') {
             return false;
         }
         return true;
@@ -178,7 +185,7 @@ class Zend_Cache_Backend_Test extends Zend_Cache_Backend implements Zend_Cache_B
     public function remove($id)
     {
         $this->_addLog('remove', array($id));
-        if ($id=='false') {
+        if (substr($id,-5)=='false') {
             return false;
         }
         return true;
@@ -252,6 +259,145 @@ class Zend_Cache_Backend_Test extends Zend_Cache_Backend implements Zend_Cache_B
     }
 
     /**
+     * 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
index 2af42ca..135ff6a 100644 (file)
@@ -15,9 +15,9 @@
  * @category   Zend
  * @package    Zend_Cache
  * @subpackage Zend_Cache_Backend
- * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @copyright  Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
  * @license    http://framework.zend.com/license/new-bsd     New BSD License
- * @version    $Id: TwoLevels.php 10020 2009-08-18 14:34:09Z j.fischer@metaways.de $
+ * @version    $Id$
  */
 
 
@@ -35,7 +35,7 @@ require_once 'Zend/Cache/Backend.php';
 /**
  * @package    Zend_Cache
  * @subpackage Zend_Cache_Backend
- * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @copyright  Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
  * @license    http://framework.zend.com/license/new-bsd     New BSD License
  */
 
@@ -72,6 +72,11 @@ class Zend_Cache_Backend_TwoLevels extends Zend_Cache_Backend implements Zend_Ca
      * =====> (boolean) fast_backend_autoload :
      * - See Zend_Cache::factory() method
      *
+     * =====> (boolean) auto_fill_fast_cache
+     * - If true, automatically fill the fast cache when a cache record was not found in fast cache, but did
+     *   exist in slow cache. This can be usefull when a non-persistent cache like APC or Memcached got
+     *   purged for whatever reason.
+     * 
      * =====> (boolean) auto_refresh_fast_cache
      * - If true, auto refresh the fast cache when a cache record is hit
      *
@@ -87,29 +92,30 @@ class Zend_Cache_Backend_TwoLevels extends Zend_Cache_Backend implements Zend_Ca
         'fast_backend_custom_naming' => false,
         'slow_backend_autoload' => false,
         'fast_backend_autoload' => false,
+        'auto_fill_fast_cache' => true,
         'auto_refresh_fast_cache' => true
     );
 
     /**
      * Slow Backend
      *
-     * @var Zend_Cache_Backend
+     * @var Zend_Cache_Backend_ExtendedInterface
      */
-    private $_slowBackend;
+    protected $_slowBackend;
 
     /**
      * Fast Backend
      *
-     * @var Zend_Cache_Backend
+     * @var Zend_Cache_Backend_ExtendedInterface
      */
-    private $_fastBackend;
+    protected $_fastBackend;
 
     /**
      * Cache for the fast backend filling percentage
      *
      * @var int
      */
-    private $_fastBackendFillingPercentage = null;
+    protected $_fastBackendFillingPercentage = null;
 
     /**
      * Constructor
@@ -121,20 +127,39 @@ class Zend_Cache_Backend_TwoLevels extends Zend_Cache_Backend implements Zend_Ca
     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 = Zend_Cache::_makeBackend($this->_options['slow_backend'], $this->_options['slow_backend_options'], $this->_options['slow_backend_custom_naming'], $this->_options['slow_backend_autoload']);
-        $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->_slowBackend))) {
-            Zend_Cache::throwException('slow_backend must implement the Zend_Cache_Backend_ExtendedInterface interface');
-        }
-        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);
     }
@@ -177,8 +202,19 @@ class Zend_Cache_Backend_TwoLevels extends Zend_Cache_Backend implements Zend_Ca
         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;
+                }
+            }
         }
-        $boolSlow = $this->_slowBackend->save($preparedData, $id, $tags, $lifetime);
+
         return ($boolFast && $boolSlow);
     }
 
@@ -193,17 +229,23 @@ class Zend_Cache_Backend_TwoLevels extends Zend_Cache_Backend implements Zend_Ca
      */
     public function load($id, $doNotTestCacheValidity = false)
     {
-        $res = $this->_fastBackend->load($id, $doNotTestCacheValidity);
-        if ($res === false) {
-            $res = $this->_slowBackend->load($id, $doNotTestCacheValidity);
-            if ($res === false) {
+        $resultFast = $this->_fastBackend->load($id, $doNotTestCacheValidity);
+        if ($resultFast === false) {
+            $resultSlow = $this->_slowBackend->load($id, $doNotTestCacheValidity);
+            if ($resultSlow === false) {
                 // there is no cache at all for this id
                 return false;
             }
         }
-        $array = unserialize($res);
+        $array = $resultFast !== false ? unserialize($resultFast) : unserialize($resultSlow);
+        
+        //In case no cache entry was found in the FastCache and auto-filling is enabled, copy data to FastCache
+        if ($resultFast === false && $this->_options['auto_fill_fast_cache']) {
+            $preparedData = $this->_prepareData($array['data'], $array['lifetime'], $array['priority']);
+            $this->_fastBackend->save($preparedData, $id, array(), $array['lifetime']);
+        }
         // maybe, we have to refresh the fast cache ?
-        if ($this->_options['auto_refresh_fast_cache']) {
+        elseif ($this->_options['auto_refresh_fast_cache']) {
             if ($array['priority'] == 10) {
                 // no need to refresh the fast cache with priority = 10
                 return $array['data'];
@@ -228,8 +270,9 @@ class Zend_Cache_Backend_TwoLevels extends Zend_Cache_Backend implements Zend_Ca
      */
     public function remove($id)
     {
-        $this->_fastBackend->remove($id);
-        return $this->_slowBackend->remove($id);
+        $boolFast = $this->_fastBackend->remove($id);
+        $boolSlow = $this->_slowBackend->remove($id);
+        return $boolFast && $boolSlow;
     }
 
     /**
@@ -264,7 +307,8 @@ class Zend_Cache_Backend_TwoLevels extends Zend_Cache_Backend implements Zend_Ca
                 $ids = $this->_slowBackend->getIdsMatchingTags($tags);
                 $res = true;
                 foreach ($ids as $id) {
-                    $res = $res && $this->_slowBackend->remove($id) && $this->_fastBackend->remove($id);
+                    $bool = $this->remove($id);
+                    $res = $res && $bool;
                 }
                 return $res;
                 break;
@@ -272,7 +316,8 @@ class Zend_Cache_Backend_TwoLevels extends Zend_Cache_Backend implements Zend_Ca
                 $ids = $this->_slowBackend->getIdsNotMatchingTags($tags);
                 $res = true;
                 foreach ($ids as $id) {
-                    $res = $res && $this->_slowBackend->remove($id) && $this->_fastBackend->remove($id);
+                    $bool = $this->remove($id);
+                    $res = $res && $bool;
                 }
                 return $res;
                 break;
@@ -280,7 +325,8 @@ class Zend_Cache_Backend_TwoLevels extends Zend_Cache_Backend implements Zend_Ca
                 $ids = $this->_slowBackend->getIdsMatchingAnyTags($tags);
                 $res = true;
                 foreach ($ids as $id) {
-                    $res = $res && $this->_slowBackend->remove($id) && $this->_fastBackend->remove($id);
+                    $bool = $this->remove($id);
+                    $res = $res && $bool;
                 }
                 return $res;
                 break;
@@ -349,7 +395,6 @@ class Zend_Cache_Backend_TwoLevels extends Zend_Cache_Backend implements Zend_Ca
         return $this->_slowBackend->getIdsMatchingAnyTags($tags);
     }
 
-
     /**
      * Return the filling percentage of the backend storage
      *
@@ -447,18 +492,19 @@ class Zend_Cache_Backend_TwoLevels extends Zend_Cache_Backend implements Zend_Ca
      */
     private function _getFastLifetime($lifetime, $priority, $maxLifetime = null)
     {
-        if ($lifetime === null) {
-            // if lifetime is null, we have an infinite lifetime
+        if ($lifetime <= 0) {
+            // if no lifetime, we have an infinite lifetime
             // we need to use arbitrary lifetimes
             $fastLifetime = (int) (2592000 / (11 - $priority));
         } else {
-            $fastLifetime = (int) ($lifetime / (11 - $priority));
+            // prevent computed infinite lifetime (0) by ceil
+            $fastLifetime = (int) ceil($lifetime / (11 - $priority));
         }
-        if (($maxLifetime !== null) && ($maxLifetime >= 0)) {
-            if ($fastLifetime > $maxLifetime) {
-                return $maxLifetime;
-            }
+
+        if ($maxLifetime >= 0 && $fastLifetime > $maxLifetime) {
+            return $maxLifetime;
         }
+
         return $fastLifetime;
     }
 
diff --git a/tine20/library/Zend/Cache/Backend/WinCache.php b/tine20/library/Zend/Cache/Backend/WinCache.php
new file mode 100644 (file)
index 0000000..06843fa
--- /dev/null
@@ -0,0 +1,349 @@
+<?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-2015 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-2015 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 = $memSize - $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
+        );
+    }
+
+}
index 5529dd1..4bc077f 100644 (file)
@@ -15,9 +15,9 @@
  * @category   Zend
  * @package    Zend_Cache
  * @subpackage Zend_Cache_Backend
- * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @copyright  Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
  * @license    http://framework.zend.com/license/new-bsd     New BSD License
- * @version    $Id: Xcache.php 10020 2009-08-18 14:34:09Z j.fischer@metaways.de $
+ * @version    $Id$
  */
 
 
@@ -35,7 +35,7 @@ require_once 'Zend/Cache/Backend.php';
 /**
  * @package    Zend_Cache
  * @subpackage Zend_Cache_Backend
- * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @copyright  Copyright (c) 2005-2015 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
@@ -46,7 +46,7 @@ class Zend_Cache_Backend_Xcache extends Zend_Cache_Backend implements Zend_Cache
      */
     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
      *
@@ -182,7 +182,12 @@ class Zend_Cache_Backend_Xcache extends Zend_Cache_Backend implements Zend_Cache
                 if ($this->_options['password']) {
                     $_SERVER['PHP_AUTH_PW'] = $this->_options['password'];
                 }
-                xcache_clear_cache(XC_TYPE_VAR, 0);
+
+                $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'];
index 1df06cc..31e9a7a 100644 (file)
@@ -15,9 +15,9 @@
  * @category   Zend
  * @package    Zend_Cache
  * @subpackage Zend_Cache_Backend
- * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @copyright  Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
  * @license    http://framework.zend.com/license/new-bsd     New BSD License
- * @version    $Id: ZendPlatform.php 10020 2009-08-18 14:34:09Z j.fischer@metaways.de $
+ * @version    $Id$
  */
 
 /**
@@ -36,7 +36,7 @@ require_once 'Zend/Cache/Backend/Interface.php';
  *
  * @package    Zend_Cache
  * @subpackage Zend_Cache_Backend
- * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @copyright  Copyright (c) 2005-2015 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
index da12364..ededaf5 100755 (executable)
-<?php\r
-/**\r
- * Zend Framework\r
- *\r
- * LICENSE\r
- *\r
- * This source file is subject to the new BSD license that is bundled\r
- * with this package in the file LICENSE.txt.\r
- * It is also available through the world-wide-web at this URL:\r
- * http://framework.zend.com/license/new-bsd\r
- * If you did not receive a copy of the license and are unable to\r
- * obtain it through the world-wide-web, please send an email\r
- * to license@zend.com so we can send you a copy immediately.\r
- *\r
- * @category   Zend\r
- * @package    Zend_Cache\r
- * @subpackage Zend_Cache_Backend\r
- * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)\r
- * @license    http://framework.zend.com/license/new-bsd     New BSD License\r
- * @version    $Id: ZendServer.php 10020 2009-08-18 14:34:09Z j.fischer@metaways.de $\r
- */\r
-\r
-\r
-/** @see Zend_Cache_Backend_Interface */\r
-require_once 'Zend/Cache/Backend/Interface.php';\r
-\r
-/** @see Zend_Cache_Backend */\r
-require_once 'Zend/Cache/Backend.php';\r
-\r
-\r
-/**\r
- * @package    Zend_Cache\r
- * @subpackage Zend_Cache_Backend\r
- * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)\r
- * @license    http://framework.zend.com/license/new-bsd     New BSD License\r
- */\r
-abstract class Zend_Cache_Backend_ZendServer extends Zend_Cache_Backend implements Zend_Cache_Backend_Interface\r
-{\r
-    /**\r
-     * Available options\r
-     *\r
-     * =====> (string) namespace :\r
-     * Namespace to be used for chaching operations\r
-     *\r
-     * @var array available options\r
-     */\r
-    protected $_options = array(\r
-        'namespace' => 'zendframework'\r
-    );\r
-\r
-    /**\r
-     * Store data\r
-     *\r
-     * @param mixed  $data        Object to store\r
-     * @param string $id          Cache id\r
-     * @param int    $timeToLive  Time to live in seconds\r
-     * @throws Zend_Cache_Exception\r
-     */\r
-    abstract protected function _store($data, $id, $timeToLive);\r
-\r
-    /**\r
-     * Fetch data\r
-     *\r
-     * @param string $id          Cache id\r
-     * @throws Zend_Cache_Exception\r
-     */\r
-    abstract protected function _fetch($id);\r
-\r
-    /**\r
-     * Unset data\r
-     *\r
-     * @param string $id          Cache id\r
-     */\r
-    abstract protected function _unset($id);\r
-\r
-    /**\r
-     * Clear cache\r
-     */\r
-    abstract protected function _clear();\r
-\r
-    /**\r
-     * Test if a cache is available for the given id and (if yes) return it (false else)\r
-     *\r
-     * @param  string  $id                     cache id\r
-     * @param  boolean $doNotTestCacheValidity if set to true, the cache validity won't be tested\r
-     * @return string cached datas (or false)\r
-     */\r
-    public function load($id, $doNotTestCacheValidity = false)\r
-    {\r
-        $tmp = $this->_fetch($id);\r
-        if ($tmp !== null) {\r
-            return $tmp;\r
-        }\r
-        return false;\r
-    }\r
-\r
-    /**\r
-     * Test if a cache is available or not (for the given id)\r
-     *\r
-     * @param  string $id cache id\r
-     * @return mixed false (a cache is not available) or "last modified" timestamp (int) of the available cache record\r
-     * @throws Zend_Cache_Exception\r
-     */\r
-    public function test($id)\r
-    {\r
-        $tmp = $this->_fetch('internal-metadatas---' . $id);\r
-        if ($tmp !== null) {\r
-               if (!is_array($tmp) || !isset($tmp['mtime'])) {\r
-                       Zend_Cache::throwException('Cache metadata for \'' . $id . '\' id is corrupted' );\r
-               }\r
-            return $tmp['mtime'];\r
-        }\r
-        return false;\r
-    }\r
-\r
-    /**\r
-     * Compute & return the expire time\r
-     *\r
-     * @return int expire time (unix timestamp)\r
-     */\r
-    private function _expireTime($lifetime)\r
-    {\r
-        if ($lifetime === null) {\r
-            return 9999999999;\r
-        }\r
-        return time() + $lifetime;\r
-    }\r
-\r
-    /**\r
-     * Save some string datas into a cache record\r
-     *\r
-     * Note : $data is always "string" (serialization is done by the\r
-     * core not by the backend)\r
-     *\r
-     * @param string $data datas to cache\r
-     * @param string $id cache id\r
-     * @param array $tags array of strings, the cache record will be tagged by each string entry\r
-     * @param int $specificLifetime if != false, set a specific lifetime for this cache record (null => infinite lifetime)\r
-     * @return boolean true if no problem\r
-     */\r
-    public function save($data, $id, $tags = array(), $specificLifetime = false)\r
-    {\r
-        $lifetime = $this->getLifetime($specificLifetime);\r
-        $metadatas = array(\r
-            'mtime' => time(),\r
-            'expire' => $this->_expireTime($lifetime),\r
-        );\r
-\r
-        if (count($tags) > 0) {\r
-            $this->_log('Zend_Cache_Backend_ZendServer::save() : tags are unsupported by the ZendServer backends');\r
-        }\r
-\r
-        return  $this->_store($data, $id, $lifetime) &&\r
-                $this->_store($metadatas, 'internal-metadatas---' . $id, $lifetime);\r
-    }\r
-\r
-    /**\r
-     * Remove a cache record\r
-     *\r
-     * @param  string $id cache id\r
-     * @return boolean true if no problem\r
-     */\r
-    public function remove($id)\r
-    {\r
-       $result1 = $this->_unset($id);\r
-       $result2 = $this->_unset('internal-metadatas---' . $id);\r
-\r
-        return $result1 && $result2;\r
-    }\r
-\r
-    /**\r
-     * Clean some cache records\r
-     *\r
-     * Available modes are :\r
-     * 'all' (default)  => remove all cache entries ($tags is not used)\r
-     * 'old'            => unsupported\r
-     * 'matchingTag'    => unsupported\r
-     * 'notMatchingTag' => unsupported\r
-     * 'matchingAnyTag' => unsupported\r
-     *\r
-     * @param  string $mode clean mode\r
-     * @param  array  $tags array of tags\r
-     * @throws Zend_Cache_Exception\r
-     * @return boolean true if no problem\r
-     */\r
-    public function clean($mode = Zend_Cache::CLEANING_MODE_ALL, $tags = array())\r
-    {\r
-        switch ($mode) {\r
-            case Zend_Cache::CLEANING_MODE_ALL:\r
-               $this->_clear();\r
-                return true;\r
-                break;\r
-            case Zend_Cache::CLEANING_MODE_OLD:\r
-                $this->_log("Zend_Cache_Backend_ZendServer::clean() : CLEANING_MODE_OLD is unsupported by the Zend Server backends.");\r
-                break;\r
-            case Zend_Cache::CLEANING_MODE_MATCHING_TAG:\r
-            case Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG:\r
-            case Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG:\r
-               $this->_clear();\r
-                $this->_log('Zend_Cache_Backend_ZendServer::clean() : tags are unsupported by the Zend Server backends.');\r
-                break;\r
-            default:\r
-                Zend_Cache::throwException('Invalid mode for clean() method');\r
-                break;\r
-        }\r
-    }\r
-}\r
+<?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-2015 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/Interface.php';
+
+/** @see Zend_Cache_Backend */
+require_once 'Zend/Cache/Backend.php';
+
+
+/**
+ * @package    Zend_Cache
+ * @subpackage Zend_Cache_Backend
+ * @copyright  Copyright (c) 2005-2015 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;
+        }
+    }
+}
index 00a4fb3..54914fe 100755 (executable)
-<?php\r
-/**\r
- * Zend Framework\r
- *\r
- * LICENSE\r
- *\r
- * This source file is subject to the new BSD license that is bundled\r
- * with this package in the file LICENSE.txt.\r
- * It is also available through the world-wide-web at this URL:\r
- * http://framework.zend.com/license/new-bsd\r
- * If you did not receive a copy of the license and are unable to\r
- * obtain it through the world-wide-web, please send an email\r
- * to license@zend.com so we can send you a copy immediately.\r
- *\r
- * @category   Zend\r
- * @package    Zend_Cache\r
- * @subpackage Zend_Cache_Backend\r
- * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)\r
- * @license    http://framework.zend.com/license/new-bsd     New BSD License\r
- * @version    $Id: Disk.php 10020 2009-08-18 14:34:09Z j.fischer@metaways.de $\r
- */\r
-\r
-\r
-/** @see Zend_Cache_Backend_Interface */\r
-require_once 'Zend/Cache/Backend/Interface.php';\r
-\r
-/** @see Zend_Cache_Backend_ZendServer */\r
-require_once 'Zend/Cache/Backend/ZendServer.php';\r
-\r
-\r
-/**\r
- * @package    Zend_Cache\r
- * @subpackage Zend_Cache_Backend\r
- * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)\r
- * @license    http://framework.zend.com/license/new-bsd     New BSD License\r
- */\r
-class Zend_Cache_Backend_ZendServer_Disk extends Zend_Cache_Backend_ZendServer implements Zend_Cache_Backend_Interface\r
-{\r
-    /**\r
-     * Constructor\r
-     *\r
-     * @param  array $options associative array of options\r
-     * @throws Zend_Cache_Exception\r
-     */\r
-    public function __construct(array $options = array())\r
-    {\r
-        if (!function_exists('zend_disk_cache_store')) {\r
-            Zend_Cache::throwException('Zend_Cache_ZendServer_Disk backend has to be used within Zend Server environment.');\r
-        }\r
-        parent::__construct($options);\r
-    }\r
-\r
-       /**\r
-     * Store data\r
-     *\r
-     * @param mixed  $data        Object to store\r
-     * @param string $id          Cache id\r
-     * @param int    $timeToLive  Time to live in seconds\r
-     * @return boolean true if no problem\r
-     */\r
-    protected function _store($data, $id, $timeToLive)\r
-    {\r
-       if (zend_disk_cache_store($this->_options['namespace'] . '::' . $id,\r
-                                 $data,\r
-                                 $timeToLive) === false) {\r
-            $this->_log('Store operation failed.');\r
-            return false;\r
-       }\r
-       return true;\r
-    }\r
-\r
-    /**\r
-     * Fetch data\r
-     *\r
-     * @param string $id          Cache id\r
-     */\r
-    protected function _fetch($id)\r
-    {\r
-       return zend_disk_cache_fetch($this->_options['namespace'] . '::' . $id);\r
-    }\r
-\r
-    /**\r
-     * Unset data\r
-     *\r
-     * @param string $id          Cache id\r
-     * @return boolean true if no problem\r
-     */\r
-    protected function _unset($id)\r
-    {\r
-       return zend_disk_cache_delete($this->_options['namespace'] . '::' . $id);\r
-    }\r
-\r
-    /**\r
-     * Clear cache\r
-     */\r
-    protected function _clear()\r
-    {\r
-       zend_disk_cache_clear($this->_options['namespace']);\r
-    }\r
-}\r
+<?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-2015 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/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-2015 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
+     * @return mixed|null
+     */
+    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']);
+    }
+}
index 97c8f4f..83086dc 100755 (executable)
-<?php\r
-/**\r
- * Zend Framework\r
- *\r
- * LICENSE\r
- *\r
- * This source file is subject to the new BSD license that is bundled\r
- * with this package in the file LICENSE.txt.\r
- * It is also available through the world-wide-web at this URL:\r
- * http://framework.zend.com/license/new-bsd\r
- * If you did not receive a copy of the license and are unable to\r
- * obtain it through the world-wide-web, please send an email\r
- * to license@zend.com so we can send you a copy immediately.\r
- *\r
- * @category   Zend\r
- * @package    Zend_Cache\r
- * @subpackage Zend_Cache_Backend\r
- * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)\r
- * @license    http://framework.zend.com/license/new-bsd     New BSD License\r
- * @version    $Id: ShMem.php 10020 2009-08-18 14:34:09Z j.fischer@metaways.de $\r
- */\r
-\r
-\r
-/** @see Zend_Cache_Backend_Interface */\r
-require_once 'Zend/Cache/Backend/Interface.php';\r
-\r
-/** @see Zend_Cache_Backend_ZendServer */\r
-require_once 'Zend/Cache/Backend/ZendServer.php';\r
-\r
-\r
-/**\r
- * @package    Zend_Cache\r
- * @subpackage Zend_Cache_Backend\r
- * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)\r
- * @license    http://framework.zend.com/license/new-bsd     New BSD License\r
- */\r
-class Zend_Cache_Backend_ZendServer_ShMem extends Zend_Cache_Backend_ZendServer implements Zend_Cache_Backend_Interface\r
-{\r
-    /**\r
-     * Constructor\r
-     *\r
-     * @param  array $options associative array of options\r
-     * @throws Zend_Cache_Exception\r
-     */\r
-    public function __construct(array $options = array())\r
-    {\r
-        if (!function_exists('zend_shm_cache_store')) {\r
-            Zend_Cache::throwException('Zend_Cache_ZendServer_ShMem backend has to be used within Zend Server environment.');\r
-        }\r
-        parent::__construct($options);\r
-    }\r
-\r
-    /**\r
-     * Store data\r
-     *\r
-     * @param mixed  $data        Object to store\r
-     * @param string $id          Cache id\r
-     * @param int    $timeToLive  Time to live in seconds\r
-     *\r
-     */\r
-    protected function _store($data, $id, $timeToLive)\r
-    {\r
-        if (zend_shm_cache_store($this->_options['namespace'] . '::' . $id,\r
-                                  $data,\r
-                                  $timeToLive) === false) {\r
-            $this->_log('Store operation failed.');\r
-            return false;\r
-        }\r
-        return true;\r
-    }\r
-\r
-    /**\r
-     * Fetch data\r
-     *\r
-     * @param string $id          Cache id\r
-     */\r
-    protected function _fetch($id)\r
-    {\r
-        return zend_shm_cache_fetch($this->_options['namespace'] . '::' . $id);\r
-    }\r
-\r
-    /**\r
-     * Unset data\r
-     *\r
-     * @param string $id          Cache id\r
-     * @return boolean true if no problem\r
-     */\r
-    protected function _unset($id)\r
-    {\r
-        return zend_shm_cache_delete($this->_options['namespace'] . '::' . $id);\r
-    }\r
-\r
-    /**\r
-     * Clear cache\r
-     */\r
-    protected function _clear()\r
-    {\r
-        zend_shm_cache_clear($this->_options['namespace']);\r
-    }\r
-}\r
+<?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-2015 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/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-2015 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
+     * @return bool
+     */
+    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
+     * @return mixed|null
+     */
+    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']);
+    }
+}
index 4cf57f3..685d5d5 100644 (file)
  *
  * @category   Zend
  * @package    Zend_Cache
- * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @copyright  Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
  * @license    http://framework.zend.com/license/new-bsd     New BSD License
- * @version    $Id: Core.php 10020 2009-08-18 14:34:09Z j.fischer@metaways.de $
+ * @version    $Id$
  */
 
 
 /**
  * @package    Zend_Cache
- * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @copyright  Copyright (c) 2005-2015 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 object $_backend
+     * @var Zend_Cache_Backend_Interface $_backend
      */
     protected $_backend = null;
 
@@ -124,22 +130,44 @@ class Zend_Cache_Core
     /**
      * Constructor
      *
-     * @param  array $options Associative array of options
+     * @param  array|Zend_Config $options Associative array of options or Zend_Config instance
      * @throws Zend_Cache_Exception
      * @return void
      */
-    public function __construct(array $options = array())
+    public function __construct($options = array())
     {
-        while (list($name, $value) = each($options)) {
+        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.");
+        }
+        foreach ($options as $name => $value) {
             $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();
+        foreach ($options as $name => $value) {
+            $this->setOption($name, $value);
+        }
+        return $this;
+    }
+
+    /**
      * Set the backend
      *
-     * @param  object $backendObject
+     * @param  Zend_Cache_Backend $backendObject
      * @throws Zend_Cache_Exception
      * @return void
      */
@@ -163,7 +191,7 @@ class Zend_Cache_Core
     /**
      * Returns the backend
      *
-     * @return object backend object
+     * @return Zend_Cache_Backend backend object
      */
     public function getBackend()
     {
@@ -183,7 +211,7 @@ class Zend_Cache_Core
     public function setOption($name, $value)
     {
         if (!is_string($name)) {
-            Zend_Cache::throwException("Incorrect option name : $name");
+            Zend_Cache::throwException("Incorrect option name!");
         }
         $name = strtolower($name);
         if (array_key_exists($name, $this->_options)) {
@@ -207,17 +235,18 @@ class Zend_Cache_Core
      */
     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];
-            }
+        $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");
     }
 
@@ -234,6 +263,9 @@ class Zend_Cache_Core
         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;
     }
 
@@ -268,7 +300,9 @@ class Zend_Cache_Core
         }
         $id = $this->_id($id); // cache id may need prefix
         $this->_lastId = $id;
-        self::_validateIdOrTag($id);
+        $this->_validateIdOrTag($id);
+
+        $this->_log("Zend_Cache_Core: load item '{$id}'", 7);
         $data = $this->_backend->load($id, $doNotTestCacheValidity);
         if ($data===false) {
             // no cache available
@@ -285,7 +319,7 @@ class Zend_Cache_Core
      * Test if a cache is available for the given id
      *
      * @param  string $id Cache id
-     * @return boolean True is a cache is available, false else
+     * @return int|false Last modified time of cache entry if it is available, false otherwise
      */
     public function test($id)
     {
@@ -293,8 +327,10 @@ class Zend_Cache_Core
             return false;
         }
         $id = $this->_id($id); // cache id may need prefix
-        self::_validateIdOrTag($id);
+        $this->_validateIdOrTag($id);
         $this->_lastId = $id;
+
+        $this->_log("Zend_Cache_Core: test item '{$id}'", 7);
         return $this->_backend->test($id);
     }
 
@@ -319,8 +355,8 @@ class Zend_Cache_Core
         } else {
             $id = $this->_id($id);
         }
-        self::_validateIdOrTag($id);
-        self::_validateTagsArray($tags);
+        $this->_validateIdOrTag($id);
+        $this->_validateTagsArray($tags);
         if ($this->_options['automatic_serialization']) {
             // we need to serialize datas before storing them
             $data = serialize($data);
@@ -329,27 +365,22 @@ class Zend_Cache_Core
                 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) {
-                if ($this->_extendedBackend) {
-                    // New way
-                    if ($this->_backendCapabilities['automatic_cleaning']) {
-                        $this->clean(Zend_Cache::CLEANING_MODE_OLD);
-                    } else {
-                        $this->_log('Zend_Cache_Core::save() / automatic cleaning is not available/necessary with this backend');
-                    }
+                //  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 {
-                    // Deprecated way (will be removed in next major version)
-                    if (method_exists($this->_backend, 'isAutomaticCleaningAvailable') && ($this->_backend->isAutomaticCleaningAvailable())) {
-                        $this->clean(Zend_Cache::CLEANING_MODE_OLD);
-                    } else {
-                        $this->_log('Zend_Cache_Core::save() / automatic cleaning is not available/necessary with this backend');
-                    }
+                    $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);
         }
@@ -361,22 +392,23 @@ class Zend_Cache_Core
         if ($this->_options['ignore_user_abort']) {
             ignore_user_abort($abort);
         }
+
         if (!$result) {
             // maybe the cache is corrupted, so we remove it !
-            if ($this->_options['logging']) {
-                $this->_log("Zend_Cache_Core::save() : impossible to save cache (id=$id)");
-            }
-            $this->remove($id);
+            $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 : written and read data do not match');
+                $this->_log("Zend_Cache_Core::save(): write control of item '{$id}' failed -> removing it", 4);
                 $this->_backend->remove($id);
                 return false;
             }
         }
+
         return true;
     }
 
@@ -392,7 +424,9 @@ class Zend_Cache_Core
             return true;
         }
         $id = $this->_id($id); // cache id may need prefix
-        self::_validateIdOrTag($id);
+        $this->_validateIdOrTag($id);
+
+        $this->_log("Zend_Cache_Core: remove item '{$id}'", 7);
         return $this->_backend->remove($id);
     }
 
@@ -426,7 +460,8 @@ class Zend_Cache_Core
                                    Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG))) {
             Zend_Cache::throwException('Invalid cleaning mode');
         }
-        self::_validateTagsArray($tags);
+        $this->_validateTagsArray($tags);
+
         return $this->_backend->clean($mode, $tags);
     }
 
@@ -441,12 +476,26 @@ class Zend_Cache_Core
     public function getIdsMatchingTags($tags = array())
     {
         if (!$this->_extendedBackend) {
-            Zend_Cache::throwException('Current backend doesn\'t implement the Zend_Cache_Backend_ExtendedInterface, so this method is not available');
+            Zend_Cache::throwException(self::BACKEND_NOT_IMPLEMENTS_EXTENDED_IF);
         }
         if (!($this->_backendCapabilities['tags'])) {
-            Zend_Cache::throwException('tags are not supported by the current backend');
+            Zend_Cache::throwException(self::BACKEND_NOT_SUPPORTS_TAG);
         }
-        return $this->_backend->getIdsMatchingTags($tags);
+
+        $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;
     }
 
     /**
@@ -460,12 +509,59 @@ class Zend_Cache_Core
     public function getIdsNotMatchingTags($tags = array())
     {
         if (!$this->_extendedBackend) {
-            Zend_Cache::throwException('Current backend doesn\'t implement the Zend_Cache_Backend_ExtendedInterface, so this method is not available');
+            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('tags are not supported by the current backend');
+            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 $this->_backend->getIdsNotMatchingTags($tags);
+
+        return $ids;
     }
 
     /**
@@ -476,20 +572,23 @@ class Zend_Cache_Core
     public function getIds()
     {
         if (!$this->_extendedBackend) {
-            Zend_Cache::throwException('Current backend doesn\'t implement the Zend_Cache_Backend_ExtendedInterface, so this method is not available');
-        }
-        $array = $this->_backend->getIds();
-        if ((!isset($this->_options['cache_id_prefix'])) || ($this->_options['cache_id_prefix'] == '')) return $array;
-        // we need to remove cache_id_prefix from ids (see #ZF-6178)
-        $res = array();
-        while (list(,$id) = each($array)) {
-               if (strpos($id, $this->_options['cache_id_prefix']) === 0) {
-                       $res[] = preg_replace("~^{$this->_options['cache_id_prefix']}~", '', $id);
-               } else {
-                       $res[] = $id;
-               }
-        }
-        return $res;
+            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;
     }
 
     /**
@@ -500,10 +599,10 @@ class Zend_Cache_Core
     public function getTags()
     {
         if (!$this->_extendedBackend) {
-            Zend_Cache::throwException('Current backend doesn\'t implement the Zend_Cache_Backend_ExtendedInterface, so this method is not available');
+            Zend_Cache::throwException(self::BACKEND_NOT_IMPLEMENTS_EXTENDED_IF);
         }
         if (!($this->_backendCapabilities['tags'])) {
-            Zend_Cache::throwException('tags are not supported by the current backend');
+            Zend_Cache::throwException(self::BACKEND_NOT_SUPPORTS_TAG);
         }
         return $this->_backend->getTags();
     }
@@ -516,11 +615,11 @@ class Zend_Cache_Core
     public function getFillingPercentage()
     {
         if (!$this->_extendedBackend) {
-            Zend_Cache::throwException('Current backend doesn\'t implement the Zend_Cache_Backend_ExtendedInterface, so this method is not available');
+            Zend_Cache::throwException(self::BACKEND_NOT_IMPLEMENTS_EXTENDED_IF);
         }
         return $this->_backend->getFillingPercentage();
     }
-    
+
     /**
      * Return an array of metadatas for the given cache id
      *
@@ -534,8 +633,8 @@ class Zend_Cache_Core
      */
     public function getMetadatas($id)
     {
-       if (!$this->_extendedBackend) {
-            Zend_Cache::throwException('Current backend doesn\'t implement the Zend_Cache_Backend_ExtendedInterface, so this method is not available');
+        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);
@@ -551,9 +650,11 @@ class Zend_Cache_Core
     public function touch($id, $extraLifetime)
     {
         if (!$this->_extendedBackend) {
-            Zend_Cache::throwException('Current backend doesn\'t implement the Zend_Cache_Backend_ExtendedInterface, so this method is not available');
+            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);
     }
 
@@ -566,7 +667,7 @@ class Zend_Cache_Core
      * @throws Zend_Cache_Exception
      * @return void
      */
-    protected static function _validateIdOrTag($string)
+    protected function _validateIdOrTag($string)
     {
         if (!is_string($string)) {
             Zend_Cache::throwException('Invalid id or tag : must be a string');
@@ -574,7 +675,7 @@ class Zend_Cache_Core
         if (substr($string, 0, 9) == 'internal-') {
             Zend_Cache::throwException('"internal-*" ids or tags are reserved');
         }
-        if (!preg_match('~^[\w]+$~D', $string)) {
+        if (!preg_match('~^[a-zA-Z0-9_]+$~D', $string)) {
             Zend_Cache::throwException("Invalid id or tag '$string' : must use only [a-zA-Z0-9_]");
         }
     }
@@ -588,13 +689,13 @@ class Zend_Cache_Core
      * @throws Zend_Cache_Exception
      * @return void
      */
-    protected static function _validateTagsArray($tags)
+    protected function _validateTagsArray($tags)
     {
         if (!is_array($tags)) {
             Zend_Cache::throwException('Invalid tags array : must be an array');
         }
         foreach($tags as $tag) {
-            self::_validateIdOrTag($tag);
+            $this->_validateIdOrTag($tag);
         }
         reset($tags);
     }
@@ -618,8 +719,11 @@ class Zend_Cache_Core
         }
 
         // 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;
     }
 
index 9e2102a..ee53b20 100644 (file)
@@ -14,9 +14,9 @@
  *
  * @category   Zend
  * @package    Zend_Cache
- * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @copyright  Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
  * @license    http://framework.zend.com/license/new-bsd     New BSD License
- * @version    $Id: Exception.php 10020 2009-08-18 14:34:09Z j.fischer@metaways.de $
+ * @version    $Id$
  */
 
 /**
@@ -26,7 +26,7 @@ require_once 'Zend/Exception.php';
 
 /**
  * @package    Zend_Cache
- * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @copyright  Copyright (c) 2005-2015 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 {}
diff --git a/tine20/library/Zend/Cache/Frontend/Capture.php b/tine20/library/Zend/Cache/Frontend/Capture.php
new file mode 100644 (file)
index 0000000..32ecc23
--- /dev/null
@@ -0,0 +1,88 @@
+<?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-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id$
+ */
+
+
+/**
+ * @see Zend_Cache_Core
+ */
+require_once 'Zend/Cache/Core.php';
+
+
+/**
+ * @package    Zend_Cache
+ * @subpackage Zend_Cache_Frontend
+ * @copyright  Copyright (c) 2005-2015 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;
+    }
+}
index 781a80b..4740402 100644 (file)
@@ -15,9 +15,9 @@
  * @category   Zend
  * @package    Zend_Cache
  * @subpackage Zend_Cache_Frontend
- * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @copyright  Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
  * @license    http://framework.zend.com/license/new-bsd     New BSD License
- * @version    $Id: Class.php 10020 2009-08-18 14:34:09Z j.fischer@metaways.de $
+ * @version    $Id$
  */
 
 /**
@@ -29,8 +29,8 @@ require_once 'Zend/Cache/Core.php';
 /**
  * @package    Zend_Cache
  * @subpackage Zend_Cache_Frontend
- * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
- * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @copyright  Copyright (c) 2005-2015 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
 {
@@ -53,9 +53,9 @@ class Zend_Cache_Frontend_Class extends Zend_Cache_Core
      * @var array available options
      */
     protected $_specificOptions = array(
-        'cached_entity' => null,
-        'cache_by_default' => true,
-        'cached_methods' => array(),
+        'cached_entity'      => null,
+        'cache_by_default'   => true,
+        'cached_methods'     => array(),
         'non_cached_methods' => array()
     );
 
@@ -64,23 +64,23 @@ class Zend_Cache_Frontend_Class extends Zend_Cache_Core
      *
      * @var array
      */
-    private $_tags = array();
+    protected $_tags = array();
 
     /**
      * SpecificLifetime value
      *
      * false => no specific life time
      *
-     * @var int
+     * @var bool|int
      */
-    private $_specificLifetime = false;
+    protected $_specificLifetime = false;
 
     /**
      * The cached object or the name of the cached abstract class
      *
      * @var mixed
      */
-    private $_cachedEntity = null;
+    protected $_cachedEntity = null;
 
      /**
       * The class name of the cached object or cached abstract class
@@ -89,25 +89,24 @@ class Zend_Cache_Frontend_Class extends Zend_Cache_Core
       *
       * @var string
       */
-    private $_cachedEntityLabel = '';
+    protected $_cachedEntityLabel = '';
 
     /**
      * Priority (used by some particular backends)
      *
      * @var int
      */
-    private $_priority = 8;
+    protected $_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)) {
+        foreach ($options as $name => $value) {
             $this->setOption($name, $value);
         }
         if ($this->_specificOptions['cached_entity'] === null) {
@@ -120,7 +119,7 @@ class Zend_Cache_Frontend_Class extends Zend_Cache_Core
     /**
      * Set a specific life time
      *
-     * @param  int $specificLifetime
+     * @param  bool|int $specificLifetime
      * @return void
      */
     public function setSpecificLifetime($specificLifetime = false)
@@ -168,11 +167,15 @@ class Zend_Cache_Frontend_Class extends Zend_Cache_Core
     public function setCachedEntity($cachedEntity)
     {
         if (!is_string($cachedEntity) && !is_object($cachedEntity)) {
-            Zend_Cache::throwException('cached_entity must be an object or a class name');
+            Zend_Cache::throwException(
+                'cached_entity must be an object or a class name'
+            );
         }
-        $this->_cachedEntity = $cachedEntity;
+
+        $this->_cachedEntity                     = $cachedEntity;
         $this->_specificOptions['cached_entity'] = $cachedEntity;
-        if (is_string($this->_cachedEntity)){
+
+        if (is_string($this->_cachedEntity)) {
             $this->_cachedEntityLabel = $this->_cachedEntity;
         } else {
             $ro = new ReflectionObject($this->_cachedEntity);
@@ -197,47 +200,76 @@ class Zend_Cache_Frontend_Class extends Zend_Cache_Core
      * @param  string $name       Method name
      * @param  array  $parameters Method parameters
      * @return mixed Result
+     * @throws Exception
      */
     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));
+        $cache      = (($cacheBool1 || $cacheBool2) && (!$cacheBool3));
+
         if (!$cache) {
             // We do not have not cache
-            return call_user_func_array(array($this->_cachedEntity, $name), $parameters);
+            return call_user_func_array($callback, $parameters);
         }
-        $id = $this->_makeId($name, $parameters);
-        if ($this->test($id)) {
+
+        $id = $this->makeId($name, $parameters);
+        if (($rs = $this->load($id)) && (array_key_exists(0, $rs))
+            && (array_key_exists(1, $rs))
+        ) {
             // A cache is available
-            $result = $this->load($id);
-            $output = $result[0];
-            $return = $result[1];
+            $output = $rs[0];
+            $return = $rs[1];
         } else {
-            // A cache is not available
+            // A cache is not available (or not valid for this frontend)
             ob_start();
             ob_implicit_flush(false);
-            $return = call_user_func_array(array($this->_cachedEntity, $name), $parameters);
-            $output = ob_get_contents();
-            ob_end_clean();
-            $data = array($output, $return);
-            $this->save($data, $id, $this->_tags, $this->_specificLifetime, $this->_priority);
+
+            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  $parameters Method parameters
+     * @param  string $name Method name
+     * @param  array  $args Method parameters
      * @return string Cache id
      */
-    private function _makeId($name, $parameters)
+    public function makeId($name, array $args = array())
     {
-        return md5($this->_cachedEntityLabel . '__' . $name . '__' . serialize($parameters));
+        return md5($this->_cachedEntityLabel . '__' . $name . '__' . serialize($args));
     }
-
 }
index e99596b..e5017c6 100644 (file)
@@ -15,9 +15,9 @@
  * @category   Zend
  * @package    Zend_Cache
  * @subpackage Zend_Cache_Frontend
- * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @copyright  Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
  * @license    http://framework.zend.com/license/new-bsd     New BSD License
- * @version    $Id: File.php 10020 2009-08-18 14:34:09Z j.fischer@metaways.de $
+ * @version    $Id$
  */
 
 
@@ -30,51 +30,51 @@ require_once 'Zend/Cache/Core.php';
 /**
  * @package    Zend_Cache
  * @subpackage Zend_Cache_Frontend
- * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @copyright  Copyright (c) 2005-2015 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';
-       
+
+    /**
+     * 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 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_file' => null,
         'master_files' => null,
-       'master_files_mode' => 'OR',
-       'ignore_missing_master_files' => false
+        'master_files_mode' => 'OR',
+        'ignore_missing_master_files' => false
     );
 
     /**
      * Master file mtimes
      *
      * Array of int
-     * 
+     *
      * @var array
      */
     private $_masterFile_mtimes = null;
@@ -88,48 +88,61 @@ class Zend_Cache_Frontend_File extends Zend_Cache_Core
      */
     public function __construct(array $options = array())
     {
-        while (list($name, $value) = each($options)) {
+        foreach ($options as $name => $value) {
             $this->setOption($name, $value);
         }
         if (!isset($this->_specificOptions['master_files'])) {
             Zend_Cache::throwException('master_files option must be set');
         }
     }
-    
+
     /**
-     * Change the master_file option
-     * 
-     * @param string $masterFile the complete path and name of the master file
+     * Change the master_files option
+     *
+     * @param array $masterFiles the complete paths and name of the master files
      */
-    public function setMasterFiles($masterFiles)
+    public function setMasterFiles(array $masterFiles)
     {
-        clearstatcache();
-        $this->_specificOptions['master_file'] = $masterFiles[0]; // to keep a compatibility
-        $this->_specificOptions['master_files'] = $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) {
-               $this->_masterFile_mtimes[$i] = @filemtime($masterFile);
-               if ((!($this->_specificOptions['ignore_missing_master_files'])) && (!($this->_masterFile_mtimes[$i]))) {
-                       Zend_Cache::throwException('Unable to read master_file : '.$masterFile);     
-               }
-               $i++;
+            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 
-     * 
+     *
+     * To keep the compatibility
+     *
      * @deprecated
      * @param string $masterFile the complete path and name of the master file
-     */    
+     */
     public function setMasterFile($masterFile)
     {
-               $this->setMasterFiles(array(0 => $masterFile));
+          $this->setMasterFiles(array($masterFile));
     }
-    
+
     /**
      * Public frontend to set an option
      *
@@ -145,7 +158,7 @@ class Zend_Cache_Frontend_File extends Zend_Cache_Core
         if ($name == 'master_file') {
             $this->setMasterFile($value);
         } else if ($name == 'master_files') {
-               $this->setMasterFiles($value);
+            $this->setMasterFiles($value);
         } else {
             parent::setOption($name, $value);
         }
@@ -174,33 +187,33 @@ class Zend_Cache_Frontend_File extends Zend_Cache_Core
      * Test if a cache is available for the given id
      *
      * @param  string $id Cache id
-     * @return boolean True is a cache is available, false else
+     * @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;
-               }
+            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;
     }
index 003d3ad..8af521b 100644 (file)
@@ -15,9 +15,9 @@
  * @category   Zend
  * @package    Zend_Cache
  * @subpackage Zend_Cache_Frontend
- * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @copyright  Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
  * @license    http://framework.zend.com/license/new-bsd     New BSD License
- * @version    $Id: Function.php 10020 2009-08-18 14:34:09Z j.fischer@metaways.de $
+ * @version    $Id$
  */
 
 
@@ -30,7 +30,7 @@ require_once 'Zend/Cache/Core.php';
 /**
  * @package    Zend_Cache
  * @subpackage Zend_Cache_Frontend
- * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @copyright  Copyright (c) 2005-2015 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
@@ -63,7 +63,7 @@ class Zend_Cache_Frontend_Function extends Zend_Cache_Core
      */
     public function __construct(array $options = array())
     {
-        while (list($name, $value) = each($options)) {
+        foreach ($options as $name => $value) {
             $this->setOption($name, $value);
         }
         $this->setOption('automatic_serialization', true);
@@ -72,60 +72,108 @@ class Zend_Cache_Frontend_Function extends Zend_Cache_Core
     /**
      * Main method : call the specified function or get the result from cache
      *
-     * @param  string $name             Function name
-     * @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             
+     * @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($name, $parameters = array(), $tags = array(), $specificLifetime = false, $priority = 8)
+    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) {
-            // We do not have not cache
-            return call_user_func_array($name, $parameters);
+            // Caching of this callback is disabled
+            return call_user_func_array($callback, $parameters);
         }
-        $id = $this->_makeId($name, $parameters);
-        if ($this->test($id)) {
+
+        $id = $this->_makeId($callback, $parameters);
+        if ( ($rs = $this->load($id)) && isset($rs[0], $rs[1])) {
             // A cache is available
-            $result = $this->load($id);
-            $output = $result[0];
-            $return = $result[1];
+            $output = $rs[0];
+            $return = $rs[1];
         } else {
-            // A cache is not available
+            // A cache is not available (or not valid for this frontend)
             ob_start();
             ob_implicit_flush(false);
-            $return = call_user_func_array($name, $parameters);
-            $output = ob_get_contents();
-            ob_end_clean();
+            $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  string $name       Function name
-     * @param  array  $parameters Function parameters
+     * @param  callback $callback A valid callback
+     * @param  array    $args     Function parameters
      * @throws Zend_Cache_Exception
      * @return string Cache id
      */
-    private function _makeId($name, $parameters)
+    public function makeId($callback, array $args = array())
     {
-        if (!is_string($name)) {
-            Zend_Cache::throwException('Incorrect function name');
+        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;
         }
-        if (!is_array($parameters)) {
-            Zend_Cache::throwException('parameters argument must be an array');
+
+        // 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 . serialize($parameters));
+
+        return md5($name . $argsStr);
     }
 
 }
index 18bf590..99a8a64 100644 (file)
@@ -15,9 +15,9 @@
  * @category   Zend
  * @package    Zend_Cache
  * @subpackage Zend_Cache_Frontend
- * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @copyright  Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
  * @license    http://framework.zend.com/license/new-bsd     New BSD License
- * @version    $Id: Output.php 10020 2009-08-18 14:34:09Z j.fischer@metaways.de $
+ * @version    $Id$
  */
 
 
@@ -30,7 +30,7 @@ require_once 'Zend/Cache/Core.php';
 /**
  * @package    Zend_Cache
  * @subpackage Zend_Cache_Frontend
- * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @copyright  Copyright (c) 2005-2015 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
@@ -55,7 +55,7 @@ class Zend_Cache_Frontend_Output extends Zend_Cache_Core
      *
      * @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)
+     * @param  boolean $echoData               If set to true, datas are sent to the browser if the cache is hit (simply 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)
@@ -88,8 +88,7 @@ class Zend_Cache_Frontend_Output extends Zend_Cache_Core
     public function end($tags = array(), $specificLifetime = false, $forcedDatas = null, $echoData = true, $priority = 8)
     {
         if ($forcedDatas === null) {
-            $data = ob_get_contents();
-            ob_end_clean();
+            $data = ob_get_clean();
         } else {
             $data =& $forcedDatas;
         }
index 4aead52..cc253d5 100644 (file)
@@ -15,9 +15,9 @@
  * @category   Zend
  * @package    Zend_Cache
  * @subpackage Zend_Cache_Frontend
- * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @copyright  Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
  * @license    http://framework.zend.com/license/new-bsd     New BSD License
- * @version    $Id: Page.php 10020 2009-08-18 14:34:09Z j.fischer@metaways.de $
+ * @version    $Id$
  */
 
 
@@ -30,7 +30,7 @@ require_once 'Zend/Cache/Core.php';
 /**
  * @package    Zend_Cache
  * @subpackage Zend_Cache_Frontend
- * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @copyright  Copyright (c) 2005-2015 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
@@ -129,7 +129,7 @@ class Zend_Cache_Frontend_Page extends Zend_Cache_Core
      */
     public function __construct(array $options = array())
     {
-        while (list($name, $value) = each($options)) {
+        foreach ($options as $name => $value) {
             $name = strtolower($name);
             switch ($name) {
                 case 'regexps':
@@ -243,9 +243,11 @@ class Zend_Cache_Frontend_Page extends Zend_Cache_Core
     {
         $this->_cancel = false;
         $lastMatchingRegexp = null;
-        foreach ($this->_specificOptions['regexps'] as $regexp => $conf) {
-            if (preg_match("`$regexp`", $_SERVER['REQUEST_URI'])) {
-                $lastMatchingRegexp = $regexp;
+        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'];
@@ -275,7 +277,7 @@ class Zend_Cache_Frontend_Page extends Zend_Cache_Core
                     header("$name: $value");
                 }
             }
-               if ($this->_specificOptions['debug_header']) {
+            if ($this->_specificOptions['debug_header']) {
                 echo 'DEBUG HEADER : This is a cached page !';
             }
             echo $data;
@@ -339,9 +341,9 @@ class Zend_Cache_Frontend_Page extends Zend_Cache_Core
     {
         $tmp = $_SERVER['REQUEST_URI'];
         $array = explode('?', $tmp, 2);
-       $tmp = $array[0];
+          $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']);
+            $tmp2 = $this->_makePartialId($arrayName, $this->_activeOptions['cache_with_' . strtolower($arrayName) . '_variables'], $this->_activeOptions['make_id_with_' . strtolower($arrayName) . '_variables']);
             if ($tmp2===false) {
                 return false;
             }
@@ -360,7 +362,7 @@ class Zend_Cache_Frontend_Page extends Zend_Cache_Core
      */
     protected function _makePartialId($arrayName, $bool1, $bool2)
     {
-       switch ($arrayName) {
+        switch ($arrayName) {
         case 'Get':
             $var = $_GET;
             break;
diff --git a/tine20/library/Zend/Cache/Manager.php b/tine20/library/Zend/Cache/Manager.php
new file mode 100644 (file)
index 0000000..330ea95
--- /dev/null
@@ -0,0 +1,308 @@
+<?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-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id$
+ */
+
+/** @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-2015 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
+     * @throws Zend_Cache_Exception
+     */
+    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'
+            &nbs