From 63b1164049778d4946fcc8bd851bdaf406d7ca37 Mon Sep 17 00:00:00 2001 From: Petr Skoda Date: Sat, 24 Oct 2009 19:49:26 +0000 Subject: [PATCH] MDL-20632 latest zend framework lib import --- lib/zend/Zend/Acl.php | 1119 ++++++++++++ lib/zend/Zend/Application.php | 397 +++++ lib/zend/Zend/Auth.php | 169 ++ lib/zend/Zend/Cache.php | 245 +++ lib/zend/Zend/Config.php | 456 +++++ lib/zend/Zend/Crypt.php | 167 ++ lib/zend/Zend/Currency.php | 624 +++++++ lib/zend/Zend/Date.php | 1246 ++++++------- lib/zend/Zend/Db.php | 281 +++ lib/zend/Zend/Debug.php | 108 ++ lib/zend/Zend/Dojo.php | 87 + lib/zend/Zend/Exception.php | 5 +- lib/zend/Zend/Feed.php | 411 +++++ lib/zend/Zend/Filter.php | 192 ++ lib/zend/Zend/Form.php | 3079 +++++++++++++++++++++++++++++++++ lib/zend/Zend/Gdata.php | 66 +- lib/zend/Zend/InfoCard.php | 497 ++++++ lib/zend/Zend/Json.php | 339 ++++ lib/zend/Zend/Layout.php | 795 +++++++++ lib/zend/Zend/Ldap.php | 1476 ++++++++++++++++ lib/zend/Zend/Loader.php | 47 +- lib/zend/Zend/Locale.php | 1019 +++++++++++ lib/zend/Zend/Log.php | 222 +++ lib/zend/Zend/Mail.php | 1055 +++++++++++ lib/zend/Zend/Memory.php | 73 + lib/zend/Zend/Mime.php | 127 +- lib/zend/Zend/Navigation.php | 54 + lib/zend/Zend/OpenId.php | 753 ++++++++ lib/zend/Zend/Paginator.php | 1107 ++++++++++++ lib/zend/Zend/Pdf.php | 1429 +++++++++++++++ lib/zend/Zend/ProgressBar.php | 209 +++ lib/zend/Zend/Queue.php | 569 ++++++ lib/zend/Zend/Registry.php | 22 +- lib/zend/Zend/Session.php | 878 ++++++++++ lib/zend/Zend/TimeSync.php | 304 ++++ lib/zend/Zend/Translate.php | 179 ++ lib/zend/Zend/Uri.php | 35 +- lib/zend/Zend/Validate.php | 246 +++ lib/zend/Zend/Version.php | 12 +- lib/zend/Zend/View.php | 111 ++ 40 files changed, 19559 insertions(+), 651 deletions(-) create mode 100644 lib/zend/Zend/Acl.php create mode 100644 lib/zend/Zend/Application.php create mode 100644 lib/zend/Zend/Auth.php create mode 100644 lib/zend/Zend/Cache.php create mode 100644 lib/zend/Zend/Config.php create mode 100644 lib/zend/Zend/Crypt.php create mode 100644 lib/zend/Zend/Currency.php create mode 100644 lib/zend/Zend/Db.php create mode 100644 lib/zend/Zend/Debug.php create mode 100644 lib/zend/Zend/Dojo.php create mode 100644 lib/zend/Zend/Feed.php create mode 100644 lib/zend/Zend/Filter.php create mode 100644 lib/zend/Zend/Form.php create mode 100644 lib/zend/Zend/InfoCard.php create mode 100644 lib/zend/Zend/Json.php create mode 100644 lib/zend/Zend/Layout.php create mode 100644 lib/zend/Zend/Ldap.php create mode 100644 lib/zend/Zend/Locale.php create mode 100644 lib/zend/Zend/Log.php create mode 100644 lib/zend/Zend/Mail.php create mode 100644 lib/zend/Zend/Memory.php create mode 100644 lib/zend/Zend/Navigation.php create mode 100644 lib/zend/Zend/OpenId.php create mode 100644 lib/zend/Zend/Paginator.php create mode 100644 lib/zend/Zend/Pdf.php create mode 100644 lib/zend/Zend/ProgressBar.php create mode 100644 lib/zend/Zend/Queue.php create mode 100644 lib/zend/Zend/Session.php create mode 100644 lib/zend/Zend/TimeSync.php create mode 100644 lib/zend/Zend/Translate.php create mode 100644 lib/zend/Zend/Validate.php create mode 100644 lib/zend/Zend/View.php diff --git a/lib/zend/Zend/Acl.php b/lib/zend/Zend/Acl.php new file mode 100644 index 0000000000..f39cfaf5e3 --- /dev/null +++ b/lib/zend/Zend/Acl.php @@ -0,0 +1,1119 @@ + 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(); + } + +} diff --git a/lib/zend/Zend/Application.php b/lib/zend/Zend/Application.php new file mode 100644 index 0000000000..a2c84786ab --- /dev/null +++ b/lib/zend/Zend/Application.php @@ -0,0 +1,397 @@ +_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(); + } +} diff --git a/lib/zend/Zend/Auth.php b/lib/zend/Zend/Auth.php new file mode 100644 index 0000000000..7fbd5bfa16 --- /dev/null +++ b/lib/zend/Zend/Auth.php @@ -0,0 +1,169 @@ +_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(); + } +} diff --git a/lib/zend/Zend/Cache.php b/lib/zend/Zend/Cache.php new file mode 100644 index 0000000000..7853437f13 --- /dev/null +++ b/lib/zend/Zend/Cache.php @@ -0,0 +1,245 @@ +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; + } + +} diff --git a/lib/zend/Zend/Config.php b/lib/zend/Zend/Config.php new file mode 100644 index 0000000000..5a10b6dfb5 --- /dev/null +++ b/lib/zend/Zend/Config.php @@ -0,0 +1,456 @@ +_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); + } + } + +} diff --git a/lib/zend/Zend/Crypt.php b/lib/zend/Zend/Crypt.php new file mode 100644 index 0000000000..f40291a05a --- /dev/null +++ b/lib/zend/Zend/Crypt.php @@ -0,0 +1,167 @@ + 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; + } +} diff --git a/lib/zend/Zend/Date.php b/lib/zend/Zend/Date.php index 54a834b5ec..158aed1605 100644 --- a/lib/zend/Zend/Date.php +++ b/lib/zend/Zend/Date.php @@ -14,7 +14,7 @@ * * @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$ */ @@ -30,7 +30,7 @@ require_once 'Zend/Locale/Math.php'; /** * @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 @@ -50,96 +50,75 @@ 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, @@ -157,32 +136,38 @@ class Zend_Date extends Zend_Date_DateObject */ 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); } } @@ -212,11 +197,30 @@ class Zend_Date extends Zend_Date_DateObject $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 { @@ -406,12 +410,32 @@ class Zend_Date extends Zend_Date_DateObject */ 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; } @@ -426,297 +450,7 @@ class Zend_Date extends Zend_Date_DateObject $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); } /** @@ -775,7 +509,7 @@ class Zend_Date extends Zend_Date_DateObject * * @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) { @@ -783,7 +517,7 @@ class Zend_Date extends Zend_Date_DateObject $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; } @@ -792,303 +526,443 @@ class Zend_Date extends Zend_Date_DateObject $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; } /** @@ -1286,9 +1160,17 @@ class Zend_Date extends Zend_Date_DateObject 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"; @@ -1297,7 +1179,7 @@ class Zend_Date extends Zend_Date_DateObject 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(); @@ -1376,12 +1258,12 @@ class Zend_Date extends Zend_Date_DateObject */ 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; } @@ -1715,7 +1597,7 @@ class Zend_Date extends Zend_Date_DateObject $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); } @@ -1724,7 +1606,7 @@ class Zend_Date extends Zend_Date_DateObject $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); } @@ -1746,7 +1628,7 @@ class Zend_Date extends Zend_Date_DateObject $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); } @@ -1755,7 +1637,7 @@ class Zend_Date extends Zend_Date_DateObject $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); } @@ -1787,7 +1669,7 @@ class Zend_Date extends Zend_Date_DateObject $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); } @@ -1796,7 +1678,7 @@ class Zend_Date extends Zend_Date_DateObject $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); } @@ -1818,7 +1700,7 @@ class Zend_Date extends Zend_Date_DateObject $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); } @@ -1827,7 +1709,7 @@ class Zend_Date extends Zend_Date_DateObject $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); } @@ -1865,7 +1747,7 @@ class Zend_Date extends Zend_Date_DateObject $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); } @@ -1874,7 +1756,7 @@ class Zend_Date extends Zend_Date_DateObject $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); } @@ -2332,8 +2214,13 @@ class Zend_Date extends Zend_Date_DateObject $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); @@ -2383,8 +2270,127 @@ class Zend_Date extends Zend_Date_DateObject $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); @@ -2685,18 +2691,14 @@ class Zend_Date extends Zend_Date_DateObject */ 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 @@ -2711,21 +2713,22 @@ class Zend_Date extends Zend_Date_DateObject $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; } @@ -2812,7 +2815,7 @@ class Zend_Date extends Zend_Date_DateObject */ 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; } @@ -2829,23 +2832,19 @@ class Zend_Date extends Zend_Date_DateObject */ 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"); @@ -2855,6 +2854,10 @@ class Zend_Date extends Zend_Date_DateObject $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']); @@ -2864,15 +2867,10 @@ class Zend_Date extends Zend_Date_DateObject 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; } @@ -3373,7 +3371,7 @@ class Zend_Date extends Zend_Date_DateObject */ 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"); } @@ -3508,7 +3506,7 @@ class Zend_Date extends Zend_Date_DateObject */ 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'); } @@ -3539,7 +3537,7 @@ class Zend_Date extends Zend_Date_DateObject $cnt = 0; foreach ($monthlist as $key => $value) { if (strtoupper($value) == strtoupper($month)) { - $found = $key + 1; + $found = ($key % 12) + 1; break; } ++$cnt; @@ -3663,7 +3661,7 @@ class Zend_Date extends Zend_Date_DateObject */ 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'); } @@ -3811,7 +3809,7 @@ class Zend_Date extends Zend_Date_DateObject */ 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'); } @@ -4389,7 +4387,7 @@ class Zend_Date extends Zend_Date_DateObject */ public function subMilliSecond($milli = null, $precision = null) { - return $this->addMilliSecond(0 - $milli); + return $this->addMilliSecond(0 - $milli, $precision); } /** @@ -4525,16 +4523,13 @@ class Zend_Date extends Zend_Date_DateObject */ 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; } @@ -4555,14 +4550,15 @@ class Zend_Date extends Zend_Date_DateObject * 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; } @@ -4571,47 +4567,32 @@ class Zend_Date extends Zend_Date_DateObject $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']))) { @@ -4627,7 +4608,7 @@ class Zend_Date extends Zend_Date_DateObject 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']))) { @@ -4642,7 +4623,7 @@ class Zend_Date extends Zend_Date_DateObject // Set not given dateparts if (isset($parsed['hour']) === false) { - $parsed['hour'] = 0; + $parsed['hour'] = 12; } if (isset($parsed['minute']) === false) { @@ -4665,9 +4646,16 @@ class Zend_Date extends Zend_Date_DateObject $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; @@ -4701,4 +4689,84 @@ class Zend_Date extends Zend_Date_DateObject 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; + } } diff --git a/lib/zend/Zend/Db.php b/lib/zend/Zend/Db.php new file mode 100644 index 0000000000..1c7df20bb7 --- /dev/null +++ b/lib/zend/Zend/Db.php @@ -0,0 +1,281 @@ +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; + } + +} diff --git a/lib/zend/Zend/Debug.php b/lib/zend/Zend/Debug.php new file mode 100644 index 0000000000..f56d5d9a3a --- /dev/null +++ b/lib/zend/Zend/Debug.php @@ -0,0 +1,108 @@ + 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 = '
'
+                    . $label
+                    . $output
+                    . '
'; + } + + if ($echo) { + echo($output); + } + return $output; + } + +} diff --git a/lib/zend/Zend/Dojo.php b/lib/zend/Zend/Dojo.php new file mode 100644 index 0000000000..2175bf6a9f --- /dev/null +++ b/lib/zend/Zend/Dojo.php @@ -0,0 +1,87 @@ +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'); + } + } +} + diff --git a/lib/zend/Zend/Exception.php b/lib/zend/Zend/Exception.php index 599d8a033e..04ffa37ef0 100644 --- a/lib/zend/Zend/Exception.php +++ b/lib/zend/Zend/Exception.php @@ -14,15 +14,16 @@ * * @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 diff --git a/lib/zend/Zend/Feed.php b/lib/zend/Zend/Feed.php new file mode 100644 index 0000000000..83c68241cc --- /dev/null +++ b/lib/zend/Zend/Feed.php @@ -0,0 +1,411 @@ + '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 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 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 tags + @ini_set('track_errors', 1); + $pattern = '~(]+)/?>~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); + } +} diff --git a/lib/zend/Zend/Filter.php b/lib/zend/Zend/Filter.php new file mode 100644 index 0000000000..fe97688e7e --- /dev/null +++ b/lib/zend/Zend/Filter.php @@ -0,0 +1,192 @@ +_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'"); + } +} diff --git a/lib/zend/Zend/Form.php b/lib/zend/Zend/Form.php new file mode 100644 index 0000000000..4316ea64ae --- /dev/null +++ b/lib/zend/Zend/Form.php @@ -0,0 +1,3079 @@ +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; + } +} diff --git a/lib/zend/Zend/Gdata.php b/lib/zend/Zend/Gdata.php index 9e63f88938..c9f73224dd 100644 --- a/lib/zend/Zend/Gdata.php +++ b/lib/zend/Zend/Gdata.php @@ -15,8 +15,10 @@ * * @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$ */ /** @@ -29,13 +31,14 @@ require_once 'Zend/Gdata/App.php'; * 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 @@ -68,14 +71,16 @@ 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 @@ -95,7 +100,8 @@ class Zend_Gdata extends Zend_Gdata_App * 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') { @@ -109,15 +115,20 @@ class Zend_Gdata extends Zend_Gdata_App * @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); @@ -126,12 +137,15 @@ class Zend_Gdata extends Zend_Gdata_App } /** - * 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') { @@ -149,10 +163,14 @@ class Zend_Gdata extends Zend_Gdata_App } /** - * 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') { @@ -171,11 +189,11 @@ class Zend_Gdata extends Zend_Gdata_App /** * 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, @@ -204,4 +222,20 @@ class Zend_Gdata extends Zend_Gdata_App } } + /** + * 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; + } + } diff --git a/lib/zend/Zend/InfoCard.php b/lib/zend/Zend/InfoCard.php new file mode 100644 index 0000000000..25b84b3d2e --- /dev/null +++ b/lib/zend/Zend/InfoCard.php @@ -0,0 +1,497 @@ +_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; + } +} diff --git a/lib/zend/Zend/Json.php b/lib/zend/Zend/Json.php new file mode 100644 index 0000000000..c3197d10a4 --- /dev/null +++ b/lib/zend/Zend/Json.php @@ -0,0 +1,339 @@ +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. +} diff --git a/lib/zend/Zend/Layout.php b/lib/zend/Zend/Layout.php new file mode 100644 index 0000000000..e1cc3104bd --- /dev/null +++ b/lib/zend/Zend/Layout.php @@ -0,0 +1,795 @@ +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); + } +} diff --git a/lib/zend/Zend/Ldap.php b/lib/zend/Zend/Ldap.php new file mode 100644 index 0000000000..cb74de3247 --- /dev/null +++ b/lib/zend/Zend/Ldap.php @@ -0,0 +1,1476 @@ +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; + } +} diff --git a/lib/zend/Zend/Loader.php b/lib/zend/Zend/Loader.php index d140684cfb..9532aa4418 100644 --- a/lib/zend/Zend/Loader.php +++ b/lib/zend/Zend/Loader.php @@ -14,7 +14,7 @@ * * @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$ */ @@ -24,7 +24,7 @@ * * @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 @@ -80,7 +80,7 @@ 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)) { @@ -177,13 +177,15 @@ class Zend_Loader * spl_autoload_register(array('Zend_Loader', 'autoload')); * * - * @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; @@ -193,6 +195,7 @@ class Zend_Loader /** * Register {@link autoload()} with spl_autoload() * + * @deprecated Since 1.8.0 * @param string $class (optional) * @param boolean $enabled (optional) * @return void @@ -201,22 +204,26 @@ class Zend_Loader */ 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); + } } } @@ -232,7 +239,7 @@ class Zend_Loader /** * 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'); } diff --git a/lib/zend/Zend/Locale.php b/lib/zend/Zend/Locale.php new file mode 100644 index 0000000000..669313d5fc --- /dev/null +++ b/lib/zend/Zend/Locale.php @@ -0,0 +1,1019 @@ + 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; + } +} diff --git a/lib/zend/Zend/Log.php b/lib/zend/Zend/Log.php new file mode 100644 index 0000000000..b0dd790ded --- /dev/null +++ b/lib/zend/Zend/Log.php @@ -0,0 +1,222 @@ +_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)); + } + +} diff --git a/lib/zend/Zend/Mail.php b/lib/zend/Zend/Mail.php new file mode 100644 index 0000000000..4a5153ac47 --- /dev/null +++ b/lib/zend/Zend/Mail.php @@ -0,0 +1,1055 @@ +_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); + } + } + +} diff --git a/lib/zend/Zend/Memory.php b/lib/zend/Zend/Memory.php new file mode 100644 index 0000000000..1ed9d3f159 --- /dev/null +++ b/lib/zend/Zend/Memory.php @@ -0,0 +1,73 @@ + ""); + + // 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. diff --git a/lib/zend/Zend/Navigation.php b/lib/zend/Zend/Navigation.php new file mode 100644 index 0000000000..0915f55d8d --- /dev/null +++ b/lib/zend/Zend/Navigation.php @@ -0,0 +1,54 @@ +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'); + } + } +} diff --git a/lib/zend/Zend/OpenId.php b/lib/zend/Zend/OpenId.php new file mode 100644 index 0000000000..55a0fea576 --- /dev/null +++ b/lib/zend/Zend/OpenId.php @@ -0,0 +1,753 @@ + 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 = "\n"; + $body .= "
\n"; + if (is_array($params) && count($params) > 0) { + foreach($params as $key => $value) { + $body .= '\n"; + } + } + $body .= "\n"; + $body .= "
\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(""); + } 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); + } + } + +} diff --git a/lib/zend/Zend/Paginator.php b/lib/zend/Zend/Paginator.php new file mode 100644 index 0000000000..6e1db3ded9 --- /dev/null +++ b/lib/zend/Zend/Paginator.php @@ -0,0 +1,1107 @@ +addPrefixPath($prefix, $path); + } + + /** + * Adds an array of adapter prefix paths to the plugin + * loader. + * + * + * $prefixPaths = array( + * 'My_Paginator_Adapter' => 'My/Paginator/Adapter/', + * 'Your_Paginator_Adapter' => 'Your/Paginator/Adapter/' + * ); + * + * + * @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. + * + * + * $prefixPaths = array( + * 'My_Paginator_ScrollingStyle' => 'My/Paginator/ScrollingStyle/', + * 'Your_Paginator_ScrollingStyle' => 'Your/Paginator/ScrollingStyle/' + * ); + * + * + * @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'); + } + } +} diff --git a/lib/zend/Zend/Pdf.php b/lib/zend/Zend/Pdf.php new file mode 100644 index 0000000000..cdebe5e17e --- /dev/null +++ b/lib/zend/Zend/Pdf.php @@ -0,0 +1,1429 @@ +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: + * => Zend_Pdf_Page + * + * @var SplObjectStorage + */ + protected $_pageReferences = null; + + /** + * Pages collection hash: + * => 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) . '\''; + } + +} diff --git a/lib/zend/Zend/ProgressBar.php b/lib/zend/Zend/ProgressBar.php new file mode 100644 index 0000000000..bb7141a206 --- /dev/null +++ b/lib/zend/Zend/ProgressBar.php @@ -0,0 +1,209 @@ + $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(); + } +} diff --git a/lib/zend/Zend/Queue.php b/lib/zend/Zend/Queue.php new file mode 100644 index 0000000000..181f317910 --- /dev/null +++ b/lib/zend/Zend/Queue.php @@ -0,0 +1,569 @@ +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; + } +} diff --git a/lib/zend/Zend/Registry.php b/lib/zend/Zend/Registry.php index 11bba274b7..3c3cf49652 100644 --- a/lib/zend/Zend/Registry.php +++ b/lib/zend/Zend/Registry.php @@ -14,7 +14,7 @@ * * @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$ */ @@ -24,7 +24,7 @@ * * @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 @@ -109,8 +109,10 @@ 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; } @@ -181,6 +183,18 @@ class Zend_Registry extends ArrayObject 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 diff --git a/lib/zend/Zend/Session.php b/lib/zend/Zend/Session.php new file mode 100644 index 0000000000..157547b479 --- /dev/null +++ b/lib/zend/Zend/Session.php @@ -0,0 +1,878 @@ +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