--- /dev/null
+<?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_Acl
+ * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ * @version $Id$
+ */
+
+
+/**
+ * @see Zend_Acl_Resource_Interface
+ */
+require_once 'Zend/Acl/Resource/Interface.php';
+
+
+/**
+ * @see Zend_Acl_Role_Registry
+ */
+require_once 'Zend/Acl/Role/Registry.php';
+
+
+/**
+ * @see Zend_Acl_Assert_Interface
+ */
+require_once 'Zend/Acl/Assert/Interface.php';
+
+
+/**
+ * @category Zend
+ * @package Zend_Acl
+ * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+class Zend_Acl
+{
+ /**
+ * Rule type: allow
+ */
+ const TYPE_ALLOW = 'TYPE_ALLOW';
+
+ /**
+ * Rule type: deny
+ */
+ const TYPE_DENY = 'TYPE_DENY';
+
+ /**
+ * Rule operation: add
+ */
+ const OP_ADD = 'OP_ADD';
+
+ /**
+ * Rule operation: remove
+ */
+ const OP_REMOVE = 'OP_REMOVE';
+
+ /**
+ * Role registry
+ *
+ * @var Zend_Acl_Role_Registry
+ */
+ protected $_roleRegistry = null;
+
+ /**
+ * Resource tree
+ *
+ * @var array
+ */
+ protected $_resources = array();
+
+ /**
+ * @var Zend_Acl_Role_Interface
+ */
+ protected $_isAllowedRole = null;
+
+ /**
+ * @var Zend_Acl_Resource_Interface
+ */
+ protected $_isAllowedResource = null;
+
+ /**
+ * ACL rules; whitelist (deny everything to all) by default
+ *
+ * @var array
+ */
+ protected $_rules = array(
+ 'allResources' => array(
+ 'allRoles' => array(
+ 'allPrivileges' => array(
+ 'type' => self::TYPE_DENY,
+ 'assert' => null
+ ),
+ 'byPrivilegeId' => array()
+ ),
+ 'byRoleId' => array()
+ ),
+ 'byResourceId' => array()
+ );
+
+ /**
+ * Adds a Role having an identifier unique to the registry
+ *
+ * The $parents parameter may be a reference to, or the string identifier for,
+ * a Role existing in the registry, or $parents may be passed as an array of
+ * these - mixing string identifiers and objects is ok - to indicate the Roles
+ * from which the newly added Role will directly inherit.
+ *
+ * In order to resolve potential ambiguities with conflicting rules inherited
+ * from different parents, the most recently added parent takes precedence over
+ * parents that were previously added. In other words, the first parent added
+ * will have the least priority, and the last parent added will have the
+ * highest priority.
+ *
+ * @param Zend_Acl_Role_Interface $role
+ * @param Zend_Acl_Role_Interface|string|array $parents
+ * @uses Zend_Acl_Role_Registry::add()
+ * @return Zend_Acl Provides a fluent interface
+ */
+ public function addRole($role, $parents = null)
+ {
+ if (is_string($role)) {
+ $role = new Zend_Acl_Role($role);
+ }
+
+ if (!$role instanceof Zend_Acl_Role_Interface) {
+ require_once 'Zend/Acl/Exception.php';
+ throw new Zend_Acl_Exception('addRole() expects $role to be of type Zend_Acl_Role_Interface');
+ }
+
+
+ $this->_getRoleRegistry()->add($role, $parents);
+
+ return $this;
+ }
+
+ /**
+ * Returns the identified Role
+ *
+ * The $role parameter can either be a Role or Role identifier.
+ *
+ * @param Zend_Acl_Role_Interface|string $role
+ * @uses Zend_Acl_Role_Registry::get()
+ * @return Zend_Acl_Role_Interface
+ */
+ public function getRole($role)
+ {
+ return $this->_getRoleRegistry()->get($role);
+ }
+
+ /**
+ * Returns true if and only if the Role exists in the registry
+ *
+ * The $role parameter can either be a Role or a Role identifier.
+ *
+ * @param Zend_Acl_Role_Interface|string $role
+ * @uses Zend_Acl_Role_Registry::has()
+ * @return boolean
+ */
+ public function hasRole($role)
+ {
+ return $this->_getRoleRegistry()->has($role);
+ }
+
+ /**
+ * Returns true if and only if $role inherits from $inherit
+ *
+ * Both parameters may be either a Role or a Role identifier. If
+ * $onlyParents is true, then $role must inherit directly from
+ * $inherit in order to return true. By default, this method looks
+ * through the entire inheritance DAG to determine whether $role
+ * inherits from $inherit through its ancestor Roles.
+ *
+ * @param Zend_Acl_Role_Interface|string $role
+ * @param Zend_Acl_Role_Interface|string $inherit
+ * @param boolean $onlyParents
+ * @uses Zend_Acl_Role_Registry::inherits()
+ * @return boolean
+ */
+ public function inheritsRole($role, $inherit, $onlyParents = false)
+ {
+ return $this->_getRoleRegistry()->inherits($role, $inherit, $onlyParents);
+ }
+
+ /**
+ * Removes the Role from the registry
+ *
+ * The $role parameter can either be a Role or a Role identifier.
+ *
+ * @param Zend_Acl_Role_Interface|string $role
+ * @uses Zend_Acl_Role_Registry::remove()
+ * @return Zend_Acl Provides a fluent interface
+ */
+ public function removeRole($role)
+ {
+ $this->_getRoleRegistry()->remove($role);
+
+ if ($role instanceof Zend_Acl_Role_Interface) {
+ $roleId = $role->getRoleId();
+ } else {
+ $roleId = $role;
+ }
+
+ foreach ($this->_rules['allResources']['byRoleId'] as $roleIdCurrent => $rules) {
+ if ($roleId === $roleIdCurrent) {
+ unset($this->_rules['allResources']['byRoleId'][$roleIdCurrent]);
+ }
+ }
+ foreach ($this->_rules['byResourceId'] as $resourceIdCurrent => $visitor) {
+ if (array_key_exists('byRoleId', $visitor)) {
+ foreach ($visitor['byRoleId'] as $roleIdCurrent => $rules) {
+ if ($roleId === $roleIdCurrent) {
+ unset($this->_rules['byResourceId'][$resourceIdCurrent]['byRoleId'][$roleIdCurrent]);
+ }
+ }
+ }
+ }
+
+ return $this;
+ }
+
+ /**
+ * Removes all Roles from the registry
+ *
+ * @uses Zend_Acl_Role_Registry::removeAll()
+ * @return Zend_Acl Provides a fluent interface
+ */
+ public function removeRoleAll()
+ {
+ $this->_getRoleRegistry()->removeAll();
+
+ foreach ($this->_rules['allResources']['byRoleId'] as $roleIdCurrent => $rules) {
+ unset($this->_rules['allResources']['byRoleId'][$roleIdCurrent]);
+ }
+ foreach ($this->_rules['byResourceId'] as $resourceIdCurrent => $visitor) {
+ foreach ($visitor['byRoleId'] as $roleIdCurrent => $rules) {
+ unset($this->_rules['byResourceId'][$resourceIdCurrent]['byRoleId'][$roleIdCurrent]);
+ }
+ }
+
+ return $this;
+ }
+
+ /**
+ * Adds a Resource having an identifier unique to the ACL
+ *
+ * The $parent parameter may be a reference to, or the string identifier for,
+ * the existing Resource from which the newly added Resource will inherit.
+ *
+ * @param Zend_Acl_Resource_Interface|string $resource
+ * @param Zend_Acl_Resource_Interface|string $parent
+ * @throws Zend_Acl_Exception
+ * @return Zend_Acl Provides a fluent interface
+ */
+ public function addResource($resource, $parent = null)
+ {
+ if (is_string($resource)) {
+ $resource = new Zend_Acl_Resource($resource);
+ }
+
+ if (!$resource instanceof Zend_Acl_Resource_Interface) {
+ require_once 'Zend/Acl/Exception.php';
+ throw new Zend_Acl_Exception('addResource() expects $resource to be of type Zend_Acl_Resource_Interface');
+ }
+
+ $resourceId = $resource->getResourceId();
+
+ if ($this->has($resourceId)) {
+ require_once 'Zend/Acl/Exception.php';
+ throw new Zend_Acl_Exception("Resource id '$resourceId' already exists in the ACL");
+ }
+
+ $resourceParent = null;
+
+ if (null !== $parent) {
+ try {
+ if ($parent instanceof Zend_Acl_Resource_Interface) {
+ $resourceParentId = $parent->getResourceId();
+ } else {
+ $resourceParentId = $parent;
+ }
+ $resourceParent = $this->get($resourceParentId);
+ } catch (Zend_Acl_Exception $e) {
+ throw new Zend_Acl_Exception("Parent Resource id '$resourceParentId' does not exist");
+ }
+ $this->_resources[$resourceParentId]['children'][$resourceId] = $resource;
+ }
+
+ $this->_resources[$resourceId] = array(
+ 'instance' => $resource,
+ 'parent' => $resourceParent,
+ 'children' => array()
+ );
+
+ return $this;
+ }
+
+ /**
+ * Adds a Resource having an identifier unique to the ACL
+ *
+ * The $parent parameter may be a reference to, or the string identifier for,
+ * the existing Resource from which the newly added Resource will inherit.
+ *
+ * @deprecated in version 1.9.1 and will be available till 2.0. New code
+ * should use addResource() instead.
+ *
+ * @param Zend_Acl_Resource_Interface $resource
+ * @param Zend_Acl_Resource_Interface|string $parent
+ * @throws Zend_Acl_Exception
+ * @return Zend_Acl Provides a fluent interface
+ */
+ public function add(Zend_Acl_Resource_Interface $resource, $parent = null)
+ {
+ return $this->addResource($resource, $parent);
+ }
+
+ /**
+ * Returns the identified Resource
+ *
+ * The $resource parameter can either be a Resource or a Resource identifier.
+ *
+ * @param Zend_Acl_Resource_Interface|string $resource
+ * @throws Zend_Acl_Exception
+ * @return Zend_Acl_Resource_Interface
+ */
+ public function get($resource)
+ {
+ if ($resource instanceof Zend_Acl_Resource_Interface) {
+ $resourceId = $resource->getResourceId();
+ } else {
+ $resourceId = (string) $resource;
+ }
+
+ if (!$this->has($resource)) {
+ require_once 'Zend/Acl/Exception.php';
+ throw new Zend_Acl_Exception("Resource '$resourceId' not found");
+ }
+
+ return $this->_resources[$resourceId]['instance'];
+ }
+
+ /**
+ * Returns true if and only if the Resource exists in the ACL
+ *
+ * The $resource parameter can either be a Resource or a Resource identifier.
+ *
+ * @param Zend_Acl_Resource_Interface|string $resource
+ * @return boolean
+ */
+ public function has($resource)
+ {
+ if ($resource instanceof Zend_Acl_Resource_Interface) {
+ $resourceId = $resource->getResourceId();
+ } else {
+ $resourceId = (string) $resource;
+ }
+
+ return isset($this->_resources[$resourceId]);
+ }
+
+ /**
+ * Returns true if and only if $resource inherits from $inherit
+ *
+ * Both parameters may be either a Resource or a Resource identifier. If
+ * $onlyParent is true, then $resource must inherit directly from
+ * $inherit in order to return true. By default, this method looks
+ * through the entire inheritance tree to determine whether $resource
+ * inherits from $inherit through its ancestor Resources.
+ *
+ * @param Zend_Acl_Resource_Interface|string $resource
+ * @param Zend_Acl_Resource_Interface|string $inherit
+ * @param boolean $onlyParent
+ * @throws Zend_Acl_Resource_Registry_Exception
+ * @return boolean
+ */
+ public function inherits($resource, $inherit, $onlyParent = false)
+ {
+ try {
+ $resourceId = $this->get($resource)->getResourceId();
+ $inheritId = $this->get($inherit)->getResourceId();
+ } catch (Zend_Acl_Exception $e) {
+ throw $e;
+ }
+
+ if (null !== $this->_resources[$resourceId]['parent']) {
+ $parentId = $this->_resources[$resourceId]['parent']->getResourceId();
+ if ($inheritId === $parentId) {
+ return true;
+ } else if ($onlyParent) {
+ return false;
+ }
+ } else {
+ return false;
+ }
+
+ while (null !== $this->_resources[$parentId]['parent']) {
+ $parentId = $this->_resources[$parentId]['parent']->getResourceId();
+ if ($inheritId === $parentId) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Removes a Resource and all of its children
+ *
+ * The $resource parameter can either be a Resource or a Resource identifier.
+ *
+ * @param Zend_Acl_Resource_Interface|string $resource
+ * @throws Zend_Acl_Exception
+ * @return Zend_Acl Provides a fluent interface
+ */
+ public function remove($resource)
+ {
+ try {
+ $resourceId = $this->get($resource)->getResourceId();
+ } catch (Zend_Acl_Exception $e) {
+ throw $e;
+ }
+
+ $resourcesRemoved = array($resourceId);
+ if (null !== ($resourceParent = $this->_resources[$resourceId]['parent'])) {
+ unset($this->_resources[$resourceParent->getResourceId()]['children'][$resourceId]);
+ }
+ foreach ($this->_resources[$resourceId]['children'] as $childId => $child) {
+ $this->remove($childId);
+ $resourcesRemoved[] = $childId;
+ }
+
+ foreach ($resourcesRemoved as $resourceIdRemoved) {
+ foreach ($this->_rules['byResourceId'] as $resourceIdCurrent => $rules) {
+ if ($resourceIdRemoved === $resourceIdCurrent) {
+ unset($this->_rules['byResourceId'][$resourceIdCurrent]);
+ }
+ }
+ }
+
+ unset($this->_resources[$resourceId]);
+
+ return $this;
+ }
+
+ /**
+ * Removes all Resources
+ *
+ * @return Zend_Acl Provides a fluent interface
+ */
+ public function removeAll()
+ {
+ foreach ($this->_resources as $resourceId => $resource) {
+ foreach ($this->_rules['byResourceId'] as $resourceIdCurrent => $rules) {
+ if ($resourceId === $resourceIdCurrent) {
+ unset($this->_rules['byResourceId'][$resourceIdCurrent]);
+ }
+ }
+ }
+
+ $this->_resources = array();
+
+ return $this;
+ }
+
+ /**
+ * Adds an "allow" rule to the ACL
+ *
+ * @param Zend_Acl_Role_Interface|string|array $roles
+ * @param Zend_Acl_Resource_Interface|string|array $resources
+ * @param string|array $privileges
+ * @param Zend_Acl_Assert_Interface $assert
+ * @uses Zend_Acl::setRule()
+ * @return Zend_Acl Provides a fluent interface
+ */
+ public function allow($roles = null, $resources = null, $privileges = null, Zend_Acl_Assert_Interface $assert = null)
+ {
+ return $this->setRule(self::OP_ADD, self::TYPE_ALLOW, $roles, $resources, $privileges, $assert);
+ }
+
+ /**
+ * Adds a "deny" rule to the ACL
+ *
+ * @param Zend_Acl_Role_Interface|string|array $roles
+ * @param Zend_Acl_Resource_Interface|string|array $resources
+ * @param string|array $privileges
+ * @param Zend_Acl_Assert_Interface $assert
+ * @uses Zend_Acl::setRule()
+ * @return Zend_Acl Provides a fluent interface
+ */
+ public function deny($roles = null, $resources = null, $privileges = null, Zend_Acl_Assert_Interface $assert = null)
+ {
+ return $this->setRule(self::OP_ADD, self::TYPE_DENY, $roles, $resources, $privileges, $assert);
+ }
+
+ /**
+ * Removes "allow" permissions from the ACL
+ *
+ * @param Zend_Acl_Role_Interface|string|array $roles
+ * @param Zend_Acl_Resource_Interface|string|array $resources
+ * @param string|array $privileges
+ * @uses Zend_Acl::setRule()
+ * @return Zend_Acl Provides a fluent interface
+ */
+ public function removeAllow($roles = null, $resources = null, $privileges = null)
+ {
+ return $this->setRule(self::OP_REMOVE, self::TYPE_ALLOW, $roles, $resources, $privileges);
+ }
+
+ /**
+ * Removes "deny" restrictions from the ACL
+ *
+ * @param Zend_Acl_Role_Interface|string|array $roles
+ * @param Zend_Acl_Resource_Interface|string|array $resources
+ * @param string|array $privileges
+ * @uses Zend_Acl::setRule()
+ * @return Zend_Acl Provides a fluent interface
+ */
+ public function removeDeny($roles = null, $resources = null, $privileges = null)
+ {
+ return $this->setRule(self::OP_REMOVE, self::TYPE_DENY, $roles, $resources, $privileges);
+ }
+
+ /**
+ * Performs operations on ACL rules
+ *
+ * The $operation parameter may be either OP_ADD or OP_REMOVE, depending on whether the
+ * user wants to add or remove a rule, respectively:
+ *
+ * OP_ADD specifics:
+ *
+ * A rule is added that would allow one or more Roles access to [certain $privileges
+ * upon] the specified Resource(s).
+ *
+ * OP_REMOVE specifics:
+ *
+ * The rule is removed only in the context of the given Roles, Resources, and privileges.
+ * Existing rules to which the remove operation does not apply would remain in the
+ * ACL.
+ *
+ * The $type parameter may be either TYPE_ALLOW or TYPE_DENY, depending on whether the
+ * rule is intended to allow or deny permission, respectively.
+ *
+ * The $roles and $resources parameters may be references to, or the string identifiers for,
+ * existing Resources/Roles, or they may be passed as arrays of these - mixing string identifiers
+ * and objects is ok - to indicate the Resources and Roles to which the rule applies. If either
+ * $roles or $resources is null, then the rule applies to all Roles or all Resources, respectively.
+ * Both may be null in order to work with the default rule of the ACL.
+ *
+ * The $privileges parameter may be used to further specify that the rule applies only
+ * to certain privileges upon the Resource(s) in question. This may be specified to be a single
+ * privilege with a string, and multiple privileges may be specified as an array of strings.
+ *
+ * If $assert is provided, then its assert() method must return true in order for
+ * the rule to apply. If $assert is provided with $roles, $resources, and $privileges all
+ * equal to null, then a rule having a type of:
+ *
+ * TYPE_ALLOW will imply a type of TYPE_DENY, and
+ *
+ * TYPE_DENY will imply a type of TYPE_ALLOW
+ *
+ * when the rule's assertion fails. This is because the ACL needs to provide expected
+ * behavior when an assertion upon the default ACL rule fails.
+ *
+ * @param string $operation
+ * @param string $type
+ * @param Zend_Acl_Role_Interface|string|array $roles
+ * @param Zend_Acl_Resource_Interface|string|array $resources
+ * @param string|array $privileges
+ * @param Zend_Acl_Assert_Interface $assert
+ * @throws Zend_Acl_Exception
+ * @uses Zend_Acl_Role_Registry::get()
+ * @uses Zend_Acl::get()
+ * @return Zend_Acl Provides a fluent interface
+ */
+ public function setRule($operation, $type, $roles = null, $resources = null, $privileges = null,
+ Zend_Acl_Assert_Interface $assert = null)
+ {
+ // ensure that the rule type is valid; normalize input to uppercase
+ $type = strtoupper($type);
+ if (self::TYPE_ALLOW !== $type && self::TYPE_DENY !== $type) {
+ require_once 'Zend/Acl/Exception.php';
+ throw new Zend_Acl_Exception("Unsupported rule type; must be either '" . self::TYPE_ALLOW . "' or '"
+ . self::TYPE_DENY . "'");
+ }
+
+ // ensure that all specified Roles exist; normalize input to array of Role objects or null
+ if (!is_array($roles)) {
+ $roles = array($roles);
+ } else if (0 === count($roles)) {
+ $roles = array(null);
+ }
+ $rolesTemp = $roles;
+ $roles = array();
+ foreach ($rolesTemp as $role) {
+ if (null !== $role) {
+ $roles[] = $this->_getRoleRegistry()->get($role);
+ } else {
+ $roles[] = null;
+ }
+ }
+ unset($rolesTemp);
+
+ // ensure that all specified Resources exist; normalize input to array of Resource objects or null
+ if (!is_array($resources)) {
+ $resources = array($resources);
+ } else if (0 === count($resources)) {
+ $resources = array(null);
+ }
+ $resourcesTemp = $resources;
+ $resources = array();
+ foreach ($resourcesTemp as $resource) {
+ if (null !== $resource) {
+ $resources[] = $this->get($resource);
+ } else {
+ $resources[] = null;
+ }
+ }
+ unset($resourcesTemp);
+
+ // normalize privileges to array
+ if (null === $privileges) {
+ $privileges = array();
+ } else if (!is_array($privileges)) {
+ $privileges = array($privileges);
+ }
+
+ switch ($operation) {
+
+ // add to the rules
+ case self::OP_ADD:
+ foreach ($resources as $resource) {
+ foreach ($roles as $role) {
+ $rules =& $this->_getRules($resource, $role, true);
+ if (0 === count($privileges)) {
+ $rules['allPrivileges']['type'] = $type;
+ $rules['allPrivileges']['assert'] = $assert;
+ if (!isset($rules['byPrivilegeId'])) {
+ $rules['byPrivilegeId'] = array();
+ }
+ } else {
+ foreach ($privileges as $privilege) {
+ $rules['byPrivilegeId'][$privilege]['type'] = $type;
+ $rules['byPrivilegeId'][$privilege]['assert'] = $assert;
+ }
+ }
+ }
+ }
+ break;
+
+ // remove from the rules
+ case self::OP_REMOVE:
+ foreach ($resources as $resource) {
+ foreach ($roles as $role) {
+ $rules =& $this->_getRules($resource, $role);
+ if (null === $rules) {
+ continue;
+ }
+ if (0 === count($privileges)) {
+ if (null === $resource && null === $role) {
+ if ($type === $rules['allPrivileges']['type']) {
+ $rules = array(
+ 'allPrivileges' => array(
+ 'type' => self::TYPE_DENY,
+ 'assert' => null
+ ),
+ 'byPrivilegeId' => array()
+ );
+ }
+ continue;
+ }
+ if ($type === $rules['allPrivileges']['type']) {
+ unset($rules['allPrivileges']);
+ }
+ } else {
+ foreach ($privileges as $privilege) {
+ if (isset($rules['byPrivilegeId'][$privilege]) &&
+ $type === $rules['byPrivilegeId'][$privilege]['type']) {
+ unset($rules['byPrivilegeId'][$privilege]);
+ }
+ }
+ }
+ }
+ }
+ break;
+
+ default:
+ require_once 'Zend/Acl/Exception.php';
+ throw new Zend_Acl_Exception("Unsupported operation; must be either '" . self::OP_ADD . "' or '"
+ . self::OP_REMOVE . "'");
+ }
+
+ return $this;
+ }
+
+ /**
+ * Returns true if and only if the Role has access to the Resource
+ *
+ * The $role and $resource parameters may be references to, or the string identifiers for,
+ * an existing Resource and Role combination.
+ *
+ * If either $role or $resource is null, then the query applies to all Roles or all Resources,
+ * respectively. Both may be null to query whether the ACL has a "blacklist" rule
+ * (allow everything to all). By default, Zend_Acl creates a "whitelist" rule (deny
+ * everything to all), and this method would return false unless this default has
+ * been overridden (i.e., by executing $acl->allow()).
+ *
+ * If a $privilege is not provided, then this method returns false if and only if the
+ * Role is denied access to at least one privilege upon the Resource. In other words, this
+ * method returns true if and only if the Role is allowed all privileges on the Resource.
+ *
+ * This method checks Role inheritance using a depth-first traversal of the Role registry.
+ * The highest priority parent (i.e., the parent most recently added) is checked first,
+ * and its respective parents are checked similarly before the lower-priority parents of
+ * the Role are checked.
+ *
+ * @param Zend_Acl_Role_Interface|string $role
+ * @param Zend_Acl_Resource_Interface|string $resource
+ * @param string $privilege
+ * @uses Zend_Acl::get()
+ * @uses Zend_Acl_Role_Registry::get()
+ * @return boolean
+ */
+ public function isAllowed($role = null, $resource = null, $privilege = null)
+ {
+ // reset role & resource to null
+ $this->_isAllowedRole = $this->_isAllowedResource = null;
+
+ if (null !== $role) {
+ // keep track of originally called role
+ $this->_isAllowedRole = $role;
+ $role = $this->_getRoleRegistry()->get($role);
+ if (!$this->_isAllowedRole instanceof Zend_Acl_Role_Interface) {
+ $this->_isAllowedRole = $role;
+ }
+ }
+
+ if (null !== $resource) {
+ // keep track of originally called resource
+ $this->_isAllowedResource = $resource;
+ $resource = $this->get($resource);
+ if (!$this->_isAllowedResource instanceof Zend_Acl_Resource_Interface) {
+ $this->_isAllowedResource = $resource;
+ }
+ }
+
+ if (null === $privilege) {
+ // query on all privileges
+ do {
+ // depth-first search on $role if it is not 'allRoles' pseudo-parent
+ if (null !== $role && null !== ($result = $this->_roleDFSAllPrivileges($role, $resource, $privilege))) {
+ return $result;
+ }
+
+ // look for rule on 'allRoles' psuedo-parent
+ if (null !== ($rules = $this->_getRules($resource, null))) {
+ foreach ($rules['byPrivilegeId'] as $privilege => $rule) {
+ if (self::TYPE_DENY === ($ruleTypeOnePrivilege = $this->_getRuleType($resource, null, $privilege))) {
+ return false;
+ }
+ }
+ if (null !== ($ruleTypeAllPrivileges = $this->_getRuleType($resource, null, null))) {
+ return self::TYPE_ALLOW === $ruleTypeAllPrivileges;
+ }
+ }
+
+ // try next Resource
+ $resource = $this->_resources[$resource->getResourceId()]['parent'];
+
+ } while (true); // loop terminates at 'allResources' pseudo-parent
+ } else {
+ // query on one privilege
+ do {
+ // depth-first search on $role if it is not 'allRoles' pseudo-parent
+ if (null !== $role && null !== ($result = $this->_roleDFSOnePrivilege($role, $resource, $privilege))) {
+ return $result;
+ }
+
+ // look for rule on 'allRoles' pseudo-parent
+ if (null !== ($ruleType = $this->_getRuleType($resource, null, $privilege))) {
+ return self::TYPE_ALLOW === $ruleType;
+ } else if (null !== ($ruleTypeAllPrivileges = $this->_getRuleType($resource, null, null))) {
+ return self::TYPE_ALLOW === $ruleTypeAllPrivileges;
+ }
+
+ // try next Resource
+ $resource = $this->_resources[$resource->getResourceId()]['parent'];
+
+ } while (true); // loop terminates at 'allResources' pseudo-parent
+ }
+ }
+
+ /**
+ * Returns the Role registry for this ACL
+ *
+ * If no Role registry has been created yet, a new default Role registry
+ * is created and returned.
+ *
+ * @return Zend_Acl_Role_Registry
+ */
+ protected function _getRoleRegistry()
+ {
+ if (null === $this->_roleRegistry) {
+ $this->_roleRegistry = new Zend_Acl_Role_Registry();
+ }
+ return $this->_roleRegistry;
+ }
+
+ /**
+ * Performs a depth-first search of the Role DAG, starting at $role, in order to find a rule
+ * allowing/denying $role access to all privileges upon $resource
+ *
+ * This method returns true if a rule is found and allows access. If a rule exists and denies access,
+ * then this method returns false. If no applicable rule is found, then this method returns null.
+ *
+ * @param Zend_Acl_Role_Interface $role
+ * @param Zend_Acl_Resource_Interface $resource
+ * @return boolean|null
+ */
+ protected function _roleDFSAllPrivileges(Zend_Acl_Role_Interface $role, Zend_Acl_Resource_Interface $resource = null)
+ {
+ $dfs = array(
+ 'visited' => array(),
+ 'stack' => array()
+ );
+
+ if (null !== ($result = $this->_roleDFSVisitAllPrivileges($role, $resource, $dfs))) {
+ return $result;
+ }
+
+ while (null !== ($role = array_pop($dfs['stack']))) {
+ if (!isset($dfs['visited'][$role->getRoleId()])) {
+ if (null !== ($result = $this->_roleDFSVisitAllPrivileges($role, $resource, $dfs))) {
+ return $result;
+ }
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Visits an $role in order to look for a rule allowing/denying $role access to all privileges upon $resource
+ *
+ * This method returns true if a rule is found and allows access. If a rule exists and denies access,
+ * then this method returns false. If no applicable rule is found, then this method returns null.
+ *
+ * This method is used by the internal depth-first search algorithm and may modify the DFS data structure.
+ *
+ * @param Zend_Acl_Role_Interface $role
+ * @param Zend_Acl_Resource_Interface $resource
+ * @param array $dfs
+ * @return boolean|null
+ * @throws Zend_Acl_Exception
+ */
+ protected function _roleDFSVisitAllPrivileges(Zend_Acl_Role_Interface $role, Zend_Acl_Resource_Interface $resource = null,
+ &$dfs = null)
+ {
+ if (null === $dfs) {
+ /**
+ * @see Zend_Acl_Exception
+ */
+ require_once 'Zend/Acl/Exception.php';
+ throw new Zend_Acl_Exception('$dfs parameter may not be null');
+ }
+
+ if (null !== ($rules = $this->_getRules($resource, $role))) {
+ foreach ($rules['byPrivilegeId'] as $privilege => $rule) {
+ if (self::TYPE_DENY === ($ruleTypeOnePrivilege = $this->_getRuleType($resource, $role, $privilege))) {
+ return false;
+ }
+ }
+ if (null !== ($ruleTypeAllPrivileges = $this->_getRuleType($resource, $role, null))) {
+ return self::TYPE_ALLOW === $ruleTypeAllPrivileges;
+ }
+ }
+
+ $dfs['visited'][$role->getRoleId()] = true;
+ foreach ($this->_getRoleRegistry()->getParents($role) as $roleParentId => $roleParent) {
+ $dfs['stack'][] = $roleParent;
+ }
+
+ return null;
+ }
+
+ /**
+ * Performs a depth-first search of the Role DAG, starting at $role, in order to find a rule
+ * allowing/denying $role access to a $privilege upon $resource
+ *
+ * This method returns true if a rule is found and allows access. If a rule exists and denies access,
+ * then this method returns false. If no applicable rule is found, then this method returns null.
+ *
+ * @param Zend_Acl_Role_Interface $role
+ * @param Zend_Acl_Resource_Interface $resource
+ * @param string $privilege
+ * @return boolean|null
+ * @throws Zend_Acl_Exception
+ */
+ protected function _roleDFSOnePrivilege(Zend_Acl_Role_Interface $role, Zend_Acl_Resource_Interface $resource = null,
+ $privilege = null)
+ {
+ if (null === $privilege) {
+ /**
+ * @see Zend_Acl_Exception
+ */
+ require_once 'Zend/Acl/Exception.php';
+ throw new Zend_Acl_Exception('$privilege parameter may not be null');
+ }
+
+ $dfs = array(
+ 'visited' => array(),
+ 'stack' => array()
+ );
+
+ if (null !== ($result = $this->_roleDFSVisitOnePrivilege($role, $resource, $privilege, $dfs))) {
+ return $result;
+ }
+
+ while (null !== ($role = array_pop($dfs['stack']))) {
+ if (!isset($dfs['visited'][$role->getRoleId()])) {
+ if (null !== ($result = $this->_roleDFSVisitOnePrivilege($role, $resource, $privilege, $dfs))) {
+ return $result;
+ }
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Visits an $role in order to look for a rule allowing/denying $role access to a $privilege upon $resource
+ *
+ * This method returns true if a rule is found and allows access. If a rule exists and denies access,
+ * then this method returns false. If no applicable rule is found, then this method returns null.
+ *
+ * This method is used by the internal depth-first search algorithm and may modify the DFS data structure.
+ *
+ * @param Zend_Acl_Role_Interface $role
+ * @param Zend_Acl_Resource_Interface $resource
+ * @param string $privilege
+ * @param array $dfs
+ * @return boolean|null
+ * @throws Zend_Acl_Exception
+ */
+ protected function _roleDFSVisitOnePrivilege(Zend_Acl_Role_Interface $role, Zend_Acl_Resource_Interface $resource = null,
+ $privilege = null, &$dfs = null)
+ {
+ if (null === $privilege) {
+ /**
+ * @see Zend_Acl_Exception
+ */
+ require_once 'Zend/Acl/Exception.php';
+ throw new Zend_Acl_Exception('$privilege parameter may not be null');
+ }
+
+ if (null === $dfs) {
+ /**
+ * @see Zend_Acl_Exception
+ */
+ require_once 'Zend/Acl/Exception.php';
+ throw new Zend_Acl_Exception('$dfs parameter may not be null');
+ }
+
+ if (null !== ($ruleTypeOnePrivilege = $this->_getRuleType($resource, $role, $privilege))) {
+ return self::TYPE_ALLOW === $ruleTypeOnePrivilege;
+ } else if (null !== ($ruleTypeAllPrivileges = $this->_getRuleType($resource, $role, null))) {
+ return self::TYPE_ALLOW === $ruleTypeAllPrivileges;
+ }
+
+ $dfs['visited'][$role->getRoleId()] = true;
+ foreach ($this->_getRoleRegistry()->getParents($role) as $roleParentId => $roleParent) {
+ $dfs['stack'][] = $roleParent;
+ }
+
+ return null;
+ }
+
+ /**
+ * Returns the rule type associated with the specified Resource, Role, and privilege
+ * combination.
+ *
+ * If a rule does not exist or its attached assertion fails, which means that
+ * the rule is not applicable, then this method returns null. Otherwise, the
+ * rule type applies and is returned as either TYPE_ALLOW or TYPE_DENY.
+ *
+ * If $resource or $role is null, then this means that the rule must apply to
+ * all Resources or Roles, respectively.
+ *
+ * If $privilege is null, then the rule must apply to all privileges.
+ *
+ * If all three parameters are null, then the default ACL rule type is returned,
+ * based on whether its assertion method passes.
+ *
+ * @param Zend_Acl_Resource_Interface $resource
+ * @param Zend_Acl_Role_Interface $role
+ * @param string $privilege
+ * @return string|null
+ */
+ protected function _getRuleType(Zend_Acl_Resource_Interface $resource = null, Zend_Acl_Role_Interface $role = null,
+ $privilege = null)
+ {
+ // get the rules for the $resource and $role
+ if (null === ($rules = $this->_getRules($resource, $role))) {
+ return null;
+ }
+
+ // follow $privilege
+ if (null === $privilege) {
+ if (isset($rules['allPrivileges'])) {
+ $rule = $rules['allPrivileges'];
+ } else {
+ return null;
+ }
+ } else if (!isset($rules['byPrivilegeId'][$privilege])) {
+ return null;
+ } else {
+ $rule = $rules['byPrivilegeId'][$privilege];
+ }
+
+ // check assertion first
+ if ($rule['assert']) {
+ $assertion = $rule['assert'];
+ $assertionValue = $assertion->assert(
+ $this,
+ ($this->_isAllowedRole instanceof Zend_Acl_Role_Interface) ? $this->_isAllowedRole : $role,
+ ($this->_isAllowedResource instanceof Zend_Acl_Resource_Interface) ? $this->_isAllowedResource : $resource,
+ $privilege
+ );
+ }
+
+ if (null === $rule['assert'] || $assertionValue) {
+ return $rule['type'];
+ } else if (null !== $resource || null !== $role || null !== $privilege) {
+ return null;
+ } else if (self::TYPE_ALLOW === $rule['type']) {
+ return self::TYPE_DENY;
+ } else {
+ return self::TYPE_ALLOW;
+ }
+ }
+
+ /**
+ * Returns the rules associated with a Resource and a Role, or null if no such rules exist
+ *
+ * If either $resource or $role is null, this means that the rules returned are for all Resources or all Roles,
+ * respectively. Both can be null to return the default rule set for all Resources and all Roles.
+ *
+ * If the $create parameter is true, then a rule set is first created and then returned to the caller.
+ *
+ * @param Zend_Acl_Resource_Interface $resource
+ * @param Zend_Acl_Role_Interface $role
+ * @param boolean $create
+ * @return array|null
+ */
+ protected function &_getRules(Zend_Acl_Resource_Interface $resource = null, Zend_Acl_Role_Interface $role = null,
+ $create = false)
+ {
+ // create a reference to null
+ $null = null;
+ $nullRef =& $null;
+
+ // follow $resource
+ do {
+ if (null === $resource) {
+ $visitor =& $this->_rules['allResources'];
+ break;
+ }
+ $resourceId = $resource->getResourceId();
+ if (!isset($this->_rules['byResourceId'][$resourceId])) {
+ if (!$create) {
+ return $nullRef;
+ }
+ $this->_rules['byResourceId'][$resourceId] = array();
+ }
+ $visitor =& $this->_rules['byResourceId'][$resourceId];
+ } while (false);
+
+
+ // follow $role
+ if (null === $role) {
+ if (!isset($visitor['allRoles'])) {
+ if (!$create) {
+ return $nullRef;
+ }
+ $visitor['allRoles']['byPrivilegeId'] = array();
+ }
+ return $visitor['allRoles'];
+ }
+ $roleId = $role->getRoleId();
+ if (!isset($visitor['byRoleId'][$roleId])) {
+ if (!$create) {
+ return $nullRef;
+ }
+ $visitor['byRoleId'][$roleId]['byPrivilegeId'] = array();
+ }
+ return $visitor['byRoleId'][$roleId];
+ }
+
+
+ /**
+ * @return array of registered roles
+ *
+ */
+ public function getRegisteredRoles()
+ {
+ return $this->_getRoleRegistry()->getRoles();
+ }
+
+}
--- /dev/null
+<?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_Application
+ * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ * @version $Id$
+ */
+
+/**
+ * @category Zend
+ * @package Zend_Application
+ * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+class Zend_Application
+{
+ /**
+ * Autoloader to use
+ *
+ * @var Zend_Loader_Autoloader
+ */
+ protected $_autoloader;
+
+ /**
+ * Bootstrap
+ *
+ * @var Zend_Application_Bootstrap_BootstrapAbstract
+ */
+ protected $_bootstrap;
+
+ /**
+ * Application environment
+ *
+ * @var string
+ */
+ protected $_environment;
+
+ /**
+ * Flattened (lowercase) option keys
+ *
+ * @var array
+ */
+ protected $_optionKeys = array();
+
+ /**
+ * Options for Zend_Application
+ *
+ * @var array
+ */
+ protected $_options = array();
+
+ /**
+ * Constructor
+ *
+ * Initialize application. Potentially initializes include_paths, PHP
+ * settings, and bootstrap class.
+ *
+ * @param string $environment
+ * @param string|array|Zend_Config $options String path to configuration file, or array/Zend_Config of configuration options
+ * @throws Zend_Application_Exception When invalid options are provided
+ * @return void
+ */
+ public function __construct($environment, $options = null)
+ {
+ $this->_environment = (string) $environment;
+
+ require_once 'Zend/Loader/Autoloader.php';
+ $this->_autoloader = Zend_Loader_Autoloader::getInstance();
+
+ if (null !== $options) {
+ if (is_string($options)) {
+ $options = $this->_loadConfig($options);
+ } elseif ($options instanceof Zend_Config) {
+ $options = $options->toArray();
+ } elseif (!is_array($options)) {
+ throw new Zend_Application_Exception('Invalid options provided; must be location of config file, a config object, or an array');
+ }
+
+ $this->setOptions($options);
+ }
+ }
+
+ /**
+ * Retrieve current environment
+ *
+ * @return string
+ */
+ public function getEnvironment()
+ {
+ return $this->_environment;
+ }
+
+ /**
+ * Retrieve autoloader instance
+ *
+ * @return Zend_Loader_Autoloader
+ */
+ public function getAutoloader()
+ {
+ return $this->_autoloader;
+ }
+
+ /**
+ * Set application options
+ *
+ * @param array $options
+ * @throws Zend_Application_Exception When no bootstrap path is provided
+ * @throws Zend_Application_Exception When invalid bootstrap information are provided
+ * @return Zend_Application
+ */
+ public function setOptions(array $options)
+ {
+ if (!empty($options['config'])) {
+ $options = $this->mergeOptions($options, $this->_loadConfig($options['config']));
+ }
+
+ $this->_options = $options;
+
+ $options = array_change_key_case($options, CASE_LOWER);
+
+ $this->_optionKeys = array_keys($options);
+
+ if (!empty($options['phpsettings'])) {
+ $this->setPhpSettings($options['phpsettings']);
+ }
+
+ if (!empty($options['includepaths'])) {
+ $this->setIncludePaths($options['includepaths']);
+ }
+
+ if (!empty($options['autoloadernamespaces'])) {
+ $this->setAutoloaderNamespaces($options['autoloadernamespaces']);
+ }
+
+ if (!empty($options['autoloaderzfpath'])) {
+ $autoloader = $this->getAutoloader();
+ if (method_exists($autoloader, 'setZfPath')) {
+ $zfPath = $options['autoloaderzfpath'];
+ $zfVersion = !empty($options['autoloaderzfversion'])
+ ? $options['autoloaderzfversion']
+ : 'latest';
+ $autoloader->setZfPath($zfPath, $zfVersion);
+ }
+ }
+
+ if (!empty($options['bootstrap'])) {
+ $bootstrap = $options['bootstrap'];
+
+ if (is_string($bootstrap)) {
+ $this->setBootstrap($bootstrap);
+ } elseif (is_array($bootstrap)) {
+ if (empty($bootstrap['path'])) {
+ throw new Zend_Application_Exception('No bootstrap path provided');
+ }
+
+ $path = $bootstrap['path'];
+ $class = null;
+
+ if (!empty($bootstrap['class'])) {
+ $class = $bootstrap['class'];
+ }
+
+ $this->setBootstrap($path, $class);
+ } else {
+ throw new Zend_Application_Exception('Invalid bootstrap information provided');
+ }
+ }
+
+ return $this;
+ }
+
+ /**
+ * Retrieve application options (for caching)
+ *
+ * @return array
+ */
+ public function getOptions()
+ {
+ return $this->_options;
+ }
+
+ /**
+ * Is an option present?
+ *
+ * @param string $key
+ * @return bool
+ */
+ public function hasOption($key)
+ {
+ return in_array(strtolower($key), $this->_optionKeys);
+ }
+
+ /**
+ * Retrieve a single option
+ *
+ * @param string $key
+ * @return mixed
+ */
+ public function getOption($key)
+ {
+ if ($this->hasOption($key)) {
+ $options = $this->getOptions();
+ $options = array_change_key_case($options, CASE_LOWER);
+ return $options[strtolower($key)];
+ }
+ return null;
+ }
+
+ /**
+ * Merge options recursively
+ *
+ * @param array $array1
+ * @param mixed $array2
+ * @return array
+ */
+ public function mergeOptions(array $array1, $array2 = null)
+ {
+ if (is_array($array2)) {
+ foreach ($array2 as $key => $val) {
+ if (is_array($array2[$key])) {
+ $array1[$key] = (array_key_exists($key, $array1) && is_array($array1[$key]))
+ ? $this->mergeOptions($array1[$key], $array2[$key])
+ : $array2[$key];
+ } else {
+ $array1[$key] = $val;
+ }
+ }
+ }
+ return $array1;
+ }
+
+ /**
+ * Set PHP configuration settings
+ *
+ * @param array $settings
+ * @param string $prefix Key prefix to prepend to array values (used to map . separated INI values)
+ * @return Zend_Application
+ */
+ public function setPhpSettings(array $settings, $prefix = '')
+ {
+ foreach ($settings as $key => $value) {
+ $key = empty($prefix) ? $key : $prefix . $key;
+ if (is_scalar($value)) {
+ ini_set($key, $value);
+ } elseif (is_array($value)) {
+ $this->setPhpSettings($value, $key . '.');
+ }
+ }
+
+ return $this;
+ }
+
+ /**
+ * Set include path
+ *
+ * @param array $paths
+ * @return Zend_Application
+ */
+ public function setIncludePaths(array $paths)
+ {
+ $path = implode(PATH_SEPARATOR, $paths);
+ set_include_path($path . PATH_SEPARATOR . get_include_path());
+ return $this;
+ }
+
+ /**
+ * Set autoloader namespaces
+ *
+ * @param array $namespaces
+ * @return Zend_Application
+ */
+ public function setAutoloaderNamespaces(array $namespaces)
+ {
+ $autoloader = $this->getAutoloader();
+
+ foreach ($namespaces as $namespace) {
+ $autoloader->registerNamespace($namespace);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Set bootstrap path/class
+ *
+ * @param string $path
+ * @param string $class
+ * @return Zend_Application
+ */
+ public function setBootstrap($path, $class = null)
+ {
+ // setOptions() can potentially send a null value; specify default
+ // here
+ if (null === $class) {
+ $class = 'Bootstrap';
+ }
+
+ if (!class_exists($class, false)) {
+ require_once $path;
+ if (!class_exists($class, false)) {
+ throw new Zend_Application_Exception('Bootstrap class not found');
+ }
+ }
+ $this->_bootstrap = new $class($this);
+
+ if (!$this->_bootstrap instanceof Zend_Application_Bootstrap_Bootstrapper) {
+ throw new Zend_Application_Exception('Bootstrap class does not implement Zend_Application_Bootstrap_Bootstrapper');
+ }
+
+ return $this;
+ }
+
+ /**
+ * Get bootstrap object
+ *
+ * @return Zend_Application_Bootstrap_BootstrapAbstract
+ */
+ public function getBootstrap()
+ {
+ if (null === $this->_bootstrap) {
+ $this->_bootstrap = new Zend_Application_Bootstrap_Bootstrap($this);
+ }
+ return $this->_bootstrap;
+ }
+
+ /**
+ * Bootstrap application
+ *
+ * @param null|string|array $resource
+ * @return Zend_Application
+ */
+ public function bootstrap($resource = null)
+ {
+ $this->getBootstrap()->bootstrap($resource);
+ return $this;
+ }
+
+ /**
+ * Run the application
+ *
+ * @return void
+ */
+ public function run()
+ {
+ $this->getBootstrap()->run();
+ }
+
+ /**
+ * Load configuration file of options
+ *
+ * @param string $file
+ * @throws Zend_Application_Exception When invalid configuration file is provided
+ * @return array
+ */
+ protected function _loadConfig($file)
+ {
+ $environment = $this->getEnvironment();
+ $suffix = strtolower(pathinfo($file, PATHINFO_EXTENSION));
+
+ switch ($suffix) {
+ case 'ini':
+ $config = new Zend_Config_Ini($file, $environment);
+ break;
+
+ case 'xml':
+ $config = new Zend_Config_Xml($file, $environment);
+ break;
+
+ case 'php':
+ case 'inc':
+ $config = include $file;
+ if (!is_array($config)) {
+ throw new Zend_Application_Exception('Invalid configuration file provided; PHP file does not return array value');
+ }
+ return $config;
+ break;
+
+ default:
+ throw new Zend_Application_Exception('Invalid configuration file provided; unknown config type');
+ }
+
+ return $config->toArray();
+ }
+}
--- /dev/null
+<?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_Auth
+ * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ * @version $Id$
+ */
+
+
+/**
+ * @category Zend
+ * @package Zend_Auth
+ * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+class Zend_Auth
+{
+ /**
+ * Singleton instance
+ *
+ * @var Zend_Auth
+ */
+ protected static $_instance = null;
+
+ /**
+ * Persistent storage handler
+ *
+ * @var Zend_Auth_Storage_Interface
+ */
+ protected $_storage = null;
+
+ /**
+ * Singleton pattern implementation makes "new" unavailable
+ *
+ * @return void
+ */
+ protected function __construct()
+ {}
+
+ /**
+ * Singleton pattern implementation makes "clone" unavailable
+ *
+ * @return void
+ */
+ protected function __clone()
+ {}
+
+ /**
+ * Returns an instance of Zend_Auth
+ *
+ * Singleton pattern implementation
+ *
+ * @return Zend_Auth Provides a fluent interface
+ */
+ public static function getInstance()
+ {
+ if (null === self::$_instance) {
+ self::$_instance = new self();
+ }
+
+ return self::$_instance;
+ }
+
+ /**
+ * Returns the persistent storage handler
+ *
+ * Session storage is used by default unless a different storage adapter has been set.
+ *
+ * @return Zend_Auth_Storage_Interface
+ */
+ public function getStorage()
+ {
+ if (null === $this->_storage) {
+ /**
+ * @see Zend_Auth_Storage_Session
+ */
+ require_once 'Zend/Auth/Storage/Session.php';
+ $this->setStorage(new Zend_Auth_Storage_Session());
+ }
+
+ return $this->_storage;
+ }
+
+ /**
+ * Sets the persistent storage handler
+ *
+ * @param Zend_Auth_Storage_Interface $storage
+ * @return Zend_Auth Provides a fluent interface
+ */
+ public function setStorage(Zend_Auth_Storage_Interface $storage)
+ {
+ $this->_storage = $storage;
+ return $this;
+ }
+
+ /**
+ * Authenticates against the supplied adapter
+ *
+ * @param Zend_Auth_Adapter_Interface $adapter
+ * @return Zend_Auth_Result
+ */
+ public function authenticate(Zend_Auth_Adapter_Interface $adapter)
+ {
+ $result = $adapter->authenticate();
+
+ /**
+ * ZF-7546 - prevent multiple succesive calls from storing inconsistent results
+ * Ensure storage has clean state
+ */
+ if ($this->hasIdentity()) {
+ $this->clearIdentity();
+ }
+
+ if ($result->isValid()) {
+ $this->getStorage()->write($result->getIdentity());
+ }
+
+ return $result;
+ }
+
+ /**
+ * Returns true if and only if an identity is available from storage
+ *
+ * @return boolean
+ */
+ public function hasIdentity()
+ {
+ return !$this->getStorage()->isEmpty();
+ }
+
+ /**
+ * Returns the identity from storage or null if no identity is available
+ *
+ * @return mixed|null
+ */
+ public function getIdentity()
+ {
+ $storage = $this->getStorage();
+
+ if ($storage->isEmpty()) {
+ return null;
+ }
+
+ return $storage->read();
+ }
+
+ /**
+ * Clears the identity from persistent storage
+ *
+ * @return void
+ */
+ public function clearIdentity()
+ {
+ $this->getStorage()->clear();
+ }
+}
--- /dev/null
+<?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-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ * @version $Id$
+ */
+
+
+/**
+ * @package Zend_Cache
+ * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+abstract class Zend_Cache
+{
+
+ /**
+ * Standard frontends
+ *
+ * @var array
+ */
+ public static $standardFrontends = array('Core', 'Output', 'Class', 'File', 'Function', 'Page');
+
+ /**
+ * Standard backends
+ *
+ * @var array
+ */
+ public static $standardBackends = array('File', 'Sqlite', 'Memcached', 'Apc', 'ZendPlatform', 'Xcache', 'TwoLevels');
+
+ /**
+ * Standard backends which implement the ExtendedInterface
+ *
+ * @var array
+ */
+ public static $standardExtendedBackends = array('File', 'Apc', 'TwoLevels', 'Memcached', 'Sqlite');
+
+ /**
+ * Only for backward compatibily (may be removed in next major release)
+ *
+ * @var array
+ * @deprecated
+ */
+ public static $availableFrontends = array('Core', 'Output', 'Class', 'File', 'Function', 'Page');
+
+ /**
+ * Only for backward compatibily (may be removed in next major release)
+ *
+ * @var array
+ * @deprecated
+ */
+ public static $availableBackends = array('File', 'Sqlite', 'Memcached', 'Apc', 'ZendPlatform', 'Xcache', 'TwoLevels');
+
+ /**
+ * Consts for clean() method
+ */
+ const CLEANING_MODE_ALL = 'all';
+ const CLEANING_MODE_OLD = 'old';
+ const CLEANING_MODE_MATCHING_TAG = 'matchingTag';
+ const CLEANING_MODE_NOT_MATCHING_TAG = 'notMatchingTag';
+ const CLEANING_MODE_MATCHING_ANY_TAG = 'matchingAnyTag';
+
+ /**
+ * Factory
+ *
+ * @param mixed $frontend frontend name (string) or Zend_Cache_Frontend_ object
+ * @param mixed $backend backend name (string) or Zend_Cache_Backend_ object
+ * @param array $frontendOptions associative array of options for the corresponding frontend constructor
+ * @param array $backendOptions associative array of options for the corresponding backend constructor
+ * @param boolean $customFrontendNaming if true, the frontend argument is used as a complete class name ; if false, the frontend argument is used as the end of "Zend_Cache_Frontend_[...]" class name
+ * @param boolean $customBackendNaming if true, the backend argument is used as a complete class name ; if false, the backend argument is used as the end of "Zend_Cache_Backend_[...]" class name
+ * @param boolean $autoload if true, there will no require_once for backend and frontend (usefull only for custom backends/frontends)
+ * @throws Zend_Cache_Exception
+ * @return Zend_Cache_Core|Zend_Cache_Frontend
+ */
+ public static function factory($frontend, $backend, $frontendOptions = array(), $backendOptions = array(), $customFrontendNaming = false, $customBackendNaming = false, $autoload = false)
+ {
+ if (is_string($backend)) {
+ $backendObject = self::_makeBackend($backend, $backendOptions, $customBackendNaming, $autoload);
+ } else {
+ if ((is_object($backend)) && (in_array('Zend_Cache_Backend_Interface', class_implements($backend)))) {
+ $backendObject = $backend;
+ } else {
+ self::throwException('backend must be a backend name (string) or an object which implements Zend_Cache_Backend_Interface');
+ }
+ }
+ if (is_string($frontend)) {
+ $frontendObject = self::_makeFrontend($frontend, $frontendOptions, $customFrontendNaming, $autoload);
+ } else {
+ if (is_object($frontend)) {
+ $frontendObject = $frontend;
+ } else {
+ self::throwException('frontend must be a frontend name (string) or an object');
+ }
+ }
+ $frontendObject->setBackend($backendObject);
+ return $frontendObject;
+ }
+
+ /**
+ * Frontend Constructor
+ *
+ * @param string $backend
+ * @param array $backendOptions
+ * @param boolean $customBackendNaming
+ * @param boolean $autoload
+ * @return Zend_Cache_Backend
+ */
+ public static function _makeBackend($backend, $backendOptions, $customBackendNaming = false, $autoload = false)
+ {
+ if (!$customBackendNaming) {
+ $backend = self::_normalizeName($backend);
+ }
+ if (in_array($backend, Zend_Cache::$standardBackends)) {
+ // we use a standard backend
+ $backendClass = 'Zend_Cache_Backend_' . $backend;
+ // security controls are explicit
+ require_once str_replace('_', DIRECTORY_SEPARATOR, $backendClass) . '.php';
+ } else {
+ // we use a custom backend
+ if (!preg_match('~^[\w]+$~D', $backend)) {
+ Zend_Cache::throwException("Invalid backend name [$backend]");
+ }
+ if (!$customBackendNaming) {
+ // we use this boolean to avoid an API break
+ $backendClass = 'Zend_Cache_Backend_' . $backend;
+ } else {
+ $backendClass = $backend;
+ }
+ if (!$autoload) {
+ $file = str_replace('_', DIRECTORY_SEPARATOR, $backendClass) . '.php';
+ if (!(self::_isReadable($file))) {
+ self::throwException("file $file not found in include_path");
+ }
+ require_once $file;
+ }
+ }
+ return new $backendClass($backendOptions);
+ }
+
+ /**
+ * Backend Constructor
+ *
+ * @param string $frontend
+ * @param array $frontendOptions
+ * @param boolean $customFrontendNaming
+ * @param boolean $autoload
+ * @return Zend_Cache_Core|Zend_Cache_Frontend
+ */
+ public static function _makeFrontend($frontend, $frontendOptions = array(), $customFrontendNaming = false, $autoload = false)
+ {
+ if (!$customFrontendNaming) {
+ $frontend = self::_normalizeName($frontend);
+ }
+ if (in_array($frontend, self::$standardFrontends)) {
+ // we use a standard frontend
+ // For perfs reasons, with frontend == 'Core', we can interact with the Core itself
+ $frontendClass = 'Zend_Cache_' . ($frontend != 'Core' ? 'Frontend_' : '') . $frontend;
+ // security controls are explicit
+ require_once str_replace('_', DIRECTORY_SEPARATOR, $frontendClass) . '.php';
+ } else {
+ // we use a custom frontend
+ if (!preg_match('~^[\w]+$~D', $frontend)) {
+ Zend_Cache::throwException("Invalid frontend name [$frontend]");
+ }
+ if (!$customFrontendNaming) {
+ // we use this boolean to avoid an API break
+ $frontendClass = 'Zend_Cache_Frontend_' . $frontend;
+ } else {
+ $frontendClass = $frontend;
+ }
+ if (!$autoload) {
+ $file = str_replace('_', DIRECTORY_SEPARATOR, $frontendClass) . '.php';
+ if (!(self::_isReadable($file))) {
+ self::throwException("file $file not found in include_path");
+ }
+ require_once $file;
+ }
+ }
+ return new $frontendClass($frontendOptions);
+ }
+
+ /**
+ * Throw an exception
+ *
+ * Note : for perf reasons, the "load" of Zend/Cache/Exception is dynamic
+ * @param string $msg Message for the exception
+ * @throws Zend_Cache_Exception
+ */
+ public static function throwException($msg)
+ {
+ // For perfs reasons, we use this dynamic inclusion
+ require_once 'Zend/Cache/Exception.php';
+ throw new Zend_Cache_Exception($msg);
+ }
+
+ /**
+ * Normalize frontend and backend names to allow multiple words TitleCased
+ *
+ * @param string $name Name to normalize
+ * @return string
+ */
+ protected static function _normalizeName($name)
+ {
+ $name = ucfirst(strtolower($name));
+ $name = str_replace(array('-', '_', '.'), ' ', $name);
+ $name = ucwords($name);
+ $name = str_replace(' ', '', $name);
+ return $name;
+ }
+
+ /**
+ * Returns TRUE if the $filename is readable, or FALSE otherwise.
+ * This function uses the PHP include_path, where PHP's is_readable()
+ * does not.
+ *
+ * Note : this method comes from Zend_Loader (see #ZF-2891 for details)
+ *
+ * @param string $filename
+ * @return boolean
+ */
+ private static function _isReadable($filename)
+ {
+ if (!$fh = @fopen($filename, 'r', true)) {
+ return false;
+ }
+ @fclose($fh);
+ return true;
+ }
+
+}
--- /dev/null
+<?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_Config
+ * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ * @version $Id$
+ */
+
+
+/**
+ * @category Zend
+ * @package Zend_Config
+ * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+class Zend_Config implements Countable, Iterator
+{
+ /**
+ * Whether in-memory modifications to configuration data are allowed
+ *
+ * @var boolean
+ */
+ protected $_allowModifications;
+
+ /**
+ * Iteration index
+ *
+ * @var integer
+ */
+ protected $_index;
+
+ /**
+ * Number of elements in configuration data
+ *
+ * @var integer
+ */
+ protected $_count;
+
+ /**
+ * Contains array of configuration data
+ *
+ * @var array
+ */
+ protected $_data;
+
+ /**
+ * Used when unsetting values during iteration to ensure we do not skip
+ * the next element
+ *
+ * @var boolean
+ */
+ protected $_skipNextIteration;
+
+ /**
+ * Contains which config file sections were loaded. This is null
+ * if all sections were loaded, a string name if one section is loaded
+ * and an array of string names if multiple sections were loaded.
+ *
+ * @var mixed
+ */
+ protected $_loadedSection;
+
+ /**
+ * This is used to track section inheritance. The keys are names of sections that
+ * extend other sections, and the values are the extended sections.
+ *
+ * @var array
+ */
+ protected $_extends = array();
+
+ /**
+ * Load file error string.
+ *
+ * Is null if there was no error while file loading
+ *
+ * @var string
+ */
+ protected $_loadFileErrorStr = null;
+
+ /**
+ * Zend_Config provides a property based interface to
+ * an array. The data are read-only unless $allowModifications
+ * is set to true on construction.
+ *
+ * Zend_Config also implements Countable and Iterator to
+ * facilitate easy access to the data.
+ *
+ * @param array $array
+ * @param boolean $allowModifications
+ * @return void
+ */
+ public function __construct(array $array, $allowModifications = false)
+ {
+ $this->_allowModifications = (boolean) $allowModifications;
+ $this->_loadedSection = null;
+ $this->_index = 0;
+ $this->_data = array();
+ foreach ($array as $key => $value) {
+ if (is_array($value)) {
+ $this->_data[$key] = new self($value, $this->_allowModifications);
+ } else {
+ $this->_data[$key] = $value;
+ }
+ }
+ $this->_count = count($this->_data);
+ }
+
+ /**
+ * Retrieve a value and return $default if there is no element set.
+ *
+ * @param string $name
+ * @param mixed $default
+ * @return mixed
+ */
+ public function get($name, $default = null)
+ {
+ $result = $default;
+ if (array_key_exists($name, $this->_data)) {
+ $result = $this->_data[$name];
+ }
+ return $result;
+ }
+
+ /**
+ * Magic function so that $obj->value will work.
+ *
+ * @param string $name
+ * @return mixed
+ */
+ public function __get($name)
+ {
+ return $this->get($name);
+ }
+
+ /**
+ * Only allow setting of a property if $allowModifications
+ * was set to true on construction. Otherwise, throw an exception.
+ *
+ * @param string $name
+ * @param mixed $value
+ * @throws Zend_Config_Exception
+ * @return void
+ */
+ public function __set($name, $value)
+ {
+ if ($this->_allowModifications) {
+ if (is_array($value)) {
+ $this->_data[$name] = new self($value, true);
+ } else {
+ $this->_data[$name] = $value;
+ }
+ $this->_count = count($this->_data);
+ } else {
+ /** @see Zend_Config_Exception */
+ require_once 'Zend/Config/Exception.php';
+ throw new Zend_Config_Exception('Zend_Config is read only');
+ }
+ }
+
+ /**
+ * Deep clone of this instance to ensure that nested Zend_Configs
+ * are also cloned.
+ *
+ * @return void
+ */
+ public function __clone()
+ {
+ $array = array();
+ foreach ($this->_data as $key => $value) {
+ if ($value instanceof Zend_Config) {
+ $array[$key] = clone $value;
+ } else {
+ $array[$key] = $value;
+ }
+ }
+ $this->_data = $array;
+ }
+
+ /**
+ * Return an associative array of the stored data.
+ *
+ * @return array
+ */
+ public function toArray()
+ {
+ $array = array();
+ $data = $this->_data;
+ foreach ($data as $key => $value) {
+ if ($value instanceof Zend_Config) {
+ $array[$key] = $value->toArray();
+ } else {
+ $array[$key] = $value;
+ }
+ }
+ return $array;
+ }
+
+ /**
+ * Support isset() overloading on PHP 5.1
+ *
+ * @param string $name
+ * @return boolean
+ */
+ public function __isset($name)
+ {
+ return isset($this->_data[$name]);
+ }
+
+ /**
+ * Support unset() overloading on PHP 5.1
+ *
+ * @param string $name
+ * @throws Zend_Config_Exception
+ * @return void
+ */
+ public function __unset($name)
+ {
+ if ($this->_allowModifications) {
+ unset($this->_data[$name]);
+ $this->_count = count($this->_data);
+ $this->_skipNextIteration = true;
+ } else {
+ /** @see Zend_Config_Exception */
+ require_once 'Zend/Config/Exception.php';
+ throw new Zend_Config_Exception('Zend_Config is read only');
+ }
+
+ }
+
+ /**
+ * Defined by Countable interface
+ *
+ * @return int
+ */
+ public function count()
+ {
+ return $this->_count;
+ }
+
+ /**
+ * Defined by Iterator interface
+ *
+ * @return mixed
+ */
+ public function current()
+ {
+ $this->_skipNextIteration = false;
+ return current($this->_data);
+ }
+
+ /**
+ * Defined by Iterator interface
+ *
+ * @return mixed
+ */
+ public function key()
+ {
+ return key($this->_data);
+ }
+
+ /**
+ * Defined by Iterator interface
+ *
+ */
+ public function next()
+ {
+ if ($this->_skipNextIteration) {
+ $this->_skipNextIteration = false;
+ return;
+ }
+ next($this->_data);
+ $this->_index++;
+ }
+
+ /**
+ * Defined by Iterator interface
+ *
+ */
+ public function rewind()
+ {
+ $this->_skipNextIteration = false;
+ reset($this->_data);
+ $this->_index = 0;
+ }
+
+ /**
+ * Defined by Iterator interface
+ *
+ * @return boolean
+ */
+ public function valid()
+ {
+ return $this->_index < $this->_count;
+ }
+
+ /**
+ * Returns the section name(s) loaded.
+ *
+ * @return mixed
+ */
+ public function getSectionName()
+ {
+ if(is_array($this->_loadedSection) && count($this->_loadedSection) == 1) {
+ $this->_loadedSection = $this->_loadedSection[0];
+ }
+ return $this->_loadedSection;
+ }
+
+ /**
+ * Returns true if all sections were loaded
+ *
+ * @return boolean
+ */
+ public function areAllSectionsLoaded()
+ {
+ return $this->_loadedSection === null;
+ }
+
+
+ /**
+ * Merge another Zend_Config with this one. The items
+ * in $merge will override the same named items in
+ * the current config.
+ *
+ * @param Zend_Config $merge
+ * @return Zend_Config
+ */
+ public function merge(Zend_Config $merge)
+ {
+ foreach($merge as $key => $item) {
+ if(array_key_exists($key, $this->_data)) {
+ if($item instanceof Zend_Config && $this->$key instanceof Zend_Config) {
+ $this->$key = $this->$key->merge(new Zend_Config($item->toArray(), !$this->readOnly()));
+ } else {
+ $this->$key = $item;
+ }
+ } else {
+ if($item instanceof Zend_Config) {
+ $this->$key = new Zend_Config($item->toArray(), !$this->readOnly());
+ } else {
+ $this->$key = $item;
+ }
+ }
+ }
+
+ return $this;
+ }
+
+ /**
+ * Prevent any more modifications being made to this instance. Useful
+ * after merge() has been used to merge multiple Zend_Config objects
+ * into one object which should then not be modified again.
+ *
+ */
+ public function setReadOnly()
+ {
+ $this->_allowModifications = false;
+ foreach ($this->_data as $key => $value) {
+ if ($value instanceof Zend_Config) {
+ $value->setReadOnly();
+ }
+ }
+ }
+
+ /**
+ * Returns if this Zend_Config object is read only or not.
+ *
+ * @return boolean
+ */
+ public function readOnly()
+ {
+ return !$this->_allowModifications;
+ }
+
+ /**
+ * Get the current extends
+ *
+ * @return array
+ */
+ public function getExtends()
+ {
+ return $this->_extends;
+ }
+
+ /**
+ * Set an extend for Zend_Config_Writer
+ *
+ * @param string $extendingSection
+ * @param string $extendedSection
+ * @return void
+ */
+ public function setExtend($extendingSection, $extendedSection = null)
+ {
+ if ($extendedSection === null && isset($this->_extends[$extendingSection])) {
+ unset($this->_extends[$extendingSection]);
+ } else if ($extendedSection !== null) {
+ $this->_extends[$extendingSection] = $extendedSection;
+ }
+ }
+
+ /**
+ * Throws an exception if $extendingSection may not extend $extendedSection,
+ * and tracks the section extension if it is valid.
+ *
+ * @param string $extendingSection
+ * @param string $extendedSection
+ * @throws Zend_Config_Exception
+ * @return void
+ */
+ protected function _assertValidExtend($extendingSection, $extendedSection)
+ {
+ // detect circular section inheritance
+ $extendedSectionCurrent = $extendedSection;
+ while (array_key_exists($extendedSectionCurrent, $this->_extends)) {
+ if ($this->_extends[$extendedSectionCurrent] == $extendingSection) {
+ /** @see Zend_Config_Exception */
+ require_once 'Zend/Config/Exception.php';
+ throw new Zend_Config_Exception('Illegal circular inheritance detected');
+ }
+ $extendedSectionCurrent = $this->_extends[$extendedSectionCurrent];
+ }
+ // remember that this section extends another section
+ $this->_extends[$extendingSection] = $extendedSection;
+ }
+
+ /**
+ * Handle any errors from simplexml_load_file or parse_ini_file
+ *
+ * @param integer $errno
+ * @param string $errstr
+ * @param string $errfile
+ * @param integer $errline
+ */
+ protected function _loadFileErrorHandler($errno, $errstr, $errfile, $errline)
+ {
+ if ($this->_loadFileErrorStr === null) {
+ $this->_loadFileErrorStr = $errstr;
+ } else {
+ $this->_loadFileErrorStr .= (PHP_EOL . $errstr);
+ }
+ }
+
+}
--- /dev/null
+<?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_Crypt
+ * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ * @version $Id$
+ */
+
+/**
+ * @category Zend
+ * @package Zend_Crypt
+ * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+class Zend_Crypt
+{
+
+ const TYPE_OPENSSL = 'openssl';
+ const TYPE_HASH = 'hash';
+ const TYPE_MHASH = 'mhash';
+
+ protected static $_type = null;
+
+ /**
+ * @var array
+ */
+ protected static $_supportedAlgosOpenssl = array(
+ 'md2',
+ 'md4',
+ 'mdc2',
+ 'rmd160',
+ 'sha',
+ 'sha1',
+ 'sha224',
+ 'sha256',
+ 'sha384',
+ 'sha512'
+ );
+
+ /**
+ * @var array
+ */
+ protected static $_supportedAlgosMhash = array(
+ 'adler32',
+ 'crc32',
+ 'crc32b',
+ 'gost',
+ 'haval128',
+ 'haval160',
+ 'haval192',
+ 'haval256',
+ 'md4',
+ 'md5',
+ 'ripemd160',
+ 'sha1',
+ 'sha256',
+ 'tiger',
+ 'tiger128',
+ 'tiger160'
+ );
+
+ /**
+ * @param string $algorithm
+ * @param string $data
+ * @param bool $binaryOutput
+ * @return unknown
+ */
+ public static function hash($algorithm, $data, $binaryOutput = false)
+ {
+ $algorithm = strtolower($algorithm);
+ if (function_exists($algorithm)) {
+ return $algorithm($data, $binaryOutput);
+ }
+ self::_detectHashSupport($algorithm);
+ $supportedMethod = '_digest' . ucfirst(self::$_type);
+ $result = self::$supportedMethod($algorithm, $data, $binaryOutput);
+ }
+
+ /**
+ * @param string $algorithm
+ * @throws Zend_Crypt_Exception
+ */
+ protected static function _detectHashSupport($algorithm)
+ {
+ if (function_exists('hash')) {
+ self::$_type = self::TYPE_HASH;
+ if (in_array($algorithm, hash_algos())) {
+ return;
+ }
+ }
+ if (function_exists('mhash')) {
+ self::$_type = self::TYPE_MHASH;
+ if (in_array($algorithm, self::$_supportedAlgosMhash)) {
+ return;
+ }
+ }
+ if (function_exists('openssl_digest')) {
+ if ($algorithm == 'ripemd160') {
+ $algorithm = 'rmd160';
+ }
+ self::$_type = self::TYPE_OPENSSL;
+ if (in_array($algorithm, self::$_supportedAlgosOpenssl)) {
+ return;
+ }
+ }
+ /**
+ * @see Zend_Crypt_Exception
+ */
+ require_once 'Zend/Crypt/Exception.php';
+ throw new Zend_Crypt_Exception('\'' . $algorithm . '\' is not supported by any available extension or native function');
+ }
+
+ /**
+ * @param string $algorithm
+ * @param string $data
+ * @param bool $binaryOutput
+ * @return string
+ */
+ protected static function _digestHash($algorithm, $data, $binaryOutput)
+ {
+ return hash($algorithm, $data, $binaryOutput);
+ }
+
+ /**
+ * @param string $algorithm
+ * @param string $data
+ * @param bool $binaryOutput
+ * @return string
+ */
+ protected static function _digestMhash($algorithm, $data, $binaryOutput)
+ {
+ $constant = constant('MHASH_' . strtoupper($algorithm));
+ $binary = mhash($constant, $data);
+ if ($binaryOutput) {
+ return $binary;
+ }
+ return bin2hex($binary);
+ }
+
+ /**
+ * @param string $algorithm
+ * @param string $data
+ * @param bool $binaryOutput
+ * @return string
+ */
+ protected static function _digestOpenssl($algorithm, $data, $binaryOutput)
+ {
+ if ($algorithm == 'ripemd160') {
+ $algorithm = 'rmd160';
+ }
+ return openssl_digest($data, $algorithm, $binaryOutput);
+ }
+
+}
\ No newline at end of file
--- /dev/null
+<?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_Currency
+ * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ * @version $Id$
+ */
+
+/**
+ * include needed classes
+ */
+require_once 'Zend/Locale.php';
+require_once 'Zend/Locale/Data.php';
+require_once 'Zend/Locale/Format.php';
+
+/**
+ * Class for handling currency notations
+ *
+ * @category Zend
+ * @package Zend_Currency
+ * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+class Zend_Currency
+{
+ // Constants for defining what currency symbol should be displayed
+ const NO_SYMBOL = 1;
+ const USE_SYMBOL = 2;
+ const USE_SHORTNAME = 3;
+ const USE_NAME = 4;
+
+ // Constants for defining the position of the currencysign
+ const STANDARD = 8;
+ const RIGHT = 16;
+ const LEFT = 32;
+
+ /**
+ * Locale for this currency
+ *
+ * @var string
+ */
+ private $_locale = null;
+
+ /**
+ * Options array
+ *
+ * The following options are available
+ * 'position' => Position for the currency sign
+ * 'script' => Script for the output
+ * 'format' => Locale for numeric output
+ * 'display' => Currency detail to show
+ * 'precision' => Precision for the currency
+ * 'name' => Name for this currency
+ * 'currency' => 3 lettered international abbreviation
+ * 'symbol' => Currency symbol
+ *
+ * @var array
+ * @see Zend_Locale
+ */
+ protected $_options = array(
+ 'position' => self::STANDARD,
+ 'script' => null,
+ 'format' => null,
+ 'display' => self::NO_SYMBOL,
+ 'precision' => 2,
+ 'name' => null,
+ 'currency' => null,
+ 'symbol' => null
+ );
+
+ /**
+ * Creates a currency instance. Every supressed parameter is used from the actual or the given locale.
+ *
+ * @param string $currency OPTIONAL currency short name
+ * @param string|Zend_Locale $locale OPTIONAL locale name
+ * @throws Zend_Currency_Exception When currency is invalid
+ */
+ public function __construct($currency = null, $locale = null)
+ {
+ if (Zend_Locale::isLocale($currency, true, false)) {
+ $temp = $locale;
+ $locale = $currency;
+ $currency = $temp;
+ }
+
+ $this->setLocale($locale);
+
+ // Get currency details
+ $this->_options['currency'] = self::getShortName($currency, $this->_locale);
+ $this->_options['name'] = self::getName($currency, $this->_locale);
+ $this->_options['symbol'] = self::getSymbol($currency, $this->_locale);
+
+ if (($this->_options['currency'] === null) and ($this->_options['name'] === null)) {
+ require_once 'Zend/Currency/Exception.php';
+ throw new Zend_Currency_Exception("Currency '$currency' not found");
+ }
+
+ // Get the format
+ $this->_options['display'] = self::NO_SYMBOL;
+ if (empty($this->_options['symbol']) === false) {
+ $this->_options['display'] = self::USE_SYMBOL;
+ } else if (empty($this->_options['currency']) === false) {
+ $this->_options['display'] = self::USE_SHORTNAME;
+ }
+ }
+
+ /**
+ * Returns a localized currency string
+ *
+ * @param integer|float $value Currency value
+ * @param array $options OPTIONAL options to set temporary
+ * @throws Zend_Currency_Exception When the value is not a number
+ * @return string
+ */
+ public function toCurrency($value, array $options = array())
+ {
+ // Validate the passed number
+ if ((isset($value) === false) or (is_numeric($value) === false)) {
+ require_once 'Zend/Currency/Exception.php';
+ throw new Zend_Currency_Exception("Value '$value' has to be numeric");
+ }
+
+ $options = $this->_checkOptions($options) + $this->_options;
+
+ // Format the number
+ $format = $options['format'];
+ $locale = $this->_locale;
+ if (empty($format)) {
+ $format = Zend_Locale_Data::getContent($this->_locale, 'currencynumber');
+ } else if (Zend_Locale::isLocale($format, true, false)) {
+ $locale = $format;
+ $format = Zend_Locale_Data::getContent($format, 'currencynumber');
+ }
+
+ $symbols = Zend_Locale_Data::getList($locale, 'symbols');
+ $original = $value;
+ $value = Zend_Locale_Format::toNumber($value, array('locale' => $locale,
+ 'number_format' => $format,
+ 'precision' => $options['precision']));
+
+ if ($options['position'] !== self::STANDARD) {
+ $value = str_replace('¤', '', $value);
+ $space = '';
+ if (iconv_strpos($value, ' ') !== false) {
+ $value = str_replace(' ', '', $value);
+ $space = ' ';
+ }
+
+ if ($options['position'] == self::LEFT) {
+ $value = '¤' . $space . $value;
+ } else {
+ $value = $value . $space . '¤';
+ }
+ }
+
+ // Localize the number digits
+ if (empty($options['script']) === false) {
+ $value = Zend_Locale_Format::convertNumerals($value, 'Latn', $options['script']);
+ }
+
+ // Get the sign to be placed next to the number
+ if (is_numeric($options['display']) === false) {
+ $sign = $options['display'];
+ } else {
+ switch($options['display']) {
+ case self::USE_SYMBOL:
+ $sign = $this->_extractPattern($options['symbol'], $original);
+ break;
+
+ case self::USE_SHORTNAME:
+ $sign = $options['currency'];
+ break;
+
+ case self::USE_NAME:
+ $sign = $options['name'];
+ break;
+
+ default:
+ $sign = '';
+ $value = str_replace(' ', '', $value);
+ break;
+ }
+ }
+
+ $value = str_replace('¤', $sign, $value);
+ return $value;
+ }
+
+ /**
+ * Internal method to extract the currency pattern
+ * when a choice is given based on the given value
+ *
+ * @param string $pattern
+ * @param float|integer $value
+ * @return string
+ */
+ private function _extractPattern($pattern, $value)
+ {
+ if (strpos($pattern, '|') === false) {
+ return $pattern;
+ }
+
+ $patterns = explode('|', $pattern);
+ $token = $pattern;
+ $value = trim(str_replace('¤', '', $value));
+ krsort($patterns);
+ foreach($patterns as $content) {
+ if (strpos($content, '<') !== false) {
+ $check = iconv_substr($content, 0, iconv_strpos($content, '<'));
+ $token = iconv_substr($content, iconv_strpos($content, '<') + 1);
+ if ($check < $value) {
+ return $token;
+ }
+ } else {
+ $check = iconv_substr($content, 0, iconv_strpos($content, '≤'));
+ $token = iconv_substr($content, iconv_strpos($content, '≤') + 1);
+ if ($check <= $value) {
+ return $token;
+ }
+ }
+
+ }
+
+ return $token;
+ }
+
+ /**
+ * Sets the formating options of the localized currency string
+ * If no parameter is passed, the standard setting of the
+ * actual set locale will be used
+ *
+ * @param array $options (Optional) Options to set
+ * @return Zend_Currency
+ */
+ public function setFormat(array $options = array())
+ {
+ $this->_options = $this->_checkOptions($options) + $this->_options;
+ return $this;
+ }
+
+ /**
+ * Internal function for checking static given locale parameter
+ *
+ * @param string $currency (Optional) Currency name
+ * @param string|Zend_Locale $locale (Optional) Locale to display informations
+ * @throws Zend_Currency_Exception When locale contains no region
+ * @return string The extracted locale representation as string
+ */
+ private function _checkParams($currency = null, $locale = null)
+ {
+ // Manage the params
+ if ((empty($locale)) and (!empty($currency)) and
+ (Zend_Locale::isLocale($currency, true, false))) {
+ $locale = $currency;
+ $currency = null;
+ }
+
+ // Validate the locale and get the country short name
+ $country = null;
+ if ((Zend_Locale::isLocale($locale, true, false)) and (strlen($locale) > 4)) {
+ $country = substr($locale, (strpos($locale, '_') + 1));
+ } else {
+ require_once 'Zend/Currency/Exception.php';
+ throw new Zend_Currency_Exception("No region found within the locale '" . (string) $locale . "'");
+ }
+
+ // Get the available currencies for this country
+ $data = Zend_Locale_Data::getContent($locale, 'currencytoregion', $country);
+ if ((empty($currency) === false) and (empty($data) === false)) {
+ $abbreviation = $currency;
+ } else {
+ $abbreviation = $data;
+ }
+
+ return array('locale' => $locale, 'currency' => $currency, 'name' => $abbreviation, 'country' => $country);
+ }
+
+ /**
+ * Returns the actual or details of other currency symbols,
+ * when no symbol is available it returns the currency shortname (f.e. FIM for Finnian Mark)
+ *
+ * @param string $currency (Optional) Currency name
+ * @param string|Zend_Locale $locale (Optional) Locale to display informations
+ * @return string
+ */
+ public function getSymbol($currency = null, $locale = null)
+ {
+ if (($currency === null) and ($locale === null)) {
+ return $this->_options['symbol'];
+ }
+
+ $params = self::_checkParams($currency, $locale);
+
+ // Get the symbol
+ $symbol = Zend_Locale_Data::getContent($params['locale'], 'currencysymbol', $params['currency']);
+ if (empty($symbol) === true) {
+ $symbol = Zend_Locale_Data::getContent($params['locale'], 'currencysymbol', $params['name']);
+ }
+
+ if (empty($symbol) === true) {
+ return null;
+ }
+
+ return $symbol;
+ }
+
+ /**
+ * Returns the actual or details of other currency shortnames
+ *
+ * @param string $currency OPTIONAL Currency's name
+ * @param string|Zend_Locale $locale OPTIONAL The locale
+ * @return string
+ */
+ public function getShortName($currency = null, $locale = null)
+ {
+ if (($currency === null) and ($locale === null)) {
+ return $this->_options['currency'];
+ }
+
+ $params = self::_checkParams($currency, $locale);
+
+ // Get the shortname
+ if (empty($params['currency']) === true) {
+ return $params['name'];
+ }
+
+ $list = Zend_Locale_Data::getContent($params['locale'], 'currencytoname', $params['currency']);
+ if (empty($list) === true) {
+ $list = Zend_Locale_Data::getContent($params['locale'], 'nametocurrency', $params['currency']);
+ if (empty($list) === false) {
+ $list = $params['currency'];
+ }
+ }
+
+ if (empty($list) === true) {
+ return null;
+ }
+
+ return $list;
+ }
+
+ /**
+ * Returns the actual or details of other currency names
+ *
+ * @param string $currency (Optional) Currency's short name
+ * @param string|Zend_Locale $locale (Optional) The locale
+ * @return string
+ */
+ public function getName($currency = null, $locale = null)
+ {
+ if (($currency === null) and ($locale === null)) {
+ return $this->_options['name'];
+ }
+
+ $params = self::_checkParams($currency, $locale);
+
+ // Get the name
+ $name = Zend_Locale_Data::getContent($params['locale'], 'nametocurrency', $params['currency']);
+ if (empty($name) === true) {
+ $name = Zend_Locale_Data::getContent($params['locale'], 'nametocurrency', $params['name']);
+ }
+
+ if (empty($name) === true) {
+ return null;
+ }
+
+ return $name;
+ }
+
+ /**
+ * Returns a list of regions where this currency is or was known
+ *
+ * @param string $currency OPTIONAL Currency's short name
+ * @throws Zend_Currency_Exception When no currency was defined
+ * @return array List of regions
+ */
+ public function getRegionList($currency = null)
+ {
+ if ($currency === null) {
+ $currency = $this->_options['currency'];
+ }
+
+ if (empty($currency) === true) {
+ require_once 'Zend/Currency/Exception.php';
+ throw new Zend_Currency_Exception('No currency defined');
+ }
+
+ $data = Zend_Locale_Data::getContent('', 'regiontocurrency', $currency);
+
+ $result = explode(' ', $data);
+ return $result;
+ }
+
+ /**
+ * Returns a list of currencies which are used in this region
+ * a region name should be 2 charachters only (f.e. EG, DE, US)
+ * If no region is given, the actual region is used
+ *
+ * @param string $region OPTIONAL Region to return the currencies for
+ * @return array List of currencies
+ */
+ public function getCurrencyList($region = null)
+ {
+ if (empty($region) === true) {
+ if (strlen($this->_locale) > 4) {
+ $region = substr($this->_locale, (strpos($this->_locale, '_') + 1));
+ }
+ }
+
+ return Zend_Locale_Data::getList('', 'regiontocurrency', $region);
+ }
+
+ /**
+ * Returns the actual currency name
+ *
+ * @return string
+ */
+ public function toString()
+ {
+ return (empty($this->_options['name']) === false) ? $this->_options['name'] : $this->_options['currency'];
+ }
+
+ /**
+ * Returns the currency name
+ *
+ * @return string
+ */
+ public function __toString()
+ {
+ return $this->toString();
+ }
+
+ /**
+ * Returns the set cache
+ *
+ * @return Zend_Cache_Core The set cache
+ */
+ public static function getCache()
+ {
+ $cache = Zend_Locale_Data::getCache();
+ return $cache;
+ }
+
+ /**
+ * Sets a cache for Zend_Currency
+ *
+ * @param Zend_Cache_Core $cache Cache to set
+ * @return void
+ */
+ public static function setCache(Zend_Cache_Core $cache)
+ {
+ Zend_Locale_Data::setCache($cache);
+ }
+
+ /**
+ * Returns true when a cache is set
+ *
+ * @return boolean
+ */
+ public static function hasCache()
+ {
+ return Zend_Locale_Data::hasCache();
+ }
+
+ /**
+ * Removes any set cache
+ *
+ * @return void
+ */
+ public static function removeCache()
+ {
+ Zend_Locale_Data::removeCache();
+ }
+
+ /**
+ * Clears all set cache data
+ *
+ * @return void
+ */
+ public static function clearCache()
+ {
+ Zend_Locale_Data::clearCache();
+ }
+
+ /**
+ * Sets a new locale for data retreivement
+ * Example: 'de_XX' will be set to 'de' because 'de_XX' does not exist
+ * 'xx_YY' will be set to 'root' because 'xx' does not exist
+ *
+ * @param string|Zend_Locale $locale (Optional) Locale for parsing input
+ * @throws Zend_Currency_Exception When the given locale does not exist
+ * @return Zend_Currency Provides fluent interface
+ */
+ public function setLocale($locale = null)
+ {
+ require_once 'Zend/Locale.php';
+ try {
+ $this->_locale = Zend_Locale::findLocale($locale);
+ } catch (Zend_Locale_Exception $e) {
+ require_once 'Zend/Currency/Exception.php';
+ throw new Zend_Currency_Exception($e->getMessage());
+ }
+
+ // Get currency details
+ $this->_options['currency'] = $this->getShortName(null, $this->_locale);
+ $this->_options['name'] = $this->getName(null, $this->_locale);
+ $this->_options['symbol'] = $this->getSymbol(null, $this->_locale);
+
+ return $this;
+ }
+
+ /**
+ * Returns the actual set locale
+ *
+ * @return string
+ */
+ public function getLocale()
+ {
+ return $this->_locale;
+ }
+
+ /**
+ * Internal method for checking the options array
+ *
+ * @param array $options Options to check
+ * @throws Zend_Currency_Exception On unknown position
+ * @throws Zend_Currency_Exception On unknown locale
+ * @throws Zend_Currency_Exception On unknown display
+ * @throws Zend_Currency_Exception On precision not between -1 and 30
+ * @throws Zend_Currency_Exception On problem with script conversion
+ * @throws Zend_Currency_Exception On unknown options
+ * @return array
+ */
+ private function _checkOptions(array $options = array())
+ {
+ if (count($options) === 0) {
+ return $this->_options;
+ }
+
+ foreach ($options as $name => $value) {
+ $name = strtolower($name);
+ if ($name !== 'format') {
+ if (gettype($value) === 'string') {
+ $value = strtolower($value);
+ }
+ }
+
+ switch($name) {
+ case 'position':
+ if (($value !== self::STANDARD) and ($value !== self::RIGHT) and ($value !== self::LEFT)) {
+ require_once 'Zend/Currency/Exception.php';
+ throw new Zend_Currency_Exception("Unknown position '" . $value . "'");
+ }
+
+ break;
+
+ case 'format':
+ if ((empty($value) === false) and (Zend_Locale::isLocale($value, null, false) === false)) {
+ require_once 'Zend/Currency/Exception.php';
+ throw new Zend_Currency_Exception("'" .
+ ((gettype($value) === 'object') ? get_class($value) : $value)
+ . "' is not a known locale.");
+ }
+ break;
+
+ case 'display':
+ if (is_numeric($value) and ($value !== self::NO_SYMBOL) and ($value !== self::USE_SYMBOL) and
+ ($value !== self::USE_SHORTNAME) and ($value !== self::USE_NAME)) {
+ require_once 'Zend/Currency/Exception.php';
+ throw new Zend_Currency_Exception("Unknown display '$value'");
+ }
+ break;
+
+ case 'precision':
+ if ($value === null) {
+ $value = -1;
+ }
+
+ if (($value < -1) or ($value > 30)) {
+ require_once 'Zend/Currency/Exception.php';
+ throw new Zend_Currency_Exception("'$value' precision has to be between -1 and 30.");
+ }
+ break;
+
+ case 'script':
+ try {
+ Zend_Locale_Format::convertNumerals(0, $options['script']);
+ } catch (Zend_Locale_Exception $e) {
+ require_once 'Zend/Currency/Exception.php';
+ throw new Zend_Currency_Exception($e->getMessage());
+ }
+ break;
+
+ case 'name':
+ // Break intentionally omitted
+ case 'currency':
+ // Break intentionally omitted
+ case 'symbol':
+ // Unchecked options
+ break;
+
+ default:
+ require_once 'Zend/Currency/Exception.php';
+ throw new Zend_Currency_Exception("Unknown option: '$name' = '$value'");
+ break;
+ }
+ }
+
+ return $options;
+ }
+}
*
* @category Zend
* @package Zend_Date
- * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id$
*/
/**
* @category Zend
* @package Zend_Date
- * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Date extends Zend_Date_DateObject
);
// Class wide Date Constants
- // day formats
- const DAY = 'DAY'; // d - 2 digit day of month, 01-31
- const DAY_SHORT = 'DAY_SHORT'; // j - 1,2 digit day of month, 1-31
-
- const DAY_SUFFIX = 'DAY_SUFFIX'; // S - english suffix day of month, st-th
- const DAY_OF_YEAR = 'DAY_OF_YEAR'; // z - Number of day of year
-
- const WEEKDAY = 'WEEKDAY'; // l - full day name - locale aware, Monday - Sunday
- const WEEKDAY_SHORT = 'WEEKDAY_SHORT'; // --- 3 letter day of week - locale aware, Mon-Sun
- const WEEKDAY_NARROW = 'WEEKDAY_NARROW'; // --- 1 letter day name - locale aware, M-S
- const WEEKDAY_NAME = 'WEEKDAY_NAME'; // D - abbreviated day name, 1-3 letters - locale aware, Mon-Sun
-
- const WEEKDAY_8601 = 'WEEKDAY_8601'; // N - digit weekday ISO 8601, 1-7 1 = monday, 7=sunday
- const WEEKDAY_DIGIT = 'WEEKDAY_DIGIT'; // w - weekday, 0-6 0=sunday, 6=saturday
-
- // week formats
- const WEEK = 'WEEK'; // W - number of week ISO8601, 1-53
-
- // month formats
- const MONTH = 'MONTH'; // m - 2 digit month, 01-12
- const MONTH_SHORT = 'MONTH_SHORT'; // n - 1 digit month, no leading zeros, 1-12
-
- const MONTH_DAYS = 'MONTH_DAYS'; // t - Number of days this month
-
- const MONTH_NAME = 'MONTH_NAME'; // F - full month name - locale aware, January-December
- const MONTH_NAME_SHORT = 'MONTH_NAME_SHORT'; // M - 3 letter monthname - locale aware, Jan-Dec
- const MONTH_NAME_NARROW = 'MONTH_NAME_NARROW'; // --- 1 letter month name - locale aware, J-D
-
- // year formats
- const YEAR = 'YEAR'; // Y - 4 digit year
- const YEAR_SHORT = 'YEAR_SHORT'; // y - 2 digit year, leading zeros 00-99
-
- const YEAR_8601 = 'YEAR_8601'; // o - number of year ISO8601
- const YEAR_SHORT_8601= 'YEAR_SHORT_8601';// --- 2 digit number of year ISO8601
-
- const LEAPYEAR = 'LEAPYEAR'; // L - is leapyear ?, 0-1
-
- // time formats
- const MERIDIEM = 'MERIDIEM'; // A,a - AM/PM - locale aware, AM/PM
- const SWATCH = 'SWATCH'; // B - Swatch Internet Time
-
- const HOUR = 'HOUR'; // H - 2 digit hour, leading zeros, 00-23
- const HOUR_SHORT = 'HOUR_SHORT'; // G - 1 digit hour, no leading zero, 0-23
-
- const HOUR_AM = 'HOUR_AM'; // h - 2 digit hour, leading zeros, 01-12 am/pm
- const HOUR_SHORT_AM = 'HOUR_SHORT_AM'; // g - 1 digit hour, no leading zero, 1-12 am/pm
-
- const MINUTE = 'MINUTE'; // i - 2 digit minute, leading zeros, 00-59
- const MINUTE_SHORT = 'MINUTE_SHORT'; // --- 1 digit minute, no leading zero, 0-59
-
- const SECOND = 'SECOND'; // s - 2 digit second, leading zeros, 00-59
- const SECOND_SHORT = 'SECOND_SHORT'; // --- 1 digit second, no leading zero, 0-59
-
- const MILLISECOND = 'MILLISECOND'; // --- milliseconds
-
- // timezone formats
- const TIMEZONE_NAME = 'TIMEZONE_NAME'; // e - timezone string
- const DAYLIGHT = 'DAYLIGHT'; // I - is Daylight saving time ?, 0-1
- const GMT_DIFF = 'GMT_DIFF'; // O - GMT difference, -1200 +1200
- const GMT_DIFF_SEP = 'GMT_DIFF_SEP'; // P - seperated GMT diff, -12:00 +12:00
- const TIMEZONE = 'TIMEZONE'; // T - timezone, EST, GMT, MDT
- const TIMEZONE_SECS = 'TIMEZONE_SECS'; // Z - timezone offset in seconds, -43200 +43200
-
- // date strings
- const ISO_8601 = 'ISO_8601'; // c - ISO 8601 date string
- const RFC_2822 = 'RFC_2822'; // r - RFC 2822 date string
- const TIMESTAMP = 'TIMESTAMP'; // U - unix timestamp
-
- // additional formats
- const ERA = 'ERA'; // --- short name of era, locale aware,
- const ERA_NAME = 'ERA_NAME'; // --- full name of era, locale aware,
- const DATES = 'DATES'; // --- standard date, locale aware
- const DATE_FULL = 'DATE_FULL'; // --- full date, locale aware
- const DATE_LONG = 'DATE_LONG'; // --- long date, locale aware
- const DATE_MEDIUM = 'DATE_MEDIUM'; // --- medium date, locale aware
- const DATE_SHORT = 'DATE_SHORT'; // --- short date, locale aware
- const TIMES = 'TIMES'; // --- standard time, locale aware
- const TIME_FULL = 'TIME_FULL'; // --- full time, locale aware
- const TIME_LONG = 'TIME_LONG'; // --- long time, locale aware
- const TIME_MEDIUM = 'TIME_MEDIUM'; // --- medium time, locale aware
- const TIME_SHORT = 'TIME_SHORT'; // --- short time, locale aware
- const ATOM = 'ATOM'; // --- DATE_ATOM
- const COOKIE = 'COOKIE'; // --- DATE_COOKIE
- const RFC_822 = 'RFC_822'; // --- DATE_RFC822
- const RFC_850 = 'RFC_850'; // --- DATE_RFC850
- const RFC_1036 = 'RFC_1036'; // --- DATE_RFC1036
- const RFC_1123 = 'RFC_1123'; // --- DATE_RFC1123
- const RFC_3339 = 'RFC_3339'; // --- DATE_RFC3339
- const RSS = 'RSS'; // --- DATE_RSS
- const W3C = 'W3C'; // --- DATE_W3C
+ const DAY = 'dd';
+ const DAY_SHORT = 'd';
+ const DAY_SUFFIX = 'SS';
+ const DAY_OF_YEAR = 'D';
+ const WEEKDAY = 'EEEE';
+ const WEEKDAY_SHORT = 'EEE';
+ const WEEKDAY_NARROW = 'E';
+ const WEEKDAY_NAME = 'EE';
+ const WEEKDAY_8601 = 'eee';
+ const WEEKDAY_DIGIT = 'e';
+ const WEEK = 'ww';
+ const MONTH = 'MM';
+ const MONTH_SHORT = 'M';
+ const MONTH_DAYS = 'ddd';
+ const MONTH_NAME = 'MMMM';
+ const MONTH_NAME_SHORT = 'MMM';
+ const MONTH_NAME_NARROW = 'MMMMM';
+ const YEAR = 'y';
+ const YEAR_SHORT = 'yy';
+ const YEAR_8601 = 'Y';
+ const YEAR_SHORT_8601 = 'YY';
+ const LEAPYEAR = 'l';
+ const MERIDIEM = 'a';
+ const SWATCH = 'B';
+ const HOUR = 'HH';
+ const HOUR_SHORT = 'H';
+ const HOUR_AM = 'hh';
+ const HOUR_SHORT_AM = 'h';
+ const MINUTE = 'mm';
+ const MINUTE_SHORT = 'm';
+ const SECOND = 'ss';
+ const SECOND_SHORT = 's';
+ const MILLISECOND = 'S';
+ const TIMEZONE_NAME = 'zzzz';
+ const DAYLIGHT = 'I';
+ const GMT_DIFF = 'Z';
+ const GMT_DIFF_SEP = 'ZZZZ';
+ const TIMEZONE = 'z';
+ const TIMEZONE_SECS = 'X';
+ const ISO_8601 = 'c';
+ const RFC_2822 = 'r';
+ const TIMESTAMP = 'U';
+ const ERA = 'G';
+ const ERA_NAME = 'GGGG';
+ const ERA_NARROW = 'GGGGG';
+ const DATES = 'F';
+ const DATE_FULL = 'FFFFF';
+ const DATE_LONG = 'FFFF';
+ const DATE_MEDIUM = 'FFF';
+ const DATE_SHORT = 'FF';
+ const TIMES = 'WW';
+ const TIME_FULL = 'TTTTT';
+ const TIME_LONG = 'TTTT';
+ const TIME_MEDIUM = 'TTT';
+ const TIME_SHORT = 'TT';
+ const DATETIME = 'K';
+ const DATETIME_FULL = 'KKKKK';
+ const DATETIME_LONG = 'KKKK';
+ const DATETIME_MEDIUM = 'KKK';
+ const DATETIME_SHORT = 'KK';
+ const ATOM = 'OOO';
+ const COOKIE = 'CCC';
+ const RFC_822 = 'R';
+ const RFC_850 = 'RR';
+ const RFC_1036 = 'RRR';
+ const RFC_1123 = 'RRRR';
+ const RFC_3339 = 'RRRRR';
+ const RSS = 'SSS';
+ const W3C = 'WWW';
/**
* Generates the standard date object, could be a unix timestamp, localized date,
*/
public function __construct($date = null, $part = null, $locale = null)
{
- if (($date !== null) and !($date instanceof Zend_TimeSync_Protocol) and (Zend_Locale::isLocale($date, true, false))) {
+ if (is_object($date) and !($date instanceof Zend_TimeSync_Protocol) and
+ !($date instanceof Zend_Date)) {
+ if ($locale instanceof Zend_Locale) {
+ $locale = $date;
+ $date = null;
+ $part = null;
+ } else {
+ $date = (string) $date;
+ }
+ }
+
+ if (($date !== null) and !is_array($date) and !($date instanceof Zend_TimeSync_Protocol) and
+ !($date instanceof Zend_Date) and !defined($date) and Zend_Locale::isLocale($date, true, false)) {
$locale = $date;
- $date = null;
- $part = null;
- } else if (($part !== null) and (Zend_Locale::isLocale($part, null, false))) {
+ $date = null;
+ $part = null;
+ } else if (($part !== null) and !defined($part) and Zend_Locale::isLocale($part, true, false)) {
$locale = $part;
$part = null;
}
- if (empty($locale)) {
- require_once 'Zend/Registry.php';
- if (Zend_Registry::isRegistered('Zend_Locale') === true) {
- $locale = Zend_Registry::get('Zend_Locale');
- }
- }
-
$this->setLocale($locale);
-
- if (is_string($date) && defined('self::' . $date)) {
+ if (is_string($date) && ($part === null) && (strlen($date) <= 5)) {
$part = $date;
$date = null;
}
- if (is_null($date)) {
- $date = self::now($locale);
- if (($part !== null) && ($part !== self::TIMESTAMP)) {
+ if ($date === null) {
+ if ($part === null) {
+ $date = time();
+ } else if ($part !== self::TIMESTAMP) {
+ $date = self::now($locale);
$date = $date->get($part);
}
}
$this->set($date, $part, $this->_locale);
// DST fix
- if ((is_array($date) === true) and (isset($date['hour']) === true)) {
+ if (is_array($date) === true) {
+ if (!isset($date['hour'])) {
+ $date['hour'] = 0;
+ }
+
$hour = $this->toString('H');
$hour = $date['hour'] - $hour;
- if ($hour !== 0) {
- $this->addTimestamp($hour * 3600);
+ switch ($hour) {
+ case 1 :
+ case -23 :
+ $this->addTimestamp(3600);
+ break;
+ case -1 :
+ case 23 :
+ $this->subTimestamp(3600);
+ break;
+ case 2 :
+ case -22 :
+ $this->addTimestamp(7200);
+ break;
+ case -2 :
+ case 22 :
+ $this->subTimestamp(7200);
+ break;
}
}
} else {
*/
public function toString($format = null, $type = null, $locale = null)
{
- if ((strlen($format) != 2) and ($format !== null) and (Zend_Locale::isLocale($format, null, false))) {
+ if (is_object($format)) {
+ if ($format instanceof Zend_Locale) {
+ $locale = $format;
+ $format = null;
+ } else {
+ $format = (string) $format;
+ }
+ }
+
+ if (is_object($type)) {
+ if ($type instanceof Zend_Locale) {
+ $locale = $type;
+ $type = null;
+ } else {
+ $type = (string) $type;
+ }
+ }
+
+ if (($format !== null) and !defined($format) and
+ ($format != 'ee') and ($format != 'ss') and Zend_Locale::isLocale($format, null, false)) {
$locale = $format;
$format = null;
}
- if (($type !== null) and (Zend_Locale::isLocale($type, null, false))) {
+ if (($type !== null) and ($type != 'php') and ($type != 'iso') and
+ Zend_Locale::isLocale($type, null, false)) {
$locale = $type;
$type = null;
}
$format = Zend_Locale_Format::convertPhpToIsoFormat($format);
}
- // get format tokens
- $j = 0;
- $comment = false;
- $output = array();
- for($i = 0; $i < strlen($format); ++$i) {
-
- if ($format[$i] == "'") {
- if ($comment == false) {
- $comment = true;
- ++$j;
- $output[$j] = "'";
- } else if (isset($format[$i+1]) and ($format[$i+1] == "'")) {
- $output[$j] .= "'";
- ++$i;
- } else {
- $comment = false;
- }
- continue;
- }
-
- if (isset($output[$j]) and ($output[$j][0] == $format[$i]) or
- ($comment == true)) {
- $output[$j] .= $format[$i];
- } else {
- ++$j;
- $output[$j] = $format[$i];
- }
- }
-
- $notset = false;
- // fill format tokens with date information
- for($i = 1; $i <= count($output); ++$i) {
- // fill fixed tokens
- switch ($output[$i]) {
-
- // special formats
- case 'SS' :
- $output[$i] = $this->date('S', $this->getUnixTimestamp(), false);
- break;
-
- case 'eee' :
- $output[$i] = $this->date('N', $this->getUnixTimestamp(), false);
- break;
-
- case 'ddd' :
- $output[$i] = $this->date('t', $this->getUnixTimestamp(), false);
- break;
-
- case 'l' :
- $output[$i] = $this->date('L', $this->getUnixTimestamp(), false);
- break;
-
- case 'B' :
- $output[$i] = $this->date('B', $this->getUnixTimestamp(), false);
- break;
-
- case 'I' :
- $output[$i] = $this->date('I', $this->getUnixTimestamp(), false);
- break;
-
- case 'X' :
- $output[$i] = $this->date('Z', $this->getUnixTimestamp(), false);
- break;
-
- case 'r' :
- $output[$i] = $this->date('r', $this->getUnixTimestamp(), false);
- break;
-
- case 'U' :
- $output[$i] = $this->getUnixTimestamp();
- break;
-
- // eras
- case 'GGGGG' :
- $output[$i] = iconv_substr($this->get(self::ERA, $locale), 0, 1, 'UTF-8') . ".";
- break;
-
- case 'GGGG' :
- $output[$i] = $this->get(self::ERA_NAME, $locale);
- break;
-
- case 'GGG' :
- case 'GG' :
- case 'G' :
- $output[$i] = $this->get(self::ERA, $locale);
- break;
-
- // years
- case 'yy' :
- $output[$i] = str_pad($this->get(self::YEAR_SHORT, $locale), 2, '0', STR_PAD_LEFT);
- break;
-
- // ISO years
- case 'YY' :
- $output[$i] = str_pad($this->get(self::YEAR_SHORT_8601, $locale), 2, '0', STR_PAD_LEFT);
- break;
-
- // months
- case 'MMMMM' :
- $output[$i] = iconv_substr($this->get(self::MONTH_NAME_NARROW, $locale), 0, 1, 'UTF-8');
- break;
-
- case 'MMMM' :
- $output[$i] = $this->get(self::MONTH_NAME, $locale);
- break;
-
- case 'MMM' :
- $output[$i] = $this->get(self::MONTH_NAME_SHORT, $locale);
- break;
-
- case 'MM' :
- $output[$i] = $this->get(self::MONTH, $locale);
- break;
-
- case 'M' :
- $output[$i] = $this->get(self::MONTH_SHORT, $locale);
- break;
-
- // week
- case 'ww' :
- $output[$i] = str_pad($this->get(self::WEEK, $locale), 2, '0', STR_PAD_LEFT);
- break;
-
- case 'w' :
- $output[$i] = $this->get(self::WEEK, $locale);
- break;
-
- // monthday
- case 'dd' :
- $output[$i] = $this->get(self::DAY, $locale);
- break;
-
- case 'd' :
- $output[$i] = $this->get(self::DAY_SHORT, $locale);
- break;
-
- // yearday
- case 'DDD' :
- $output[$i] = str_pad($this->get(self::DAY_OF_YEAR, $locale), 3, '0', STR_PAD_LEFT);
- break;
-
- case 'DD' :
- $output[$i] = str_pad($this->get(self::DAY_OF_YEAR, $locale), 2, '0', STR_PAD_LEFT);
- break;
-
- case 'D' :
- $output[$i] = $this->get(self::DAY_OF_YEAR, $locale);
- break;
-
- // weekday
- case 'EEEEE' :
- $output[$i] = $this->get(self::WEEKDAY_NARROW, $locale);
- break;
-
- case 'EEEE' :
- $output[$i] = $this->get(self::WEEKDAY, $locale);
- break;
-
- case 'EEE' :
- $output[$i] = $this->get(self::WEEKDAY_SHORT, $locale);
- break;
-
- case 'EE' :
- $output[$i] = $this->get(self::WEEKDAY_NAME, $locale);
- break;
-
- case 'E' :
- $output[$i] = $this->get(self::WEEKDAY_NARROW, $locale);
- break;
-
- // weekday number
- case 'ee' :
- $output[$i] = str_pad($this->get(self::WEEKDAY_8601, $locale), 2, '0', STR_PAD_LEFT);
- break;
-
- case 'e' :
- $output[$i] = $this->get(self::WEEKDAY_8601, $locale);
- break;
-
-
- // period
- case 'a' :
- $output[$i] = $this->get(self::MERIDIEM, $locale);
- break;
-
- // hour
- case 'hh' :
- $output[$i] = $this->get(self::HOUR_AM, $locale);
- break;
-
- case 'h' :
- $output[$i] = $this->get(self::HOUR_SHORT_AM, $locale);
- break;
-
- case 'HH' :
- $output[$i] = $this->get(self::HOUR, $locale);
- break;
-
- case 'H' :
- $output[$i] = $this->get(self::HOUR_SHORT, $locale);
- break;
-
- // minute
- case 'mm' :
- $output[$i] = $this->get(self::MINUTE, $locale);
- break;
-
- case 'm' :
- $output[$i] = $this->get(self::MINUTE_SHORT, $locale);
- break;
-
- // second
- case 'ss' :
- $output[$i] = $this->get(self::SECOND, $locale);
- break;
-
- case 's' :
- $output[$i] = $this->get(self::SECOND_SHORT, $locale);
- break;
-
- case 'S' :
- $output[$i] = $this->get(self::MILLISECOND, $locale);
- break;
-
- // zone
- // @todo v needs to be reworked as it's the long wall time and not the timezone
- case 'vvvv' :
- case 'zzzz' :
- $output[$i] = $this->get(self::TIMEZONE_NAME, $locale);
- break;
-
- // @todo v needs to be reworked as it's the short wall time and not the timezone
- case 'v' :
- case 'zzz' :
- case 'zz' :
- case 'z' :
- $output[$i] = $this->get(self::TIMEZONE, $locale);
- break;
-
- // zone offset
- case 'ZZZZ' :
- $output[$i] = $this->get(self::GMT_DIFF_SEP, $locale);
- break;
-
- case 'ZZZ' :
- case 'ZZ' :
- case 'Z' :
- $output[$i] = $this->get(self::GMT_DIFF, $locale);
- break;
-
- default :
- $notset = true;
- break;
- }
-
- // fill variable tokens
- if ($notset == true) {
- if (($output[$i][0] !== "'") and (preg_match('/y+/', $output[$i]))) {
- $length = iconv_strlen($output[$i], 'UTF-8');
- $output[$i] = $this->get(self::YEAR, $locale);
- $output[$i] = str_pad($output[$i], $length, '0', STR_PAD_LEFT);
- }
-
- if (($output[$i][0] !== "'") and (preg_match('/Y+/', $output[$i]))) {
- $length = iconv_strlen($output[$i], 'UTF-8');
- $output[$i] = $this->get(self::YEAR_8601, $locale);
- $output[$i] = str_pad($output[$i], $length, '0', STR_PAD_LEFT);
- }
-
- if (($output[$i][0] !== "'") and (preg_match('/A+/', $output[$i]))) {
- $length = iconv_strlen($output[$i], 'UTF-8');
- $hour = $this->get(self::HOUR, $locale);
- $minute = $this->get(self::MINUTE, $locale);
- $second = $this->get(self::SECOND, $locale);
- $milli = $this->get(self::MILLISECOND, $locale);
-
- $seconds = $milli + ($second * 1000) + ($minute * 60000) + ($hour * 3600000);
- $output[$i] = str_pad($seconds, $length, '0', STR_PAD_LEFT);
- }
-
- if ($output[$i][0] === "'") {
- $output[$i] = iconv_substr($output[$i],
- 1,
- iconv_strlen($output[$i], 'UTF-8') - 1,
- 'UTF-8');
- }
- }
- $notset = false;
- }
-
- return implode('', $output);
+ return $this->get($format, $locale);
}
/**
*
* @param string $part OPTIONAL Part of the date to return, if null the timestamp is returned
* @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
- * @return integer|string date or datepart
+ * @return string date or datepart
*/
public function get($part = null, $locale = null)
{
$locale = $this->getLocale();
}
- if (($part !== null) and (Zend_Locale::isLocale($part, null, false))) {
+ if (($part !== null) && (strlen($part) !== 2) && (Zend_Locale::isLocale($part, null, false))) {
$locale = $part;
$part = null;
}
$part = self::TIMESTAMP;
}
- if (!defined("self::".$part)) {
- return $this->toString($part, $locale);
+ return $this->date($this->_toToken($part, $locale), $this->getUnixTimestamp(), false);
+ }
+
+ /**
+ * Internal method to apply tokens
+ *
+ * @param string $part
+ * @param string $locale
+ * @return string
+ */
+ private function _toToken($part, $locale) {
+ // get format tokens
+ $comment = false;
+ $format = '';
+ $orig = '';
+ for ($i = 0; $i < strlen($part); ++$i) {
+ if ($part[$i] == "'") {
+ $comment = $comment ? false : true;
+ if (isset($part[$i+1]) && ($part[$i+1] == "'")) {
+ $comment = $comment ? false : true;
+ $format .= "\\'";
+ ++$i;
+ }
+
+ $orig = '';
+ continue;
+ }
+
+ if ($comment) {
+ $format .= '\\' . $part[$i];
+ $orig = '';
+ } else {
+ $orig .= $part[$i];
+ if (!isset($part[$i+1]) || (isset($orig[0]) && ($orig[0] != $part[$i+1]))) {
+ $format .= $this->_parseIsoToDate($orig, $locale);
+ $orig = '';
+ }
+ }
}
- switch($part) {
+ return $format;
+ }
- // day formats
+ /**
+ * Internal parsing method
+ *
+ * @param string $token
+ * @param string $locale
+ * @return string
+ */
+ private function _parseIsoToDate($token, $locale) {
+ switch($token) {
case self::DAY :
- return $this->date('d', $this->getUnixTimestamp(), false);
+ return 'd';
break;
case self::WEEKDAY_SHORT :
$weekday = strtolower($this->date('D', $this->getUnixTimestamp(), false));
- $day = Zend_Locale_Data::getContent($locale, 'day', array('gregorian', 'format', 'wide', $weekday));
- return iconv_substr($day, 0, 3, 'UTF-8');
+ $day = Zend_Locale_Data::getContent($locale, 'day', array('gregorian', 'format', 'wide', $weekday));
+ return $this->_toComment(iconv_substr($day, 0, 3, 'UTF-8'));
break;
case self::DAY_SHORT :
- return $this->date('j', $this->getUnixTimestamp(), false);
+ return 'j';
break;
case self::WEEKDAY :
$weekday = strtolower($this->date('D', $this->getUnixTimestamp(), false));
- return Zend_Locale_Data::getContent($locale, 'day', array('gregorian', 'format', 'wide', $weekday));
+ return $this->_toComment(Zend_Locale_Data::getContent($locale, 'day', array('gregorian', 'format', 'wide', $weekday)));
break;
case self::WEEKDAY_8601 :
- return $this->date('N', $this->getUnixTimestamp(), false);
+ return 'N';
+ break;
+
+ case 'ee' :
+ return $this->_toComment(str_pad($this->date('N', $this->getUnixTimestamp(), false), 2, '0', STR_PAD_LEFT));
break;
case self::DAY_SUFFIX :
- return $this->date('S', $this->getUnixTimestamp(), false);
+ return 'S';
break;
case self::WEEKDAY_DIGIT :
- return $this->date('w', $this->getUnixTimestamp(), false);
+ return 'w';
break;
case self::DAY_OF_YEAR :
- return $this->date('z', $this->getUnixTimestamp(), false);
+ return 'z';
+ break;
+
+ case 'DDD' :
+ return $this->_toComment(str_pad($this->date('z', $this->getUnixTimestamp(), false), 3, '0', STR_PAD_LEFT));
+ break;
+
+ case 'DD' :
+ return $this->_toComment(str_pad($this->date('z', $this->getUnixTimestamp(), false), 2, '0', STR_PAD_LEFT));
break;
case self::WEEKDAY_NARROW :
+ case 'EEEEE' :
$weekday = strtolower($this->date('D', $this->getUnixTimestamp(), false));
$day = Zend_Locale_Data::getContent($locale, 'day', array('gregorian', 'format', 'abbreviated', $weekday));
- return iconv_substr($day, 0, 1, 'UTF-8');
+ return $this->_toComment(iconv_substr($day, 0, 1, 'UTF-8'));
break;
case self::WEEKDAY_NAME :
$weekday = strtolower($this->date('D', $this->getUnixTimestamp(), false));
- return Zend_Locale_Data::getContent($locale, 'day', array('gregorian', 'format', 'abbreviated', $weekday));
+ return $this->_toComment(Zend_Locale_Data::getContent($locale, 'day', array('gregorian', 'format', 'abbreviated', $weekday)));
+ break;
+
+ case 'w' :
+ $week = $this->date('W', $this->getUnixTimestamp(), false);
+ return $this->_toComment(($week[0] == '0') ? $week[1] : $week);
break;
- // week formats
case self::WEEK :
- return $this->date('W', $this->getUnixTimestamp(), false);
+ return 'W';
break;
- // month formats
case self::MONTH_NAME :
$month = $this->date('n', $this->getUnixTimestamp(), false);
- return Zend_Locale_Data::getContent($locale, 'month', array('gregorian', 'format', 'wide', $month));
+ return $this->_toComment(Zend_Locale_Data::getContent($locale, 'month', array('gregorian', 'format', 'wide', $month)));
break;
case self::MONTH :
- return $this->date('m', $this->getUnixTimestamp(), false);
+ return 'm';
break;
case self::MONTH_NAME_SHORT :
$month = $this->date('n', $this->getUnixTimestamp(), false);
- return Zend_Locale_Data::getContent($locale, 'month', array('gregorian', 'format', 'abbreviated', $month));
+ return $this->_toComment(Zend_Locale_Data::getContent($locale, 'month', array('gregorian', 'format', 'abbreviated', $month)));
break;
case self::MONTH_SHORT :
- return $this->date('n', $this->getUnixTimestamp(), false);
+ return 'n';
break;
case self::MONTH_DAYS :
- return $this->date('t', $this->getUnixTimestamp(), false);
+ return 't';
break;
case self::MONTH_NAME_NARROW :
$month = $this->date('n', $this->getUnixTimestamp(), false);
$mon = Zend_Locale_Data::getContent($locale, 'month', array('gregorian', 'format', 'abbreviated', $month));
- return iconv_substr($mon, 0, 1, 'UTF-8');
+ return $this->_toComment(iconv_substr($mon, 0, 1, 'UTF-8'));
break;
- // year formats
case self::LEAPYEAR :
- return $this->date('L', $this->getUnixTimestamp(), false);
+ return 'L';
break;
case self::YEAR_8601 :
- return $this->date('o', $this->getUnixTimestamp(), false);
+ return 'o';
break;
case self::YEAR :
- return $this->date('Y', $this->getUnixTimestamp(), false);
+ return 'Y';
break;
case self::YEAR_SHORT :
- return $this->date('y', $this->getUnixTimestamp(), false);
+ return 'y';
break;
-
case self::YEAR_SHORT_8601 :
- return substr($this->date('o', $this->getUnixTimestamp(), false), -2, 2);
+ return $this->_toComment(substr($this->date('o', $this->getUnixTimestamp(), false), -2, 2));
break;
- // time formats
case self::MERIDIEM :
$am = $this->date('a', $this->getUnixTimestamp(), false);
if ($am == 'am') {
- return Zend_Locale_Data::getContent($locale, 'am');
+ return $this->_toComment(Zend_Locale_Data::getContent($locale, 'am'));
}
- return Zend_Locale_Data::getContent($locale, 'pm');
+
+ return $this->_toComment(Zend_Locale_Data::getContent($locale, 'pm'));
break;
case self::SWATCH :
- return $this->date('B', $this->getUnixTimestamp(), false);
+ return 'B';
break;
case self::HOUR_SHORT_AM :
- return $this->date('g', $this->getUnixTimestamp(), false);
+ return 'g';
break;
case self::HOUR_SHORT :
- return $this->date('G', $this->getUnixTimestamp(), false);
+ return 'G';
break;
case self::HOUR_AM :
- return $this->date('h', $this->getUnixTimestamp(), false);
+ return 'h';
break;
case self::HOUR :
- return $this->date('H', $this->getUnixTimestamp(), false);
+ return 'H';
break;
case self::MINUTE :
- return $this->date('i', $this->getUnixTimestamp(), false);
+ return $this->_toComment(str_pad($this->date('i', $this->getUnixTimestamp(), false), 2, '0', STR_PAD_LEFT));
break;
case self::SECOND :
- return $this->date('s', $this->getUnixTimestamp(), false);
+ return $this->_toComment(str_pad($this->date('s', $this->getUnixTimestamp(), false), 2, '0', STR_PAD_LEFT));
break;
case self::MINUTE_SHORT :
- return $this->date('i', $this->getUnixTimestamp(), false);
+ return 'i';
break;
case self::SECOND_SHORT :
- return $this->date('s', $this->getUnixTimestamp(), false);
+ return 's';
break;
case self::MILLISECOND :
- return $this->_fractional;
+ return $this->_toComment($this->_fractional);
break;
- // timezone formats
case self::TIMEZONE_NAME :
- return $this->date('e', $this->getUnixTimestamp(), false);
+ case 'vvvv' :
+ return 'e';
break;
case self::DAYLIGHT :
- return $this->date('I', $this->getUnixTimestamp(), false);
+ return 'I';
break;
case self::GMT_DIFF :
- return $this->date('O', $this->getUnixTimestamp(), false);
+ case 'ZZ' :
+ case 'ZZZ' :
+ return 'O';
break;
case self::GMT_DIFF_SEP :
- return $this->date('P', $this->getUnixTimestamp(), false);
+ return 'P';
break;
case self::TIMEZONE :
- return $this->date('T', $this->getUnixTimestamp(), false);
+ case 'v' :
+ case 'zz' :
+ case 'zzz' :
+ return 'T';
break;
case self::TIMEZONE_SECS :
- return $this->date('Z', $this->getUnixTimestamp(), false);
+ return 'Z';
break;
- // date strings
case self::ISO_8601 :
- return $this->date('c', $this->getUnixTimestamp(), false);
+ return 'c';
break;
case self::RFC_2822 :
- return $this->date('r', $this->getUnixTimestamp(), false);
+ return 'r';
break;
case self::TIMESTAMP :
- return $this->getUnixTimestamp();
+ return 'U';
break;
- // additional formats
case self::ERA :
+ case 'GG' :
+ case 'GGG' :
$year = $this->date('Y', $this->getUnixTimestamp(), false);
if ($year < 0) {
- return Zend_Locale_Data::getContent($locale, 'era', array('gregorian', 'Abbr', '0'));
+ return $this->_toComment(Zend_Locale_Data::getContent($locale, 'era', array('gregorian', 'Abbr', '0')));
}
- return Zend_Locale_Data::getContent($locale, 'era', array('gregorian', 'Abbr', '1'));
+
+ return $this->_toComment(Zend_Locale_Data::getContent($locale, 'era', array('gregorian', 'Abbr', '1')));
+ break;
+
+ case self::ERA_NARROW :
+ $year = $this->date('Y', $this->getUnixTimestamp(), false);
+ if ($year < 0) {
+ return $this->_toComment(iconv_substr(Zend_Locale_Data::getContent($locale, 'era', array('gregorian', 'Abbr', '0')), 0, 1, 'UTF-8')) . '.';
+ }
+
+ return $this->_toComment(iconv_substr(Zend_Locale_Data::getContent($locale, 'era', array('gregorian', 'Abbr', '1')), 0, 1, 'UTF-8')) . '.';
break;
case self::ERA_NAME :
$year = $this->date('Y', $this->getUnixTimestamp(), false);
if ($year < 0) {
- return Zend_Locale_Data::getContent($locale, 'era', array('gregorian', 'Names', '0'));
+ return $this->_toComment(Zend_Locale_Data::getContent($locale, 'era', array('gregorian', 'Names', '0')));
}
- return Zend_Locale_Data::getContent($locale, 'era', array('gregorian', 'Names', '1'));
+
+ return $this->_toComment(Zend_Locale_Data::getContent($locale, 'era', array('gregorian', 'Names', '1')));
break;
case self::DATES :
- return $this->toString(Zend_Locale_Format::getDateFormat($locale), 'iso', $locale);
+ return $this->_toToken(Zend_Locale_Format::getDateFormat($locale), $locale);
break;
case self::DATE_FULL :
- $date = Zend_Locale_Data::getContent($locale, 'date', array('gregorian', 'full'));
- return $this->toString($date, 'iso', $locale);
+ return $this->_toToken(Zend_Locale_Data::getContent($locale, 'date', array('gregorian', 'full')), $locale);
break;
case self::DATE_LONG :
- $date = Zend_Locale_Data::getContent($locale, 'date', array('gregorian', 'long'));
- return $this->toString($date, 'iso', $locale);
+ return $this->_toToken(Zend_Locale_Data::getContent($locale, 'date', array('gregorian', 'long')), $locale);
break;
case self::DATE_MEDIUM :
- $date = Zend_Locale_Data::getContent($locale, 'date', array('gregorian', 'medium'));
- return $this->toString($date, 'iso', $locale);
+ return $this->_toToken(Zend_Locale_Data::getContent($locale, 'date', array('gregorian', 'medium')), $locale);
break;
case self::DATE_SHORT :
- $date = Zend_Locale_Data::getContent($locale, 'date', array('gregorian', 'short'));
- return $this->toString($date, 'iso', $locale);
+ return $this->_toToken(Zend_Locale_Data::getContent($locale, 'date', array('gregorian', 'short')), $locale);
break;
case self::TIMES :
- return $this->toString(Zend_Locale_Format::getTimeFormat($locale), 'iso', $locale);
+ return $this->_toToken(Zend_Locale_Format::getTimeFormat($locale), $locale);
break;
case self::TIME_FULL :
- $time = Zend_Locale_Data::getContent($locale, 'time', 'full');
- return $this->toString($time, 'iso', $locale);
+ return $this->_toToken(Zend_Locale_Data::getContent($locale, 'time', 'full'), $locale);
break;
case self::TIME_LONG :
- $time = Zend_Locale_Data::getContent($locale, 'time', 'long');
- return $this->toString($time, 'iso', $locale);
+ return $this->_toToken(Zend_Locale_Data::getContent($locale, 'time', 'long'), $locale);
break;
case self::TIME_MEDIUM :
- $time = Zend_Locale_Data::getContent($locale, 'time', 'medium');
- return $this->toString($time, 'iso', $locale);
+ return $this->_toToken(Zend_Locale_Data::getContent($locale, 'time', 'medium'), $locale);
break;
case self::TIME_SHORT :
- $time = Zend_Locale_Data::getContent($locale, 'time', 'short');
- return $this->toString($time, 'iso', $locale);
+ return $this->_toToken(Zend_Locale_Data::getContent($locale, 'time', 'short'), $locale);
+ break;
+
+ case self::DATETIME :
+ return $this->_toToken(Zend_Locale_Format::getDateTimeFormat($locale), $locale);
+ break;
+
+ case self::DATETIME_FULL :
+ return $this->_toToken(Zend_Locale_Data::getContent($locale, 'datetime', array('gregorian', 'full')), $locale);
+ break;
+
+ case self::DATETIME_LONG :
+ return $this->_toToken(Zend_Locale_Data::getContent($locale, 'datetime', array('gregorian', 'long')), $locale);
+ break;
+
+ case self::DATETIME_MEDIUM :
+ return $this->_toToken(Zend_Locale_Data::getContent($locale, 'datetime', array('gregorian', 'medium')), $locale);
+ break;
+
+ case self::DATETIME_SHORT :
+ return $this->_toToken(Zend_Locale_Data::getContent($locale, 'datetime', array('gregorian', 'short')), $locale);
break;
case self::ATOM :
- return $this->date('Y\-m\-d\TH\:i\:sP', $this->getUnixTimestamp(), false);
+ return 'Y\-m\-d\TH\:i\:sP';
break;
case self::COOKIE :
- return $this->date('l\, d\-M\-y H\:i\:s e', $this->getUnixTimestamp(), false);
+ return 'l\, d\-M\-y H\:i\:s e';
break;
case self::RFC_822 :
- return $this->date('D\, d M y H\:i\:s O', $this->getUnixTimestamp(), false);
+ return 'D\, d M y H\:i\:s O';
break;
case self::RFC_850 :
- return $this->date('l\, d\-M\-y H\:i\:s e', $this->getUnixTimestamp(), false);
+ return 'l\, d\-M\-y H\:i\:s e';
break;
case self::RFC_1036 :
- return $this->date('D\, d M y H\:i\:s O', $this->getUnixTimestamp(), false);
+ return 'D\, d M y H\:i\:s O';
break;
case self::RFC_1123 :
- return $this->date('D\, d M Y H\:i\:s O', $this->getUnixTimestamp(), false);
+ return 'D\, d M Y H\:i\:s O';
break;
case self::RFC_3339 :
- return $this->date('Y\-m\-d\TH\:i\:sP', $this->getUnixTimestamp(), false);
+ return 'Y\-m\-d\TH\:i\:sP';
break;
case self::RSS :
- return $this->date('D\, d M Y H\:i\:s O', $this->getUnixTimestamp(), false);
+ return 'D\, d M Y H\:i\:s O';
break;
case self::W3C :
- return $this->date('Y\-m\-d\TH\:i\:sP', $this->getUnixTimestamp(), false);
+ return 'Y\-m\-d\TH\:i\:sP';
+ break;
+ }
+
+ if ($token == '') {
+ return '';
+ }
+
+ switch ($token[0]) {
+ case 'y' :
+ if ((strlen($token) == 4) && (abs($this->getUnixTimestamp()) <= 0x7FFFFFFF)) {
+ return 'Y';
+ }
+
+ $length = iconv_strlen($token, 'UTF-8');
+ return $this->_toComment(str_pad($this->date('Y', $this->getUnixTimestamp(), false), $length, '0', STR_PAD_LEFT));
+ break;
+
+ case 'Y' :
+ if ((strlen($token) == 4) && (abs($this->getUnixTimestamp()) <= 0x7FFFFFFF)) {
+ return 'o';
+ }
+
+ $length = iconv_strlen($token, 'UTF-8');
+ return $this->_toComment(str_pad($this->date('o', $this->getUnixTimestamp(), false), $length, '0', STR_PAD_LEFT));
+ break;
+
+ case 'A' :
+ $length = iconv_strlen($token, 'UTF-8');
+ $result = $this->_fractional;
+ $result += $this->date('s', $this->getUnixTimestamp(), false) * 1000;
+ $result += $this->date('i', $this->getUnixTimestamp(), false) * 60000;
+ $result += $this->date('H', $this->getUnixTimestamp(), false) * 3600000;
+
+ return $this->_toComment(str_pad($result, $length, '0', STR_PAD_LEFT));
break;
}
+
+ return $this->_toComment($token);
+ }
+
+ /**
+ * Private function to make a comment of a token
+ *
+ * @param string $token
+ * @return string
+ */
+ private function _toComment($token)
+ {
+ $token = str_split($token);
+ $result = '';
+ foreach ($token as $tok) {
+ $result .= '\\' . $tok;
+ }
+
+ return $result;
}
/**
if (is_array($zone)) {
return $this->getTimezone();
}
+
if ($zone instanceof Zend_Date) {
return $zone->getTimezone();
}
+
+ $match = array();
+ preg_match('/\dZ$/', $zone, $match);
+ if (!empty($match)) {
+ return "Etc/UTC";
+ }
+
preg_match('/([+-]\d{2}):{0,1}\d{2}/', $zone, $match);
if (!empty($match) and ($match[count($match) - 1] <= 12) and ($match[count($match) - 1] >= -12)) {
$zone = "Etc/GMT";
return $zone;
}
- preg_match('/([[:alpha:]\/]{3,30})/', $zone, $match);
+ preg_match('/([[:alpha:]\/]{3,30})(?!.*([[:alpha:]\/]{3,30}))/', $zone, $match);
try {
if (!empty($match) and (!is_int($match[count($match) - 1]))) {
$oldzone = $this->getTimezone();
*/
private function _calculate($calc, $date, $part, $locale)
{
- if (is_null($date) === true) {
+ if ($date === null) {
require_once 'Zend/Date/Exception.php';
throw new Zend_Date_Exception('parameter $date must be set, null is not allowed');
}
- if (($part !== null) and (Zend_Locale::isLocale($part, null, false))) {
+ if (($part !== null) && (strlen($part) !== 2) && (Zend_Locale::isLocale($part, null, false))) {
$locale = $part;
$part = null;
}
$date += $found;
$calc = 'set';
if (self::$_options['extend_month'] == false) {
- $parts = $this->getDateParts($this->mktime(0, 0, 0, $date, $day, $year, false));
+ $parts = $this->getDateParts($this->mktime($hour, $minute, $second, $date, $day, $year, false));
if ($parts['mday'] != $day) {
$fixday = ($parts['mday'] < $day) ? -$parts['mday'] : ($parts['mday'] - $day);
}
$date = $month - $found;
$calc = 'set';
if (self::$_options['extend_month'] == false) {
- $parts = $this->getDateParts($this->mktime(0, 0, 0, $date, $day, $year, false));
+ $parts = $this->getDateParts($this->mktime($hour, $minute, $second, $date, $day, $year, false));
if ($parts['mday'] != $day) {
$fixday = ($parts['mday'] < $day) ? -$parts['mday'] : ($parts['mday'] - $day);
}
$date += $month;
$calc = 'set';
if (self::$_options['extend_month'] == false) {
- $parts = $this->getDateParts($this->mktime(0, 0, 0, $date, $day, $year, false));
+ $parts = $this->getDateParts($this->mktime($hour, $minute, $second, $date, $day, $year, false));
if ($parts['mday'] != $day) {
$fixday = ($parts['mday'] < $day) ? -$parts['mday'] : ($parts['mday'] - $day);
}
$date = $month - $date;
$calc = 'set';
if (self::$_options['extend_month'] == false) {
- $parts = $this->getDateParts($this->mktime(0, 0, 0, $date, $day, $year, false));
+ $parts = $this->getDateParts($this->mktime($hour, $minute, $second, $date, $day, $year, false));
if ($parts['mday'] != $day) {
$fixday = ($parts['mday'] < $day) ? -$parts['mday'] : ($parts['mday'] - $day);
}
$date += $found;
$calc = 'set';
if (self::$_options['extend_month'] === false) {
- $parts = $this->getDateParts($this->mktime(0, 0, 0, $date, $day, $year, false));
+ $parts = $this->getDateParts($this->mktime($hour, $minute, $second, $date, $day, $year, false));
if ($parts['mday'] != $day) {
$fixday = ($parts['mday'] < $day) ? -$parts['mday'] : ($parts['mday'] - $day);
}
$date = $month - $found;
$calc = 'set';
if (self::$_options['extend_month'] === false) {
- $parts = $this->getDateParts($this->mktime(0, 0, 0, $date, $day, $year, false));
+ $parts = $this->getDateParts($this->mktime($hour, $minute, $second, $date, $day, $year, false));
if ($parts['mday'] != $day) {
$fixday = ($parts['mday'] < $day) ? -$parts['mday'] : ($parts['mday'] - $day);
}
$date += $month;
$calc = 'set';
if (self::$_options['extend_month'] === false) {
- $parts = $this->getDateParts($this->mktime(0, 0, 0, $date, $day, $year, false));
+ $parts = $this->getDateParts($this->mktime($hour, $minute, $second, $date, $day, $year, false));
if ($parts['mday'] != $day) {
$fixday = ($parts['mday'] < $day) ? -$parts['mday'] : ($parts['mday'] - $day);
}
$date = $month - $date;
$calc = 'set';
if (self::$_options['extend_month'] === false) {
- $parts = $this->getDateParts($this->mktime(0, 0, 0, $date, $day, $year, false));
+ $parts = $this->getDateParts($this->mktime($hour, $minute, $second, $date, $day, $year, false));
if ($parts['mday'] != $day) {
$fixday = ($parts['mday'] < $day) ? -$parts['mday'] : ($parts['mday'] - $day);
}
$date += $found;
$calc = 'set';
if (self::$_options['extend_month'] === false) {
- $parts = $this->getDateParts($this->mktime(0, 0, 0, $date, $day, $year, false));
+ $parts = $this->getDateParts($this->mktime($hour, $minute, $second, $date, $day, $year, false));
if ($parts['mday'] != $day) {
$fixday = ($parts['mday'] < $day) ? -$parts['mday'] : ($parts['mday'] - $day);
}
$date = $month - $found;
$calc = 'set';
if (self::$_options['extend_month'] === false) {
- $parts = $this->getDateParts($this->mktime(0, 0, 0, $date, $day, $year, false));
+ $parts = $this->getDateParts($this->mktime($hour, $minute, $second, $date, $day, $year, false));
if ($parts['mday'] != $day) {
$fixday = ($parts['mday'] < $day) ? -$parts['mday'] : ($parts['mday'] - $day);
}
$day = 1;
$year = 1970;
}
- return $this->_assign($calc, $this->mktime($parsed['hour'], $parsed['minute'], 0, $month, $day, $year, true),
- $this->mktime($hour, $minute, $second, $month, $day, $year, true), false);
+
+ if (!isset($parsed['second'])) {
+ $parsed['second'] = 0;
+ }
+
+ return $this->_assign($calc, $this->mktime($parsed['hour'], $parsed['minute'], $parsed['second'], $month, $day, $year, true),
+ $this->mktime($hour, $minute, $second, $month, $day, $year, true), false);
} catch (Zend_Locale_Exception $e) {
require_once 'Zend/Date/Exception.php';
throw new Zend_Date_Exception($e->getMessage(), $date);
$day = 1;
$year = 1970;
}
- return $this->_assign($calc, $this->mktime($parsed['hour'], $parsed['minute'], 0, $month, $day, $year, true),
- $this->mktime($hour, $minute, $second, $month, $day, $year, true), false);
+
+ if (!isset($parsed['second'])) {
+ $parsed['second'] = 0;
+ }
+
+ return $this->_assign($calc, $this->mktime($parsed['hour'], $parsed['minute'], $parsed['second'], $month, $day, $year, true),
+ $this->mktime($hour, $minute, $second, $month, $day, $year, true), false);
+ } catch (Zend_Locale_Exception $e) {
+ require_once 'Zend/Date/Exception.php';
+ throw new Zend_Date_Exception($e->getMessage(), $date);
+ }
+ break;
+
+ case self::DATETIME:
+ try {
+ $parsed = Zend_Locale_Format::getDateTime($date, array('locale' => $locale, 'format_type' => 'iso', 'fix_date' => true));
+ if (($calc == 'set') || ($calc == 'cmp')) {
+ --$parsed['month'];
+ --$month;
+ --$parsed['day'];
+ --$day;
+ $parsed['year'] -= 1970;
+ $year -= 1970;
+ }
+ return $this->_assign($calc, $this->mktime($parsed['hour'], $parsed['minute'], $parsed['second'], 1 + $parsed['month'], 1 + $parsed['day'], 1970 + $parsed['year'], true),
+ $this->mktime($hour, $minute, $second, 1 + $month, 1 + $day, 1970 + $year, true), $hour);
+ } catch (Zend_Locale_Exception $e) {
+ require_once 'Zend/Date/Exception.php';
+ throw new Zend_Date_Exception($e->getMessage(), $date);
+ }
+ break;
+
+ case self::DATETIME_FULL:
+ try {
+ $format = Zend_Locale_Data::getContent($locale, 'datetime', array('gregorian', 'full'));
+ $parsed = Zend_Locale_Format::getDateTime($date, array('date_format' => $format, 'format_type' => 'iso', 'locale' => $locale));
+
+ if (($calc == 'set') || ($calc == 'cmp')) {
+ --$parsed['month'];
+ --$month;
+ --$parsed['day'];
+ --$day;
+ $parsed['year'] -= 1970;
+ $year -= 1970;
+ }
+
+ if (!isset($parsed['second'])) {
+ $parsed['second'] = 0;
+ }
+
+ return $this->_assign($calc, $this->mktime($parsed['hour'], $parsed['minute'], $parsed['second'], 1 + $parsed['month'], 1 + $parsed['day'], 1970 + $parsed['year'], true),
+ $this->mktime($hour, $minute, $second, 1 + $month, 1 + $day, 1970 + $year, true), $hour);
+ } catch (Zend_Locale_Exception $e) {
+ require_once 'Zend/Date/Exception.php';
+ throw new Zend_Date_Exception($e->getMessage(), $date);
+ }
+ break;
+
+ case self::DATETIME_LONG:
+ try {
+ $format = Zend_Locale_Data::getContent($locale, 'datetime', array('gregorian', 'long'));
+ $parsed = Zend_Locale_Format::getDateTime($date, array('date_format' => $format, 'format_type' => 'iso', 'locale' => $locale));
+
+ if (($calc == 'set') || ($calc == 'cmp')){
+ --$parsed['month'];
+ --$month;
+ --$parsed['day'];
+ --$day;
+ $parsed['year'] -= 1970;
+ $year -= 1970;
+ }
+ return $this->_assign($calc, $this->mktime($parsed['hour'], $parsed['minute'], $parsed['second'], 1 + $parsed['month'], 1 + $parsed['day'], 1970 + $parsed['year'], true),
+ $this->mktime($hour, $minute, $second, 1 + $month, 1 + $day, 1970 + $year, true), $hour);
+ } catch (Zend_Locale_Exception $e) {
+ require_once 'Zend/Date/Exception.php';
+ throw new Zend_Date_Exception($e->getMessage(), $date);
+ }
+ break;
+
+ case self::DATETIME_MEDIUM:
+ try {
+ $format = Zend_Locale_Data::getContent($locale, 'datetime', array('gregorian', 'medium'));
+ $parsed = Zend_Locale_Format::getDateTime($date, array('date_format' => $format, 'format_type' => 'iso', 'locale' => $locale));
+ if (($calc == 'set') || ($calc == 'cmp')) {
+ --$parsed['month'];
+ --$month;
+ --$parsed['day'];
+ --$day;
+ $parsed['year'] -= 1970;
+ $year -= 1970;
+ }
+ return $this->_assign($calc, $this->mktime($parsed['hour'], $parsed['minute'], $parsed['second'], 1 + $parsed['month'], 1 + $parsed['day'], 1970 + $parsed['year'], true),
+ $this->mktime($hour, $minute, $second, 1 + $month, 1 + $day, 1970 + $year, true), $hour);
+ } catch (Zend_Locale_Exception $e) {
+ require_once 'Zend/Date/Exception.php';
+ throw new Zend_Date_Exception($e->getMessage(), $date);
+ }
+ break;
+
+ case self::DATETIME_SHORT:
+ try {
+ $format = Zend_Locale_Data::getContent($locale, 'datetime', array('gregorian', 'short'));
+ $parsed = Zend_Locale_Format::getDateTime($date, array('date_format' => $format, 'format_type' => 'iso', 'locale' => $locale));
+
+ $parsed['year'] = self::getFullYear($parsed['year']);
+
+ if (($calc == 'set') || ($calc == 'cmp')) {
+ --$parsed['month'];
+ --$month;
+ --$parsed['day'];
+ --$day;
+ $parsed['year'] -= 1970;
+ $year -= 1970;
+ }
+
+ if (!isset($parsed['second'])) {
+ $parsed['second'] = 0;
+ }
+
+ return $this->_assign($calc, $this->mktime($parsed['hour'], $parsed['minute'], $parsed['second'], 1 + $parsed['month'], 1 + $parsed['day'], 1970 + $parsed['year'], true),
+ $this->mktime($hour, $minute, $second, 1 + $month, 1 + $day, 1970 + $year, true), $hour);
} catch (Zend_Locale_Exception $e) {
require_once 'Zend/Date/Exception.php';
throw new Zend_Date_Exception($e->getMessage(), $date);
*/
private function _time($calc, $time, $format, $locale)
{
- if (is_null($time)) {
+ if ($time === null) {
require_once 'Zend/Date/Exception.php';
throw new Zend_Date_Exception('parameter $time must be set, null is not allowed');
}
- if ($locale === null) {
- $locale = $this->getLocale();
- }
-
if ($time instanceof Zend_Date) {
// extract time from object
- $time = $time->get(self::TIME_MEDIUM, $locale);
+ $time = $time->get('HH:mm:ss');
} else {
if (is_array($time)) {
if ((isset($time['hour']) === true) or (isset($time['minute']) === true) or
$format = Zend_Locale_Format::convertPhpToIsoFormat($format);
}
try {
+ if ($locale === null) {
+ $locale = $this->getLocale();
+ }
+
$parsed = Zend_Locale_Format::getTime($time, array('date_format' => $format, 'locale' => $locale, 'format_type' => 'iso'));
} catch (Zend_Locale_Exception $e) {
require_once 'Zend/Date/Exception.php';
throw new Zend_Date_Exception($e->getMessage());
}
}
- $time = new self(0, self::TIMESTAMP, $locale);
- $time->setTimezone('UTC');
- $time->set($parsed['hour'], self::HOUR);
- $time->set($parsed['minute'], self::MINUTE);
- $time->set($parsed['second'], self::SECOND);
- $time = $time->get(self::TIME_MEDIUM, $locale);
+ $time = str_pad($parsed['hour'], 2, '0', STR_PAD_LEFT) . ":";
+ $time .= str_pad($parsed['minute'], 2, '0', STR_PAD_LEFT) . ":";
+ $time .= str_pad($parsed['second'], 2, '0', STR_PAD_LEFT);
}
- $return = $this->_calcdetail($calc, $time, self::TIME_MEDIUM, $locale);
+ $return = $this->_calcdetail($calc, $time, self::TIMES, 'de');
if ($calc != 'cmp') {
return $this;
}
*/
public function getDate($locale = null)
{
- $date = $this->copyPart(self::DATE_FULL, $locale);
+ $date = $this->copyPart(self::DATE_MEDIUM, $locale);
$date->addTimestamp($this->getGmtOffset());
return $date;
}
*/
private function _date($calc, $date, $format, $locale)
{
- if (is_null($date)) {
+ if ($date === null) {
require_once 'Zend/Date/Exception.php';
throw new Zend_Date_Exception('parameter $date must be set, null is not allowed');
}
- if ($locale === null) {
- $locale = $this->getLocale();
- }
-
if ($date instanceof Zend_Date) {
// extract date from object
- $date = $date->get(self::DATE_FULL, $locale);
+ $date = $date->get('d.M.Y');
} else {
if (is_array($date)) {
- if ((isset($time['year']) === true) or (isset($time['month']) === true) or
- (isset($time['day']) === true)) {
- $parsed = $time;
+ if ((isset($date['year']) === true) or (isset($date['month']) === true) or
+ (isset($date['day']) === true)) {
+ $parsed = $date;
} else {
require_once 'Zend/Date/Exception.php';
throw new Zend_Date_Exception("no day,month or year given in array");
$format = Zend_Locale_Format::convertPhpToIsoFormat($format);
}
try {
+ if ($locale === null) {
+ $locale = $this->getLocale();
+ }
+
$parsed = Zend_Locale_Format::getDate($date, array('date_format' => $format, 'locale' => $locale, 'format_type' => 'iso'));
if ((strpos(strtoupper($format), 'YY') !== false) and (strpos(strtoupper($format), 'YYYY') === false)) {
$parsed['year'] = self::getFullYear($parsed['year']);
throw new Zend_Date_Exception($e->getMessage());
}
}
- $date = new self(0, self::TIMESTAMP, $locale);
- $date->setTimezone('UTC');
- $date->set($parsed['year'], self::YEAR);
- $date->set($parsed['month'], self::MONTH);
- $date->set($parsed['day'], self::DAY);
- $date = $date->get(self::DATE_FULL, $locale);
+ $date = $parsed['day'] . "." . $parsed['month'] . "." . $parsed['year'];
}
- $return = $this->_calcdetail($calc, $date, self::DATE_FULL, $locale);
+ $return = $this->_calcdetail($calc, $date, self::DATE_MEDIUM, 'de');
if ($calc != 'cmp') {
return $this;
}
*/
private function _calcvalue($calc, $value, $type, $parameter, $locale)
{
- if (is_null($value)) {
+ if ($value === null) {
require_once 'Zend/Date/Exception.php';
throw new Zend_Date_Exception("parameter $type must be set, null is not allowed");
}
*/
private function _month($calc, $month, $locale)
{
- if (is_null($month)) {
+ if ($month === null) {
require_once 'Zend/Date/Exception.php';
throw new Zend_Date_Exception('parameter $month must be set, null is not allowed');
}
$cnt = 0;
foreach ($monthlist as $key => $value) {
if (strtoupper($value) == strtoupper($month)) {
- $found = $key + 1;
+ $found = ($key % 12) + 1;
break;
}
++$cnt;
*/
private function _day($calc, $day, $locale)
{
- if (is_null($day)) {
+ if ($day === null) {
require_once 'Zend/Date/Exception.php';
throw new Zend_Date_Exception('parameter $day must be set, null is not allowed');
}
*/
private function _weekday($calc, $weekday, $locale)
{
- if (is_null($weekday)) {
+ if ($weekday === null) {
require_once 'Zend/Date/Exception.php';
throw new Zend_Date_Exception('parameter $weekday must be set, null is not allowed');
}
*/
public function subMilliSecond($milli = null, $precision = null)
{
- return $this->addMilliSecond(0 - $milli);
+ return $this->addMilliSecond(0 - $milli, $precision);
}
/**
*/
public function setLocale($locale = null)
{
- if (!Zend_Locale::isLocale($locale, true, false)) {
- if (!Zend_Locale::isLocale($locale, false, false)) {
- require_once 'Zend/Date/Exception.php';
- throw new Zend_Date_Exception("Given locale ({$locale}) does not exist", (string) $locale);
- }
-
- $locale = new Zend_Locale($locale);
+ try {
+ $this->_locale = Zend_Locale::findLocale($locale);
+ } catch (Zend_Locale_Exception $e) {
+ require_once 'Zend/Date/Exception.php';
+ throw new Zend_Date_Exception($e->getMessage());
}
- $this->_locale = (string) $locale;
return $this;
}
* If no format is given the standard dateformat for the actual locale is used.
* f.e. 30.February.2007 will return false if format is 'dd.MMMM.YYYY'
*
- * @param string $date Date to parse for correctness
- * @param string $format (Optional) Format for parsing the date string
- * @param string|Zend_Locale $locale (Optional) Locale for parsing date parts
- * @return boolean True when all date parts are correct
+ * @param string|array|Zend_Date $date Date to parse for correctness
+ * @param string $format (Optional) Format for parsing the date string
+ * @param string|Zend_Locale $locale (Optional) Locale for parsing date parts
+ * @return boolean True when all date parts are correct
*/
public static function isDate($date, $format = null, $locale = null)
{
- if (!is_string($date) and !is_numeric($date) and !($date instanceof Zend_Date)) {
+ if (!is_string($date) && !is_numeric($date) && !($date instanceof Zend_Date) &&
+ !is_array($date)) {
return false;
}
$format = null;
}
- if (empty($locale)) {
- require_once 'Zend/Registry.php';
- if (Zend_Registry::isRegistered('Zend_Locale') === true) {
- $locale = Zend_Registry::get('Zend_Locale');
- }
- }
-
- if (!Zend_Locale::isLocale($locale, true, false)) {
- if (!Zend_Locale::isLocale($locale, false, false)) {
- require_once 'Zend/Date/Exception.php';
- throw new Zend_Date_Exception("Given locale ({$locale}) does not exist", (string) $locale);
- }
-
- $locale = new Zend_Locale($locale);
- }
+ $locale = Zend_Locale::findLocale($locale);
- $locale = (string) $locale;
if ($format === null) {
$format = Zend_Locale_Format::getDateFormat($locale);
} else if (self::$_options['format_type'] == 'php') {
$format = Zend_Locale_Format::convertPhpToIsoFormat($format);
}
- try {
- $parsed = Zend_Locale_Format::getDate($date, array('locale' => $locale,
- 'date_format' => $format, 'format_type' => 'iso',
- 'fix_date' => false));
-
- if (isset($parsed['year']) and ((strpos(strtoupper($format), 'YY') !== false) and
- (strpos(strtoupper($format), 'YYYY') === false))) {
- $parsed['year'] = self::getFullYear($parsed['year']);
+ $format = self::_getLocalizedToken($format, $locale);
+ if (!is_array($date)) {
+ try {
+ $parsed = Zend_Locale_Format::getDate($date, array('locale' => $locale,
+ 'date_format' => $format, 'format_type' => 'iso',
+ 'fix_date' => false));
+ } catch (Zend_Locale_Exception $e) {
+ // Date can not be parsed
+ return false;
}
- } catch (Zend_Locale_Exception $e) {
- // Date can not be parsed
- return false;
+ } else {
+ $parsed = $date;
}
if (((strpos($format, 'Y') !== false) or (strpos($format, 'y') !== false)) and
(!isset($parsed['year']))) {
// Year expected but not found
- return false;
+ return false;
}
if ((strpos($format, 'M') !== false) and (!isset($parsed['month']))) {
if (((strpos($format, 'H') !== false) or (strpos($format, 'h') !== false)) and
(!isset($parsed['hour']))) {
// Hour expected but not found
- return false;
+ return false;
}
if ((strpos($format, 'm') !== false) and (!isset($parsed['minute']))) {
// Set not given dateparts
if (isset($parsed['hour']) === false) {
- $parsed['hour'] = 0;
+ $parsed['hour'] = 12;
}
if (isset($parsed['minute']) === false) {
$parsed['year'] = 1970;
}
+ if (self::isYearLeapYear($parsed['year'])) {
+ $parsed['year'] = 1972;
+ } else {
+ $parsed['year'] = 1971;
+ }
+
$date = new self($parsed, null, $locale);
$timestamp = $date->mktime($parsed['hour'], $parsed['minute'], $parsed['second'],
$parsed['month'], $parsed['day'], $parsed['year']);
+
if ($parsed['year'] != $date->date('Y', $timestamp)) {
// Given year differs from parsed year
return false;
return true;
}
+ /**
+ * Returns the ISO Token for all localized constants
+ *
+ * @param string $token Token to normalize
+ * @param string $locale Locale to search
+ * @return string
+ */
+ protected static function _getLocalizedToken($token, $locale)
+ {
+ switch($token) {
+ case self::ISO_8601 :
+ return "dd mm yy";
+ break;
+ case self::RFC_2822 :
+ return "EEE, dd MMM yyyy HH:mm:ss";
+ break;
+ case self::DATES :
+ return Zend_Locale_Data::getContent($locale, 'date');
+ break;
+ case self::DATE_FULL :
+ return Zend_Locale_Data::getContent($locale, 'date', array('gregorian', 'full'));
+ break;
+ case self::DATE_LONG :
+ return Zend_Locale_Data::getContent($locale, 'date', array('gregorian', 'long'));
+ break;
+ case self::DATE_MEDIUM :
+ return Zend_Locale_Data::getContent($locale, 'date', array('gregorian', 'medium'));
+ break;
+ case self::DATE_SHORT :
+ return Zend_Locale_Data::getContent($locale, 'date', array('gregorian', 'short'));
+ break;
+ case self::TIMES :
+ return Zend_Locale_Data::getContent($locale, 'date');
+ break;
+ case self::TIME_FULL :
+ return Zend_Locale_Data::getContent($locale, 'time', array('gregorian', 'full'));
+ break;
+ case self::TIME_LONG :
+ return Zend_Locale_Data::getContent($locale, 'date', array('gregorian', 'long'));
+ break;
+ case self::TIME_MEDIUM :
+ return Zend_Locale_Data::getContent($locale, 'date', array('gregorian', 'medium'));
+ break;
+ case self::TIME_SHORT :
+ return Zend_Locale_Data::getContent($locale, 'date', array('gregorian', 'short'));
+ break;
+ case self::DATETIME :
+ return Zend_Locale_Data::getContent($locale, 'datetime');
+ break;
+ case self::DATETIME_FULL :
+ return Zend_Locale_Data::getContent($locale, 'datetime', array('gregorian', 'full'));
+ break;
+ case self::DATETIME_LONG :
+ return Zend_Locale_Data::getContent($locale, 'datetime', array('gregorian', 'long'));
+ break;
+ case self::DATETIME_MEDIUM :
+ return Zend_Locale_Data::getContent($locale, 'datetime', array('gregorian', 'medium'));
+ break;
+ case self::DATETIME_SHORT :
+ return Zend_Locale_Data::getContent($locale, 'datetime', array('gregorian', 'short'));
+ break;
+ case self::ATOM :
+ case self::RFC_3339 :
+ case self::W3C :
+ return "yyyy-MM-DD HH:mm:ss";
+ break;
+ case self::COOKIE :
+ case self::RFC_850 :
+ return "EEEE, dd-MM-yyyy HH:mm:ss";
+ break;
+ case self::RFC_822 :
+ case self::RFC_1036 :
+ case self::RFC_1123 :
+ case self::RSS :
+ return "EEE, dd MM yyyy HH:mm:ss";
+ break;
+ }
+
+ return $token;
+ }
}
--- /dev/null
+<?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_Db
+ * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ * @version $Id$
+ */
+
+
+/**
+ * Class for connecting to SQL databases and performing common operations.
+ *
+ * @category Zend
+ * @package Zend_Db
+ * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+class Zend_Db
+{
+
+ /**
+ * Use the PROFILER constant in the config of a Zend_Db_Adapter.
+ */
+ const PROFILER = 'profiler';
+
+ /**
+ * Use the CASE_FOLDING constant in the config of a Zend_Db_Adapter.
+ */
+ const CASE_FOLDING = 'caseFolding';
+
+ /**
+ * Use the AUTO_QUOTE_IDENTIFIERS constant in the config of a Zend_Db_Adapter.
+ */
+ const AUTO_QUOTE_IDENTIFIERS = 'autoQuoteIdentifiers';
+
+ /**
+ * Use the ALLOW_SERIALIZATION constant in the config of a Zend_Db_Adapter.
+ */
+ const ALLOW_SERIALIZATION = 'allowSerialization';
+
+ /**
+ * Use the AUTO_RECONNECT_ON_UNSERIALIZE constant in the config of a Zend_Db_Adapter.
+ */
+ const AUTO_RECONNECT_ON_UNSERIALIZE = 'autoReconnectOnUnserialize';
+
+ /**
+ * Use the INT_TYPE, BIGINT_TYPE, and FLOAT_TYPE with the quote() method.
+ */
+ const INT_TYPE = 0;
+ const BIGINT_TYPE = 1;
+ const FLOAT_TYPE = 2;
+
+ /**
+ * PDO constant values discovered by this script result:
+ *
+ * $list = array(
+ * 'PARAM_BOOL', 'PARAM_NULL', 'PARAM_INT', 'PARAM_STR', 'PARAM_LOB',
+ * 'PARAM_STMT', 'PARAM_INPUT_OUTPUT', 'FETCH_LAZY', 'FETCH_ASSOC',
+ * 'FETCH_NUM', 'FETCH_BOTH', 'FETCH_OBJ', 'FETCH_BOUND',
+ * 'FETCH_COLUMN', 'FETCH_CLASS', 'FETCH_INTO', 'FETCH_FUNC',
+ * 'FETCH_GROUP', 'FETCH_UNIQUE', 'FETCH_CLASSTYPE', 'FETCH_SERIALIZE',
+ * 'FETCH_NAMED', 'ATTR_AUTOCOMMIT', 'ATTR_PREFETCH', 'ATTR_TIMEOUT',
+ * 'ATTR_ERRMODE', 'ATTR_SERVER_VERSION', 'ATTR_CLIENT_VERSION',
+ * 'ATTR_SERVER_INFO', 'ATTR_CONNECTION_STATUS', 'ATTR_CASE',
+ * 'ATTR_CURSOR_NAME', 'ATTR_CURSOR', 'ATTR_ORACLE_NULLS',
+ * 'ATTR_PERSISTENT', 'ATTR_STATEMENT_CLASS', 'ATTR_FETCH_TABLE_NAMES',
+ * 'ATTR_FETCH_CATALOG_NAMES', 'ATTR_DRIVER_NAME',
+ * 'ATTR_STRINGIFY_FETCHES', 'ATTR_MAX_COLUMN_LEN', 'ERRMODE_SILENT',
+ * 'ERRMODE_WARNING', 'ERRMODE_EXCEPTION', 'CASE_NATURAL',
+ * 'CASE_LOWER', 'CASE_UPPER', 'NULL_NATURAL', 'NULL_EMPTY_STRING',
+ * 'NULL_TO_STRING', 'ERR_NONE', 'FETCH_ORI_NEXT',
+ * 'FETCH_ORI_PRIOR', 'FETCH_ORI_FIRST', 'FETCH_ORI_LAST',
+ * 'FETCH_ORI_ABS', 'FETCH_ORI_REL', 'CURSOR_FWDONLY', 'CURSOR_SCROLL',
+ * 'ERR_CANT_MAP', 'ERR_SYNTAX', 'ERR_CONSTRAINT', 'ERR_NOT_FOUND',
+ * 'ERR_ALREADY_EXISTS', 'ERR_NOT_IMPLEMENTED', 'ERR_MISMATCH',
+ * 'ERR_TRUNCATED', 'ERR_DISCONNECTED', 'ERR_NO_PERM',
+ * );
+ *
+ * $const = array();
+ * foreach ($list as $name) {
+ * $const[$name] = constant("PDO::$name");
+ * }
+ * var_export($const);
+ */
+ const ATTR_AUTOCOMMIT = 0;
+ const ATTR_CASE = 8;
+ const ATTR_CLIENT_VERSION = 5;
+ const ATTR_CONNECTION_STATUS = 7;
+ const ATTR_CURSOR = 10;
+ const ATTR_CURSOR_NAME = 9;
+ const ATTR_DRIVER_NAME = 16;
+ const ATTR_ERRMODE = 3;
+ const ATTR_FETCH_CATALOG_NAMES = 15;
+ const ATTR_FETCH_TABLE_NAMES = 14;
+ const ATTR_MAX_COLUMN_LEN = 18;
+ const ATTR_ORACLE_NULLS = 11;
+ const ATTR_PERSISTENT = 12;
+ const ATTR_PREFETCH = 1;
+ const ATTR_SERVER_INFO = 6;
+ const ATTR_SERVER_VERSION = 4;
+ const ATTR_STATEMENT_CLASS = 13;
+ const ATTR_STRINGIFY_FETCHES = 17;
+ const ATTR_TIMEOUT = 2;
+ const CASE_LOWER = 2;
+ const CASE_NATURAL = 0;
+ const CASE_UPPER = 1;
+ const CURSOR_FWDONLY = 0;
+ const CURSOR_SCROLL = 1;
+ const ERR_ALREADY_EXISTS = NULL;
+ const ERR_CANT_MAP = NULL;
+ const ERR_CONSTRAINT = NULL;
+ const ERR_DISCONNECTED = NULL;
+ const ERR_MISMATCH = NULL;
+ const ERR_NO_PERM = NULL;
+ const ERR_NONE = '00000';
+ const ERR_NOT_FOUND = NULL;
+ const ERR_NOT_IMPLEMENTED = NULL;
+ const ERR_SYNTAX = NULL;
+ const ERR_TRUNCATED = NULL;
+ const ERRMODE_EXCEPTION = 2;
+ const ERRMODE_SILENT = 0;
+ const ERRMODE_WARNING = 1;
+ const FETCH_ASSOC = 2;
+ const FETCH_BOTH = 4;
+ const FETCH_BOUND = 6;
+ const FETCH_CLASS = 8;
+ const FETCH_CLASSTYPE = 262144;
+ const FETCH_COLUMN = 7;
+ const FETCH_FUNC = 10;
+ const FETCH_GROUP = 65536;
+ const FETCH_INTO = 9;
+ const FETCH_LAZY = 1;
+ const FETCH_NAMED = 11;
+ const FETCH_NUM = 3;
+ const FETCH_OBJ = 5;
+ const FETCH_ORI_ABS = 4;
+ const FETCH_ORI_FIRST = 2;
+ const FETCH_ORI_LAST = 3;
+ const FETCH_ORI_NEXT = 0;
+ const FETCH_ORI_PRIOR = 1;
+ const FETCH_ORI_REL = 5;
+ const FETCH_SERIALIZE = 524288;
+ const FETCH_UNIQUE = 196608;
+ const NULL_EMPTY_STRING = 1;
+ const NULL_NATURAL = 0;
+ const NULL_TO_STRING = NULL;
+ const PARAM_BOOL = 5;
+ const PARAM_INPUT_OUTPUT = -2147483648;
+ const PARAM_INT = 1;
+ const PARAM_LOB = 3;
+ const PARAM_NULL = 0;
+ const PARAM_STMT = 4;
+ const PARAM_STR = 2;
+
+ /**
+ * Factory for Zend_Db_Adapter_Abstract classes.
+ *
+ * First argument may be a string containing the base of the adapter class
+ * name, e.g. 'Mysqli' corresponds to class Zend_Db_Adapter_Mysqli. This
+ * name is currently case-insensitive, but is not ideal to rely on this behavior.
+ * If your class is named 'My_Company_Pdo_Mysql', where 'My_Company' is the namespace
+ * and 'Pdo_Mysql' is the adapter name, it is best to use the name exactly as it
+ * is defined in the class. This will ensure proper use of the factory API.
+ *
+ * First argument may alternatively be an object of type Zend_Config.
+ * The adapter class base name is read from the 'adapter' property.
+ * The adapter config parameters are read from the 'params' property.
+ *
+ * Second argument is optional and may be an associative array of key-value
+ * pairs. This is used as the argument to the adapter constructor.
+ *
+ * If the first argument is of type Zend_Config, it is assumed to contain
+ * all parameters, and the second argument is ignored.
+ *
+ * @param mixed $adapter String name of base adapter class, or Zend_Config object.
+ * @param mixed $config OPTIONAL; an array or Zend_Config object with adapter parameters.
+ * @return Zend_Db_Adapter_Abstract
+ * @throws Zend_Db_Exception
+ */
+ public static function factory($adapter, $config = array())
+ {
+ if ($config instanceof Zend_Config) {
+ $config = $config->toArray();
+ }
+
+ /*
+ * Convert Zend_Config argument to plain string
+ * adapter name and separate config object.
+ */
+ if ($adapter instanceof Zend_Config) {
+ if (isset($adapter->params)) {
+ $config = $adapter->params->toArray();
+ }
+ if (isset($adapter->adapter)) {
+ $adapter = (string) $adapter->adapter;
+ } else {
+ $adapter = null;
+ }
+ }
+
+ /*
+ * Verify that adapter parameters are in an array.
+ */
+ if (!is_array($config)) {
+ /**
+ * @see Zend_Db_Exception
+ */
+ require_once 'Zend/Db/Exception.php';
+ throw new Zend_Db_Exception('Adapter parameters must be in an array or a Zend_Config object');
+ }
+
+ /*
+ * Verify that an adapter name has been specified.
+ */
+ if (!is_string($adapter) || empty($adapter)) {
+ /**
+ * @see Zend_Db_Exception
+ */
+ require_once 'Zend/Db/Exception.php';
+ throw new Zend_Db_Exception('Adapter name must be specified in a string');
+ }
+
+ /*
+ * Form full adapter class name
+ */
+ $adapterNamespace = 'Zend_Db_Adapter';
+ if (isset($config['adapterNamespace'])) {
+ if ($config['adapterNamespace'] != '') {
+ $adapterNamespace = $config['adapterNamespace'];
+ }
+ unset($config['adapterNamespace']);
+ }
+
+ // Adapter no longer normalized- see http://framework.zend.com/issues/browse/ZF-5606
+ $adapterName = $adapterNamespace . '_';
+ $adapterName .= str_replace(' ', '_', ucwords(str_replace('_', ' ', strtolower($adapter))));
+
+ /*
+ * Load the adapter class. This throws an exception
+ * if the specified class cannot be loaded.
+ */
+ if (!class_exists($adapterName)) {
+ require_once 'Zend/Loader.php';
+ Zend_Loader::loadClass($adapterName);
+ }
+
+ /*
+ * Create an instance of the adapter class.
+ * Pass the config to the adapter class constructor.
+ */
+ $dbAdapter = new $adapterName($config);
+
+ /*
+ * Verify that the object created is a descendent of the abstract adapter type.
+ */
+ if (! $dbAdapter instanceof Zend_Db_Adapter_Abstract) {
+ /**
+ * @see Zend_Db_Exception
+ */
+ require_once 'Zend/Db/Exception.php';
+ throw new Zend_Db_Exception("Adapter class '$adapterName' does not extend Zend_Db_Adapter_Abstract");
+ }
+
+ return $dbAdapter;
+ }
+
+}
--- /dev/null
+<?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_Debug
+ * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ * @version $Id$
+ */
+
+/**
+ * Concrete class for generating debug dumps related to the output source.
+ *
+ * @category Zend
+ * @package Zend_Debug
+ * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+class Zend_Debug
+{
+
+ /**
+ * @var string
+ */
+ protected static $_sapi = null;
+
+ /**
+ * Get the current value of the debug output environment.
+ * This defaults to the value of PHP_SAPI.
+ *
+ * @return string;
+ */
+ public static function getSapi()
+ {
+ if (self::$_sapi === null) {
+ self::$_sapi = PHP_SAPI;
+ }
+ return self::$_sapi;
+ }
+
+ /**
+ * Set the debug ouput environment.
+ * Setting a value of null causes Zend_Debug to use PHP_SAPI.
+ *
+ * @param string $sapi
+ * @return void;
+ */
+ public static function setSapi($sapi)
+ {
+ self::$_sapi = $sapi;
+ }
+
+ /**
+ * Debug helper function. This is a wrapper for var_dump() that adds
+ * the <pre /> tags, cleans up newlines and indents, and runs
+ * htmlentities() before output.
+ *
+ * @param mixed $var The variable to dump.
+ * @param string $label OPTIONAL Label to prepend to output.
+ * @param bool $echo OPTIONAL Echo output if true.
+ * @return string
+ */
+ public static function dump($var, $label=null, $echo=true)
+ {
+ // format the label
+ $label = ($label===null) ? '' : rtrim($label) . ' ';
+
+ // var_dump the variable into a buffer and keep the output
+ ob_start();
+ var_dump($var);
+ $output = ob_get_clean();
+
+ // neaten the newlines and indents
+ $output = preg_replace("/\]\=\>\n(\s+)/m", "] => ", $output);
+ if (self::getSapi() == 'cli') {
+ $output = PHP_EOL . $label
+ . PHP_EOL . $output
+ . PHP_EOL;
+ } else {
+ if(!extension_loaded('xdebug')) {
+ $output = htmlspecialchars($output, ENT_QUOTES);
+ }
+
+ $output = '<pre>'
+ . $label
+ . $output
+ . '</pre>';
+ }
+
+ if ($echo) {
+ echo($output);
+ }
+ return $output;
+ }
+
+}
--- /dev/null
+<?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_Dojo
+ * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+/**
+ * Enable Dojo components
+ *
+ * @package Zend_Dojo
+ * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ * @version $Id$
+ */
+class Zend_Dojo
+{
+ /**
+ * @const string Base path to AOL CDN
+ */
+ const CDN_BASE_AOL = 'http://o.aolcdn.com/dojo/';
+
+ /**
+ * @const string Path to dojo on AOL CDN (following version string)
+ */
+ const CDN_DOJO_PATH_AOL = '/dojo/dojo.xd.js';
+
+ /**
+ * @const string Base path to Google CDN
+ */
+ const CDN_BASE_GOOGLE = 'http://ajax.googleapis.com/ajax/libs/dojo/';
+
+ /**
+ * @const string Path to dojo on Google CDN (following version string)
+ */
+ const CDN_DOJO_PATH_GOOGLE = '/dojo/dojo.xd.js';
+
+ /**
+ * Dojo-enable a form instance
+ *
+ * @param Zend_Form $form
+ * @return void
+ */
+ public static function enableForm(Zend_Form $form)
+ {
+ $form->addPrefixPath('Zend_Dojo_Form_Decorator', 'Zend/Dojo/Form/Decorator', 'decorator')
+ ->addPrefixPath('Zend_Dojo_Form_Element', 'Zend/Dojo/Form/Element', 'element')
+ ->addElementPrefixPath('Zend_Dojo_Form_Decorator', 'Zend/Dojo/Form/Decorator', 'decorator')
+ ->addDisplayGroupPrefixPath('Zend_Dojo_Form_Decorator', 'Zend/Dojo/Form/Decorator')
+ ->setDefaultDisplayGroupClass('Zend_Dojo_Form_DisplayGroup');
+
+ foreach ($form->getSubForms() as $subForm) {
+ self::enableForm($subForm);
+ }
+
+ if (null !== ($view = $form->getView())) {
+ self::enableView($view);
+ }
+ }
+
+ /**
+ * Dojo-enable a view instance
+ *
+ * @param Zend_View_Interface $view
+ * @return void
+ */
+ public static function enableView(Zend_View_Interface $view)
+ {
+ if (false === $view->getPluginLoader('helper')->getPaths('Zend_Dojo_View_Helper')) {
+ $view->addHelperPath('Zend/Dojo/View/Helper', 'Zend_Dojo_View_Helper');
+ }
+ }
+}
+
*
* @category Zend
* @package Zend
- * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
+ * @version $Id$
*/
/**
* @category Zend
* @package Zend
- * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Exception extends Exception
--- /dev/null
+<?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_Feed
+ * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ * @version $Id$
+ */
+
+
+/**
+ * Feed utility class
+ *
+ * Base Zend_Feed class, containing constants and the Zend_Http_Client instance
+ * accessor.
+ *
+ * @category Zend
+ * @package Zend_Feed
+ * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+class Zend_Feed
+{
+
+ /**
+ * HTTP client object to use for retrieving feeds
+ *
+ * @var Zend_Http_Client
+ */
+ protected static $_httpClient = null;
+
+ /**
+ * Override HTTP PUT and DELETE request methods?
+ *
+ * @var boolean
+ */
+ protected static $_httpMethodOverride = false;
+
+ /**
+ * @var array
+ */
+ protected static $_namespaces = array(
+ 'opensearch' => 'http://a9.com/-/spec/opensearchrss/1.0/',
+ 'atom' => 'http://www.w3.org/2005/Atom',
+ 'rss' => 'http://blogs.law.harvard.edu/tech/rss',
+ );
+
+
+ /**
+ * Set the HTTP client instance
+ *
+ * Sets the HTTP client object to use for retrieving the feeds.
+ *
+ * @param Zend_Http_Client $httpClient
+ * @return void
+ */
+ public static function setHttpClient(Zend_Http_Client $httpClient)
+ {
+ self::$_httpClient = $httpClient;
+ }
+
+
+ /**
+ * Gets the HTTP client object. If none is set, a new Zend_Http_Client will be used.
+ *
+ * @return Zend_Http_Client_Abstract
+ */
+ public static function getHttpClient()
+ {
+ if (!self::$_httpClient instanceof Zend_Http_Client) {
+ /**
+ * @see Zend_Http_Client
+ */
+ require_once 'Zend/Http/Client.php';
+ self::$_httpClient = new Zend_Http_Client();
+ }
+
+ return self::$_httpClient;
+ }
+
+
+ /**
+ * Toggle using POST instead of PUT and DELETE HTTP methods
+ *
+ * Some feed implementations do not accept PUT and DELETE HTTP
+ * methods, or they can't be used because of proxies or other
+ * measures. This allows turning on using POST where PUT and
+ * DELETE would normally be used; in addition, an
+ * X-Method-Override header will be sent with a value of PUT or
+ * DELETE as appropriate.
+ *
+ * @param boolean $override Whether to override PUT and DELETE.
+ * @return void
+ */
+ public static function setHttpMethodOverride($override = true)
+ {
+ self::$_httpMethodOverride = $override;
+ }
+
+
+ /**
+ * Get the HTTP override state
+ *
+ * @return boolean
+ */
+ public static function getHttpMethodOverride()
+ {
+ return self::$_httpMethodOverride;
+ }
+
+
+ /**
+ * Get the full version of a namespace prefix
+ *
+ * Looks up a prefix (atom:, etc.) in the list of registered
+ * namespaces and returns the full namespace URI if
+ * available. Returns the prefix, unmodified, if it's not
+ * registered.
+ *
+ * @return string
+ */
+ public static function lookupNamespace($prefix)
+ {
+ return isset(self::$_namespaces[$prefix]) ?
+ self::$_namespaces[$prefix] :
+ $prefix;
+ }
+
+
+ /**
+ * Add a namespace and prefix to the registered list
+ *
+ * Takes a prefix and a full namespace URI and adds them to the
+ * list of registered namespaces for use by
+ * Zend_Feed::lookupNamespace().
+ *
+ * @param string $prefix The namespace prefix
+ * @param string $namespaceURI The full namespace URI
+ * @return void
+ */
+ public static function registerNamespace($prefix, $namespaceURI)
+ {
+ self::$_namespaces[$prefix] = $namespaceURI;
+ }
+
+
+ /**
+ * Imports a feed located at $uri.
+ *
+ * @param string $uri
+ * @throws Zend_Feed_Exception
+ * @return Zend_Feed_Abstract
+ */
+ public static function import($uri)
+ {
+ $client = self::getHttpClient();
+ $client->setUri($uri);
+ $response = $client->request('GET');
+ if ($response->getStatus() !== 200) {
+ /**
+ * @see Zend_Feed_Exception
+ */
+ require_once 'Zend/Feed/Exception.php';
+ throw new Zend_Feed_Exception('Feed failed to load, got response code ' . $response->getStatus());
+ }
+ $feed = $response->getBody();
+ return self::importString($feed);
+ }
+
+
+ /**
+ * Imports a feed represented by $string.
+ *
+ * @param string $string
+ * @throws Zend_Feed_Exception
+ * @return Zend_Feed_Abstract
+ */
+ public static function importString($string)
+ {
+ // Load the feed as an XML DOMDocument object
+ $libxml_errflag = libxml_use_internal_errors(true);
+ $doc = new DOMDocument;
+ if (trim($string) == '') {
+ require_once 'Zend/Feed/Exception.php';
+ throw new Zend_Feed_Exception('Document/string being imported'
+ . ' is an Empty string or comes from an empty HTTP response');
+ }
+ $status = $doc->loadXML($string);
+ libxml_use_internal_errors($libxml_errflag);
+
+
+ if (!$status) {
+ // prevent the class to generate an undefined variable notice (ZF-2590)
+ // Build error message
+ $error = libxml_get_last_error();
+ if ($error && $error->message) {
+ $errormsg = "DOMDocument cannot parse XML: {$error->message}";
+ } else {
+ $errormsg = "DOMDocument cannot parse XML";
+ }
+
+
+ /**
+ * @see Zend_Feed_Exception
+ */
+ require_once 'Zend/Feed/Exception.php';
+ throw new Zend_Feed_Exception($errormsg);
+ }
+
+ // Try to find the base feed element or a single <entry> of an Atom feed
+ if ($doc->getElementsByTagName('feed')->item(0) ||
+ $doc->getElementsByTagName('entry')->item(0)) {
+ /**
+ * @see Zend_Feed_Atom
+ */
+ require_once 'Zend/Feed/Atom.php';
+ // return a newly created Zend_Feed_Atom object
+ return new Zend_Feed_Atom(null, $string);
+ }
+
+ // Try to find the base feed element of an RSS feed
+ if ($doc->getElementsByTagName('channel')->item(0)) {
+ /**
+ * @see Zend_Feed_Rss
+ */
+ require_once 'Zend/Feed/Rss.php';
+ // return a newly created Zend_Feed_Rss object
+ return new Zend_Feed_Rss(null, $string);
+ }
+
+ // $string does not appear to be a valid feed of the supported types
+ /**
+ * @see Zend_Feed_Exception
+ */
+ require_once 'Zend/Feed/Exception.php';
+ throw new Zend_Feed_Exception('Invalid or unsupported feed format');
+ }
+
+
+ /**
+ * Imports a feed from a file located at $filename.
+ *
+ * @param string $filename
+ * @throws Zend_Feed_Exception
+ * @return Zend_Feed_Abstract
+ */
+ public static function importFile($filename)
+ {
+ @ini_set('track_errors', 1);
+ $feed = @file_get_contents($filename);
+ @ini_restore('track_errors');
+ if ($feed === false) {
+ /**
+ * @see Zend_Feed_Exception
+ */
+ require_once 'Zend/Feed/Exception.php';
+ throw new Zend_Feed_Exception("File could not be loaded: $php_errormsg");
+ }
+ return self::importString($feed);
+ }
+
+
+ /**
+ * Attempts to find feeds at $uri referenced by <link ... /> tags. Returns an
+ * array of the feeds referenced at $uri.
+ *
+ * @todo Allow findFeeds() to follow one, but only one, code 302.
+ *
+ * @param string $uri
+ * @throws Zend_Feed_Exception
+ * @return array
+ */
+ public static function findFeeds($uri)
+ {
+ // Get the HTTP response from $uri and save the contents
+ $client = self::getHttpClient();
+ $client->setUri($uri);
+ $response = $client->request();
+ if ($response->getStatus() !== 200) {
+ /**
+ * @see Zend_Feed_Exception
+ */
+ require_once 'Zend/Feed/Exception.php';
+ throw new Zend_Feed_Exception("Failed to access $uri, got response code " . $response->getStatus());
+ }
+ $contents = $response->getBody();
+
+ // Parse the contents for appropriate <link ... /> tags
+ @ini_set('track_errors', 1);
+ $pattern = '~(<link[^>]+)/?>~i';
+ $result = @preg_match_all($pattern, $contents, $matches);
+ @ini_restore('track_errors');
+ if ($result === false) {
+ /**
+ * @see Zend_Feed_Exception
+ */
+ require_once 'Zend/Feed/Exception.php';
+ throw new Zend_Feed_Exception("Internal error: $php_errormsg");
+ }
+
+ // Try to fetch a feed for each link tag that appears to refer to a feed
+ $feeds = array();
+ if (isset($matches[1]) && count($matches[1]) > 0) {
+ foreach ($matches[1] as $link) {
+ // force string to be an utf-8 one
+ if (!mb_check_encoding($link, 'UTF-8')) {
+ $link = mb_convert_encoding($link, 'UTF-8');
+ }
+ $xml = @simplexml_load_string(rtrim($link, ' /') . ' />');
+ if ($xml === false) {
+ continue;
+ }
+ $attributes = $xml->attributes();
+ if (!isset($attributes['rel']) || !@preg_match('~^(?:alternate|service\.feed)~i', $attributes['rel'])) {
+ continue;
+ }
+ if (!isset($attributes['type']) ||
+ !@preg_match('~^application/(?:atom|rss|rdf)\+xml~', $attributes['type'])) {
+ continue;
+ }
+ if (!isset($attributes['href'])) {
+ continue;
+ }
+ try {
+ // checks if we need to canonize the given uri
+ try {
+ $uri = Zend_Uri::factory((string) $attributes['href']);
+ } catch (Zend_Uri_Exception $e) {
+ // canonize the uri
+ $path = (string) $attributes['href'];
+ $query = $fragment = '';
+ if (substr($path, 0, 1) != '/') {
+ // add the current root path to this one
+ $path = rtrim($client->getUri()->getPath(), '/') . '/' . $path;
+ }
+ if (strpos($path, '?') !== false) {
+ list($path, $query) = explode('?', $path, 2);
+ }
+ if (strpos($query, '#') !== false) {
+ list($query, $fragment) = explode('#', $query, 2);
+ }
+ $uri = Zend_Uri::factory($client->getUri(true));
+ $uri->setPath($path);
+ $uri->setQuery($query);
+ $uri->setFragment($fragment);
+ }
+
+ $feed = self::import($uri);
+ } catch (Exception $e) {
+ continue;
+ }
+ $feeds[$uri->getUri()] = $feed;
+ }
+ }
+
+ // Return the fetched feeds
+ return $feeds;
+ }
+
+ /**
+ * Construct a new Zend_Feed_Abstract object from a custom array
+ *
+ * @param array $data
+ * @param string $format (rss|atom) the requested output format
+ * @return Zend_Feed_Abstract
+ */
+ public static function importArray(array $data, $format = 'atom')
+ {
+ $obj = 'Zend_Feed_' . ucfirst(strtolower($format));
+ if (!class_exists($obj)) {
+ require_once 'Zend/Loader.php';
+ Zend_Loader::loadClass($obj);
+ }
+
+ /**
+ * @see Zend_Feed_Builder
+ */
+ require_once 'Zend/Feed/Builder.php';
+ return new $obj(null, null, new Zend_Feed_Builder($data));
+ }
+
+ /**
+ * Construct a new Zend_Feed_Abstract object from a Zend_Feed_Builder_Interface data source
+ *
+ * @param Zend_Feed_Builder_Interface $builder this object will be used to extract the data of the feed
+ * @param string $format (rss|atom) the requested output format
+ * @return Zend_Feed_Abstract
+ */
+ public static function importBuilder(Zend_Feed_Builder_Interface $builder, $format = 'atom')
+ {
+ $obj = 'Zend_Feed_' . ucfirst(strtolower($format));
+ if (!class_exists($obj)) {
+ require_once 'Zend/Loader.php';
+ Zend_Loader::loadClass($obj);
+ }
+ return new $obj(null, null, $builder);
+ }
+}
--- /dev/null
+<?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_Filter
+ * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ * @version $Id$
+ */
+
+/**
+ * @see Zend_Filter_Interface
+ */
+require_once 'Zend/Filter/Interface.php';
+
+/**
+ * @category Zend
+ * @package Zend_Filter
+ * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+class Zend_Filter implements Zend_Filter_Interface
+{
+ /**
+ * Filter chain
+ *
+ * @var array
+ */
+ protected $_filters = array();
+
+ /**
+ * Default Namespaces
+ *
+ * @var array
+ */
+ protected static $_defaultNamespaces = array();
+
+ /**
+ * Adds a filter to the end of the chain
+ *
+ * @param Zend_Filter_Interface $filter
+ * @return Zend_Filter Provides a fluent interface
+ */
+ public function addFilter(Zend_Filter_Interface $filter)
+ {
+ $this->_filters[] = $filter;
+ return $this;
+ }
+
+ /**
+ * Returns $value filtered through each filter in the chain
+ *
+ * Filters are run in the order in which they were added to the chain (FIFO)
+ *
+ * @param mixed $value
+ * @return mixed
+ */
+ public function filter($value)
+ {
+ $valueFiltered = $value;
+ foreach ($this->_filters as $filter) {
+ $valueFiltered = $filter->filter($valueFiltered);
+ }
+ return $valueFiltered;
+ }
+
+ /**
+ * Returns the set default namespaces
+ *
+ * @return array
+ */
+ public static function getDefaultNamespaces()
+ {
+ return self::$_defaultNamespaces;
+ }
+
+ /**
+ * Sets new default namespaces
+ *
+ * @param array|string $namespace
+ * @return null
+ */
+ public static function setDefaultNamespaces($namespace)
+ {
+ if (!is_array($namespace)) {
+ $namespace = array((string) $namespace);
+ }
+
+ self::$_defaultNamespaces = $namespace;
+ }
+
+ /**
+ * Adds a new default namespace
+ *
+ * @param array|string $namespace
+ * @return null
+ */
+ public static function addDefaultNamespaces($namespace)
+ {
+ if (!is_array($namespace)) {
+ $namespace = array((string) $namespace);
+ }
+
+ self::$_defaultNamespaces = array_unique(array_merge(self::$_defaultNamespaces, $namespace));
+ }
+
+ /**
+ * Returns true when defaultNamespaces are set
+ *
+ * @return boolean
+ */
+ public static function hasDefaultNamespaces()
+ {
+ return (!empty(self::$_defaultNamespaces));
+ }
+
+ /**
+ * @deprecated
+ * @see Zend_Filter::filterStatic()
+ *
+ * @param mixed $value
+ * @param string $classBaseName
+ * @param array $args OPTIONAL
+ * @param array|string $namespaces OPTIONAL
+ * @return mixed
+ * @throws Zend_Filter_Exception
+ */
+ public static function get($value, $classBaseName, array $args = array(), $namespaces = array())
+ {
+ trigger_error(
+ 'Zend_Filter::get() is deprecated as of 1.9.0; please update your code to utilize Zend_Filter::filterStatic()',
+ E_USER_NOTICE
+ );
+
+ return self::filterStatic($value, $classBaseName, $args, $namespaces);
+ }
+
+ /**
+ * Returns a value filtered through a specified filter class, without requiring separate
+ * instantiation of the filter object.
+ *
+ * The first argument of this method is a data input value, that you would have filtered.
+ * The second argument is a string, which corresponds to the basename of the filter class,
+ * relative to the Zend_Filter namespace. This method automatically loads the class,
+ * creates an instance, and applies the filter() method to the data input. You can also pass
+ * an array of constructor arguments, if they are needed for the filter class.
+ *
+ * @param mixed $value
+ * @param string $classBaseName
+ * @param array $args OPTIONAL
+ * @param array|string $namespaces OPTIONAL
+ * @return mixed
+ * @throws Zend_Filter_Exception
+ */
+ public static function filterStatic($value, $classBaseName, array $args = array(), $namespaces = array())
+ {
+ require_once 'Zend/Loader.php';
+ $namespaces = array_merge((array) $namespaces, self::$_defaultNamespaces, array('Zend_Filter'));
+ foreach ($namespaces as $namespace) {
+ $className = $namespace . '_' . ucfirst($classBaseName);
+ if (!class_exists($className)) {
+ try {
+ Zend_Loader::loadClass($className);
+ } catch (Zend_Exception $ze) {
+ continue;
+ }
+ }
+ $class = new ReflectionClass($className);
+ if ($class->implementsInterface('Zend_Filter_Interface')) {
+ if ($class->hasMethod('__construct')) {
+ $object = $class->newInstanceArgs($args);
+ } else {
+ $object = $class->newInstance();
+ }
+ return $object->filter($value);
+ }
+ }
+ require_once 'Zend/Filter/Exception.php';
+ throw new Zend_Filter_Exception("Filter class not found from basename '$classBaseName'");
+ }
+}
--- /dev/null
+<?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_Form
+ * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+/** @see Zend_Validate_Interface */
+require_once 'Zend/Validate/Interface.php';
+
+/**
+ * Zend_Form
+ *
+ * @category Zend
+ * @package Zend_Form
+ * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ * @version $Id$
+ */
+class Zend_Form implements Iterator, Countable, Zend_Validate_Interface
+{
+ /**#@+
+ * Plugin loader type constants
+ */
+ const DECORATOR = 'DECORATOR';
+ const ELEMENT = 'ELEMENT';
+ /**#@-*/
+
+ /**#@+
+ * Method type constants
+ */
+ const METHOD_DELETE = 'delete';
+ const METHOD_GET = 'get';
+ const METHOD_POST = 'post';
+ const METHOD_PUT = 'put';
+ /**#@-*/
+
+ /**#@+
+ * Encoding type constants
+ */
+ const ENCTYPE_URLENCODED = 'application/x-www-form-urlencoded';
+ const ENCTYPE_MULTIPART = 'multipart/form-data';
+ /**#@-*/
+
+ /**
+ * Form metadata and attributes
+ * @var array
+ */
+ protected $_attribs = array();
+
+ /**
+ * Decorators for rendering
+ * @var array
+ */
+ protected $_decorators = array();
+
+ /**
+ * Default display group class
+ * @var string
+ */
+ protected $_defaultDisplayGroupClass = 'Zend_Form_DisplayGroup';
+
+ /**
+ * Form description
+ * @var string
+ */
+ protected $_description;
+
+ /**
+ * Should we disable loading the default decorators?
+ * @var bool
+ */
+ protected $_disableLoadDefaultDecorators = false;
+
+ /**
+ * Display group prefix paths
+ * @var array
+ */
+ protected $_displayGroupPrefixPaths = array();
+
+ /**
+ * Groups of elements grouped for display purposes
+ * @var array
+ */
+ protected $_displayGroups = array();
+
+ /**
+ * Global decorators to apply to all elements
+ * @var null|array
+ */
+ protected $_elementDecorators;
+
+ /**
+ * Prefix paths to use when creating elements
+ * @var array
+ */
+ protected $_elementPrefixPaths = array();
+
+ /**
+ * Form elements
+ * @var array
+ */
+ protected $_elements = array();
+
+ /**
+ * Array to which elements belong (if any)
+ * @var string
+ */
+ protected $_elementsBelongTo;
+
+ /**
+ * Custom form-level error messages
+ * @var array
+ */
+ protected $_errorMessages = array();
+
+ /**
+ * Are there errors in the form?
+ * @var bool
+ */
+ protected $_errorsExist = false;
+
+ /**
+ * Has the form been manually flagged as an error?
+ * @var bool
+ */
+ protected $_errorsForced = false;
+
+ /**
+ * Form order
+ * @var int|null
+ */
+ protected $_formOrder;
+
+ /**
+ * Whether or not form elements are members of an array
+ * @var bool
+ */
+ protected $_isArray = false;
+
+ /**
+ * Form legend
+ * @var string
+ */
+ protected $_legend;
+
+ /**
+ * Plugin loaders
+ * @var array
+ */
+ protected $_loaders = array();
+
+ /**
+ * Allowed form methods
+ * @var array
+ */
+ protected $_methods = array('delete', 'get', 'post', 'put');
+
+ /**
+ * Order in which to display and iterate elements
+ * @var array
+ */
+ protected $_order = array();
+
+ /**
+ * Whether internal order has been updated or not
+ * @var bool
+ */
+ protected $_orderUpdated = false;
+
+ /**
+ * Sub form prefix paths
+ * @var array
+ */
+ protected $_subFormPrefixPaths = array();
+
+ /**
+ * Sub forms
+ * @var array
+ */
+ protected $_subForms = array();
+
+ /**
+ * @var Zend_Translate
+ */
+ protected $_translator;
+
+ /**
+ * Global default translation adapter
+ * @var Zend_Translate
+ */
+ protected static $_translatorDefault;
+
+ /**
+ * is the translator disabled?
+ * @var bool
+ */
+ protected $_translatorDisabled = false;
+
+ /**
+ * @var Zend_View_Interface
+ */
+ protected $_view;
+
+ /**
+ * Constructor
+ *
+ * Registers form view helper as decorator
+ *
+ * @param mixed $options
+ * @return void
+ */
+ public function __construct($options = null)
+ {
+ if (is_array($options)) {
+ $this->setOptions($options);
+ } elseif ($options instanceof Zend_Config) {
+ $this->setConfig($options);
+ }
+
+ // Extensions...
+ $this->init();
+
+ $this->loadDefaultDecorators();
+ }
+
+ /**
+ * Clone form object and all children
+ *
+ * @return void
+ */
+ public function __clone()
+ {
+ $elements = array();
+ foreach ($this->getElements() as $name => $element) {
+ $elements[] = clone $element;
+ }
+ $this->setElements($elements);
+
+ $subForms = array();
+ foreach ($this->getSubForms() as $name => $subForm) {
+ $subForms[$name] = clone $subForm;
+ }
+ $this->setSubForms($subForms);
+
+ $displayGroups = array();
+ foreach ($this->_displayGroups as $group) {
+ $clone = clone $group;
+ $elements = array();
+ foreach ($clone->getElements() as $name => $e) {
+ $elements[] = $this->getElement($name);
+ }
+ $clone->setElements($elements);
+ $displayGroups[] = $clone;
+ }
+ $this->setDisplayGroups($displayGroups);
+ }
+
+ /**
+ * Reset values of form
+ *
+ * @return Zend_Form
+ */
+ public function reset()
+ {
+ foreach ($this->getElements() as $element) {
+ $element->setValue(null);
+ }
+ foreach ($this->getSubForms() as $subForm) {
+ $subForm->reset();
+ }
+
+ return $this;
+ }
+
+ /**
+ * Initialize form (used by extending classes)
+ *
+ * @return void
+ */
+ public function init()
+ {
+ }
+
+ /**
+ * Set form state from options array
+ *
+ * @param array $options
+ * @return Zend_Form
+ */
+ public function setOptions(array $options)
+ {
+ if (isset($options['prefixPath'])) {
+ $this->addPrefixPaths($options['prefixPath']);
+ unset($options['prefixPath']);
+ }
+
+ if (isset($options['elementPrefixPath'])) {
+ $this->addElementPrefixPaths($options['elementPrefixPath']);
+ unset($options['elementPrefixPath']);
+ }
+
+ if (isset($options['displayGroupPrefixPath'])) {
+ $this->addDisplayGroupPrefixPaths($options['displayGroupPrefixPath']);
+ unset($options['displayGroupPrefixPath']);
+ }
+
+ if (isset($options['elementDecorators'])) {
+ $this->_elementDecorators = $options['elementDecorators'];
+ unset($options['elementDecorators']);
+ }
+
+ if (isset($options['elements'])) {
+ $this->setElements($options['elements']);
+ unset($options['elements']);
+ }
+
+ if (isset($options['defaultDisplayGroupClass'])) {
+ $this->setDefaultDisplayGroupClass($options['defaultDisplayGroupClass']);
+ unset($options['defaultDisplayGroupClass']);
+ }
+
+ if (isset($options['displayGroupDecorators'])) {
+ $displayGroupDecorators = $options['displayGroupDecorators'];
+ unset($options['displayGroupDecorators']);
+ }
+
+ if (isset($options['elementsBelongTo'])) {
+ $elementsBelongTo = $options['elementsBelongTo'];
+ unset($options['elementsBelongTo']);
+ }
+
+ if (isset($options['attribs'])) {
+ $this->addAttribs($options['attribs']);
+ unset($options['attribs']);
+ }
+
+ $forbidden = array(
+ 'Options', 'Config', 'PluginLoader', 'SubForms', 'View', 'Translator',
+ 'Attrib', 'Default',
+ );
+
+ foreach ($options as $key => $value) {
+ $normalized = ucfirst($key);
+ if (in_array($normalized, $forbidden)) {
+ continue;
+ }
+
+ $method = 'set' . $normalized;
+ if (method_exists($this, $method)) {
+ $this->$method($value);
+ } else {
+ $this->setAttrib($key, $value);
+ }
+ }
+
+ if (isset($displayGroupDecorators)) {
+ $this->setDisplayGroupDecorators($displayGroupDecorators);
+ }
+
+ if (isset($elementsBelongTo)) {
+ $this->setElementsBelongTo($elementsBelongTo);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Set form state from config object
+ *
+ * @param Zend_Config $config
+ * @return Zend_Form
+ */
+ public function setConfig(Zend_Config $config)
+ {
+ return $this->setOptions($config->toArray());
+ }
+
+
+ // Loaders
+
+ /**
+ * Set plugin loaders for use with decorators and elements
+ *
+ * @param Zend_Loader_PluginLoader_Interface $loader
+ * @param string $type 'decorator' or 'element'
+ * @return Zend_Form
+ * @throws Zend_Form_Exception on invalid type
+ */
+ public function setPluginLoader(Zend_Loader_PluginLoader_Interface $loader, $type = null)
+ {
+ $type = strtoupper($type);
+ switch ($type) {
+ case self::DECORATOR:
+ case self::ELEMENT:
+ $this->_loaders[$type] = $loader;
+ return $this;
+ default:
+ require_once 'Zend/Form/Exception.php';
+ throw new Zend_Form_Exception(sprintf('Invalid type "%s" provided to setPluginLoader()', $type));
+ }
+ }
+
+ /**
+ * Retrieve plugin loader for given type
+ *
+ * $type may be one of:
+ * - decorator
+ * - element
+ *
+ * If a plugin loader does not exist for the given type, defaults are
+ * created.
+ *
+ * @param string $type
+ * @return Zend_Loader_PluginLoader_Interface
+ */
+ public function getPluginLoader($type = null)
+ {
+ $type = strtoupper($type);
+ if (!isset($this->_loaders[$type])) {
+ switch ($type) {
+ case self::DECORATOR:
+ $prefixSegment = 'Form_Decorator';
+ $pathSegment = 'Form/Decorator';
+ break;
+ case self::ELEMENT:
+ $prefixSegment = 'Form_Element';
+ $pathSegment = 'Form/Element';
+ break;
+ default:
+ require_once 'Zend/Form/Exception.php';
+ throw new Zend_Form_Exception(sprintf('Invalid type "%s" provided to getPluginLoader()', $type));
+ }
+
+ require_once 'Zend/Loader/PluginLoader.php';
+ $this->_loaders[$type] = new Zend_Loader_PluginLoader(
+ array('Zend_' . $prefixSegment . '_' => 'Zend/' . $pathSegment . '/')
+ );
+ }
+
+ return $this->_loaders[$type];
+ }
+
+ /**
+ * Add prefix path for plugin loader
+ *
+ * If no $type specified, assumes it is a base path for both filters and
+ * validators, and sets each according to the following rules:
+ * - decorators: $prefix = $prefix . '_Decorator'
+ * - elements: $prefix = $prefix . '_Element'
+ *
+ * Otherwise, the path prefix is set on the appropriate plugin loader.
+ *
+ * If $type is 'decorators', sets the path in the decorator plugin loader
+ * for all elements. Additionally, if no $type is provided,
+ * {@link Zend_Form_Element::addPrefixPath()} is called on each element.
+ *
+ * @param string $prefix
+ * @param string $path
+ * @param string $type
+ * @return Zend_Form
+ * @throws Zend_Form_Exception for invalid type
+ */
+ public function addPrefixPath($prefix, $path, $type = null)
+ {
+ $type = strtoupper($type);
+ switch ($type) {
+ case self::DECORATOR:
+ case self::ELEMENT:
+ $loader = $this->getPluginLoader($type);
+ $loader->addPrefixPath($prefix, $path);
+ return $this;
+ case null:
+ $prefix = rtrim($prefix, '_');
+ $path = rtrim($path, DIRECTORY_SEPARATOR);
+ foreach (array(self::DECORATOR, self::ELEMENT) as $type) {
+ $cType = ucfirst(strtolower($type));
+ $pluginPath = $path . DIRECTORY_SEPARATOR . $cType . DIRECTORY_SEPARATOR;
+ $pluginPrefix = $prefix . '_' . $cType;
+ $loader = $this->getPluginLoader($type);
+ $loader->addPrefixPath($pluginPrefix, $pluginPath);
+ }
+ return $this;
+ default:
+ require_once 'Zend/Form/Exception.php';
+ throw new Zend_Form_Exception(sprintf('Invalid type "%s" provided to getPluginLoader()', $type));
+ }
+ }
+
+ /**
+ * Add many prefix paths at once
+ *
+ * @param array $spec
+ * @return Zend_Form
+ */
+ public function addPrefixPaths(array $spec)
+ {
+ if (isset($spec['prefix']) && isset($spec['path'])) {
+ return $this->addPrefixPath($spec['prefix'], $spec['path']);
+ }
+ foreach ($spec as $type => $paths) {
+ if (is_numeric($type) && is_array($paths)) {
+ $type = null;
+ if (isset($paths['prefix']) && isset($paths['path'])) {
+ if (isset($paths['type'])) {
+ $type = $paths['type'];
+ }
+ $this->addPrefixPath($paths['prefix'], $paths['path'], $type);
+ }
+ } elseif (!is_numeric($type)) {
+ if (!isset($paths['prefix']) || !isset($paths['path'])) {
+ continue;
+ }
+ $this->addPrefixPath($paths['prefix'], $paths['path'], $type);
+ }
+ }
+ return $this;
+ }
+
+ /**
+ * Add prefix path for all elements
+ *
+ * @param string $prefix
+ * @param string $path
+ * @param string $type
+ * @return Zend_Form
+ */
+ public function addElementPrefixPath($prefix, $path, $type = null)
+ {
+ $this->_elementPrefixPaths[] = array(
+ 'prefix' => $prefix,
+ 'path' => $path,
+ 'type' => $type,
+ );
+
+ foreach ($this->getElements() as $element) {
+ $element->addPrefixPath($prefix, $path, $type);
+ }
+
+ foreach ($this->getSubForms() as $subForm) {
+ $subForm->addElementPrefixPath($prefix, $path, $type);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Add prefix paths for all elements
+ *
+ * @param array $spec
+ * @return Zend_Form
+ */
+ public function addElementPrefixPaths(array $spec)
+ {
+ $this->_elementPrefixPaths = $this->_elementPrefixPaths + $spec;
+
+ foreach ($this->getElements() as $element) {
+ $element->addPrefixPaths($spec);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Add prefix path for all display groups
+ *
+ * @param string $prefix
+ * @param string $path
+ * @return Zend_Form
+ */
+ public function addDisplayGroupPrefixPath($prefix, $path)
+ {
+ $this->_displayGroupPrefixPaths[] = array(
+ 'prefix' => $prefix,
+ 'path' => $path,
+ );
+
+ foreach ($this->getDisplayGroups() as $group) {
+ $group->addPrefixPath($prefix, $path);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Add multiple display group prefix paths at once
+ *
+ * @param array $spec
+ * @return Zend_Form
+ */
+ public function addDisplayGroupPrefixPaths(array $spec)
+ {
+ foreach ($spec as $key => $value) {
+ if (is_string($value) && !is_numeric($key)) {
+ $this->addDisplayGroupPrefixPath($key, $value);
+ continue;
+ }
+
+ if (is_string($value) && is_numeric($key)) {
+ continue;
+ }
+
+ if (is_array($value)) {
+ $count = count($value);
+ if (array_keys($value) === range(0, $count - 1)) {
+ if ($count < 2) {
+ continue;
+ }
+ $prefix = array_shift($value);
+ $path = array_shift($value);
+ $this->addDisplayGroupPrefixPath($prefix, $path);
+ continue;
+ }
+ if (array_key_exists('prefix', $value) && array_key_exists('path', $value)) {
+ $this->addDisplayGroupPrefixPath($value['prefix'], $value['path']);
+ }
+ }
+ }
+ return $this;
+ }
+
+ // Form metadata:
+
+ /**
+ * Set form attribute
+ *
+ * @param string $key
+ * @param mixed $value
+ * @return Zend_Form
+ */
+ public function setAttrib($key, $value)
+ {
+ $key = (string) $key;
+ $this->_attribs[$key] = $value;
+ return $this;
+ }
+
+ /**
+ * Add multiple form attributes at once
+ *
+ * @param array $attribs
+ * @return Zend_Form
+ */
+ public function addAttribs(array $attribs)
+ {
+ foreach ($attribs as $key => $value) {
+ $this->setAttrib($key, $value);
+ }
+ return $this;
+ }
+
+ /**
+ * Set multiple form attributes at once
+ *
+ * Overwrites any previously set attributes.
+ *
+ * @param array $attribs
+ * @return Zend_Form
+ */
+ public function setAttribs(array $attribs)
+ {
+ $this->clearAttribs();
+ return $this->addAttribs($attribs);
+ }
+
+ /**
+ * Retrieve a single form attribute
+ *
+ * @param string $key
+ * @return mixed
+ */
+ public function getAttrib($key)
+ {
+ $key = (string) $key;
+ if (!isset($this->_attribs[$key])) {
+ return null;
+ }
+
+ return $this->_attribs[$key];
+ }
+
+ /**
+ * Retrieve all form attributes/metadata
+ *
+ * @return array
+ */
+ public function getAttribs()
+ {
+ return $this->_attribs;
+ }
+
+ /**
+ * Remove attribute
+ *
+ * @param string $key
+ * @return bool
+ */
+ public function removeAttrib($key)
+ {
+ if (isset($this->_attribs[$key])) {
+ unset($this->_attribs[$key]);
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Clear all form attributes
+ *
+ * @return Zend_Form
+ */
+ public function clearAttribs()
+ {
+ $this->_attribs = array();
+ return $this;
+ }
+
+ /**
+ * Set form action
+ *
+ * @param string $action
+ * @return Zend_Form
+ */
+ public function setAction($action)
+ {
+ return $this->setAttrib('action', (string) $action);
+ }
+
+ /**
+ * Get form action
+ *
+ * Sets default to '' if not set.
+ *
+ * @return string
+ */
+ public function getAction()
+ {
+ $action = $this->getAttrib('action');
+ if (null === $action) {
+ $action = '';
+ $this->setAction($action);
+ }
+ return $action;
+ }
+
+ /**
+ * Set form method
+ *
+ * Only values in {@link $_methods()} allowed
+ *
+ * @param string $method
+ * @return Zend_Form
+ * @throws Zend_Form_Exception
+ */
+ public function setMethod($method)
+ {
+ $method = strtolower($method);
+ if (!in_array($method, $this->_methods)) {
+ require_once 'Zend/Form/Exception.php';
+ throw new Zend_Form_Exception(sprintf('"%s" is an invalid form method', $method));
+ }
+ $this->setAttrib('method', $method);
+ return $this;
+ }
+
+ /**
+ * Retrieve form method
+ *
+ * @return string
+ */
+ public function getMethod()
+ {
+ if (null === ($method = $this->getAttrib('method'))) {
+ $method = self::METHOD_POST;
+ $this->setAttrib('method', $method);
+ }
+ return strtolower($method);
+ }
+
+ /**
+ * Set encoding type
+ *
+ * @param string $value
+ * @return Zend_Form
+ */
+ public function setEnctype($value)
+ {
+ $this->setAttrib('enctype', $value);
+ return $this;
+ }
+
+ /**
+ * Get encoding type
+ *
+ * @return string
+ */
+ public function getEnctype()
+ {
+ if (null === ($enctype = $this->getAttrib('enctype'))) {
+ $enctype = self::ENCTYPE_URLENCODED;
+ $this->setAttrib('enctype', $enctype);
+ }
+ return $this->getAttrib('enctype');
+ }
+
+ /**
+ * Filter a name to only allow valid variable characters
+ *
+ * @param string $value
+ * @param bool $allowBrackets
+ * @return string
+ */
+ public function filterName($value, $allowBrackets = false)
+ {
+ $charset = '^a-zA-Z0-9_\x7f-\xff';
+ if ($allowBrackets) {
+ $charset .= '\[\]';
+ }
+ return preg_replace('/[' . $charset . ']/', '', (string) $value);
+ }
+
+ /**
+ * Set form name
+ *
+ * @param string $name
+ * @return Zend_Form
+ */
+ public function setName($name)
+ {
+ $name = $this->filterName($name);
+ if (('0' !== $name) && empty($name)) {
+ require_once 'Zend/Form/Exception.php';
+ throw new Zend_Form_Exception('Invalid name provided; must contain only valid variable characters and be non-empty');
+ }
+
+ return $this->setAttrib('name', $name);
+ }
+
+ /**
+ * Get name attribute
+ *
+ * @return null|string
+ */
+ public function getName()
+ {
+ return $this->getAttrib('name');
+ }
+
+ /**
+ * Get fully qualified name
+ *
+ * Places name as subitem of array and/or appends brackets.
+ *
+ * @return string
+ */
+ public function getFullyQualifiedName()
+ {
+ return $this->getName();
+ }
+
+ /**
+ * Get element id
+ *
+ * @return string
+ */
+ public function getId()
+ {
+ if (null !== ($id = $this->getAttrib('id'))) {
+ return $id;
+ }
+
+ $id = $this->getFullyQualifiedName();
+
+ // Bail early if no array notation detected
+ if (!strstr($id, '[')) {
+ return $id;
+ }
+
+ // Strip array notation
+ if ('[]' == substr($id, -2)) {
+ $id = substr($id, 0, strlen($id) - 2);
+ }
+ $id = str_replace('][', '-', $id);
+ $id = str_replace(array(']', '['), '-', $id);
+ $id = trim($id, '-');
+
+ return $id;
+ }
+
+ /**
+ * Set form legend
+ *
+ * @param string $value
+ * @return Zend_Form
+ */
+ public function setLegend($value)
+ {
+ $this->_legend = (string) $value;
+ return $this;
+ }
+
+ /**
+ * Get form legend
+ *
+ * @return string
+ */
+ public function getLegend()
+ {
+ return $this->_legend;
+ }
+
+ /**
+ * Set form description
+ *
+ * @param string $value
+ * @return Zend_Form
+ */
+ public function setDescription($value)
+ {
+ $this->_description = (string) $value;
+ return $this;
+ }
+
+ /**
+ * Retrieve form description
+ *
+ * @return string
+ */
+ public function getDescription()
+ {
+ return $this->_description;
+ }
+
+ /**
+ * Set form order
+ *
+ * @param int $index
+ * @return Zend_Form
+ */
+ public function setOrder($index)
+ {
+ $this->_formOrder = (int) $index;
+ return $this;
+ }
+
+ /**
+ * Get form order
+ *
+ * @return int|null
+ */
+ public function getOrder()
+ {
+ return $this->_formOrder;
+ }
+
+ // Element interaction:
+
+ /**
+ * Add a new element
+ *
+ * $element may be either a string element type, or an object of type
+ * Zend_Form_Element. If a string element type is provided, $name must be
+ * provided, and $options may be optionally provided for configuring the
+ * element.
+ *
+ * If a Zend_Form_Element is provided, $name may be optionally provided,
+ * and any provided $options will be ignored.
+ *
+ * @param string|Zend_Form_Element $element
+ * @param string $name
+ * @param array|Zend_Config $options
+ * @return Zend_Form
+ */
+ public function addElement($element, $name = null, $options = null)
+ {
+ if (is_string($element)) {
+ if (null === $name) {
+ require_once 'Zend/Form/Exception.php';
+ throw new Zend_Form_Exception('Elements specified by string must have an accompanying name');
+ }
+
+ if (is_array($this->_elementDecorators)) {
+ if (null === $options) {
+ $options = array('decorators' => $this->_elementDecorators);
+ } elseif ($options instanceof Zend_Config) {
+ $options = $options->toArray();
+ }
+ if (is_array($options)
+ && !array_key_exists('decorators', $options)
+ ) {
+ $options['decorators'] = $this->_elementDecorators;
+ }
+ }
+
+ $this->_elements[$name] = $this->createElement($element, $name, $options);
+ } elseif ($element instanceof Zend_Form_Element) {
+ $prefixPaths = array();
+ $prefixPaths['decorator'] = $this->getPluginLoader('decorator')->getPaths();
+ if (!empty($this->_elementPrefixPaths)) {
+ $prefixPaths = array_merge($prefixPaths, $this->_elementPrefixPaths);
+ }
+
+ if (null === $name) {
+ $name = $element->getName();
+ }
+
+ $this->_elements[$name] = $element;
+ $this->_elements[$name]->addPrefixPaths($prefixPaths);
+ }
+
+ $this->_order[$name] = $this->_elements[$name]->getOrder();
+ $this->_orderUpdated = true;
+ $this->_setElementsBelongTo($name);
+
+ return $this;
+ }
+
+ /**
+ * Create an element
+ *
+ * Acts as a factory for creating elements. Elements created with this
+ * method will not be attached to the form, but will contain element
+ * settings as specified in the form object (including plugin loader
+ * prefix paths, default decorators, etc.).
+ *
+ * @param string $type
+ * @param string $name
+ * @param array|Zend_Config $options
+ * @return Zend_Form_Element
+ */
+ public function createElement($type, $name, $options = null)
+ {
+ if (!is_string($type)) {
+ require_once 'Zend/Form/Exception.php';
+ throw new Zend_Form_Exception('Element type must be a string indicating type');
+ }
+
+ if (!is_string($name)) {
+ require_once 'Zend/Form/Exception.php';
+ throw new Zend_Form_Exception('Element name must be a string');
+ }
+
+ $prefixPaths = array();
+ $prefixPaths['decorator'] = $this->getPluginLoader('decorator')->getPaths();
+ if (!empty($this->_elementPrefixPaths)) {
+ $prefixPaths = array_merge($prefixPaths, $this->_elementPrefixPaths);
+ }
+
+ if ($options instanceof Zend_Config) {
+ $options = $options->toArray();
+ }
+
+ if ((null === $options) || !is_array($options)) {
+ $options = array('prefixPath' => $prefixPaths);
+ } elseif (is_array($options)) {
+ if (array_key_exists('prefixPath', $options)) {
+ $options['prefixPath'] = array_merge($prefixPaths, $options['prefixPath']);
+ } else {
+ $options['prefixPath'] = $prefixPaths;
+ }
+ }
+
+ $class = $this->getPluginLoader(self::ELEMENT)->load($type);
+ $element = new $class($name, $options);
+
+ return $element;
+ }
+
+ /**
+ * Add multiple elements at once
+ *
+ * @param array $elements
+ * @return Zend_Form
+ */
+ public function addElements(array $elements)
+ {
+ foreach ($elements as $key => $spec) {
+ $name = null;
+ if (!is_numeric($key)) {
+ $name = $key;
+ }
+
+ if (is_string($spec) || ($spec instanceof Zend_Form_Element)) {
+ $this->addElement($spec, $name);
+ continue;
+ }
+
+ if (is_array($spec)) {
+ $argc = count($spec);
+ $options = array();
+ if (isset($spec['type'])) {
+ $type = $spec['type'];
+ if (isset($spec['name'])) {
+ $name = $spec['name'];
+ }
+ if (isset($spec['options'])) {
+ $options = $spec['options'];
+ }
+ $this->addElement($type, $name, $options);
+ } else {
+ switch ($argc) {
+ case 0:
+ continue;
+ case (1 <= $argc):
+ $type = array_shift($spec);
+ case (2 <= $argc):
+ if (null === $name) {
+ $name = array_shift($spec);
+ } else {
+ $options = array_shift($spec);
+ }
+ case (3 <= $argc):
+ if (empty($options)) {
+ $options = array_shift($spec);
+ }
+ default:
+ $this->addElement($type, $name, $options);
+ }
+ }
+ }
+ }
+ return $this;
+ }
+
+ /**
+ * Set form elements (overwrites existing elements)
+ *
+ * @param array $elements
+ * @return Zend_Form
+ */
+ public function setElements(array $elements)
+ {
+ $this->clearElements();
+ return $this->addElements($elements);
+ }
+
+ /**
+ * Retrieve a single element
+ *
+ * @param string $name
+ * @return Zend_Form_Element|null
+ */
+ public function getElement($name)
+ {
+ if (array_key_exists($name, $this->_elements)) {
+ return $this->_elements[$name];
+ }
+ return null;
+ }
+
+ /**
+ * Retrieve all elements
+ *
+ * @return array
+ */
+ public function getElements()
+ {
+ return $this->_elements;
+ }
+
+ /**
+ * Remove element
+ *
+ * @param string $name
+ * @return boolean
+ */
+ public function removeElement($name)
+ {
+ $name = (string) $name;
+ if (isset($this->_elements[$name])) {
+ unset($this->_elements[$name]);
+ if (array_key_exists($name, $this->_order)) {
+ unset($this->_order[$name]);
+ $this->_orderUpdated = true;
+ } else {
+ foreach ($this->_displayGroups as $group) {
+ if (null !== $group->getElement($name)) {
+ $group->removeElement($name);
+ }
+ }
+ }
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Remove all form elements
+ *
+ * @return Zend_Form
+ */
+ public function clearElements()
+ {
+ foreach (array_keys($this->_elements) as $key) {
+ if (array_key_exists($key, $this->_order)) {
+ unset($this->_order[$key]);
+ }
+ }
+ $this->_elements = array();
+ $this->_orderUpdated = true;
+ return $this;
+ }
+
+ /**
+ * Set default values for elements
+ *
+ * Sets values for all elements specified in the array of $defaults.
+ *
+ * @param array $defaults
+ * @return Zend_Form
+ */
+ public function setDefaults(array $defaults)
+ {
+ foreach ($this->getElements() as $name => $element) {
+ if (array_key_exists($name, $defaults)) {
+ $this->setDefault($name, $defaults[$name]);
+ }
+ }
+ foreach ($this->getSubForms() as $name => $form) {
+ if (array_key_exists($name, $defaults)) {
+ $form->setDefaults($defaults[$name]);
+ } else {
+ $form->setDefaults($defaults);
+ }
+ }
+ return $this;
+ }
+
+ /**
+ * Set default value for an element
+ *
+ * @param string $name
+ * @param mixed $value
+ * @return Zend_Form
+ */
+ public function setDefault($name, $value)
+ {
+ $name = (string) $name;
+ if ($element = $this->getElement($name)) {
+ $element->setValue($value);
+ } else {
+ if (is_scalar($value)) {
+ foreach ($this->getSubForms() as $subForm) {
+ $subForm->setDefault($name, $value);
+ }
+ } elseif (is_array($value) && ($subForm = $this->getSubForm($name))) {
+ $subForm->setDefaults($value);
+ }
+ }
+ return $this;
+ }
+
+ /**
+ * Retrieve value for single element
+ *
+ * @param string $name
+ * @return mixed
+ */
+ public function getValue($name)
+ {
+ if ($element = $this->getElement($name)) {
+ return $element->getValue();
+ }
+
+ if ($subForm = $this->getSubForm($name)) {
+ return $subForm->getValues(true);
+ }
+
+ foreach ($this->getSubForms() as $subForm) {
+ if ($name == $subForm->getElementsBelongTo()) {
+ return $subForm->getValues(true);
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Retrieve all form element values
+ *
+ * @param bool $suppressArrayNotation
+ * @return array
+ */
+ public function getValues($suppressArrayNotation = false)
+ {
+ $values = array();
+ foreach ($this->getElements() as $key => $element) {
+ if (!$element->getIgnore()) {
+ $values[$key] = $element->getValue();
+ }
+ }
+ foreach ($this->getSubForms() as $key => $subForm) {
+ $fValues = $this->_attachToArray($subForm->getValues(true), $subForm->getElementsBelongTo());
+ $values = array_merge($values, $fValues);
+ }
+
+ if (!$suppressArrayNotation && $this->isArray()) {
+ $values = $this->_attachToArray($values, $this->getElementsBelongTo());
+ }
+
+ return $values;
+ }
+
+ /**
+ * Get unfiltered element value
+ *
+ * @param string $name
+ * @return mixed
+ */
+ public function getUnfilteredValue($name)
+ {
+ if ($element = $this->getElement($name)) {
+ return $element->getUnfilteredValue();
+ }
+ return null;
+ }
+
+ /**
+ * Retrieve all unfiltered element values
+ *
+ * @return array
+ */
+ public function getUnfilteredValues()
+ {
+ $values = array();
+ foreach ($this->getElements() as $key => $element) {
+ $values[$key] = $element->getUnfilteredValue();
+ }
+
+ return $values;
+ }
+
+ /**
+ * Set all elements' filters
+ *
+ * @param array $filters
+ * @return Zend_Form
+ */
+ public function setElementFilters(array $filters)
+ {
+ foreach ($this->getElements() as $element) {
+ $element->setFilters($filters);
+ }
+ return $this;
+ }
+
+ /**
+ * Set name of array elements belong to
+ *
+ * @param string $array
+ * @return Zend_Form
+ */
+ public function setElementsBelongTo($array)
+ {
+ $origName = $this->getElementsBelongTo();
+ $name = $this->filterName($array, true);
+ if (empty($name)) {
+ $name = null;
+ }
+ $this->_elementsBelongTo = $name;
+
+ if (null === $name) {
+ $this->setIsArray(false);
+ if (null !== $origName) {
+ $this->_setElementsBelongTo();
+ }
+ } else {
+ $this->setIsArray(true);
+ $this->_setElementsBelongTo();
+ }
+
+ return $this;
+ }
+
+ /**
+ * Set array to which elements belong
+ *
+ * @param string $name Element name
+ * @return void
+ */
+ protected function _setElementsBelongTo($name = null)
+ {
+ $array = $this->getElementsBelongTo();
+
+ if (null === $array) {
+ return;
+ }
+
+ if (null === $name) {
+ foreach ($this->getElements() as $element) {
+ $element->setBelongsTo($array);
+ }
+ } else {
+ if (null !== ($element = $this->getElement($name))) {
+ $element->setBelongsTo($array);
+ }
+ }
+ }
+
+ /**
+ * Get name of array elements belong to
+ *
+ * @return string|null
+ */
+ public function getElementsBelongTo()
+ {
+ if ((null === $this->_elementsBelongTo) && $this->isArray()) {
+ $name = $this->getName();
+ if (!empty($name)) {
+ return $name;
+ }
+ }
+ return $this->_elementsBelongTo;
+ }
+
+ /**
+ * Set flag indicating elements belong to array
+ *
+ * @param bool $flag Value of flag
+ * @return Zend_Form
+ */
+ public function setIsArray($flag)
+ {
+ $this->_isArray = (bool) $flag;
+ return $this;
+ }
+
+ /**
+ * Get flag indicating if elements belong to an array
+ *
+ * @return bool
+ */
+ public function isArray()
+ {
+ return $this->_isArray;
+ }
+
+ // Element groups:
+
+ /**
+ * Add a form group/subform
+ *
+ * @param Zend_Form $form
+ * @param string $name
+ * @param int $order
+ * @return Zend_Form
+ */
+ public function addSubForm(Zend_Form $form, $name, $order = null)
+ {
+ $name = (string) $name;
+ foreach ($this->_loaders as $type => $loader) {
+ $loaderPaths = $loader->getPaths();
+ foreach ($loaderPaths as $prefix => $paths) {
+ foreach ($paths as $path) {
+ $form->addPrefixPath($prefix, $path, $type);
+ }
+ }
+ }
+
+ if (!empty($this->_elementPrefixPaths)) {
+ foreach ($this->_elementPrefixPaths as $spec) {
+ list($prefix, $path, $type) = array_values($spec);
+ $form->addElementPrefixPath($prefix, $path, $type);
+ }
+ }
+
+ if (!empty($this->_displayGroupPrefixPaths)) {
+ foreach ($this->_displayGroupPrefixPaths as $spec) {
+ list($prefix, $path) = array_values($spec);
+ $form->addDisplayGroupPrefixPath($prefix, $path);
+ }
+ }
+
+ if (null !== $order) {
+ $form->setOrder($order);
+ }
+
+ $form->setName($name);
+ $this->_subForms[$name] = $form;
+ $this->_order[$name] = $order;
+ $this->_orderUpdated = true;
+ return $this;
+ }
+
+ /**
+ * Add multiple form subForms/subforms at once
+ *
+ * @param array $subForms
+ * @return Zend_Form
+ */
+ public function addSubForms(array $subForms)
+ {
+ foreach ($subForms as $key => $spec) {
+ $name = null;
+ if (!is_numeric($key)) {
+ $name = $key;
+ }
+
+ if ($spec instanceof Zend_Form) {
+ $this->addSubForm($spec, $name);
+ continue;
+ }
+
+ if (is_array($spec)) {
+ $argc = count($spec);
+ $order = null;
+ switch ($argc) {
+ case 0:
+ continue;
+ case (1 <= $argc):
+ $subForm = array_shift($spec);
+ case (2 <= $argc):
+ $name = array_shift($spec);
+ case (3 <= $argc):
+ $order = array_shift($spec);
+ default:
+ $this->addSubForm($subForm, $name, $order);
+ }
+ }
+ }
+ return $this;
+ }
+
+ /**
+ * Set multiple form subForms/subforms (overwrites)
+ *
+ * @param array $subForms
+ * @return Zend_Form
+ */
+ public function setSubForms(array $subForms)
+ {
+ $this->clearSubForms();
+ return $this->addSubForms($subForms);
+ }
+
+ /**
+ * Retrieve a form subForm/subform
+ *
+ * @param string $name
+ * @return Zend_Form|null
+ */
+ public function getSubForm($name)
+ {
+ $name = (string) $name;
+ if (isset($this->_subForms[$name])) {
+ return $this->_subForms[$name];
+ }
+ return null;
+ }
+
+ /**
+ * Retrieve all form subForms/subforms
+ *
+ * @return array
+ */
+ public function getSubForms()
+ {
+ return $this->_subForms;
+ }
+
+ /**
+ * Remove form subForm/subform
+ *
+ * @param string $name
+ * @return boolean
+ */
+ public function removeSubForm($name)
+ {
+ $name = (string) $name;
+ if (array_key_exists($name, $this->_subForms)) {
+ unset($this->_subForms[$name]);
+ if (array_key_exists($name, $this->_order)) {
+ unset($this->_order[$name]);
+ $this->_orderUpdated = true;
+ }
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Remove all form subForms/subforms
+ *
+ * @return Zend_Form
+ */
+ public function clearSubForms()
+ {
+ foreach (array_keys($this->_subForms) as $key) {
+ if (array_key_exists($key, $this->_order)) {
+ unset($this->_order[$key]);
+ }
+ }
+ $this->_subForms = array();
+ $this->_orderUpdated = true;
+ return $this;
+ }
+
+
+ // Display groups:
+
+ /**
+ * Set default display group class
+ *
+ * @param string $class
+ * @return Zend_Form
+ */
+ public function setDefaultDisplayGroupClass($class)
+ {
+ $this->_defaultDisplayGroupClass = (string) $class;
+ return $this;
+ }
+
+ /**
+ * Retrieve default display group class
+ *
+ * @return string
+ */
+ public function getDefaultDisplayGroupClass()
+ {
+ return $this->_defaultDisplayGroupClass;
+ }
+
+ /**
+ * Add a display group
+ *
+ * Groups named elements for display purposes.
+ *
+ * If a referenced element does not yet exist in the form, it is omitted.
+ *
+ * @param array $elements
+ * @param string $name
+ * @param array|Zend_Config $options
+ * @return Zend_Form
+ * @throws Zend_Form_Exception if no valid elements provided
+ */
+ public function addDisplayGroup(array $elements, $name, $options = null)
+ {
+ $group = array();
+ foreach ($elements as $element) {
+ if (isset($this->_elements[$element])) {
+ $add = $this->getElement($element);
+ if (null !== $add) {
+ unset($this->_order[$element]);
+ $group[] = $add;
+ }
+ }
+ }
+ if (empty($group)) {
+ require_once 'Zend/Form/Exception.php';
+ throw new Zend_Form_Exception('No valid elements specified for display group');
+ }
+
+ $name = (string) $name;
+
+ if (is_array($options)) {
+ $options['elements'] = $group;
+ } elseif ($options instanceof Zend_Config) {
+ $options = $options->toArray();
+ $options['elements'] = $group;
+ } else {
+ $options = array('elements' => $group);
+ }
+
+ if (isset($options['displayGroupClass'])) {
+ $class = $options['displayGroupClass'];
+ unset($options['displayGroupClass']);
+ } else {
+ $class = $this->getDefaultDisplayGroupClass();
+ }
+
+ if (!class_exists($class)) {
+ require_once 'Zend/Loader.php';
+ Zend_Loader::loadClass($class);
+ }
+ $this->_displayGroups[$name] = new $class(
+ $name,
+ $this->getPluginLoader(self::DECORATOR),
+ $options
+ );
+
+ if (!empty($this->_displayGroupPrefixPaths)) {
+ $this->_displayGroups[$name]->addPrefixPaths($this->_displayGroupPrefixPaths);
+ }
+
+ $this->_order[$name] = $this->_displayGroups[$name]->getOrder();
+ $this->_orderUpdated = true;
+ return $this;
+ }
+
+ /**
+ * Add a display group object (used with cloning)
+ *
+ * @param Zend_Form_DisplayGroup $group
+ * @param string|null $name
+ * @return Zend_Form
+ */
+ protected function _addDisplayGroupObject(Zend_Form_DisplayGroup $group, $name = null)
+ {
+ if (null === $name) {
+ $name = $group->getName();
+ if (empty($name)) {
+ require_once 'Zend/Form/Exception.php';
+ throw new Zend_Form_Exception('Invalid display group added; requires name');
+ }
+ }
+
+ $this->_displayGroups[$name] = $group;
+
+ if (!empty($this->_displayGroupPrefixPaths)) {
+ $this->_displayGroups[$name]->addPrefixPaths($this->_displayGroupPrefixPaths);
+ }
+
+ $this->_order[$name] = $this->_displayGroups[$name]->getOrder();
+ $this->_orderUpdated = true;
+ return $this;
+ }
+
+ /**
+ * Add multiple display groups at once
+ *
+ * @param array $groups
+ * @return Zend_Form
+ */
+ public function addDisplayGroups(array $groups)
+ {
+ foreach ($groups as $key => $spec) {
+ $name = null;
+ if (!is_numeric($key)) {
+ $name = $key;
+ }
+
+ if ($spec instanceof Zend_Form_DisplayGroup) {
+ $this->_addDisplayGroupObject($spec);
+ }
+
+ if (!is_array($spec) || empty($spec)) {
+ continue;
+ }
+
+ $argc = count($spec);
+ $options = array();
+
+ if (isset($spec['elements'])) {
+ $elements = $spec['elements'];
+ if (isset($spec['name'])) {
+ $name = $spec['name'];
+ }
+ if (isset($spec['options'])) {
+ $options = $spec['options'];
+ }
+ $this->addDisplayGroup($elements, $name, $options);
+ } else {
+ switch ($argc) {
+ case (1 <= $argc):
+ $elements = array_shift($spec);
+ if (!is_array($elements) && (null !== $name)) {
+ $elements = array_merge((array) $elements, $spec);
+ $this->addDisplayGroup($elements, $name);
+ break;
+ }
+ case (2 <= $argc):
+ if (null !== $name) {
+ $options = array_shift($spec);
+ $this->addDisplayGroup($elements, $name, $options);
+ break;
+ }
+ $name = array_shift($spec);
+ case (3 <= $argc):
+ $options = array_shift($spec);
+ default:
+ $this->addDisplayGroup($elements, $name, $options);
+ }
+ }
+ }
+ return $this;
+ }
+
+ /**
+ * Add multiple display groups (overwrites)
+ *
+ * @param array $groups
+ * @return Zend_Form
+ */
+ public function setDisplayGroups(array $groups)
+ {
+ return $this->clearDisplayGroups()
+ ->addDisplayGroups($groups);
+ }
+
+ /**
+ * Return a display group
+ *
+ * @param string $name
+ * @return Zend_Form_DisplayGroup|null
+ */
+ public function getDisplayGroup($name)
+ {
+ $name = (string) $name;
+ if (isset($this->_displayGroups[$name])) {
+ return $this->_displayGroups[$name];
+ }
+
+ return null;
+ }
+
+ /**
+ * Return all display groups
+ *
+ * @return array
+ */
+ public function getDisplayGroups()
+ {
+ return $this->_displayGroups;
+ }
+
+ /**
+ * Remove a display group by name
+ *
+ * @param string $name
+ * @return boolean
+ */
+ public function removeDisplayGroup($name)
+ {
+ $name = (string) $name;
+ if (array_key_exists($name, $this->_displayGroups)) {
+ foreach ($this->_displayGroups[$name] as $key => $element) {
+ if (array_key_exists($key, $this->_elements)) {
+ $this->_order[$key] = $element->getOrder();
+ $this->_orderUpdated = true;
+ }
+ }
+ unset($this->_displayGroups[$name]);
+
+ if (array_key_exists($name, $this->_order)) {
+ unset($this->_order[$name]);
+ $this->_orderUpdated = true;
+ }
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Remove all display groups
+ *
+ * @return Zend_Form
+ */
+ public function clearDisplayGroups()
+ {
+ foreach ($this->_displayGroups as $key => $group) {
+ if (array_key_exists($key, $this->_order)) {
+ unset($this->_order[$key]);
+ }
+ foreach ($group as $name => $element) {
+ if (isset($this->_elements[$name])) {
+ $this->_order[$name] = $element->getOrder();
+ }
+ $this->_order[$name] = $element->getOrder();
+ }
+ }
+ $this->_displayGroups = array();
+ $this->_orderUpdated = true;
+ return $this;
+ }
+
+
+ // Processing
+
+ /**
+ * Populate form
+ *
+ * Proxies to {@link setDefaults()}
+ *
+ * @param array $values
+ * @return Zend_Form
+ */
+ public function populate(array $values)
+ {
+ return $this->setDefaults($values);
+ }
+
+ /**
+ * Determine array key name from given value
+ *
+ * Given a value such as foo[bar][baz], returns the last element (in this case, 'baz').
+ *
+ * @param string $value
+ * @return string
+ */
+ protected function _getArrayName($value)
+ {
+ if (empty($value) || !is_string($value)) {
+ return $value;
+ }
+
+ if (!strstr($value, '[')) {
+ return $value;
+ }
+
+ $endPos = strlen($value) - 1;
+ if (']' != $value[$endPos]) {
+ return $value;
+ }
+
+ $start = strrpos($value, '[') + 1;
+ $name = substr($value, $start, $endPos - $start);
+ return $name;
+ }
+
+ /**
+ * Extract the value by walking the array using given array path.
+ *
+ * Given an array path such as foo[bar][baz], returns the value of the last
+ * element (in this case, 'baz').
+ *
+ * @param array $value Array to walk
+ * @param string $arrayPath Array notation path of the part to extract
+ * @return string
+ */
+ protected function _dissolveArrayValue($value, $arrayPath)
+ {
+ // As long as we have more levels
+ while ($arrayPos = strpos($arrayPath, '[')) {
+ // Get the next key in the path
+ $arrayKey = trim(substr($arrayPath, 0, $arrayPos), ']');
+
+ // Set the potentially final value or the next search point in the array
+ if (isset($value[$arrayKey])) {
+ $value = $value[$arrayKey];
+ }
+
+ // Set the next search point in the path
+ $arrayPath = trim(substr($arrayPath, $arrayPos + 1), ']');
+ }
+
+ if (isset($value[$arrayPath])) {
+ $value = $value[$arrayPath];
+ }
+
+ return $value;
+ }
+
+ /**
+ * Converts given arrayPath to an array and attaches given value at the end of it.
+ *
+ * @param mixed $value The value to attach
+ * @param string $arrayPath Given array path to convert and attach to.
+ * @return array
+ */
+ protected function _attachToArray($value, $arrayPath)
+ {
+ // As long as we have more levels
+ while ($arrayPos = strrpos($arrayPath, '[')) {
+ // Get the next key in the path
+ $arrayKey = trim(substr($arrayPath, $arrayPos + 1), ']');
+
+ // Attach
+ $value = array($arrayKey => $value);
+
+ // Set the next search point in the path
+ $arrayPath = trim(substr($arrayPath, 0, $arrayPos), ']');
+ }
+
+ $value = array($arrayPath => $value);
+
+ return $value;
+ }
+
+ /**
+ * Validate the form
+ *
+ * @param array $data
+ * @return boolean
+ */
+ public function isValid($data)
+ {
+ if (!is_array($data)) {
+ require_once 'Zend/Form/Exception.php';
+ throw new Zend_Form_Exception(__CLASS__ . '::' . __METHOD__ . ' expects an array');
+ }
+ $translator = $this->getTranslator();
+ $valid = true;
+
+ if ($this->isArray()) {
+ $data = $this->_dissolveArrayValue($data, $this->getElementsBelongTo());
+ }
+
+ foreach ($this->getElements() as $key => $element) {
+ $element->setTranslator($translator);
+ if (!isset($data[$key])) {
+ $valid = $element->isValid(null, $data) && $valid;
+ } else {
+ $valid = $element->isValid($data[$key], $data) && $valid;
+ }
+ }
+ foreach ($this->getSubForms() as $key => $form) {
+ $form->setTranslator($translator);
+ if (isset($data[$key])) {
+ $valid = $form->isValid($data[$key]) && $valid;
+ } else {
+ $valid = $form->isValid($data) && $valid;
+ }
+ }
+
+ $this->_errorsExist = !$valid;
+
+ // If manually flagged as an error, return invalid status
+ if ($this->_errorsForced) {
+ return false;
+ }
+
+ return $valid;
+ }
+
+ /**
+ * Validate a partial form
+ *
+ * Does not check for required flags.
+ *
+ * @param array $data
+ * @return boolean
+ */
+ public function isValidPartial(array $data)
+ {
+ if ($this->isArray()) {
+ $data = $this->_dissolveArrayValue($data, $this->getElementsBelongTo());
+ }
+
+ $translator = $this->getTranslator();
+ $valid = true;
+ $validatedSubForms = array();
+
+ foreach ($data as $key => $value) {
+ if (null !== ($element = $this->getElement($key))) {
+ if (null !== $translator) {
+ $element->setTranslator($translator);
+ }
+ $valid = $element->isValid($value, $data) && $valid;
+ } elseif (null !== ($subForm = $this->getSubForm($key))) {
+ if (null !== $translator) {
+ $subForm->setTranslator($translator);
+ }
+ $valid = $subForm->isValidPartial($data[$key]) && $valid;
+ $validatedSubForms[] = $key;
+ }
+ }
+ foreach ($this->getSubForms() as $key => $subForm) {
+ if (!in_array($key, $validatedSubForms)) {
+ if (null !== $translator) {
+ $subForm->setTranslator($translator);
+ }
+
+ $valid = $subForm->isValidPartial($data) && $valid;
+ }
+ }
+
+ $this->_errorsExist = !$valid;
+ return $valid;
+ }
+
+ /**
+ * Process submitted AJAX data
+ *
+ * Checks if provided $data is valid, via {@link isValidPartial()}. If so,
+ * it returns JSON-encoded boolean true. If not, it returns JSON-encoded
+ * error messages (as returned by {@link getMessages()}).
+ *
+ * @param array $data
+ * @return string JSON-encoded boolean true or error messages
+ */
+ public function processAjax(array $data)
+ {
+ require_once 'Zend/Json.php';
+ if ($this->isValidPartial($data)) {
+ return Zend_Json::encode(true);
+ }
+ $messages = $this->getMessages();
+ return Zend_Json::encode($messages);
+ }
+
+ /**
+ * Add a custom error message to return in the event of failed validation
+ *
+ * @param string $message
+ * @return Zend_Form
+ */
+ public function addErrorMessage($message)
+ {
+ $this->_errorMessages[] = (string) $message;
+ return $this;
+ }
+
+ /**
+ * Add multiple custom error messages to return in the event of failed validation
+ *
+ * @param array $messages
+ * @return Zend_Form
+ */
+ public function addErrorMessages(array $messages)
+ {
+ foreach ($messages as $message) {
+ $this->addErrorMessage($message);
+ }
+ return $this;
+ }
+
+ /**
+ * Same as addErrorMessages(), but clears custom error message stack first
+ *
+ * @param array $messages
+ * @return Zend_Form
+ */
+ public function setErrorMessages(array $messages)
+ {
+ $this->clearErrorMessages();
+ return $this->addErrorMessages($messages);
+ }
+
+ /**
+ * Retrieve custom error messages
+ *
+ * @return array
+ */
+ public function getErrorMessages()
+ {
+ return $this->_errorMessages;
+ }
+
+ /**
+ * Clear custom error messages stack
+ *
+ * @return Zend_Form
+ */
+ public function clearErrorMessages()
+ {
+ $this->_errorMessages = array();
+ return $this;
+ }
+
+ /**
+ * Mark the element as being in a failed validation state
+ *
+ * @return Zend_Form
+ */
+ public function markAsError()
+ {
+ $this->_errorsExist = true;
+ $this->_errorsForced = true;
+ return $this;
+ }
+
+ /**
+ * Add an error message and mark element as failed validation
+ *
+ * @param string $message
+ * @return Zend_Form
+ */
+ public function addError($message)
+ {
+ $this->addErrorMessage($message);
+ $this->markAsError();
+ return $this;
+ }
+
+ /**
+ * Add multiple error messages and flag element as failed validation
+ *
+ * @param array $messages
+ * @return Zend_Form
+ */
+ public function addErrors(array $messages)
+ {
+ foreach ($messages as $message) {
+ $this->addError($message);
+ }
+ return $this;
+ }
+
+ /**
+ * Overwrite any previously set error messages and flag as failed validation
+ *
+ * @param array $messages
+ * @return Zend_Form
+ */
+ public function setErrors(array $messages)
+ {
+ $this->clearErrorMessages();
+ return $this->addErrors($messages);
+ }
+
+
+ public function persistData()
+ {
+ }
+
+ /**
+ * Are there errors in the form?
+ *
+ * @return bool
+ */
+ public function isErrors()
+ {
+ return $this->_errorsExist;
+ }
+
+ /**
+ * Get error codes for all elements failing validation
+ *
+ * @param string $name
+ * @return array
+ */
+ public function getErrors($name = null)
+ {
+ $errors = array();
+ if ((null !== $name) && isset($this->_elements[$name])) {
+ $errors = $this->getElement($name)->getErrors();
+ } elseif ((null !== $name) && isset($this->_subForms[$name])) {
+ $errors = $this->getSubForm($name)->getErrors();
+ } else {
+ foreach ($this->_elements as $key => $element) {
+ $errors[$key] = $element->getErrors();
+ }
+ foreach ($this->getSubForms() as $key => $subForm) {
+ $fErrors = $this->_attachToArray($subForm->getErrors(), $subForm->getElementsBelongTo());
+ $errors = array_merge($errors, $fErrors);
+ }
+ }
+ return $errors;
+ }
+
+ /**
+ * Retrieve error messages from elements failing validations
+ *
+ * @param string $name
+ * @param bool $suppressArrayNotation
+ * @return array
+ */
+ public function getMessages($name = null, $suppressArrayNotation = false)
+ {
+ if ((null !== $name) && isset($this->_elements[$name])) {
+ return $this->getElement($name)->getMessages();
+ }
+
+ if ((null !== $name) && isset($this->_subForms[$name])) {
+ return $this->getSubForm($name)->getMessages(null, true);
+ }
+
+ $arrayKeys = array();
+ foreach ($this->getSubForms() as $key => $subForm) {
+ $array = $this->_getArrayName($subForm->getElementsBelongTo());
+ if (!empty($array)) {
+ if ($name == $array) {
+ return $subForm->getMessages(null, true);
+ }
+ $arrayKeys[$key] = $subForm->getElementsBelongTo();
+ }
+ }
+
+ $customMessages = $this->_getErrorMessages();
+ if ($this->isErrors() && !empty($customMessages)) {
+ return $customMessages;
+ }
+
+ $messages = array();
+
+ foreach ($this->getElements() as $name => $element) {
+ $eMessages = $element->getMessages();
+ if (!empty($eMessages)) {
+ $messages[$name] = $eMessages;
+ }
+ }
+
+ foreach ($this->getSubForms() as $key => $subForm) {
+ $fMessages = $subForm->getMessages(null, true);
+ if (!empty($fMessages)) {
+ if (array_key_exists($key, $arrayKeys)) {
+ $fMessages = $this->_attachToArray($fMessages, $arrayKeys[$key]);
+ $messages = array_merge($messages, $fMessages);
+ } else {
+ $messages[$key] = $fMessages;
+ }
+ }
+ }
+
+ if (!$suppressArrayNotation && $this->isArray()) {
+ $messages = $this->_attachToArray($messages, $this->getElementsBelongTo());
+ }
+
+ return $messages;
+ }
+
+
+ // Rendering
+
+ /**
+ * Set view object
+ *
+ * @param Zend_View_Interface $view
+ * @return Zend_Form
+ */
+ public function setView(Zend_View_Interface $view = null)
+ {
+ $this->_view = $view;
+ return $this;
+ }
+
+ /**
+ * Retrieve view object
+ *
+ * If none registered, attempts to pull from ViewRenderer.
+ *
+ * @return Zend_View_Interface|null
+ */
+ public function getView()
+ {
+ if (null === $this->_view) {
+ require_once 'Zend/Controller/Action/HelperBroker.php';
+ $viewRenderer = Zend_Controller_Action_HelperBroker::getStaticHelper('viewRenderer');
+ $this->setView($viewRenderer->view);
+ }
+
+ return $this->_view;
+ }
+
+ /**
+ * Instantiate a decorator based on class name or class name fragment
+ *
+ * @param string $name
+ * @param null|array $options
+ * @return Zend_Form_Decorator_Interface
+ */
+ protected function _getDecorator($name, $options)
+ {
+ $class = $this->getPluginLoader(self::DECORATOR)->load($name);
+ if (null === $options) {
+ $decorator = new $class;
+ } else {
+ $decorator = new $class($options);
+ }
+
+ return $decorator;
+ }
+
+ /**
+ * Add a decorator for rendering the element
+ *
+ * @param string|Zend_Form_Decorator_Interface $decorator
+ * @param array|Zend_Config $options Options with which to initialize decorator
+ * @return Zend_Form
+ */
+ public function addDecorator($decorator, $options = null)
+ {
+ if ($decorator instanceof Zend_Form_Decorator_Interface) {
+ $name = get_class($decorator);
+ } elseif (is_string($decorator)) {
+ $name = $decorator;
+ $decorator = array(
+ 'decorator' => $name,
+ 'options' => $options,
+ );
+ } elseif (is_array($decorator)) {
+ foreach ($decorator as $name => $spec) {
+ break;
+ }
+ if (is_numeric($name)) {
+ require_once 'Zend/Form/Exception.php';
+ throw new Zend_Form_Exception('Invalid alias provided to addDecorator; must be alphanumeric string');
+ }
+ if (is_string($spec)) {
+ $decorator = array(
+ 'decorator' => $spec,
+ 'options' => $options,
+ );
+ } elseif ($spec instanceof Zend_Form_Decorator_Interface) {
+ $decorator = $spec;
+ }
+ } else {
+ require_once 'Zend/Form/Exception.php';
+ throw new Zend_Form_Exception('Invalid decorator provided to addDecorator; must be string or Zend_Form_Decorator_Interface');
+ }
+
+ $this->_decorators[$name] = $decorator;
+
+ return $this;
+ }
+
+ /**
+ * Add many decorators at once
+ *
+ * @param array $decorators
+ * @return Zend_Form
+ */
+ public function addDecorators(array $decorators)
+ {
+ foreach ($decorators as $decoratorInfo) {
+ if (is_string($decoratorInfo)) {
+ $this->addDecorator($decoratorInfo);
+ } elseif ($decoratorInfo instanceof Zend_Form_Decorator_Interface) {
+ $this->addDecorator($decoratorInfo);
+ } elseif (is_array($decoratorInfo)) {
+ $argc = count($decoratorInfo);
+ $options = array();
+ if (isset($decoratorInfo['decorator'])) {
+ $decorator = $decoratorInfo['decorator'];
+ if (isset($decoratorInfo['options'])) {
+ $options = $decoratorInfo['options'];
+ }
+ $this->addDecorator($decorator, $options);
+ } else {
+ switch (true) {
+ case (0 == $argc):
+ break;
+ case (1 <= $argc):
+ $decorator = array_shift($decoratorInfo);
+ case (2 <= $argc):
+ $options = array_shift($decoratorInfo);
+ default:
+ $this->addDecorator($decorator, $options);
+ break;
+ }
+ }
+ } else {
+ require_once 'Zend/Form/Exception.php';
+ throw new Zend_Form_Exception('Invalid decorator passed to addDecorators()');
+ }
+ }
+
+ return $this;
+ }
+
+ /**
+ * Overwrite all decorators
+ *
+ * @param array $decorators
+ * @return Zend_Form
+ */
+ public function setDecorators(array $decorators)
+ {
+ $this->clearDecorators();
+ return $this->addDecorators($decorators);
+ }
+
+ /**
+ * Retrieve a registered decorator
+ *
+ * @param string $name
+ * @return false|Zend_Form_Decorator_Abstract
+ */
+ public function getDecorator($name)
+ {
+ if (!isset($this->_decorators[$name])) {
+ $len = strlen($name);
+ foreach ($this->_decorators as $localName => $decorator) {
+ if ($len > strlen($localName)) {
+ continue;
+ }
+
+ if (0 === substr_compare($localName, $name, -$len, $len, true)) {
+ if (is_array($decorator)) {
+ return $this->_loadDecorator($decorator, $localName);
+ }
+ return $decorator;
+ }
+ }
+ return false;
+ }
+
+ if (is_array($this->_decorators[$name])) {
+ return $this->_loadDecorator($this->_decorators[$name], $name);
+ }
+
+ return $this->_decorators[$name];
+ }
+
+ /**
+ * Retrieve all decorators
+ *
+ * @return array
+ */
+ public function getDecorators()
+ {
+ foreach ($this->_decorators as $key => $value) {
+ if (is_array($value)) {
+ $this->_loadDecorator($value, $key);
+ }
+ }
+ return $this->_decorators;
+ }
+
+ /**
+ * Remove a single decorator
+ *
+ * @param string $name
+ * @return bool
+ */
+ public function removeDecorator($name)
+ {
+ $decorator = $this->getDecorator($name);
+ if ($decorator) {
+ if (array_key_exists($name, $this->_decorators)) {
+ unset($this->_decorators[$name]);
+ } else {
+ $class = get_class($decorator);
+ if (!array_key_exists($class, $this->_decorators)) {
+ return false;
+ }
+ unset($this->_decorators[$class]);
+ }
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Clear all decorators
+ *
+ * @return Zend_Form
+ */
+ public function clearDecorators()
+ {
+ $this->_decorators = array();
+ return $this;
+ }
+
+ /**
+ * Set all element decorators as specified
+ *
+ * @param array $decorators
+ * @param array|null $elements Specific elements to decorate or exclude from decoration
+ * @param bool $include Whether $elements is an inclusion or exclusion list
+ * @return Zend_Form
+ */
+ public function setElementDecorators(array $decorators, array $elements = null, $include = true)
+ {
+ if (is_array($elements)) {
+ if ($include) {
+ $elementObjs = array();
+ foreach ($elements as $name) {
+ if (null !== ($element = $this->getElement($name))) {
+ $elementObjs[] = $element;
+ }
+ }
+ } else {
+ $elementObjs = $this->getElements();
+ foreach ($elements as $name) {
+ if (array_key_exists($name, $elementObjs)) {
+ unset($elementObjs[$name]);
+ }
+ }
+ }
+ } else {
+ $elementObjs = $this->getElements();
+ }
+
+ foreach ($elementObjs as $element) {
+ $element->setDecorators($decorators);
+ }
+
+ $this->_elementDecorators = $decorators;
+
+ return $this;
+ }
+
+ /**
+ * Set all display group decorators as specified
+ *
+ * @param array $decorators
+ * @return Zend_Form
+ */
+ public function setDisplayGroupDecorators(array $decorators)
+ {
+ foreach ($this->getDisplayGroups() as $group) {
+ $group->setDecorators($decorators);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Set all subform decorators as specified
+ *
+ * @param array $decorators
+ * @return Zend_Form
+ */
+ public function setSubFormDecorators(array $decorators)
+ {
+ foreach ($this->getSubForms() as $form) {
+ $form->setDecorators($decorators);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Render form
+ *
+ * @param Zend_View_Interface $view
+ * @return string
+ */
+ public function render(Zend_View_Interface $view = null)
+ {
+ if (null !== $view) {
+ $this->setView($view);
+ }
+
+ $content = '';
+ foreach ($this->getDecorators() as $decorator) {
+ $decorator->setElement($this);
+ $content = $decorator->render($content);
+ }
+ return $content;
+ }
+
+ /**
+ * Serialize as string
+ *
+ * Proxies to {@link render()}.
+ *
+ * @return string
+ */
+ public function __toString()
+ {
+ try {
+ $return = $this->render();
+ return $return;
+ } catch (Exception $e) {
+ $message = "Exception caught by form: " . $e->getMessage()
+ . "\nStack Trace:\n" . $e->getTraceAsString();
+ trigger_error($message, E_USER_WARNING);
+ return '';
+ }
+ }
+
+
+ // Localization:
+
+ /**
+ * Set translator object
+ *
+ * @param Zend_Translate|Zend_Translate_Adapter|null $translator
+ * @return Zend_Form
+ */
+ public function setTranslator($translator = null)
+ {
+ if (null === $translator) {
+ $this->_translator = null;
+ } elseif ($translator instanceof Zend_Translate_Adapter) {
+ $this->_translator = $translator;
+ } elseif ($translator instanceof Zend_Translate) {
+ $this->_translator = $translator->getAdapter();
+ } else {
+ require_once 'Zend/Form/Exception.php';
+ throw new Zend_Form_Exception('Invalid translator specified');
+ }
+
+ return $this;
+ }
+
+ /**
+ * Set global default translator object
+ *
+ * @param Zend_Translate|Zend_Translate_Adapter|null $translator
+ * @return void
+ */
+ public static function setDefaultTranslator($translator = null)
+ {
+ if (null === $translator) {
+ self::$_translatorDefault = null;
+ } elseif ($translator instanceof Zend_Translate_Adapter) {
+ self::$_translatorDefault = $translator;
+ } elseif ($translator instanceof Zend_Translate) {
+ self::$_translatorDefault = $translator->getAdapter();
+ } else {
+ require_once 'Zend/Form/Exception.php';
+ throw new Zend_Form_Exception('Invalid translator specified');
+ }
+ }
+
+ /**
+ * Retrieve translator object
+ *
+ * @return Zend_Translate|null
+ */
+ public function getTranslator()
+ {
+ if ($this->translatorIsDisabled()) {
+ return null;
+ }
+
+ if (null === $this->_translator) {
+ return self::getDefaultTranslator();
+ }
+
+ return $this->_translator;
+ }
+
+ /**
+ * Get global default translator object
+ *
+ * @return null|Zend_Translate
+ */
+ public static function getDefaultTranslator()
+ {
+ if (null === self::$_translatorDefault) {
+ require_once 'Zend/Registry.php';
+ if (Zend_Registry::isRegistered('Zend_Translate')) {
+ $translator = Zend_Registry::get('Zend_Translate');
+ if ($translator instanceof Zend_Translate_Adapter) {
+ return $translator;
+ } elseif ($translator instanceof Zend_Translate) {
+ return $translator->getAdapter();
+ }
+ }
+ }
+ return self::$_translatorDefault;
+ }
+
+ /**
+ * Indicate whether or not translation should be disabled
+ *
+ * @param bool $flag
+ * @return Zend_Form
+ */
+ public function setDisableTranslator($flag)
+ {
+ $this->_translatorDisabled = (bool) $flag;
+ return $this;
+ }
+
+ /**
+ * Is translation disabled?
+ *
+ * @return bool
+ */
+ public function translatorIsDisabled()
+ {
+ return $this->_translatorDisabled;
+ }
+
+ /**
+ * Overloading: access to elements, form groups, and display groups
+ *
+ * @param string $name
+ * @return Zend_Form_Element|Zend_Form|null
+ */
+ public function __get($name)
+ {
+ if (isset($this->_elements[$name])) {
+ return $this->_elements[$name];
+ } elseif (isset($this->_subForms[$name])) {
+ return $this->_subForms[$name];
+ } elseif (isset($this->_displayGroups[$name])) {
+ return $this->_displayGroups[$name];
+ }
+
+ return null;
+ }
+
+ /**
+ * Overloading: access to elements, form groups, and display groups
+ *
+ * @param string $name
+ * @param Zend_Form_Element|Zend_Form $value
+ * @return void
+ * @throws Zend_Form_Exception for invalid $value
+ */
+ public function __set($name, $value)
+ {
+ if ($value instanceof Zend_Form_Element) {
+ $this->addElement($value, $name);
+ return;
+ } elseif ($value instanceof Zend_Form) {
+ $this->addSubForm($value, $name);
+ return;
+ } elseif (is_array($value)) {
+ $this->addDisplayGroup($value, $name);
+ return;
+ }
+
+ require_once 'Zend/Form/Exception.php';
+ if (is_object($value)) {
+ $type = get_class($value);
+ } else {
+ $type = gettype($value);
+ }
+ throw new Zend_Form_Exception('Only form elements and groups may be overloaded; variable of type "' . $type . '" provided');
+ }
+
+ /**
+ * Overloading: access to elements, form groups, and display groups
+ *
+ * @param string $name
+ * @return boolean
+ */
+ public function __isset($name)
+ {
+ if (isset($this->_elements[$name])
+ || isset($this->_subForms[$name])
+ || isset($this->_displayGroups[$name]))
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Overloading: access to elements, form groups, and display groups
+ *
+ * @param string $name
+ * @return void
+ */
+ public function __unset($name)
+ {
+ if (isset($this->_elements[$name])) {
+ unset($this->_elements[$name]);
+ } elseif (isset($this->_subForms[$name])) {
+ unset($this->_subForms[$name]);
+ } elseif (isset($this->_displayGroups[$name])) {
+ unset($this->_displayGroups[$name]);
+ }
+ }
+
+ /**
+ * Overloading: allow rendering specific decorators
+ *
+ * Call renderDecoratorName() to render a specific decorator.
+ *
+ * @param string $method
+ * @param array $args
+ * @return string
+ * @throws Zend_Form_Exception for invalid decorator or invalid method call
+ */
+ public function __call($method, $args)
+ {
+ if ('render' == substr($method, 0, 6)) {
+ $decoratorName = substr($method, 6);
+ if (false !== ($decorator = $this->getDecorator($decoratorName))) {
+ $decorator->setElement($this);
+ $seed = '';
+ if (0 < count($args)) {
+ $seed = array_shift($args);
+ }
+ return $decorator->render($seed);
+ }
+
+ require_once 'Zend/Form/Exception.php';
+ throw new Zend_Form_Exception(sprintf('Decorator by name %s does not exist', $decoratorName));
+ }
+
+ require_once 'Zend/Form/Exception.php';
+ throw new Zend_Form_Exception(sprintf('Method %s does not exist', $method));
+ }
+
+ // Interfaces: Iterator, Countable
+
+ /**
+ * Current element/subform/display group
+ *
+ * @return Zend_Form_Element|Zend_Form_DisplayGroup|Zend_Form
+ */
+ public function current()
+ {
+ $this->_sort();
+ current($this->_order);
+ $key = key($this->_order);
+
+ if (isset($this->_elements[$key])) {
+ return $this->getElement($key);
+ } elseif (isset($this->_subForms[$key])) {
+ return $this->getSubForm($key);
+ } elseif (isset($this->_displayGroups[$key])) {
+ return $this->getDisplayGroup($key);
+ } else {
+ require_once 'Zend/Form/Exception.php';
+ throw new Zend_Form_Exception(sprintf('Corruption detected in form; invalid key ("%s") found in internal iterator', (string) $key));
+ }
+ }
+
+ /**
+ * Current element/subform/display group name
+ *
+ * @return string
+ */
+ public function key()
+ {
+ $this->_sort();
+ return key($this->_order);
+ }
+
+ /**
+ * Move pointer to next element/subform/display group
+ *
+ * @return void
+ */
+ public function next()
+ {
+ $this->_sort();
+ next($this->_order);
+ }
+
+ /**
+ * Move pointer to beginning of element/subform/display group loop
+ *
+ * @return void
+ */
+ public function rewind()
+ {
+ $this->_sort();
+ reset($this->_order);
+ }
+
+ /**
+ * Determine if current element/subform/display group is valid
+ *
+ * @return bool
+ */
+ public function valid()
+ {
+ $this->_sort();
+ return (current($this->_order) !== false);
+ }
+
+ /**
+ * Count of elements/subforms that are iterable
+ *
+ * @return int
+ */
+ public function count()
+ {
+ return count($this->_order);
+ }
+
+ /**
+ * Set flag to disable loading default decorators
+ *
+ * @param bool $flag
+ * @return Zend_Form
+ */
+ public function setDisableLoadDefaultDecorators($flag)
+ {
+ $this->_disableLoadDefaultDecorators = (bool) $flag;
+ return $this;
+ }
+
+ /**
+ * Should we load the default decorators?
+ *
+ * @return bool
+ */
+ public function loadDefaultDecoratorsIsDisabled()
+ {
+ return $this->_disableLoadDefaultDecorators;
+ }
+
+ /**
+ * Load the default decorators
+ *
+ * @return void
+ */
+ public function loadDefaultDecorators()
+ {
+ if ($this->loadDefaultDecoratorsIsDisabled()) {
+ return;
+ }
+
+ $decorators = $this->getDecorators();
+ if (empty($decorators)) {
+ $this->addDecorator('FormElements')
+ ->addDecorator('HtmlTag', array('tag' => 'dl', 'class' => 'zend_form'))
+ ->addDecorator('Form');
+ }
+ }
+
+ /**
+ * Sort items according to their order
+ *
+ * @return void
+ */
+ protected function _sort()
+ {
+ if ($this->_orderUpdated) {
+ $items = array();
+ $index = 0;
+ foreach ($this->_order as $key => $order) {
+ if (null === $order) {
+ if (null === ($order = $this->{$key}->getOrder())) {
+ while (array_search($index, $this->_order, true)) {
+ ++$index;
+ }
+ $items[$index] = $key;
+ ++$index;
+ } else {
+ $items[$order] = $key;
+ }
+ } else {
+ $items[$order] = $key;
+ }
+ }
+
+ $items = array_flip($items);
+ asort($items);
+ $this->_order = $items;
+ $this->_orderUpdated = false;
+ }
+ }
+
+ /**
+ * Lazy-load a decorator
+ *
+ * @param array $decorator Decorator type and options
+ * @param mixed $name Decorator name or alias
+ * @return Zend_Form_Decorator_Interface
+ */
+ protected function _loadDecorator(array $decorator, $name)
+ {
+ $sameName = false;
+ if ($name == $decorator['decorator']) {
+ $sameName = true;
+ }
+
+ $instance = $this->_getDecorator($decorator['decorator'], $decorator['options']);
+ if ($sameName) {
+ $newName = get_class($instance);
+ $decoratorNames = array_keys($this->_decorators);
+ $order = array_flip($decoratorNames);
+ $order[$newName] = $order[$name];
+ $decoratorsExchange = array();
+ unset($order[$name]);
+ asort($order);
+ foreach ($order as $key => $index) {
+ if ($key == $newName) {
+ $decoratorsExchange[$key] = $instance;
+ continue;
+ }
+ $decoratorsExchange[$key] = $this->_decorators[$key];
+ }
+ $this->_decorators = $decoratorsExchange;
+ } else {
+ $this->_decorators[$name] = $instance;
+ }
+
+ return $instance;
+ }
+
+ /**
+ * Retrieve optionally translated custom error messages
+ *
+ * @return array
+ */
+ protected function _getErrorMessages()
+ {
+ $messages = $this->getErrorMessages();
+ $translator = $this->getTranslator();
+ if (null !== $translator) {
+ foreach ($messages as $key => $message) {
+ $messages[$key] = $translator->translate($message);
+ }
+ }
+ return $messages;
+ }
+}
*
* @category Zend
* @package Zend_Gdata
- * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @subpackage Gdata
+ * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
+ * @version $Id$
*/
/**
* Subclasses exist to implement service-specific features
*
* As the Google data API protocol is based upon the Atom Publishing Protocol
- * (APP), GData functionality extends the appropriate Zend_Gdata_App classes
+ * (APP), Gdata functionality extends the appropriate Zend_Gdata_App classes
*
* @link http://code.google.com/apis/gdata/overview.html
*
* @category Zend
* @package Zend_Gdata
- * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @subpackage Gdata
+ * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Gdata extends Zend_Gdata_App
'Zend_Gdata_App');
/**
- * Namespaces used for GData data
+ * Namespaces used for Gdata data
*
* @var array
*/
public static $namespaces = array(
- 'openSearch' => 'http://a9.com/-/spec/opensearchrss/1.0/',
- 'rss' => 'http://blogs.law.harvard.edu/tech/rss',
- 'gd' => 'http://schemas.google.com/g/2005');
+ array('gd', 'http://schemas.google.com/g/2005', 1, 0),
+ array('openSearch', 'http://a9.com/-/spec/opensearchrss/1.0/', 1, 0),
+ array('openSearch', 'http://a9.com/-/spec/opensearch/1.1/', 2, 0),
+ array('rss', 'http://blogs.law.harvard.edu/tech/rss', 1, 0)
+ );
/**
* Client object used to communicate
* Create Gdata object
*
* @param Zend_Http_Client $client
- * @param string $applicationId The identity of the app in the form of Company-AppName-Version
+ * @param string $applicationId The identity of the app in the form of
+ * Company-AppName-Version
*/
public function __construct($client = null, $applicationId = 'MyCompany-MyApp-1.0')
{
* @param Zend_Http_Client $client The client used for communication
* @param string $className The class which is used as the return type
* @throws Zend_Gdata_App_Exception
- * @return Zend_Gdata_App_Feed
+ * @return string|Zend_Gdata_App_Feed Returns string only if the object
+ * mapping has been disabled explicitly
+ * by passing false to the
+ * useObjectMapping() function.
*/
- public static function import($uri, $client = null, $className='Zend_Gdata_Feed')
+ public static function import($uri, $client = null,
+ $className='Zend_Gdata_Feed')
{
$app = new Zend_Gdata($client);
$requestData = $app->decodeRequest('GET', $uri);
$response = $app->performHttpRequest($requestData['method'], $requestData['url']);
$feedContent = $response->getBody();
+
$feed = self::importString($feedContent, $className);
if ($client != null) {
$feed->setHttpClient($client);
}
/**
- * Retreive feed object
+ * Retrieve feed as string or object
*
* @param mixed $location The location as string or Zend_Gdata_Query
* @param string $className The class type to use for returning the feed
* @throws Zend_Gdata_App_InvalidArgumentException
- * @return Zend_Gdata_Feed
+ * @return string|Zend_Gdata_App_Feed Returns string only if the object
+ * mapping has been disabled explicitly
+ * by passing false to the
+ * useObjectMapping() function.
*/
public function getFeed($location, $className='Zend_Gdata_Feed')
{
}
/**
- * Retreive entry object
+ * Retrieve entry as string or object
*
* @param mixed $location The location as string or Zend_Gdata_Query
- * @return Zend_Gdata_Feed
+ * @throws Zend_Gdata_App_InvalidArgumentException
+ * @return string|Zend_Gdata_App_Entry Returns string only if the object
+ * mapping has been disabled explicitly
+ * by passing false to the
+ * useObjectMapping() function.
*/
public function getEntry($location, $className='Zend_Gdata_Entry')
{
/**
* Performs a HTTP request using the specified method.
- *
+ *
* Overrides the definition in the parent (Zend_Gdata_App)
* and uses the Zend_Gdata_HttpClient functionality
* to filter the HTTP requests and responses.
- *
+ *
* @param string $method The HTTP method for the request -
* 'GET', 'POST', 'PUT', 'DELETE'
* @param string $url The URL to which this request is being performed,
}
}
+ /**
+ * Determines whether service object is authenticated.
+ *
+ * @return boolean True if service object is authenticated, false otherwise.
+ */
+ public function isAuthenticated()
+ {
+ $client = parent::getHttpClient();
+ if ($client->getClientLoginToken() ||
+ $client->getAuthSubToken()) {
+ return true;
+ }
+
+ return false;
+ }
+
}
--- /dev/null
+<?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_InfoCard
+ * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ * @version $Id$
+ */
+
+/**
+ * Zend_InfoCard_Xml_EncryptedData
+ */
+require_once 'Zend/InfoCard/Xml/EncryptedData.php';
+
+/**
+ * Zend_InfoCard_Xml_Assertion
+ */
+require_once 'Zend/InfoCard/Xml/Assertion.php';
+
+/**
+ * Zend_InfoCard_Cipher
+ */
+require_once 'Zend/InfoCard/Cipher.php';
+
+/**
+ * Zend_InfoCard_Xml_Security
+ */
+require_once 'Zend/InfoCard/Xml/Security.php';
+
+/**
+ * Zend_InfoCard_Adapter_Interface
+ */
+require_once 'Zend/InfoCard/Adapter/Interface.php';
+
+/**
+ * Zend_InfoCard_Claims
+ */
+require_once 'Zend/InfoCard/Claims.php';
+
+/**
+ * @category Zend
+ * @package Zend_InfoCard
+ * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+class Zend_InfoCard
+{
+ /**
+ * URI for XML Digital Signature SHA1 Digests
+ */
+ const DIGEST_SHA1 = 'http://www.w3.org/2000/09/xmldsig#sha1';
+
+ /**
+ * An array of certificate pair files and optional passwords for them to search
+ * when trying to determine which certificate was used to encrypt the transient key
+ *
+ * @var Array
+ */
+ protected $_keyPairs;
+
+ /**
+ * The instance to use to decrypt public-key encrypted data
+ *
+ * @var Zend_InfoCard_Cipher_Pki_Interface
+ */
+ protected $_pkiCipherObj;
+
+ /**
+ * The instance to use to decrypt symmetric encrypted data
+ *
+ * @var Zend_InfoCard_Cipher_Symmetric_Interface
+ */
+ protected $_symCipherObj;
+
+ /**
+ * The InfoCard Adapter to use for callbacks into the application using the component
+ * such as when storing assertions, etc.
+ *
+ * @var Zend_InfoCard_Adapter_Interface
+ */
+ protected $_adapter;
+
+
+ /**
+ * InfoCard Constructor
+ *
+ * @throws Zend_InfoCard_Exception
+ */
+ public function __construct()
+ {
+ $this->_keyPairs = array();
+
+ if(!extension_loaded('mcrypt')) {
+ require_once 'Zend/InfoCard/Exception.php';
+ throw new Zend_InfoCard_Exception("Use of the Zend_InfoCard component requires the mcrypt extension to be enabled in PHP");
+ }
+
+ if(!extension_loaded('openssl')) {
+ require_once 'Zend/InfoCard/Exception.php';
+ throw new Zend_InfoCard_Exception("Use of the Zend_InfoCard component requires the openssl extension to be enabled in PHP");
+ }
+ }
+
+ /**
+ * Sets the adapter uesd for callbacks into the application using the component, used
+ * when doing things such as storing / retrieving assertions, etc.
+ *
+ * @param Zend_InfoCard_Adapter_Interface $a The Adapter instance
+ * @return Zend_InfoCard The instnace
+ */
+ public function setAdapter(Zend_InfoCard_Adapter_Interface $a)
+ {
+ $this->_adapter = $a;
+ return $this;
+ }
+
+ /**
+ * Retrieves the adapter used for callbacks into the application using the component.
+ * If no adapter was set then an instance of Zend_InfoCard_Adapter_Default is used
+ *
+ * @return Zend_InfoCard_Adapter_Interface The Adapter instance
+ */
+ public function getAdapter()
+ {
+ if($this->_adapter === null) {
+ require_once 'Zend/InfoCard/Adapter/Default.php';
+ $this->setAdapter(new Zend_InfoCard_Adapter_Default());
+ }
+
+ return $this->_adapter;
+ }
+
+ /**
+ * Gets the Public Key Cipher object used in this instance
+ *
+ * @return Zend_InfoCard_Cipher_Pki_Interface
+ */
+ public function getPkiCipherObject()
+ {
+ return $this->_pkiCipherObj;
+ }
+
+ /**
+ * Sets the Public Key Cipher Object used in this instance
+ *
+ * @param Zend_InfoCard_Cipher_Pki_Interface $cipherObj
+ * @return Zend_InfoCard
+ */
+ public function setPkiCipherObject(Zend_InfoCard_Cipher_Pki_Interface $cipherObj)
+ {
+ $this->_pkiCipherObj = $cipherObj;
+ return $this;
+ }
+
+ /**
+ * Get the Symmetric Cipher Object used in this instance
+ *
+ * @return Zend_InfoCard_Cipher_Symmetric_Interface
+ */
+ public function getSymCipherObject()
+ {
+ return $this->_symCipherObj;
+ }
+
+ /**
+ * Sets the Symmetric Cipher Object used in this instance
+ *
+ * @param Zend_InfoCard_Cipher_Symmetric_Interface $cipherObj
+ * @return Zend_InfoCard
+ */
+ public function setSymCipherObject($cipherObj)
+ {
+ $this->_symCipherObj = $cipherObj;
+ return $this;
+ }
+
+ /**
+ * Remove a Certificate Pair by Key ID from the search list
+ *
+ * @throws Zend_InfoCard_Exception
+ * @param string $key_id The Certificate Key ID returned from adding the certificate pair
+ * @return Zend_InfoCard
+ */
+ public function removeCertificatePair($key_id)
+ {
+
+ if(!key_exists($key_id, $this->_keyPairs)) {
+ require_once 'Zend/InfoCard/Exception.php';
+ throw new Zend_InfoCard_Exception("Attempted to remove unknown key id: $key_id");
+ }
+
+ unset($this->_keyPairs[$key_id]);
+ return $this;
+ }
+
+ /**
+ * Add a Certificate Pair to the list of certificates searched by the component
+ *
+ * @throws Zend_InfoCard_Exception
+ * @param string $private_key_file The path to the private key file for the pair
+ * @param string $public_key_file The path to the certificate / public key for the pair
+ * @param string $type (optional) The URI for the type of key pair this is (default RSA with OAEP padding)
+ * @param string $password (optional) The password for the private key file if necessary
+ * @return string A key ID representing this key pair in the component
+ */
+ public function addCertificatePair($private_key_file, $public_key_file, $type = Zend_InfoCard_Cipher::ENC_RSA_OAEP_MGF1P, $password = null)
+ {
+ if(!file_exists($private_key_file) ||
+ !file_exists($public_key_file)) {
+ require_once 'Zend/InfoCard/Exception.php';
+ throw new Zend_InfoCard_Exception("Could not locate the public and private certificate pair files: $private_key_file, $public_key_file");
+ }
+
+ if(!is_readable($private_key_file) ||
+ !is_readable($public_key_file)) {
+ require_once 'Zend/InfoCard/Exception.php';
+ throw new Zend_InfoCard_Exception("Could not read the public and private certificate pair files (check permissions): $private_key_file, $public_key_file");
+ }
+
+ $key_id = md5($private_key_file.$public_key_file);
+
+ if(key_exists($key_id, $this->_keyPairs)) {
+ require_once 'Zend/InfoCard/Exception.php';
+ throw new Zend_InfoCard_Exception("Attempted to add previously existing certificate pair: $private_key_file, $public_key_file");
+ }
+
+ switch($type) {
+ case Zend_InfoCard_Cipher::ENC_RSA:
+ case Zend_InfoCard_Cipher::ENC_RSA_OAEP_MGF1P:
+ $this->_keyPairs[$key_id] = array('private' => $private_key_file,
+ 'public' => $public_key_file,
+ 'type_uri' => $type);
+
+ if($password !== null) {
+ $this->_keyPairs[$key_id]['password'] = $password;
+ } else {
+ $this->_keyPairs[$key_id]['password'] = null;
+ }
+
+ return $key_id;
+ break;
+ default:
+ require_once 'Zend/InfoCard/Exception.php';
+ throw new Zend_InfoCard_Exception("Invalid Certificate Pair Type specified: $type");
+ }
+ }
+
+ /**
+ * Return a Certificate Pair from a key ID
+ *
+ * @throws Zend_InfoCard_Exception
+ * @param string $key_id The Key ID of the certificate pair in the component
+ * @return array An array containing the path to the private/public key files,
+ * the type URI and the password if provided
+ */
+ public function getCertificatePair($key_id)
+ {
+ if(key_exists($key_id, $this->_keyPairs)) {
+ return $this->_keyPairs[$key_id];
+ }
+
+ require_once 'Zend/InfoCard/Exception.php';
+ throw new Zend_InfoCard_Exception("Invalid Certificate Pair ID provided: $key_id");
+ }
+
+ /**
+ * Retrieve the digest of a given public key / certificate using the provided digest
+ * method
+ *
+ * @throws Zend_InfoCard_Exception
+ * @param string $key_id The certificate key id in the component
+ * @param string $digestMethod The URI of the digest method to use (default SHA1)
+ * @return string The digest value in binary format
+ */
+ protected function _getPublicKeyDigest($key_id, $digestMethod = self::DIGEST_SHA1)
+ {
+ $certificatePair = $this->getCertificatePair($key_id);
+
+ $temp = file($certificatePair['public']);
+ unset($temp[count($temp)-1]);
+ unset($temp[0]);
+ $certificateData = base64_decode(implode("\n", $temp));
+
+ switch($digestMethod) {
+ case self::DIGEST_SHA1:
+ $digest_retval = sha1($certificateData, true);
+ break;
+ default:
+ require_once 'Zend/InfoCard/Exception.php';
+ throw new Zend_InfoCard_Exception("Invalid Digest Type Provided: $digestMethod");
+ }
+
+ return $digest_retval;
+ }
+
+ /**
+ * Find a certificate pair based on a digest of its public key / certificate file
+ *
+ * @param string $digest The digest value of the public key wanted in binary form
+ * @param string $digestMethod The URI of the digest method used to calculate the digest
+ * @return mixed The Key ID of the matching certificate pair or false if not found
+ */
+ protected function _findCertifiatePairByDigest($digest, $digestMethod = self::DIGEST_SHA1)
+ {
+
+ foreach($this->_keyPairs as $key_id => $certificate_data) {
+
+ $cert_digest = $this->_getPublicKeyDigest($key_id, $digestMethod);
+
+ if($cert_digest == $digest) {
+ return $key_id;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Extracts the Signed Token from an EncryptedData block
+ *
+ * @throws Zend_InfoCard_Exception
+ * @param string $strXmlToken The EncryptedData XML block
+ * @return string The XML of the Signed Token inside of the EncryptedData block
+ */
+ protected function _extractSignedToken($strXmlToken)
+ {
+ $encryptedData = Zend_InfoCard_Xml_EncryptedData::getInstance($strXmlToken);
+
+ // Determine the Encryption Method used to encrypt the token
+
+ switch($encryptedData->getEncryptionMethod()) {
+ case Zend_InfoCard_Cipher::ENC_AES128CBC:
+ case Zend_InfoCard_Cipher::ENC_AES256CBC:
+ break;
+ default:
+ require_once 'Zend/InfoCard/Exception.php';
+ throw new Zend_InfoCard_Exception("Unknown Encryption Method used in the secure token");
+ }
+
+ // Figure out the Key we are using to decrypt the token
+
+ $keyinfo = $encryptedData->getKeyInfo();
+
+ if(!($keyinfo instanceof Zend_InfoCard_Xml_KeyInfo_XmlDSig)) {
+ require_once 'Zend/InfoCard/Exception.php';
+ throw new Zend_InfoCard_Exception("Expected a XML digital signature KeyInfo, but was not found");
+ }
+
+
+ $encryptedKey = $keyinfo->getEncryptedKey();
+
+ switch($encryptedKey->getEncryptionMethod()) {
+ case Zend_InfoCard_Cipher::ENC_RSA:
+ case Zend_InfoCard_Cipher::ENC_RSA_OAEP_MGF1P:
+ break;
+ default:
+ require_once 'Zend/InfoCard/Exception.php';
+ throw new Zend_InfoCard_Exception("Unknown Key Encryption Method used in secure token");
+ }
+
+ $securityTokenRef = $encryptedKey->getKeyInfo()->getSecurityTokenReference();
+
+ $key_id = $this->_findCertifiatePairByDigest($securityTokenRef->getKeyReference());
+
+ if(!$key_id) {
+ require_once 'Zend/InfoCard/Exception.php';
+ throw new Zend_InfoCard_Exception("Unable to find key pair used to encrypt symmetric InfoCard Key");
+ }
+
+ $certificate_pair = $this->getCertificatePair($key_id);
+
+ // Santity Check
+
+ if($certificate_pair['type_uri'] != $encryptedKey->getEncryptionMethod()) {
+ require_once 'Zend/InfoCard/Exception.php';
+ throw new Zend_InfoCard_Exception("Certificate Pair which matches digest is not of same algorithm type as document, check addCertificate()");
+ }
+
+ $PKcipher = Zend_InfoCard_Cipher::getInstanceByURI($encryptedKey->getEncryptionMethod());
+
+ $base64DecodeSupportsStrictParam = version_compare(PHP_VERSION, '5.2.0', '>=');
+
+ if ($base64DecodeSupportsStrictParam) {
+ $keyCipherValueBase64Decoded = base64_decode($encryptedKey->getCipherValue(), true);
+ } else {
+ $keyCipherValueBase64Decoded = base64_decode($encryptedKey->getCipherValue());
+ }
+
+ $symmetricKey = $PKcipher->decrypt(
+ $keyCipherValueBase64Decoded,
+ file_get_contents($certificate_pair['private']),
+ $certificate_pair['password']
+ );
+
+ $symCipher = Zend_InfoCard_Cipher::getInstanceByURI($encryptedData->getEncryptionMethod());
+
+ if ($base64DecodeSupportsStrictParam) {
+ $dataCipherValueBase64Decoded = base64_decode($encryptedData->getCipherValue(), true);
+ } else {
+ $dataCipherValueBase64Decoded = base64_decode($encryptedData->getCipherValue());
+ }
+
+ $signedToken = $symCipher->decrypt($dataCipherValueBase64Decoded, $symmetricKey);
+
+ return $signedToken;
+ }
+
+ /**
+ * Process an input Infomation Card EncryptedData block sent from the client,
+ * validate it, and return the claims contained within it on success or an error message on error
+ *
+ * @param string $strXmlToken The XML token sent to the server from the client
+ * @return Zend_Infocard_Claims The Claims object containing the claims, or any errors which occurred
+ */
+ public function process($strXmlToken)
+ {
+
+ $retval = new Zend_InfoCard_Claims();
+
+ require_once 'Zend/InfoCard/Exception.php';
+ try {
+ $signedAssertionsXml = $this->_extractSignedToken($strXmlToken);
+ } catch(Zend_InfoCard_Exception $e) {
+ $retval->setError('Failed to extract assertion document');
+ $retval->setCode(Zend_InfoCard_Claims::RESULT_PROCESSING_FAILURE);
+ return $retval;
+ }
+
+ try {
+ $assertions = Zend_InfoCard_Xml_Assertion::getInstance($signedAssertionsXml);
+ } catch(Zend_InfoCard_Exception $e) {
+ $retval->setError('Failure processing assertion document');
+ $retval->setCode(Zend_InfoCard_Claims::RESULT_PROCESSING_FAILURE);
+ return $retval;
+ }
+
+ if(!($assertions instanceof Zend_InfoCard_Xml_Assertion_Interface)) {
+ throw new Zend_InfoCard_Exception("Invalid Assertion Object returned");
+ }
+
+ if(!($reference_id = Zend_InfoCard_Xml_Security::validateXMLSignature($assertions->asXML()))) {
+ $retval->setError("Failure Validating the Signature of the assertion document");
+ $retval->setCode(Zend_InfoCard_Claims::RESULT_VALIDATION_FAILURE);
+ return $retval;
+ }
+
+ // The reference id should be locally scoped as far as I know
+ if($reference_id[0] == '#') {
+ $reference_id = substr($reference_id, 1);
+ } else {
+ $retval->setError("Reference of document signature does not reference the local document");
+ $retval->setCode(Zend_InfoCard_Claims::RESULT_VALIDATION_FAILURE);
+ return $retval;
+ }
+
+ // Make sure the signature is in reference to the same document as the assertions
+ if($reference_id != $assertions->getAssertionID()) {
+ $retval->setError("Reference of document signature does not reference the local document");
+ $retval->setCode(Zend_InfoCard_Claims::RESULT_VALIDATION_FAILURE);
+ }
+
+ // Validate we haven't seen this before and the conditions are acceptable
+ $conditions = $this->getAdapter()->retrieveAssertion($assertions->getAssertionURI(), $assertions->getAssertionID());
+
+ if($conditions === false) {
+ $conditions = $assertions->getConditions();
+ }
+
+
+ if(is_array($condition_error = $assertions->validateConditions($conditions))) {
+ $retval->setError("Conditions of assertion document are not met: {$condition_error[1]} ({$condition_error[0]})");
+ $retval->setCode(Zend_InfoCard_Claims::RESULT_VALIDATION_FAILURE);
+ }
+
+ $attributes = $assertions->getAttributes();
+
+ $retval->setClaims($attributes);
+
+ if($retval->getCode() == 0) {
+ $retval->setCode(Zend_InfoCard_Claims::RESULT_SUCCESS);
+ }
+
+ return $retval;
+ }
+}
--- /dev/null
+<?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_Json
+ * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ * @version $Id$
+ */
+
+/**
+ * Zend_Json_Expr.
+ *
+ * @see Zend_Json_Expr
+ */
+require_once 'Zend/Json/Expr.php';
+
+
+/**
+ * Class for encoding to and decoding from JSON.
+ *
+ * @category Zend
+ * @package Zend_Json
+ * @uses Zend_Json_Expr
+ * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+class Zend_Json
+{
+ /**
+ * How objects should be encoded -- arrays or as StdClass. TYPE_ARRAY is 1
+ * so that it is a boolean true value, allowing it to be used with
+ * ext/json's functions.
+ */
+ const TYPE_ARRAY = 1;
+ const TYPE_OBJECT = 0;
+
+ /**
+ * To check the allowed nesting depth of the XML tree during xml2json conversion.
+ *
+ * @var int
+ */
+ public static $maxRecursionDepthAllowed=25;
+
+ /**
+ * @var bool
+ */
+ public static $useBuiltinEncoderDecoder = false;
+
+ /**
+ * Decodes the given $encodedValue string which is
+ * encoded in the JSON format
+ *
+ * Uses ext/json's json_decode if available.
+ *
+ * @param string $encodedValue Encoded in JSON format
+ * @param int $objectDecodeType Optional; flag indicating how to decode
+ * objects. See {@link Zend_Json_Decoder::decode()} for details.
+ * @return mixed
+ */
+ public static function decode($encodedValue, $objectDecodeType = Zend_Json::TYPE_ARRAY)
+ {
+ if (function_exists('json_decode') && self::$useBuiltinEncoderDecoder !== true) {
+ return json_decode($encodedValue, $objectDecodeType);
+ }
+
+ require_once 'Zend/Json/Decoder.php';
+ return Zend_Json_Decoder::decode($encodedValue, $objectDecodeType);
+ }
+
+ /**
+ * Encode the mixed $valueToEncode into the JSON format
+ *
+ * Encodes using ext/json's json_encode() if available.
+ *
+ * NOTE: Object should not contain cycles; the JSON format
+ * does not allow object reference.
+ *
+ * NOTE: Only public variables will be encoded
+ *
+ * NOTE: Encoding native javascript expressions are possible using Zend_Json_Expr.
+ * You can enable this by setting $options['enableJsonExprFinder'] = true
+ *
+ * @see Zend_Json_Expr
+ *
+ * @param mixed $valueToEncode
+ * @param boolean $cycleCheck Optional; whether or not to check for object recursion; off by default
+ * @param array $options Additional options used during encoding
+ * @return string JSON encoded object
+ */
+ public static function encode($valueToEncode, $cycleCheck = false, $options = array())
+ {
+ if (is_object($valueToEncode) && method_exists($valueToEncode, 'toJson')) {
+ return $valueToEncode->toJson();
+ }
+
+ // Pre-encoding look for Zend_Json_Expr objects and replacing by tmp ids
+ $javascriptExpressions = array();
+ if(isset($options['enableJsonExprFinder'])
+ && ($options['enableJsonExprFinder'] == true)
+ ) {
+ /**
+ * @see Zend_Json_Encoder
+ */
+ require_once "Zend/Json/Encoder.php";
+ $valueToEncode = self::_recursiveJsonExprFinder($valueToEncode, $javascriptExpressions);
+ }
+
+ // Encoding
+ if (function_exists('json_encode') && self::$useBuiltinEncoderDecoder !== true) {
+ $encodedResult = json_encode($valueToEncode);
+ } else {
+ require_once 'Zend/Json/Encoder.php';
+ $encodedResult = Zend_Json_Encoder::encode($valueToEncode, $cycleCheck, $options);
+ }
+
+ //only do post-proccessing to revert back the Zend_Json_Expr if any.
+ if (count($javascriptExpressions) > 0) {
+ $count = count($javascriptExpressions);
+ for($i = 0; $i < $count; $i++) {
+ $magicKey = $javascriptExpressions[$i]['magicKey'];
+ $value = $javascriptExpressions[$i]['value'];
+
+ $encodedResult = str_replace(
+ //instead of replacing "key:magicKey", we replace directly magicKey by value because "key" never changes.
+ '"' . $magicKey . '"',
+ $value,
+ $encodedResult
+ );
+ }
+ }
+
+ return $encodedResult;
+ }
+
+ /**
+ * Check & Replace Zend_Json_Expr for tmp ids in the valueToEncode
+ *
+ * Check if the value is a Zend_Json_Expr, and if replace its value
+ * with a magic key and save the javascript expression in an array.
+ *
+ * NOTE this method is recursive.
+ *
+ * NOTE: This method is used internally by the encode method.
+ *
+ * @see encode
+ * @param mixed $valueToCheck a string - object property to be encoded
+ * @return void
+ */
+ protected static function _recursiveJsonExprFinder(
+ &$value, array &$javascriptExpressions, $currentKey = null
+ ) {
+ if ($value instanceof Zend_Json_Expr) {
+ // TODO: Optimize with ascii keys, if performance is bad
+ $magicKey = "____" . $currentKey . "_" . (count($javascriptExpressions));
+ $javascriptExpressions[] = array(
+
+ //if currentKey is integer, encodeUnicodeString call is not required.
+ "magicKey" => (is_int($currentKey)) ? $magicKey : Zend_Json_Encoder::encodeUnicodeString($magicKey),
+ "value" => $value->__toString(),
+ );
+ $value = $magicKey;
+ } elseif (is_array($value)) {
+ foreach ($value as $k => $v) {
+ $value[$k] = self::_recursiveJsonExprFinder($value[$k], $javascriptExpressions, $k);
+ }
+ } elseif (is_object($value)) {
+ foreach ($value as $k => $v) {
+ $value->$k = self::_recursiveJsonExprFinder($value->$k, $javascriptExpressions, $k);
+ }
+ }
+ return $value;
+ }
+
+ /**
+ * fromXml - Converts XML to JSON
+ *
+ * Converts a XML formatted string into a JSON formatted string.
+ * The value returned will be a string in JSON format.
+ *
+ * The caller of this function needs to provide only the first parameter,
+ * which is an XML formatted String. The second parameter is optional, which
+ * lets the user to select if the XML attributes in the input XML string
+ * should be included or ignored in xml2json conversion.
+ *
+ * This function converts the XML formatted string into a PHP array by
+ * calling a recursive (protected static) function in this class. Then, it
+ * converts that PHP array into JSON by calling the "encode" static funcion.
+ *
+ * Throws a Zend_Json_Exception if the input not a XML formatted string.
+ * NOTE: Encoding native javascript expressions via Zend_Json_Expr is not possible.
+ *
+ * @static
+ * @access public
+ * @param string $xmlStringContents XML String to be converted
+ * @param boolean $ignoreXmlAttributes Include or exclude XML attributes in
+ * the xml2json conversion process.
+ * @return mixed - JSON formatted string on success
+ * @throws Zend_Json_Exception
+ */
+ public static function fromXml ($xmlStringContents, $ignoreXmlAttributes=true) {
+ // Load the XML formatted string into a Simple XML Element object.
+ $simpleXmlElementObject = simplexml_load_string($xmlStringContents);
+
+ // If it is not a valid XML content, throw an exception.
+ if ($simpleXmlElementObject == null) {
+ require_once 'Zend/Json/Exception.php';
+ throw new Zend_Json_Exception('Function fromXml was called with an invalid XML formatted string.');
+ } // End of if ($simpleXmlElementObject == null)
+
+ $resultArray = null;
+
+ // Call the recursive function to convert the XML into a PHP array.
+ $resultArray = self::_processXml($simpleXmlElementObject, $ignoreXmlAttributes);
+
+ // Convert the PHP array to JSON using Zend_Json encode method.
+ // It is just that simple.
+ $jsonStringOutput = self::encode($resultArray);
+ return($jsonStringOutput);
+ } // End of function fromXml.
+
+ /**
+ * _processXml - Contains the logic for xml2json
+ *
+ * The logic in this function is a recursive one.
+ *
+ * The main caller of this function (i.e. fromXml) needs to provide
+ * only the first two parameters i.e. the SimpleXMLElement object and
+ * the flag for ignoring or not ignoring XML attributes. The third parameter
+ * will be used internally within this function during the recursive calls.
+ *
+ * This function converts the SimpleXMLElement object into a PHP array by
+ * calling a recursive (protected static) function in this class. Once all
+ * the XML elements are stored in the PHP array, it is returned to the caller.
+ *
+ * Throws a Zend_Json_Exception if the XML tree is deeper than the allowed limit.
+ *
+ * @static
+ * @access protected
+ * @param SimpleXMLElement $simpleXmlElementObject XML element to be converted
+ * @param boolean $ignoreXmlAttributes Include or exclude XML attributes in
+ * the xml2json conversion process.
+ * @param int $recursionDepth Current recursion depth of this function
+ * @return mixed - On success, a PHP associative array of traversed XML elements
+ * @throws Zend_Json_Exception
+ */
+ protected static function _processXml ($simpleXmlElementObject, $ignoreXmlAttributes, $recursionDepth=0) {
+ // Keep an eye on how deeply we are involved in recursion.
+ if ($recursionDepth > self::$maxRecursionDepthAllowed) {
+ // XML tree is too deep. Exit now by throwing an exception.
+ require_once 'Zend/Json/Exception.php';
+ throw new Zend_Json_Exception(
+ "Function _processXml exceeded the allowed recursion depth of " .
+ self::$maxRecursionDepthAllowed);
+ } // End of if ($recursionDepth > self::$maxRecursionDepthAllowed)
+
+ if ($recursionDepth == 0) {
+ // Store the original SimpleXmlElementObject sent by the caller.
+ // We will need it at the very end when we return from here for good.
+ $callerProvidedSimpleXmlElementObject = $simpleXmlElementObject;
+ } // End of if ($recursionDepth == 0)
+
+ if ($simpleXmlElementObject instanceof SimpleXMLElement) {
+ // Get a copy of the simpleXmlElementObject
+ $copyOfSimpleXmlElementObject = $simpleXmlElementObject;
+ // Get the object variables in the SimpleXmlElement object for us to iterate.
+ $simpleXmlElementObject = get_object_vars($simpleXmlElementObject);
+ } // End of if (get_class($simpleXmlElementObject) == "SimpleXMLElement")
+
+ // It needs to be an array of object variables.
+ if (is_array($simpleXmlElementObject)) {
+ // Initialize a result array.
+ $resultArray = array();
+ // Is the input array size 0? Then, we reached the rare CDATA text if any.
+ if (count($simpleXmlElementObject) <= 0) {
+ // Let us return the lonely CDATA. It could even be
+ // an empty element or just filled with whitespaces.
+ return (trim(strval($copyOfSimpleXmlElementObject)));
+ } // End of if (count($simpleXmlElementObject) <= 0)
+
+ // Let us walk through the child elements now.
+ foreach($simpleXmlElementObject as $key=>$value) {
+ // Check if we need to ignore the XML attributes.
+ // If yes, you can skip processing the XML attributes.
+ // Otherwise, add the XML attributes to the result array.
+ if(($ignoreXmlAttributes == true) && (is_string($key)) && ($key == "@attributes")) {
+ continue;
+ } // End of if(($ignoreXmlAttributes == true) && ($key == "@attributes"))
+
+ // Let us recursively process the current XML element we just visited.
+ // Increase the recursion depth by one.
+ $recursionDepth++;
+ $resultArray[$key] = self::_processXml ($value, $ignoreXmlAttributes, $recursionDepth);
+
+ // Decrease the recursion depth by one.
+ $recursionDepth--;
+ } // End of foreach($simpleXmlElementObject as $key=>$value) {
+
+ if ($recursionDepth == 0) {
+ // That is it. We are heading to the exit now.
+ // Set the XML root element name as the root [top-level] key of
+ // the associative array that we are going to return to the original
+ // caller of this recursive function.
+ $tempArray = $resultArray;
+ $resultArray = array();
+ $resultArray[$callerProvidedSimpleXmlElementObject->getName()] = $tempArray;
+ } // End of if ($recursionDepth == 0)
+
+ return($resultArray);
+ } else {
+ // We are now looking at either the XML attribute text or
+ // the text between the XML tags.
+
+ // In order to allow Zend_Json_Expr from xml, we check if the node
+ // matchs the pattern that try to detect if it is a new Zend_Json_Expr
+ // if it matches, we return a new Zend_Json_Expr instead of a text node
+ $pattern = '/^[\s]*new Zend_Json_Expr[\s]*\([\s]*[\"\']{1}(.*)[\"\']{1}[\s]*\)[\s]*$/';
+ $matchings = array();
+ $match = preg_match ($pattern, $simpleXmlElementObject, $matchings);
+ if ($match) {
+ return new Zend_Json_Expr($matchings[1]);
+ } else {
+ return (trim(strval($simpleXmlElementObject)));
+ }
+
+ } // End of if (is_array($simpleXmlElementObject))
+ } // End of function _processXml.
+}
--- /dev/null
+<?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_Layout
+ * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ * @version $Id$
+ */
+
+/**
+ * Provide Layout support for MVC applications
+ *
+ * @category Zend
+ * @package Zend_Layout
+ * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+class Zend_Layout
+{
+ /**
+ * Placeholder container for layout variables
+ * @var Zend_View_Helper_Placeholder_Container
+ */
+ protected $_container;
+
+ /**
+ * Key used to store content from 'default' named response segment
+ * @var string
+ */
+ protected $_contentKey = 'content';
+
+ /**
+ * Are layouts enabled?
+ * @var bool
+ */
+ protected $_enabled = true;
+
+ /**
+ * Helper class
+ * @var string
+ */
+ protected $_helperClass = 'Zend_Layout_Controller_Action_Helper_Layout';
+
+ /**
+ * Inflector used to resolve layout script
+ * @var Zend_Filter_Inflector
+ */
+ protected $_inflector;
+
+ /**
+ * Flag: is inflector enabled?
+ * @var bool
+ */
+ protected $_inflectorEnabled = true;
+
+ /**
+ * Inflector target
+ * @var string
+ */
+ protected $_inflectorTarget = ':script.:suffix';
+
+ /**
+ * Layout view
+ * @var string
+ */
+ protected $_layout = 'layout';
+
+ /**
+ * Layout view script path
+ * @var string
+ */
+ protected $_viewScriptPath = null;
+
+ protected $_viewBasePath = null;
+ protected $_viewBasePrefix = 'Layout_View';
+
+ /**
+ * Flag: is MVC integration enabled?
+ * @var bool
+ */
+ protected $_mvcEnabled = true;
+
+ /**
+ * Instance registered with MVC, if any
+ * @var Zend_Layout
+ */
+ protected static $_mvcInstance;
+
+ /**
+ * Flag: is MVC successful action only flag set?
+ * @var bool
+ */
+ protected $_mvcSuccessfulActionOnly = true;
+
+ /**
+ * Plugin class
+ * @var string
+ */
+ protected $_pluginClass = 'Zend_Layout_Controller_Plugin_Layout';
+
+ /**
+ * @var Zend_View_Interface
+ */
+ protected $_view;
+
+ /**
+ * View script suffix for layout script
+ * @var string
+ */
+ protected $_viewSuffix = 'phtml';
+
+ /**
+ * Constructor
+ *
+ * Accepts either:
+ * - A string path to layouts
+ * - An array of options
+ * - A Zend_Config object with options
+ *
+ * Layout script path, either as argument or as key in options, is
+ * required.
+ *
+ * If mvcEnabled flag is false from options, simply sets layout script path.
+ * Otherwise, also instantiates and registers action helper and controller
+ * plugin.
+ *
+ * @param string|array|Zend_Config $options
+ * @return void
+ */
+ public function __construct($options = null, $initMvc = false)
+ {
+ if (null !== $options) {
+ if (is_string($options)) {
+ $this->setLayoutPath($options);
+ } elseif (is_array($options)) {
+ $this->setOptions($options);
+ } elseif ($options instanceof Zend_Config) {
+ $this->setConfig($options);
+ } else {
+ require_once 'Zend/Layout/Exception.php';
+ throw new Zend_Layout_Exception('Invalid option provided to constructor');
+ }
+ }
+
+ $this->_initVarContainer();
+
+ if ($initMvc) {
+ $this->_setMvcEnabled(true);
+ $this->_initMvc();
+ } else {
+ $this->_setMvcEnabled(false);
+ }
+ }
+
+ /**
+ * Static method for initialization with MVC support
+ *
+ * @param string|array|Zend_Config $options
+ * @return Zend_Layout
+ */
+ public static function startMvc($options = null)
+ {
+ if (null === self::$_mvcInstance) {
+ self::$_mvcInstance = new self($options, true);
+ }
+
+ if (is_string($options)) {
+ self::$_mvcInstance->setLayoutPath($options);
+ } elseif (is_array($options) || $options instanceof Zend_Config) {
+ self::$_mvcInstance->setOptions($options);
+ }
+
+ return self::$_mvcInstance;
+ }
+
+ /**
+ * Retrieve MVC instance of Zend_Layout object
+ *
+ * @return Zend_Layout|null
+ */
+ public static function getMvcInstance()
+ {
+ return self::$_mvcInstance;
+ }
+
+ /**
+ * Reset MVC instance
+ *
+ * Unregisters plugins and helpers, and destroys MVC layout instance.
+ *
+ * @return void
+ */
+ public static function resetMvcInstance()
+ {
+ if (null !== self::$_mvcInstance) {
+ $layout = self::$_mvcInstance;
+ $pluginClass = $layout->getPluginClass();
+ $front = Zend_Controller_Front::getInstance();
+ if ($front->hasPlugin($pluginClass)) {
+ $front->unregisterPlugin($pluginClass);
+ }
+
+ if (Zend_Controller_Action_HelperBroker::hasHelper('layout')) {
+ Zend_Controller_Action_HelperBroker::removeHelper('layout');
+ }
+
+ unset($layout);
+ self::$_mvcInstance = null;
+ }
+ }
+
+ /**
+ * Set options en masse
+ *
+ * @param array|Zend_Config $options
+ * @return void
+ */
+ public function setOptions($options)
+ {
+ if ($options instanceof Zend_Config) {
+ $options = $options->toArray();
+ } elseif (!is_array($options)) {
+ require_once 'Zend/Layout/Exception.php';
+ throw new Zend_Layout_Exception('setOptions() expects either an array or a Zend_Config object');
+ }
+
+ foreach ($options as $key => $value) {
+ $method = 'set' . ucfirst($key);
+ if (method_exists($this, $method)) {
+ $this->$method($value);
+ }
+ }
+ }
+
+ /**
+ * Initialize MVC integration
+ *
+ * @return void
+ */
+ protected function _initMvc()
+ {
+ $this->_initPlugin();
+ $this->_initHelper();
+ }
+
+ /**
+ * Initialize front controller plugin
+ *
+ * @return void
+ */
+ protected function _initPlugin()
+ {
+ $pluginClass = $this->getPluginClass();
+ require_once 'Zend/Controller/Front.php';
+ $front = Zend_Controller_Front::getInstance();
+ if (!$front->hasPlugin($pluginClass)) {
+ if (!class_exists($pluginClass)) {
+ require_once 'Zend/Loader.php';
+ Zend_Loader::loadClass($pluginClass);
+ }
+ $front->registerPlugin(
+ // register to run last | BUT before the ErrorHandler (if its available)
+ new $pluginClass($this),
+ 99
+ );
+ }
+ }
+
+ /**
+ * Initialize action helper
+ *
+ * @return void
+ */
+ protected function _initHelper()
+ {
+ $helperClass = $this->getHelperClass();
+ require_once 'Zend/Controller/Action/HelperBroker.php';
+ if (!Zend_Controller_Action_HelperBroker::hasHelper('layout')) {
+ if (!class_exists($helperClass)) {
+ require_once 'Zend/Loader.php';
+ Zend_Loader::loadClass($helperClass);
+ }
+ Zend_Controller_Action_HelperBroker::getStack()->offsetSet(-90, new $helperClass($this));
+ }
+ }
+
+ /**
+ * Set options from a config object
+ *
+ * @param Zend_Config $config
+ * @return Zend_Layout
+ */
+ public function setConfig(Zend_Config $config)
+ {
+ $this->setOptions($config->toArray());
+ return $this;
+ }
+
+ /**
+ * Initialize placeholder container for layout vars
+ *
+ * @return Zend_View_Helper_Placeholder_Container
+ */
+ protected function _initVarContainer()
+ {
+ if (null === $this->_container) {
+ require_once 'Zend/View/Helper/Placeholder/Registry.php';
+ $this->_container = Zend_View_Helper_Placeholder_Registry::getRegistry()->getContainer(__CLASS__);
+ }
+
+ return $this->_container;
+ }
+
+ /**
+ * Set layout script to use
+ *
+ * Note: enables layout.
+ *
+ * @param string $name
+ * @return Zend_Layout
+ */
+ public function setLayout($name)
+ {
+ $this->_layout = (string) $name;
+ $this->enableLayout();
+ return $this;
+ }
+
+ /**
+ * Get current layout script
+ *
+ * @return string
+ */
+ public function getLayout()
+ {
+ return $this->_layout;
+ }
+
+ /**
+ * Disable layout
+ *
+ * @return Zend_Layout
+ */
+ public function disableLayout()
+ {
+ $this->_enabled = false;
+ return $this;
+ }
+
+ /**
+ * Enable layout
+ *
+ * @return Zend_Layout
+ */
+ public function enableLayout()
+ {
+ $this->_enabled = true;
+ return $this;
+ }
+
+ /**
+ * Is layout enabled?
+ *
+ * @return bool
+ */
+ public function isEnabled()
+ {
+ return $this->_enabled;
+ }
+
+
+ public function setViewBasePath($path, $prefix = 'Layout_View')
+ {
+ $this->_viewBasePath = $path;
+ $this->_viewBasePrefix = $prefix;
+ return $this;
+ }
+
+ public function getViewBasePath()
+ {
+ return $this->_viewBasePath;
+ }
+
+ public function setViewScriptPath($path)
+ {
+ $this->_viewScriptPath = $path;
+ return $this;
+ }
+
+ public function getViewScriptPath()
+ {
+ return $this->_viewScriptPath;
+ }
+
+ /**
+ * Set layout script path
+ *
+ * @param string $path
+ * @return Zend_Layout
+ */
+ public function setLayoutPath($path)
+ {
+ return $this->setViewScriptPath($path);
+ }
+
+ /**
+ * Get current layout script path
+ *
+ * @return string
+ */
+ public function getLayoutPath()
+ {
+ return $this->getViewScriptPath();
+ }
+
+ /**
+ * Set content key
+ *
+ * Key in namespace container denoting default content
+ *
+ * @param string $contentKey
+ * @return Zend_Layout
+ */
+ public function setContentKey($contentKey)
+ {
+ $this->_contentKey = (string) $contentKey;
+ return $this;
+ }
+
+ /**
+ * Retrieve content key
+ *
+ * @return string
+ */
+ public function getContentKey()
+ {
+ return $this->_contentKey;
+ }
+
+ /**
+ * Set MVC enabled flag
+ *
+ * @param bool $mvcEnabled
+ * @return Zend_Layout
+ */
+ protected function _setMvcEnabled($mvcEnabled)
+ {
+ $this->_mvcEnabled = ($mvcEnabled) ? true : false;
+ return $this;
+ }
+
+ /**
+ * Retrieve MVC enabled flag
+ *
+ * @return bool
+ */
+ public function getMvcEnabled()
+ {
+ return $this->_mvcEnabled;
+ }
+
+ /**
+ * Set MVC Successful Action Only flag
+ *
+ * @param bool $successfulActionOnly
+ * @return Zend_Layout
+ */
+ public function setMvcSuccessfulActionOnly($successfulActionOnly)
+ {
+ $this->_mvcSuccessfulActionOnly = ($successfulActionOnly) ? true : false;
+ return $this;
+ }
+
+ /**
+ * Get MVC Successful Action Only Flag
+ *
+ * @return bool
+ */
+ public function getMvcSuccessfulActionOnly()
+ {
+ return $this->_mvcSuccessfulActionOnly;
+ }
+
+ /**
+ * Set view object
+ *
+ * @param Zend_View_Interface $view
+ * @return Zend_Layout
+ */
+ public function setView(Zend_View_Interface $view)
+ {
+ $this->_view = $view;
+ return $this;
+ }
+
+ /**
+ * Retrieve helper class
+ *
+ * @return string
+ */
+ public function getHelperClass()
+ {
+ return $this->_helperClass;
+ }
+
+ /**
+ * Set helper class
+ *
+ * @param string $helperClass
+ * @return Zend_Layout
+ */
+ public function setHelperClass($helperClass)
+ {
+ $this->_helperClass = (string) $helperClass;
+ return $this;
+ }
+
+ /**
+ * Retrieve plugin class
+ *
+ * @return string
+ */
+ public function getPluginClass()
+ {
+ return $this->_pluginClass;
+ }
+
+ /**
+ * Set plugin class
+ *
+ * @param string $pluginClass
+ * @return Zend_Layout
+ */
+ public function setPluginClass($pluginClass)
+ {
+ $this->_pluginClass = (string) $pluginClass;
+ return $this;
+ }
+
+ /**
+ * Get current view object
+ *
+ * If no view object currently set, retrieves it from the ViewRenderer.
+ *
+ * @todo Set inflector from view renderer at same time
+ * @return Zend_View_Interface
+ */
+ public function getView()
+ {
+ if (null === $this->_view) {
+ require_once 'Zend/Controller/Action/HelperBroker.php';
+ $viewRenderer = Zend_Controller_Action_HelperBroker::getStaticHelper('viewRenderer');
+ if (null === $viewRenderer->view) {
+ $viewRenderer->initView();
+ }
+ $this->setView($viewRenderer->view);
+ }
+ return $this->_view;
+ }
+
+ /**
+ * Set layout view script suffix
+ *
+ * @param string $viewSuffix
+ * @return Zend_Layout
+ */
+ public function setViewSuffix($viewSuffix)
+ {
+ $this->_viewSuffix = (string) $viewSuffix;
+ return $this;
+ }
+
+ /**
+ * Retrieve layout view script suffix
+ *
+ * @return string
+ */
+ public function getViewSuffix()
+ {
+ return $this->_viewSuffix;
+ }
+
+ /**
+ * Retrieve inflector target
+ *
+ * @return string
+ */
+ public function getInflectorTarget()
+ {
+ return $this->_inflectorTarget;
+ }
+
+ /**
+ * Set inflector target
+ *
+ * @param string $inflectorTarget
+ * @return Zend_Layout
+ */
+ public function setInflectorTarget($inflectorTarget)
+ {
+ $this->_inflectorTarget = (string) $inflectorTarget;
+ return $this;
+ }
+
+ /**
+ * Set inflector to use when resolving layout names
+ *
+ * @param Zend_Filter_Inflector $inflector
+ * @return Zend_Layout
+ */
+ public function setInflector(Zend_Filter_Inflector $inflector)
+ {
+ $this->_inflector = $inflector;
+ return $this;
+ }
+
+ /**
+ * Retrieve inflector
+ *
+ * @return Zend_Filter_Inflector
+ */
+ public function getInflector()
+ {
+ if (null === $this->_inflector) {
+ require_once 'Zend/Filter/Inflector.php';
+ $inflector = new Zend_Filter_Inflector();
+ $inflector->setTargetReference($this->_inflectorTarget)
+ ->addRules(array(':script' => array('Word_CamelCaseToDash', 'StringToLower')))
+ ->setStaticRuleReference('suffix', $this->_viewSuffix);
+ $this->setInflector($inflector);
+ }
+
+ return $this->_inflector;
+ }
+
+ /**
+ * Enable inflector
+ *
+ * @return Zend_Layout
+ */
+ public function enableInflector()
+ {
+ $this->_inflectorEnabled = true;
+ return $this;
+ }
+
+ /**
+ * Disable inflector
+ *
+ * @return Zend_Layout
+ */
+ public function disableInflector()
+ {
+ $this->_inflectorEnabled = false;
+ return $this;
+ }
+
+ /**
+ * Return status of inflector enabled flag
+ *
+ * @return bool
+ */
+ public function inflectorEnabled()
+ {
+ return $this->_inflectorEnabled;
+ }
+
+ /**
+ * Set layout variable
+ *
+ * @param string $key
+ * @param mixed $value
+ * @return void
+ */
+ public function __set($key, $value)
+ {
+ $this->_container[$key] = $value;
+ }
+
+ /**
+ * Get layout variable
+ *
+ * @param string $key
+ * @return mixed
+ */
+ public function __get($key)
+ {
+ if (isset($this->_container[$key])) {
+ return $this->_container[$key];
+ }
+
+ return null;
+ }
+
+ /**
+ * Is a layout variable set?
+ *
+ * @param string $key
+ * @return bool
+ */
+ public function __isset($key)
+ {
+ return (isset($this->_container[$key]));
+ }
+
+ /**
+ * Unset a layout variable?
+ *
+ * @param string $key
+ * @return void
+ */
+ public function __unset($key)
+ {
+ if (isset($this->_container[$key])) {
+ unset($this->_container[$key]);
+ }
+ }
+
+ /**
+ * Assign one or more layout variables
+ *
+ * @param mixed $spec Assoc array or string key; if assoc array, sets each
+ * key as a layout variable
+ * @param mixed $value Value if $spec is a key
+ * @return Zend_Layout
+ * @throws Zend_Layout_Exception if non-array/string value passed to $spec
+ */
+ public function assign($spec, $value = null)
+ {
+ if (is_array($spec)) {
+ $orig = $this->_container->getArrayCopy();
+ $merged = array_merge($orig, $spec);
+ $this->_container->exchangeArray($merged);
+ return $this;
+ }
+
+ if (is_string($spec)) {
+ $this->_container[$spec] = $value;
+ return $this;
+ }
+
+ require_once 'Zend/Layout/Exception.php';
+ throw new Zend_Layout_Exception('Invalid values passed to assign()');
+ }
+
+ /**
+ * Render layout
+ *
+ * Sets internal script path as last path on script path stack, assigns
+ * layout variables to view, determines layout name using inflector, and
+ * renders layout view script.
+ *
+ * $name will be passed to the inflector as the key 'script'.
+ *
+ * @param mixed $name
+ * @return mixed
+ */
+ public function render($name = null)
+ {
+ if (null === $name) {
+ $name = $this->getLayout();
+ }
+
+ if ($this->inflectorEnabled() && (null !== ($inflector = $this->getInflector())))
+ {
+ $name = $this->_inflector->filter(array('script' => $name));
+ }
+
+ $view = $this->getView();
+
+ if (null !== ($path = $this->getViewScriptPath())) {
+ if (method_exists($view, 'addScriptPath')) {
+ $view->addScriptPath($path);
+ } else {
+ $view->setScriptPath($path);
+ }
+ } elseif (null !== ($path = $this->getViewBasePath())) {
+ $view->addBasePath($path, $this->_viewBasePrefix);
+ }
+
+ return $view->render($name);
+ }
+}
--- /dev/null
+<?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_Ldap
+ * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ * @version $Id$
+ */
+
+/**
+ * @category Zend
+ * @package Zend_Ldap
+ * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+class Zend_Ldap
+{
+ const SEARCH_SCOPE_SUB = 1;
+ const SEARCH_SCOPE_ONE = 2;
+ const SEARCH_SCOPE_BASE = 3;
+
+ const ACCTNAME_FORM_DN = 1;
+ const ACCTNAME_FORM_USERNAME = 2;
+ const ACCTNAME_FORM_BACKSLASH = 3;
+ const ACCTNAME_FORM_PRINCIPAL = 4;
+
+ /**
+ * String used with ldap_connect for error handling purposes.
+ *
+ * @var string
+ */
+ private $_connectString;
+
+ /**
+ * The options used in connecting, binding, etc.
+ *
+ * @var array
+ */
+ protected $_options = null;
+
+ /**
+ * The raw LDAP extension resource.
+ *
+ * @var resource
+ */
+ protected $_resource = null;
+
+ /**
+ * Caches the RootDSE
+ *
+ * @var Zend_Ldap_Node
+ */
+ protected $_rootDse = null;
+
+ /**
+ * Caches the schema
+ *
+ * @var Zend_Ldap_Node
+ */
+ protected $_schema = null;
+
+ /**
+ * @deprecated will be removed, use {@see Zend_Ldap_Filter_Abstract::escapeValue()}
+ * @param string $str The string to escape.
+ * @return string The escaped string
+ */
+ public static function filterEscape($str)
+ {
+ /**
+ * @see Zend_Ldap_Filter_Abstract
+ */
+ require_once 'Zend/Ldap/Filter/Abstract.php';
+ return Zend_Ldap_Filter_Abstract::escapeValue($str);
+ }
+
+ /**
+ * @deprecated will be removed, use {@see Zend_Ldap_Dn::checkDn()}
+ * @param string $dn The DN to parse
+ * @param array $keys An optional array to receive DN keys (e.g. CN, OU, DC, ...)
+ * @param array $vals An optional array to receive DN values
+ * @return boolean True if the DN was successfully parsed or false if the string is
+ * not a valid DN.
+ */
+ public static function explodeDn($dn, array &$keys = null, array &$vals = null)
+ {
+ /**
+ * @see Zend_Ldap_Dn
+ */
+ require_once 'Zend/Ldap/Dn.php';
+ return Zend_Ldap_Dn::checkDn($dn, $keys, $vals);
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param array|Zend_Config $options Options used in connecting, binding, etc.
+ * @return void
+ */
+ public function __construct($options = array())
+ {
+ $this->setOptions($options);
+ }
+
+ /**
+ * Destructor.
+ *
+ * @return void
+ */
+ public function __destruct()
+ {
+ $this->disconnect();
+ }
+
+ /**
+ * @return resource The raw LDAP extension resource.
+ */
+ public function getResource()
+ {
+ return $this->_resource;
+ }
+
+ /**
+ * Return the LDAP error number of the last LDAP command
+ *
+ * @return int
+ */
+ public function getLastErrorCode()
+ {
+ $ret = @ldap_get_option($this->getResource(), LDAP_OPT_ERROR_NUMBER, $err);
+ if ($ret === true) {
+ if ($err <= -1 && $err >= -17) {
+ /**
+ * @see Zend_Ldap_Exception
+ */
+ require_once 'Zend/Ldap/Exception.php';
+ /* For some reason draft-ietf-ldapext-ldap-c-api-xx.txt error
+ * codes in OpenLDAP are negative values from -1 to -17.
+ */
+ $err = Zend_Ldap_Exception::LDAP_SERVER_DOWN + (-$err - 1);
+ }
+ return $err;
+ }
+ return 0;
+ }
+
+ /**
+ * Return the LDAP error message of the last LDAP command
+ *
+ * @param int $errorCode
+ * @param array $errorMessages
+ * @return string
+ */
+ public function getLastError(&$errorCode = null, array &$errorMessages = null)
+ {
+ $errorCode = $this->getLastErrorCode();
+ $errorMessages = array();
+
+ /* The various error retrieval functions can return
+ * different things so we just try to collect what we
+ * can and eliminate dupes.
+ */
+ $estr1 = @ldap_error($this->getResource());
+ if ($errorCode !== 0 && $estr1 === 'Success') {
+ $estr1 = @ldap_err2str($errorCode);
+ }
+ if (!empty($estr1)) {
+ $errorMessages[] = $estr1;
+ }
+
+ @ldap_get_option($this->getResource(), LDAP_OPT_ERROR_STRING, $estr2);
+ if (!empty($estr2) && !in_array($estr2, $errorMessages)) {
+ $errorMessages[] = $estr2;
+ }
+
+ $message = '';
+ if ($errorCode > 0) {
+ $message = '0x' . dechex($errorCode) . ' ';
+ } else {
+ $message = '';
+ }
+ if (count($errorMessages) > 0) {
+ $message .= '(' . implode('; ', $errorMessages) . ')';
+ } else {
+ $message .= '(no error message from LDAP)';
+ }
+ return $message;
+ }
+
+ /**
+ * Sets the options used in connecting, binding, etc.
+ *
+ * Valid option keys:
+ * host
+ * port
+ * useSsl
+ * username
+ * password
+ * bindRequiresDn
+ * baseDn
+ * accountCanonicalForm
+ * accountDomainName
+ * accountDomainNameShort
+ * accountFilterFormat
+ * allowEmptyPassword
+ * useStartTls
+ * optRefferals
+ * tryUsernameSplit
+ *
+ * @param array|Zend_Config $options Options used in connecting, binding, etc.
+ * @return Zend_Ldap Provides a fluent interface
+ * @throws Zend_Ldap_Exception
+ */
+ public function setOptions($options)
+ {
+ if ($options instanceof Zend_Config) {
+ $options = $options->toArray();
+ }
+
+ $permittedOptions = array(
+ 'host' => null,
+ 'port' => 0,
+ 'useSsl' => false,
+ 'username' => null,
+ 'password' => null,
+ 'bindRequiresDn' => false,
+ 'baseDn' => null,
+ 'accountCanonicalForm' => null,
+ 'accountDomainName' => null,
+ 'accountDomainNameShort' => null,
+ 'accountFilterFormat' => null,
+ 'allowEmptyPassword' => false,
+ 'useStartTls' => false,
+ 'optReferrals' => false,
+ 'tryUsernameSplit' => true,
+ );
+
+ foreach ($permittedOptions as $key => $val) {
+ if (array_key_exists($key, $options)) {
+ $val = $options[$key];
+ unset($options[$key]);
+ /* Enforce typing. This eliminates issues like Zend_Config_Ini
+ * returning '1' as a string (ZF-3163).
+ */
+ switch ($key) {
+ case 'port':
+ case 'accountCanonicalForm':
+ $permittedOptions[$key] = (int)$val;
+ break;
+ case 'useSsl':
+ case 'bindRequiresDn':
+ case 'allowEmptyPassword':
+ case 'useStartTls':
+ case 'optReferrals':
+ case 'tryUsernameSplit':
+ $permittedOptions[$key] = ($val === true ||
+ $val === '1' || strcasecmp($val, 'true') == 0);
+ break;
+ default:
+ $permittedOptions[$key] = trim($val);
+ break;
+ }
+ }
+ }
+ if (count($options) > 0) {
+ $key = key($options);
+ /**
+ * @see Zend_Ldap_Exception
+ */
+ require_once 'Zend/Ldap/Exception.php';
+ throw new Zend_Ldap_Exception(null, "Unknown Zend_Ldap option: $key");
+ }
+ $this->_options = $permittedOptions;
+ return $this;
+ }
+
+ /**
+ * @return array The current options.
+ */
+ public function getOptions()
+ {
+ return $this->_options;
+ }
+
+ /**
+ * @return string The hostname of the LDAP server being used to authenticate accounts
+ */
+ protected function _getHost()
+ {
+ return $this->_options['host'];
+ }
+
+ /**
+ * @return int The port of the LDAP server or 0 to indicate that no port value is set
+ */
+ protected function _getPort()
+ {
+ return $this->_options['port'];
+ }
+
+ /**
+ * @return boolean The default SSL / TLS encrypted transport control
+ */
+ protected function _getUseSsl()
+ {
+ return $this->_options['useSsl'];
+ }
+
+ /**
+ * @return string The default acctname for binding
+ */
+ protected function _getUsername()
+ {
+ return $this->_options['username'];
+ }
+
+ /**
+ * @return string The default password for binding
+ */
+ protected function _getPassword()
+ {
+ return $this->_options['password'];
+ }
+
+ /**
+ * @return boolean Bind requires DN
+ */
+ protected function _getBindRequiresDn()
+ {
+ return $this->_options['bindRequiresDn'];
+ }
+
+ /**
+ * Gets the base DN under which objects of interest are located
+ *
+ * @return string
+ */
+ public function getBaseDn()
+ {
+ return $this->_options['baseDn'];
+ }
+
+ /**
+ * @return integer Either ACCTNAME_FORM_BACKSLASH, ACCTNAME_FORM_PRINCIPAL or
+ * ACCTNAME_FORM_USERNAME indicating the form usernames should be canonicalized to.
+ */
+ protected function _getAccountCanonicalForm()
+ {
+ /* Account names should always be qualified with a domain. In some scenarios
+ * using non-qualified account names can lead to security vulnerabilities. If
+ * no account canonical form is specified, we guess based in what domain
+ * names have been supplied.
+ */
+
+ $accountCanonicalForm = $this->_options['accountCanonicalForm'];
+ if (!$accountCanonicalForm) {
+ $accountDomainName = $this->_getAccountDomainName();
+ $accountDomainNameShort = $this->_getAccountDomainNameShort();
+ if ($accountDomainNameShort) {
+ $accountCanonicalForm = Zend_Ldap::ACCTNAME_FORM_BACKSLASH;
+ } else if ($accountDomainName) {
+ $accountCanonicalForm = Zend_Ldap::ACCTNAME_FORM_PRINCIPAL;
+ } else {
+ $accountCanonicalForm = Zend_Ldap::ACCTNAME_FORM_USERNAME;
+ }
+ }
+
+ return $accountCanonicalForm;
+ }
+
+ /**
+ * @return string The account domain name
+ */
+ protected function _getAccountDomainName()
+ {
+ return $this->_options['accountDomainName'];
+ }
+
+ /**
+ * @return string The short account domain name
+ */
+ protected function _getAccountDomainNameShort()
+ {
+ return $this->_options['accountDomainNameShort'];
+ }
+
+ /**
+ * @return string A format string for building an LDAP search filter to match
+ * an account
+ */
+ protected function _getAccountFilterFormat()
+ {
+ return $this->_options['accountFilterFormat'];
+ }
+
+ /**
+ * @return boolean Allow empty passwords
+ */
+ protected function _getAllowEmptyPassword()
+ {
+ return $this->_options['allowEmptyPassword'];
+ }
+
+ /**
+ * @return boolean The default SSL / TLS encrypted transport control
+ */
+ protected function _getUseStartTls()
+ {
+ return $this->_options['useStartTls'];
+ }
+
+ /**
+ * @return boolean Opt. Referrals
+ */
+ protected function _getOptReferrals()
+ {
+ return $this->_options['optReferrals'];
+ }
+
+ /**
+ * @return boolean Try splitting the username into username and domain
+ */
+ protected function _getTryUsernameSplit()
+ {
+ return $this->_options['tryUsernameSplit'];
+ }
+
+ /**
+ * @return string The LDAP search filter for matching directory accounts
+ */
+ protected function _getAccountFilter($acctname)
+ {
+ /**
+ * @see Zend_Ldap_Filter_Abstract
+ */
+ require_once 'Zend/Ldap/Filter/Abstract.php';
+ $this->_splitName($acctname, $dname, $aname);
+ $accountFilterFormat = $this->_getAccountFilterFormat();
+ $aname = Zend_Ldap_Filter_Abstract::escapeValue($aname);
+ if ($accountFilterFormat) {
+ return sprintf($accountFilterFormat, $aname);
+ }
+ if (!$this->_getBindRequiresDn()) {
+ // is there a better way to detect this?
+ return sprintf("(&(objectClass=user)(sAMAccountName=%s))", $aname);
+ }
+ return sprintf("(&(objectClass=posixAccount)(uid=%s))", $aname);
+ }
+
+ /**
+ * @param string $name The name to split
+ * @param string $dname The resulting domain name (this is an out parameter)
+ * @param string $aname The resulting account name (this is an out parameter)
+ * @return void
+ */
+ protected function _splitName($name, &$dname, &$aname)
+ {
+ $dname = null;
+ $aname = $name;
+
+ if (!$this->_getTryUsernameSplit()) {
+ return;
+ }
+
+ $pos = strpos($name, '@');
+ if ($pos) {
+ $dname = substr($name, $pos + 1);
+ $aname = substr($name, 0, $pos);
+ } else {
+ $pos = strpos($name, '\\');
+ if ($pos) {
+ $dname = substr($name, 0, $pos);
+ $aname = substr($name, $pos + 1);
+ }
+ }
+ }
+
+ /**
+ * @param string $acctname The name of the account
+ * @return string The DN of the specified account
+ * @throws Zend_Ldap_Exception
+ */
+ protected function _getAccountDn($acctname)
+ {
+ /**
+ * @see Zend_Ldap_Dn
+ */
+ require_once 'Zend/Ldap/Dn.php';
+ if (Zend_Ldap_Dn::checkDn($acctname)) return $acctname;
+ $acctname = $this->getCanonicalAccountName($acctname, Zend_Ldap::ACCTNAME_FORM_USERNAME);
+ $acct = $this->_getAccount($acctname, array('dn'));
+ return $acct['dn'];
+ }
+
+ /**
+ * @param string $dname The domain name to check
+ * @return boolean
+ */
+ protected function _isPossibleAuthority($dname)
+ {
+ if ($dname === null) {
+ return true;
+ }
+ $accountDomainName = $this->_getAccountDomainName();
+ $accountDomainNameShort = $this->_getAccountDomainNameShort();
+ if ($accountDomainName === null && $accountDomainNameShort === null) {
+ return true;
+ }
+ if (strcasecmp($dname, $accountDomainName) == 0) {
+ return true;
+ }
+ if (strcasecmp($dname, $accountDomainNameShort) == 0) {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * @param string $acctname The name to canonicalize
+ * @param int $type The desired form of canonicalization
+ * @return string The canonicalized name in the desired form
+ * @throws Zend_Ldap_Exception
+ */
+ public function getCanonicalAccountName($acctname, $form = 0)
+ {
+ $this->_splitName($acctname, $dname, $uname);
+
+ if (!$this->_isPossibleAuthority($dname)) {
+ /**
+ * @see Zend_Ldap_Exception
+ */
+ require_once 'Zend/Ldap/Exception.php';
+ throw new Zend_Ldap_Exception(null,
+ "Binding domain is not an authority for user: $acctname",
+ Zend_Ldap_Exception::LDAP_X_DOMAIN_MISMATCH);
+ }
+
+ if (!$uname) {
+ /**
+ * @see Zend_Ldap_Exception
+ */
+ require_once 'Zend/Ldap/Exception.php';
+ throw new Zend_Ldap_Exception(null, "Invalid account name syntax: $acctname");
+ }
+
+ if (function_exists('mb_strtolower')) {
+ $uname = mb_strtolower($uname, 'UTF-8');
+ } else {
+ $uname = strtolower($uname);
+ }
+
+ if ($form === 0) {
+ $form = $this->_getAccountCanonicalForm();
+ }
+
+ switch ($form) {
+ case Zend_Ldap::ACCTNAME_FORM_DN:
+ return $this->_getAccountDn($acctname);
+ case Zend_Ldap::ACCTNAME_FORM_USERNAME:
+ return $uname;
+ case Zend_Ldap::ACCTNAME_FORM_BACKSLASH:
+ $accountDomainNameShort = $this->_getAccountDomainNameShort();
+ if (!$accountDomainNameShort) {
+ /**
+ * @see Zend_Ldap_Exception
+ */
+ require_once 'Zend/Ldap/Exception.php';
+ throw new Zend_Ldap_Exception(null, 'Option required: accountDomainNameShort');
+ }
+ return "$accountDomainNameShort\\$uname";
+ case Zend_Ldap::ACCTNAME_FORM_PRINCIPAL:
+ $accountDomainName = $this->_getAccountDomainName();
+ if (!$accountDomainName) {
+ /**
+ * @see Zend_Ldap_Exception
+ */
+ require_once 'Zend/Ldap/Exception.php';
+ throw new Zend_Ldap_Exception(null, 'Option required: accountDomainName');
+ }
+ return "$uname@$accountDomainName";
+ default:
+ /**
+ * @see Zend_Ldap_Exception
+ */
+ require_once 'Zend/Ldap/Exception.php';
+ throw new Zend_Ldap_Exception(null, "Unknown canonical name form: $form");
+ }
+ }
+
+ /**
+ * @param array $attrs An array of names of desired attributes
+ * @return array An array of the attributes representing the account
+ * @throws Zend_Ldap_Exception
+ */
+ protected function _getAccount($acctname, array $attrs = null)
+ {
+ $baseDn = $this->getBaseDn();
+ if (!$baseDn) {
+ /**
+ * @see Zend_Ldap_Exception
+ */
+ require_once 'Zend/Ldap/Exception.php';
+ throw new Zend_Ldap_Exception(null, 'Base DN not set');
+ }
+
+ $accountFilter = $this->_getAccountFilter($acctname);
+ if (!$accountFilter) {
+ /**
+ * @see Zend_Ldap_Exception
+ */
+ require_once 'Zend/Ldap/Exception.php';
+ throw new Zend_Ldap_Exception(null, 'Invalid account filter');
+ }
+
+ if (!is_resource($this->getResource())) {
+ $this->bind();
+ }
+
+ $accounts = $this->search($accountFilter, $baseDn, self::SEARCH_SCOPE_SUB, $attrs);
+ $count = $accounts->count();
+ if ($count === 1) {
+ $acct = $accounts->getFirst();
+ $accounts->close();
+ return $acct;
+ } else if ($count === 0) {
+ /**
+ * @see Zend_Ldap_Exception
+ */
+ require_once 'Zend/Ldap/Exception.php';
+ $code = Zend_Ldap_Exception::LDAP_NO_SUCH_OBJECT;
+ $str = "No object found for: $accountFilter";
+ } else {
+ /**
+ * @see Zend_Ldap_Exception
+ */
+ require_once 'Zend/Ldap/Exception.php';
+ $code = Zend_Ldap_Exception::LDAP_OPERATIONS_ERROR;
+ $str = "Unexpected result count ($count) for: $accountFilter";
+ }
+ $accounts->close();
+ /**
+ * @see Zend_Ldap_Exception
+ */
+ require_once 'Zend/Ldap/Exception.php';
+ throw new Zend_Ldap_Exception($this, $str, $code);
+ }
+
+ /**
+ * @return Zend_Ldap Provides a fluent interface
+ */
+ public function disconnect()
+ {
+ if (is_resource($this->getResource())) {
+ if (!extension_loaded('ldap')) {
+ /**
+ * @see Zend_Ldap_Exception
+ */
+ require_once 'Zend/Ldap/Exception.php';
+ throw new Zend_Ldap_Exception(null, 'LDAP extension not loaded',
+ Zend_Ldap_Exception::LDAP_X_EXTENSION_NOT_LOADED);
+ }
+ @ldap_unbind($this->getResource());
+ }
+ $this->_resource = null;
+ return $this;
+ }
+
+ /**
+ * @param string $host The hostname of the LDAP server to connect to
+ * @param int $port The port number of the LDAP server to connect to
+ * @param boolean $useSsl Use SSL
+ * @param boolean $useStartTls Use STARTTLS
+ * @return Zend_Ldap Provides a fluent interface
+ * @throws Zend_Ldap_Exception
+ */
+ public function connect($host = null, $port = null, $useSsl = null, $useStartTls = null)
+ {
+ if ($host === null) {
+ $host = $this->_getHost();
+ }
+ if ($port === null) {
+ $port = $this->_getPort();
+ } else {
+ $port = (int)$port;
+ }
+ if ($useSsl === null) {
+ $useSsl = $this->_getUseSsl();
+ } else {
+ $useSsl = (bool)$useSsl;
+ }
+ if ($useStartTls === null) {
+ $useStartTls = $this->_getUseStartTls();
+ } else {
+ $useStartTls = (bool)$useStartTls;
+ }
+
+ if (!$host) {
+ /**
+ * @see Zend_Ldap_Exception
+ */
+ require_once 'Zend/Ldap/Exception.php';
+ throw new Zend_Ldap_Exception(null, 'A host parameter is required');
+ }
+
+ /* To connect using SSL it seems the client tries to verify the server
+ * certificate by default. One way to disable this behavior is to set
+ * 'TLS_REQCERT never' in OpenLDAP's ldap.conf and restarting Apache. Or,
+ * if you really care about the server's cert you can put a cert on the
+ * web server.
+ */
+ $url = ($useSsl) ? "ldaps://$host" : "ldap://$host";
+ if ($port) {
+ $url .= ":$port";
+ }
+
+ /* Because ldap_connect doesn't really try to connect, any connect error
+ * will actually occur during the ldap_bind call. Therefore, we save the
+ * connect string here for reporting it in error handling in bind().
+ */
+ $this->_connectString = $url;
+
+ $this->disconnect();
+
+ if (!extension_loaded('ldap')) {
+ /**
+ * @see Zend_Ldap_Exception
+ */
+ require_once 'Zend/Ldap/Exception.php';
+ throw new Zend_Ldap_Exception(null, 'LDAP extension not loaded',
+ Zend_Ldap_Exception::LDAP_X_EXTENSION_NOT_LOADED);
+ }
+
+ /* Only OpenLDAP 2.2 + supports URLs so if SSL is not requested, just
+ * use the old form.
+ */
+ $resource = ($useSsl) ? @ldap_connect($url) : @ldap_connect($host, $port);
+
+ if (is_resource($resource) === true) {
+ $this->_resource = $resource;
+
+ $optReferrals = ($this->_getOptReferrals()) ? 1 : 0;
+ if (@ldap_set_option($resource, LDAP_OPT_PROTOCOL_VERSION, 3) &&
+ @ldap_set_option($resource, LDAP_OPT_REFERRALS, $optReferrals)) {
+ if ($useSsl || !$useStartTls || @ldap_start_tls($resource)) {
+ return $this;
+ }
+ }
+
+ /**
+ * @see Zend_Ldap_Exception
+ */
+ require_once 'Zend/Ldap/Exception.php';
+ $zle = new Zend_Ldap_Exception($this, "$host:$port");
+ $this->disconnect();
+ throw $zle;
+ }
+ /**
+ * @see Zend_Ldap_Exception
+ */
+ require_once 'Zend/Ldap/Exception.php';
+ throw new Zend_Ldap_Exception(null, "Failed to connect to LDAP server: $host:$port");
+ }
+
+ /**
+ * @param string $username The username for authenticating the bind
+ * @param string $password The password for authenticating the bind
+ * @return Zend_Ldap Provides a fluent interface
+ * @throws Zend_Ldap_Exception
+ */
+ public function bind($username = null, $password = null)
+ {
+ $moreCreds = true;
+
+ if ($username === null) {
+ $username = $this->_getUsername();
+ $password = $this->_getPassword();
+ $moreCreds = false;
+ }
+
+ if ($username === null) {
+ /* Perform anonymous bind
+ */
+ $password = null;
+ } else {
+ /* Check to make sure the username is in DN form.
+ */
+ /**
+ * @see Zend_Ldap_Dn
+ */
+ require_once 'Zend/Ldap/Dn.php';
+ if (!Zend_Ldap_Dn::checkDn($username)) {
+ if ($this->_getBindRequiresDn()) {
+ /* moreCreds stops an infinite loop if _getUsername does not
+ * return a DN and the bind requires it
+ */
+ if ($moreCreds) {
+ try {
+ $username = $this->_getAccountDn($username);
+ } catch (Zend_Ldap_Exception $zle) {
+ switch ($zle->getCode()) {
+ case Zend_Ldap_Exception::LDAP_NO_SUCH_OBJECT:
+ case Zend_Ldap_Exception::LDAP_X_DOMAIN_MISMATCH:
+ case Zend_Ldap_Exception::LDAP_X_EXTENSION_NOT_LOADED:
+ throw $zle;
+ }
+ throw new Zend_Ldap_Exception(null,
+ 'Failed to retrieve DN for account: ' . $username .
+ ' [' . $zle->getMessage() . ']',
+ Zend_Ldap_Exception::LDAP_OPERATIONS_ERROR);
+ }
+ } else {
+ /**
+ * @see Zend_Ldap_Exception
+ */
+ require_once 'Zend/Ldap/Exception.php';
+ throw new Zend_Ldap_Exception(null, 'Binding requires username in DN form');
+ }
+ } else {
+ $username = $this->getCanonicalAccountName($username,
+ $this->_getAccountCanonicalForm());
+ }
+ }
+ }
+
+ if (!is_resource($this->getResource())) {
+ $this->connect();
+ }
+
+ if ($username !== null && $password === '' && $this->_getAllowEmptyPassword() !== true) {
+ /**
+ * @see Zend_Ldap_Exception
+ */
+ require_once 'Zend/Ldap/Exception.php';
+ $zle = new Zend_Ldap_Exception(null,
+ 'Empty password not allowed - see allowEmptyPassword option.');
+ } else {
+ if (@ldap_bind($this->getResource(), $username, $password)) {
+ return $this;
+ }
+
+ $message = ($username === null) ? $this->_connectString : $username;
+ /**
+ * @see Zend_Ldap_Exception
+ */
+ require_once 'Zend/Ldap/Exception.php';
+ switch ($this->getLastErrorCode()) {
+ case Zend_Ldap_Exception::LDAP_SERVER_DOWN:
+ /* If the error is related to establishing a connection rather than binding,
+ * the connect string is more informative than the username.
+ */
+ $message = $this->_connectString;
+ }
+
+ $zle = new Zend_Ldap_Exception($this, $message);
+ }
+ $this->disconnect();
+ throw $zle;
+ }
+
+ /**
+ * A global LDAP search routine for finding information.
+ *
+ * @param string|Zend_Ldap_Filter_Abstract $filter
+ * @param string|Zend_Ldap_Dn|null $basedn
+ * @param integer $scope
+ * @param array $attributes
+ * @param string|null $sort
+ * @param string|null $collectionClass
+ * @return Zend_Ldap_Collection
+ * @throws Zend_Ldap_Exception
+ */
+ public function search($filter, $basedn = null, $scope = self::SEARCH_SCOPE_SUB,
+ array $attributes = array(), $sort = null, $collectionClass = null)
+ {
+ if ($basedn === null) {
+ $basedn = $this->getBaseDn();
+ }
+ else if ($basedn instanceof Zend_Ldap_Dn) {
+ $basedn = $basedn->toString();
+ }
+
+ if ($filter instanceof Zend_Ldap_Filter_Abstract) {
+ $filter = $filter->toString();
+ }
+
+ switch ($scope) {
+ case self::SEARCH_SCOPE_ONE:
+ $search = @ldap_list($this->getResource(), $basedn, $filter, $attributes);
+ break;
+ case self::SEARCH_SCOPE_BASE:
+ $search = @ldap_read($this->getResource(), $basedn, $filter, $attributes);
+ break;
+ case self::SEARCH_SCOPE_SUB:
+ default:
+ $search = @ldap_search($this->getResource(), $basedn, $filter, $attributes);
+ break;
+ }
+
+ if($search === false) {
+ /**
+ * @see Zend_Ldap_Exception
+ */
+ require_once 'Zend/Ldap/Exception.php';
+ throw new Zend_Ldap_Exception($this, 'searching: ' . $filter);
+ }
+ if (!is_null($sort) && is_string($sort)) {
+ $isSorted = @ldap_sort($this->getResource(), $search, $sort);
+ if($search === false) {
+ /**
+ * @see Zend_Ldap_Exception
+ */
+ require_once 'Zend/Ldap/Exception.php';
+ throw new Zend_Ldap_Exception($this, 'sorting: ' . $sort);
+ }
+ }
+
+ /**
+ * Zend_Ldap_Collection_Iterator_Default
+ */
+ require_once 'Zend/Ldap/Collection/Iterator/Default.php';
+ $iterator = new Zend_Ldap_Collection_Iterator_Default($this, $search);
+ if ($collectionClass === null) {
+ /**
+ * Zend_Ldap_Collection
+ */
+ require_once 'Zend/Ldap/Collection.php';
+ return new Zend_Ldap_Collection($iterator);
+ } else {
+ $collectionClass = (string)$collectionClass;
+ if (!class_exists($collectionClass)) {
+ /**
+ * @see Zend_Ldap_Exception
+ */
+ require_once 'Zend/Ldap/Exception.php';
+ throw new Zend_Ldap_Exception(null,
+ "Class '$collectionClass' can not be found");
+ }
+ if (!is_subclass_of($collectionClass, 'Zend_Ldap_Collection')) {
+ /**
+ * @see Zend_Ldap_Exception
+ */
+ require_once 'Zend/Ldap/Exception.php';
+ throw new Zend_Ldap_Exception(null,
+ "Class '$collectionClass' must subclass 'Zend_Ldap_Collection'");
+ }
+ return new $collectionClass($iterator);
+ }
+ }
+
+ /**
+ * Count items found by given filter.
+ *
+ * @param string|Zend_Ldap_Filter_Abstract $filter
+ * @param string|Zend_Ldap_Dn|null $basedn
+ * @param integer $scope
+ * @return integer
+ * @throws Zend_Ldap_Exception
+ */
+ public function count($filter, $basedn = null, $scope = self::SEARCH_SCOPE_SUB)
+ {
+ try {
+ $result = $this->search($filter, $basedn, $scope, array('dn'), null);
+ } catch (Zend_Ldap_Exception $e) {
+ if ($e->getCode() === Zend_Ldap_Exception::LDAP_NO_SUCH_OBJECT) return 0;
+ else throw $e;
+ }
+ return $result->count();
+ }
+
+ /**
+ * Count children for a given DN.
+ *
+ * @param string|Zend_Ldap_Dn $dn
+ * @return integer
+ * @throws Zend_Ldap_Exception
+ */
+ public function countChildren($dn)
+ {
+ return $this->count('(objectClass=*)', $dn, self::SEARCH_SCOPE_ONE);
+ }
+
+ /**
+ * Check if a given DN exists.
+ *
+ * @param string|Zend_Ldap_Dn $dn
+ * @return boolean
+ * @throws Zend_Ldap_Exception
+ */
+ public function exists($dn)
+ {
+ return ($this->count('(objectClass=*)', $dn, self::SEARCH_SCOPE_BASE) == 1);
+ }
+
+ /**
+ * Search LDAP registry for entries matching filter and optional attributes
+ *
+ * @param string|Zend_Ldap_Filter_Abstract $filter
+ * @param string|Zend_Ldap_Dn|null $basedn
+ * @param integer $scope
+ * @param array $attributes
+ * @param string|null $sort
+ * @return array
+ * @throws Zend_Ldap_Exception
+ */
+ public function searchEntries($filter, $basedn = null, $scope = self::SEARCH_SCOPE_SUB,
+ array $attributes = array(), $sort = null)
+ {
+ $result = $this->search($filter, $basedn, $scope, $attributes, $sort);
+ return $result->toArray();
+ }
+
+ /**
+ * Get LDAP entry by DN
+ *
+ * @param string|Zend_Ldap_Dn $dn
+ * @param array $attributes
+ * @param boolean $throwOnNotFound
+ * @return array
+ * @throws Zend_Ldap_Exception
+ */
+ public function getEntry($dn, array $attributes = array(), $throwOnNotFound = false)
+ {
+ try {
+ $result = $this->search("(objectClass=*)", $dn, self::SEARCH_SCOPE_BASE,
+ $attributes, null);
+ return $result->getFirst();
+ } catch (Zend_Ldap_Exception $e){
+ if ($throwOnNotFound !== false) throw $e;
+ }
+ return null;
+ }
+
+ /**
+ * Prepares an ldap data entry array for insert/update operation
+ *
+ * @param array $entry
+ * @return void
+ * @throws InvalidArgumentException
+ */
+ public static function prepareLdapEntryArray(array &$entry)
+ {
+ if (array_key_exists('dn', $entry)) unset($entry['dn']);
+ foreach ($entry as $key => $value) {
+ if (is_array($value)) {
+ foreach ($value as $i => $v) {
+ if (is_null($v)) unset($value[$i]);
+ else if (!is_scalar($v)) {
+ throw new InvalidArgumentException('Only scalar values allowed in LDAP data');
+ } else {
+ $v = (string)$v;
+ if (strlen($v) == 0) {
+ unset($value[$i]);
+ } else {
+ $value[$i] = $v;
+ }
+ }
+ }
+ $entry[$key] = array_values($value);
+ } else {
+ if (is_null($value)) $entry[$key] = array();
+ else if (!is_scalar($value)) {
+ throw new InvalidArgumentException('Only scalar values allowed in LDAP data');
+ } else {
+ $value = (string)$value;
+ if (strlen($value) == 0) {
+ $entry[$key] = array();
+ } else {
+ $entry[$key] = array($value);
+ }
+ }
+ }
+ }
+ $entry = array_change_key_case($entry, CASE_LOWER);
+ }
+
+ /**
+ * Add new information to the LDAP repository
+ *
+ * @param string|Zend_Ldap_Dn $dn
+ * @param array $entry
+ * @return Zend_Ldap Provides a fluid interface
+ * @throws Zend_Ldap_Exception
+ */
+ public function add($dn, array $entry)
+ {
+ if (!($dn instanceof Zend_Ldap_Dn)) {
+ $dn = Zend_Ldap_Dn::factory($dn, null);
+ }
+ self::prepareLdapEntryArray($entry);
+ foreach ($entry as $key => $value) {
+ if (is_array($value) && count($value) === 0) {
+ unset($entry[$key]);
+ }
+ }
+
+ $rdnParts = $dn->getRdn(Zend_Ldap_Dn::ATTR_CASEFOLD_LOWER);
+ foreach ($rdnParts as $key => $value) {
+ $value = Zend_Ldap_Dn::unescapeValue($value);
+ if (!array_key_exists($key, $entry) ||
+ !in_array($value, $entry[$key]) ||
+ count($entry[$key]) !== 1) {
+ $entry[$key] = array($value);
+ }
+ }
+ $adAttributes = array('distinguishedname', 'instancetype', 'name', 'objectcategory',
+ 'objectguid', 'usnchanged', 'usncreated', 'whenchanged', 'whencreated');
+ foreach ($adAttributes as $attr) {
+ if (array_key_exists($attr, $entry)) {
+ unset($entry[$attr]);
+ }
+ }
+
+ $isAdded = @ldap_add($this->getResource(), $dn->toString(), $entry);
+ if($isAdded === false) {
+ /**
+ * @see Zend_Ldap_Exception
+ */
+ require_once 'Zend/Ldap/Exception.php';
+ throw new Zend_Ldap_Exception($this, 'adding: ' . $dn->toString());
+ }
+ return $this;
+ }
+
+ /**
+ * Update LDAP registry
+ *
+ * @param string|Zend_Ldap_Dn $dn
+ * @param array $entry
+ * @return Zend_Ldap Provides a fluid interface
+ * @throws Zend_Ldap_Exception
+ */
+ public function update($dn, array $entry)
+ {
+ if (!($dn instanceof Zend_Ldap_Dn)) {
+ $dn = Zend_Ldap_Dn::factory($dn, null);
+ }
+ self::prepareLdapEntryArray($entry);
+
+ $rdnParts = $dn->getRdn(Zend_Ldap_Dn::ATTR_CASEFOLD_LOWER);
+ $adAttributes = array('distinguishedname', 'instancetype', 'name', 'objectcategory',
+ 'objectguid', 'usnchanged', 'usncreated', 'whenchanged', 'whencreated');
+ $stripAttributes = array_merge(array_keys($rdnParts), $adAttributes);
+ foreach ($stripAttributes as $attr) {
+ if (array_key_exists($attr, $entry)) {
+ unset($entry[$attr]);
+ }
+ }
+
+ if (count($entry) > 0) {
+ $isModified = @ldap_modify($this->getResource(), $dn->toString(), $entry);
+ if($isModified === false) {
+ /**
+ * @see Zend_Ldap_Exception
+ */
+ require_once 'Zend/Ldap/Exception.php';
+ throw new Zend_Ldap_Exception($this, 'updating: ' . $dn->toString());
+ }
+ }
+ return $this;
+ }
+
+ /**
+ * Save entry to LDAP registry.
+ *
+ * Internally decides if entry will be updated to added by calling
+ * {@link exists()}.
+ *
+ * @param string|Zend_Ldap_Dn $dn
+ * @param array $entry
+ * @return Zend_Ldap Provides a fluid interface
+ * @throws Zend_Ldap_Exception
+ */
+ public function save($dn, array $entry)
+ {
+ if ($dn instanceof Zend_Ldap_Dn) {
+ $dn = $dn->toString();
+ }
+ if ($this->exists($dn)) $this->update($dn, $entry);
+ else $this->add($dn, $entry);
+ return $this;
+ }
+
+ /**
+ * Delete an LDAP entry
+ *
+ * @param string|Zend_Ldap_Dn $dn
+ * @param boolean $recursively
+ * @return Zend_Ldap Provides a fluid interface
+ * @throws Zend_Ldap_Exception
+ */
+ public function delete($dn, $recursively = false)
+ {
+ if ($dn instanceof Zend_Ldap_Dn) {
+ $dn = $dn->toString();
+ }
+ if ($recursively === true) {
+ if ($this->countChildren($dn)>0) {
+ $children = $this->_getChildrenDns($dn);
+ foreach ($children as $c) {
+ $this->delete($c, true);
+ }
+ }
+ }
+ $isDeleted = @ldap_delete($this->getResource(), $dn);
+ if($isDeleted === false) {
+ /**
+ * @see Zend_Ldap_Exception
+ */
+ require_once 'Zend/Ldap/Exception.php';
+ throw new Zend_Ldap_Exception($this, 'deleting: ' . $dn);
+ }
+ return $this;
+ }
+
+ /**
+ * Retrieve the immediate children DNs of the given $parentDn
+ *
+ * This method is used in recursive methods like {@see delete()}
+ * or {@see copy()}
+ *
+ * @param string|Zend_Ldap_Dn $parentDn
+ * @return array of DNs
+ */
+ protected function _getChildrenDns($parentDn)
+ {
+ if ($parentDn instanceof Zend_Ldap_Dn) {
+ $parentDn = $parentDn->toString();
+ }
+ $children = array();
+ $search = @ldap_list($this->getResource(), $parentDn, '(objectClass=*)', array('dn'));
+ for ($entry = @ldap_first_entry($this->getResource(), $search);
+ $entry !== false;
+ $entry = @ldap_next_entry($this->getResource(), $entry)) {
+ $childDn = @ldap_get_dn($this->getResource(), $entry);
+ if ($childDn === false) {
+ /**
+ * @see Zend_Ldap_Exception
+ */
+ require_once 'Zend/Ldap/Exception.php';
+ throw new Zend_Ldap_Exception($this, 'getting dn');
+ }
+ $children[] = $childDn;
+ }
+ @ldap_free_result($search);
+ return $children;
+ }
+
+ /**
+ * Moves a LDAP entry from one DN to another subtree.
+ *
+ * @param string|Zend_Ldap_Dn $from
+ * @param string|Zend_Ldap_Dn $to
+ * @param boolean $recursively
+ * @param boolean $alwaysEmulate
+ * @return Zend_Ldap Provides a fluid interface
+ * @throws Zend_Ldap_Exception
+ */
+ public function moveToSubtree($from, $to, $recursively = false, $alwaysEmulate = false)
+ {
+ if ($from instanceof Zend_Ldap_Dn) {
+ $orgDnParts = $from->toArray();
+ } else {
+ $orgDnParts = Zend_Ldap_Dn::explodeDn($from);
+ }
+
+ if ($to instanceof Zend_Ldap_Dn) {
+ $newParentDnParts = $to->toArray();
+ } else {
+ $newParentDnParts = Zend_Ldap_Dn::explodeDn($to);
+ }
+
+ $newDnParts = array_merge(array(array_shift($orgDnParts)), $newParentDnParts);
+ $newDn = Zend_Ldap_Dn::fromArray($newDnParts);
+ return $this->rename($from, $newDn, $recursively, $alwaysEmulate);
+ }
+
+ /**
+ * Moves a LDAP entry from one DN to another DN.
+ *
+ * This is an alias for {@link rename()}
+ *
+ * @param string|Zend_Ldap_Dn $from
+ * @param string|Zend_Ldap_Dn $to
+ * @param boolean $recursively
+ * @param boolean $alwaysEmulate
+ * @return Zend_Ldap Provides a fluid interface
+ * @throws Zend_Ldap_Exception
+ */
+ public function move($from, $to, $recursively = false, $alwaysEmulate = false)
+ {
+ return $this->rename($from, $to, $recursively, $alwaysEmulate);
+ }
+
+ /**
+ * Renames a LDAP entry from one DN to another DN.
+ *
+ * This method implicitely moves the entry to another location within the tree.
+ *
+ * @param string|Zend_Ldap_Dn $from
+ * @param string|Zend_Ldap_Dn $to
+ * @param boolean $recursively
+ * @param boolean $alwaysEmulate
+ * @return Zend_Ldap Provides a fluid interface
+ * @throws Zend_Ldap_Exception
+ */
+ public function rename($from, $to, $recursively = false, $alwaysEmulate = false)
+ {
+ $emulate = (bool)$alwaysEmulate;
+ if (!function_exists('ldap_rename')) $emulate = true;
+ else if ($recursively) $emulate = true;
+
+ if ($emulate === false) {
+ if ($from instanceof Zend_Ldap_Dn) {
+ $from = $from->toString();
+ }
+
+ if ($to instanceof Zend_Ldap_Dn) {
+ $newDnParts = $to->toArray();
+ } else {
+ $newDnParts = Zend_Ldap_Dn::explodeDn($to);
+ }
+
+ $newRdn = Zend_Ldap_Dn::implodeRdn(array_shift($newDnParts));
+ $newParent = Zend_Ldap_Dn::implodeDn($newDnParts);
+ $isOK = @ldap_rename($this->getResource(), $from, $newRdn, $newParent, true);
+ if($isOK === false) {
+ /**
+ * @see Zend_Ldap_Exception
+ */
+ require_once 'Zend/Ldap/Exception.php';
+ throw new Zend_Ldap_Exception($this, 'renaming ' . $from . ' to ' . $to);
+ }
+ else if (!$this->exists($to)) $emulate = true;
+ }
+ if ($emulate) {
+ $this->copy($from, $to, $recursively);
+ $this->delete($from, $recursively);
+ }
+ return $this;
+ }
+
+ /**
+ * Copies a LDAP entry from one DN to another subtree.
+ *
+ * @param string|Zend_Ldap_Dn $from
+ * @param string|Zend_Ldap_Dn $to
+ * @param boolean $recursively
+ * @return Zend_Ldap Provides a fluid interface
+ * @throws Zend_Ldap_Exception
+ */
+ public function copyToSubtree($from, $to, $recursively = false)
+ {
+ if ($from instanceof Zend_Ldap_Dn) {
+ $orgDnParts = $from->toArray();
+ } else {
+ $orgDnParts = Zend_Ldap_Dn::explodeDn($from);
+ }
+
+ if ($to instanceof Zend_Ldap_Dn) {
+ $newParentDnParts = $to->toArray();
+ } else {
+ $newParentDnParts = Zend_Ldap_Dn::explodeDn($to);
+ }
+
+ $newDnParts = array_merge(array(array_shift($orgDnParts)), $newParentDnParts);
+ $newDn = Zend_Ldap_Dn::fromArray($newDnParts);
+ return $this->copy($from, $newDn, $recursively);
+ }
+
+ /**
+ * Copies a LDAP entry from one DN to another DN.
+ *
+ * @param string|Zend_Ldap_Dn $from
+ * @param string|Zend_Ldap_Dn $to
+ * @param boolean $recursively
+ * @return Zend_Ldap Provides a fluid interface
+ * @throws Zend_Ldap_Exception
+ */
+ public function copy($from, $to, $recursively = false)
+ {
+ $entry = $this->getEntry($from, array(), true);
+
+ if ($to instanceof Zend_Ldap_Dn) {
+ $toDnParts = $to->toArray();
+ } else {
+ $toDnParts = Zend_Ldap_Dn::explodeDn($to);
+ }
+ $this->add($to, $entry);
+
+ if ($recursively === true && $this->countChildren($from)>0) {
+ $children = $this->_getChildrenDns($from);
+ foreach ($children as $c) {
+ $cDnParts = Zend_Ldap_Dn::explodeDn($c);
+ $newChildParts = array_merge(array(array_shift($cDnParts)), $toDnParts);
+ $newChild = Zend_Ldap_Dn::implodeDn($newChildParts);
+ $this->copy($c, $newChild, true);
+ }
+ }
+ return $this;
+ }
+
+ /**
+ * Returns the specified DN as a Zend_Ldap_Node
+ *
+ * @param string|Zend_Ldap_Dn $dn
+ * @return Zend_Ldap_Node
+ * @throws Zend_Ldap_Exception
+ */
+ public function getNode($dn)
+ {
+ /**
+ * Zend_Ldap_Node
+ */
+ require_once 'Zend/Ldap/Node.php';
+ return Zend_Ldap_Node::fromLdap($dn, $this);
+ }
+
+ /**
+ * Returns the base node as a Zend_Ldap_Node
+ *
+ * @return Zend_Ldap_Node
+ * @throws Zend_Ldap_Exception
+ */
+ public function getBaseNode()
+ {
+ return $this->getNode($this->getBaseDn(), $this);
+ }
+
+ /**
+ * Returns the RootDSE
+ *
+ * @return Zend_Ldap_Node_RootDse
+ * @throws Zend_Ldap_Exception
+ */
+ public function getRootDse()
+ {
+ if ($this->_rootDse === null) {
+ /**
+ * @see Zend_Ldap_Node_Schema
+ */
+ require_once 'Zend/Ldap/Node/RootDse.php';
+ $this->_rootDse = Zend_Ldap_Node_RootDse::create($this);
+ }
+ return $this->_rootDse;
+ }
+
+ /**
+ * Returns the schema
+ *
+ * @return Zend_Ldap_Node_Schema
+ * @throws Zend_Ldap_Exception
+ */
+ public function getSchema()
+ {
+ if ($this->_schema === null) {
+ /**
+ * @see Zend_Ldap_Node_Schema
+ */
+ require_once 'Zend/Ldap/Node/Schema.php';
+ $this->_schema = Zend_Ldap_Node_Schema::create($this);
+ }
+ return $this->_schema;
+ }
+}
*
* @category Zend
* @package Zend_Loader
- * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id$
*/
*
* @category Zend
* @package Zend_Loader
- * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Loader
self::loadFile($file, $dirs, true);
} else {
self::_securityCheck($file);
- include_once $file;
+ include $file;
}
if (!class_exists($class, false) && !interface_exists($class, false)) {
* spl_autoload_register(array('Zend_Loader', 'autoload'));
* </code>
*
- * @param string $class
+ * @deprecated Since 1.8.0
+ * @param string $class
* @return string|false Class name on success; false on failure
*/
public static function autoload($class)
{
+ trigger_error(__CLASS__ . '::' . __METHOD__ . ' is deprecated as of 1.8.0 and will be removed with 2.0.0; use Zend_Loader_Autoloader instead', E_USER_NOTICE);
try {
- self::loadClass($class);
+ @self::loadClass($class);
return $class;
} catch (Exception $e) {
return false;
/**
* Register {@link autoload()} with spl_autoload()
*
+ * @deprecated Since 1.8.0
* @param string $class (optional)
* @param boolean $enabled (optional)
* @return void
*/
public static function registerAutoload($class = 'Zend_Loader', $enabled = true)
{
- if (!function_exists('spl_autoload_register')) {
- require_once 'Zend/Exception.php';
- throw new Zend_Exception('spl_autoload does not exist in this PHP installation');
- }
+ trigger_error(__CLASS__ . '::' . __METHOD__ . ' is deprecated as of 1.8.0 and will be removed with 2.0.0; use Zend_Loader_Autoloader instead', E_USER_NOTICE);
+ require_once 'Zend/Loader/Autoloader.php';
+ $autoloader = Zend_Loader_Autoloader::getInstance();
+ $autoloader->setFallbackAutoloader(true);
- self::loadClass($class);
- $methods = get_class_methods($class);
- if (!in_array('autoload', (array) $methods)) {
- require_once 'Zend/Exception.php';
- throw new Zend_Exception("The class \"$class\" does not have an autoload() method");
- }
+ if ('Zend_Loader' != $class) {
+ self::loadClass($class);
+ $methods = get_class_methods($class);
+ if (!in_array('autoload', (array) $methods)) {
+ require_once 'Zend/Exception.php';
+ throw new Zend_Exception("The class \"$class\" does not have an autoload() method");
+ }
- if ($enabled === true) {
- spl_autoload_register(array($class, 'autoload'));
- } else {
- spl_autoload_unregister(array($class, 'autoload'));
+ $callback = array($class, 'autoload');
+
+ if ($enabled) {
+ $autoloader->pushAutoloader($callback);
+ } else {
+ $autoloader->removeAutoloader($callback);
+ }
}
}
/**
* Security check
*/
- if (preg_match('/[^a-z0-9\\/\\\\_.-]/i', $filename)) {
+ if (preg_match('/[^a-z0-9\\/\\\\_.:-]/i', $filename)) {
require_once 'Zend/Exception.php';
throw new Zend_Exception('Security check: Illegal character in filename');
}
--- /dev/null
+<?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_Locale
+ * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ * @version $Id$
+ */
+
+/**
+ * Base class for localization
+ *
+ * @category Zend
+ * @package Zend_Locale
+ * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+class Zend_Locale
+{
+ /**
+ * Class wide Locale Constants
+ *
+ * @var array $_localeData
+ */
+ private static $_localeData = array(
+ 'root' => true, 'aa_DJ' => true, 'aa_ER' => true, 'aa_ET' => true, 'aa' => true,
+ 'af_NA' => true, 'af_ZA' => true, 'af' => true, 'ak_GH' => true, 'ak' => true,
+ 'am_ET' => true, 'am' => true, 'ar_AE' => true, 'ar_BH' => true, 'ar_DZ' => true,
+ 'ar_EG' => true, 'ar_IQ' => true, 'ar_JO' => true, 'ar_KW' => true, 'ar_LB' => true,
+ 'ar_LY' => true, 'ar_MA' => true, 'ar_OM' => true, 'ar_QA' => true, 'ar_SA' => true,
+ 'ar_SD' => true, 'ar_SY' => true, 'ar_TN' => true, 'ar_YE' => true, 'ar' => true,
+ 'as_IN' => true, 'as' => true, 'az_AZ' => true, 'az' => true, 'be_BY' => true,
+ 'be' => true, 'bg_BG' => true, 'bg' => true, 'bn_BD' => true, 'bn_IN' => true,
+ 'bn' => true, 'bo_CN' => true, 'bo_IN' => true, 'bo' => true, 'bs_BA' => true,
+ 'bs' => true, 'byn_ER'=> true, 'byn' => true, 'ca_ES' => true, 'ca' => true,
+ 'cch_NG'=> true, 'cch' => true, 'cop' => true, 'cs_CZ' => true, 'cs' => true,
+ 'cy_GB' => true, 'cy' => true, 'da_DK' => true, 'da' => true, 'de_AT' => true,
+ 'de_BE' => true, 'de_CH' => true, 'de_DE' => true, 'de_LI' => true, 'de_LU' => true,
+ 'de' => true, 'dv_MV' => true, 'dv' => true, 'dz_BT' => true, 'dz' => true,
+ 'ee_GH' => true, 'ee_TG' => true, 'ee' => true, 'el_CY' => true, 'el_GR' => true,
+ 'el' => true, 'en_AS' => true, 'en_AU' => true, 'en_BE' => true, 'en_BW' => true,
+ 'en_BZ' => true, 'en_CA' => true, 'en_GB' => true, 'en_GU' => true, 'en_HK' => true,
+ 'en_IE' => true, 'en_IN' => true, 'en_JM' => true, 'en_MH' => true, 'en_MP' => true,
+ 'en_MT' => true, 'en_NA' => true, 'en_NZ' => true, 'en_PH' => true, 'en_PK' => true,
+ 'en_SG' => true, 'en_TT' => true, 'en_UM' => true, 'en_US' => true, 'en_VI' => true,
+ 'en_ZA' => true, 'en_ZW' => true, 'en' => true, 'eo' => true, 'es_AR' => true,
+ 'es_BO' => true, 'es_CL' => true, 'es_CO' => true, 'es_CR' => true, 'es_DO' => true,
+ 'es_EC' => true, 'es_ES' => true, 'es_GT' => true, 'es_HN' => true, 'es_MX' => true,
+ 'es_NI' => true, 'es_PA' => true, 'es_PE' => true, 'es_PR' => true, 'es_PY' => true,
+ 'es_SV' => true, 'es_US' => true, 'es_UY' => true, 'es_VE' => true, 'es' => true,
+ 'et_EE' => true, 'et' => true, 'eu_ES' => true, 'eu' => true, 'fa_AF' => true,
+ 'fa_IR' => true, 'fa' => true, 'fi_FI' => true, 'fi' => true, 'fil_PH'=> true,
+ 'fil' => true, 'fo_FO' => true, 'fo' => true, 'fr_BE' => true, 'fr_CA' => true,
+ 'fr_CH' => true, 'fr_FR' => true, 'fr_LU' => true, 'fr_MC' => true, 'fr_SN' => true,
+ 'fr' => true, 'fur_IT'=> true, 'fur' => true, 'ga_IE' => true, 'ga' => true,
+ 'gaa_GH'=> true, 'gaa' => true, 'gez_ER'=> true, 'gez_ET'=> true, 'gez' => true,
+ 'gl_ES' => true, 'gl' => true, 'gsw_CH'=> true, 'gsw' => true, 'gu_IN' => true,
+ 'gu' => true, 'gv_GB' => true, 'gv' => true, 'ha_GH' => true, 'ha_NE' => true,
+ 'ha_NG' => true, 'ha_SD' => true, 'ha' => true, 'haw_US'=> true, 'haw' => true,
+ 'he_IL' => true, 'he' => true, 'hi_IN' => true, 'hi' => true, 'hr_HR' => true,
+ 'hr' => true, 'hu_HU' => true, 'hu' => true, 'hy_AM' => true, 'hy' => true,
+ 'ia' => true, 'id_ID' => true, 'id' => true, 'ig_NG' => true, 'ig' => true,
+ 'ii_CN' => true, 'ii' => true, 'in' => true, 'is_IS' => true, 'is' => true,
+ 'it_CH' => true, 'it_IT' => true, 'it' => true, 'iu' => true, 'iw' => true,
+ 'ja_JP' => true, 'ja' => true, 'ka_GE' => true, 'ka' => true, 'kaj_NG'=> true,
+ 'kaj' => true, 'kam_KE'=> true, 'kam' => true, 'kcg_NG'=> true, 'kcg' => true,
+ 'kfo_CI'=> true, 'kfo' => true, 'kk_KZ' => true, 'kk' => true, 'kl_GL' => true,
+ 'kl' => true, 'km_KH' => true, 'km' => true, 'kn_IN' => true, 'kn' => true,
+ 'ko_KR' => true, 'ko' => true, 'kok_IN'=> true, 'kok' => true, 'kpe_GN'=> true,
+ 'kpe_LR'=> true, 'kpe' => true, 'ku_IQ' => true, 'ku_IR' => true, 'ku_SY' => true,
+ 'ku_TR' => true, 'ku' => true, 'kw_GB' => true, 'kw' => true, 'ky_KG' => true,
+ 'ky' => true, 'ln_CD' => true, 'ln_CG' => true, 'ln' => true, 'lo_LA' => true,
+ 'lo' => true, 'lt_LT' => true, 'lt' => true, 'lv_LV' => true, 'lv' => true,
+ 'mk_MK' => true, 'mk' => true, 'ml_IN' => true, 'ml' => true, 'mn_CN' => true,
+ 'mn_MN' => true, 'mn' => true, 'mo' => true, 'mr_IN' => true, 'mr' => true,
+ 'ms_BN' => true, 'ms_MY' => true, 'ms' => true, 'mt_MT' => true, 'mt' => true,
+ 'my_MM' => true, 'my' => true, 'nb_NO' => true, 'nb' => true, 'nds_DE'=> true,
+ 'nds' => true, 'ne_IN' => true, 'ne_NP' => true, 'ne' => true, 'nl_BE' => true,
+ 'nl_NL' => true, 'nl' => true, 'nn_NO' => true, 'nn' => true, 'no' => true,
+ 'nr_ZA' => true, 'nr' => true, 'nso_ZA'=> true, 'nso' => true, 'ny_MW' => true,
+ 'ny' => true, 'oc_FR' => true, 'oc' => true, 'om_ET' => true, 'om_KE' => true,
+ 'om' => true, 'or_IN' => true, 'or' => true, 'pa_IN' => true, 'pa_PK' => true,
+ 'pa' => true, 'pl_PL' => true, 'pl' => true, 'ps_AF' => true, 'ps' => true,
+ 'pt_BR' => true, 'pt_PT' => true, 'pt' => true, 'ro_MD' => true, 'ro_RO' => true,
+ 'ro' => true, 'ru_RU' => true, 'ru_UA' => true, 'ru' => true, 'rw_RW' => true,
+ 'rw' => true, 'sa_IN' => true, 'sa' => true, 'se_FI' => true, 'se_NO' => true,
+ 'se' => true, 'sh_BA' => true, 'sh_CS' => true, 'sh_YU' => true, 'sh' => true,
+ 'si_LK' => true, 'si' => true, 'sid_ET'=> true, 'sid' => true, 'sk_SK' => true,
+ 'sk' => true, 'sl_SI' => true, 'sl' => true, 'so_DJ' => true, 'so_ET' => true,
+ 'so_KE' => true, 'so_SO' => true, 'so' => true, 'sq_AL' => true, 'sq' => true,
+ 'sr_BA' => true, 'sr_CS' => true, 'sr_ME' => true, 'sr_RS' => true, 'sr_YU' => true,
+ 'sr' => true, 'ss_SZ' => true, 'ss_ZA' => true, 'ss' => true, 'st_LS' => true,
+ 'st_ZA' => true, 'st' => true, 'sv_FI' => true, 'sv_SE' => true, 'sv' => true,
+ 'sw_KE' => true, 'sw_TZ' => true, 'sw' => true, 'syr_SY'=> true, 'syr' => true,
+ 'ta_IN' => true, 'ta' => true, 'te_IN' => true, 'te' => true, 'tg_TJ' => true,
+ 'tg' => true, 'th_TH' => true, 'th' => true, 'ti_ER' => true, 'ti_ET' => true,
+ 'ti' => true, 'tig_ER'=> true, 'tig' => true, 'tl' => true, 'tn_ZA' => true,
+ 'tn' => true, 'to_TO' => true, 'to' => true, 'tr_TR' => true, 'tr' => true,
+ 'trv_TW'=> true, 'trv' => true, 'ts_ZA' => true, 'ts' => true, 'tt_RU' => true,
+ 'tt' => true, 'ug_CN' => true, 'ug' => true, 'uk_UA' => true, 'uk' => true,
+ 'ur_IN' => true, 'ur_PK' => true, 'ur' => true, 'uz_AF' => true, 'uz_UZ' => true,
+ 'uz' => true, 've_ZA' => true, 've' => true, 'vi_VN' => true, 'vi' => true,
+ 'wal_ET'=> true, 'wal' => true, 'wo_SN' => true, 'wo' => true, 'xh_ZA' => true,
+ 'xh' => true, 'yo_NG' => true, 'yo' => true, 'zh_CN' => true, 'zh_HK' => true,
+ 'zh_MO' => true, 'zh_SG' => true, 'zh_TW' => true, 'zh' => true, 'zu_ZA' => true,
+ 'zu' => true
+ );
+
+ /**
+ * Autosearch constants
+ */
+ const BROWSER = 'browser';
+ const ENVIRONMENT = 'environment';
+ const ZFDEFAULT = 'default';
+
+ /**
+ * Defines if old behaviour should be supported
+ * Old behaviour throws notices and will be deleted in future releases
+ *
+ * @var boolean
+ */
+ public static $compatibilityMode = false;
+
+ /**
+ * Internal variable
+ *
+ * @var boolean
+ */
+ private static $_breakChain = false;
+
+ /**
+ * Actual set locale
+ *
+ * @var string Locale
+ */
+ protected $_locale;
+
+ /**
+ * Automatic detected locale
+ *
+ * @var string Locales
+ */
+ protected static $_auto;
+
+ /**
+ * Browser detected locale
+ *
+ * @var string Locales
+ */
+ protected static $_browser;
+
+ /**
+ * Environment detected locale
+ *
+ * @var string Locales
+ */
+ protected static $_environment;
+
+ /**
+ * Default locale
+ *
+ * @var string Locales
+ */
+ protected static $_default = array('en' => true);
+
+ /**
+ * Generates a locale object
+ * If no locale is given a automatic search is done
+ * Then the most probable locale will be automatically set
+ * Search order is
+ * 1. Given Locale
+ * 2. HTTP Client
+ * 3. Server Environment
+ * 4. Framework Standard
+ *
+ * @param string|Zend_Locale $locale (Optional) Locale for parsing input
+ * @throws Zend_Locale_Exception When autodetection has been failed
+ */
+ public function __construct($locale = null)
+ {
+ $locale = self::_prepareLocale($locale);
+ $this->setLocale((string) $locale);
+ }
+
+ /**
+ * Serialization Interface
+ *
+ * @return string
+ */
+ public function serialize()
+ {
+ return serialize($this);
+ }
+
+ /**
+ * Returns a string representation of the object
+ *
+ * @return string
+ */
+ public function toString()
+ {
+ return (string) $this->_locale;
+ }
+
+ /**
+ * Returns a string representation of the object
+ * Alias for toString
+ *
+ * @return string
+ */
+ public function __toString()
+ {
+ return $this->toString();
+ }
+
+ /**
+ * Return the default locale
+ *
+ * @return array Returns an array of all locale string
+ */
+ public static function getDefault()
+ {
+ if ((self::$compatibilityMode === true) or (func_num_args() > 0)) {
+ if (!self::$_breakChain) {
+ self::$_breakChain = true;
+ trigger_error('You are running Zend_Locale in compatibility mode... please migrate your scripts', E_USER_NOTICE);
+ $params = func_get_args();
+ $param = null;
+ if (isset($params[0])) {
+ $param = $params[0];
+ }
+ return self::getOrder($param);
+ }
+
+ self::$_breakChain = false;
+ }
+
+ return self::$_default;
+ }
+
+ /**
+ * Sets a new default locale which will be used when no locale can be detected
+ * If provided you can set a quality between 0 and 1 (or 2 and 100)
+ * which represents the percent of quality the browser
+ * requested within HTTP
+ *
+ * @param string|Zend_Locale $locale Locale to set
+ * @param float $quality The quality to set from 0 to 1
+ * @throws Zend_Locale_Exception When a autolocale was given
+ * @throws Zend_Locale_Exception When a unknown locale was given
+ * @return void
+ */
+ public static function setDefault($locale, $quality = 1)
+ {
+ if (($locale === 'auto') or ($locale === 'root') or ($locale === 'default') or
+ ($locale === 'environment') or ($locale === 'browser')) {
+ require_once 'Zend/Locale/Exception.php';
+ throw new Zend_Locale_Exception('Only full qualified locales can be used as default!');
+ }
+
+ if (($quality < 0.1) or ($quality > 100)) {
+ require_once 'Zend/Locale/Exception.php';
+ throw new Zend_Locale_Exception("Quality must be between 0.1 and 100");
+ }
+
+ if ($quality > 1) {
+ $quality /= 100;
+ }
+
+ $locale = self::_prepareLocale($locale);
+ if (isset(self::$_localeData[(string) $locale]) === true) {
+ self::$_default = array((string) $locale => $quality);
+ } else {
+ $elocale = explode('_', (string) $locale);
+ if (isset(self::$_localeData[$elocale[0]]) === true) {
+ self::$_default = array($elocale[0] => $quality);
+ } else {
+ require_once 'Zend/Locale/Exception.php';
+ throw new Zend_Locale_Exception("Unknown locale '" . (string) $locale . "' can not be set as default!");
+ }
+ }
+ }
+
+ /**
+ * Expects the Systems standard locale
+ *
+ * For Windows:
+ * f.e.: LC_COLLATE=C;LC_CTYPE=German_Austria.1252;LC_MONETARY=C
+ * would be recognised as de_AT
+ *
+ * @return array
+ */
+ public static function getEnvironment()
+ {
+ if (self::$_environment !== null) {
+ return self::$_environment;
+ }
+
+ require_once 'Zend/Locale/Data/Translation.php';
+
+ $language = setlocale(LC_ALL, 0);
+ $languages = explode(';', $language);
+ $languagearray = array();
+
+ foreach ($languages as $locale) {
+ if (strpos($locale, '=') !== false) {
+ $language = substr($locale, strpos($locale, '='));
+ $language = substr($language, 1);
+ }
+
+ if ($language !== 'C') {
+ if (strpos($language, '.') !== false) {
+ $language = substr($language, 0, (strpos($language, '.') - 1));
+ } else if (strpos($language, '@') !== false) {
+ $language = substr($language, 0, (strpos($language, '@') - 1));
+ }
+
+ $splitted = explode('_', $language);
+ $language = (string) $language;
+ if (isset(self::$_localeData[$language]) === true) {
+ $languagearray[$language] = 1;
+ if (strlen($language) > 4) {
+ $languagearray[substr($language, 0, 2)] = 1;
+ }
+
+ continue;
+ }
+
+ if (empty(Zend_Locale_Data_Translation::$localeTranslation[$splitted[0]]) === false) {
+ if (empty(Zend_Locale_Data_Translation::$localeTranslation[$splitted[1]]) === false) {
+ $languagearray[Zend_Locale_Data_Translation::$localeTranslation[$splitted[0]] . '_' .
+ Zend_Locale_Data_Translation::$localeTranslation[$splitted[1]]] = 1;
+ }
+
+ $languagearray[Zend_Locale_Data_Translation::$localeTranslation[$splitted[0]]] = 1;
+ }
+ }
+ }
+
+ self::$_environment = $languagearray;
+ return $languagearray;
+ }
+
+ /**
+ * Return an array of all accepted languages of the client
+ * Expects RFC compilant Header !!
+ *
+ * The notation can be :
+ * de,en-UK-US;q=0.5,fr-FR;q=0.2
+ *
+ * @return array - list of accepted languages including quality
+ */
+ public static function getBrowser()
+ {
+ if (self::$_browser !== null) {
+ return self::$_browser;
+ }
+
+ $httplanguages = getenv('HTTP_ACCEPT_LANGUAGE');
+ $languages = array();
+ if (empty($httplanguages) === true) {
+ return $languages;
+ }
+
+ $accepted = preg_split('/,\s*/', $httplanguages);
+
+ foreach ($accepted as $accept) {
+ $match = null;
+ $result = preg_match('/^([a-z]{1,8}(?:[-_][a-z]{1,8})*)(?:;\s*q=(0(?:\.[0-9]{1,3})?|1(?:\.0{1,3})?))?$/i',
+ $accept, $match);
+
+ if ($result < 1) {
+ continue;
+ }
+
+ if (isset($match[2]) === true) {
+ $quality = (float) $match[2];
+ } else {
+ $quality = 1.0;
+ }
+
+ $countrys = explode('-', $match[1]);
+ $region = array_shift($countrys);
+
+ $country2 = explode('_', $region);
+ $region = array_shift($country2);
+
+ foreach ($countrys as $country) {
+ $languages[$region . '_' . strtoupper($country)] = $quality;
+ }
+
+ foreach ($country2 as $country) {
+ $languages[$region . '_' . strtoupper($country)] = $quality;
+ }
+
+ if ((isset($languages[$region]) === false) || ($languages[$region] < $quality)) {
+ $languages[$region] = $quality;
+ }
+ }
+
+ self::$_browser = $languages;
+ return $languages;
+ }
+
+ /**
+ * Sets a new locale
+ *
+ * @param string|Zend_Locale $locale (Optional) New locale to set
+ * @return void
+ */
+ public function setLocale($locale = null)
+ {
+ $locale = self::_prepareLocale($locale);
+
+ if (isset(self::$_localeData[(string) $locale]) === false) {
+ $region = substr((string) $locale, 0, 3);
+ if (isset($region[2]) === true) {
+ if (($region[2] === '_') or ($region[2] === '-')) {
+ $region = substr($region, 0, 2);
+ }
+ }
+
+ if (isset(self::$_localeData[(string) $region]) === true) {
+ $this->_locale = $region;
+ } else {
+ $this->_locale = 'root';
+ }
+ } else {
+ $this->_locale = $locale;
+ }
+ }
+
+ /**
+ * Returns the language part of the locale
+ *
+ * @return string
+ */
+ public function getLanguage()
+ {
+ $locale = explode('_', $this->_locale);
+ return $locale[0];
+ }
+
+ /**
+ * Returns the region part of the locale if available
+ *
+ * @return string|false - Regionstring
+ */
+ public function getRegion()
+ {
+ $locale = explode('_', $this->_locale);
+ if (isset($locale[1]) === true) {
+ return $locale[1];
+ }
+
+ return false;
+ }
+
+ /**
+ * Return the accepted charset of the client
+ *
+ * @return string
+ */
+ public static function getHttpCharset()
+ {
+ $httpcharsets = getenv('HTTP_ACCEPT_CHARSET');
+
+ $charsets = array();
+ if ($httpcharsets === false) {
+ return $charsets;
+ }
+
+ $accepted = preg_split('/,\s*/', $httpcharsets);
+ foreach ($accepted as $accept) {
+ if (empty($accept) === true) {
+ continue;
+ }
+
+ if (strpos($accept, ';') !== false) {
+ $quality = (float) substr($accept, (strpos($accept, '=') + 1));
+ $pos = substr($accept, 0, strpos($accept, ';'));
+ $charsets[$pos] = $quality;
+ } else {
+ $quality = 1.0;
+ $charsets[$accept] = $quality;
+ }
+ }
+
+ return $charsets;
+ }
+
+ /**
+ * Returns true if both locales are equal
+ *
+ * @param Zend_Locale $object Locale to check for equality
+ * @return boolean
+ */
+ public function equals(Zend_Locale $object)
+ {
+ if ($object->toString() === $this->toString()) {
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Returns localized informations as array, supported are several
+ * types of informations.
+ * For detailed information about the types look into the documentation
+ *
+ * @param string $path (Optional) Type of information to return
+ * @param string|Zend_Locale $locale (Optional) Locale|Language for which this informations should be returned
+ * @param string $value (Optional) Value for detail list
+ * @return array Array with the wished information in the given language
+ */
+ public static function getTranslationList($path = null, $locale = null, $value = null)
+ {
+ require_once 'Zend/Locale/Data.php';
+ $locale = self::_prepareLocale($locale);
+ $result = Zend_Locale_Data::getList($locale, $path, $value);
+ if (empty($result) === true) {
+ return false;
+ }
+
+ return $result;
+ }
+
+ /**
+ * Returns an array with the name of all languages translated to the given language
+ *
+ * @param string|Zend_Locale $locale (Optional) Locale for language translation
+ * @return array
+ * @deprecated
+ */
+ public static function getLanguageTranslationList($locale = null)
+ {
+ trigger_error("The method getLanguageTranslationList is deprecated. Use getTranslationList('language', $locale) instead", E_USER_NOTICE);
+ return self::getTranslationList('language', $locale);
+ }
+
+ /**
+ * Returns an array with the name of all scripts translated to the given language
+ *
+ * @param string|Zend_Locale $locale (Optional) Locale for script translation
+ * @return array
+ * @deprecated
+ */
+ public static function getScriptTranslationList($locale = null)
+ {
+ trigger_error("The method getScriptTranslationList is deprecated. Use getTranslationList('script', $locale) instead", E_USER_NOTICE);
+ return self::getTranslationList('script', $locale);
+ }
+
+ /**
+ * Returns an array with the name of all countries translated to the given language
+ *
+ * @param string|Zend_Locale $locale (Optional) Locale for country translation
+ * @return array
+ * @deprecated
+ */
+ public static function getCountryTranslationList($locale = null)
+ {
+ trigger_error("The method getCountryTranslationList is deprecated. Use getTranslationList('territory', $locale, 2) instead", E_USER_NOTICE);
+ return self::getTranslationList('territory', $locale, 2);
+ }
+
+ /**
+ * Returns an array with the name of all territories translated to the given language
+ * All territories contains other countries.
+ *
+ * @param string|Zend_Locale $locale (Optional) Locale for territory translation
+ * @return array
+ * @deprecated
+ */
+ public static function getTerritoryTranslationList($locale = null)
+ {
+ trigger_error("The method getTerritoryTranslationList is deprecated. Use getTranslationList('territory', $locale, 1) instead", E_USER_NOTICE);
+ return self::getTranslationList('territory', $locale, 1);
+ }
+
+ /**
+ * Returns a localized information string, supported are several types of informations.
+ * For detailed information about the types look into the documentation
+ *
+ * @param string $value Name to get detailed information about
+ * @param string $path (Optional) Type of information to return
+ * @param string|Zend_Locale $locale (Optional) Locale|Language for which this informations should be returned
+ * @return string|false The wished information in the given language
+ */
+ public static function getTranslation($value = null, $path = null, $locale = null)
+ {
+ require_once 'Zend/Locale/Data.php';
+ $locale = self::_prepareLocale($locale);
+ $result = Zend_Locale_Data::getContent($locale, $path, $value);
+ if (empty($result) === true) {
+ return false;
+ }
+
+ return $result;
+ }
+
+ /**
+ * Returns the localized language name
+ *
+ * @param string $value Name to get detailed information about
+ * @param string $locale (Optional) Locale for language translation
+ * @return array
+ * @deprecated
+ */
+ public static function getLanguageTranslation($value, $locale = null)
+ {
+ trigger_error("The method getLanguageTranslation is deprecated. Use getTranslation($value, 'language', $locale) instead", E_USER_NOTICE);
+ return self::getTranslation($value, 'language', $locale);
+ }
+
+ /**
+ * Returns the localized script name
+ *
+ * @param string $value Name to get detailed information about
+ * @param string $locale (Optional) locale for script translation
+ * @return array
+ * @deprecated
+ */
+ public static function getScriptTranslation($value, $locale = null)
+ {
+ trigger_error("The method getScriptTranslation is deprecated. Use getTranslation($value, 'script', $locale) instead", E_USER_NOTICE);
+ return self::getTranslation($value, 'script', $locale);
+ }
+
+ /**
+ * Returns the localized country name
+ *
+ * @param string $value Name to get detailed information about
+ * @param string|Zend_Locale $locale (Optional) Locale for country translation
+ * @return array
+ * @deprecated
+ */
+ public static function getCountryTranslation($value, $locale = null)
+ {
+ trigger_error("The method getCountryTranslation is deprecated. Use getTranslation($value, 'country', $locale) instead", E_USER_NOTICE);
+ return self::getTranslation($value, 'country', $locale);
+ }
+
+ /**
+ * Returns the localized territory name
+ * All territories contains other countries.
+ *
+ * @param string $value Name to get detailed information about
+ * @param string|Zend_Locale $locale (Optional) Locale for territory translation
+ * @return array
+ * @deprecated
+ */
+ public static function getTerritoryTranslation($value, $locale = null)
+ {
+ trigger_error("The method getTerritoryTranslation is deprecated. Use getTranslation($value, 'territory', $locale) instead", E_USER_NOTICE);
+ return self::getTranslation($value, 'territory', $locale);
+ }
+
+ /**
+ * Returns an array with translated yes strings
+ *
+ * @param string|Zend_Locale $locale (Optional) Locale for language translation (defaults to $this locale)
+ * @return array
+ */
+ public static function getQuestion($locale = null)
+ {
+ require_once 'Zend/Locale/Data.php';
+ $locale = self::_prepareLocale($locale);
+ $quest = Zend_Locale_Data::getList($locale, 'question');
+ $yes = explode(':', $quest['yes']);
+ $no = explode(':', $quest['no']);
+ $quest['yes'] = $yes[0];
+ $quest['yesarray'] = $yes;
+ $quest['no'] = $no[0];
+ $quest['noarray'] = $no;
+ $quest['yesexpr'] = self::_prepareQuestionString($yes);
+ $quest['noexpr'] = self::_prepareQuestionString($no);
+
+ return $quest;
+ }
+
+ /**
+ * Internal function for preparing the returned question regex string
+ *
+ * @param string $input Regex to parse
+ * @return string
+ */
+ private static function _prepareQuestionString($input)
+ {
+ $regex = '';
+ if (is_array($input) === true) {
+ $regex = '^';
+ $start = true;
+ foreach ($input as $row) {
+ if ($start === false) {
+ $regex .= '|';
+ }
+
+ $start = false;
+ $regex .= '(';
+ $one = null;
+ if (strlen($row) > 2) {
+ $one = true;
+ }
+
+ foreach (str_split($row, 1) as $char) {
+ $regex .= '[' . $char;
+ $regex .= strtoupper($char) . ']';
+ if ($one === true) {
+ $one = false;
+ $regex .= '(';
+ }
+ }
+
+ if ($one === false) {
+ $regex .= ')';
+ }
+
+ $regex .= '?)';
+ }
+ }
+
+ return $regex;
+ }
+
+ /**
+ * Checks if a locale identifier is a real locale or not
+ * Examples:
+ * "en_XX" refers to "en", which returns true
+ * "XX_yy" refers to "root", which returns false
+ *
+ * @param string|Zend_Locale $locale Locale to check for
+ * @param boolean $strict (Optional) If true, no rerouting will be done when checking
+ * @param boolean $compatible (DEPRECIATED) Only for internal usage, brakes compatibility mode
+ * @return boolean If the locale is known dependend on the settings
+ */
+ public static function isLocale($locale, $strict = false, $compatible = true)
+ {
+ if ($locale instanceof Zend_Locale) {
+ return true;
+ }
+
+ if (($locale !== null) and !is_string($locale) and !is_array($locale)) {
+ return false;
+ }
+
+ try {
+ $locale = self::_prepareLocale($locale, $strict);
+ } catch (Zend_Locale_Exception $e) {
+ return false;
+ }
+
+ if (($compatible === true) and (self::$compatibilityMode === true)) {
+ trigger_error('You are running Zend_Locale in compatibility mode... please migrate your scripts', E_USER_NOTICE);
+ if (isset(self::$_localeData[$locale]) === true) {
+ return $locale;
+ } else if (!$strict) {
+ $locale = explode('_', $locale);
+ if (isset(self::$_localeData[$locale[0]]) === true) {
+ return $locale[0];
+ }
+ }
+ } else {
+ if (isset(self::$_localeData[$locale]) === true) {
+ return true;
+ } else if (!$strict) {
+ $locale = explode('_', $locale);
+ if (isset(self::$_localeData[$locale[0]]) === true) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Finds the proper locale based on the input
+ * Checks if it exists, degrades it when necessary
+ * Detects registry locale and when all fails tries to detect a automatic locale
+ * Returns the found locale as string
+ *
+ * @param string $locale
+ * @throws Zend_Locale_Exception When the given locale is no locale or the autodetection fails
+ * @return string
+ */
+ public static function findLocale($locale = null)
+ {
+ if ($locale === null) {
+ require_once 'Zend/Registry.php';
+ if (Zend_Registry::isRegistered('Zend_Locale')) {
+ $locale = Zend_Registry::get('Zend_Locale');
+ }
+ }
+
+ require_once 'Zend/Locale.php';
+ if ($locale === null) {
+ $locale = new Zend_Locale();
+ }
+
+ if (!Zend_Locale::isLocale($locale, true, false)) {
+ if (!Zend_Locale::isLocale($locale, false, false)) {
+ require_once 'Zend/Locale/Exception.php';
+ throw new Zend_Locale_Exception("The locale '$locale' is no known locale");
+ }
+
+ $locale = new Zend_Locale($locale);
+ }
+
+ if ($locale instanceof Zend_Locale) {
+ $locale = $locale->toString();
+ }
+
+ return $locale;
+ }
+
+ /**
+ * Returns a list of all known locales where the locale is the key
+ * Only real locales are returned, the internal locales 'root', 'auto', 'browser'
+ * and 'environment' are suppressed
+ *
+ * @return array List of all Locales
+ */
+ public static function getLocaleList()
+ {
+ $list = self::$_localeData;
+ unset($list['root']);
+ unset($list['auto']);
+ unset($list['browser']);
+ unset($list['environment']);
+ return $list;
+ }
+
+ /**
+ * Returns the set cache
+ *
+ * @return Zend_Cache_Core The set cache
+ */
+ public static function getCache()
+ {
+ require_once 'Zend/Locale/Data.php';
+ $cache = Zend_Locale_Data::getCache();
+
+ return $cache;
+ }
+
+ /**
+ * Sets a cache
+ *
+ * @param Zend_Cache_Core $cache Cache to set
+ * @return void
+ */
+ public static function setCache(Zend_Cache_Core $cache)
+ {
+ require_once 'Zend/Locale/Data.php';
+ Zend_Locale_Data::setCache($cache);
+ }
+
+ /**
+ * Returns true when a cache is set
+ *
+ * @return boolean
+ */
+ public static function hasCache()
+ {
+ require_once 'Zend/Locale/Data.php';
+ return Zend_Locale_Data::hasCache();
+ }
+
+ /**
+ * Removes any set cache
+ *
+ * @return void
+ */
+ public static function removeCache()
+ {
+ require_once 'Zend/Locale/Data.php';
+ Zend_Locale_Data::removeCache();
+ }
+
+ /**
+ * Clears all set cache data
+ *
+ * @return void
+ */
+ public static function clearCache()
+ {
+ require_once 'Zend/Locale/Data.php';
+ Zend_Locale_Data::clearCache();
+ }
+
+ /**
+ * Disables the set cache
+ *
+ * @param boolean $flag True disables any set cache, default is false
+ * @return void
+ */
+ public static function disableCache($flag)
+ {
+ require_once 'Zend/Locale/Data.php';
+ Zend_Locale_Data::disableCache($flag);
+ }
+
+ /**
+ * Internal function, returns a single locale on detection
+ *
+ * @param string|Zend_Locale $locale (Optional) Locale to work on
+ * @param boolean $strict (Optional) Strict preparation
+ * @throws Zend_Locale_Exception When no locale is set which is only possible when the class was wrong extended
+ * @return string
+ */
+ private static function _prepareLocale($locale, $strict = false)
+ {
+ if ($locale instanceof Zend_Locale) {
+ $locale = $locale->toString();
+ }
+
+ if (is_array($locale)) {
+ return '';
+ }
+
+ if (empty(self::$_auto) === true) {
+ self::$_browser = self::getBrowser();
+ self::$_environment = self::getEnvironment();
+ self::$_breakChain = true;
+ self::$_auto = self::getBrowser() + self::getEnvironment() + self::getDefault();
+ }
+
+ if (!$strict) {
+ if ($locale === 'browser') {
+ $locale = self::$_browser;
+ }
+
+ if ($locale === 'environment') {
+ $locale = self::$_environment;
+ }
+
+ if ($locale === 'default') {
+ $locale = self::$_default;
+ }
+
+ if (($locale === 'auto') or ($locale === null)) {
+ $locale = self::$_auto;
+ }
+
+ if (is_array($locale) === true) {
+ $locale = key($locale);
+ }
+ }
+
+ // This can only happen when someone extends Zend_Locale and erases the default
+ if ($locale === null) {
+ require_once 'Zend/Locale/Exception.php';
+ throw new Zend_Locale_Exception('Autodetection of Locale has been failed!');
+ }
+
+ if (strpos($locale, '-') !== false) {
+ $locale = strtr($locale, '-', '_');
+ }
+
+ $parts = explode('_', $locale);
+ if (!isset(self::$_localeData[$parts[0]])) {
+ return '';
+ }
+
+ foreach($parts as $key => $value) {
+ if ((strlen($value) < 2) || (strlen($value) > 3)) {
+ unset($parts[$key]);
+ }
+ }
+
+ $locale = implode('_', $parts);
+ return (string) $locale;
+ }
+
+ /**
+ * Search the locale automatically and return all used locales
+ * ordered by quality
+ *
+ * Standard Searchorder is Browser, Environment, Default
+ *
+ * @param string $searchorder (Optional) Searchorder
+ * @return array Returns an array of all detected locales
+ */
+ public static function getOrder($order = null)
+ {
+ switch ($order) {
+ case self::ENVIRONMENT:
+ self::$_breakChain = true;
+ $languages = self::getEnvironment() + self::getBrowser() + self::getDefault();
+ break;
+
+ case self::ZFDEFAULT:
+ self::$_breakChain = true;
+ $languages = self::getDefault() + self::getEnvironment() + self::getBrowser();
+ break;
+
+ default:
+ self::$_breakChain = true;
+ $languages = self::getBrowser() + self::getEnvironment() + self::getDefault();
+ break;
+ }
+
+ return $languages;
+ }
+}
--- /dev/null
+<?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_Log
+ * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ * @version $Id$
+ */
+
+/**
+ * @category Zend
+ * @package Zend_Log
+ * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ * @version $Id$
+ */
+class Zend_Log
+{
+ const EMERG = 0; // Emergency: system is unusable
+ const ALERT = 1; // Alert: action must be taken immediately
+ const CRIT = 2; // Critical: critical conditions
+ const ERR = 3; // Error: error conditions
+ const WARN = 4; // Warning: warning conditions
+ const NOTICE = 5; // Notice: normal but significant condition
+ const INFO = 6; // Informational: informational messages
+ const DEBUG = 7; // Debug: debug messages
+
+ /**
+ * @var array of priorities where the keys are the
+ * priority numbers and the values are the priority names
+ */
+ protected $_priorities = array();
+
+ /**
+ * @var array of Zend_Log_Writer_Abstract
+ */
+ protected $_writers = array();
+
+ /**
+ * @var array of Zend_Log_Filter_Interface
+ */
+ protected $_filters = array();
+
+ /**
+ * @var array of extra log event
+ */
+ protected $_extras = array();
+
+ /**
+ * Class constructor. Create a new logger
+ *
+ * @param Zend_Log_Writer_Abstract|null $writer default writer
+ */
+ public function __construct(Zend_Log_Writer_Abstract $writer = null)
+ {
+ $r = new ReflectionClass($this);
+ $this->_priorities = array_flip($r->getConstants());
+
+ if ($writer !== null) {
+ $this->addWriter($writer);
+ }
+ }
+
+ /**
+ * Class destructor. Shutdown log writers
+ *
+ * @return void
+ */
+ public function __destruct()
+ {
+ foreach($this->_writers as $writer) {
+ $writer->shutdown();
+ }
+ }
+
+ /**
+ * Undefined method handler allows a shortcut:
+ * $log->priorityName('message')
+ * instead of
+ * $log->log('message', Zend_Log::PRIORITY_NAME)
+ *
+ * @param string $method priority name
+ * @param string $params message to log
+ * @return void
+ * @throws Zend_Log_Exception
+ */
+ public function __call($method, $params)
+ {
+ $priority = strtoupper($method);
+ if (($priority = array_search($priority, $this->_priorities)) !== false) {
+ $this->log(array_shift($params), $priority);
+ } else {
+ /** @see Zend_Log_Exception */
+ require_once 'Zend/Log/Exception.php';
+ throw new Zend_Log_Exception('Bad log priority');
+ }
+ }
+
+ /**
+ * Log a message at a priority
+ *
+ * @param string $message Message to log
+ * @param integer $priority Priority of message
+ * @return void
+ * @throws Zend_Log_Exception
+ */
+ public function log($message, $priority)
+ {
+ // sanity checks
+ if (empty($this->_writers)) {
+ /** @see Zend_Log_Exception */
+ require_once 'Zend/Log/Exception.php';
+ throw new Zend_Log_Exception('No writers were added');
+ }
+
+ if (! isset($this->_priorities[$priority])) {
+ /** @see Zend_Log_Exception */
+ require_once 'Zend/Log/Exception.php';
+ throw new Zend_Log_Exception('Bad log priority');
+ }
+
+ // pack into event required by filters and writers
+ $event = array_merge(array('timestamp' => date('c'),
+ 'message' => $message,
+ 'priority' => $priority,
+ 'priorityName' => $this->_priorities[$priority]),
+ $this->_extras);
+
+ // abort if rejected by the global filters
+ foreach ($this->_filters as $filter) {
+ if (! $filter->accept($event)) {
+ return;
+ }
+ }
+
+ // send to each writer
+ foreach ($this->_writers as $writer) {
+ $writer->write($event);
+ }
+ }
+
+ /**
+ * Add a custom priority
+ *
+ * @param string $name Name of priority
+ * @param integer $priority Numeric priority
+ * @throws Zend_Log_InvalidArgumentException
+ */
+ public function addPriority($name, $priority)
+ {
+ // Priority names must be uppercase for predictability.
+ $name = strtoupper($name);
+
+ if (isset($this->_priorities[$priority])
+ || array_search($name, $this->_priorities)) {
+ /** @see Zend_Log_Exception */
+ require_once 'Zend/Log/Exception.php';
+ throw new Zend_Log_Exception('Existing priorities cannot be overwritten');
+ }
+
+ $this->_priorities[$priority] = $name;
+ }
+
+ /**
+ * Add a filter that will be applied before all log writers.
+ * Before a message will be received by any of the writers, it
+ * must be accepted by all filters added with this method.
+ *
+ * @param int|Zend_Log_Filter_Interface $filter
+ * @return void
+ */
+ public function addFilter($filter)
+ {
+ if (is_integer($filter)) {
+ /** @see Zend_Log_Filter_Priority */
+ require_once 'Zend/Log/Filter/Priority.php';
+ $filter = new Zend_Log_Filter_Priority($filter);
+ } elseif(!is_object($filter) || ! $filter instanceof Zend_Log_Filter_Interface) {
+ /** @see Zend_Log_Exception */
+ require_once 'Zend/Log/Exception.php';
+ throw new Zend_Log_Exception('Invalid filter provided');
+ }
+
+ $this->_filters[] = $filter;
+ }
+
+ /**
+ * Add a writer. A writer is responsible for taking a log
+ * message and writing it out to storage.
+ *
+ * @param Zend_Log_Writer_Abstract $writer
+ * @return void
+ */
+ public function addWriter(Zend_Log_Writer_Abstract $writer)
+ {
+ $this->_writers[] = $writer;
+ }
+
+ /**
+ * Set an extra item to pass to the log writers.
+ *
+ * @param $name Name of the field
+ * @param $value Value of the field
+ * @return void
+ */
+ public function setEventItem($name, $value) {
+ $this->_extras = array_merge($this->_extras, array($name => $value));
+ }
+
+}
--- /dev/null
+<?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_Mail
+ * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ * @version $Id$
+ */
+
+
+/**
+ * @see Zend_Mail_Transport_Abstract
+ */
+require_once 'Zend/Mail/Transport/Abstract.php';
+
+/**
+ * @see Zend_Mime
+ */
+require_once 'Zend/Mime.php';
+
+/**
+ * @see Zend_Mime_Message
+ */
+require_once 'Zend/Mime/Message.php';
+
+/**
+ * @see Zend_Mime_Part
+ */
+require_once 'Zend/Mime/Part.php';
+
+
+/**
+ * Class for sending an email.
+ *
+ * @category Zend
+ * @package Zend_Mail
+ * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+class Zend_Mail extends Zend_Mime_Message
+{
+ /**#@+
+ * @access protected
+ */
+
+ /**
+ * @var Zend_Mail_Transport_Abstract
+ * @static
+ */
+ protected static $_defaultTransport = null;
+
+ /**
+ * Mail character set
+ * @var string
+ */
+ protected $_charset = null;
+
+ /**
+ * Mail headers
+ * @var array
+ */
+ protected $_headers = array();
+
+ /**
+ * Encoding of Mail headers
+ * @var string
+ */
+ protected $_headerEncoding = Zend_Mime::ENCODING_QUOTEDPRINTABLE;
+
+ /**
+ * From: address
+ * @var string
+ */
+ protected $_from = null;
+
+ /**
+ * To: addresses
+ * @var array
+ */
+ protected $_to = array();
+
+ /**
+ * Array of all recipients
+ * @var array
+ */
+ protected $_recipients = array();
+
+ /**
+ * Return-Path header
+ * @var string
+ */
+ protected $_returnPath = null;
+
+ /**
+ * Subject: header
+ * @var string
+ */
+ protected $_subject = null;
+
+ /**
+ * Date: header
+ * @var string
+ */
+ protected $_date = null;
+
+ /**
+ * Message-ID: header
+ * @var string
+ */
+ protected $_messageId = null;
+
+ /**
+ * text/plain MIME part
+ * @var false|Zend_Mime_Part
+ */
+ protected $_bodyText = false;
+
+ /**
+ * text/html MIME part
+ * @var false|Zend_Mime_Part
+ */
+ protected $_bodyHtml = false;
+
+ /**
+ * MIME boundary string
+ * @var string
+ */
+ protected $_mimeBoundary = null;
+
+ /**
+ * Content type of the message
+ * @var string
+ */
+ protected $_type = null;
+
+ /**#@-*/
+
+ /**
+ * Flag: whether or not email has attachments
+ * @var boolean
+ */
+ public $hasAttachments = false;
+
+
+ /**
+ * Sets the default mail transport for all following uses of
+ * Zend_Mail::send();
+ *
+ * @todo Allow passing a string to indicate the transport to load
+ * @todo Allow passing in optional options for the transport to load
+ * @param Zend_Mail_Transport_Abstract $transport
+ */
+ public static function setDefaultTransport(Zend_Mail_Transport_Abstract $transport)
+ {
+ self::$_defaultTransport = $transport;
+ }
+
+ /**
+ * Public constructor
+ *
+ * @param string $charset
+ */
+ public function __construct($charset = 'iso-8859-1')
+ {
+ $this->_charset = $charset;
+ }
+
+ /**
+ * Return charset string
+ *
+ * @return string
+ */
+ public function getCharset()
+ {
+ return $this->_charset;
+ }
+
+ /**
+ * Set content type
+ *
+ * Should only be used for manually setting multipart content types.
+ *
+ * @param string $type Content type
+ * @return Zend_Mail Implements fluent interface
+ * @throws Zend_Mail_Exception for types not supported by Zend_Mime
+ */
+ public function setType($type)
+ {
+ $allowed = array(
+ Zend_Mime::MULTIPART_ALTERNATIVE,
+ Zend_Mime::MULTIPART_MIXED,
+ Zend_Mime::MULTIPART_RELATED,
+ );
+ if (!in_array($type, $allowed)) {
+ /**
+ * @see Zend_Mail_Exception
+ */
+ require_once 'Zend/Mail/Exception.php';
+ throw new Zend_Mail_Exception('Invalid content type "' . $type . '"');
+ }
+
+ $this->_type = $type;
+ return $this;
+ }
+
+ /**
+ * Get content type of the message
+ *
+ * @return string
+ */
+ public function getType()
+ {
+ return $this->_type;
+ }
+
+ /**
+ * Set an arbitrary mime boundary for the message
+ *
+ * If not set, Zend_Mime will generate one.
+ *
+ * @param string $boundary
+ * @return Zend_Mail Provides fluent interface
+ */
+ public function setMimeBoundary($boundary)
+ {
+ $this->_mimeBoundary = $boundary;
+
+ return $this;
+ }
+
+ /**
+ * Return the boundary string used for the message
+ *
+ * @return string
+ */
+ public function getMimeBoundary()
+ {
+ return $this->_mimeBoundary;
+ }
+
+ /**
+ * Return encoding of mail headers
+ *
+ * @deprecated use {@link getHeaderEncoding()} instead
+ * @return string
+ */
+ public function getEncodingOfHeaders()
+ {
+ return $this->getHeaderEncoding();
+ }
+
+ /**
+ * Return the encoding of mail headers
+ *
+ * Either Zend_Mime::ENCODING_QUOTEDPRINTABLE or Zend_Mime::ENCODING_BASE64
+ *
+ * @return string
+ */
+ public function getHeaderEncoding()
+ {
+ return $this->_headerEncoding;
+ }
+
+ /**
+ * Set the encoding of mail headers
+ *
+ * @deprecated Use {@link setHeaderEncoding()} instead.
+ * @param string $encoding
+ * @return Zend_Mail
+ */
+ public function setEncodingOfHeaders($encoding)
+ {
+ return $this->setHeaderEncoding($encoding);
+ }
+
+ /**
+ * Set the encoding of mail headers
+ *
+ * @param string $encoding Zend_Mime::ENCODING_QUOTEDPRINTABLE or Zend_Mime::ENCODING_BASE64
+ * @return Zend_Mail Provides fluent interface
+ */
+ public function setHeaderEncoding($encoding)
+ {
+ $allowed = array(
+ Zend_Mime::ENCODING_BASE64,
+ Zend_Mime::ENCODING_QUOTEDPRINTABLE
+ );
+ if (!in_array($encoding, $allowed)) {
+ /**
+ * @see Zend_Mail_Exception
+ */
+ require_once 'Zend/Mail/Exception.php';
+ throw new Zend_Mail_Exception('Invalid encoding "' . $encoding . '"');
+ }
+ $this->_headerEncoding = $encoding;
+
+ return $this;
+ }
+
+ /**
+ * Sets the text body for the message.
+ *
+ * @param string $txt
+ * @param string $charset
+ * @param string $encoding
+ * @return Zend_Mail Provides fluent interface
+ */
+ public function setBodyText($txt, $charset = null, $encoding = Zend_Mime::ENCODING_QUOTEDPRINTABLE)
+ {
+ if ($charset === null) {
+ $charset = $this->_charset;
+ }
+
+ $mp = new Zend_Mime_Part($txt);
+ $mp->encoding = $encoding;
+ $mp->type = Zend_Mime::TYPE_TEXT;
+ $mp->disposition = Zend_Mime::DISPOSITION_INLINE;
+ $mp->charset = $charset;
+
+ $this->_bodyText = $mp;
+
+ return $this;
+ }
+
+ /**
+ * Return text body Zend_Mime_Part or string
+ *
+ * @param bool textOnly Whether to return just the body text content or the MIME part; defaults to false, the MIME part
+ * @return false|Zend_Mime_Part|string
+ */
+ public function getBodyText($textOnly = false)
+ {
+ if ($textOnly && $this->_bodyText) {
+ $body = $this->_bodyText;
+ return $body->getContent();
+ }
+
+ return $this->_bodyText;
+ }
+
+ /**
+ * Sets the HTML body for the message
+ *
+ * @param string $html
+ * @param string $charset
+ * @param string $encoding
+ * @return Zend_Mail Provides fluent interface
+ */
+ public function setBodyHtml($html, $charset = null, $encoding = Zend_Mime::ENCODING_QUOTEDPRINTABLE)
+ {
+ if ($charset === null) {
+ $charset = $this->_charset;
+ }
+
+ $mp = new Zend_Mime_Part($html);
+ $mp->encoding = $encoding;
+ $mp->type = Zend_Mime::TYPE_HTML;
+ $mp->disposition = Zend_Mime::DISPOSITION_INLINE;
+ $mp->charset = $charset;
+
+ $this->_bodyHtml = $mp;
+
+ return $this;
+ }
+
+ /**
+ * Return Zend_Mime_Part representing body HTML
+ *
+ * @param bool $htmlOnly Whether to return the body HTML only, or the MIME part; defaults to false, the MIME part
+ * @return false|Zend_Mime_Part|string
+ */
+ public function getBodyHtml($htmlOnly = false)
+ {
+ if ($htmlOnly && $this->_bodyHtml) {
+ $body = $this->_bodyHtml;
+ return $body->getContent();
+ }
+
+ return $this->_bodyHtml;
+ }
+
+ /**
+ * Adds an existing attachment to the mail message
+ *
+ * @param Zend_Mime_Part $attachment
+ * @return Zend_Mail Provides fluent interface
+ */
+ public function addAttachment(Zend_Mime_Part $attachment)
+ {
+ $this->addPart($attachment);
+ $this->hasAttachments = true;
+
+ return $this;
+ }
+
+ /**
+ * Creates a Zend_Mime_Part attachment
+ *
+ * Attachment is automatically added to the mail object after creation. The
+ * attachment object is returned to allow for further manipulation.
+ *
+ * @param string $body
+ * @param string $mimeType
+ * @param string $disposition
+ * @param string $encoding
+ * @param string $filename OPTIONAL A filename for the attachment
+ * @return Zend_Mime_Part Newly created Zend_Mime_Part object (to allow
+ * advanced settings)
+ */
+ public function createAttachment($body,
+ $mimeType = Zend_Mime::TYPE_OCTETSTREAM,
+ $disposition = Zend_Mime::DISPOSITION_ATTACHMENT,
+ $encoding = Zend_Mime::ENCODING_BASE64,
+ $filename = null)
+ {
+
+ $mp = new Zend_Mime_Part($body);
+ $mp->encoding = $encoding;
+ $mp->type = $mimeType;
+ $mp->disposition = $disposition;
+ $mp->filename = $filename;
+
+ $this->addAttachment($mp);
+
+ return $mp;
+ }
+
+ /**
+ * Return a count of message parts
+ *
+ * @return integer
+ */
+ public function getPartCount()
+ {
+ return count($this->_parts);
+ }
+
+ /**
+ * Encode header fields
+ *
+ * Encodes header content according to RFC1522 if it contains non-printable
+ * characters.
+ *
+ * @param string $value
+ * @return string
+ */
+ protected function _encodeHeader($value)
+ {
+ if (Zend_Mime::isPrintable($value) === false) {
+ if ($this->getHeaderEncoding() === Zend_Mime::ENCODING_QUOTEDPRINTABLE) {
+ $value = Zend_Mime::encodeQuotedPrintableHeader($value, $this->getCharset(), Zend_Mime::LINELENGTH, Zend_Mime::LINEEND);
+ } else {
+ $value = Zend_Mime::encodeBase64Header($value, $this->getCharset(), Zend_Mime::LINELENGTH, Zend_Mime::LINEEND);
+ }
+ }
+
+ return $value;
+ }
+
+ /**
+ * Add a header to the message
+ *
+ * Adds a header to this message. If append is true and the header already
+ * exists, raises a flag indicating that the header should be appended.
+ *
+ * @param string $headerName
+ * @param string $value
+ * @param bool $append
+ */
+ protected function _storeHeader($headerName, $value, $append = false)
+ {
+ if (isset($this->_headers[$headerName])) {
+ $this->_headers[$headerName][] = $value;
+ } else {
+ $this->_headers[$headerName] = array($value);
+ }
+
+ if ($append) {
+ $this->_headers[$headerName]['append'] = true;
+ }
+
+ }
+
+ /**
+ * Clear header from the message
+ *
+ * @param string $headerName
+ */
+ protected function _clearHeader($headerName)
+ {
+ if (isset($this->_headers[$headerName])){
+ unset($this->_headers[$headerName]);
+ }
+ }
+
+ /**
+ * Helper function for adding a recipient and the corresponding header
+ *
+ * @param string $headerName
+ * @param string $email
+ * @param string $name
+ */
+ protected function _addRecipientAndHeader($headerName, $email, $name)
+ {
+ $email = $this->_filterEmail($email);
+ $name = $this->_filterName($name);
+ // prevent duplicates
+ $this->_recipients[$email] = 1;
+ $this->_storeHeader($headerName, $this->_formatAddress($email, $name), true);
+ }
+
+ /**
+ * Adds To-header and recipient
+ *
+ * @param string $email
+ * @param string $name
+ * @return Zend_Mail Provides fluent interface
+ */
+ public function addTo($email, $name='')
+ {
+ $this->_addRecipientAndHeader('To', $email, $name);
+ $this->_to[] = $email;
+ return $this;
+ }
+
+ /**
+ * Adds Cc-header and recipient
+ *
+ * @param string $email
+ * @param string $name
+ * @return Zend_Mail Provides fluent interface
+ */
+ public function addCc($email, $name='')
+ {
+ $this->_addRecipientAndHeader('Cc', $email, $name);
+ return $this;
+ }
+
+ /**
+ * Adds Bcc recipient
+ *
+ * @param string $email
+ * @return Zend_Mail Provides fluent interface
+ */
+ public function addBcc($email)
+ {
+ $this->_addRecipientAndHeader('Bcc', $email, '');
+ return $this;
+ }
+
+ /**
+ * Return list of recipient email addresses
+ *
+ * @return array (of strings)
+ */
+ public function getRecipients()
+ {
+ return array_keys($this->_recipients);
+ }
+
+ /**
+ * Clears list of recipient email addresses
+ *
+ * @return Zend_Mail Provides fluent interface
+ */
+ public function clearRecipients()
+ {
+ $this->_recipients = array();
+ $this->_to = array();
+
+ $this->_clearHeader('To');
+ $this->_clearHeader('Cc');
+ $this->_clearHeader('Bcc');
+
+ return $this;
+ }
+
+ /**
+ * Sets From-header and sender of the message
+ *
+ * @param string $email
+ * @param string $name
+ * @return Zend_Mail Provides fluent interface
+ * @throws Zend_Mail_Exception if called subsequent times
+ */
+ public function setFrom($email, $name = null)
+ {
+ if ($this->_from === null) {
+ $email = $this->_filterEmail($email);
+ $name = $this->_filterName($name);
+ $this->_from = $email;
+ $this->_storeHeader('From', $this->_formatAddress($email, $name), true);
+ } else {
+ /**
+ * @see Zend_Mail_Exception
+ */
+ require_once 'Zend/Mail/Exception.php';
+ throw new Zend_Mail_Exception('From Header set twice');
+ }
+ return $this;
+ }
+
+ /**
+ * Set Reply-To Header
+ *
+ * @param string $email
+ * @param string $name
+ * @return Zend_Mail
+ */
+ public function setReplyTo($email, $name=null)
+ {
+ $this->_addRecipientAndHeader('Reply-To', $email, $name);
+ return $this;
+ }
+
+ /**
+ * Returns the sender of the mail
+ *
+ * @return string
+ */
+ public function getFrom()
+ {
+ return $this->_from;
+ }
+
+ /**
+ * Clears the sender from the mail
+ *
+ * @return Zend_Mail Provides fluent interface
+ */
+ public function clearFrom()
+ {
+ $this->_from = null;
+ $this->_clearHeader('From');
+
+ return $this;
+ }
+
+ /**
+ * Sets the Return-Path header of the message
+ *
+ * @param string $email
+ * @return Zend_Mail Provides fluent interface
+ * @throws Zend_Mail_Exception if set multiple times
+ */
+ public function setReturnPath($email)
+ {
+ if ($this->_returnPath === null) {
+ $email = $this->_filterEmail($email);
+ $this->_returnPath = $email;
+ $this->_storeHeader('Return-Path', $email, false);
+ } else {
+ /**
+ * @see Zend_Mail_Exception
+ */
+ require_once 'Zend/Mail/Exception.php';
+ throw new Zend_Mail_Exception('Return-Path Header set twice');
+ }
+ return $this;
+ }
+
+ /**
+ * Returns the current Return-Path address of the message
+ *
+ * If no Return-Path header is set, returns the value of {@link $_from}.
+ *
+ * @return string
+ */
+ public function getReturnPath()
+ {
+ if (null !== $this->_returnPath) {
+ return $this->_returnPath;
+ }
+
+ return $this->_from;
+ }
+
+ /**
+ * Clears the current Return-Path address from the message
+ *
+ * @return Zend_Mail Provides fluent interface
+ */
+ public function clearReturnPath()
+ {
+ $this->_returnPath = null;
+ $this->_clearHeader('Return-Path');
+
+ return $this;
+ }
+
+ /**
+ * Sets the subject of the message
+ *
+ * @param string $subject
+ * @return Zend_Mail Provides fluent interface
+ * @throws Zend_Mail_Exception
+ */
+ public function setSubject($subject)
+ {
+ if ($this->_subject === null) {
+ $subject = $this->_filterOther($subject);
+ $this->_subject = $this->_encodeHeader($subject);
+ $this->_storeHeader('Subject', $this->_subject);
+ } else {
+ /**
+ * @see Zend_Mail_Exception
+ */
+ require_once 'Zend/Mail/Exception.php';
+ throw new Zend_Mail_Exception('Subject set twice');
+ }
+ return $this;
+ }
+
+ /**
+ * Returns the encoded subject of the message
+ *
+ * @return string
+ */
+ public function getSubject()
+ {
+ return $this->_subject;
+ }
+
+ /**
+ * Clears the encoded subject from the message
+ *
+ * @return Zend_Mail Provides fluent interface
+ */
+ public function clearSubject()
+ {
+ $this->_subject = null;
+ $this->_clearHeader('Subject');
+
+ return $this;
+ }
+
+ /**
+ * Sets Date-header
+ *
+ * @param string $date
+ * @return Zend_Mail Provides fluent interface
+ * @throws Zend_Mail_Exception if called subsequent times
+ */
+ public function setDate($date = null)
+ {
+ if ($this->_date === null) {
+ if ($date === null) {
+ $date = date('r');
+ } else if (is_int($date)) {
+ $date = date('r', $date);
+ } else if (is_string($date)) {
+ $date = strtotime($date);
+ if ($date === false || $date < 0) {
+ /**
+ * @see Zend_Mail_Exception
+ */
+ require_once 'Zend/Mail/Exception.php';
+ throw new Zend_Mail_Exception('String representations of Date Header must be ' .
+ 'strtotime()-compatible');
+ }
+ $date = date('r', $date);
+ } else if ($date instanceof Zend_Date) {
+ $date = $date->get(Zend_Date::RFC_2822);
+ } else {
+ /**
+ * @see Zend_Mail_Exception
+ */
+ require_once 'Zend/Mail/Exception.php';
+ throw new Zend_Mail_Exception(__METHOD__ . ' only accepts UNIX timestamps, Zend_Date objects, ' .
+ ' and strtotime()-compatible strings');
+ }
+ $this->_date = $date;
+ $this->_storeHeader('Date', $date);
+ } else {
+ /**
+ * @see Zend_Mail_Exception
+ */
+ require_once 'Zend/Mail/Exception.php';
+ throw new Zend_Mail_Exception('Date Header set twice');
+ }
+ return $this;
+ }
+
+ /**
+ * Returns the formatted date of the message
+ *
+ * @return string
+ */
+ public function getDate()
+ {
+ return $this->_date;
+ }
+
+ /**
+ * Clears the formatted date from the message
+ *
+ * @return Zend_Mail Provides fluent interface
+ */
+ public function clearDate()
+ {
+ $this->_date = null;
+ $this->_clearHeader('Date');
+
+ return $this;
+ }
+
+ /**
+ * Sets the Message-ID of the message
+ *
+ * @param boolean|string $id
+ * true :Auto
+ * false :No set
+ * null :No set
+ * string:Sets string
+ * @return Zend_Mail Provides fluent interface
+ * @throws Zend_Mail_Exception
+ */
+ public function setMessageId($id = true)
+ {
+ if ($id === null || $id === false) {
+ return $this;
+ } elseif ($id === true) {
+ $id = $this->createMessageId();
+ }
+
+ if ($this->_messageId === null) {
+ $id = $this->_filterOther($id);
+ $this->_messageId = $id;
+ $this->_storeHeader('Message-Id', $this->_messageId);
+ } else {
+ /**
+ * @see Zend_Mail_Exception
+ */
+ require_once 'Zend/Mail/Exception.php';
+ throw new Zend_Mail_Exception('Message-ID set twice');
+ }
+
+ return $this;
+ }
+
+ /**
+ * Returns the Message-ID of the message
+ *
+ * @return string
+ */
+ public function getMessageId()
+ {
+ return $this->_messageId;
+ }
+
+
+ /**
+ * Clears the Message-ID from the message
+ *
+ * @return Zend_Mail Provides fluent interface
+ */
+ public function clearMessageId()
+ {
+ $this->_messageId = null;
+ $this->_clearHeader('Message-Id');
+
+ return $this;
+ }
+
+ /**
+ * Creates the Message-ID
+ *
+ * @return string
+ */
+ public function createMessageId() {
+
+ $time = time();
+
+ if ($this->_from !== null) {
+ $user = $this->_from;
+ } elseif (isset($_SERVER['REMOTE_ADDR'])) {
+ $user = $_SERVER['REMOTE_ADDR'];
+ } else {
+ $user = getmypid();
+ }
+
+ $rand = mt_rand();
+
+ if ($this->_recipients !== array()) {
+ $recipient = array_rand($this->_recipients);
+ } else {
+ $recipient = 'unknown';
+ }
+
+ if (isset($_SERVER["SERVER_NAME"])) {
+ $hostName = $_SERVER["SERVER_NAME"];
+ } else {
+ $hostName = php_uname('n');
+ }
+
+ return sha1($time . $user . $rand . $recipient) . '@' . $hostName;
+ }
+
+ /**
+ * Add a custom header to the message
+ *
+ * @param string $name
+ * @param string $value
+ * @param boolean $append
+ * @return Zend_Mail Provides fluent interface
+ * @throws Zend_Mail_Exception on attempts to create standard headers
+ */
+ public function addHeader($name, $value, $append = false)
+ {
+ $prohibit = array('to', 'cc', 'bcc', 'from', 'subject',
+ 'return-path', 'date', 'message-id',
+ );
+ if (in_array(strtolower($name), $prohibit)) {
+ /**
+ * @see Zend_Mail_Exception
+ */
+ require_once 'Zend/Mail/Exception.php';
+ throw new Zend_Mail_Exception('Cannot set standard header from addHeader()');
+ }
+
+ $value = $this->_filterOther($value);
+ $value = $this->_encodeHeader($value);
+ $this->_storeHeader($name, $value, $append);
+
+ return $this;
+ }
+
+ /**
+ * Return mail headers
+ *
+ * @return void
+ */
+ public function getHeaders()
+ {
+ return $this->_headers;
+ }
+
+ /**
+ * Sends this email using the given transport or a previously
+ * set DefaultTransport or the internal mail function if no
+ * default transport had been set.
+ *
+ * @param Zend_Mail_Transport_Abstract $transport
+ * @return Zend_Mail Provides fluent interface
+ */
+ public function send($transport = null)
+ {
+ if ($transport === null) {
+ if (! self::$_defaultTransport instanceof Zend_Mail_Transport_Abstract) {
+ require_once 'Zend/Mail/Transport/Sendmail.php';
+ $transport = new Zend_Mail_Transport_Sendmail();
+ } else {
+ $transport = self::$_defaultTransport;
+ }
+ }
+
+ if ($this->_date === null) {
+ $this->setDate();
+ }
+
+ $transport->send($this);
+
+ return $this;
+ }
+
+ /**
+ * Filter of email data
+ *
+ * @param string $email
+ * @return string
+ */
+ protected function _filterEmail($email)
+ {
+ $rule = array("\r" => '',
+ "\n" => '',
+ "\t" => '',
+ '"' => '',
+ ',' => '',
+ '<' => '',
+ '>' => '',
+ );
+
+ return strtr($email, $rule);
+ }
+
+ /**
+ * Filter of name data
+ *
+ * @param string $name
+ * @return string
+ */
+ protected function _filterName($name)
+ {
+ $rule = array("\r" => '',
+ "\n" => '',
+ "\t" => '',
+ '"' => "'",
+ '<' => '[',
+ '>' => ']',
+ );
+
+ return trim(strtr($name, $rule));
+ }
+
+ /**
+ * Filter of other data
+ *
+ * @param string $data
+ * @return string
+ */
+ protected function _filterOther($data)
+ {
+ $rule = array("\r" => '',
+ "\n" => '',
+ "\t" => '',
+ );
+
+ return strtr($data, $rule);
+ }
+
+ /**
+ * Formats e-mail address
+ *
+ * @param string $email
+ * @param string $name
+ * @return string
+ */
+ protected function _formatAddress($email, $name)
+ {
+ if ($name === '' || $name === null || $name === $email) {
+ return $email;
+ } else {
+ $encodedName = $this->_encodeHeader($name);
+ if ($encodedName === $name && strpos($name, ',') !== false) {
+ $format = '"%s" <%s>';
+ } else {
+ $format = '%s <%s>';
+ }
+ return sprintf($format, $encodedName, $email);
+ }
+ }
+
+}
--- /dev/null
+<?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.
+ *
+ * @package Zend_Memory
+ * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ * @version $Id$
+ */
+
+/** Zend_Memory_Exception */
+require_once 'Zend/Memory/Manager.php';
+
+/** Zend_Memory_Value */
+require_once 'Zend/Memory/Value.php';
+
+/** Zend_Memory_Container */
+require_once 'Zend/Memory/Container.php';
+
+/** Zend_Memory_Exception */
+require_once 'Zend/Cache.php';
+
+/**
+ * @category Zend
+ * @package Zend_Memory
+ * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+class Zend_Memory
+{
+ /**
+ * Factory
+ *
+ * @param string $backend backend name
+ * @param array $backendOptions associative array of options for the corresponding backend constructor
+ * @return Zend_Memory_Manager
+ * @throws Zend_Memory_Exception
+ */
+ public static function factory($backend, $backendOptions = array())
+ {
+ if (strcasecmp($backend, 'none') == 0) {
+ return new Zend_Memory_Manager();
+ }
+
+ // because lowercase will fail
+ $backend = @ucfirst(strtolower($backend));
+
+ if (!in_array($backend, Zend_Cache::$availableBackends)) {
+ require_once 'Zend/Memory/Exception.php';
+ throw new Zend_Memory_Exception("Incorrect backend ($backend)");
+ }
+
+ $backendClass = 'Zend_Cache_Backend_' . $backend;
+
+ // For perfs reasons, we do not use the Zend_Loader::loadClass() method
+ // (security controls are explicit)
+ require_once str_replace('_', DIRECTORY_SEPARATOR, $backendClass) . '.php';
+
+ $backendObject = new $backendClass($backendOptions);
+
+ return new Zend_Memory_Manager($backendObject);
+ }
+}
*
* @category Zend
* @package Zend_Mime
- * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
+ * @version $Id$
*/
*
* @category Zend
* @package Zend_Mime
- * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Mime
const ENCODING_BASE64 = 'base64';
const DISPOSITION_ATTACHMENT = 'attachment';
const DISPOSITION_INLINE = 'inline';
- const LINELENGTH = 74;
+ const LINELENGTH = 72;
const LINEEND = "\n";
const MULTIPART_ALTERNATIVE = 'multipart/alternative';
const MULTIPART_MIXED = 'multipart/mixed';
}
/**
- * Encode a given string with the QUOTED_PRINTABLE mechanism
+ * Encode a given string with the QUOTED_PRINTABLE mechanism and wrap the lines.
*
* @param string $str
* @param int $lineLength Defaults to {@link LINELENGTH}
$lineEnd = self::LINEEND)
{
$out = '';
- $str = str_replace('=', '=3D', $str);
- $str = str_replace(self::$qpKeys, self::$qpReplaceValues, $str);
- $str = rtrim($str);
+ $str = self::_encodeQuotedPrintable($str);
// Split encoded text into separate lines
while ($str) {
return $out;
}
+ /**
+ * Converts a string into quoted printable format.
+ *
+ * @param string $str
+ * @return string
+ */
+ private static function _encodeQuotedPrintable($str)
+ {
+ $str = str_replace('=', '=3D', $str);
+ $str = str_replace(self::$qpKeys, self::$qpReplaceValues, $str);
+ $str = rtrim($str);
+ return $str;
+ }
+
+ /**
+ * Encode a given string with the QUOTED_PRINTABLE mechanism for Mail Headers.
+ *
+ * Mail headers depend on an extended quoted printable algorithm otherwise
+ * a range of bugs can occur.
+ *
+ * @param string $str
+ * @param string $charset
+ * @param int $lineLength Defaults to {@link LINELENGTH}
+ * @param int $lineEnd Defaults to {@link LINEEND}
+ * @return string
+ */
+ public static function encodeQuotedPrintableHeader($str, $charset,
+ $lineLength = self::LINELENGTH,
+ $lineEnd = self::LINEEND)
+ {
+ // Reduce line-length by the length of the required delimiter, charsets and encoding
+ $prefix = sprintf('=?%s?Q?', $charset);
+ $lineLength = $lineLength-strlen($prefix)-3;
+
+ $str = self::_encodeQuotedPrintable($str);
+
+ // Mail-Header required chars have to be encoded also:
+ $str = str_replace(array('?', ' ', '_'), array('=3F', '=20', '=5F'), $str);
+
+ // initialize first line, we need it anyways
+ $lines = array(0 => "");
+
+ // Split encoded text into separate lines
+ $tmp = "";
+ while(strlen($str) > 0) {
+ $currentLine = max(count($lines)-1, 0);
+ $token = self::getNextQuotedPrintableToken($str);
+ $str = substr($str, strlen($token));
+
+ $tmp .= $token;
+ if($token == '=20') {
+ // only if we have a single char token or space, we can append the
+ // tempstring it to the current line or start a new line if necessary.
+ if(strlen($lines[$currentLine].$tmp) > $lineLength) {
+ $lines[$currentLine+1] = $tmp;
+ } else {
+ $lines[$currentLine] .= $tmp;
+ }
+ $tmp = "";
+ }
+ // don't forget to append the rest to the last line
+ if(strlen($str) == 0) {
+ $lines[$currentLine] .= $tmp;
+ }
+ }
+
+ // assemble the lines together by pre- and appending delimiters, charset, encoding.
+ for($i = 0; $i < count($lines); $i++) {
+ $lines[$i] = " ".$prefix.$lines[$i]."?=";
+ }
+ $str = trim(implode($lineEnd, $lines));
+ return $str;
+ }
+
+ /**
+ * Retrieves the first token from a quoted printable string.
+ *
+ * @param string $str
+ * @return string
+ */
+ private static function getNextQuotedPrintableToken($str)
+ {
+ if(substr($str, 0, 1) == "=") {
+ $token = substr($str, 0, 3);
+ } else {
+ $token = substr($str, 0, 1);
+ }
+ return $token;
+ }
+
+ /**
+ * Encode a given string in mail header compatible base64 encoding.
+ *
+ * @param string $str
+ * @param string $charset
+ * @param int $lineLength Defaults to {@link LINELENGTH}
+ * @param int $lineEnd Defaults to {@link LINEEND}
+ * @return string
+ */
+ public static function encodeBase64Header($str,
+ $charset,
+ $lineLength = self::LINELENGTH,
+ $lineEnd = self::LINEEND)
+ {
+ $prefix = '=?' . $charset . '?B?';
+ $suffix = '?=';
+ $remainingLength = $lineLength - strlen($prefix) - strlen($suffix);
+
+ $encodedValue = self::encodeBase64($str, $remainingLength, $lineEnd);
+ $encodedValue = str_replace($lineEnd, $suffix . $lineEnd . ' ' . $prefix, $encodedValue);
+ $encodedValue = $prefix . $encodedValue . $suffix;
+ return $encodedValue;
+ }
+
/**
* Encode a given string in base64 encoding and break lines
* according to the maximum linelength.
--- /dev/null
+<?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_Navigation
+ * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ * @version $Id$
+ */
+
+/**
+ * @see Zend_Navigation_Container
+ */
+require_once 'Zend/Navigation/Container.php';
+
+/**
+ * A simple container class for {@link Zend_Navigation_Page} pages
+ *
+ * @category Zend
+ * @package Zend_Navigation
+ * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+class Zend_Navigation extends Zend_Navigation_Container
+{
+ /**
+ * Creates a new navigation container
+ *
+ * @param array|Zend_Config $pages [optional] pages to add
+ * @throws Zend_Navigation_Exception if $pages is invalid
+ */
+ public function __construct($pages = null)
+ {
+ if (is_array($pages) || $pages instanceof Zend_Config) {
+ $this->addPages($pages);
+ } elseif (null !== $pages) {
+ require_once 'Zend/Navigation/Exception.php';
+ throw new Zend_Navigation_Exception(
+ 'Invalid argument: $pages must be an array, an ' .
+ 'instance of Zend_Config, or null');
+ }
+ }
+}
--- /dev/null
+<?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_OpenId
+ * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ * @version $Id$
+ */
+
+/**
+ * @see Zend_Controller_Response_Abstract
+ */
+require_once "Zend/Controller/Response/Abstract.php";
+
+/**
+ * Static class that contains common utility functions for
+ * {@link Zend_OpenId_Consumer} and {@link Zend_OpenId_Provider}.
+ *
+ * This class implements common utility functions that are used by both
+ * Consumer and Provider. They include functions for Diffie-Hellman keys
+ * generation and exchange, URL normalization, HTTP redirection and some others.
+ *
+ * @category Zend
+ * @package Zend_OpenId
+ * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+class Zend_OpenId
+{
+ /**
+ * Default Diffie-Hellman key generator (1024 bit)
+ */
+ const DH_P = 'dcf93a0b883972ec0e19989ac5a2ce310e1d37717e8d9571bb7623731866e61ef75a2e27898b057f9891c2e27a639c3f29b60814581cd3b2ca3986d2683705577d45c2e7e52dc81c7a171876e5cea74b1448bfdfaf18828efd2519f14e45e3826634af1949e5b535cc829a483b8a76223e5d490a257f05bdff16f2fb22c583ab';
+
+ /**
+ * Default Diffie-Hellman prime number (should be 2 or 5)
+ */
+ const DH_G = '02';
+
+ /**
+ * OpenID 2.0 namespace. All OpenID 2.0 messages MUST contain variable
+ * openid.ns with its value.
+ */
+ const NS_2_0 = 'http://specs.openid.net/auth/2.0';
+
+ /**
+ * Allows enable/disable stoping execution of PHP script after redirect()
+ */
+ static public $exitOnRedirect = true;
+
+ /**
+ * Alternative request URL that can be used to override the default
+ * selfUrl() response
+ */
+ static public $selfUrl = null;
+
+ /**
+ * Sets alternative request URL that can be used to override the default
+ * selfUrl() response
+ *
+ * @param string $selfUrl the URL to be set
+ * @return string the old value of overriding URL
+ */
+ static public function setSelfUrl($selfUrl = null)
+ {
+ $ret = self::$selfUrl;
+ self::$selfUrl = $selfUrl;
+ return $ret;
+ }
+
+ /**
+ * Returns a full URL that was requested on current HTTP request.
+ *
+ * @return string
+ */
+ static public function selfUrl()
+ {
+ if (self::$selfUrl !== null) {
+ return self::$selfUrl;
+ } if (isset($_SERVER['SCRIPT_URI'])) {
+ return $_SERVER['SCRIPT_URI'];
+ }
+ $url = '';
+ $port = '';
+ if (isset($_SERVER['HTTP_HOST'])) {
+ if (($pos = strpos($_SERVER['HTTP_HOST'], ':')) === false) {
+ if (isset($_SERVER['SERVER_PORT'])) {
+ $port = ':' . $_SERVER['SERVER_PORT'];
+ }
+ $url = $_SERVER['HTTP_HOST'];
+ } else {
+ $url = substr($_SERVER['HTTP_HOST'], 0, $pos);
+ $port = substr($_SERVER['HTTP_HOST'], $pos);
+ }
+ } else if (isset($_SERVER['SERVER_NAME'])) {
+ $url = $_SERVER['SERVER_NAME'];
+ if (isset($_SERVER['SERVER_PORT'])) {
+ $port = ':' . $_SERVER['SERVER_PORT'];
+ }
+ }
+ if (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') {
+ $url = 'https://' . $url;
+ if ($port == ':443') {
+ $port = '';
+ }
+ } else {
+ $url = 'http://' . $url;
+ if ($port == ':80') {
+ $port = '';
+ }
+ }
+
+ $url .= $port;
+ if (isset($_SERVER['HTTP_X_REWRITE_URL'])) {
+ $url .= $_SERVER['HTTP_X_REWRITE_URL'];
+ } elseif (isset($_SERVER['REQUEST_URI'])) {
+ $query = strpos($_SERVER['REQUEST_URI'], '?');
+ if ($query === false) {
+ $url .= $_SERVER['REQUEST_URI'];
+ } else {
+ $url .= substr($_SERVER['REQUEST_URI'], 0, $query);
+ }
+ } else if (isset($_SERVER['SCRIPT_URL'])) {
+ $url .= $_SERVER['SCRIPT_URL'];
+ } else if (isset($_SERVER['REDIRECT_URL'])) {
+ $url .= $_SERVER['REDIRECT_URL'];
+ } else if (isset($_SERVER['PHP_SELF'])) {
+ $url .= $_SERVER['PHP_SELF'];
+ } else if (isset($_SERVER['SCRIPT_NAME'])) {
+ $url .= $_SERVER['SCRIPT_NAME'];
+ if (isset($_SERVER['PATH_INFO'])) {
+ $url .= $_SERVER['PATH_INFO'];
+ }
+ }
+ return $url;
+ }
+
+ /**
+ * Returns an absolute URL for the given one
+ *
+ * @param string $url absilute or relative URL
+ * @return string
+ */
+ static public function absoluteUrl($url)
+ {
+ if (empty($url)) {
+ return Zend_OpenId::selfUrl();
+ } else if (!preg_match('|^([^:]+)://|', $url)) {
+ if (preg_match('|^([^:]+)://([^:@]*(?:[:][^@]*)?@)?([^/:@?#]*)(?:[:]([^/?#]*))?(/[^?]*)?((?:[?](?:[^#]*))?(?:#.*)?)$|', Zend_OpenId::selfUrl(), $reg)) {
+ $scheme = $reg[1];
+ $auth = $reg[2];
+ $host = $reg[3];
+ $port = $reg[4];
+ $path = $reg[5];
+ $query = $reg[6];
+ if ($url[0] == '/') {
+ return $scheme
+ . '://'
+ . $auth
+ . $host
+ . (empty($port) ? '' : (':' . $port))
+ . $url;
+ } else {
+ $dir = dirname($path);
+ return $scheme
+ . '://'
+ . $auth
+ . $host
+ . (empty($port) ? '' : (':' . $port))
+ . (strlen($dir) > 1 ? $dir : '')
+ . '/'
+ . $url;
+ }
+ }
+ }
+ return $url;
+ }
+
+ /**
+ * Converts variable/value pairs into URL encoded query string
+ *
+ * @param array $params variable/value pairs
+ * @return string URL encoded query string
+ */
+ static public function paramsToQuery($params)
+ {
+ foreach($params as $key => $value) {
+ if (isset($query)) {
+ $query .= '&' . $key . '=' . urlencode($value);
+ } else {
+ $query = $key . '=' . urlencode($value);
+ }
+ }
+ return isset($query) ? $query : '';
+ }
+
+ /**
+ * Normalizes URL according to RFC 3986 to use it in comparison operations.
+ * The function gets URL argument by reference and modifies it.
+ * It returns true on success and false of failure.
+ *
+ * @param string &$id url to be normalized
+ * @return bool
+ */
+ static public function normalizeUrl(&$id)
+ {
+ // RFC 3986, 6.2.2. Syntax-Based Normalization
+
+ // RFC 3986, 6.2.2.2 Percent-Encoding Normalization
+ $i = 0;
+ $n = strlen($id);
+ $res = '';
+ while ($i < $n) {
+ if ($id[$i] == '%') {
+ if ($i + 2 >= $n) {
+ return false;
+ }
+ ++$i;
+ if ($id[$i] >= '0' && $id[$i] <= '9') {
+ $c = ord($id[$i]) - ord('0');
+ } else if ($id[$i] >= 'A' && $id[$i] <= 'F') {
+ $c = ord($id[$i]) - ord('A') + 10;
+ } else if ($id[$i] >= 'a' && $id[$i] <= 'f') {
+ $c = ord($id[$i]) - ord('a') + 10;
+ } else {
+ return false;
+ }
+ ++$i;
+ if ($id[$i] >= '0' && $id[$i] <= '9') {
+ $c = ($c << 4) | (ord($id[$i]) - ord('0'));
+ } else if ($id[$i] >= 'A' && $id[$i] <= 'F') {
+ $c = ($c << 4) | (ord($id[$i]) - ord('A') + 10);
+ } else if ($id[$i] >= 'a' && $id[$i] <= 'f') {
+ $c = ($c << 4) | (ord($id[$i]) - ord('a') + 10);
+ } else {
+ return false;
+ }
+ ++$i;
+ $ch = chr($c);
+ if (($ch >= 'A' && $ch <= 'Z') ||
+ ($ch >= 'a' && $ch <= 'z') ||
+ $ch == '-' ||
+ $ch == '.' ||
+ $ch == '_' ||
+ $ch == '~') {
+ $res .= $ch;
+ } else {
+ $res .= '%';
+ if (($c >> 4) < 10) {
+ $res .= chr(($c >> 4) + ord('0'));
+ } else {
+ $res .= chr(($c >> 4) - 10 + ord('A'));
+ }
+ $c = $c & 0xf;
+ if ($c < 10) {
+ $res .= chr($c + ord('0'));
+ } else {
+ $res .= chr($c - 10 + ord('A'));
+ }
+ }
+ } else {
+ $res .= $id[$i++];
+ }
+ }
+
+ if (!preg_match('|^([^:]+)://([^:@]*(?:[:][^@]*)?@)?([^/:@?#]*)(?:[:]([^/?#]*))?(/[^?#]*)?((?:[?](?:[^#]*))?)((?:#.*)?)$|', $res, $reg)) {
+ return false;
+ }
+ $scheme = $reg[1];
+ $auth = $reg[2];
+ $host = $reg[3];
+ $port = $reg[4];
+ $path = $reg[5];
+ $query = $reg[6];
+ $fragment = $reg[7]; /* strip it */
+
+ if (empty($scheme) || empty($host)) {
+ return false;
+ }
+
+ // RFC 3986, 6.2.2.1. Case Normalization
+ $scheme = strtolower($scheme);
+ $host = strtolower($host);
+
+ // RFC 3986, 6.2.2.3. Path Segment Normalization
+ if (!empty($path)) {
+ $i = 0;
+ $n = strlen($path);
+ $res = "";
+ while ($i < $n) {
+ if ($path[$i] == '/') {
+ ++$i;
+ while ($i < $n && $path[$i] == '/') {
+ ++$i;
+ }
+ if ($i < $n && $path[$i] == '.') {
+ ++$i;
+ if ($i < $n && $path[$i] == '.') {
+ ++$i;
+ if ($i == $n || $path[$i] == '/') {
+ if (($pos = strrpos($res, '/')) !== false) {
+ $res = substr($res, 0, $pos);
+ }
+ } else {
+ $res .= '/..';
+ }
+ } else if ($i != $n && $path[$i] != '/') {
+ $res .= '/.';
+ }
+ } else {
+ $res .= '/';
+ }
+ } else {
+ $res .= $path[$i++];
+ }
+ }
+ $path = $res;
+ }
+
+ // RFC 3986,6.2.3. Scheme-Based Normalization
+ if ($scheme == 'http') {
+ if ($port == 80) {
+ $port = '';
+ }
+ } else if ($scheme == 'https') {
+ if ($port == 443) {
+ $port = '';
+ }
+ }
+ if (empty($path)) {
+ $path = '/';
+ }
+
+ $id = $scheme
+ . '://'
+ . $auth
+ . $host
+ . (empty($port) ? '' : (':' . $port))
+ . $path
+ . $query;
+ return true;
+ }
+
+ /**
+ * Normalizes OpenID identifier that can be URL or XRI name.
+ * Returns true on success and false of failure.
+ *
+ * Normalization is performed according to the following rules:
+ * 1. If the user's input starts with one of the "xri://", "xri://$ip*",
+ * or "xri://$dns*" prefixes, they MUST be stripped off, so that XRIs
+ * are used in the canonical form, and URI-authority XRIs are further
+ * considered URL identifiers.
+ * 2. If the first character of the resulting string is an XRI Global
+ * Context Symbol ("=", "@", "+", "$", "!"), then the input SHOULD be
+ * treated as an XRI.
+ * 3. Otherwise, the input SHOULD be treated as an http URL; if it does
+ * not include a "http" or "https" scheme, the Identifier MUST be
+ * prefixed with the string "http://".
+ * 4. URL identifiers MUST then be further normalized by both following
+ * redirects when retrieving their content and finally applying the
+ * rules in Section 6 of [RFC3986] to the final destination URL.
+ * @param string &$id identifier to be normalized
+ * @return bool
+ */
+ static public function normalize(&$id)
+ {
+ $id = trim($id);
+ if (strlen($id) === 0) {
+ return true;
+ }
+
+ // 7.2.1
+ if (strpos($id, 'xri://$ip*') === 0) {
+ $id = substr($id, strlen('xri://$ip*'));
+ } else if (strpos($id, 'xri://$dns*') === 0) {
+ $id = substr($id, strlen('xri://$dns*'));
+ } else if (strpos($id, 'xri://') === 0) {
+ $id = substr($id, strlen('xri://'));
+ }
+
+ // 7.2.2
+ if ($id[0] == '=' ||
+ $id[0] == '@' ||
+ $id[0] == '+' ||
+ $id[0] == '$' ||
+ $id[0] == '!') {
+ return true;
+ }
+
+ // 7.2.3
+ if (strpos($id, "://") === false) {
+ $id = 'http://' . $id;
+ }
+
+ // 7.2.4
+ return self::normalizeURL($id);
+ }
+
+ /**
+ * Performs a HTTP redirection to specified URL with additional data.
+ * It may generate redirected request using GET or POST HTTP method.
+ * The function never returns.
+ *
+ * @param string $url URL to redirect to
+ * @param array $params additional variable/value pairs to send
+ * @param Zend_Controller_Response_Abstract $response
+ * @param string $method redirection method ('GET' or 'POST')
+ */
+ static public function redirect($url, $params = null,
+ Zend_Controller_Response_Abstract $response = null, $method = 'GET')
+ {
+ $url = Zend_OpenId::absoluteUrl($url);
+ $body = "";
+ if (null === $response) {
+ require_once "Zend/Controller/Response/Http.php";
+ $response = new Zend_Controller_Response_Http();
+ }
+
+ if ($method == 'POST') {
+ $body = "<html><body onLoad=\"document.forms[0].submit();\">\n";
+ $body .= "<form method=\"POST\" action=\"$url\">\n";
+ if (is_array($params) && count($params) > 0) {
+ foreach($params as $key => $value) {
+ $body .= '<input type="hidden" name="' . $key . '" value="' . $value . "\">\n";
+ }
+ }
+ $body .= "<input type=\"submit\" value=\"Continue OpenID transaction\">\n";
+ $body .= "</form></body></html>\n";
+ } else if (is_array($params) && count($params) > 0) {
+ if (strpos($url, '?') === false) {
+ $url .= '?' . self::paramsToQuery($params);
+ } else {
+ $url .= '&' . self::paramsToQuery($params);
+ }
+ }
+ if (!empty($body)) {
+ $response->setBody($body);
+ } else if (!$response->canSendHeaders()) {
+ $response->setBody("<script language=\"JavaScript\"" .
+ " type=\"text/javascript\">window.location='$url';" .
+ "</script>");
+ } else {
+ $response->setRedirect($url);
+ }
+ $response->sendResponse();
+ if (self::$exitOnRedirect) {
+ exit();
+ }
+ }
+
+ /**
+ * Produces string of random byte of given length.
+ *
+ * @param integer $len length of requested string
+ * @return string RAW random binary string
+ */
+ static public function randomBytes($len)
+ {
+ $key = '';
+ for($i=0; $i < $len; $i++) {
+ $key .= chr(mt_rand(0, 255));
+ }
+ return $key;
+ }
+
+ /**
+ * Generates a hash value (message digest) according to given algorithm.
+ * It returns RAW binary string.
+ *
+ * This is a wrapper function that uses one of available internal function
+ * dependent on given PHP configuration. It may use various functions from
+ * ext/openssl, ext/hash, ext/mhash or ext/standard.
+ *
+ * @param string $func digest algorithm
+ * @param string $data data to sign
+ * @return string RAW digital signature
+ * @throws Zend_OpenId_Exception
+ */
+ static public function digest($func, $data)
+ {
+ if (function_exists('openssl_digest')) {
+ return openssl_digest($data, $func, true);
+ } else if (function_exists('hash')) {
+ return hash($func, $data, true);
+ } else if ($func === 'sha1') {
+ return sha1($data, true);
+ } else if ($func === 'sha256') {
+ if (function_exists('mhash')) {
+ return mhash(MHASH_SHA256 , $data);
+ }
+ }
+ require_once "Zend/OpenId/Exception.php";
+ throw new Zend_OpenId_Exception(
+ 'Unsupported digest algorithm "' . $func . '".',
+ Zend_OpenId_Exception::UNSUPPORTED_DIGEST);
+ }
+
+ /**
+ * Generates a keyed hash value using the HMAC method. It uses ext/hash
+ * if available or user-level PHP implementation, that is not significantly
+ * slower.
+ *
+ * @param string $macFunc name of selected hashing algorithm (sha1, sha256)
+ * @param string $data data to sign
+ * @param string $secret shared secret key used for generating the HMAC
+ * variant of the message digest
+ * @return string RAW HMAC value
+ */
+ static public function hashHmac($macFunc, $data, $secret)
+ {
+// require_once "Zend/Crypt/Hmac.php";
+// return Zend_Crypt_Hmac::compute($secret, $macFunc, $data, Zend_Crypt_Hmac::BINARY);
+ if (function_exists('hash_hmac')) {
+ return hash_hmac($macFunc, $data, $secret, 1);
+ } else {
+ if (Zend_OpenId::strlen($secret) > 64) {
+ $secret = self::digest($macFunc, $secret);
+ }
+ $secret = str_pad($secret, 64, chr(0x00));
+ $ipad = str_repeat(chr(0x36), 64);
+ $opad = str_repeat(chr(0x5c), 64);
+ $hash1 = self::digest($macFunc, ($secret ^ $ipad) . $data);
+ return self::digest($macFunc, ($secret ^ $opad) . $hash1);
+ }
+ }
+
+ /**
+ * Converts binary representation into ext/gmp or ext/bcmath big integer
+ * representation.
+ *
+ * @param string $bin binary representation of big number
+ * @return mixed
+ * @throws Zend_OpenId_Exception
+ */
+ static protected function binToBigNum($bin)
+ {
+ if (extension_loaded('gmp')) {
+ return gmp_init(bin2hex($bin), 16);
+ } else if (extension_loaded('bcmath')) {
+ $bn = 0;
+ $len = Zend_OpenId::strlen($bin);
+ for ($i = 0; $i < $len; $i++) {
+ $bn = bcmul($bn, 256);
+ $bn = bcadd($bn, ord($bin[$i]));
+ }
+ return $bn;
+ }
+ require_once "Zend/OpenId/Exception.php";
+ throw new Zend_OpenId_Exception(
+ 'The system doesn\'t have proper big integer extension',
+ Zend_OpenId_Exception::UNSUPPORTED_LONG_MATH);
+ }
+
+ /**
+ * Converts internal ext/gmp or ext/bcmath big integer representation into
+ * binary string.
+ *
+ * @param mixed $bn big number
+ * @return string
+ * @throws Zend_OpenId_Exception
+ */
+ static protected function bigNumToBin($bn)
+ {
+ if (extension_loaded('gmp')) {
+ $s = gmp_strval($bn, 16);
+ if (strlen($s) % 2 != 0) {
+ $s = '0' . $s;
+ } else if ($s[0] > '7') {
+ $s = '00' . $s;
+ }
+ return pack("H*", $s);
+ } else if (extension_loaded('bcmath')) {
+ $cmp = bccomp($bn, 0);
+ if ($cmp == 0) {
+ return (chr(0));
+ } else if ($cmp < 0) {
+ require_once "Zend/OpenId/Exception.php";
+ throw new Zend_OpenId_Exception(
+ 'Big integer arithmetic error',
+ Zend_OpenId_Exception::ERROR_LONG_MATH);
+ }
+ $bin = "";
+ while (bccomp($bn, 0) > 0) {
+ $bin = chr(bcmod($bn, 256)) . $bin;
+ $bn = bcdiv($bn, 256);
+ }
+ if (ord($bin[0]) > 127) {
+ $bin = chr(0) . $bin;
+ }
+ return $bin;
+ }
+ require_once "Zend/OpenId/Exception.php";
+ throw new Zend_OpenId_Exception(
+ 'The system doesn\'t have proper big integer extension',
+ Zend_OpenId_Exception::UNSUPPORTED_LONG_MATH);
+ }
+
+ /**
+ * Performs the first step of a Diffie-Hellman key exchange by generating
+ * private and public DH values based on given prime number $p and
+ * generator $g. Both sides of key exchange MUST have the same prime number
+ * and generator. In this case they will able to create a random shared
+ * secret that is never send from one to the other.
+ *
+ * @param string $p prime number in binary representation
+ * @param string $g generator in binary representation
+ * @param string $priv_key private key in binary representation
+ * @return mixed
+ */
+ static public function createDhKey($p, $g, $priv_key = null)
+ {
+ if (function_exists('openssl_dh_compute_key')) {
+ $dh_details = array(
+ 'p' => $p,
+ 'g' => $g
+ );
+ if ($priv_key !== null) {
+ $dh_details['priv_key'] = $priv_key;
+ }
+ return openssl_pkey_new(array('dh'=>$dh_details));
+ } else {
+ $bn_p = self::binToBigNum($p);
+ $bn_g = self::binToBigNum($g);
+ if ($priv_key === null) {
+ $priv_key = self::randomBytes(Zend_OpenId::strlen($p));
+ }
+ $bn_priv_key = self::binToBigNum($priv_key);
+ if (extension_loaded('gmp')) {
+ $bn_pub_key = gmp_powm($bn_g, $bn_priv_key, $bn_p);
+ } else if (extension_loaded('bcmath')) {
+ $bn_pub_key = bcpowmod($bn_g, $bn_priv_key, $bn_p);
+ }
+ $pub_key = self::bigNumToBin($bn_pub_key);
+
+ return array(
+ 'p' => $bn_p,
+ 'g' => $bn_g,
+ 'priv_key' => $bn_priv_key,
+ 'pub_key' => $bn_pub_key,
+ 'details' => array(
+ 'p' => $p,
+ 'g' => $g,
+ 'priv_key' => $priv_key,
+ 'pub_key' => $pub_key));
+ }
+ }
+
+ /**
+ * Returns an associative array with Diffie-Hellman key components in
+ * binary representation. The array includes original prime number 'p' and
+ * generator 'g', random private key 'priv_key' and corresponding public
+ * key 'pub_key'.
+ *
+ * @param mixed $dh Diffie-Hellman key
+ * @return array
+ */
+ static public function getDhKeyDetails($dh)
+ {
+ if (function_exists('openssl_dh_compute_key')) {
+ $details = openssl_pkey_get_details($dh);
+ if (isset($details['dh'])) {
+ return $details['dh'];
+ }
+ } else {
+ return $dh['details'];
+ }
+ }
+
+ /**
+ * Computes the shared secret from the private DH value $dh and the other
+ * party's public value in $pub_key
+ *
+ * @param string $pub_key other party's public value
+ * @param mixed $dh Diffie-Hellman key
+ * @return string
+ * @throws Zend_OpenId_Exception
+ */
+ static public function computeDhSecret($pub_key, $dh)
+ {
+ if (function_exists('openssl_dh_compute_key')) {
+ $ret = openssl_dh_compute_key($pub_key, $dh);
+ if (ord($ret[0]) > 127) {
+ $ret = chr(0) . $ret;
+ }
+ return $ret;
+ } else if (extension_loaded('gmp')) {
+ $bn_pub_key = self::binToBigNum($pub_key);
+ $bn_secret = gmp_powm($bn_pub_key, $dh['priv_key'], $dh['p']);
+ return self::bigNumToBin($bn_secret);
+ } else if (extension_loaded('bcmath')) {
+ $bn_pub_key = self::binToBigNum($pub_key);
+ $bn_secret = bcpowmod($bn_pub_key, $dh['priv_key'], $dh['p']);
+ return self::bigNumToBin($bn_secret);
+ }
+ require_once "Zend/OpenId/Exception.php";
+ throw new Zend_OpenId_Exception(
+ 'The system doesn\'t have proper big integer extension',
+ Zend_OpenId_Exception::UNSUPPORTED_LONG_MATH);
+ }
+
+ /**
+ * Takes an arbitrary precision integer and returns its shortest big-endian
+ * two's complement representation.
+ *
+ * Arbitrary precision integers MUST be encoded as big-endian signed two's
+ * complement binary strings. Henceforth, "btwoc" is a function that takes
+ * an arbitrary precision integer and returns its shortest big-endian two's
+ * complement representation. All integers that are used with
+ * Diffie-Hellman Key Exchange are positive. This means that the left-most
+ * bit of the two's complement representation MUST be zero. If it is not,
+ * implementations MUST add a zero byte at the front of the string.
+ *
+ * @param string $str binary representation of arbitrary precision integer
+ * @return string big-endian signed representation
+ */
+ static public function btwoc($str)
+ {
+ if (ord($str[0]) > 127) {
+ return chr(0) . $str;
+ }
+ return $str;
+ }
+
+ /**
+ * Returns lenght of binary string in bytes
+ *
+ * @param string $str
+ * @return int the string lenght
+ */
+ static public function strlen($str)
+ {
+ if (extension_loaded('mbstring') &&
+ (((int)ini_get('mbstring.func_overload')) & 2)) {
+ return mb_strlen($str, 'latin1');
+ } else {
+ return strlen($str);
+ }
+ }
+
+}
--- /dev/null
+<?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_Paginator
+ * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ * @version $Id$
+ */
+
+/**
+ * @see Zend_Loader_PluginLoader
+ */
+require_once 'Zend/Loader/PluginLoader.php';
+
+/**
+ * @see Zend_Json
+ */
+require_once 'Zend/Json.php';
+
+/**
+ * @category Zend
+ * @package Zend_Paginator
+ * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+class Zend_Paginator implements Countable, IteratorAggregate
+{
+ /**
+ * Specifies that the factory should try to detect the proper adapter type first
+ *
+ * @var string
+ */
+ const INTERNAL_ADAPTER = 'Zend_Paginator_Adapter_Internal';
+
+ /**
+ * The cache tag prefix used to namespace Paginator results in the cache
+ *
+ */
+ const CACHE_TAG_PREFIX = 'Zend_Paginator_';
+
+ /**
+ * Adapter plugin loader
+ *
+ * @var Zend_Loader_PluginLoader
+ */
+ protected static $_adapterLoader = null;
+
+ /**
+ * Configuration file
+ *
+ * @var Zend_Config
+ */
+ protected static $_config = null;
+
+ /**
+ * Default scrolling style
+ *
+ * @var string
+ */
+ protected static $_defaultScrollingStyle = 'Sliding';
+
+ /**
+ * Default item count per page
+ *
+ * @var int
+ */
+ protected static $_defaultItemCountPerPage = 10;
+
+ /**
+ * Scrolling style plugin loader
+ *
+ * @var Zend_Loader_PluginLoader
+ */
+ protected static $_scrollingStyleLoader = null;
+
+ /**
+ * Cache object
+ *
+ * @var Zend_Cache_Core
+ */
+ protected static $_cache;
+
+ /**
+ * Enable or desable the cache by Zend_Paginator instance
+ *
+ * @var bool
+ */
+ protected $_cacheEnabled = true;
+
+ /**
+ * Adapter
+ *
+ * @var Zend_Paginator_Adapter_Interface
+ */
+ protected $_adapter = null;
+
+ /**
+ * Number of items in the current page
+ *
+ * @var integer
+ */
+ protected $_currentItemCount = null;
+
+ /**
+ * Current page items
+ *
+ * @var Traversable
+ */
+ protected $_currentItems = null;
+
+ /**
+ * Current page number (starting from 1)
+ *
+ * @var integer
+ */
+ protected $_currentPageNumber = 1;
+
+ /**
+ * Result filter
+ *
+ * @var Zend_Filter_Interface
+ */
+ protected $_filter = null;
+
+ /**
+ * Number of items per page
+ *
+ * @var integer
+ */
+ protected $_itemCountPerPage = null;
+
+ /**
+ * Number of pages
+ *
+ * @var integer
+ */
+ protected $_pageCount = null;
+
+ /**
+ * Number of local pages (i.e., the number of discrete page numbers
+ * that will be displayed, including the current page number)
+ *
+ * @var integer
+ */
+ protected $_pageRange = 10;
+
+ /**
+ * Pages
+ *
+ * @var array
+ */
+ protected $_pages = null;
+
+ /**
+ * View instance used for self rendering
+ *
+ * @var Zend_View_Interface
+ */
+ protected $_view = null;
+
+ /**
+ * Adds an adapter prefix path to the plugin loader.
+ *
+ * @param string $prefix
+ * @param string $path
+ */
+ public static function addAdapterPrefixPath($prefix, $path)
+ {
+ self::getAdapterLoader()->addPrefixPath($prefix, $path);
+ }
+
+ /**
+ * Adds an array of adapter prefix paths to the plugin
+ * loader.
+ *
+ * <code>
+ * $prefixPaths = array(
+ * 'My_Paginator_Adapter' => 'My/Paginator/Adapter/',
+ * 'Your_Paginator_Adapter' => 'Your/Paginator/Adapter/'
+ * );
+ * </code>
+ *
+ * @param array $prefixPaths
+ */
+ public static function addAdapterPrefixPaths(array $prefixPaths)
+ {
+ if (isset($prefixPaths['prefix']) && isset($prefixPaths['path'])) {
+ self::addAdapterPrefixPath($prefixPaths['prefix'], $prefixPaths['path']);
+ } else {
+ foreach ($prefixPaths as $prefix => $path) {
+ if (is_array($path) && isset($path['prefix']) && isset($path['path'])) {
+ $prefix = $path['prefix'];
+ $path = $path['path'];
+ }
+
+ self::addAdapterPrefixPath($prefix, $path);
+ }
+ }
+ }
+
+ /**
+ * Adds a scrolling style prefix path to the plugin loader.
+ *
+ * @param string $prefix
+ * @param string $path
+ */
+ public static function addScrollingStylePrefixPath($prefix, $path)
+ {
+ self::getScrollingStyleLoader()->addPrefixPath($prefix, $path);
+ }
+
+ /**
+ * Adds an array of scrolling style prefix paths to the plugin
+ * loader.
+ *
+ * <code>
+ * $prefixPaths = array(
+ * 'My_Paginator_ScrollingStyle' => 'My/Paginator/ScrollingStyle/',
+ * 'Your_Paginator_ScrollingStyle' => 'Your/Paginator/ScrollingStyle/'
+ * );
+ * </code>
+ *
+ * @param array $prefixPaths
+ */
+ public static function addScrollingStylePrefixPaths(array $prefixPaths)
+ {
+ if (isset($prefixPaths['prefix']) && isset($prefixPaths['path'])) {
+ self::addScrollingStylePrefixPath($prefixPaths['prefix'], $prefixPaths['path']);
+ } else {
+ foreach ($prefixPaths as $prefix => $path) {
+ if (is_array($path) && isset($path['prefix']) && isset($path['path'])) {
+ $prefix = $path['prefix'];
+ $path = $path['path'];
+ }
+
+ self::addScrollingStylePrefixPath($prefix, $path);
+ }
+ }
+ }
+
+ /**
+ * Factory.
+ *
+ * @param mixed $data
+ * @param string $adapter
+ * @param array $prefixPaths
+ * @return Zend_Paginator
+ */
+ public static function factory($data, $adapter = self::INTERNAL_ADAPTER,
+ array $prefixPaths = null)
+ {
+ if ($data instanceof Zend_Paginator_AdapterAggregate) {
+ return new self($data->getPaginatorAdapter());
+ } else {
+ if ($adapter == self::INTERNAL_ADAPTER) {
+ if (is_array($data)) {
+ $adapter = 'Array';
+ } else if ($data instanceof Zend_Db_Table_Select) {
+ $adapter = 'DbTableSelect';
+ } else if ($data instanceof Zend_Db_Select) {
+ $adapter = 'DbSelect';
+ } else if ($data instanceof Iterator) {
+ $adapter = 'Iterator';
+ } else if (is_integer($data)) {
+ $adapter = 'Null';
+ } else {
+ $type = (is_object($data)) ? get_class($data) : gettype($data);
+
+ /**
+ * @see Zend_Paginator_Exception
+ */
+ require_once 'Zend/Paginator/Exception.php';
+
+ throw new Zend_Paginator_Exception('No adapter for type ' . $type);
+ }
+ }
+
+ $pluginLoader = self::getAdapterLoader();
+
+ if (null !== $prefixPaths) {
+ foreach ($prefixPaths as $prefix => $path) {
+ $pluginLoader->addPrefixPath($prefix, $path);
+ }
+ }
+
+ $adapterClassName = $pluginLoader->load($adapter);
+
+ return new self(new $adapterClassName($data));
+ }
+ }
+
+ /**
+ * Returns the adapter loader. If it doesn't exist it's created.
+ *
+ * @return Zend_Loader_PluginLoader
+ */
+ public static function getAdapterLoader()
+ {
+ if (self::$_adapterLoader === null) {
+ self::$_adapterLoader = new Zend_Loader_PluginLoader(
+ array('Zend_Paginator_Adapter' => 'Zend/Paginator/Adapter')
+ );
+ }
+
+ return self::$_adapterLoader;
+ }
+
+ /**
+ * Set a global config
+ *
+ * @param Zend_Config $config
+ */
+ public static function setConfig(Zend_Config $config)
+ {
+ self::$_config = $config;
+
+ $adapterPaths = $config->get('adapterpaths');
+
+ if ($adapterPaths != null) {
+ self::addAdapterPrefixPaths($adapterPaths->adapterpath->toArray());
+ }
+
+ $prefixPaths = $config->get('prefixpaths');
+
+ if ($prefixPaths != null) {
+ self::addScrollingStylePrefixPaths($prefixPaths->prefixpath->toArray());
+ }
+
+ $scrollingStyle = $config->get('scrollingstyle');
+
+ if ($scrollingStyle != null) {
+ self::setDefaultScrollingStyle($scrollingStyle);
+ }
+ }
+
+ /**
+ * Returns the default scrolling style.
+ *
+ * @return string
+ */
+ public static function getDefaultScrollingStyle()
+ {
+ return self::$_defaultScrollingStyle;
+ }
+
+ /**
+ * Get the default item count per page
+ *
+ * @return int
+ */
+ public static function getDefaultItemCountPerPage()
+ {
+ return self::$_defaultItemCountPerPage;
+ }
+
+ /**
+ * Set the default item count per page
+ *
+ * @param int $count
+ */
+ public static function setDefaultItemCountPerPage($count)
+ {
+ self::$_defaultItemCountPerPage = (int) $count;
+ }
+
+ /**
+ * Sets a cache object
+ *
+ * @param Zend_Cache_Core $cache
+ */
+ public static function setCache(Zend_Cache_Core $cache)
+ {
+ self::$_cache = $cache;
+ }
+
+ /**
+ * Sets the default scrolling style.
+ *
+ * @param string $scrollingStyle
+ */
+ public static function setDefaultScrollingStyle($scrollingStyle = 'Sliding')
+ {
+ self::$_defaultScrollingStyle = $scrollingStyle;
+ }
+
+ /**
+ * Returns the scrolling style loader. If it doesn't exist it's
+ * created.
+ *
+ * @return Zend_Loader_PluginLoader
+ */
+ public static function getScrollingStyleLoader()
+ {
+ if (self::$_scrollingStyleLoader === null) {
+ self::$_scrollingStyleLoader = new Zend_Loader_PluginLoader(
+ array('Zend_Paginator_ScrollingStyle' => 'Zend/Paginator/ScrollingStyle')
+ );
+ }
+
+ return self::$_scrollingStyleLoader;
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param Zend_Paginator_Adapter_Interface|Zend_Paginator_AdapterAggregate $adapter
+ */
+ public function __construct($adapter)
+ {
+ if ($adapter instanceof Zend_Paginator_Adapter_Interface) {
+ $this->_adapter = $adapter;
+ } else if ($adapter instanceof Zend_Paginator_AdapterAggregate) {
+ $this->_adapter = $adapter->getPaginatorAdapter();
+ } else {
+ /**
+ * @see Zend_Paginator_Exception
+ */
+ require_once 'Zend/Paginator/Exception.php';
+
+ throw new Zend_Paginator_Exception(
+ 'Zend_Paginator only accepts instances of the type ' .
+ 'Zend_Paginator_Adapter_Interface or Zend_Paginator_AdapterAggregate.'
+ );
+ }
+
+ $config = self::$_config;
+
+ if ($config != null) {
+ $setupMethods = array('ItemCountPerPage', 'PageRange');
+
+ foreach ($setupMethods as $setupMethod) {
+ $value = $config->get(strtolower($setupMethod));
+
+ if ($value != null) {
+ $setupMethod = 'set' . $setupMethod;
+ $this->$setupMethod($value);
+ }
+ }
+ }
+ }
+
+ /**
+ * Serializes the object as a string. Proxies to {@link render()}.
+ *
+ * @return string
+ */
+ public function __toString()
+ {
+ try {
+ $return = $this->render();
+ return $return;
+ } catch (Exception $e) {
+ trigger_error($e->getMessage(), E_USER_WARNING);
+ }
+
+ return '';
+ }
+
+ /**
+ * Enables/Disables the cache for this instance
+ *
+ * @param bool $enable
+ * @return Zend_Paginator
+ */
+ public function setCacheEnabled($enable)
+ {
+ $this->_cacheEnabled = (bool)$enable;
+ return $this;
+ }
+
+ /**
+ * Returns the number of pages.
+ *
+ * @return integer
+ */
+ public function count()
+ {
+ if (!$this->_pageCount) {
+ $this->_pageCount = $this->_calculatePageCount();
+ }
+
+ return $this->_pageCount;
+ }
+
+ /**
+ * Returns the total number of items available.
+ *
+ * @return integer
+ */
+ public function getTotalItemCount()
+ {
+ return count($this->getAdapter());
+ }
+
+ /**
+ * Clear the page item cache.
+ *
+ * @param int $pageNumber
+ * @return Zend_Paginator
+ */
+ public function clearPageItemCache($pageNumber = null)
+ {
+ if (!$this->_cacheEnabled()) {
+ return $this;
+ }
+
+ if (null === $pageNumber) {
+ $cleanTags = self::CACHE_TAG_PREFIX;
+ foreach (self::$_cache->getIdsMatchingTags(array($this->_getCacheInternalId())) as $id) {
+ if (preg_match('|'.self::CACHE_TAG_PREFIX."(\d+)_.*|", $id, $page)) {
+ self::$_cache->remove($this->_getCacheId($page[1]));
+ }
+ }
+ } else {
+ $cleanId = $this->_getCacheId($pageNumber);
+ self::$_cache->remove($cleanId);
+ }
+ return $this;
+ }
+
+ /**
+ * Returns the absolute item number for the specified item.
+ *
+ * @param integer $relativeItemNumber Relative item number
+ * @param integer $pageNumber Page number
+ * @return integer
+ */
+ public function getAbsoluteItemNumber($relativeItemNumber, $pageNumber = null)
+ {
+ $relativeItemNumber = $this->normalizeItemNumber($relativeItemNumber);
+
+ if ($pageNumber == null) {
+ $pageNumber = $this->getCurrentPageNumber();
+ }
+
+ $pageNumber = $this->normalizePageNumber($pageNumber);
+
+ return (($pageNumber - 1) * $this->getItemCountPerPage()) + $relativeItemNumber;
+ }
+
+ /**
+ * Returns the adapter.
+ *
+ * @return Zend_Paginator_Adapter_Interface
+ */
+ public function getAdapter()
+ {
+ return $this->_adapter;
+ }
+
+ /**
+ * Returns the number of items for the current page.
+ *
+ * @return integer
+ */
+ public function getCurrentItemCount()
+ {
+ if ($this->_currentItemCount === null) {
+ $this->_currentItemCount = $this->getItemCount($this->getCurrentItems());
+ }
+
+ return $this->_currentItemCount;
+ }
+
+ /**
+ * Returns the items for the current page.
+ *
+ * @return Traversable
+ */
+ public function getCurrentItems()
+ {
+ if ($this->_currentItems === null) {
+ $this->_currentItems = $this->getItemsByPage($this->getCurrentPageNumber());
+ }
+
+ return $this->_currentItems;
+ }
+
+ /**
+ * Returns the current page number.
+ *
+ * @return integer
+ */
+ public function getCurrentPageNumber()
+ {
+ return $this->normalizePageNumber($this->_currentPageNumber);
+ }
+
+ /**
+ * Sets the current page number.
+ *
+ * @param integer $pageNumber Page number
+ * @return Zend_Paginator $this
+ */
+ public function setCurrentPageNumber($pageNumber)
+ {
+ $this->_currentPageNumber = (integer) $pageNumber;
+ $this->_currentItems = null;
+ $this->_currentItemCount = null;
+
+ return $this;
+ }
+
+ /**
+ * Get the filter
+ *
+ * @return Zend_Filter_Interface
+ */
+ public function getFilter()
+ {
+ return $this->_filter;
+ }
+
+ /**
+ * Set a filter chain
+ *
+ * @param Zend_Filter_Interface $filter
+ * @return Zend_Paginator
+ */
+ public function setFilter(Zend_Filter_Interface $filter)
+ {
+ $this->_filter = $filter;
+
+ return $this;
+ }
+
+ /**
+ * Returns an item from a page. The current page is used if there's no
+ * page sepcified.
+ *
+ * @param integer $itemNumber Item number (1 to itemCountPerPage)
+ * @param integer $pageNumber
+ * @return mixed
+ */
+ public function getItem($itemNumber, $pageNumber = null)
+ {
+ $itemNumber = $this->normalizeItemNumber($itemNumber);
+
+ if ($pageNumber == null) {
+ $pageNumber = $this->getCurrentPageNumber();
+ }
+
+ $page = $this->getItemsByPage($pageNumber);
+ $itemCount = $this->getItemCount($page);
+
+ if ($itemCount == 0) {
+ /**
+ * @see Zend_Paginator_Exception
+ */
+ require_once 'Zend/Paginator/Exception.php';
+
+ throw new Zend_Paginator_Exception('Page ' . $pageNumber . ' does not exist');
+ }
+
+ if ($itemNumber > $itemCount) {
+ /**
+ * @see Zend_Paginator_Exception
+ */
+ require_once 'Zend/Paginator/Exception.php';
+
+ throw new Zend_Paginator_Exception('Page ' . $pageNumber . ' does not'
+ . ' contain item number ' . $itemNumber);
+ }
+
+ return $page[$itemNumber - 1];
+ }
+
+ /**
+ * Returns the number of items per page.
+ *
+ * @return integer
+ */
+ public function getItemCountPerPage()
+ {
+ if (empty($this->_itemCountPerPage)) {
+ $this->_itemCountPerPage = self::getDefaultItemCountPerPage();
+ }
+
+ return $this->_itemCountPerPage;
+ }
+
+ /**
+ * Sets the number of items per page.
+ *
+ * @param integer $itemCountPerPage
+ * @return Zend_Paginator $this
+ */
+ public function setItemCountPerPage($itemCountPerPage)
+ {
+ $this->_itemCountPerPage = (integer) $itemCountPerPage;
+ if ($this->_itemCountPerPage < 1) {
+ $this->_itemCountPerPage = $this->getItemCountPerPage();
+ }
+ $this->_pageCount = $this->_calculatePageCount();
+ $this->_currentItems = null;
+ $this->_currentItemCount = null;
+
+ return $this;
+ }
+
+ /**
+ * Returns the number of items in a collection.
+ *
+ * @param mixed $items Items
+ * @return integer
+ */
+ public function getItemCount($items)
+ {
+ $itemCount = 0;
+
+ if (is_array($items) || $items instanceof Countable) {
+ $itemCount = count($items);
+ } else { // $items is something like LimitIterator
+ $itemCount = iterator_count($items);
+ }
+
+ return $itemCount;
+ }
+
+ /**
+ * Returns the items for a given page.
+ *
+ * @return Traversable
+ */
+ public function getItemsByPage($pageNumber)
+ {
+ $pageNumber = $this->normalizePageNumber($pageNumber);
+
+ if ($this->_cacheEnabled()) {
+ $data = self::$_cache->load($this->_getCacheId($pageNumber));
+ if ($data !== false) {
+ return $data;
+ }
+ }
+
+ $offset = ($pageNumber - 1) * $this->getItemCountPerPage();
+
+ $items = $this->_adapter->getItems($offset, $this->getItemCountPerPage());
+
+ $filter = $this->getFilter();
+
+ if ($filter !== null) {
+ $items = $filter->filter($items);
+ }
+
+ if (!$items instanceof Traversable) {
+ $items = new ArrayIterator($items);
+ }
+
+ if ($this->_cacheEnabled()) {
+ self::$_cache->save($items, $this->_getCacheId($pageNumber), array($this->_getCacheInternalId()));
+ }
+
+ return $items;
+ }
+
+ /**
+ * Returns a foreach-compatible iterator.
+ *
+ * @return Traversable
+ */
+ public function getIterator()
+ {
+ return $this->getCurrentItems();
+ }
+
+ /**
+ * Returns the page range (see property declaration above).
+ *
+ * @return integer
+ */
+ public function getPageRange()
+ {
+ return $this->_pageRange;
+ }
+
+ /**
+ * Sets the page range (see property declaration above).
+ *
+ * @param integer $pageRange
+ * @return Zend_Paginator $this
+ */
+ public function setPageRange($pageRange)
+ {
+ $this->_pageRange = (integer) $pageRange;
+
+ return $this;
+ }
+
+ /**
+ * Returns the page collection.
+ *
+ * @param string $scrollingStyle Scrolling style
+ * @return array
+ */
+ public function getPages($scrollingStyle = null)
+ {
+ if ($this->_pages === null) {
+ $this->_pages = $this->_createPages($scrollingStyle);
+ }
+
+ return $this->_pages;
+ }
+
+ /**
+ * Returns a subset of pages within a given range.
+ *
+ * @param integer $lowerBound Lower bound of the range
+ * @param integer $upperBound Upper bound of the range
+ * @return array
+ */
+ public function getPagesInRange($lowerBound, $upperBound)
+ {
+ $lowerBound = $this->normalizePageNumber($lowerBound);
+ $upperBound = $this->normalizePageNumber($upperBound);
+
+ $pages = array();
+
+ for ($pageNumber = $lowerBound; $pageNumber <= $upperBound; $pageNumber++) {
+ $pages[$pageNumber] = $pageNumber;
+ }
+
+ return $pages;
+ }
+
+ /**
+ * Returns the page item cache.
+ *
+ * @return array
+ */
+ public function getPageItemCache()
+ {
+ $data = array();
+ if ($this->_cacheEnabled()) {
+ foreach (self::$_cache->getIdsMatchingTags(array($this->_getCacheInternalId())) as $id) {
+ if (preg_match('|'.self::CACHE_TAG_PREFIX."(\d+)_.*|", $id, $page)) {
+ $data[$page[1]] = self::$_cache->load($this->_getCacheId($page[1]));
+ }
+ }
+ }
+ return $data;
+ }
+
+ /**
+ * Retrieves the view instance. If none registered, attempts to pull f
+ * rom ViewRenderer.
+ *
+ * @return Zend_View_Interface|null
+ */
+ public function getView()
+ {
+ if ($this->_view === null) {
+ /**
+ * @see Zend_Controller_Action_HelperBroker
+ */
+ require_once 'Zend/Controller/Action/HelperBroker.php';
+
+ $viewRenderer = Zend_Controller_Action_HelperBroker::getStaticHelper('viewRenderer');
+ if ($viewRenderer->view === null) {
+ $viewRenderer->initView();
+ }
+ $this->_view = $viewRenderer->view;
+ }
+
+ return $this->_view;
+ }
+
+ /**
+ * Sets the view object.
+ *
+ * @param Zend_View_Interface $view
+ * @return Zend_Paginator
+ */
+ public function setView(Zend_View_Interface $view = null)
+ {
+ $this->_view = $view;
+
+ return $this;
+ }
+
+ /**
+ * Brings the item number in range of the page.
+ *
+ * @param integer $itemNumber
+ * @return integer
+ */
+ public function normalizeItemNumber($itemNumber)
+ {
+ if ($itemNumber < 1) {
+ $itemNumber = 1;
+ }
+
+ if ($itemNumber > $this->getItemCountPerPage()) {
+ $itemNumber = $this->getItemCountPerPage();
+ }
+
+ return $itemNumber;
+ }
+
+ /**
+ * Brings the page number in range of the paginator.
+ *
+ * @param integer $pageNumber
+ * @return integer
+ */
+ public function normalizePageNumber($pageNumber)
+ {
+ if ($pageNumber < 1) {
+ $pageNumber = 1;
+ }
+
+ $pageCount = $this->count();
+
+ if ($pageCount > 0 && $pageNumber > $pageCount) {
+ $pageNumber = $pageCount;
+ }
+
+ return $pageNumber;
+ }
+
+ /**
+ * Renders the paginator.
+ *
+ * @param Zend_View_Interface $view
+ * @return string
+ */
+ public function render(Zend_View_Interface $view = null)
+ {
+ if (null !== $view) {
+ $this->setView($view);
+ }
+
+ $view = $this->getView();
+
+ return $view->paginationControl($this);
+ }
+
+ /**
+ * Returns the items of the current page as JSON.
+ *
+ * @return string
+ */
+ public function toJson()
+ {
+ $currentItems = $this->getCurrentItems();
+
+ if ($currentItems instanceof Zend_Db_Table_Rowset_Abstract) {
+ return Zend_Json::encode($currentItems->toArray());
+ } else {
+ return Zend_Json::encode($currentItems);
+ }
+ }
+
+ /**
+ * Tells if there is an active cache object
+ * and if the cache has not been desabled
+ *
+ * @return bool
+ */
+ protected function _cacheEnabled()
+ {
+ return ((self::$_cache !== null) && $this->_cacheEnabled);
+ }
+
+ /**
+ * Makes an Id for the cache
+ * Depends on the adapter object and the page number
+ *
+ * Used to store item in cache from that Paginator instance
+ * and that current page
+ *
+ * @param int $page
+ * @return string
+ */
+ protected function _getCacheId($page = null)
+ {
+ if ($page === null) {
+ $page = $this->getCurrentPageNumber();
+ }
+ return self::CACHE_TAG_PREFIX . $page . '_' . $this->_getCacheInternalId();
+ }
+
+ /**
+ * Get the internal cache id
+ * Depends on the adapter and the item count per page
+ *
+ * Used to tag that unique Paginator instance in cache
+ *
+ * @return string
+ */
+ protected function _getCacheInternalId()
+ {
+ return md5(serialize($this->getAdapter()) . $this->getItemCountPerPage());
+ }
+
+ /**
+ * Calculates the page count.
+ *
+ * @return integer
+ */
+ protected function _calculatePageCount()
+ {
+ return (integer) ceil($this->getAdapter()->count() / $this->getItemCountPerPage());
+ }
+
+ /**
+ * Creates the page collection.
+ *
+ * @param string $scrollingStyle Scrolling style
+ * @return stdClass
+ */
+ protected function _createPages($scrollingStyle = null)
+ {
+ $pageCount = $this->count();
+ $currentPageNumber = $this->getCurrentPageNumber();
+
+ $pages = new stdClass();
+ $pages->pageCount = $pageCount;
+ $pages->itemCountPerPage = $this->getItemCountPerPage();
+ $pages->first = 1;
+ $pages->current = $currentPageNumber;
+ $pages->last = $pageCount;
+
+ // Previous and next
+ if ($currentPageNumber - 1 > 0) {
+ $pages->previous = $currentPageNumber - 1;
+ }
+
+ if ($currentPageNumber + 1 <= $pageCount) {
+ $pages->next = $currentPageNumber + 1;
+ }
+
+ // Pages in range
+ $scrollingStyle = $this->_loadScrollingStyle($scrollingStyle);
+ $pages->pagesInRange = $scrollingStyle->getPages($this);
+ $pages->firstPageInRange = min($pages->pagesInRange);
+ $pages->lastPageInRange = max($pages->pagesInRange);
+
+ // Item numbers
+ if ($this->getCurrentItems() !== null) {
+ $pages->currentItemCount = $this->getCurrentItemCount();
+ $pages->itemCountPerPage = $this->getItemCountPerPage();
+ $pages->totalItemCount = $this->getTotalItemCount();
+ $pages->firstItemNumber = (($currentPageNumber - 1) * $this->getItemCountPerPage()) + 1;
+ $pages->lastItemNumber = $pages->firstItemNumber + $pages->currentItemCount - 1;
+ }
+
+ return $pages;
+ }
+
+ /**
+ * Loads a scrolling style.
+ *
+ * @param string $scrollingStyle
+ * @return Zend_Paginator_ScrollingStyle_Interface
+ */
+ protected function _loadScrollingStyle($scrollingStyle = null)
+ {
+ if ($scrollingStyle === null) {
+ $scrollingStyle = self::$_defaultScrollingStyle;
+ }
+
+ switch (strtolower(gettype($scrollingStyle))) {
+ case 'object':
+ if (!$scrollingStyle instanceof Zend_Paginator_ScrollingStyle_Interface) {
+ /**
+ * @see Zend_View_Exception
+ */
+ require_once 'Zend/View/Exception.php';
+
+ throw new Zend_View_Exception('Scrolling style must implement ' .
+ 'Zend_Paginator_ScrollingStyle_Interface');
+ }
+
+ return $scrollingStyle;
+
+ case 'string':
+ $className = self::getScrollingStyleLoader()->load($scrollingStyle);
+
+ return new $className();
+
+ case 'null':
+ // Fall through to default case
+
+ default:
+ /**
+ * @see Zend_View_Exception
+ */
+ require_once 'Zend/View/Exception.php';
+
+ throw new Zend_View_Exception('Scrolling style must be a class ' .
+ 'name or object implementing Zend_Paginator_ScrollingStyle_Interface');
+ }
+ }
+}
--- /dev/null
+<?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_Pdf
+ * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ * @version $Id$
+ */
+
+/** Zend_Pdf_Page */
+require_once 'Zend/Pdf/Page.php';
+
+/** Zend_Pdf_Cmap */
+require_once 'Zend/Pdf/Cmap.php';
+
+/** Zend_Pdf_Font */
+require_once 'Zend/Pdf/Font.php';
+
+/** Zend_Pdf_Style */
+require_once 'Zend/Pdf/Style.php';
+
+/** Zend_Pdf_Parser */
+require_once 'Zend/Pdf/Parser.php';
+
+/** Zend_Pdf_Trailer */
+require_once 'Zend/Pdf/Trailer.php';
+
+/** Zend_Pdf_Trailer_Generator */
+require_once 'Zend/Pdf/Trailer/Generator.php';
+
+/** Zend_Pdf_Color */
+require_once 'Zend/Pdf/Color.php';
+
+/** Zend_Pdf_Color_GrayScale */
+require_once 'Zend/Pdf/Color/GrayScale.php';
+
+/** Zend_Pdf_Color_Rgb */
+require_once 'Zend/Pdf/Color/Rgb.php';
+
+/** Zend_Pdf_Color_Cmyk */
+require_once 'Zend/Pdf/Color/Cmyk.php';
+
+/** Zend_Pdf_Color_Html */
+require_once 'Zend/Pdf/Color/Html.php';
+
+/** Zend_Pdf_Image */
+require_once 'Zend/Pdf/Resource/Image.php';
+
+/** Zend_Pdf_Image */
+require_once 'Zend/Pdf/Image.php';
+
+/** Zend_Pdf_Image_Jpeg */
+require_once 'Zend/Pdf/Resource/Image/Jpeg.php';
+
+/** Zend_Pdf_Image_Tiff */
+require_once 'Zend/Pdf/Resource/Image/Tiff.php';
+
+/** Zend_Pdf_Image_Png */
+require_once 'Zend/Pdf/Resource/Image/Png.php';
+
+/** Zend_Memory */
+require_once 'Zend/Memory.php';
+
+/** Zend_Pdf_Action */
+require_once 'Zend/Pdf/Action.php';
+
+/** Zend_Pdf_Destination */
+require_once 'Zend/Pdf/Destination.php';
+
+/** Zend_Pdf_Destination_Explicit */
+require_once 'Zend/Pdf/Destination/Explicit.php';
+
+/** Zend_Pdf_Destination_Named */
+require_once 'Zend/Pdf/Destination/Named.php';
+
+/** Zend_Pdf_Outline_Created */
+require_once 'Zend/Pdf/Outline/Created.php';
+
+/** Zend_Pdf_Outline_Loaded */
+require_once 'Zend/Pdf/Outline/Loaded.php';
+
+/** Zend_Pdf_RecursivelyIteratableObjectsContainer */
+require_once 'Zend/Pdf/RecursivelyIteratableObjectsContainer.php';
+
+/** Zend_Pdf_NameTree */
+require_once 'Zend/Pdf/NameTree.php';
+
+/** Zend_Pdf_Destination */
+require_once 'Zend/Pdf/Exception.php';
+
+/**
+ * General entity which describes PDF document.
+ * It implements document abstraction with a document level operations.
+ *
+ * Class is used to create new PDF document or load existing document.
+ * See details in a class constructor description
+ *
+ * Class agregates document level properties and entities (pages, bookmarks,
+ * document level actions, attachments, form object, etc)
+ *
+ * @category Zend
+ * @package Zend_Pdf
+ * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+class Zend_Pdf
+{
+ /**** Class Constants ****/
+
+ /**
+ * Version number of generated PDF documents.
+ */
+ const PDF_VERSION = '1.4';
+
+ /**
+ * PDF file header.
+ */
+ const PDF_HEADER = "%PDF-1.4\n%\xE2\xE3\xCF\xD3\n";
+
+
+
+ /**
+ * Pages collection
+ *
+ * @todo implement it as a class, which supports ArrayAccess and Iterator interfaces,
+ * to provide incremental parsing and pages tree updating.
+ * That will give good performance and memory (PDF size) benefits.
+ *
+ * @var array - array of Zend_Pdf_Page object
+ */
+ public $pages = array();
+
+ /**
+ * Document properties
+ *
+ * It's an associative array with PDF meta information, values may
+ * be string, boolean or float.
+ * Returned array could be used directly to access, add, modify or remove
+ * document properties.
+ *
+ * Standard document properties: Title (must be set for PDF/X documents), Author,
+ * Subject, Keywords (comma separated list), Creator (the name of the application,
+ * that created document, if it was converted from other format), Trapped (must be
+ * true, false or null, can not be null for PDF/X documents)
+ *
+ * @var array
+ */
+ public $properties = array();
+
+ /**
+ * Original properties set.
+ *
+ * Used for tracking properties changes
+ *
+ * @var array
+ */
+ protected $_originalProperties = array();
+
+ /**
+ * Document level javascript
+ *
+ * @var string
+ */
+ protected $_javaScript = null;
+
+ /**
+ * Document named destinations or "GoTo..." actions, used to refer
+ * document parts from outside PDF
+ *
+ * @var array - array of Zend_Pdf_Target objects
+ */
+ protected $_namedTargets = array();
+
+ /**
+ * Document outlines
+ *
+ * @var array - array of Zend_Pdf_Outline objects
+ */
+ public $outlines = array();
+
+ /**
+ * Original document outlines list
+ * Used to track outlines update
+ *
+ * @var array - array of Zend_Pdf_Outline objects
+ */
+ protected $_originalOutlines = array();
+
+ /**
+ * Original document outlines open elements count
+ * Used to track outlines update
+ *
+ * @var integer
+ */
+ protected $_originalOpenOutlinesCount = 0;
+
+ /**
+ * Pdf trailer (last or just created)
+ *
+ * @var Zend_Pdf_Trailer
+ */
+ protected $_trailer = null;
+
+ /**
+ * PDF objects factory.
+ *
+ * @var Zend_Pdf_ElementFactory_Interface
+ */
+ protected $_objFactory = null;
+
+ /**
+ * Memory manager for stream objects
+ *
+ * @var Zend_Memory_Manager|null
+ */
+ protected static $_memoryManager = null;
+
+ /**
+ * Pdf file parser.
+ * It's not used, but has to be destroyed only with Zend_Pdf object
+ *
+ * @var Zend_Pdf_Parser
+ */
+ protected $_parser;
+
+
+ /**
+ * List of inheritable attributesfor pages tree
+ *
+ * @var array
+ */
+ protected static $_inheritableAttributes = array('Resources', 'MediaBox', 'CropBox', 'Rotate');
+
+ /**
+ * Request used memory manager
+ *
+ * @return Zend_Memory_Manager
+ */
+ static public function getMemoryManager()
+ {
+ if (self::$_memoryManager === null) {
+ self::$_memoryManager = Zend_Memory::factory('none');
+ }
+
+ return self::$_memoryManager;
+ }
+
+ /**
+ * Set user defined memory manager
+ *
+ * @param Zend_Memory_Manager $memoryManager
+ */
+ static public function setMemoryManager(Zend_Memory_Manager $memoryManager)
+ {
+ self::$_memoryManager = $memoryManager;
+ }
+
+
+ /**
+ * Create new PDF document from a $source string
+ *
+ * @param string $source
+ * @param integer $revision
+ * @return Zend_Pdf
+ */
+ public static function parse(&$source = null, $revision = null)
+ {
+ return new Zend_Pdf($source, $revision);
+ }
+
+ /**
+ * Load PDF document from a file
+ *
+ * @param string $source
+ * @param integer $revision
+ * @return Zend_Pdf
+ */
+ public static function load($source = null, $revision = null)
+ {
+ return new Zend_Pdf($source, $revision, true);
+ }
+
+ /**
+ * Render PDF document and save it.
+ *
+ * If $updateOnly is true, then it only appends new section to the end of file.
+ *
+ * @param string $filename
+ * @param boolean $updateOnly
+ * @throws Zend_Pdf_Exception
+ */
+ public function save($filename, $updateOnly = false)
+ {
+ if (($file = @fopen($filename, $updateOnly ? 'ab':'wb')) === false ) {
+ require_once 'Zend/Pdf/Exception.php';
+ throw new Zend_Pdf_Exception( "Can not open '$filename' file for writing." );
+ }
+
+ $this->render($updateOnly, $file);
+
+ fclose($file);
+ }
+
+ /**
+ * Creates or loads PDF document.
+ *
+ * If $source is null, then it creates a new document.
+ *
+ * If $source is a string and $load is false, then it loads document
+ * from a binary string.
+ *
+ * If $source is a string and $load is true, then it loads document
+ * from a file.
+
+ * $revision used to roll back document to specified version
+ * (0 - currtent version, 1 - previous version, 2 - ...)
+ *
+ * @param string $source - PDF file to load
+ * @param integer $revision
+ * @throws Zend_Pdf_Exception
+ * @return Zend_Pdf
+ */
+ public function __construct($source = null, $revision = null, $load = false)
+ {
+ $this->_objFactory = Zend_Pdf_ElementFactory::createFactory(1);
+
+ if ($source !== null) {
+ $this->_parser = new Zend_Pdf_Parser($source, $this->_objFactory, $load);
+ $this->_pdfHeaderVersion = $this->_parser->getPDFVersion();
+ $this->_trailer = $this->_parser->getTrailer();
+ if ($this->_trailer->Encrypt !== null) {
+ require_once 'Zend/Pdf/Exception.php';
+ throw new Zend_Pdf_Exception('Encrypted document modification is not supported');
+ }
+ if ($revision !== null) {
+ $this->rollback($revision);
+ } else {
+ $this->_loadPages($this->_trailer->Root->Pages);
+ }
+
+ $this->_loadNamedDestinations($this->_trailer->Root, $this->_parser->getPDFVersion());
+ $this->_loadOutlines($this->_trailer->Root);
+
+ if ($this->_trailer->Info !== null) {
+ $this->properties = $this->_trailer->Info->toPhp();
+
+ if (isset($this->properties['Trapped'])) {
+ switch ($this->properties['Trapped']) {
+ case 'True':
+ $this->properties['Trapped'] = true;
+ break;
+
+ case 'False':
+ $this->properties['Trapped'] = false;
+ break;
+
+ case 'Unknown':
+ $this->properties['Trapped'] = null;
+ break;
+
+ default:
+ // Wrong property value
+ // Do nothing
+ break;
+ }
+ }
+
+ $this->_originalProperties = $this->properties;
+ }
+ } else {
+ $this->_pdfHeaderVersion = Zend_Pdf::PDF_VERSION;
+
+ $trailerDictionary = new Zend_Pdf_Element_Dictionary();
+
+ /**
+ * Document id
+ */
+ $docId = md5(uniqid(rand(), true)); // 32 byte (128 bit) identifier
+ $docIdLow = substr($docId, 0, 16); // first 16 bytes
+ $docIdHigh = substr($docId, 16, 16); // second 16 bytes
+
+ $trailerDictionary->ID = new Zend_Pdf_Element_Array();
+ $trailerDictionary->ID->items[] = new Zend_Pdf_Element_String_Binary($docIdLow);
+ $trailerDictionary->ID->items[] = new Zend_Pdf_Element_String_Binary($docIdHigh);
+
+ $trailerDictionary->Size = new Zend_Pdf_Element_Numeric(0);
+
+ $this->_trailer = new Zend_Pdf_Trailer_Generator($trailerDictionary);
+
+ /**
+ * Document catalog indirect object.
+ */
+ $docCatalog = $this->_objFactory->newObject(new Zend_Pdf_Element_Dictionary());
+ $docCatalog->Type = new Zend_Pdf_Element_Name('Catalog');
+ $docCatalog->Version = new Zend_Pdf_Element_Name(Zend_Pdf::PDF_VERSION);
+ $this->_trailer->Root = $docCatalog;
+
+ /**
+ * Pages container
+ */
+ $docPages = $this->_objFactory->newObject(new Zend_Pdf_Element_Dictionary());
+ $docPages->Type = new Zend_Pdf_Element_Name('Pages');
+ $docPages->Kids = new Zend_Pdf_Element_Array();
+ $docPages->Count = new Zend_Pdf_Element_Numeric(0);
+ $docCatalog->Pages = $docPages;
+ }
+ }
+
+ /**
+ * Retrive number of revisions.
+ *
+ * @return integer
+ */
+ public function revisions()
+ {
+ $revisions = 1;
+ $currentTrailer = $this->_trailer;
+
+ while ($currentTrailer->getPrev() !== null && $currentTrailer->getPrev()->Root !== null ) {
+ $revisions++;
+ $currentTrailer = $currentTrailer->getPrev();
+ }
+
+ return $revisions++;
+ }
+
+ /**
+ * Rollback document $steps number of revisions.
+ * This method must be invoked before any changes, applied to the document.
+ * Otherwise behavior is undefined.
+ *
+ * @param integer $steps
+ */
+ public function rollback($steps)
+ {
+ for ($count = 0; $count < $steps; $count++) {
+ if ($this->_trailer->getPrev() !== null && $this->_trailer->getPrev()->Root !== null) {
+ $this->_trailer = $this->_trailer->getPrev();
+ } else {
+ break;
+ }
+ }
+ $this->_objFactory->setObjectCount($this->_trailer->Size->value);
+
+ // Mark content as modified to force new trailer generation at render time
+ $this->_trailer->Root->touch();
+
+ $this->pages = array();
+ $this->_loadPages($this->_trailer->Root->Pages);
+ }
+
+
+ /**
+ * Load pages recursively
+ *
+ * @param Zend_Pdf_Element_Reference $pages
+ * @param array|null $attributes
+ */
+ protected function _loadPages(Zend_Pdf_Element_Reference $pages, $attributes = array())
+ {
+ if ($pages->getType() != Zend_Pdf_Element::TYPE_DICTIONARY) {
+ require_once 'Zend/Pdf/Exception.php';
+ throw new Zend_Pdf_Exception('Wrong argument');
+ }
+
+ foreach ($pages->getKeys() as $property) {
+ if (in_array($property, self::$_inheritableAttributes)) {
+ $attributes[$property] = $pages->$property;
+ $pages->$property = null;
+ }
+ }
+
+
+ foreach ($pages->Kids->items as $child) {
+ if ($child->Type->value == 'Pages') {
+ $this->_loadPages($child, $attributes);
+ } else if ($child->Type->value == 'Page') {
+ foreach (self::$_inheritableAttributes as $property) {
+ if ($child->$property === null && array_key_exists($property, $attributes)) {
+ /**
+ * Important note.
+ * If any attribute or dependant object is an indirect object, then it's still
+ * shared between pages.
+ */
+ if ($attributes[$property] instanceof Zend_Pdf_Element_Object ||
+ $attributes[$property] instanceof Zend_Pdf_Element_Reference) {
+ $child->$property = $attributes[$property];
+ } else {
+ $child->$property = $this->_objFactory->newObject($attributes[$property]);
+ }
+ }
+ }
+ $this->pages[] = new Zend_Pdf_Page($child, $this->_objFactory);
+ }
+ }
+ }
+
+ /**
+ * Load named destinations recursively
+ *
+ * @param Zend_Pdf_Element_Reference $root Document catalog entry
+ * @param string $pdfHeaderVersion
+ * @throws Zend_Pdf_Exception
+ */
+ protected function _loadNamedDestinations(Zend_Pdf_Element_Reference $root, $pdfHeaderVersion)
+ {
+ if ($root->Version !== null && version_compare($root->Version->value, $pdfHeaderVersion, '>')) {
+ $versionIs_1_2_plus = version_compare($root->Version->value, '1.1', '>');
+ } else {
+ $versionIs_1_2_plus = version_compare($pdfHeaderVersion, '1.1', '>');
+ }
+
+ if ($versionIs_1_2_plus) {
+ // PDF version is 1.2+
+ // Look for Destinations structure at Name dictionary
+ if ($root->Names !== null && $root->Names->Dests !== null) {
+ foreach (new Zend_Pdf_NameTree($root->Names->Dests) as $name => $destination) {
+ $this->_namedTargets[$name] = Zend_Pdf_Target::load($destination);
+ }
+ }
+ } else {
+ // PDF version is 1.1 (or earlier)
+ // Look for Destinations sructure at Dest entry of document catalog
+ if ($root->Dests !== null) {
+ if ($root->Dests->getType() != Zend_Pdf_Element::TYPE_DICTIONARY) {
+ require_once 'Zend/Pdf/Exception.php';
+ throw new Zend_Pdf_Exception('Document catalog Dests entry must be a dictionary.');
+ }
+
+ foreach ($root->Dests->getKeys() as $destKey) {
+ $this->_namedTargets[$destKey] = Zend_Pdf_Target::load($root->Dests->$destKey);
+ }
+ }
+ }
+ }
+
+ /**
+ * Load outlines recursively
+ *
+ * @param Zend_Pdf_Element_Reference $root Document catalog entry
+ */
+ protected function _loadOutlines(Zend_Pdf_Element_Reference $root)
+ {
+ if ($root->Outlines === null) {
+ return;
+ }
+
+ if ($root->Outlines->getType() != Zend_Pdf_Element::TYPE_DICTIONARY) {
+ require_once 'Zend/Pdf/Exception.php';
+ throw new Zend_Pdf_Exception('Document catalog Outlines entry must be a dictionary.');
+ }
+
+ if ($root->Outlines->Type !== null && $root->Outlines->Type->value != 'Outlines') {
+ require_once 'Zend/Pdf/Exception.php';
+ throw new Zend_Pdf_Exception('Outlines Type entry must be an \'Outlines\' string.');
+ }
+
+ if ($root->Outlines->First === null) {
+ return;
+ }
+
+ $outlineDictionary = $root->Outlines->First;
+ $processedDictionaries = new SplObjectStorage();
+ while ($outlineDictionary !== null && !$processedDictionaries->contains($outlineDictionary)) {
+ $processedDictionaries->attach($outlineDictionary);
+
+ $this->outlines[] = new Zend_Pdf_Outline_Loaded($outlineDictionary);
+
+ $outlineDictionary = $outlineDictionary->Next;
+ }
+
+ $this->_originalOutlines = $this->outlines;
+
+ if ($root->Outlines->Count !== null) {
+ $this->_originalOpenOutlinesCount = $root->Outlines->Count->value;
+ }
+ }
+
+ /**
+ * Orginize pages to tha pages tree structure.
+ *
+ * @todo atomatically attach page to the document, if it's not done yet.
+ * @todo check, that page is attached to the current document
+ *
+ * @todo Dump pages as a balanced tree instead of a plain set.
+ */
+ protected function _dumpPages()
+ {
+ $root = $this->_trailer->Root;
+ $pagesContainer = $root->Pages;
+
+ $pagesContainer->touch();
+ $pagesContainer->Kids->items = array();
+
+ foreach ($this->pages as $page ) {
+ $page->render($this->_objFactory);
+
+ $pageDictionary = $page->getPageDictionary();
+ $pageDictionary->touch();
+ $pageDictionary->Parent = $pagesContainer;
+
+ $pagesContainer->Kids->items[] = $pageDictionary;
+ }
+
+ $this->_refreshPagesHash();
+
+ $pagesContainer->Count->touch();
+ $pagesContainer->Count->value = count($this->pages);
+
+
+ // Refresh named destinations list
+ foreach ($this->_namedTargets as $name => $namedTarget) {
+ if ($namedTarget instanceof Zend_Pdf_Destination_Explicit) {
+ // Named target is an explicit destination
+ if ($this->resolveDestination($namedTarget, false) === null) {
+ unset($this->_namedTargets[$name]);
+ }
+ } else if ($namedTarget instanceof Zend_Pdf_Action) {
+ // Named target is an action
+ if ($this->_cleanUpAction($namedTarget, false) === null) {
+ // Action is a GoTo action with an unresolved destination
+ unset($this->_namedTargets[$name]);
+ }
+ } else {
+ require_once 'Zend/Pdf/Exception.php';
+ throw new Zend_Pdf_Exception('Wrong type of named targed (\'' . get_class($namedTarget) . '\').');
+ }
+ }
+
+ // Refresh outlines
+ $iterator = new RecursiveIteratorIterator(new Zend_Pdf_RecursivelyIteratableObjectsContainer($this->outlines), RecursiveIteratorIterator::SELF_FIRST);
+ foreach ($iterator as $outline) {
+ $target = $outline->getTarget();
+
+ if ($target !== null) {
+ if ($target instanceof Zend_Pdf_Destination) {
+ // Outline target is a destination
+ if ($this->resolveDestination($target, false) === null) {
+ $outline->setTarget(null);
+ }
+ } else if ($target instanceof Zend_Pdf_Action) {
+ // Outline target is an action
+ if ($this->_cleanUpAction($target, false) === null) {
+ // Action is a GoTo action with an unresolved destination
+ $outline->setTarget(null);
+ }
+ } else {
+ require_once 'Zend/Pdf/Exception.php';
+ throw new Zend_Pdf_Exception('Wrong outline target.');
+ }
+ }
+ }
+
+ $openAction = $this->getOpenAction();
+ if ($openAction !== null) {
+ if ($openAction instanceof Zend_Pdf_Action) {
+ // OpenAction is an action
+ if ($this->_cleanUpAction($openAction, false) === null) {
+ // Action is a GoTo action with an unresolved destination
+ $this->setOpenAction(null);
+ }
+ } else if ($openAction instanceof Zend_Pdf_Destination) {
+ // OpenAction target is a destination
+ if ($this->resolveDestination($openAction, false) === null) {
+ $this->setOpenAction(null);
+ }
+ } else {
+ require_once 'Zend/Pdf/Exception.php';
+ throw new Zend_Pdf_Exception('OpenAction has to be either PDF Action or Destination.');
+ }
+ }
+ }
+
+ /**
+ * Dump named destinations
+ *
+ * @todo Create a balanced tree instead of plain structure.
+ */
+ protected function _dumpNamedDestinations()
+ {
+ ksort($this->_namedTargets, SORT_STRING);
+
+ $destArrayItems = array();
+ foreach ($this->_namedTargets as $name => $destination) {
+ $destArrayItems[] = new Zend_Pdf_Element_String($name);
+
+ if ($destination instanceof Zend_Pdf_Target) {
+ $destArrayItems[] = $destination->getResource();
+ } else {
+ require_once 'Zend/Pdf/Exception.php';
+ throw new Zend_Pdf_Exception('PDF named destinations must be a Zend_Pdf_Target object.');
+ }
+ }
+ $destArray = $this->_objFactory->newObject(new Zend_Pdf_Element_Array($destArrayItems));
+
+ $DestTree = $this->_objFactory->newObject(new Zend_Pdf_Element_Dictionary());
+ $DestTree->Names = $destArray;
+
+ $root = $this->_trailer->Root;
+
+ if ($root->Names === null) {
+ $root->touch();
+ $root->Names = $this->_objFactory->newObject(new Zend_Pdf_Element_Dictionary());
+ } else {
+ $root->Names->touch();
+ }
+ $root->Names->Dests = $DestTree;
+ }
+
+ /**
+ * Dump outlines recursively
+ */
+ protected function _dumpOutlines()
+ {
+ $root = $this->_trailer->Root;
+
+ if ($root->Outlines === null) {
+ if (count($this->outlines) == 0) {
+ return;
+ } else {
+ $root->Outlines = $this->_objFactory->newObject(new Zend_Pdf_Element_Dictionary());
+ $root->Outlines->Type = new Zend_Pdf_Element_Name('Outlines');
+ $updateOutlinesNavigation = true;
+ }
+ } else {
+ $updateOutlinesNavigation = false;
+ if (count($this->_originalOutlines) != count($this->outlines)) {
+ // If original and current outlines arrays have different size then outlines list was updated
+ $updateOutlinesNavigation = true;
+ } else if ( !(array_keys($this->_originalOutlines) === array_keys($this->outlines)) ) {
+ // If original and current outlines arrays have different keys (with a glance to an order) then outlines list was updated
+ $updateOutlinesNavigation = true;
+ } else {
+ foreach ($this->outlines as $key => $outline) {
+ if ($this->_originalOutlines[$key] !== $outline) {
+ $updateOutlinesNavigation = true;
+ }
+ }
+ }
+ }
+
+ $lastOutline = null;
+ $openOutlinesCount = 0;
+ if ($updateOutlinesNavigation) {
+ $root->Outlines->touch();
+ $root->Outlines->First = null;
+
+ foreach ($this->outlines as $outline) {
+ if ($lastOutline === null) {
+ // First pass. Update Outlines dictionary First entry using corresponding value
+ $lastOutline = $outline->dumpOutline($this->_objFactory, $updateOutlinesNavigation, $root->Outlines);
+ $root->Outlines->First = $lastOutline;
+ } else {
+ // Update previous outline dictionary Next entry (Prev is updated within dumpOutline() method)
+ $currentOutlineDictionary = $outline->dumpOutline($this->_objFactory, $updateOutlinesNavigation, $root->Outlines, $lastOutline);
+ $lastOutline->Next = $currentOutlineDictionary;
+ $lastOutline = $currentOutlineDictionary;
+ }
+ $openOutlinesCount += $outline->openOutlinesCount();
+ }
+
+ $root->Outlines->Last = $lastOutline;
+ } else {
+ foreach ($this->outlines as $outline) {
+ $lastOutline = $outline->dumpOutline($this->_objFactory, $updateOutlinesNavigation, $root->Outlines, $lastOutline);
+ $openOutlinesCount += $outline->openOutlinesCount();
+ }
+ }
+
+ if ($openOutlinesCount != $this->_originalOpenOutlinesCount) {
+ $root->Outlines->touch;
+ $root->Outlines->Count = new Zend_Pdf_Element_Numeric($openOutlinesCount);
+ }
+ }
+
+ /**
+ * Create page object, attached to the PDF document.
+ * Method signatures:
+ *
+ * 1. Create new page with a specified pagesize.
+ * If $factory is null then it will be created and page must be attached to the document to be
+ * included into output.
+ * ---------------------------------------------------------
+ * new Zend_Pdf_Page(string $pagesize);
+ * ---------------------------------------------------------
+ *
+ * 2. Create new page with a specified pagesize (in default user space units).
+ * If $factory is null then it will be created and page must be attached to the document to be
+ * included into output.
+ * ---------------------------------------------------------
+ * new Zend_Pdf_Page(numeric $width, numeric $height);
+ * ---------------------------------------------------------
+ *
+ * @param mixed $param1
+ * @param mixed $param2
+ * @return Zend_Pdf_Page
+ */
+ public function newPage($param1, $param2 = null)
+ {
+ if ($param2 === null) {
+ return new Zend_Pdf_Page($param1, $this->_objFactory);
+ } else {
+ return new Zend_Pdf_Page($param1, $param2, $this->_objFactory);
+ }
+ }
+
+ /**
+ * Return the document-level Metadata
+ * or null Metadata stream is not presented
+ *
+ * @return string
+ */
+ public function getMetadata()
+ {
+ if ($this->_trailer->Root->Metadata !== null) {
+ return $this->_trailer->Root->Metadata->value;
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Sets the document-level Metadata (mast be valid XMP document)
+ *
+ * @param string $metadata
+ */
+ public function setMetadata($metadata)
+ {
+ $metadataObject = $this->_objFactory->newStreamObject($metadata);
+ $metadataObject->dictionary->Type = new Zend_Pdf_Element_Name('Metadata');
+ $metadataObject->dictionary->Subtype = new Zend_Pdf_Element_Name('XML');
+
+ $this->_trailer->Root->Metadata = $metadataObject;
+ $this->_trailer->Root->touch();
+ }
+
+ /**
+ * Return the document-level JavaScript
+ * or null if there is no JavaScript for this document
+ *
+ * @return string
+ */
+ public function getJavaScript()
+ {
+ return $this->_javaScript;
+ }
+
+ /**
+ * Get open Action
+ * Returns Zend_Pdf_Target (Zend_Pdf_Destination or Zend_Pdf_Action object)
+ *
+ * @return Zend_Pdf_Target
+ */
+ public function getOpenAction()
+ {
+ if ($this->_trailer->Root->OpenAction !== null) {
+ return Zend_Pdf_Target::load($this->_trailer->Root->OpenAction);
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Set open Action which is actually Zend_Pdf_Destination or Zend_Pdf_Action object
+ *
+ * @param Zend_Pdf_Target $openAction
+ * @returns Zend_Pdf
+ */
+ public function setOpenAction(Zend_Pdf_Target $openAction = null)
+ {
+ $root = $this->_trailer->Root;
+ $root->touch();
+
+ if ($openAction === null) {
+ $root->OpenAction = null;
+ } else {
+ $root->OpenAction = $openAction->getResource();
+
+ if ($openAction instanceof Zend_Pdf_Action) {
+ $openAction->dumpAction($this->_objFactory);
+ }
+ }
+
+ return $this;
+ }
+
+ /**
+ * Return an associative array containing all the named destinations (or GoTo actions) in the PDF.
+ * Named targets can be used to reference from outside
+ * the PDF, ex: 'http://www.something.com/mydocument.pdf#MyAction'
+ *
+ * @return array
+ */
+ public function getNamedDestinations()
+ {
+ return $this->_namedTargets;
+ }
+
+ /**
+ * Return specified named destination
+ *
+ * @param string $name
+ * @return Zend_Pdf_Destination_Explicit|Zend_Pdf_Action_GoTo
+ */
+ public function getNamedDestination($name)
+ {
+ if (isset($this->_namedTargets[$name])) {
+ return $this->_namedTargets[$name];
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Set specified named destination
+ *
+ * @param string $name
+ * @param Zend_Pdf_Destination_Explicit|Zend_Pdf_Action_GoTo $target
+ */
+ public function setNamedDestination($name, $destination = null)
+ {
+ if ($destination !== null &&
+ !$destination instanceof Zend_Pdf_Action_GoTo &&
+ !$destination instanceof Zend_Pdf_Destination_Explicit) {
+ require_once 'Zend/Pdf/Exception.php';
+ throw new Zend_Pdf_Exception('PDF named destination must refer an explicit destination or a GoTo PDF action.');
+ }
+
+ if ($destination !== null) {
+ $this->_namedTargets[$name] = $destination;
+ } else {
+ unset($this->_namedTargets[$name]);
+ }
+ }
+
+ /**
+ * Pages collection hash:
+ * <page dictionary object hash id> => Zend_Pdf_Page
+ *
+ * @var SplObjectStorage
+ */
+ protected $_pageReferences = null;
+
+ /**
+ * Pages collection hash:
+ * <page number> => Zend_Pdf_Page
+ *
+ * @var array
+ */
+ protected $_pageNumbers = null;
+
+ /**
+ * Refresh page collection hashes
+ *
+ * @return Zend_Pdf
+ */
+ protected function _refreshPagesHash()
+ {
+ $this->_pageReferences = array();
+ $this->_pageNumbers = array();
+ $count = 1;
+ foreach ($this->pages as $page) {
+ $pageDictionaryHashId = spl_object_hash($page->getPageDictionary()->getObject());
+ $this->_pageReferences[$pageDictionaryHashId] = $page;
+ $this->_pageNumbers[$count++] = $page;
+ }
+
+ return $this;
+ }
+
+ /**
+ * Resolve destination.
+ *
+ * Returns Zend_Pdf_Page page object or null if destination is not found within PDF document.
+ *
+ * @param Zend_Pdf_Destination $destination Destination to resolve
+ * @param boolean $refreshPagesHash Refresh page collection hashes before processing
+ * @return Zend_Pdf_Page|null
+ * @throws Zend_Pdf_Exception
+ */
+ public function resolveDestination(Zend_Pdf_Destination $destination, $refreshPageCollectionHashes = true)
+ {
+ if ($this->_pageReferences === null || $refreshPageCollectionHashes) {
+ $this->_refreshPagesHash();
+ }
+
+ if ($destination instanceof Zend_Pdf_Destination_Named) {
+ if (!isset($this->_namedTargets[$destination->getName()])) {
+ return null;
+ }
+ $destination = $this->getNamedDestination($destination->getName());
+
+ if ($destination instanceof Zend_Pdf_Action) {
+ if (!$destination instanceof Zend_Pdf_Action_GoTo) {
+ return null;
+ }
+ $destination = $destination->getDestination();
+ }
+
+ if (!$destination instanceof Zend_Pdf_Destination_Explicit) {
+ require_once 'Zend/Pdf/Exception.php';
+ throw new Zend_Pdf_Exception('Named destination target has to be an explicit destination.');
+ }
+ }
+
+ // Named target is an explicit destination
+ $pageElement = $destination->getResource()->items[0];
+
+ if ($pageElement->getType() == Zend_Pdf_Element::TYPE_NUMERIC) {
+ // Page reference is a PDF number
+ if (!isset($this->_pageNumbers[$pageElement->value])) {
+ return null;
+ }
+
+ return $this->_pageNumbers[$pageElement->value];
+ }
+
+ // Page reference is a PDF page dictionary reference
+ $pageDictionaryHashId = spl_object_hash($pageElement->getObject());
+ if (!isset($this->_pageReferences[$pageDictionaryHashId])) {
+ return null;
+ }
+ return $this->_pageReferences[$pageDictionaryHashId];
+ }
+
+ /**
+ * Walk through action and its chained actions tree and remove nodes
+ * if they are GoTo actions with an unresolved target.
+ *
+ * Returns null if root node is deleted or updated action overwise.
+ *
+ * @todo Give appropriate name and make method public
+ *
+ * @param $action
+ * @param boolean $refreshPagesHash Refresh page collection hashes before processing
+ * @return Zend_Pdf_Action|null
+ */
+ protected function _cleanUpAction(Zend_Pdf_Action $action, $refreshPageCollectionHashes = true)
+ {
+ if ($this->_pageReferences === null || $refreshPageCollectionHashes) {
+ $this->_refreshPagesHash();
+ }
+
+ // Named target is an action
+ if ($action instanceof Zend_Pdf_Action_GoTo &&
+ $this->resolveDestination($action->getDestination(), false) === null) {
+ // Action itself is a GoTo action with an unresolved destination
+ return null;
+ }
+
+ // Walk through child actions
+ $iterator = new RecursiveIteratorIterator($action, RecursiveIteratorIterator::SELF_FIRST);
+
+ $actionsToClean = array();
+ $deletionCandidateKeys = array();
+ foreach ($iterator as $chainedAction) {
+ if ($chainedAction instanceof Zend_Pdf_Action_GoTo &&
+ $this->resolveDestination($chainedAction->getDestination(), false) === null) {
+ // Some child action is a GoTo action with an unresolved destination
+ // Mark it as a candidate for deletion
+ $actionsToClean[] = $iterator->getSubIterator();
+ $deletionCandidateKeys[] = $iterator->getSubIterator()->key();
+ }
+ }
+ foreach ($actionsToClean as $id => $action) {
+ unset($action->next[$deletionCandidateKeys[$id]]);
+ }
+
+ return $action;
+ }
+
+ /**
+ * Extract fonts attached to the document
+ *
+ * returns array of Zend_Pdf_Resource_Font_Extracted objects
+ *
+ * @return array
+ * @throws Zend_Pdf_Exception
+ */
+ public function extractFonts()
+ {
+ $fontResourcesUnique = array();
+ foreach ($this->pages as $page) {
+ $pageResources = $page->extractResources();
+
+ if ($pageResources->Font === null) {
+ // Page doesn't contain have any font reference
+ continue;
+ }
+
+ $fontResources = $pageResources->Font;
+
+ foreach ($fontResources->getKeys() as $fontResourceName) {
+ $fontDictionary = $fontResources->$fontResourceName;
+
+ if (! ($fontDictionary instanceof Zend_Pdf_Element_Reference ||
+ $fontDictionary instanceof Zend_Pdf_Element_Object) ) {
+ require_once 'Zend/Pdf/Exception.php';
+ throw new Zend_Pdf_Exception('Font dictionary has to be an indirect object or object reference.');
+ }
+
+ $fontResourcesUnique[spl_object_hash($fontDictionary->getObject())] = $fontDictionary;
+ }
+ }
+
+ $fonts = array();
+ require_once 'Zend/Pdf/Exception.php';
+ foreach ($fontResourcesUnique as $resourceId => $fontDictionary) {
+ try {
+ // Try to extract font
+ $extractedFont = new Zend_Pdf_Resource_Font_Extracted($fontDictionary);
+
+ $fonts[$resourceId] = $extractedFont;
+ } catch (Zend_Pdf_Exception $e) {
+ if ($e->getMessage() != 'Unsupported font type.') {
+ throw $e;
+ }
+ }
+ }
+
+ return $fonts;
+ }
+
+ /**
+ * Extract font attached to the page by specific font name
+ *
+ * $fontName should be specified in UTF-8 encoding
+ *
+ * @return Zend_Pdf_Resource_Font_Extracted|null
+ * @throws Zend_Pdf_Exception
+ */
+ public function extractFont($fontName)
+ {
+ $fontResourcesUnique = array();
+ require_once 'Zend/Pdf/Exception.php';
+ foreach ($this->pages as $page) {
+ $pageResources = $page->extractResources();
+
+ if ($pageResources->Font === null) {
+ // Page doesn't contain have any font reference
+ continue;
+ }
+
+ $fontResources = $pageResources->Font;
+
+ foreach ($fontResources->getKeys() as $fontResourceName) {
+ $fontDictionary = $fontResources->$fontResourceName;
+
+ if (! ($fontDictionary instanceof Zend_Pdf_Element_Reference ||
+ $fontDictionary instanceof Zend_Pdf_Element_Object) ) {
+ require_once 'Zend/Pdf/Exception.php';
+ throw new Zend_Pdf_Exception('Font dictionary has to be an indirect object or object reference.');
+ }
+
+ $resourceId = spl_object_hash($fontDictionary->getObject());
+ if (isset($fontResourcesUnique[$resourceId])) {
+ continue;
+ } else {
+ // Mark resource as processed
+ $fontResourcesUnique[$resourceId] = 1;
+ }
+
+ if ($fontDictionary->BaseFont->value != $fontName) {
+ continue;
+ }
+
+ try {
+ // Try to extract font
+ return new Zend_Pdf_Resource_Font_Extracted($fontDictionary);
+ } catch (Zend_Pdf_Exception $e) {
+ if ($e->getMessage() != 'Unsupported font type.') {
+ throw $e;
+ }
+ // Continue searhing
+ }
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Render the completed PDF to a string.
+ * If $newSegmentOnly is true, then only appended part of PDF is returned.
+ *
+ * @param boolean $newSegmentOnly
+ * @param resource $outputStream
+ * @return string
+ * @throws Zend_Pdf_Exception
+ */
+ public function render($newSegmentOnly = false, $outputStream = null)
+ {
+ // Save document properties if necessary
+ if ($this->properties != $this->_originalProperties) {
+ $docInfo = $this->_objFactory->newObject(new Zend_Pdf_Element_Dictionary());
+
+ foreach ($this->properties as $key => $value) {
+ switch ($key) {
+ case 'Trapped':
+ switch ($value) {
+ case true:
+ $docInfo->$key = new Zend_Pdf_Element_Name('True');
+ break;
+
+ case false:
+ $docInfo->$key = new Zend_Pdf_Element_Name('False');
+ break;
+
+ case null:
+ $docInfo->$key = new Zend_Pdf_Element_Name('Unknown');
+ break;
+
+ default:
+ require_once 'Zend/Pdf/Exception.php';
+ throw new Zend_Pdf_Exception('Wrong Trapped document property vale: \'' . $value . '\'. Only true, false and null values are allowed.');
+ break;
+ }
+
+ case 'CreationDate':
+ // break intentionally omitted
+ case 'ModDate':
+ $docInfo->$key = new Zend_Pdf_Element_String((string)$value);
+ break;
+
+ case 'Title':
+ // break intentionally omitted
+ case 'Author':
+ // break intentionally omitted
+ case 'Subject':
+ // break intentionally omitted
+ case 'Keywords':
+ // break intentionally omitted
+ case 'Creator':
+ // break intentionally omitted
+ case 'Producer':
+ if (extension_loaded('mbstring') === true) {
+ $detected = mb_detect_encoding($value);
+ if ($detected !== 'ASCII') {
+ $value = chr(254) . chr(255) . mb_convert_encoding($value, 'UTF-16', $detected);
+ }
+ }
+ $docInfo->$key = new Zend_Pdf_Element_String((string)$value);
+ break;
+
+ default:
+ // Set property using PDF type based on PHP type
+ $docInfo->$key = Zend_Pdf_Element::phpToPdf($value);
+ break;
+ }
+ }
+
+ $this->_trailer->Info = $docInfo;
+ }
+
+ $this->_dumpPages();
+ $this->_dumpNamedDestinations();
+ $this->_dumpOutlines();
+
+ // Check, that PDF file was modified
+ // File is always modified by _dumpPages() now, but future implementations may eliminate this.
+ if (!$this->_objFactory->isModified()) {
+ if ($newSegmentOnly) {
+ // Do nothing, return
+ return '';
+ }
+
+ if ($outputStream === null) {
+ return $this->_trailer->getPDFString();
+ } else {
+ $pdfData = $this->_trailer->getPDFString();
+ while ( strlen($pdfData) > 0 && ($byteCount = fwrite($outputStream, $pdfData)) != false ) {
+ $pdfData = substr($pdfData, $byteCount);
+ }
+
+ return '';
+ }
+ }
+
+ // offset (from a start of PDF file) of new PDF file segment
+ $offset = $this->_trailer->getPDFLength();
+ // Last Object number in a list of free objects
+ $lastFreeObject = $this->_trailer->getLastFreeObject();
+
+ // Array of cross-reference table subsections
+ $xrefTable = array();
+ // Object numbers of first objects in each subsection
+ $xrefSectionStartNums = array();
+
+ // Last cross-reference table subsection
+ $xrefSection = array();
+ // Dummy initialization of the first element (specail case - header of linked list of free objects).
+ $xrefSection[] = 0;
+ $xrefSectionStartNums[] = 0;
+ // Object number of last processed PDF object.
+ // Used to manage cross-reference subsections.
+ // Initialized by zero (specail case - header of linked list of free objects).
+ $lastObjNum = 0;
+
+ if ($outputStream !== null) {
+ if (!$newSegmentOnly) {
+ $pdfData = $this->_trailer->getPDFString();
+ while ( strlen($pdfData) > 0 && ($byteCount = fwrite($outputStream, $pdfData)) != false ) {
+ $pdfData = substr($pdfData, $byteCount);
+ }
+ }
+ } else {
+ $pdfSegmentBlocks = ($newSegmentOnly) ? array() : array($this->_trailer->getPDFString());
+ }
+
+ // Iterate objects to create new reference table
+ foreach ($this->_objFactory->listModifiedObjects() as $updateInfo) {
+ $objNum = $updateInfo->getObjNum();
+
+ if ($objNum - $lastObjNum != 1) {
+ // Save cross-reference table subsection and start new one
+ $xrefTable[] = $xrefSection;
+ $xrefSection = array();
+ $xrefSectionStartNums[] = $objNum;
+ }
+
+ if ($updateInfo->isFree()) {
+ // Free object cross-reference table entry
+ $xrefSection[] = sprintf("%010d %05d f \n", $lastFreeObject, $updateInfo->getGenNum());
+ $lastFreeObject = $objNum;
+ } else {
+ // In-use object cross-reference table entry
+ $xrefSection[] = sprintf("%010d %05d n \n", $offset, $updateInfo->getGenNum());
+
+ $pdfBlock = $updateInfo->getObjectDump();
+ $offset += strlen($pdfBlock);
+
+ if ($outputStream === null) {
+ $pdfSegmentBlocks[] = $pdfBlock;
+ } else {
+ while ( strlen($pdfBlock) > 0 && ($byteCount = fwrite($outputStream, $pdfBlock)) != false ) {
+ $pdfBlock = substr($pdfBlock, $byteCount);
+ }
+ }
+ }
+ $lastObjNum = $objNum;
+ }
+ // Save last cross-reference table subsection
+ $xrefTable[] = $xrefSection;
+
+ // Modify first entry (specail case - header of linked list of free objects).
+ $xrefTable[0][0] = sprintf("%010d 65535 f \n", $lastFreeObject);
+
+ $xrefTableStr = "xref\n";
+ foreach ($xrefTable as $sectId => $xrefSection) {
+ $xrefTableStr .= sprintf("%d %d \n", $xrefSectionStartNums[$sectId], count($xrefSection));
+ foreach ($xrefSection as $xrefTableEntry) {
+ $xrefTableStr .= $xrefTableEntry;
+ }
+ }
+
+ $this->_trailer->Size->value = $this->_objFactory->getObjectCount();
+
+ $pdfBlock = $xrefTableStr
+ . $this->_trailer->toString()
+ . "startxref\n" . $offset . "\n"
+ . "%%EOF\n";
+
+ $this->_objFactory->cleanEnumerationShiftCache();
+
+ if ($outputStream === null) {
+ $pdfSegmentBlocks[] = $pdfBlock;
+
+ return implode('', $pdfSegmentBlocks);
+ } else {
+ while ( strlen($pdfBlock) > 0 && ($byteCount = fwrite($outputStream, $pdfBlock)) != false ) {
+ $pdfBlock = substr($pdfBlock, $byteCount);
+ }
+
+ return '';
+ }
+ }
+
+
+ /**
+ * Set the document-level JavaScript
+ *
+ * @param string $javascript
+ */
+ public function setJavaScript($javascript)
+ {
+ $this->_javaScript = $javascript;
+ }
+
+
+ /**
+ * Convert date to PDF format (it's close to ASN.1 (Abstract Syntax Notation
+ * One) defined in ISO/IEC 8824).
+ *
+ * @todo This really isn't the best location for this method. It should
+ * probably actually exist as Zend_Pdf_Element_Date or something like that.
+ *
+ * @todo Address the following E_STRICT issue:
+ * PHP Strict Standards: date(): It is not safe to rely on the system's
+ * timezone settings. Please use the date.timezone setting, the TZ
+ * environment variable or the date_default_timezone_set() function. In
+ * case you used any of those methods and you are still getting this
+ * warning, you most likely misspelled the timezone identifier.
+ *
+ * @param integer $timestamp (optional) If omitted, uses the current time.
+ * @return string
+ */
+ public static function pdfDate($timestamp = null)
+ {
+ if ($timestamp === null) {
+ $date = date('\D\:YmdHisO');
+ } else {
+ $date = date('\D\:YmdHisO', $timestamp);
+ }
+ return substr_replace($date, '\'', -2, 0) . '\'';
+ }
+
+}
--- /dev/null
+<?php
+/**
+ * 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_ProgressBar
+ * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ * @version $Id$
+ */
+
+/**
+ * Zend_ProgressBar offers an interface for multiple enviroments.
+ *
+ * @category Zend
+ * @package Zend_ProgressBar
+ * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+class Zend_ProgressBar
+{
+ /**
+ * Min value
+ *
+ * @var float
+ */
+ protected $_min;
+
+ /**
+ * Max value
+ *
+ * @var float
+ */
+ protected $_max;
+
+ /**
+ * Current value
+ *
+ * @var float
+ */
+ protected $_current;
+
+ /**
+ * Start time of the progressbar, required for ETA
+ *
+ * @var integer
+ */
+ protected $_startTime;
+
+ /**
+ * Current status text
+ *
+ * @var string
+ */
+ protected $_statusText = null;
+
+ /**
+ * Adapter for the output
+ *
+ * @var Zend_ProgressBar_Adapter
+ */
+ protected $_adapter;
+
+ /**
+ * Namespace for keeping the progressbar persistent
+ *
+ * @var string
+ */
+ protected $_persistenceNamespace = null;
+
+ /**
+ * Create a new progressbar backend.
+ *
+ * @param Zend_ProgressBar_Adapter $adapter
+ * @param float $min
+ * @param float $max
+ * @param string $persistenceNamespace
+ * @throws Zend_ProgressBar_Exception When $min is greater than $max
+ */
+ public function __construct(Zend_ProgressBar_Adapter $adapter, $min = 0, $max = 100, $persistenceNamespace = null)
+ {
+ // Check min/max values and set them
+ if ($min > $max) {
+ require_once 'Zend/ProgressBar/Exception.php';
+ throw new Zend_ProgressBar_Exception('$max must be greater than $min');
+ }
+
+ $this->_min = (float) $min;
+ $this->_max = (float) $max;
+ $this->_current = (float) $min;
+
+ // See if we have to open a session namespace
+ if ($persistenceNamespace !== null) {
+ require_once 'Zend/Session/Namespace.php';
+
+ $this->_persistenceNamespace = new Zend_Session_Namespace($persistenceNamespace);
+ }
+
+ // Set adapter
+ $this->_adapter = $adapter;
+
+ // Track the start time
+ $this->_startTime = time();
+
+ // See If a persistenceNamespace exists and handle accordingly
+ if ($this->_persistenceNamespace !== null) {
+ if (isset($this->_persistenceNamespace->isSet)) {
+ $this->_startTime = $this->_persistenceNamespace->startTime;
+ $this->_current = $this->_persistenceNamespace->current;
+ $this->_statusText = $this->_persistenceNamespace->statusText;
+ } else {
+ $this->_persistenceNamespace->isSet = true;
+ $this->_persistenceNamespace->startTime = $this->_startTime;
+ $this->_persistenceNamespace->current = $this->_current;
+ $this->_persistenceNamespace->statusText = $this->_statusText;
+ }
+ } else {
+ $this->update();
+ }
+ }
+
+ /**
+ * Get the current adapter
+ *
+ * @return Zend_ProgressBar_Adapter
+ */
+ public function getAdapter()
+ {
+ return $this->_adapter;
+ }
+
+ /**
+ * Update the progressbar
+ *
+ * @param float $value
+ * @param string $text
+ * @return void
+ */
+ public function update($value = null, $text = null)
+ {
+ // Update value if given
+ if ($value !== null) {
+ $this->_current = min($this->_max, max($this->_min, $value));
+ }
+
+ // Update text if given
+ if ($text !== null) {
+ $this->_statusText = $text;
+ }
+
+ // See if we have to update a namespace
+ if ($this->_persistenceNamespace !== null) {
+ $this->_persistenceNamespace->current = $this->_current;
+ $this->_persistenceNamespace->statusText = $this->_statusText;
+ }
+
+ // Calculate percent
+ if ($this->_min === $this->_max) {
+ $percent = false;
+ } else {
+ $percent = (float) ($this->_current - $this->_min) / ($this->_max - $this->_min);
+ }
+
+ // Calculate ETA
+ $timeTaken = time() - $this->_startTime;
+
+ if ($percent === .0 || $percent === false) {
+ $timeRemaining = null;
+ } else {
+ $timeRemaining = round(((1 / $percent) * $timeTaken) - $timeTaken);
+ }
+
+ // Poll the adapter
+ $this->_adapter->notify($this->_current, $this->_max, $percent, $timeTaken, $timeRemaining, $this->_statusText);
+ }
+
+ /**
+ * Update the progressbar to the next value
+ *
+ * @param string $text
+ * @return void
+ */
+ public function next($diff = 1, $text = null)
+ {
+ $this->update(max($this->_min, min($this->_max, $this->_current + $diff)), $text);
+ }
+
+ /**
+ * Call the adapters finish() behaviour
+ *
+ * @return void
+ */
+ public function finish()
+ {
+ if ($this->_persistenceNamespace !== null) {
+ unset($this->_persistenceNamespace->isSet);
+ }
+
+ $this->_adapter->finish();
+ }
+}
--- /dev/null
+<?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_Queue
+ * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ * @version $Id$
+ */
+
+/**
+ * Class for connecting to queues performing common operations.
+ *
+ * @category Zend
+ * @package Zend_Queue
+ * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+class Zend_Queue implements Countable
+{
+ /**
+ * Use the TIMEOUT constant in the config of a Zend_Queue
+ */
+ const TIMEOUT = 'timeout';
+
+ /**
+ * Default visibility passed to count
+ */
+ const VISIBILITY_TIMEOUT = 30;
+
+ /**
+ * Use the NAME constant in the config of Zend_Queue
+ */
+ const NAME = 'name';
+
+ /**
+ * @var Zend_Queue_Adapter_AdapterInterface
+ */
+ protected $_adapter = null;
+
+ /**
+ * User-provided configuration
+ *
+ * @var array
+ */
+ protected $_options = array();
+
+ /**
+ * Zend_Queue_Message class
+ *
+ * @var string
+ */
+ protected $_messageClass = 'Zend_Queue_Message';
+
+ /**
+ * Zend_Queue_Message_Iterator class
+ *
+ * @var string
+ */
+ protected $_messageSetClass = 'Zend_Queue_Message_Iterator';
+
+ /**
+ * @var Zend_Log
+ */
+ protected $_logger = null;
+
+ /**
+ * Constructor
+ *
+ * Can be called as
+ * $queue = new Zend_Queue($config);
+ * - or -
+ * $queue = new Zend_Queue('array', $config);
+ * - or -
+ * $queue = new Zend_Queue(null, $config); // Zend_Queue->createQueue();
+ *
+ * @param string|Zend_Queue_Adapter|array|Zend_Config|null String or adapter instance, or options array or Zend_Config instance
+ * @param Zend_Config|array $options Zend_Config or a configuration array
+ * @return void
+ */
+ public function __construct($spec, $options = array())
+ {
+ $adapter = null;
+ if ($spec instanceof Zend_Queue_Adapter_AdapterInterface) {
+ $adapter = $spec;
+ } elseif (is_string($spec)) {
+ $adapter = $spec;
+ } elseif ($spec instanceof Zend_Config) {
+ $options = $spec->toArray();
+ } elseif (is_array($spec)) {
+ $options = $spec;
+ }
+
+ // last minute error checking
+ if ((null === $adapter)
+ && (!is_array($options) && (!$options instanceof Zend_Config))
+ ) {
+ require_once 'Zend/Queue/Exception.php';
+ throw new Zend_Queue_Exception('No valid params passed to constructor');
+ }
+
+ // Now continue as we would if we were a normal constructor
+ if ($options instanceof Zend_Config) {
+ $options = $options->toArray();
+ } elseif (!is_array($options)) {
+ $options = array();
+ }
+
+ // Make sure we have some defaults to work with
+ if (!isset($options[self::TIMEOUT])) {
+ $options[self::TIMEOUT] = self::VISIBILITY_TIMEOUT;
+ }
+
+ // Make sure all defaults are appropriately set.
+ if (!array_key_exists('timeout', $options)) {
+ $options[self::TIMEOUT] = self::VISIBILITY_TIMEOUT;
+ }
+ if (array_key_exists('messageClass', $options)) {
+ $this->setMessageClass($options['messageClass']);
+ }
+ if (array_key_exists('messageSetClass', $options)) {
+ $this->setMessageSetClass($options['messageSetClass']);
+ }
+
+ $this->setOptions($options);
+
+ // if we were passed an adapter we either build the $adapter or use it
+ if (null !== $adapter) {
+ $this->setAdapter($adapter);
+ }
+ }
+
+ /**
+ * Set queue options
+ *
+ * @param array $options
+ * @return Zend_Queue
+ */
+ public function setOptions(array $options)
+ {
+ $this->_options = array_merge($this->_options, $options);
+ return $this;
+ }
+
+ /**
+ * Set an individual configuration option
+ *
+ * @param string $name
+ * @param mixed $value
+ * @return Zend_Queue
+ */
+ public function setOption($name, $value)
+ {
+ $this->_options[(string) $name] = $value;
+ return $this;
+ }
+
+ /**
+ * Returns the configuration options for the queue
+ *
+ * @return array
+ */
+ public function getOptions()
+ {
+ return $this->_options;
+ }
+
+ /**
+ * Determine if a requested option has been defined
+ *
+ * @param string $name
+ * @return bool
+ */
+ public function hasOption($name)
+ {
+ return array_key_exists($name, $this->_options);
+ }
+
+ /**
+ * Retrieve a single option
+ *
+ * @param string $name
+ * @return null|mixed Returns null if option does not exist; option value otherwise
+ */
+ public function getOption($name)
+ {
+ if ($this->hasOption($name)) {
+ return $this->_options[$name];
+ }
+ return null;
+ }
+
+ /**
+ * Set the adapter for this queue
+ *
+ * @param string|Zend_Queue_Adapter_AdapterInterface $adapter
+ * @return Zend_Queue Provides a fluent interface
+ */
+ public function setAdapter($adapter)
+ {
+ if (is_string($adapter)) {
+ if (null === ($adapterNamespace = $this->getOption('adapterNamespace'))) {
+ $adapterNamespace = 'Zend_Queue_Adapter';
+ }
+
+ $adapterName = str_replace(
+ ' ',
+ '_',
+ ucwords(
+ str_replace(
+ '_',
+ ' ',
+ strtolower($adapterNamespace . '_' . $adapter)
+ )
+ )
+ );
+
+ if (!class_exists($adapterName)) {
+ require_once 'Zend/Loader.php';
+ Zend_Loader::loadClass($adapterName);
+ }
+
+ /*
+ * Create an instance of the adapter class.
+ * Pass the configuration to the adapter class constructor.
+ */
+ $adapter = new $adapterName($this->getOptions(), $this);
+ }
+
+ if (!$adapter instanceof Zend_Queue_Adapter_AdapterInterface) {
+ require_once 'Zend/Queue/Exception.php';
+ throw new Zend_Queue_Exception("Adapter class '" . get_class($adapterName) . "' does not implement Zend_Queue_Adapter_AdapterInterface");
+ }
+
+ $this->_adapter = $adapter;
+
+ $this->_adapter->setQueue($this);
+
+ if (null !== ($name = $this->getOption(self::NAME))) {
+ $this->_setName($name);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Get the adapter for this queue
+ *
+ * @return Zend_Queue_Adapter_AdapterInterface
+ */
+ public function getAdapter()
+ {
+ return $this->_adapter;
+ }
+
+ /**
+ * @param string $className
+ * @return Zend_Queue Provides a fluent interface
+ */
+ public function setMessageClass($className)
+ {
+ $this->_messageClass = (string) $className;
+ return $this;
+ }
+
+ /**
+ * @return string
+ */
+ public function getMessageClass()
+ {
+ return $this->_messageClass;
+ }
+
+ /**
+ * @param string $className
+ * @return Zend_Queue Provides a fluent interface
+ */
+ public function setMessageSetClass($className)
+ {
+ $this->_messageSetClass = (string) $className;
+ return $this;
+ }
+
+ /**
+ * @return string
+ */
+ public function getMessageSetClass()
+ {
+ return $this->_messageSetClass;
+ }
+
+ /**
+ * Get the name of the queue
+ *
+ * Note: _setName() used to exist, but it caused confusion with createQueue
+ * Will evaluate later to see if we should add it back in.
+ *
+ * @return string
+ */
+ public function getName()
+ {
+ return $this->getOption(self::NAME);
+ }
+
+ /**
+ * Create a new queue
+ *
+ * @param string $name queue name
+ * @param integer $timeout default visibility timeout
+ * @return Zend_Queue|false
+ * @throws Zend_Queue_Exception
+ */
+ public function createQueue($name, $timeout = null)
+ {
+ if (!is_string($name)) {
+ require_once 'Zend/Queue/Exception.php';
+ throw new Zend_Queue_Exception('$name is not a string');
+ }
+
+ if ((null !== $timeout) && !is_integer($timeout)) {
+ require_once 'Zend/Queue/Exception.php';
+ throw new Zend_Queue_Exception('$timeout must be an integer');
+ }
+
+ // Default to standard timeout
+ if (null === $timeout) {
+ $timeout = $this->getOption(self::TIMEOUT);
+ }
+
+ // Some queues allow you to create on the fly, but cannot return
+ // a list of queues. Stomp protocol for example.
+ if ($this->isSupported('create')) {
+ if ($this->getAdapter()->isExists($name)) {
+ return false;
+ }
+
+ if (!$this->getAdapter()->create($name, $timeout)) {
+ return false;
+ }
+ }
+
+ $options = array(
+ self::NAME => $name,
+ 'timeout' => $timeout
+ );
+
+ return new self($this->getAdapter(), $options);
+ }
+
+ /**
+ * Delete the queue this object is working on.
+ *
+ * This queue is disabled, regardless of the outcome of the deletion
+ * of the queue, because the programmers intent is to disable this queue.
+ *
+ * @return boolean
+ */
+ public function deleteQueue()
+ {
+ if ($this->isSupported('delete')) {
+ $deleted = $this->getAdapter()->delete($this->getName());
+ }
+ else {
+ $deleted = true;
+ }
+
+ /**
+ * @see Zend_Queue_Adapter_Null
+ */
+ require_once('Zend/Queue/Adapter/Null.php');
+ $this->setAdapter(new Zend_Queue_Adapter_Null($this->getOptions()));
+
+ return $deleted;
+ }
+
+ /**
+ * Delete a message from the queue
+ *
+ * Returns true if the message is deleted, false if the deletion is
+ * unsuccessful.
+ *
+ * Returns true if the adapter doesn't support message deletion.
+ *
+ * @param Zend_Queue_Message $message
+ * @return boolean
+ * @throws Zend_Queue_Exception
+ */
+ public function deleteMessage(Zend_Queue_Message $message)
+ {
+ if ($this->getAdapter()->isSupported('deleteMessage')) {
+ return $this->getAdapter()->deleteMessage($message);
+ }
+ return true;
+ }
+
+ /**
+ * Send a message to the queue
+ *
+ * @param mixed $message message
+ * @return Zend_Queue_Message
+ * @throws Zend_Queue_Exception
+ */
+ public function send($message)
+ {
+ return $this->getAdapter()->send($message);
+ }
+
+ /**
+ * Returns the approximate number of messages in the queue
+ *
+ * @return integer
+ */
+ public function count()
+ {
+ if ($this->getAdapter()->isSupported('count')) {
+ return $this->getAdapter()->count();
+ }
+ return 0;
+ }
+
+ /**
+ * Return the first element in the queue
+ *
+ * @param integer $maxMessages
+ * @param integer $timeout
+ * @return Zend_Queue_Message_Iterator
+ */
+ public function receive($maxMessages=null, $timeout=null)
+ {
+ if (($maxMessages !== null) && !is_integer($maxMessages)) {
+ require_once 'Zend/Queue/Exception.php';
+ throw new Zend_Queue_Exception('$maxMessages must be an integer or null');
+ }
+
+ if (($timeout !== null) && !is_integer($timeout)) {
+ require_once 'Zend/Queue/Exception.php';
+ throw new Zend_Queue_Exception('$timeout must be an integer or null');
+ }
+
+ // Default to returning only one message
+ if ($maxMessages === null) {
+ $maxMessages = 1;
+ }
+
+ // Default to standard timeout
+ if ($timeout === null) {
+ $timeout = $this->getOption(self::TIMEOUT);
+ }
+
+ return $this->getAdapter()->receive($maxMessages, $timeout);
+ }
+
+ /**
+ * Return a list of queue capabilities functions
+ *
+ * $array['function name'] = true or false
+ * true is supported, false is not supported.
+ *
+ * @param string $name
+ * @return array
+ */
+ public function getCapabilities()
+ {
+ return $this->getAdapter()->getCapabilities();
+ }
+
+ /**
+ * Indicates if a function is supported or not.
+ *
+ * @param string $name
+ * @return boolean
+ */
+ public function isSupported($name)
+ {
+ $translation = array(
+ 'deleteQueue' => 'delete',
+ 'createQueue' => 'create'
+ );
+
+ if (isset($translation[$name])) {
+ $name = $translation[$name];
+ }
+
+ return $this->getAdapter()->isSupported($name);
+ }
+
+ /**
+ * Get an array of all available queues
+ *
+ * @return array
+ * @throws Zend_Queue_Exception
+ */
+ public function getQueues()
+ {
+ if (!$this->isSupported('getQueues')) {
+ throw new Zend_Queue_Exception( __FUNCTION__ . '() is not supported by ' . get_class($this->getAdapter()));
+ }
+
+ return $this->getAdapter()->getQueues();
+ }
+
+ /**
+ * Set the name of the queue
+ *
+ * This is AN UNSUPPORTED FUNCTION
+ *
+ * @param string $name
+ * @return Zend_Queue|false Provides a fluent interface
+ */
+ protected function _setName($name)
+ {
+ if (!is_string($name)) {
+ /**
+ * @see Zend_Queue_Exception
+ */
+ require_once 'Zend/Queue/Exception.php';
+ throw new Zend_Queue_Exception("$name is not a string");
+ }
+
+ if ($this->getAdapter()->isSupported('create')) {
+ if (!$this->getAdapter()->isExists($name)) {
+ $timeout = $this->getOption(self::TIMEOUT);
+
+ if (!$this->getAdapter()->create($name, $timeout)) {
+ // Unable to create the new queue
+ return false;
+ }
+ }
+ }
+
+ $this->setOption(self::NAME, $name);
+
+ return $this;
+ }
+
+ /**
+ * returns a listing of Zend_Queue details.
+ * useful for debugging
+ *
+ * @return array
+ */
+ public function debugInfo()
+ {
+ $info = array();
+ $info['self'] = get_class($this);
+ $info['adapter'] = get_class($this->getAdapter());
+ foreach ($this->getAdapter()->getCapabilities() as $feature => $supported) {
+ $info['adapter-' . $feature] = ($supported) ? 'yes' : 'no';
+ }
+ $info['options'] = $this->getOptions();
+ $info['options']['driverOptions'] = '[hidden]';
+ $info['currentQueue'] = $this->getName();
+ $info['messageClass'] = $this->getMessageClass();
+ $info['messageSetClass'] = $this->getMessageSetClass();
+
+ return $info;
+ }
+}
*
* @category Zend
* @package Zend_Registry
- * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id$
*/
*
* @category Zend
* @package Zend_Registry
- * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Registry extends ArrayObject
/**
* @see Zend_Loader
*/
- require_once 'Zend/Loader.php';
- Zend_Loader::loadClass($registryClassName);
+ if (!class_exists($registryClassName)) {
+ require_once 'Zend/Loader.php';
+ Zend_Loader::loadClass($registryClassName);
+ }
self::$_registryClassName = $registryClassName;
}
return self::$_registry->offsetExists($index);
}
+ /**
+ * Constructs a parent ArrayObject with default
+ * ARRAY_AS_PROPS to allow acces as an object
+ *
+ * @param array $array data array
+ * @param integer $flags ArrayObject flags
+ */
+ public function __construct($array = array(), $flags = parent::ARRAY_AS_PROPS)
+ {
+ parent::__construct($array, $flags);
+ }
+
/**
* @param string $index
* @returns mixed
--- /dev/null
+<?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_Session
+ * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ * @version $Id$
+ * @since Preview Release 0.2
+ */
+
+
+/**
+ * @see Zend_Session_Abstract
+ */
+require_once 'Zend/Session/Abstract.php';
+
+/**
+ * @see Zend_Session_Namespace
+ */
+require_once 'Zend/Session/Namespace.php';
+
+/**
+ * @see Zend_Session_SaveHandler_Interface
+ */
+require_once 'Zend/Session/SaveHandler/Interface.php';
+
+
+/**
+ * Zend_Session
+ *
+ * @category Zend
+ * @package Zend_Session
+ * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+class Zend_Session extends Zend_Session_Abstract
+{
+ /**
+ * Whether or not Zend_Session is being used with unit tests
+ *
+ * @internal
+ * @var bool
+ */
+ public static $_unitTestEnabled = false;
+
+ /**
+ * $_throwStartupException
+ *
+ * @var bool|bitset This could also be a combiniation of error codes to catch
+ */
+ protected static $_throwStartupExceptions = true;
+
+ /**
+ * Check whether or not the session was started
+ *
+ * @var bool
+ */
+ private static $_sessionStarted = false;
+
+ /**
+ * Whether or not the session id has been regenerated this request.
+ *
+ * Id regeneration state
+ * <0 - regenerate requested when session is started
+ * 0 - do nothing
+ * >0 - already called session_regenerate_id()
+ *
+ * @var int
+ */
+ private static $_regenerateIdState = 0;
+
+ /**
+ * Private list of php's ini values for ext/session
+ * null values will default to the php.ini value, otherwise
+ * the value below will overwrite the default ini value, unless
+ * the user has set an option explicity with setOptions()
+ *
+ * @var array
+ */
+ private static $_defaultOptions = array(
+ 'save_path' => null,
+ 'name' => null, /* this should be set to a unique value for each application */
+ 'save_handler' => null,
+ //'auto_start' => null, /* intentionally excluded (see manual) */
+ 'gc_probability' => null,
+ 'gc_divisor' => null,
+ 'gc_maxlifetime' => null,
+ 'serialize_handler' => null,
+ 'cookie_lifetime' => null,
+ 'cookie_path' => null,
+ 'cookie_domain' => null,
+ 'cookie_secure' => null,
+ 'cookie_httponly' => null,
+ 'use_cookies' => null,
+ 'use_only_cookies' => 'on',
+ 'referer_check' => null,
+ 'entropy_file' => null,
+ 'entropy_length' => null,
+ 'cache_limiter' => null,
+ 'cache_expire' => null,
+ 'use_trans_sid' => null,
+ 'bug_compat_42' => null,
+ 'bug_compat_warn' => null,
+ 'hash_function' => null,
+ 'hash_bits_per_character' => null
+ );
+
+ /**
+ * List of options pertaining to Zend_Session that can be set by developers
+ * using Zend_Session::setOptions(). This list intentionally duplicates
+ * the individual declaration of static "class" variables by the same names.
+ *
+ * @var array
+ */
+ private static $_localOptions = array(
+ 'strict' => '_strict',
+ 'remember_me_seconds' => '_rememberMeSeconds',
+ 'throw_startup_exceptions' => '_throwStartupExceptions'
+ );
+
+ /**
+ * Whether or not write close has been performed.
+ *
+ * @var bool
+ */
+ private static $_writeClosed = false;
+
+ /**
+ * Whether or not session id cookie has been deleted
+ *
+ * @var bool
+ */
+ private static $_sessionCookieDeleted = false;
+
+ /**
+ * Whether or not session has been destroyed via session_destroy()
+ *
+ * @var bool
+ */
+ private static $_destroyed = false;
+
+ /**
+ * Whether or not session must be initiated before usage
+ *
+ * @var bool
+ */
+ private static $_strict = false;
+
+ /**
+ * Default number of seconds the session will be remembered for when asked to be remembered
+ *
+ * @var int
+ */
+ private static $_rememberMeSeconds = 1209600; // 2 weeks
+
+ /**
+ * Whether the default options listed in Zend_Session::$_localOptions have been set
+ *
+ * @var bool
+ */
+ private static $_defaultOptionsSet = false;
+
+ /**
+ * A reference to the set session save handler
+ *
+ * @var Zend_Session_SaveHandler_Interface
+ */
+ private static $_saveHandler = null;
+
+
+ /**
+ * Constructor overriding - make sure that a developer cannot instantiate
+ */
+ protected function __construct()
+ {
+ }
+
+
+ /**
+ * setOptions - set both the class specified
+ *
+ * @param array $userOptions - pass-by-keyword style array of <option name, option value> pairs
+ * @throws Zend_Session_Exception
+ * @return void
+ */
+ public static function setOptions(array $userOptions = array())
+ {
+ // set default options on first run only (before applying user settings)
+ if (!self::$_defaultOptionsSet) {
+ foreach (self::$_defaultOptions as $defaultOptionName => $defaultOptionValue) {
+ if (isset(self::$_defaultOptions[$defaultOptionName])) {
+ ini_set("session.$defaultOptionName", $defaultOptionValue);
+ }
+ }
+
+ self::$_defaultOptionsSet = true;
+ }
+
+ // set the options the user has requested to set
+ foreach ($userOptions as $userOptionName => $userOptionValue) {
+
+ $userOptionName = strtolower($userOptionName);
+
+ // set the ini based values
+ if (array_key_exists($userOptionName, self::$_defaultOptions)) {
+ ini_set("session.$userOptionName", $userOptionValue);
+ }
+ elseif (isset(self::$_localOptions[$userOptionName])) {
+ self::${self::$_localOptions[$userOptionName]} = $userOptionValue;
+ }
+ else {
+ /** @see Zend_Session_Exception */
+ require_once 'Zend/Session/Exception.php';
+ throw new Zend_Session_Exception("Unknown option: $userOptionName = $userOptionValue");
+ }
+ }
+ }
+
+ /**
+ * getOptions()
+ *
+ * @param string $optionName OPTIONAL
+ * @return array|string
+ */
+ public static function getOptions($optionName = null)
+ {
+ $options = array();
+ foreach (ini_get_all('session') as $sysOptionName => $sysOptionValues) {
+ $options[substr($sysOptionName, 8)] = $sysOptionValues['local_value'];
+ }
+ foreach (self::$_localOptions as $localOptionName => $localOptionMemberName) {
+ $options[$localOptionName] = self::${$localOptionMemberName};
+ }
+
+ if ($optionName) {
+ if (array_key_exists($optionName, $options)) {
+ return $options[$optionName];
+ }
+ return null;
+ }
+
+ return $options;
+ }
+
+ /**
+ * setSaveHandler() - Session Save Handler assignment
+ *
+ * @param Zend_Session_SaveHandler_Interface $interface
+ * @return void
+ */
+ public static function setSaveHandler(Zend_Session_SaveHandler_Interface $saveHandler)
+ {
+ self::$_saveHandler = $saveHandler;
+
+ if (self::$_unitTestEnabled) {
+ return;
+ }
+
+ session_set_save_handler(
+ array(&$saveHandler, 'open'),
+ array(&$saveHandler, 'close'),
+ array(&$saveHandler, 'read'),
+ array(&$saveHandler, 'write'),
+ array(&$saveHandler, 'destroy'),
+ array(&$saveHandler, 'gc')
+ );
+ }
+
+
+ /**
+ * getSaveHandler() - Get the session Save Handler
+ *
+ * @return Zend_Session_SaveHandler_Interface
+ */
+ public static function getSaveHandler()
+ {
+ return self::$_saveHandler;
+ }
+
+
+ /**
+ * regenerateId() - Regenerate the session id. Best practice is to call this after
+ * session is started. If called prior to session starting, session id will be regenerated
+ * at start time.
+ *
+ * @throws Zend_Session_Exception
+ * @return void
+ */
+ public static function regenerateId()
+ {
+ if (!self::$_unitTestEnabled && headers_sent($filename, $linenum)) {
+ /** @see Zend_Session_Exception */
+ require_once 'Zend/Session/Exception.php';
+ throw new Zend_Session_Exception("You must call " . __CLASS__ . '::' . __FUNCTION__ .
+ "() before any output has been sent to the browser; output started in {$filename}/{$linenum}");
+ }
+
+ if (self::$_sessionStarted && self::$_regenerateIdState <= 0) {
+ if (!self::$_unitTestEnabled) {
+ session_regenerate_id(true);
+ }
+ self::$_regenerateIdState = 1;
+ } else {
+ /**
+ * @todo If we can detect that this requester had no session previously,
+ * then why regenerate the id before the session has started?
+ * Feedback wanted for:
+ //
+ if (isset($_COOKIE[session_name()]) || (!use only cookies && isset($_REQUEST[session_name()]))) {
+ self::$_regenerateIdState = 1;
+ } else {
+ self::$_regenerateIdState = -1;
+ }
+ //*/
+ self::$_regenerateIdState = -1;
+ }
+ }
+
+
+ /**
+ * rememberMe() - Write a persistent cookie that expires after a number of seconds in the future. If no number of
+ * seconds is specified, then this defaults to self::$_rememberMeSeconds. Due to clock errors on end users' systems,
+ * large values are recommended to avoid undesirable expiration of session cookies.
+ *
+ * @param $seconds integer - OPTIONAL specifies TTL for cookie in seconds from present time
+ * @return void
+ */
+ public static function rememberMe($seconds = null)
+ {
+ $seconds = (int) $seconds;
+ $seconds = ($seconds > 0) ? $seconds : self::$_rememberMeSeconds;
+
+ self::rememberUntil($seconds);
+ }
+
+
+ /**
+ * forgetMe() - Write a volatile session cookie, removing any persistent cookie that may have existed. The session
+ * would end upon, for example, termination of a web browser program.
+ *
+ * @return void
+ */
+ public static function forgetMe()
+ {
+ self::rememberUntil(0);
+ }
+
+
+ /**
+ * rememberUntil() - This method does the work of changing the state of the session cookie and making
+ * sure that it gets resent to the browser via regenerateId()
+ *
+ * @param int $seconds
+ * @return void
+ */
+ public static function rememberUntil($seconds = 0)
+ {
+ if (self::$_unitTestEnabled) {
+ self::regenerateId();
+ return;
+ }
+
+ $cookieParams = session_get_cookie_params();
+
+ session_set_cookie_params(
+ $seconds,
+ $cookieParams['path'],
+ $cookieParams['domain'],
+ $cookieParams['secure']
+ );
+
+ // normally "rememberMe()" represents a security context change, so should use new session id
+ self::regenerateId();
+ }
+
+
+ /**
+ * sessionExists() - whether or not a session exists for the current request
+ *
+ * @return bool
+ */
+ public static function sessionExists()
+ {
+ if (ini_get('session.use_cookies') == '1' && isset($_COOKIE[session_name()])) {
+ return true;
+ } elseif (!empty($_REQUEST[session_name()])) {
+ return true;
+ } elseif (self::$_unitTestEnabled) {
+ return true;
+ }
+
+ return false;
+ }
+
+
+ /**
+ * Whether or not session has been destroyed via session_destroy()
+ *
+ * @return bool
+ */
+ public static function isDestroyed()
+ {
+ return self::$_destroyed;
+ }
+
+
+ /**
+ * start() - Start the session.
+ *
+ * @param bool|array $options OPTIONAL Either user supplied options, or flag indicating if start initiated automatically
+ * @throws Zend_Session_Exception
+ * @return void
+ */
+ public static function start($options = false)
+ {
+ if (self::$_sessionStarted && self::$_destroyed) {
+ require_once 'Zend/Session/Exception.php';
+ throw new Zend_Session_Exception('The session was explicitly destroyed during this request, attempting to re-start is not allowed.');
+ }
+
+ if (self::$_sessionStarted) {
+ return; // already started
+ }
+
+ // make sure our default options (at the least) have been set
+ if (!self::$_defaultOptionsSet) {
+ self::setOptions(is_array($options) ? $options : array());
+ }
+
+ // In strict mode, do not allow auto-starting Zend_Session, such as via "new Zend_Session_Namespace()"
+ if (self::$_strict && $options === true) {
+ /** @see Zend_Session_Exception */
+ require_once 'Zend/Session/Exception.php';
+ throw new Zend_Session_Exception('You must explicitly start the session with Zend_Session::start() when session options are set to strict.');
+ }
+
+ $filename = $linenum = null;
+ if (!self::$_unitTestEnabled && headers_sent($filename, $linenum)) {
+ /** @see Zend_Session_Exception */
+ require_once 'Zend/Session/Exception.php';
+ throw new Zend_Session_Exception("Session must be started before any output has been sent to the browser;"
+ . " output started in {$filename}/{$linenum}");
+ }
+
+ // See http://www.php.net/manual/en/ref.session.php for explanation
+ if (!self::$_unitTestEnabled && defined('SID')) {
+ /** @see Zend_Session_Exception */
+ require_once 'Zend/Session/Exception.php';
+ throw new Zend_Session_Exception('session has already been started by session.auto-start or session_start()');
+ }
+
+ /**
+ * Hack to throw exceptions on start instead of php errors
+ * @see http://framework.zend.com/issues/browse/ZF-1325
+ */
+
+ $errorLevel = (is_int(self::$_throwStartupExceptions)) ? self::$_throwStartupExceptions : E_ALL;
+
+ /** @see Zend_Session_Exception */
+ if (!self::$_unitTestEnabled) {
+
+ if (self::$_throwStartupExceptions) {
+ require_once 'Zend/Session/Exception.php';
+ set_error_handler(array('Zend_Session_Exception', 'handleSessionStartError'), $errorLevel);
+ }
+
+ $startedCleanly = session_start();
+
+ if (self::$_throwStartupExceptions) {
+ restore_error_handler();
+ }
+
+ if (!$startedCleanly || Zend_Session_Exception::$sessionStartError != null) {
+ if (self::$_throwStartupExceptions) {
+ set_error_handler(array('Zend_Session_Exception', 'handleSilentWriteClose'), $errorLevel);
+ }
+ session_write_close();
+ if (self::$_throwStartupExceptions) {
+ restore_error_handler();
+ throw new Zend_Session_Exception(__CLASS__ . '::' . __FUNCTION__ . '() - ' . Zend_Session_Exception::$sessionStartError);
+ }
+ }
+ }
+
+ parent::$_readable = true;
+ parent::$_writable = true;
+ self::$_sessionStarted = true;
+ if (self::$_regenerateIdState === -1) {
+ self::regenerateId();
+ }
+
+ // run validators if they exist
+ if (isset($_SESSION['__ZF']['VALID'])) {
+ self::_processValidators();
+ }
+
+ self::_processStartupMetadataGlobal();
+ }
+
+
+ /**
+ * _processGlobalMetadata() - this method initizes the sessions GLOBAL
+ * metadata, mostly global data expiration calculations.
+ *
+ * @return void
+ */
+ private static function _processStartupMetadataGlobal()
+ {
+ // process global metadata
+ if (isset($_SESSION['__ZF'])) {
+
+ // expire globally expired values
+ foreach ($_SESSION['__ZF'] as $namespace => $namespace_metadata) {
+
+ // Expire Namespace by Time (ENT)
+ if (isset($namespace_metadata['ENT']) && ($namespace_metadata['ENT'] > 0) && (time() > $namespace_metadata['ENT']) ) {
+ unset($_SESSION[$namespace]);
+ unset($_SESSION['__ZF'][$namespace]['ENT']);
+ }
+
+ // Expire Namespace by Global Hop (ENGH)
+ if (isset($namespace_metadata['ENGH']) && $namespace_metadata['ENGH'] >= 1) {
+ $_SESSION['__ZF'][$namespace]['ENGH']--;
+
+ if ($_SESSION['__ZF'][$namespace]['ENGH'] === 0) {
+ if (isset($_SESSION[$namespace])) {
+ parent::$_expiringData[$namespace] = $_SESSION[$namespace];
+ unset($_SESSION[$namespace]);
+ }
+ unset($_SESSION['__ZF'][$namespace]['ENGH']);
+ }
+ }
+
+ // Expire Namespace Variables by Time (ENVT)
+ if (isset($namespace_metadata['ENVT'])) {
+ foreach ($namespace_metadata['ENVT'] as $variable => $time) {
+ if (time() > $time) {
+ unset($_SESSION[$namespace][$variable]);
+ unset($_SESSION['__ZF'][$namespace]['ENVT'][$variable]);
+
+ if (empty($_SESSION['__ZF'][$namespace]['ENVT'])) {
+ unset($_SESSION['__ZF'][$namespace]['ENVT']);
+ }
+ }
+ }
+ }
+
+ // Expire Namespace Variables by Global Hop (ENVGH)
+ if (isset($namespace_metadata['ENVGH'])) {
+ foreach ($namespace_metadata['ENVGH'] as $variable => $hops) {
+ $_SESSION['__ZF'][$namespace]['ENVGH'][$variable]--;
+
+ if ($_SESSION['__ZF'][$namespace]['ENVGH'][$variable] === 0) {
+ if (isset($_SESSION[$namespace][$variable])) {
+ parent::$_expiringData[$namespace][$variable] = $_SESSION[$namespace][$variable];
+ unset($_SESSION[$namespace][$variable]);
+ }
+ unset($_SESSION['__ZF'][$namespace]['ENVGH'][$variable]);
+ }
+ }
+ }
+ }
+
+ if (isset($namespace) && empty($_SESSION['__ZF'][$namespace])) {
+ unset($_SESSION['__ZF'][$namespace]);
+ }
+ }
+
+ if (isset($_SESSION['__ZF']) && empty($_SESSION['__ZF'])) {
+ unset($_SESSION['__ZF']);
+ }
+ }
+
+
+ /**
+ * isStarted() - convenience method to determine if the session is already started.
+ *
+ * @return bool
+ */
+ public static function isStarted()
+ {
+ return self::$_sessionStarted;
+ }
+
+
+ /**
+ * isRegenerated() - convenience method to determine if session_regenerate_id()
+ * has been called during this request by Zend_Session.
+ *
+ * @return bool
+ */
+ public static function isRegenerated()
+ {
+ return ( (self::$_regenerateIdState > 0) ? true : false );
+ }
+
+
+ /**
+ * getId() - get the current session id
+ *
+ * @return string
+ */
+ public static function getId()
+ {
+ return session_id();
+ }
+
+
+ /**
+ * setId() - set an id to a user specified id
+ *
+ * @throws Zend_Session_Exception
+ * @param string $id
+ * @return void
+ */
+ public static function setId($id)
+ {
+ if (!self::$_unitTestEnabled && defined('SID')) {
+ /** @see Zend_Session_Exception */
+ require_once 'Zend/Session/Exception.php';
+ throw new Zend_Session_Exception('The session has already been started. The session id must be set first.');
+ }
+
+ if (!self::$_unitTestEnabled && headers_sent($filename, $linenum)) {
+ /** @see Zend_Session_Exception */
+ require_once 'Zend/Session/Exception.php';
+ throw new Zend_Session_Exception("You must call ".__CLASS__.'::'.__FUNCTION__.
+ "() before any output has been sent to the browser; output started in {$filename}/{$linenum}");
+ }
+
+ if (!is_string($id) || $id === '') {
+ /** @see Zend_Session_Exception */
+ require_once 'Zend/Session/Exception.php';
+ throw new Zend_Session_Exception('You must provide a non-empty string as a session identifier.');
+ }
+
+ session_id($id);
+ }
+
+
+ /**
+ * registerValidator() - register a validator that will attempt to validate this session for
+ * every future request
+ *
+ * @param Zend_Session_Validator_Interface $validator
+ * @return void
+ */
+ public static function registerValidator(Zend_Session_Validator_Interface $validator)
+ {
+ $validator->setup();
+ }
+
+
+ /**
+ * stop() - Disable write access. Optionally disable read (not implemented).
+ *
+ * @return void
+ */
+ public static function stop()
+ {
+ parent::$_writable = false;
+ }
+
+
+ /**
+ * writeClose() - Shutdown the sesssion, close writing and detach $_SESSION from the back-end storage mechanism.
+ * This will complete the internal data transformation on this request.
+ *
+ * @param bool $readonly - OPTIONAL remove write access (i.e. throw error if Zend_Session's attempt writes)
+ * @return void
+ */
+ public static function writeClose($readonly = true)
+ {
+ if (self::$_unitTestEnabled) {
+ return;
+ }
+
+ if (self::$_writeClosed) {
+ return;
+ }
+
+ if ($readonly) {
+ parent::$_writable = false;
+ }
+
+ session_write_close();
+ self::$_writeClosed = true;
+ }
+
+
+ /**
+ * destroy() - This is used to destroy session data, and optionally, the session cookie itself
+ *
+ * @param bool $remove_cookie - OPTIONAL remove session id cookie, defaults to true (remove cookie)
+ * @param bool $readonly - OPTIONAL remove write access (i.e. throw error if Zend_Session's attempt writes)
+ * @return void
+ */
+ public static function destroy($remove_cookie = true, $readonly = true)
+ {
+ if (self::$_unitTestEnabled) {
+ return;
+ }
+
+ if (self::$_destroyed) {
+ return;
+ }
+
+ if ($readonly) {
+ parent::$_writable = false;
+ }
+
+ session_destroy();
+ self::$_destroyed = true;
+
+ if ($remove_cookie) {
+ self::expireSessionCookie();
+ }
+ }
+
+
+ /**
+ * expireSessionCookie() - Sends an expired session id cookie, causing the client to delete the session cookie
+ *
+ * @return void
+ */
+ public static function expireSessionCookie()
+ {
+ if (self::$_unitTestEnabled) {
+ return;
+ }
+
+ if (self::$_sessionCookieDeleted) {
+ return;
+ }
+
+ self::$_sessionCookieDeleted = true;
+
+ if (isset($_COOKIE[session_name()])) {
+ $cookie_params = session_get_cookie_params();
+
+ setcookie(
+ session_name(),
+ false,
+ 315554400, // strtotime('1980-01-01'),
+ $cookie_params['path'],
+ $cookie_params['domain'],
+ $cookie_params['secure']
+ );
+ }
+ }
+
+
+ /**
+ * _processValidator() - internal function that is called in the existence of VALID metadata
+ *
+ * @throws Zend_Session_Exception
+ * @return void
+ */
+ private static function _processValidators()
+ {
+ foreach ($_SESSION['__ZF']['VALID'] as $validator_name => $valid_data) {
+ if (!class_exists($validator_name)) {
+ require_once 'Zend/Loader.php';
+ Zend_Loader::loadClass($validator_name);
+ }
+ $validator = new $validator_name;
+ if ($validator->validate() === false) {
+ /** @see Zend_Session_Exception */
+ require_once 'Zend/Session/Exception.php';
+ throw new Zend_Session_Exception("This session is not valid according to {$validator_name}.");
+ }
+ }
+ }
+
+
+ /**
+ * namespaceIsset() - check to see if a namespace is set
+ *
+ * @param string $namespace
+ * @return bool
+ */
+ public static function namespaceIsset($namespace)
+ {
+ return parent::_namespaceIsset($namespace);
+ }
+
+
+ /**
+ * namespaceUnset() - unset a namespace or a variable within a namespace
+ *
+ * @param string $namespace
+ * @throws Zend_Session_Exception
+ * @return void
+ */
+ public static function namespaceUnset($namespace)
+ {
+ parent::_namespaceUnset($namespace);
+ Zend_Session_Namespace::resetSingleInstance($namespace);
+ }
+
+
+ /**
+ * namespaceGet() - get all variables in a namespace
+ * Deprecated: Use getIterator() in Zend_Session_Namespace.
+ *
+ * @param string $namespace
+ * @return array
+ */
+ public static function namespaceGet($namespace)
+ {
+ return parent::_namespaceGetAll($namespace);
+ }
+
+
+ /**
+ * getIterator() - return an iteratable object for use in foreach and the like,
+ * this completes the IteratorAggregate interface
+ *
+ * @throws Zend_Session_Exception
+ * @return ArrayObject
+ */
+ public static function getIterator()
+ {
+ if (parent::$_readable === false) {
+ /** @see Zend_Session_Exception */
+ require_once 'Zend/Session/Exception.php';
+ throw new Zend_Session_Exception(parent::_THROW_NOT_READABLE_MSG);
+ }
+
+ $spaces = array();
+ if (isset($_SESSION)) {
+ $spaces = array_keys($_SESSION);
+ foreach($spaces as $key => $space) {
+ if (!strncmp($space, '__', 2) || !is_array($_SESSION[$space])) {
+ unset($spaces[$key]);
+ }
+ }
+ }
+
+ return new ArrayObject(array_merge($spaces, array_keys(parent::$_expiringData)));
+ }
+
+
+ /**
+ * isWritable() - returns a boolean indicating if namespaces can write (use setters)
+ *
+ * @return bool
+ */
+ public static function isWritable()
+ {
+ return parent::$_writable;
+ }
+
+
+ /**
+ * isReadable() - returns a boolean indicating if namespaces can write (use setters)
+ *
+ * @return bool
+ */
+ public static function isReadable()
+ {
+ return parent::$_readable;
+ }
+
+}
--- /dev/null
+<?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_TimeSync
+ * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @version $Id$
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+/**
+ * Zend_Date
+ */
+require_once 'Zend/Date.php';
+
+/**
+ * @category Zend
+ * @package Zend_TimeSync
+ * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+class Zend_TimeSync implements IteratorAggregate
+{
+ /**
+ * Set the default timeserver protocol to "Ntp". This will be called
+ * when no protocol is specified
+ */
+ const DEFAULT_PROTOCOL = 'Ntp';
+
+ /**
+ * Contains array of timeserver objects
+ *
+ * @var array
+ */
+ protected $_timeservers = array();
+
+ /**
+ * Holds a reference to the timeserver that is currently being used
+ *
+ * @var object
+ */
+ protected $_current;
+
+ /**
+ * Allowed timeserver schemes
+ *
+ * @var array
+ */
+ protected $_allowedSchemes = array(
+ 'Ntp',
+ 'Sntp'
+ );
+
+ /**
+ * Configuration array, set using the constructor or using
+ * ::setOptions() or ::setOption()
+ *
+ * @var array
+ */
+ public static $options = array(
+ 'timeout' => 1
+ );
+
+ /**
+ * Zend_TimeSync constructor
+ *
+ * @param string|array $target - OPTIONAL single timeserver, or an array of timeservers.
+ * @param string $alias - OPTIONAL an alias for this timeserver
+ * @return object
+ */
+ public function __construct($target = null, $alias = null)
+ {
+ if ($target !== null) {
+ $this->addServer($target, $alias);
+ }
+ }
+
+ /**
+ * getIterator() - return an iteratable object for use in foreach and the like,
+ * this completes the IteratorAggregate interface
+ *
+ * @return ArrayObject
+ */
+ public function getIterator()
+ {
+ return new ArrayObject($this->_timeservers);
+ }
+
+ /**
+ * Add a timeserver or multiple timeservers
+ *
+ * Server should be a single string representation of a timeserver,
+ * or a structured array listing multiple timeservers.
+ *
+ * If you provide an array of timeservers in the $target variable,
+ * $alias will be ignored. you can enter these as the array key
+ * in the provided array, which should be structured as follows:
+ *
+ * <code>
+ * $example = array(
+ * 'server_a' => 'ntp://127.0.0.1',
+ * 'server_b' => 'ntp://127.0.0.1:123',
+ * 'server_c' => 'ntp://[2000:364:234::2.5]',
+ * 'server_d' => 'ntp://[2000:364:234::2.5]:123'
+ * );
+ * </code>
+ *
+ * If no port number has been suplied, the default matching port
+ * number will be used.
+ *
+ * Supported protocols are:
+ * - ntp
+ * - sntp
+ *
+ * @param string|array $target - Single timeserver, or an array of timeservers.
+ * @param string $alias - OPTIONAL an alias for this timeserver
+ * @throws Zend_TimeSync_Exception
+ */
+ public function addServer($target, $alias = null)
+ {
+ if (is_array($target)) {
+ foreach ($target as $key => $server) {
+ $this->_addServer($server, $key);
+ }
+ } else {
+ $this->_addServer($target, $alias);
+ }
+ }
+
+ /**
+ * Sets the value for the given options
+ *
+ * This will replace any currently defined options.
+ *
+ * @param array $options - An array of options to be set
+ */
+ public static function setOptions(array $options)
+ {
+ foreach ($options as $key => $value) {
+ Zend_TimeSync::$options[$key] = $value;
+ }
+ }
+
+ /**
+ * Marks a nameserver as current
+ *
+ * @param string|integer $alias - The alias from the timeserver to set as current
+ * @throws Zend_TimeSync_Exception
+ */
+ public function setServer($alias)
+ {
+ if (isset($this->_timeservers[$alias]) === true) {
+ $this->_current = $this->_timeservers[$alias];
+ } else {
+ require_once 'Zend/TimeSync/Exception.php';
+ throw new Zend_TimeSync_Exception("'$alias' does not point to valid timeserver");
+ }
+ }
+
+ /**
+ * Returns the value to the option
+ *
+ * @param string $key - The option's identifier
+ * @return mixed
+ * @throws Zend_TimeSync_Exception
+ */
+ public static function getOptions($key = null)
+ {
+ if ($key == null) {
+ return Zend_TimeSync::$options;
+ }
+
+ if (isset(Zend_TimeSync::$options[$key]) === true) {
+ return Zend_TimeSync::$options[$key];
+ } else {
+ require_once 'Zend/TimeSync/Exception.php';
+ throw new Zend_TimeSync_Exception("'$key' does not point to valid option");
+ }
+ }
+
+ /**
+ * Return a specified timeserver by alias
+ * If no alias is given it will return the current timeserver
+ *
+ * @param string|integer $alias - The alias from the timeserver to return
+ * @return object
+ * @throws Zend_TimeSync_Exception
+ */
+ public function getServer($alias = null)
+ {
+ if ($alias === null) {
+ if (isset($this->_current) && $this->_current !== false) {
+ return $this->_current;
+ } else {
+ require_once 'Zend/TimeSync/Exception.php';
+ throw new Zend_TimeSync_Exception('there is no timeserver set');
+ }
+ }
+ if (isset($this->_timeservers[$alias]) === true) {
+ return $this->_timeservers[$alias];
+ } else {
+ require_once 'Zend/TimeSync/Exception.php';
+ throw new Zend_TimeSync_Exception("'$alias' does not point to valid timeserver");
+ }
+ }
+
+ /**
+ * Returns information sent/returned from the current timeserver
+ *
+ * @return array
+ */
+ public function getInfo()
+ {
+ return $this->getServer()->getInfo();
+ }
+
+ /**
+ * Query the timeserver list using the fallback mechanism
+ *
+ * If there are multiple servers listed, this method will act as a
+ * facade and will try to return the date from the first server that
+ * returns a valid result.
+ *
+ * @param $locale - OPTIONAL locale
+ * @return object
+ * @throws Zend_TimeSync_Exception
+ */
+ public function getDate($locale = null)
+ {
+ require_once 'Zend/TimeSync/Exception.php';
+ foreach ($this->_timeservers as $alias => $server) {
+ $this->_current = $server;
+ try {
+ return $server->getDate($locale);
+ } catch (Zend_TimeSync_Exception $e) {
+ if (!isset($masterException)) {
+ $masterException = new Zend_TimeSync_Exception('all timeservers are bogus');
+ }
+ $masterException->addException($e);
+ }
+ }
+
+ throw $masterException;
+ }
+
+ /**
+ * Adds a timeserver object to the timeserver list
+ *
+ * @param string|array $target - Single timeserver, or an array of timeservers.
+ * @param string $alias - An alias for this timeserver
+ */
+ protected function _addServer($target, $alias)
+ {
+ if ($pos = strpos($target, '://')) {
+ $protocol = substr($target, 0, $pos);
+ $adress = substr($target, $pos + 3);
+ } else {
+ $adress = $target;
+ $protocol = self::DEFAULT_PROTOCOL;
+ }
+
+ if ($pos = strrpos($adress, ':')) {
+ $posbr = strpos($adress, ']');
+ if ($posbr and ($pos > $posbr)) {
+ $port = substr($adress, $pos + 1);
+ $adress = substr($adress, 0, $pos);
+ } else if (!$posbr and $pos) {
+ $port = substr($adress, $pos + 1);
+ $adress = substr($adress, 0, $pos);
+ } else {
+ $port = null;
+ }
+ } else {
+ $port = null;
+ }
+
+ $protocol = ucfirst(strtolower($protocol));
+ if (!in_array($protocol, $this->_allowedSchemes)) {
+ require_once 'Zend/TimeSync/Exception.php';
+ throw new Zend_TimeSync_Exception("'$protocol' is not a supported protocol");
+ }
+
+ $className = 'Zend_TimeSync_' . $protocol;
+ if (!class_exists($className)) {
+ require_once 'Zend/Loader.php';
+ Zend_Loader::loadClass($className);
+ }
+ $timeServerObj = new $className($adress, $port);
+
+ $this->_timeservers[$alias] = $timeServerObj;
+ }
+}
--- /dev/null
+<?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_Translate
+ * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ * @version $Id$
+ */
+
+/**
+ * @see Zend_Loader
+ */
+require_once 'Zend/Loader.php';
+
+
+/**
+ * @category Zend
+ * @package Zend_Translate
+ * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+class Zend_Translate {
+ /**
+ * Adapter names constants
+ */
+ const AN_ARRAY = 'Array';
+ const AN_CSV = 'Csv';
+ const AN_GETTEXT = 'Gettext';
+ const AN_INI = 'Ini';
+ const AN_QT = 'Qt';
+ const AN_TBX = 'Tbx';
+ const AN_TMX = 'Tmx';
+ const AN_XLIFF = 'Xliff';
+ const AN_XMLTM = 'XmlTm';
+
+ const LOCALE_DIRECTORY = 'directory';
+ const LOCALE_FILENAME = 'filename';
+
+ /**
+ * Adapter
+ *
+ * @var Zend_Translate_Adapter
+ */
+ private $_adapter;
+ private static $_cache = null;
+
+ /**
+ * Generates the standard translation object
+ *
+ * @param string $adapter Adapter to use
+ * @param array $data Translation source data for the adapter
+ * Depends on the Adapter
+ * @param string|Zend_Locale $locale OPTIONAL locale to use
+ * @param array $options OPTIONAL options for the adapter
+ * @throws Zend_Translate_Exception
+ */
+ public function __construct($adapter, $data, $locale = null, array $options = array())
+ {
+ $this->setAdapter($adapter, $data, $locale, $options);
+ }
+
+ /**
+ * Sets a new adapter
+ *
+ * @param string $adapter Adapter to use
+ * @param string|array $data Translation data
+ * @param string|Zend_Locale $locale OPTIONAL locale to use
+ * @param array $options OPTIONAL Options to use
+ * @throws Zend_Translate_Exception
+ */
+ public function setAdapter($adapter, $data, $locale = null, array $options = array())
+ {
+ if (Zend_Loader::isReadable('Zend/Translate/Adapter/' . ucfirst($adapter). '.php')) {
+ $adapter = 'Zend_Translate_Adapter_' . ucfirst($adapter);
+ }
+
+ if (!class_exists($adapter)) {
+ Zend_Loader::loadClass($adapter);
+ }
+
+ if (self::$_cache !== null) {
+ call_user_func(array($adapter, 'setCache'), self::$_cache);
+ }
+ $this->_adapter = new $adapter($data, $locale, $options);
+ if (!$this->_adapter instanceof Zend_Translate_Adapter) {
+ require_once 'Zend/Translate/Exception.php';
+ throw new Zend_Translate_Exception("Adapter " . $adapter . " does not extend Zend_Translate_Adapter");
+ }
+ }
+
+ /**
+ * Returns the adapters name and it's options
+ *
+ * @return Zend_Translate_Adapter
+ */
+ public function getAdapter()
+ {
+ return $this->_adapter;
+ }
+
+ /**
+ * Returns the set cache
+ *
+ * @return Zend_Cache_Core The set cache
+ */
+ public static function getCache()
+ {
+ return self::$_cache;
+ }
+
+ /**
+ * Sets a cache for all instances of Zend_Translate
+ *
+ * @param Zend_Cache_Core $cache Cache to store to
+ * @return void
+ */
+ public static function setCache(Zend_Cache_Core $cache)
+ {
+ self::$_cache = $cache;
+ }
+
+ /**
+ * Returns true when a cache is set
+ *
+ * @return boolean
+ */
+ public static function hasCache()
+ {
+ if (self::$_cache !== null) {
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Removes any set cache
+ *
+ * @return void
+ */
+ public static function removeCache()
+ {
+ self::$_cache = null;
+ }
+
+ /**
+ * Clears all set cache data
+ *
+ * @return void
+ */
+ public static function clearCache()
+ {
+ self::$_cache->clean();
+ }
+
+ /**
+ * Calls all methods from the adapter
+ */
+ public function __call($method, array $options)
+ {
+ if (method_exists($this->_adapter, $method)) {
+ return call_user_func_array(array($this->_adapter, $method), $options);
+ }
+ require_once 'Zend/Translate/Exception.php';
+ throw new Zend_Translate_Exception("Unknown method '" . $method . "' called!");
+ }
+}
*
* @category Zend
* @package Zend_Uri
- * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id$
*/
-/**
- * @see Zend_Loader
- */
-require_once 'Zend/Loader.php';
-
/**
* Abstract class for all Zend_Uri handlers
*
* @category Zend
* @package Zend_Uri
- * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
abstract class Zend_Uri
*/
protected $_scheme = '';
+ /**
+ * Global configuration array
+ *
+ * @var array
+ */
+ static protected $_config = array(
+ 'allow_unwise' => false
+ );
+
/**
* Return a string representation of this URI.
*
break;
}
- Zend_Loader::loadClass($className);
+ if (!class_exists($className)) {
+ require_once 'Zend/Loader.php';
+ Zend_Loader::loadClass($className);
+ }
$schemeHandler = new $className($scheme, $schemeSpecific);
return $schemeHandler;
}
}
+ /**
+ * Set global configuration options
+ *
+ * @param array $config
+ */
+ static public function setConfig(array $config)
+ {
+ foreach ($config as $k => $v) {
+ self::$_config[$k] = $v;
+ }
+ }
+
/**
* Zend_Uri and its subclasses cannot be instantiated directly.
* Use Zend_Uri::factory() to return a new Zend_Uri object.
--- /dev/null
+<?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_Validate
+ * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ * @version $Id$
+ */
+
+/**
+ * @see Zend_Validate_Interface
+ */
+require_once 'Zend/Validate/Interface.php';
+
+/**
+ * @category Zend
+ * @package Zend_Validate
+ * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+class Zend_Validate implements Zend_Validate_Interface
+{
+ /**
+ * Validator chain
+ *
+ * @var array
+ */
+ protected $_validators = array();
+
+ /**
+ * Array of validation failure messages
+ *
+ * @var array
+ */
+ protected $_messages = array();
+
+ /**
+ * Default Namespaces
+ *
+ * @var array
+ */
+ protected static $_defaultNamespaces = array();
+
+ /**
+ * Array of validation failure message codes
+ *
+ * @var array
+ * @deprecated Since 1.5.0
+ */
+ protected $_errors = array();
+
+ /**
+ * Adds a validator to the end of the chain
+ *
+ * If $breakChainOnFailure is true, then if the validator fails, the next validator in the chain,
+ * if one exists, will not be executed.
+ *
+ * @param Zend_Validate_Interface $validator
+ * @param boolean $breakChainOnFailure
+ * @return Zend_Validate Provides a fluent interface
+ */
+ public function addValidator(Zend_Validate_Interface $validator, $breakChainOnFailure = false)
+ {
+ $this->_validators[] = array(
+ 'instance' => $validator,
+ 'breakChainOnFailure' => (boolean) $breakChainOnFailure
+ );
+ return $this;
+ }
+
+ /**
+ * Returns true if and only if $value passes all validations in the chain
+ *
+ * Validators are run in the order in which they were added to the chain (FIFO).
+ *
+ * @param mixed $value
+ * @return boolean
+ */
+ public function isValid($value)
+ {
+ $this->_messages = array();
+ $this->_errors = array();
+ $result = true;
+ foreach ($this->_validators as $element) {
+ $validator = $element['instance'];
+ if ($validator->isValid($value)) {
+ continue;
+ }
+ $result = false;
+ $messages = $validator->getMessages();
+ $this->_messages = array_merge($this->_messages, $messages);
+ $this->_errors = array_merge($this->_errors, array_keys($messages));
+ if ($element['breakChainOnFailure']) {
+ break;
+ }
+ }
+ return $result;
+ }
+
+ /**
+ * Defined by Zend_Validate_Interface
+ *
+ * Returns array of validation failure messages
+ *
+ * @return array
+ */
+ public function getMessages()
+ {
+ return $this->_messages;
+ }
+
+ /**
+ * Defined by Zend_Validate_Interface
+ *
+ * Returns array of validation failure message codes
+ *
+ * @return array
+ * @deprecated Since 1.5.0
+ */
+ public function getErrors()
+ {
+ return $this->_errors;
+ }
+
+ /**
+ * Returns the set default namespaces
+ *
+ * @return array
+ */
+ public static function getDefaultNamespaces()
+ {
+ return self::$_defaultNamespaces;
+ }
+
+ /**
+ * Sets new default namespaces
+ *
+ * @param array|string $namespace
+ * @return null
+ */
+ public static function setDefaultNamespaces($namespace)
+ {
+ if (!is_array($namespace)) {
+ $namespace = array((string) $namespace);
+ }
+
+ self::$_defaultNamespaces = $namespace;
+ }
+
+ /**
+ * Adds a new default namespace
+ *
+ * @param array|string $namespace
+ * @return null
+ */
+ public static function addDefaultNamespaces($namespace)
+ {
+ if (!is_array($namespace)) {
+ $namespace = array((string) $namespace);
+ }
+
+ self::$_defaultNamespaces = array_unique(array_merge(self::$_defaultNamespaces, $namespace));
+ }
+
+ /**
+ * Returns true when defaultNamespaces are set
+ *
+ * @return boolean
+ */
+ public static function hasDefaultNamespaces()
+ {
+ return (!empty(self::$_defaultNamespaces));
+ }
+
+ /**
+ * @param mixed $value
+ * @param string $classBaseName
+ * @param array $args OPTIONAL
+ * @param mixed $namespaces OPTIONAL
+ * @return boolean
+ * @throws Zend_Validate_Exception
+ */
+ public static function is($value, $classBaseName, array $args = array(), $namespaces = array())
+ {
+ $namespaces = array_merge((array) $namespaces, self::$_defaultNamespaces, array('Zend_Validate'));
+ foreach ($namespaces as $namespace) {
+ $className = $namespace . '_' . ucfirst($classBaseName);
+ try {
+ if (!class_exists($className)) {
+ require_once 'Zend/Loader.php';
+ Zend_Loader::loadClass($className);
+ }
+ $class = new ReflectionClass($className);
+ if ($class->implementsInterface('Zend_Validate_Interface')) {
+ if ($class->hasMethod('__construct')) {
+ $object = $class->newInstanceArgs($args);
+ } else {
+ $object = $class->newInstance();
+ }
+ return $object->isValid($value);
+ }
+ } catch (Zend_Validate_Exception $ze) {
+ // if there is an exception while validating throw it
+ throw $ze;
+ } catch (Zend_Exception $ze) {
+ // fallthrough and continue for missing validation classes
+ }
+ }
+ require_once 'Zend/Validate/Exception.php';
+ throw new Zend_Validate_Exception("Validate class not found from basename '$classBaseName'");
+ }
+
+ /**
+ * Returns the maximum allowed message length
+ *
+ * @return integer
+ */
+ public static function getMessageLength()
+ {
+ require_once 'Zend/Validate/Abstract.php';
+ return Zend_Validate_Abstract::getMessageLength();
+ }
+
+ /**
+ * Sets the maximum allowed message length
+ *
+ * @param integer $length
+ */
+ public static function setMessageLength($length = -1)
+ {
+ require_once 'Zend/Validate/Abstract.php';
+ Zend_Validate_Abstract::setMessageLength($length);
+ }
+}
*
* @category Zend
* @package Zend_Version
- * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id$
*/
*
* @category Zend
* @package Zend_Version
- * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
final class Zend_Version
/**
* Zend Framework version identification - see compareVersion()
*/
- const VERSION = '1.7.3';
+ const VERSION = '1.9.4';
/**
* Compare the specified Zend Framework version string $version
- * with the current Zend_Version::VERSION of the Zend Framework.
+ * with the current Zend_Version::VERSION of Zend Framework.
*
* @param string $version A version string (e.g. "0.7.1").
* @return boolean -1 if the $version is older,
*/
public static function compareVersion($version)
{
- return version_compare($version, self::VERSION);
+ $version = strtolower($version);
+ $version = preg_replace('/(\d)pr(\d?)/', '$1a$2', $version);
+ return version_compare($version, strtolower(self::VERSION));
}
}
--- /dev/null
+<?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_View
+ * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ * @version $Id$
+ */
+
+
+/**
+ * Abstract master class for extension.
+ */
+require_once 'Zend/View/Abstract.php';
+
+
+/**
+ * Concrete class for handling view scripts.
+ *
+ * @category Zend
+ * @package Zend_View
+ * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+class Zend_View extends Zend_View_Abstract
+{
+ /**
+ * Whether or not to use streams to mimic short tags
+ * @var bool
+ */
+ private $_useViewStream = false;
+
+ /**
+ * Whether or not to use stream wrapper if short_open_tag is false
+ * @var bool
+ */
+ private $_useStreamWrapper = false;
+
+ /**
+ * Constructor
+ *
+ * Register Zend_View_Stream stream wrapper if short tags are disabled.
+ *
+ * @param array $config
+ * @return void
+ */
+ public function __construct($config = array())
+ {
+ $this->_useViewStream = (bool) ini_get('short_open_tag') ? false : true;
+ if ($this->_useViewStream) {
+ if (!in_array('zend.view', stream_get_wrappers())) {
+ require_once 'Zend/View/Stream.php';
+ stream_wrapper_register('zend.view', 'Zend_View_Stream');
+ }
+ }
+
+ if (array_key_exists('useStreamWrapper', $config)) {
+ $this->setUseStreamWrapper($config['useStreamWrapper']);
+ }
+
+ parent::__construct($config);
+ }
+
+ /**
+ * Set flag indicating if stream wrapper should be used if short_open_tag is off
+ *
+ * @param bool $flag
+ * @return Zend_View
+ */
+ public function setUseStreamWrapper($flag)
+ {
+ $this->_useStreamWrapper = (bool) $flag;
+ return $this;
+ }
+
+ /**
+ * Should the stream wrapper be used if short_open_tag is off?
+ *
+ * @return bool
+ */
+ public function useStreamWrapper()
+ {
+ return $this->_useStreamWrapper;
+ }
+
+ /**
+ * Includes the view script in a scope with only public $this variables.
+ *
+ * @param string The view script to execute.
+ */
+ protected function _run()
+ {
+ if ($this->_useViewStream && $this->useStreamWrapper()) {
+ include 'zend.view://' . func_get_arg(0);
+ } else {
+ include func_get_arg(0);
+ }
+ }
+}