Lib_ZF - Version 1.0.18800

Version Notes

First stable release

Download this release

Release Info

Developer Magento Core Team
Extension Lib_ZF
Version 1.0.18800
Comparing to
See all releases


Version 1.0.18800

Files changed (100) hide show
  1. lib/Zend/Acl.php +1001 -0
  2. lib/Zend/Acl/Assert/Interface.php +64 -0
  3. lib/Zend/Acl/Exception.php +36 -0
  4. lib/Zend/Acl/Resource.php +65 -0
  5. lib/Zend/Acl/Resource/Interface.php +37 -0
  6. lib/Zend/Acl/Role.php +65 -0
  7. lib/Zend/Acl/Role/Interface.php +37 -0
  8. lib/Zend/Acl/Role/Registry.php +266 -0
  9. lib/Zend/Acl/Role/Registry/Exception.php +36 -0
  10. lib/Zend/Auth.php +162 -0
  11. lib/Zend/Auth/Adapter/DbTable.php +461 -0
  12. lib/Zend/Auth/Adapter/Digest.php +230 -0
  13. lib/Zend/Auth/Adapter/Exception.php +38 -0
  14. lib/Zend/Auth/Adapter/Http.php +841 -0
  15. lib/Zend/Auth/Adapter/Http/Resolver/Exception.php +40 -0
  16. lib/Zend/Auth/Adapter/Http/Resolver/File.php +167 -0
  17. lib/Zend/Auth/Adapter/Http/Resolver/Interface.php +47 -0
  18. lib/Zend/Auth/Adapter/InfoCard.php +263 -0
  19. lib/Zend/Auth/Adapter/Interface.php +46 -0
  20. lib/Zend/Auth/Adapter/Ldap.php +273 -0
  21. lib/Zend/Auth/Adapter/OpenId.php +272 -0
  22. lib/Zend/Auth/Exception.php +36 -0
  23. lib/Zend/Auth/Result.php +148 -0
  24. lib/Zend/Auth/Storage/Exception.php +39 -0
  25. lib/Zend/Auth/Storage/Interface.php +67 -0
  26. lib/Zend/Auth/Storage/NonPersistent.php +96 -0
  27. lib/Zend/Auth/Storage/Session.php +150 -0
  28. lib/Zend/Cache.php +159 -0
  29. lib/Zend/Cache/Backend.php +224 -0
  30. lib/Zend/Cache/Backend/Apc.php +167 -0
  31. lib/Zend/Cache/Backend/File.php +717 -0
  32. lib/Zend/Cache/Backend/Interface.php +96 -0
  33. lib/Zend/Cache/Backend/Memcached.php +234 -0
  34. lib/Zend/Cache/Backend/Sqlite.php +427 -0
  35. lib/Zend/Cache/Backend/Test.php +265 -0
  36. lib/Zend/Cache/Backend/ZendPlatform.php +285 -0
  37. lib/Zend/Cache/Core.php +474 -0
  38. lib/Zend/Cache/Exception.php +31 -0
  39. lib/Zend/Cache/Frontend/Class.php +193 -0
  40. lib/Zend/Cache/Frontend/File.php +115 -0
  41. lib/Zend/Cache/Frontend/Function.php +129 -0
  42. lib/Zend/Cache/Frontend/Output.php +82 -0
  43. lib/Zend/Cache/Frontend/Page.php +330 -0
  44. lib/Zend/Config.php +348 -0
  45. lib/Zend/Config/Exception.php +32 -0
  46. lib/Zend/Config/Ini.php +244 -0
  47. lib/Zend/Config/Xml.php +199 -0
  48. lib/Zend/Console/Getopt.php +949 -0
  49. lib/Zend/Console/Getopt/Exception.php +65 -0
  50. lib/Zend/Controller/Action.php +677 -0
  51. lib/Zend/Controller/Action/Exception.php +37 -0
  52. lib/Zend/Controller/Action/Helper/Abstract.php +164 -0
  53. lib/Zend/Controller/Action/Helper/ActionStack.php +143 -0
  54. lib/Zend/Controller/Action/Helper/AjaxContext.php +77 -0
  55. lib/Zend/Controller/Action/Helper/AutoComplete/Abstract.php +149 -0
  56. lib/Zend/Controller/Action/Helper/AutoCompleteDojo.php +74 -0
  57. lib/Zend/Controller/Action/Helper/AutoCompleteScriptaculous.php +82 -0
  58. lib/Zend/Controller/Action/Helper/ContextSwitch.php +1357 -0
  59. lib/Zend/Controller/Action/Helper/FlashMessenger.php +261 -0
  60. lib/Zend/Controller/Action/Helper/Json.php +117 -0
  61. lib/Zend/Controller/Action/Helper/Redirector.php +505 -0
  62. lib/Zend/Controller/Action/Helper/Url.php +139 -0
  63. lib/Zend/Controller/Action/Helper/ViewRenderer.php +1000 -0
  64. lib/Zend/Controller/Action/HelperBroker.php +378 -0
  65. lib/Zend/Controller/Dispatcher/Abstract.php +448 -0
  66. lib/Zend/Controller/Dispatcher/Exception.php +36 -0
  67. lib/Zend/Controller/Dispatcher/Interface.php +172 -0
  68. lib/Zend/Controller/Dispatcher/Standard.php +489 -0
  69. lib/Zend/Controller/Exception.php +34 -0
  70. lib/Zend/Controller/Front.php +954 -0
  71. lib/Zend/Controller/Plugin/Abstract.php +156 -0
  72. lib/Zend/Controller/Plugin/ActionStack.php +245 -0
  73. lib/Zend/Controller/Plugin/Broker.php +369 -0
  74. lib/Zend/Controller/Plugin/ErrorHandler.php +257 -0
  75. lib/Zend/Controller/Request/Abstract.php +338 -0
  76. lib/Zend/Controller/Request/Apache404.php +80 -0
  77. lib/Zend/Controller/Request/Exception.php +36 -0
  78. lib/Zend/Controller/Request/Http.php +885 -0
  79. lib/Zend/Controller/Request/Simple.php +54 -0
  80. lib/Zend/Controller/Response/Abstract.php +755 -0
  81. lib/Zend/Controller/Response/Cli.php +67 -0
  82. lib/Zend/Controller/Response/Exception.php +34 -0
  83. lib/Zend/Controller/Response/Http.php +37 -0
  84. lib/Zend/Controller/Router/Abstract.php +174 -0
  85. lib/Zend/Controller/Router/Exception.php +35 -0
  86. lib/Zend/Controller/Router/Interface.php +86 -0
  87. lib/Zend/Controller/Router/Rewrite.php +293 -0
  88. lib/Zend/Controller/Router/Route.php +291 -0
  89. lib/Zend/Controller/Router/Route/Interface.php +36 -0
  90. lib/Zend/Controller/Router/Route/Module.php +264 -0
  91. lib/Zend/Controller/Router/Route/Regex.php +220 -0
  92. lib/Zend/Controller/Router/Route/Static.php +112 -0
  93. lib/Zend/Currency.php +525 -0
  94. lib/Zend/Currency/Exception.php +37 -0
  95. lib/Zend/Date.php +4727 -0
  96. lib/Zend/Date/Cities.php +315 -0
  97. lib/Zend/Date/DateObject.php +1060 -0
  98. lib/Zend/Date/Exception.php +49 -0
  99. lib/Zend/Db.php +263 -0
  100. lib/Zend/Db/Adapter/Abstract.php +823 -0
lib/Zend/Acl.php ADDED
@@ -0,0 +1,1001 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Zend Framework
5
+ *
6
+ * LICENSE
7
+ *
8
+ * This source file is subject to the new BSD license that is bundled
9
+ * with this package in the file LICENSE.txt.
10
+ * It is also available through the world-wide-web at this URL:
11
+ * http://framework.zend.com/license/new-bsd
12
+ * If you did not receive a copy of the license and are unable to
13
+ * obtain it through the world-wide-web, please send an email
14
+ * to license@zend.com so we can send you a copy immediately.
15
+ *
16
+ * @category Zend
17
+ * @package Zend_Acl
18
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
19
+ * @license http://framework.zend.com/license/new-bsd New BSD License
20
+ * @version $Id: Acl.php 8245 2008-02-21 14:01:46Z darby $
21
+ */
22
+
23
+
24
+ /**
25
+ * @see Zend_Acl_Resource_Interface
26
+ */
27
+ require_once 'Zend/Acl/Resource/Interface.php';
28
+
29
+
30
+ /**
31
+ * @see Zend_Acl_Role_Registry
32
+ */
33
+ require_once 'Zend/Acl/Role/Registry.php';
34
+
35
+
36
+ /**
37
+ * @see Zend_Acl_Assert_Interface
38
+ */
39
+ require_once 'Zend/Acl/Assert/Interface.php';
40
+
41
+
42
+ /**
43
+ * @category Zend
44
+ * @package Zend_Acl
45
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
46
+ * @license http://framework.zend.com/license/new-bsd New BSD License
47
+ */
48
+ class Zend_Acl
49
+ {
50
+ /**
51
+ * Rule type: allow
52
+ */
53
+ const TYPE_ALLOW = 'TYPE_ALLOW';
54
+
55
+ /**
56
+ * Rule type: deny
57
+ */
58
+ const TYPE_DENY = 'TYPE_DENY';
59
+
60
+ /**
61
+ * Rule operation: add
62
+ */
63
+ const OP_ADD = 'OP_ADD';
64
+
65
+ /**
66
+ * Rule operation: remove
67
+ */
68
+ const OP_REMOVE = 'OP_REMOVE';
69
+
70
+ /**
71
+ * Role registry
72
+ *
73
+ * @var Zend_Acl_Role_Registry
74
+ */
75
+ protected $_roleRegistry = null;
76
+
77
+ /**
78
+ * Resource tree
79
+ *
80
+ * @var array
81
+ */
82
+ protected $_resources = array();
83
+
84
+ /**
85
+ * ACL rules; whitelist (deny everything to all) by default
86
+ *
87
+ * @var array
88
+ */
89
+ protected $_rules = array(
90
+ 'allResources' => array(
91
+ 'allRoles' => array(
92
+ 'allPrivileges' => array(
93
+ 'type' => self::TYPE_DENY,
94
+ 'assert' => null
95
+ ),
96
+ 'byPrivilegeId' => array()
97
+ ),
98
+ 'byRoleId' => array()
99
+ ),
100
+ 'byResourceId' => array()
101
+ );
102
+
103
+ /**
104
+ * Adds a Role having an identifier unique to the registry
105
+ *
106
+ * The $parents parameter may be a reference to, or the string identifier for,
107
+ * a Role existing in the registry, or $parents may be passed as an array of
108
+ * these - mixing string identifiers and objects is ok - to indicate the Roles
109
+ * from which the newly added Role will directly inherit.
110
+ *
111
+ * In order to resolve potential ambiguities with conflicting rules inherited
112
+ * from different parents, the most recently added parent takes precedence over
113
+ * parents that were previously added. In other words, the first parent added
114
+ * will have the least priority, and the last parent added will have the
115
+ * highest priority.
116
+ *
117
+ * @param Zend_Acl_Role_Interface $role
118
+ * @param Zend_Acl_Role_Interface|string|array $parents
119
+ * @uses Zend_Acl_Role_Registry::add()
120
+ * @return Zend_Acl Provides a fluent interface
121
+ */
122
+ public function addRole(Zend_Acl_Role_Interface $role, $parents = null)
123
+ {
124
+ $this->_getRoleRegistry()->add($role, $parents);
125
+
126
+ return $this;
127
+ }
128
+
129
+ /**
130
+ * Returns the identified Role
131
+ *
132
+ * The $role parameter can either be a Role or Role identifier.
133
+ *
134
+ * @param Zend_Acl_Role_Interface|string $role
135
+ * @uses Zend_Acl_Role_Registry::get()
136
+ * @return Zend_Acl_Role_Interface
137
+ */
138
+ public function getRole($role)
139
+ {
140
+ return $this->_getRoleRegistry()->get($role);
141
+ }
142
+
143
+ /**
144
+ * Returns true if and only if the Role exists in the registry
145
+ *
146
+ * The $role parameter can either be a Role or a Role identifier.
147
+ *
148
+ * @param Zend_Acl_Role_Interface|string $role
149
+ * @uses Zend_Acl_Role_Registry::has()
150
+ * @return boolean
151
+ */
152
+ public function hasRole($role)
153
+ {
154
+ return $this->_getRoleRegistry()->has($role);
155
+ }
156
+
157
+ /**
158
+ * Returns true if and only if $role inherits from $inherit
159
+ *
160
+ * Both parameters may be either a Role or a Role identifier. If
161
+ * $onlyParents is true, then $role must inherit directly from
162
+ * $inherit in order to return true. By default, this method looks
163
+ * through the entire inheritance DAG to determine whether $role
164
+ * inherits from $inherit through its ancestor Roles.
165
+ *
166
+ * @param Zend_Acl_Role_Interface|string $role
167
+ * @param Zend_Acl_Role_Interface|string $inherit
168
+ * @param boolean $onlyParents
169
+ * @uses Zend_Acl_Role_Registry::inherits()
170
+ * @return boolean
171
+ */
172
+ public function inheritsRole($role, $inherit, $onlyParents = false)
173
+ {
174
+ return $this->_getRoleRegistry()->inherits($role, $inherit, $onlyParents);
175
+ }
176
+
177
+ /**
178
+ * Removes the Role from the registry
179
+ *
180
+ * The $role parameter can either be a Role or a Role identifier.
181
+ *
182
+ * @param Zend_Acl_Role_Interface|string $role
183
+ * @uses Zend_Acl_Role_Registry::remove()
184
+ * @return Zend_Acl Provides a fluent interface
185
+ */
186
+ public function removeRole($role)
187
+ {
188
+ $this->_getRoleRegistry()->remove($role);
189
+
190
+ if ($role instanceof Zend_Acl_Role_Interface) {
191
+ $roleId = $role->getRoleId();
192
+ } else {
193
+ $roleId = $role;
194
+ }
195
+
196
+ foreach ($this->_rules['allResources']['byRoleId'] as $roleIdCurrent => $rules) {
197
+ if ($roleId === $roleIdCurrent) {
198
+ unset($this->_rules['allResources']['byRoleId'][$roleIdCurrent]);
199
+ }
200
+ }
201
+ foreach ($this->_rules['byResourceId'] as $resourceIdCurrent => $visitor) {
202
+ foreach ($visitor['byRoleId'] as $roleIdCurrent => $rules) {
203
+ if ($roleId === $roleIdCurrent) {
204
+ unset($this->_rules['byResourceId'][$resourceIdCurrent]['byRoleId'][$roleIdCurrent]);
205
+ }
206
+ }
207
+ }
208
+
209
+ return $this;
210
+ }
211
+
212
+ /**
213
+ * Removes all Roles from the registry
214
+ *
215
+ * @uses Zend_Acl_Role_Registry::removeAll()
216
+ * @return Zend_Acl Provides a fluent interface
217
+ */
218
+ public function removeRoleAll()
219
+ {
220
+ $this->_getRoleRegistry()->removeAll();
221
+
222
+ foreach ($this->_rules['allResources']['byRoleId'] as $roleIdCurrent => $rules) {
223
+ unset($this->_rules['allResources']['byRoleId'][$roleIdCurrent]);
224
+ }
225
+ foreach ($this->_rules['byResourceId'] as $resourceIdCurrent => $visitor) {
226
+ foreach ($visitor['byRoleId'] as $roleIdCurrent => $rules) {
227
+ unset($this->_rules['byResourceId'][$resourceIdCurrent]['byRoleId'][$roleIdCurrent]);
228
+ }
229
+ }
230
+
231
+ return $this;
232
+ }
233
+
234
+ /**
235
+ * Adds a Resource having an identifier unique to the ACL
236
+ *
237
+ * The $parent parameter may be a reference to, or the string identifier for,
238
+ * the existing Resource from which the newly added Resource will inherit.
239
+ *
240
+ * @param Zend_Acl_Resource_Interface $resource
241
+ * @param Zend_Acl_Resource_Interface|string $parent
242
+ * @throws Zend_Acl_Exception
243
+ * @return Zend_Acl Provides a fluent interface
244
+ */
245
+ public function add(Zend_Acl_Resource_Interface $resource, $parent = null)
246
+ {
247
+ $resourceId = $resource->getResourceId();
248
+
249
+ if ($this->has($resourceId)) {
250
+ require_once 'Zend/Acl/Exception.php';
251
+ throw new Zend_Acl_Exception("Resource id '$resourceId' already exists in the ACL");
252
+ }
253
+
254
+ $resourceParent = null;
255
+
256
+ if (null !== $parent) {
257
+ try {
258
+ if ($parent instanceof Zend_Acl_Resource_Interface) {
259
+ $resourceParentId = $parent->getResourceId();
260
+ } else {
261
+ $resourceParentId = $parent;
262
+ }
263
+ $resourceParent = $this->get($resourceParentId);
264
+ } catch (Zend_Acl_Exception $e) {
265
+ throw new Zend_Acl_Exception("Parent Resource id '$resourceParentId' does not exist");
266
+ }
267
+ $this->_resources[$resourceParentId]['children'][$resourceId] = $resource;
268
+ }
269
+
270
+ $this->_resources[$resourceId] = array(
271
+ 'instance' => $resource,
272
+ 'parent' => $resourceParent,
273
+ 'children' => array()
274
+ );
275
+
276
+ return $this;
277
+ }
278
+
279
+ /**
280
+ * Returns the identified Resource
281
+ *
282
+ * The $resource parameter can either be a Resource or a Resource identifier.
283
+ *
284
+ * @param Zend_Acl_Resource_Interface|string $resource
285
+ * @throws Zend_Acl_Exception
286
+ * @return Zend_Acl_Resource_Interface
287
+ */
288
+ public function get($resource)
289
+ {
290
+ if ($resource instanceof Zend_Acl_Resource_Interface) {
291
+ $resourceId = $resource->getResourceId();
292
+ } else {
293
+ $resourceId = (string) $resource;
294
+ }
295
+
296
+ if (!$this->has($resource)) {
297
+ require_once 'Zend/Acl/Exception.php';
298
+ throw new Zend_Acl_Exception("Resource '$resourceId' not found");
299
+ }
300
+
301
+ return $this->_resources[$resourceId]['instance'];
302
+ }
303
+
304
+ /**
305
+ * Returns true if and only if the Resource exists in the ACL
306
+ *
307
+ * The $resource parameter can either be a Resource or a Resource identifier.
308
+ *
309
+ * @param Zend_Acl_Resource_Interface|string $resource
310
+ * @return boolean
311
+ */
312
+ public function has($resource)
313
+ {
314
+ if ($resource instanceof Zend_Acl_Resource_Interface) {
315
+ $resourceId = $resource->getResourceId();
316
+ } else {
317
+ $resourceId = (string) $resource;
318
+ }
319
+
320
+ return isset($this->_resources[$resourceId]);
321
+ }
322
+
323
+ /**
324
+ * Returns true if and only if $resource inherits from $inherit
325
+ *
326
+ * Both parameters may be either a Resource or a Resource identifier. If
327
+ * $onlyParent is true, then $resource must inherit directly from
328
+ * $inherit in order to return true. By default, this method looks
329
+ * through the entire inheritance tree to determine whether $resource
330
+ * inherits from $inherit through its ancestor Resources.
331
+ *
332
+ * @param Zend_Acl_Resource_Interface|string $resource
333
+ * @param Zend_Acl_Resource_Interface|string $inherit
334
+ * @param boolean $onlyParent
335
+ * @throws Zend_Acl_Resource_Registry_Exception
336
+ * @return boolean
337
+ */
338
+ public function inherits($resource, $inherit, $onlyParent = false)
339
+ {
340
+ try {
341
+ $resourceId = $this->get($resource)->getResourceId();
342
+ $inheritId = $this->get($inherit)->getResourceId();
343
+ } catch (Zend_Acl_Exception $e) {
344
+ throw $e;
345
+ }
346
+
347
+ if (null !== $this->_resources[$resourceId]['parent']) {
348
+ $parentId = $this->_resources[$resourceId]['parent']->getResourceId();
349
+ if ($inheritId === $parentId) {
350
+ return true;
351
+ } else if ($onlyParent) {
352
+ return false;
353
+ }
354
+ } else {
355
+ return false;
356
+ }
357
+
358
+ while (null !== $this->_resources[$parentId]['parent']) {
359
+ $parentId = $this->_resources[$parentId]['parent']->getResourceId();
360
+ if ($inheritId === $parentId) {
361
+ return true;
362
+ }
363
+ }
364
+
365
+ return false;
366
+ }
367
+
368
+ /**
369
+ * Removes a Resource and all of its children
370
+ *
371
+ * The $resource parameter can either be a Resource or a Resource identifier.
372
+ *
373
+ * @param Zend_Acl_Resource_Interface|string $resource
374
+ * @throws Zend_Acl_Exception
375
+ * @return Zend_Acl Provides a fluent interface
376
+ */
377
+ public function remove($resource)
378
+ {
379
+ try {
380
+ $resourceId = $this->get($resource)->getResourceId();
381
+ } catch (Zend_Acl_Exception $e) {
382
+ throw $e;
383
+ }
384
+
385
+ $resourcesRemoved = array($resourceId);
386
+ if (null !== ($resourceParent = $this->_resources[$resourceId]['parent'])) {
387
+ unset($this->_resources[$resourceParent->getResourceId()]['children'][$resourceId]);
388
+ }
389
+ foreach ($this->_resources[$resourceId]['children'] as $childId => $child) {
390
+ $this->remove($childId);
391
+ $resourcesRemoved[] = $childId;
392
+ }
393
+
394
+ foreach ($resourcesRemoved as $resourceIdRemoved) {
395
+ foreach ($this->_rules['byResourceId'] as $resourceIdCurrent => $rules) {
396
+ if ($resourceIdRemoved === $resourceIdCurrent) {
397
+ unset($this->_rules['byResourceId'][$resourceIdCurrent]);
398
+ }
399
+ }
400
+ }
401
+
402
+ unset($this->_resources[$resourceId]);
403
+
404
+ return $this;
405
+ }
406
+
407
+ /**
408
+ * Removes all Resources
409
+ *
410
+ * @return Zend_Acl Provides a fluent interface
411
+ */
412
+ public function removeAll()
413
+ {
414
+ foreach ($this->_resources as $resourceId => $resource) {
415
+ foreach ($this->_rules['byResourceId'] as $resourceIdCurrent => $rules) {
416
+ if ($resourceId === $resourceIdCurrent) {
417
+ unset($this->_rules['byResourceId'][$resourceIdCurrent]);
418
+ }
419
+ }
420
+ }
421
+
422
+ $this->_resources = array();
423
+
424
+ return $this;
425
+ }
426
+
427
+ /**
428
+ * Adds an "allow" rule to the ACL
429
+ *
430
+ * @param Zend_Acl_Role_Interface|string|array $roles
431
+ * @param Zend_Acl_Resource_Interface|string|array $resources
432
+ * @param string|array $privileges
433
+ * @param Zend_Acl_Assert_Interface $assert
434
+ * @uses Zend_Acl::setRule()
435
+ * @return Zend_Acl Provides a fluent interface
436
+ */
437
+ public function allow($roles = null, $resources = null, $privileges = null, Zend_Acl_Assert_Interface $assert = null)
438
+ {
439
+ return $this->setRule(self::OP_ADD, self::TYPE_ALLOW, $roles, $resources, $privileges, $assert);
440
+ }
441
+
442
+ /**
443
+ * Adds a "deny" rule to the ACL
444
+ *
445
+ * @param Zend_Acl_Role_Interface|string|array $roles
446
+ * @param Zend_Acl_Resource_Interface|string|array $resources
447
+ * @param string|array $privileges
448
+ * @param Zend_Acl_Assert_Interface $assert
449
+ * @uses Zend_Acl::setRule()
450
+ * @return Zend_Acl Provides a fluent interface
451
+ */
452
+ public function deny($roles = null, $resources = null, $privileges = null, Zend_Acl_Assert_Interface $assert = null)
453
+ {
454
+ return $this->setRule(self::OP_ADD, self::TYPE_DENY, $roles, $resources, $privileges, $assert);
455
+ }
456
+
457
+ /**
458
+ * Removes "allow" permissions from the ACL
459
+ *
460
+ * @param Zend_Acl_Role_Interface|string|array $roles
461
+ * @param Zend_Acl_Resource_Interface|string|array $resources
462
+ * @param string|array $privileges
463
+ * @uses Zend_Acl::setRule()
464
+ * @return Zend_Acl Provides a fluent interface
465
+ */
466
+ public function removeAllow($roles = null, $resources = null, $privileges = null)
467
+ {
468
+ return $this->setRule(self::OP_REMOVE, self::TYPE_ALLOW, $roles, $resources, $privileges);
469
+ }
470
+
471
+ /**
472
+ * Removes "deny" restrictions from the ACL
473
+ *
474
+ * @param Zend_Acl_Role_Interface|string|array $roles
475
+ * @param Zend_Acl_Resource_Interface|string|array $resources
476
+ * @param string|array $privileges
477
+ * @uses Zend_Acl::setRule()
478
+ * @return Zend_Acl Provides a fluent interface
479
+ */
480
+ public function removeDeny($roles = null, $resources = null, $privileges = null)
481
+ {
482
+ return $this->setRule(self::OP_REMOVE, self::TYPE_DENY, $roles, $resources, $privileges);
483
+ }
484
+
485
+ /**
486
+ * Performs operations on ACL rules
487
+ *
488
+ * The $operation parameter may be either OP_ADD or OP_REMOVE, depending on whether the
489
+ * user wants to add or remove a rule, respectively:
490
+ *
491
+ * OP_ADD specifics:
492
+ *
493
+ * A rule is added that would allow one or more Roles access to [certain $privileges
494
+ * upon] the specified Resource(s).
495
+ *
496
+ * OP_REMOVE specifics:
497
+ *
498
+ * The rule is removed only in the context of the given Roles, Resources, and privileges.
499
+ * Existing rules to which the remove operation does not apply would remain in the
500
+ * ACL.
501
+ *
502
+ * The $type parameter may be either TYPE_ALLOW or TYPE_DENY, depending on whether the
503
+ * rule is intended to allow or deny permission, respectively.
504
+ *
505
+ * The $roles and $resources parameters may be references to, or the string identifiers for,
506
+ * existing Resources/Roles, or they may be passed as arrays of these - mixing string identifiers
507
+ * and objects is ok - to indicate the Resources and Roles to which the rule applies. If either
508
+ * $roles or $resources is null, then the rule applies to all Roles or all Resources, respectively.
509
+ * Both may be null in order to work with the default rule of the ACL.
510
+ *
511
+ * The $privileges parameter may be used to further specify that the rule applies only
512
+ * to certain privileges upon the Resource(s) in question. This may be specified to be a single
513
+ * privilege with a string, and multiple privileges may be specified as an array of strings.
514
+ *
515
+ * If $assert is provided, then its assert() method must return true in order for
516
+ * the rule to apply. If $assert is provided with $roles, $resources, and $privileges all
517
+ * equal to null, then a rule having a type of:
518
+ *
519
+ * TYPE_ALLOW will imply a type of TYPE_DENY, and
520
+ *
521
+ * TYPE_DENY will imply a type of TYPE_ALLOW
522
+ *
523
+ * when the rule's assertion fails. This is because the ACL needs to provide expected
524
+ * behavior when an assertion upon the default ACL rule fails.
525
+ *
526
+ * @param string $operation
527
+ * @param string $type
528
+ * @param Zend_Acl_Role_Interface|string|array $roles
529
+ * @param Zend_Acl_Resource_Interface|string|array $resources
530
+ * @param string|array $privileges
531
+ * @param Zend_Acl_Assert_Interface $assert
532
+ * @throws Zend_Acl_Exception
533
+ * @uses Zend_Acl_Role_Registry::get()
534
+ * @uses Zend_Acl::get()
535
+ * @return Zend_Acl Provides a fluent interface
536
+ */
537
+ public function setRule($operation, $type, $roles = null, $resources = null, $privileges = null,
538
+ Zend_Acl_Assert_Interface $assert = null)
539
+ {
540
+ // ensure that the rule type is valid; normalize input to uppercase
541
+ $type = strtoupper($type);
542
+ if (self::TYPE_ALLOW !== $type && self::TYPE_DENY !== $type) {
543
+ require_once 'Zend/Acl/Exception.php';
544
+ throw new Zend_Acl_Exception("Unsupported rule type; must be either '" . self::TYPE_ALLOW . "' or '"
545
+ . self::TYPE_DENY . "'");
546
+ }
547
+
548
+ // ensure that all specified Roles exist; normalize input to array of Role objects or null
549
+ if (!is_array($roles)) {
550
+ $roles = array($roles);
551
+ } else if (0 === count($roles)) {
552
+ $roles = array(null);
553
+ }
554
+ $rolesTemp = $roles;
555
+ $roles = array();
556
+ foreach ($rolesTemp as $role) {
557
+ if (null !== $role) {
558
+ $roles[] = $this->_getRoleRegistry()->get($role);
559
+ } else {
560
+ $roles[] = null;
561
+ }
562
+ }
563
+ unset($rolesTemp);
564
+
565
+ // ensure that all specified Resources exist; normalize input to array of Resource objects or null
566
+ if (!is_array($resources)) {
567
+ $resources = array($resources);
568
+ } else if (0 === count($resources)) {
569
+ $resources = array(null);
570
+ }
571
+ $resourcesTemp = $resources;
572
+ $resources = array();
573
+ foreach ($resourcesTemp as $resource) {
574
+ if (null !== $resource) {
575
+ $resources[] = $this->get($resource);
576
+ } else {
577
+ $resources[] = null;
578
+ }
579
+ }
580
+ unset($resourcesTemp);
581
+
582
+ // normalize privileges to array
583
+ if (null === $privileges) {
584
+ $privileges = array();
585
+ } else if (!is_array($privileges)) {
586
+ $privileges = array($privileges);
587
+ }
588
+
589
+ switch ($operation) {
590
+
591
+ // add to the rules
592
+ case self::OP_ADD:
593
+ foreach ($resources as $resource) {
594
+ foreach ($roles as $role) {
595
+ $rules =& $this->_getRules($resource, $role, true);
596
+ if (0 === count($privileges)) {
597
+ $rules['allPrivileges']['type'] = $type;
598
+ $rules['allPrivileges']['assert'] = $assert;
599
+ if (!isset($rules['byPrivilegeId'])) {
600
+ $rules['byPrivilegeId'] = array();
601
+ }
602
+ } else {
603
+ foreach ($privileges as $privilege) {
604
+ $rules['byPrivilegeId'][$privilege]['type'] = $type;
605
+ $rules['byPrivilegeId'][$privilege]['assert'] = $assert;
606
+ }
607
+ }
608
+ }
609
+ }
610
+ break;
611
+
612
+ // remove from the rules
613
+ case self::OP_REMOVE:
614
+ foreach ($resources as $resource) {
615
+ foreach ($roles as $role) {
616
+ $rules =& $this->_getRules($resource, $role);
617
+ if (null === $rules) {
618
+ continue;
619
+ }
620
+ if (0 === count($privileges)) {
621
+ if (null === $resource && null === $role) {
622
+ if ($type === $rules['allPrivileges']['type']) {
623
+ $rules = array(
624
+ 'allPrivileges' => array(
625
+ 'type' => self::TYPE_DENY,
626
+ 'assert' => null
627
+ ),
628
+ 'byPrivilegeId' => array()
629
+ );
630
+ }
631
+ continue;
632
+ }
633
+ if ($type === $rules['allPrivileges']['type']) {
634
+ unset($rules['allPrivileges']);
635
+ }
636
+ } else {
637
+ foreach ($privileges as $privilege) {
638
+ if (isset($rules['byPrivilegeId'][$privilege]) &&
639
+ $type === $rules['byPrivilegeId'][$privilege]['type']) {
640
+ unset($rules['byPrivilegeId'][$privilege]);
641
+ }
642
+ }
643
+ }
644
+ }
645
+ }
646
+ break;
647
+
648
+ default:
649
+ require_once 'Zend/Acl/Exception.php';
650
+ throw new Zend_Acl_Exception("Unsupported operation; must be either '" . self::OP_ADD . "' or '"
651
+ . self::OP_REMOVE . "'");
652
+ }
653
+
654
+ return $this;
655
+ }
656
+
657
+ /**
658
+ * Returns true if and only if the Role has access to the Resource
659
+ *
660
+ * The $role and $resource parameters may be references to, or the string identifiers for,
661
+ * an existing Resource and Role combination.
662
+ *
663
+ * If either $role or $resource is null, then the query applies to all Roles or all Resources,
664
+ * respectively. Both may be null to query whether the ACL has a "blacklist" rule
665
+ * (allow everything to all). By default, Zend_Acl creates a "whitelist" rule (deny
666
+ * everything to all), and this method would return false unless this default has
667
+ * been overridden (i.e., by executing $acl->allow()).
668
+ *
669
+ * If a $privilege is not provided, then this method returns false if and only if the
670
+ * Role is denied access to at least one privilege upon the Resource. In other words, this
671
+ * method returns true if and only if the Role is allowed all privileges on the Resource.
672
+ *
673
+ * This method checks Role inheritance using a depth-first traversal of the Role registry.
674
+ * The highest priority parent (i.e., the parent most recently added) is checked first,
675
+ * and its respective parents are checked similarly before the lower-priority parents of
676
+ * the Role are checked.
677
+ *
678
+ * @param Zend_Acl_Role_Interface|string $role
679
+ * @param Zend_Acl_Resource_Interface|string $resource
680
+ * @param string $privilege
681
+ * @uses Zend_Acl::get()
682
+ * @uses Zend_Acl_Role_Registry::get()
683
+ * @return boolean
684
+ */
685
+ public function isAllowed($role = null, $resource = null, $privilege = null)
686
+ {
687
+ if (null !== $role) {
688
+ $role = $this->_getRoleRegistry()->get($role);
689
+ }
690
+
691
+ if (null !== $resource) {
692
+ $resource = $this->get($resource);
693
+ }
694
+
695
+ if (null === $privilege) {
696
+ // query on all privileges
697
+ do {
698
+ // depth-first search on $role if it is not 'allRoles' pseudo-parent
699
+ if (null !== $role && null !== ($result = $this->_roleDFSAllPrivileges($role, $resource, $privilege))) {
700
+ return $result;
701
+ }
702
+
703
+ // look for rule on 'allRoles' psuedo-parent
704
+ if (null !== ($rules = $this->_getRules($resource, null))) {
705
+ foreach ($rules['byPrivilegeId'] as $privilege => $rule) {
706
+ if (self::TYPE_DENY === ($ruleTypeOnePrivilege = $this->_getRuleType($resource, null, $privilege))) {
707
+ return false;
708
+ }
709
+ }
710
+ if (null !== ($ruleTypeAllPrivileges = $this->_getRuleType($resource, null, null))) {
711
+ return self::TYPE_ALLOW === $ruleTypeAllPrivileges;
712
+ }
713
+ }
714
+
715
+ // try next Resource
716
+ $resource = $this->_resources[$resource->getResourceId()]['parent'];
717
+
718
+ } while (true); // loop terminates at 'allResources' pseudo-parent
719
+ } else {
720
+ // query on one privilege
721
+ do {
722
+ // depth-first search on $role if it is not 'allRoles' pseudo-parent
723
+ if (null !== $role && null !== ($result = $this->_roleDFSOnePrivilege($role, $resource, $privilege))) {
724
+ return $result;
725
+ }
726
+
727
+ // look for rule on 'allRoles' pseudo-parent
728
+ if (null !== ($ruleType = $this->_getRuleType($resource, null, $privilege))) {
729
+ return self::TYPE_ALLOW === $ruleType;
730
+ } else if (null !== ($ruleTypeAllPrivileges = $this->_getRuleType($resource, null, null))) {
731
+ return self::TYPE_ALLOW === $ruleTypeAllPrivileges;
732
+ }
733
+
734
+ // try next Resource
735
+ $resource = $this->_resources[$resource->getResourceId()]['parent'];
736
+
737
+ } while (true); // loop terminates at 'allResources' pseudo-parent
738
+ }
739
+ }
740
+
741
+ /**
742
+ * Returns the Role registry for this ACL
743
+ *
744
+ * If no Role registry has been created yet, a new default Role registry
745
+ * is created and returned.
746
+ *
747
+ * @return Zend_Acl_Role_Registry
748
+ */
749
+ protected function _getRoleRegistry()
750
+ {
751
+ if (null === $this->_roleRegistry) {
752
+ $this->_roleRegistry = new Zend_Acl_Role_Registry();
753
+ }
754
+ return $this->_roleRegistry;
755
+ }
756
+
757
+ /**
758
+ * Performs a depth-first search of the Role DAG, starting at $role, in order to find a rule
759
+ * allowing/denying $role access to all privileges upon $resource
760
+ *
761
+ * This method returns true if a rule is found and allows access. If a rule exists and denies access,
762
+ * then this method returns false. If no applicable rule is found, then this method returns null.
763
+ *
764
+ * @param Zend_Acl_Role_Interface $role
765
+ * @param Zend_Acl_Resource_Interface $resource
766
+ * @return boolean|null
767
+ */
768
+ protected function _roleDFSAllPrivileges(Zend_Acl_Role_Interface $role, Zend_Acl_Resource_Interface $resource = null)
769
+ {
770
+ $dfs = array(
771
+ 'visited' => array(),
772
+ 'stack' => array()
773
+ );
774
+
775
+ if (null !== ($result = $this->_roleDFSVisitAllPrivileges($role, $resource, $dfs))) {
776
+ return $result;
777
+ }
778
+
779
+ while (null !== ($role = array_pop($dfs['stack']))) {
780
+ if (!isset($dfs['visited'][$role->getRoleId()])) {
781
+ if (null !== ($result = $this->_roleDFSVisitAllPrivileges($role, $resource, $dfs))) {
782
+ return $result;
783
+ }
784
+ }
785
+ }
786
+
787
+ return null;
788
+ }
789
+
790
+ /**
791
+ * Visits an $role in order to look for a rule allowing/denying $role access to all privileges upon $resource
792
+ *
793
+ * This method returns true if a rule is found and allows access. If a rule exists and denies access,
794
+ * then this method returns false. If no applicable rule is found, then this method returns null.
795
+ *
796
+ * This method is used by the internal depth-first search algorithm and may modify the DFS data structure.
797
+ *
798
+ * @param Zend_Acl_Role_Interface $role
799
+ * @param Zend_Acl_Resource_Interface $resource
800
+ * @param array $dfs
801
+ * @return boolean|null
802
+ */
803
+ protected function _roleDFSVisitAllPrivileges(Zend_Acl_Role_Interface $role, Zend_Acl_Resource_Interface $resource = null,
804
+ &$dfs)
805
+ {
806
+ if (null !== ($rules = $this->_getRules($resource, $role))) {
807
+ foreach ($rules['byPrivilegeId'] as $privilege => $rule) {
808
+ if (self::TYPE_DENY === ($ruleTypeOnePrivilege = $this->_getRuleType($resource, $role, $privilege))) {
809
+ return false;
810
+ }
811
+ }
812
+ if (null !== ($ruleTypeAllPrivileges = $this->_getRuleType($resource, $role, null))) {
813
+ return self::TYPE_ALLOW === $ruleTypeAllPrivileges;
814
+ }
815
+ }
816
+
817
+ $dfs['visited'][$role->getRoleId()] = true;
818
+ foreach ($this->_getRoleRegistry()->getParents($role) as $roleParentId => $roleParent) {
819
+ $dfs['stack'][] = $roleParent;
820
+ }
821
+
822
+ return null;
823
+ }
824
+
825
+ /**
826
+ * Performs a depth-first search of the Role DAG, starting at $role, in order to find a rule
827
+ * allowing/denying $role access to a $privilege upon $resource
828
+ *
829
+ * This method returns true if a rule is found and allows access. If a rule exists and denies access,
830
+ * then this method returns false. If no applicable rule is found, then this method returns null.
831
+ *
832
+ * @param Zend_Acl_Role_Interface $role
833
+ * @param Zend_Acl_Resource_Interface $resource
834
+ * @param string $privilege
835
+ * @return boolean|null
836
+ */
837
+ protected function _roleDFSOnePrivilege(Zend_Acl_Role_Interface $role, Zend_Acl_Resource_Interface $resource = null, $privilege)
838
+ {
839
+ $dfs = array(
840
+ 'visited' => array(),
841
+ 'stack' => array()
842
+ );
843
+
844
+ if (null !== ($result = $this->_roleDFSVisitOnePrivilege($role, $resource, $privilege, $dfs))) {
845
+ return $result;
846
+ }
847
+
848
+ while (null !== ($role = array_pop($dfs['stack']))) {
849
+ if (!isset($dfs['visited'][$role->getRoleId()])) {
850
+ if (null !== ($result = $this->_roleDFSVisitOnePrivilege($role, $resource, $privilege, $dfs))) {
851
+ return $result;
852
+ }
853
+ }
854
+ }
855
+
856
+ return null;
857
+ }
858
+
859
+ /**
860
+ * Visits an $role in order to look for a rule allowing/denying $role access to a $privilege upon $resource
861
+ *
862
+ * This method returns true if a rule is found and allows access. If a rule exists and denies access,
863
+ * then this method returns false. If no applicable rule is found, then this method returns null.
864
+ *
865
+ * This method is used by the internal depth-first search algorithm and may modify the DFS data structure.
866
+ *
867
+ * @param Zend_Acl_Role_Interface $role
868
+ * @param Zend_Acl_Resource_Interface $resource
869
+ * @param string $privilege
870
+ * @param array $dfs
871
+ * @return boolean|null
872
+ */
873
+ protected function _roleDFSVisitOnePrivilege(Zend_Acl_Role_Interface $role, Zend_Acl_Resource_Interface $resource = null,
874
+ $privilege, &$dfs)
875
+ {
876
+ if (null !== ($ruleTypeOnePrivilege = $this->_getRuleType($resource, $role, $privilege))) {
877
+ return self::TYPE_ALLOW === $ruleTypeOnePrivilege;
878
+ } else if (null !== ($ruleTypeAllPrivileges = $this->_getRuleType($resource, $role, null))) {
879
+ return self::TYPE_ALLOW === $ruleTypeAllPrivileges;
880
+ }
881
+
882
+ $dfs['visited'][$role->getRoleId()] = true;
883
+ foreach ($this->_getRoleRegistry()->getParents($role) as $roleParentId => $roleParent) {
884
+ $dfs['stack'][] = $roleParent;
885
+ }
886
+
887
+ return null;
888
+ }
889
+
890
+ /**
891
+ * Returns the rule type associated with the specified Resource, Role, and privilege
892
+ * combination.
893
+ *
894
+ * If a rule does not exist or its attached assertion fails, which means that
895
+ * the rule is not applicable, then this method returns null. Otherwise, the
896
+ * rule type applies and is returned as either TYPE_ALLOW or TYPE_DENY.
897
+ *
898
+ * If $resource or $role is null, then this means that the rule must apply to
899
+ * all Resources or Roles, respectively.
900
+ *
901
+ * If $privilege is null, then the rule must apply to all privileges.
902
+ *
903
+ * If all three parameters are null, then the default ACL rule type is returned,
904
+ * based on whether its assertion method passes.
905
+ *
906
+ * @param Zend_Acl_Resource_Interface $resource
907
+ * @param Zend_Acl_Role_Interface $role
908
+ * @param string $privilege
909
+ * @return string|null
910
+ */
911
+ protected function _getRuleType(Zend_Acl_Resource_Interface $resource = null, Zend_Acl_Role_Interface $role = null,
912
+ $privilege = null)
913
+ {
914
+ // get the rules for the $resource and $role
915
+ if (null === ($rules = $this->_getRules($resource, $role))) {
916
+ return null;
917
+ }
918
+
919
+ // follow $privilege
920
+ if (null === $privilege) {
921
+ if (isset($rules['allPrivileges'])) {
922
+ $rule = $rules['allPrivileges'];
923
+ } else {
924
+ return null;
925
+ }
926
+ } else if (!isset($rules['byPrivilegeId'][$privilege])) {
927
+ return null;
928
+ } else {
929
+ $rule = $rules['byPrivilegeId'][$privilege];
930
+ }
931
+
932
+ // check assertion if necessary
933
+ if (null === $rule['assert'] || $rule['assert']->assert($this, $role, $resource, $privilege)) {
934
+ return $rule['type'];
935
+ } else if (null !== $resource || null !== $role || null !== $privilege) {
936
+ return null;
937
+ } else if (self::TYPE_ALLOW === $rule['type']) {
938
+ return self::TYPE_DENY;
939
+ } else {
940
+ return self::TYPE_ALLOW;
941
+ }
942
+ }
943
+
944
+ /**
945
+ * Returns the rules associated with a Resource and a Role, or null if no such rules exist
946
+ *
947
+ * If either $resource or $role is null, this means that the rules returned are for all Resources or all Roles,
948
+ * respectively. Both can be null to return the default rule set for all Resources and all Roles.
949
+ *
950
+ * If the $create parameter is true, then a rule set is first created and then returned to the caller.
951
+ *
952
+ * @param Zend_Acl_Resource_Interface $resource
953
+ * @param Zend_Acl_Role_Interface $role
954
+ * @param boolean $create
955
+ * @return array|null
956
+ */
957
+ protected function &_getRules(Zend_Acl_Resource_Interface $resource = null, Zend_Acl_Role_Interface $role = null,
958
+ $create = false)
959
+ {
960
+ // create a reference to null
961
+ $null = null;
962
+ $nullRef =& $null;
963
+
964
+ // follow $resource
965
+ do {
966
+ if (null === $resource) {
967
+ $visitor =& $this->_rules['allResources'];
968
+ break;
969
+ }
970
+ $resourceId = $resource->getResourceId();
971
+ if (!isset($this->_rules['byResourceId'][$resourceId])) {
972
+ if (!$create) {
973
+ return $nullRef;
974
+ }
975
+ $this->_rules['byResourceId'][$resourceId] = array();
976
+ }
977
+ $visitor =& $this->_rules['byResourceId'][$resourceId];
978
+ } while (false);
979
+
980
+
981
+ // follow $role
982
+ if (null === $role) {
983
+ if (!isset($visitor['allRoles'])) {
984
+ if (!$create) {
985
+ return $nullRef;
986
+ }
987
+ $visitor['allRoles']['byPrivilegeId'] = array();
988
+ }
989
+ return $visitor['allRoles'];
990
+ }
991
+ $roleId = $role->getRoleId();
992
+ if (!isset($visitor['byRoleId'][$roleId])) {
993
+ if (!$create) {
994
+ return $nullRef;
995
+ }
996
+ $visitor['byRoleId'][$roleId]['byPrivilegeId'] = array();
997
+ }
998
+ return $visitor['byRoleId'][$roleId];
999
+ }
1000
+
1001
+ }
lib/Zend/Acl/Assert/Interface.php ADDED
@@ -0,0 +1,64 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Zend Framework
4
+ *
5
+ * LICENSE
6
+ *
7
+ * This source file is subject to the new BSD license that is bundled
8
+ * with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://framework.zend.com/license/new-bsd
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@zend.com so we can send you a copy immediately.
14
+ *
15
+ * @category Zend
16
+ * @package Zend_Acl
17
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
18
+ * @license http://framework.zend.com/license/new-bsd New BSD License
19
+ * @version $Id: Interface.php 8861 2008-03-16 14:30:18Z thomas $
20
+ */
21
+
22
+
23
+ /**
24
+ * @see Zend_Acl
25
+ */
26
+ require_once 'Zend/Acl.php';
27
+
28
+
29
+ /**
30
+ * @see Zend_Acl_Role_Interface
31
+ */
32
+ require_once 'Zend/Acl/Role/Interface.php';
33
+
34
+
35
+ /**
36
+ * @see Zend_Acl_Resource_Interface
37
+ */
38
+ require_once 'Zend/Acl/Resource/Interface.php';
39
+
40
+
41
+ /**
42
+ * @category Zend
43
+ * @package Zend_Acl
44
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
45
+ * @license http://framework.zend.com/license/new-bsd New BSD License
46
+ */
47
+ interface Zend_Acl_Assert_Interface
48
+ {
49
+ /**
50
+ * Returns true if and only if the assertion conditions are met
51
+ *
52
+ * This method is passed the ACL, Role, Resource, and privilege to which the authorization query applies. If the
53
+ * $role, $resource, or $privilege parameters are null, it means that the query applies to all Roles, Resources, or
54
+ * privileges, respectively.
55
+ *
56
+ * @param Zend_Acl $acl
57
+ * @param Zend_Acl_Role_Interface $role
58
+ * @param Zend_Acl_Resource_Interface $resource
59
+ * @param string $privilege
60
+ * @return boolean
61
+ */
62
+ public function assert(Zend_Acl $acl, Zend_Acl_Role_Interface $role = null, Zend_Acl_Resource_Interface $resource = null,
63
+ $privilege = null);
64
+ }
lib/Zend/Acl/Exception.php ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Zend Framework
4
+ *
5
+ * LICENSE
6
+ *
7
+ * This source file is subject to the new BSD license that is bundled
8
+ * with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://framework.zend.com/license/new-bsd
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@zend.com so we can send you a copy immediately.
14
+ *
15
+ * @category Zend
16
+ * @package Zend_Acl
17
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
18
+ * @license http://framework.zend.com/license/new-bsd New BSD License
19
+ * @version $Id: Exception.php 8861 2008-03-16 14:30:18Z thomas $
20
+ */
21
+
22
+
23
+ /**
24
+ * @see Zend_Exception
25
+ */
26
+ require_once 'Zend/Exception.php';
27
+
28
+
29
+ /**
30
+ * @category Zend
31
+ * @package Zend_Acl
32
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
33
+ * @license http://framework.zend.com/license/new-bsd New BSD License
34
+ */
35
+ class Zend_Acl_Exception extends Zend_Exception
36
+ {}
lib/Zend/Acl/Resource.php ADDED
@@ -0,0 +1,65 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Zend Framework
4
+ *
5
+ * LICENSE
6
+ *
7
+ * This source file is subject to the new BSD license that is bundled
8
+ * with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://framework.zend.com/license/new-bsd
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@zend.com so we can send you a copy immediately.
14
+ *
15
+ * @category Zend
16
+ * @package Zend_Acl
17
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
18
+ * @license http://framework.zend.com/license/new-bsd New BSD License
19
+ * @version $Id: Resource.php 8861 2008-03-16 14:30:18Z thomas $
20
+ */
21
+
22
+
23
+ /**
24
+ * @see Zend_Acl_Resource_Interface
25
+ */
26
+ require_once 'Zend/Acl/Resource/Interface.php';
27
+
28
+
29
+ /**
30
+ * @category Zend
31
+ * @package Zend_Acl
32
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
33
+ * @license http://framework.zend.com/license/new-bsd New BSD License
34
+ */
35
+ class Zend_Acl_Resource implements Zend_Acl_Resource_Interface
36
+ {
37
+ /**
38
+ * Unique id of Resource
39
+ *
40
+ * @var string
41
+ */
42
+ protected $_resourceId;
43
+
44
+ /**
45
+ * Sets the Resource identifier
46
+ *
47
+ * @param string $resourceId
48
+ * @return void
49
+ */
50
+ public function __construct($resourceId)
51
+ {
52
+ $this->_resourceId = (string) $resourceId;
53
+ }
54
+
55
+ /**
56
+ * Defined by Zend_Acl_Resource_Interface; returns the Resource identifier
57
+ *
58
+ * @return string
59
+ */
60
+ public function getResourceId()
61
+ {
62
+ return $this->_resourceId;
63
+ }
64
+
65
+ }
lib/Zend/Acl/Resource/Interface.php ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Zend Framework
4
+ *
5
+ * LICENSE
6
+ *
7
+ * This source file is subject to the new BSD license that is bundled
8
+ * with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://framework.zend.com/license/new-bsd
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@zend.com so we can send you a copy immediately.
14
+ *
15
+ * @category Zend
16
+ * @package Zend_Acl
17
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
18
+ * @license http://framework.zend.com/license/new-bsd New BSD License
19
+ * @version $Id: Interface.php 8861 2008-03-16 14:30:18Z thomas $
20
+ */
21
+
22
+
23
+ /**
24
+ * @category Zend
25
+ * @package Zend_Acl
26
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
27
+ * @license http://framework.zend.com/license/new-bsd New BSD License
28
+ */
29
+ interface Zend_Acl_Resource_Interface
30
+ {
31
+ /**
32
+ * Returns the string identifier of the Resource
33
+ *
34
+ * @return string
35
+ */
36
+ public function getResourceId();
37
+ }
lib/Zend/Acl/Role.php ADDED
@@ -0,0 +1,65 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Zend Framework
4
+ *
5
+ * LICENSE
6
+ *
7
+ * This source file is subject to the new BSD license that is bundled
8
+ * with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://framework.zend.com/license/new-bsd
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@zend.com so we can send you a copy immediately.
14
+ *
15
+ * @category Zend
16
+ * @package Zend_Acl
17
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
18
+ * @license http://framework.zend.com/license/new-bsd New BSD License
19
+ * @version $Id: Role.php 8861 2008-03-16 14:30:18Z thomas $
20
+ */
21
+
22
+
23
+ /**
24
+ * @see Zend_Acl_Role_Interface
25
+ */
26
+ require_once 'Zend/Acl/Role/Interface.php';
27
+
28
+
29
+ /**
30
+ * @category Zend
31
+ * @package Zend_Acl
32
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
33
+ * @license http://framework.zend.com/license/new-bsd New BSD License
34
+ */
35
+ class Zend_Acl_Role implements Zend_Acl_Role_Interface
36
+ {
37
+ /**
38
+ * Unique id of Role
39
+ *
40
+ * @var string
41
+ */
42
+ protected $_roleId;
43
+
44
+ /**
45
+ * Sets the Role identifier
46
+ *
47
+ * @param string $id
48
+ * @return void
49
+ */
50
+ public function __construct($roleId)
51
+ {
52
+ $this->_roleId = (string) $roleId;
53
+ }
54
+
55
+ /**
56
+ * Defined by Zend_Acl_Role_Interface; returns the Role identifier
57
+ *
58
+ * @return string
59
+ */
60
+ public function getRoleId()
61
+ {
62
+ return $this->_roleId;
63
+ }
64
+
65
+ }
lib/Zend/Acl/Role/Interface.php ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Zend Framework
4
+ *
5
+ * LICENSE
6
+ *
7
+ * This source file is subject to the new BSD license that is bundled
8
+ * with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://framework.zend.com/license/new-bsd
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@zend.com so we can send you a copy immediately.
14
+ *
15
+ * @category Zend
16
+ * @package Zend_Acl
17
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
18
+ * @license http://framework.zend.com/license/new-bsd New BSD License
19
+ * @version $Id: Interface.php 8861 2008-03-16 14:30:18Z thomas $
20
+ */
21
+
22
+
23
+ /**
24
+ * @category Zend
25
+ * @package Zend_Acl
26
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
27
+ * @license http://framework.zend.com/license/new-bsd New BSD License
28
+ */
29
+ interface Zend_Acl_Role_Interface
30
+ {
31
+ /**
32
+ * Returns the string identifier of the Role
33
+ *
34
+ * @return string
35
+ */
36
+ public function getRoleId();
37
+ }
lib/Zend/Acl/Role/Registry.php ADDED
@@ -0,0 +1,266 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Zend Framework
4
+ *
5
+ * LICENSE
6
+ *
7
+ * This source file is subject to the new BSD license that is bundled
8
+ * with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://framework.zend.com/license/new-bsd
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@zend.com so we can send you a copy immediately.
14
+ *
15
+ * @category Zend
16
+ * @package Zend_Acl
17
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
18
+ * @license http://framework.zend.com/license/new-bsd New BSD License
19
+ * @version $Id: Registry.php 8861 2008-03-16 14:30:18Z thomas $
20
+ */
21
+
22
+
23
+ /**
24
+ * @see Zend_Acl_Role_Interface
25
+ */
26
+ require_once 'Zend/Acl/Role/Interface.php';
27
+
28
+
29
+ /**
30
+ * @category Zend
31
+ * @package Zend_Acl
32
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
33
+ * @license http://framework.zend.com/license/new-bsd New BSD License
34
+ */
35
+ class Zend_Acl_Role_Registry
36
+ {
37
+ /**
38
+ * Internal Role registry data storage
39
+ *
40
+ * @var array
41
+ */
42
+ protected $_roles = array();
43
+
44
+ /**
45
+ * Adds a Role having an identifier unique to the registry
46
+ *
47
+ * The $parents parameter may be a reference to, or the string identifier for,
48
+ * a Role existing in the registry, or $parents may be passed as an array of
49
+ * these - mixing string identifiers and objects is ok - to indicate the Roles
50
+ * from which the newly added Role will directly inherit.
51
+ *
52
+ * In order to resolve potential ambiguities with conflicting rules inherited
53
+ * from different parents, the most recently added parent takes precedence over
54
+ * parents that were previously added. In other words, the first parent added
55
+ * will have the least priority, and the last parent added will have the
56
+ * highest priority.
57
+ *
58
+ * @param Zend_Acl_Role_Interface $role
59
+ * @param Zend_Acl_Role_Interface|string|array $parents
60
+ * @throws Zend_Acl_Role_Registry_Exception
61
+ * @return Zend_Acl_Role_Registry Provides a fluent interface
62
+ */
63
+ public function add(Zend_Acl_Role_Interface $role, $parents = null)
64
+ {
65
+ $roleId = $role->getRoleId();
66
+
67
+ if ($this->has($roleId)) {
68
+ /**
69
+ * @see Zend_Acl_Role_Registry_Exception
70
+ */
71
+ require_once 'Zend/Acl/Role/Registry/Exception.php';
72
+ throw new Zend_Acl_Role_Registry_Exception("Role id '$roleId' already exists in the registry");
73
+ }
74
+
75
+ $roleParents = array();
76
+
77
+ if (null !== $parents) {
78
+ if (!is_array($parents)) {
79
+ $parents = array($parents);
80
+ }
81
+ /**
82
+ * @see Zend_Acl_Role_Registry_Exception
83
+ */
84
+ require_once 'Zend/Acl/Role/Registry/Exception.php';
85
+ foreach ($parents as $parent) {
86
+ try {
87
+ if ($parent instanceof Zend_Acl_Role_Interface) {
88
+ $roleParentId = $parent->getRoleId();
89
+ } else {
90
+ $roleParentId = $parent;
91
+ }
92
+ $roleParent = $this->get($roleParentId);
93
+ } catch (Zend_Acl_Role_Registry_Exception $e) {
94
+ throw new Zend_Acl_Role_Registry_Exception("Parent Role id '$roleParentId' does not exist");
95
+ }
96
+ $roleParents[$roleParentId] = $roleParent;
97
+ $this->_roles[$roleParentId]['children'][$roleId] = $role;
98
+ }
99
+ }
100
+
101
+ $this->_roles[$roleId] = array(
102
+ 'instance' => $role,
103
+ 'parents' => $roleParents,
104
+ 'children' => array()
105
+ );
106
+
107
+ return $this;
108
+ }
109
+
110
+ /**
111
+ * Returns the identified Role
112
+ *
113
+ * The $role parameter can either be a Role or a Role identifier.
114
+ *
115
+ * @param Zend_Acl_Role_Interface|string $role
116
+ * @throws Zend_Acl_Role_Registry_Exception
117
+ * @return Zend_Acl_Role_Interface
118
+ */
119
+ public function get($role)
120
+ {
121
+ if ($role instanceof Zend_Acl_Role_Interface) {
122
+ $roleId = $role->getRoleId();
123
+ } else {
124
+ $roleId = (string) $role;
125
+ }
126
+
127
+ if (!$this->has($role)) {
128
+ /**
129
+ * @see Zend_Acl_Role_Registry_Exception
130
+ */
131
+ require_once 'Zend/Acl/Role/Registry/Exception.php';
132
+ throw new Zend_Acl_Role_Registry_Exception("Role '$roleId' not found");
133
+ }
134
+
135
+ return $this->_roles[$roleId]['instance'];
136
+ }
137
+
138
+ /**
139
+ * Returns true if and only if the Role exists in the registry
140
+ *
141
+ * The $role parameter can either be a Role or a Role identifier.
142
+ *
143
+ * @param Zend_Acl_Role_Interface|string $role
144
+ * @return boolean
145
+ */
146
+ public function has($role)
147
+ {
148
+ if ($role instanceof Zend_Acl_Role_Interface) {
149
+ $roleId = $role->getRoleId();
150
+ } else {
151
+ $roleId = (string) $role;
152
+ }
153
+
154
+ return isset($this->_roles[$roleId]);
155
+ }
156
+
157
+ /**
158
+ * Returns an array of an existing Role's parents
159
+ *
160
+ * The array keys are the identifiers of the parent Roles, and the values are
161
+ * the parent Role instances. The parent Roles are ordered in this array by
162
+ * ascending priority. The highest priority parent Role, last in the array,
163
+ * corresponds with the parent Role most recently added.
164
+ *
165
+ * If the Role does not have any parents, then an empty array is returned.
166
+ *
167
+ * @param Zend_Acl_Role_Interface|string $role
168
+ * @uses Zend_Acl_Role_Registry::get()
169
+ * @return array
170
+ */
171
+ public function getParents($role)
172
+ {
173
+ $roleId = $this->get($role)->getRoleId();
174
+
175
+ return $this->_roles[$roleId]['parents'];
176
+ }
177
+
178
+ /**
179
+ * Returns true if and only if $role inherits from $inherit
180
+ *
181
+ * Both parameters may be either a Role or a Role identifier. If
182
+ * $onlyParents is true, then $role must inherit directly from
183
+ * $inherit in order to return true. By default, this method looks
184
+ * through the entire inheritance DAG to determine whether $role
185
+ * inherits from $inherit through its ancestor Roles.
186
+ *
187
+ * @param Zend_Acl_Role_Interface|string $role
188
+ * @param Zend_Acl_Role_Interface|string $inherit
189
+ * @param boolean $onlyParents
190
+ * @throws Zend_Acl_Role_Registry_Exception
191
+ * @return boolean
192
+ */
193
+ public function inherits($role, $inherit, $onlyParents = false)
194
+ {
195
+ /**
196
+ * @see Zend_Acl_Role_Registry_Exception
197
+ */
198
+ require_once 'Zend/Acl/Role/Registry/Exception.php';
199
+ try {
200
+ $roleId = $this->get($role)->getRoleId();
201
+ $inheritId = $this->get($inherit)->getRoleId();
202
+ } catch (Zend_Acl_Role_Registry_Exception $e) {
203
+ throw $e;
204
+ }
205
+
206
+ $inherits = isset($this->_roles[$roleId]['parents'][$inheritId]);
207
+
208
+ if ($inherits || $onlyParents) {
209
+ return $inherits;
210
+ }
211
+
212
+ foreach ($this->_roles[$roleId]['parents'] as $parentId => $parent) {
213
+ if ($this->inherits($parentId, $inheritId)) {
214
+ return true;
215
+ }
216
+ }
217
+
218
+ return false;
219
+ }
220
+
221
+ /**
222
+ * Removes the Role from the registry
223
+ *
224
+ * The $role parameter can either be a Role or a Role identifier.
225
+ *
226
+ * @param Zend_Acl_Role_Interface|string $role
227
+ * @throws Zend_Acl_Role_Registry_Exception
228
+ * @return Zend_Acl_Role_Registry Provides a fluent interface
229
+ */
230
+ public function remove($role)
231
+ {
232
+ /**
233
+ * @see Zend_Acl_Role_Registry_Exception
234
+ */
235
+ require_once 'Zend/Acl/Role/Registry/Exception.php';
236
+ try {
237
+ $roleId = $this->get($role)->getRoleId();
238
+ } catch (Zend_Acl_Role_Registry_Exception $e) {
239
+ throw $e;
240
+ }
241
+
242
+ foreach ($this->_roles[$roleId]['children'] as $childId => $child) {
243
+ unset($this->_roles[$childId]['parents'][$roleId]);
244
+ }
245
+ foreach ($this->_roles[$roleId]['parents'] as $parentId => $parent) {
246
+ unset($this->_roles[$parentId]['children'][$roleId]);
247
+ }
248
+
249
+ unset($this->_roles[$roleId]);
250
+
251
+ return $this;
252
+ }
253
+
254
+ /**
255
+ * Removes all Roles from the registry
256
+ *
257
+ * @return Zend_Acl_Role_Registry Provides a fluent interface
258
+ */
259
+ public function removeAll()
260
+ {
261
+ $this->_roles = array();
262
+
263
+ return $this;
264
+ }
265
+
266
+ }
lib/Zend/Acl/Role/Registry/Exception.php ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Zend Framework
4
+ *
5
+ * LICENSE
6
+ *
7
+ * This source file is subject to the new BSD license that is bundled
8
+ * with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://framework.zend.com/license/new-bsd
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@zend.com so we can send you a copy immediately.
14
+ *
15
+ * @category Zend
16
+ * @package Zend_Acl
17
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
18
+ * @license http://framework.zend.com/license/new-bsd New BSD License
19
+ * @version $Id: Exception.php 8861 2008-03-16 14:30:18Z thomas $
20
+ */
21
+
22
+
23
+ /**
24
+ * @see Zend_Acl_Exception
25
+ */
26
+ require_once 'Zend/Acl/Exception.php';
27
+
28
+
29
+ /**
30
+ * @category Zend
31
+ * @package Zend_Acl
32
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
33
+ * @license http://framework.zend.com/license/new-bsd New BSD License
34
+ */
35
+ class Zend_Acl_Role_Registry_Exception extends Zend_Acl_Exception
36
+ {}
lib/Zend/Auth.php ADDED
@@ -0,0 +1,162 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Zend Framework
5
+ *
6
+ * LICENSE
7
+ *
8
+ * This source file is subject to the new BSD license that is bundled
9
+ * with this package in the file LICENSE.txt.
10
+ * It is also available through the world-wide-web at this URL:
11
+ * http://framework.zend.com/license/new-bsd
12
+ * If you did not receive a copy of the license and are unable to
13
+ * obtain it through the world-wide-web, please send an email
14
+ * to license@zend.com so we can send you a copy immediately.
15
+ *
16
+ * @category Zend
17
+ * @package Zend_Auth
18
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
19
+ * @license http://framework.zend.com/license/new-bsd New BSD License
20
+ * @version $Id: Auth.php 8064 2008-02-16 10:58:39Z thomas $
21
+ */
22
+
23
+
24
+ /**
25
+ * @category Zend
26
+ * @package Zend_Auth
27
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
28
+ * @license http://framework.zend.com/license/new-bsd New BSD License
29
+ */
30
+ class Zend_Auth
31
+ {
32
+ /**
33
+ * Singleton instance
34
+ *
35
+ * @var Zend_Auth
36
+ */
37
+ protected static $_instance = null;
38
+
39
+ /**
40
+ * Persistent storage handler
41
+ *
42
+ * @var Zend_Auth_Storage_Interface
43
+ */
44
+ protected $_storage = null;
45
+
46
+ /**
47
+ * Singleton pattern implementation makes "new" unavailable
48
+ *
49
+ * @return void
50
+ */
51
+ private function __construct()
52
+ {}
53
+
54
+ /**
55
+ * Singleton pattern implementation makes "clone" unavailable
56
+ *
57
+ * @return void
58
+ */
59
+ private function __clone()
60
+ {}
61
+
62
+ /**
63
+ * Returns an instance of Zend_Auth
64
+ *
65
+ * Singleton pattern implementation
66
+ *
67
+ * @return Zend_Auth Provides a fluent interface
68
+ */
69
+ public static function getInstance()
70
+ {
71
+ if (null === self::$_instance) {
72
+ self::$_instance = new self();
73
+ }
74
+
75
+ return self::$_instance;
76
+ }
77
+
78
+ /**
79
+ * Returns the persistent storage handler
80
+ *
81
+ * Session storage is used by default unless a different storage adapter has been set.
82
+ *
83
+ * @return Zend_Auth_Storage_Interface
84
+ */
85
+ public function getStorage()
86
+ {
87
+ if (null === $this->_storage) {
88
+ /**
89
+ * @see Zend_Auth_Storage_Session
90
+ */
91
+ require_once 'Zend/Auth/Storage/Session.php';
92
+ $this->setStorage(new Zend_Auth_Storage_Session());
93
+ }
94
+
95
+ return $this->_storage;
96
+ }
97
+
98
+ /**
99
+ * Sets the persistent storage handler
100
+ *
101
+ * @param Zend_Auth_Storage_Interface $storage
102
+ * @return Zend_Auth Provides a fluent interface
103
+ */
104
+ public function setStorage(Zend_Auth_Storage_Interface $storage)
105
+ {
106
+ $this->_storage = $storage;
107
+ return $this;
108
+ }
109
+
110
+ /**
111
+ * Authenticates against the supplied adapter
112
+ *
113
+ * @param Zend_Auth_Adapter_Interface $adapter
114
+ * @return Zend_Auth_Result
115
+ */
116
+ public function authenticate(Zend_Auth_Adapter_Interface $adapter)
117
+ {
118
+ $result = $adapter->authenticate();
119
+
120
+ if ($result->isValid()) {
121
+ $this->getStorage()->write($result->getIdentity());
122
+ }
123
+
124
+ return $result;
125
+ }
126
+
127
+ /**
128
+ * Returns true if and only if an identity is available from storage
129
+ *
130
+ * @return boolean
131
+ */
132
+ public function hasIdentity()
133
+ {
134
+ return !$this->getStorage()->isEmpty();
135
+ }
136
+
137
+ /**
138
+ * Returns the identity from storage or null if no identity is available
139
+ *
140
+ * @return mixed|null
141
+ */
142
+ public function getIdentity()
143
+ {
144
+ $storage = $this->getStorage();
145
+
146
+ if ($storage->isEmpty()) {
147
+ return null;
148
+ }
149
+
150
+ return $storage->read();
151
+ }
152
+
153
+ /**
154
+ * Clears the identity from persistent storage
155
+ *
156
+ * @return void
157
+ */
158
+ public function clearIdentity()
159
+ {
160
+ $this->getStorage()->clear();
161
+ }
162
+ }
lib/Zend/Auth/Adapter/DbTable.php ADDED
@@ -0,0 +1,461 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Zend Framework
4
+ *
5
+ * LICENSE
6
+ *
7
+ * This source file is subject to the new BSD license that is bundled
8
+ * with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://framework.zend.com/license/new-bsd
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@zend.com so we can send you a copy immediately.
14
+ *
15
+ * @category Zend
16
+ * @package Zend_Auth
17
+ * @subpackage Zend_Auth_Adapter
18
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
19
+ * @license http://framework.zend.com/license/new-bsd New BSD License
20
+ * @version $Id: DbTable.php 8862 2008-03-16 15:36:00Z thomas $
21
+ */
22
+
23
+
24
+ /**
25
+ * @see Zend_Auth_Adapter_Interface
26
+ */
27
+ require_once 'Zend/Auth/Adapter/Interface.php';
28
+
29
+ /**
30
+ * @see Zend_Db_Adapter_Abstract
31
+ */
32
+ require_once 'Zend/Db/Adapter/Abstract.php';
33
+
34
+ /**
35
+ * @see Zend_Auth_Result
36
+ */
37
+ require_once 'Zend/Auth/Result.php';
38
+
39
+
40
+ /**
41
+ * @category Zend
42
+ * @package Zend_Auth
43
+ * @subpackage Zend_Auth_Adapter
44
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
45
+ * @license http://framework.zend.com/license/new-bsd New BSD License
46
+ */
47
+ class Zend_Auth_Adapter_DbTable implements Zend_Auth_Adapter_Interface
48
+ {
49
+ /**
50
+ * Database Connection
51
+ *
52
+ * @var Zend_Db_Adapter_Abstract
53
+ */
54
+ protected $_zendDb = null;
55
+
56
+ /**
57
+ * $_tableName - the table name to check
58
+ *
59
+ * @var string
60
+ */
61
+ protected $_tableName = null;
62
+
63
+ /**
64
+ * $_identityColumn - the column to use as the identity
65
+ *
66
+ * @var string
67
+ */
68
+ protected $_identityColumn = null;
69
+
70
+ /**
71
+ * $_credentialColumns - columns to be used as the credentials
72
+ *
73
+ * @var string
74
+ */
75
+ protected $_credentialColumn = null;
76
+
77
+ /**
78
+ * $_identity - Identity value
79
+ *
80
+ * @var string
81
+ */
82
+ protected $_identity = null;
83
+
84
+ /**
85
+ * $_credential - Credential values
86
+ *
87
+ * @var string
88
+ */
89
+ protected $_credential = null;
90
+
91
+ /**
92
+ * $_credentialTreatment - Treatment applied to the credential, such as MD5() or PASSWORD()
93
+ *
94
+ * @var string
95
+ */
96
+ protected $_credentialTreatment = null;
97
+
98
+ /**
99
+ * $_authenticateResultInfo
100
+ *
101
+ * @var array
102
+ */
103
+ protected $_authenticateResultInfo = null;
104
+
105
+ /**
106
+ * $_resultRow - Results of database authentication query
107
+ *
108
+ * @var array
109
+ */
110
+ protected $_resultRow = null;
111
+
112
+ /**
113
+ * __construct() - Sets configuration options
114
+ *
115
+ * @param Zend_Db_Adapter_Abstract $zendDb
116
+ * @param string $tableName
117
+ * @param string $identityColumn
118
+ * @param string $credentialColumn
119
+ * @param string $credentialTreatment
120
+ * @return void
121
+ */
122
+ public function __construct(Zend_Db_Adapter_Abstract $zendDb, $tableName = null, $identityColumn = null,
123
+ $credentialColumn = null, $credentialTreatment = null)
124
+ {
125
+ $this->_zendDb = $zendDb;
126
+
127
+ if (null !== $tableName) {
128
+ $this->setTableName($tableName);
129
+ }
130
+
131
+ if (null !== $identityColumn) {
132
+ $this->setIdentityColumn($identityColumn);
133
+ }
134
+
135
+ if (null !== $credentialColumn) {
136
+ $this->setCredentialColumn($credentialColumn);
137
+ }
138
+
139
+ if (null !== $credentialTreatment) {
140
+ $this->setCredentialTreatment($credentialTreatment);
141
+ }
142
+ }
143
+
144
+ /**
145
+ * setTableName() - set the table name to be used in the select query
146
+ *
147
+ * @param string $tableName
148
+ * @return Zend_Auth_Adapter_DbTable Provides a fluent interface
149
+ */
150
+ public function setTableName($tableName)
151
+ {
152
+ $this->_tableName = $tableName;
153
+ return $this;
154
+ }
155
+
156
+ /**
157
+ * setIdentityColumn() - set the column name to be used as the identity column
158
+ *
159
+ * @param string $identityColumn
160
+ * @return Zend_Auth_Adapter_DbTable Provides a fluent interface
161
+ */
162
+ public function setIdentityColumn($identityColumn)
163
+ {
164
+ $this->_identityColumn = $identityColumn;
165
+ return $this;
166
+ }
167
+
168
+ /**
169
+ * setCredentialColumn() - set the column name to be used as the credential column
170
+ *
171
+ * @param string $credentialColumn
172
+ * @return Zend_Auth_Adapter_DbTable Provides a fluent interface
173
+ */
174
+ public function setCredentialColumn($credentialColumn)
175
+ {
176
+ $this->_credentialColumn = $credentialColumn;
177
+ return $this;
178
+ }
179
+
180
+ /**
181
+ * setCredentialTreatment() - allows the developer to pass a parameterized string that is
182
+ * used to transform or treat the input credential data
183
+ *
184
+ * In many cases, passwords and other sensitive data are encrypted, hashed, encoded,
185
+ * obscured, or otherwise treated through some function or algorithm. By specifying a
186
+ * parameterized treatment string with this method, a developer may apply arbitrary SQL
187
+ * upon input credential data.
188
+ *
189
+ * Examples:
190
+ *
191
+ * 'PASSWORD(?)'
192
+ * 'MD5(?)'
193
+ *
194
+ * @param string $treatment
195
+ * @return Zend_Auth_Adapter_DbTable Provides a fluent interface
196
+ */
197
+ public function setCredentialTreatment($treatment)
198
+ {
199
+ $this->_credentialTreatment = $treatment;
200
+ return $this;
201
+ }
202
+
203
+ /**
204
+ * setIdentity() - set the value to be used as the identity
205
+ *
206
+ * @param string $value
207
+ * @return Zend_Auth_Adapter_DbTable Provides a fluent interface
208
+ */
209
+ public function setIdentity($value)
210
+ {
211
+ $this->_identity = $value;
212
+ return $this;
213
+ }
214
+
215
+ /**
216
+ * setCredential() - set the credential value to be used, optionally can specify a treatment
217
+ * to be used, should be supplied in parameterized form, such as 'MD5(?)' or 'PASSWORD(?)'
218
+ *
219
+ * @param string $credential
220
+ * @return Zend_Auth_Adapter_DbTable Provides a fluent interface
221
+ */
222
+ public function setCredential($credential)
223
+ {
224
+ $this->_credential = $credential;
225
+ return $this;
226
+ }
227
+
228
+ /**
229
+ * getResultRowObject() - Returns the result row as a stdClass object
230
+ *
231
+ * @param string|array $returnColumns
232
+ * @param string|array $omitColumns
233
+ * @return stdClass|boolean
234
+ */
235
+ public function getResultRowObject($returnColumns = null, $omitColumns = null)
236
+ {
237
+ if (!$this->_resultRow) {
238
+ return false;
239
+ }
240
+
241
+ $returnObject = new stdClass();
242
+
243
+ if (null !== $returnColumns) {
244
+
245
+ $availableColumns = array_keys($this->_resultRow);
246
+ foreach ( (array) $returnColumns as $returnColumn) {
247
+ if (in_array($returnColumn, $availableColumns)) {
248
+ $returnObject->{$returnColumn} = $this->_resultRow[$returnColumn];
249
+ }
250
+ }
251
+ return $returnObject;
252
+
253
+ } elseif (null !== $omitColumns) {
254
+
255
+ $omitColumns = (array) $omitColumns;
256
+ foreach ($this->_resultRow as $resultColumn => $resultValue) {
257
+ if (!in_array($resultColumn, $omitColumns)) {
258
+ $returnObject->{$resultColumn} = $resultValue;
259
+ }
260
+ }
261
+ return $returnObject;
262
+
263
+ } else {
264
+
265
+ foreach ($this->_resultRow as $resultColumn => $resultValue) {
266
+ $returnObject->{$resultColumn} = $resultValue;
267
+ }
268
+ return $returnObject;
269
+
270
+ }
271
+ }
272
+
273
+ /**
274
+ * authenticate() - defined by Zend_Auth_Adapter_Interface. This method is called to
275
+ * attempt an authenication. Previous to this call, this adapter would have already
276
+ * been configured with all nessissary information to successfully connect to a database
277
+ * table and attempt to find a record matching the provided identity.
278
+ *
279
+ * @throws Zend_Auth_Adapter_Exception if answering the authentication query is impossible
280
+ * @return Zend_Auth_Result
281
+ */
282
+ public function authenticate()
283
+ {
284
+ $this->_authenticateSetup();
285
+ $dbSelect = $this->_authenticateCreateSelect();
286
+ $resultIdentities = $this->_authenticateQuerySelect($dbSelect);
287
+
288
+ if ( ($authResult = $this->_authenticateValidateResultset($resultIdentities)) instanceof Zend_Auth_Result) {
289
+ return $authResult;
290
+ }
291
+
292
+ $authResult = $this->_authenticateValidateResult(array_shift($resultIdentities));
293
+ return $authResult;
294
+ }
295
+
296
+ /**
297
+ * _authenticateSetup() - This method abstracts the steps involved with making sure
298
+ * that this adapter was indeed setup properly with all required peices of information.
299
+ *
300
+ * @throws Zend_Auth_Adapter_Exception - in the event that setup was not done properly
301
+ * @return true
302
+ */
303
+ protected function _authenticateSetup()
304
+ {
305
+ $exception = null;
306
+
307
+ if ($this->_tableName == '') {
308
+ $exception = 'A table must be supplied for the Zend_Auth_Adapter_DbTable authentication adapter.';
309
+ } elseif ($this->_identityColumn == '') {
310
+ $exception = 'An identity column must be supplied for the Zend_Auth_Adapter_DbTable authentication adapter.';
311
+ } elseif ($this->_credentialColumn == '') {
312
+ $exception = 'A credential column must be supplied for the Zend_Auth_Adapter_DbTable authentication adapter.';
313
+ } elseif ($this->_identity == '') {
314
+ $exception = 'A value for the identity was not provided prior to authentication with Zend_Auth_Adapter_DbTable.';
315
+ } elseif ($this->_credential === null) {
316
+ $exception = 'A credential value was not provided prior to authentication with Zend_Auth_Adapter_DbTable.';
317
+ }
318
+
319
+ if (null !== $exception) {
320
+ /**
321
+ * @see Zend_Auth_Adapter_Exception
322
+ */
323
+ require_once 'Zend/Auth/Adapter/Exception.php';
324
+ throw new Zend_Auth_Adapter_Exception($exception);
325
+ }
326
+
327
+ $this->_authenticateResultInfo = array(
328
+ 'code' => Zend_Auth_Result::FAILURE,
329
+ 'identity' => $this->_identity,
330
+ 'messages' => array()
331
+ );
332
+
333
+ return true;
334
+ }
335
+
336
+ /**
337
+ * _authenticateCreateSelect() - This method creates a Zend_Db_Select object that
338
+ * is completely configured to be queried against the database.
339
+ *
340
+ * @return Zend_Db_Select
341
+ */
342
+ protected function _authenticateCreateSelect()
343
+ {
344
+ // build credential expression
345
+ if (empty($this->_credentialTreatment) || (strpos($this->_credentialTreatment, "?") === false)) {
346
+ $this->_credentialTreatment = '?';
347
+ }
348
+
349
+ $credentialExpression = new Zend_Db_Expr(
350
+ '(CASE WHEN ' .
351
+ $this->_zendDb->quoteInto(
352
+ $this->_zendDb->quoteIdentifier($this->_credentialColumn, true)
353
+ . ' = ' . $this->_credentialTreatment, $this->_credential
354
+ )
355
+ . ' THEN 1 ELSE 0 END) AS '
356
+ . $this->_zendDb->quoteIdentifier('zend_auth_credential_match')
357
+ );
358
+
359
+ // get select
360
+ $dbSelect = $this->_zendDb->select();
361
+ $dbSelect->from($this->_tableName, array('*', $credentialExpression))
362
+ ->where($this->_zendDb->quoteIdentifier($this->_identityColumn, true) . ' = ?', $this->_identity);
363
+
364
+ return $dbSelect;
365
+ }
366
+
367
+ /**
368
+ * _authenticateQuerySelect() - This method accepts a Zend_Db_Select object and
369
+ * performs a query against the database with that object.
370
+ *
371
+ * @param Zend_Db_Select $dbSelect
372
+ * @throws Zend_Auth_Adapter_Exception - when a invalid select object is encoutered
373
+ * @return array
374
+ */
375
+ protected function _authenticateQuerySelect(Zend_Db_Select $dbSelect)
376
+ {
377
+ try {
378
+ if ($this->_zendDb->getFetchMode() != Zend_DB::FETCH_ASSOC) {
379
+ $origDbFetchMode = $this->_zendDb->getFetchMode();
380
+ $this->_zendDb->setFetchMode(Zend_DB::FETCH_ASSOC);
381
+ }
382
+ $resultIdentities = $this->_zendDb->fetchAll($dbSelect->__toString());
383
+ if (isset($origDbFetchMode)) {
384
+ $this->_zendDb->setFetchMode($origDbFetchMode);
385
+ unset($origDbFetchMode);
386
+ }
387
+ } catch (Exception $e) {
388
+ /**
389
+ * @see Zend_Auth_Adapter_Exception
390
+ */
391
+ require_once 'Zend/Auth/Adapter/Exception.php';
392
+ throw new Zend_Auth_Adapter_Exception('The supplied parameters to Zend_Auth_Adapter_DbTable failed to '
393
+ . 'produce a valid sql statement, please check table and column names '
394
+ . 'for validity.');
395
+ }
396
+ return $resultIdentities;
397
+ }
398
+
399
+ /**
400
+ * _authenticateValidateResultSet() - This method attempts to make certian that only one
401
+ * record was returned in the result set
402
+ *
403
+ * @param array $resultIdentities
404
+ * @return true|Zend_Auth_Result
405
+ */
406
+ protected function _authenticateValidateResultSet(array $resultIdentities)
407
+ {
408
+
409
+
410
+ if (count($resultIdentities) < 1) {
411
+ $this->_authenticateResultInfo['code'] = Zend_Auth_Result::FAILURE_IDENTITY_NOT_FOUND;
412
+ $this->_authenticateResultInfo['messages'][] = 'A record with the supplied identity could not be found.';
413
+ return $this->_authenticateCreateAuthResult();
414
+ } elseif (count($resultIdentities) > 1) {
415
+ $this->_authenticateResultInfo['code'] = Zend_Auth_Result::FAILURE_IDENTITY_AMBIGUOUS;
416
+ $this->_authenticateResultInfo['messages'][] = 'More than one record matches the supplied identity.';
417
+ return $this->_authenticateCreateAuthResult();
418
+ }
419
+
420
+ return true;
421
+ }
422
+
423
+ /**
424
+ * _authenticateValidateResult() - This method attempts to validate that the record in the
425
+ * result set is indeed a record that matched the identity provided to this adapter.
426
+ *
427
+ * @param array $resultIdentity
428
+ * @return Zend_Auth_Result
429
+ */
430
+ protected function _authenticateValidateResult($resultIdentity)
431
+ {
432
+ if ($resultIdentity['zend_auth_credential_match'] != '1') {
433
+ $this->_authenticateResultInfo['code'] = Zend_Auth_Result::FAILURE_CREDENTIAL_INVALID;
434
+ $this->_authenticateResultInfo['messages'][] = 'Supplied credential is invalid.';
435
+ return $this->_authenticateCreateAuthResult();
436
+ }
437
+
438
+ unset($resultIdentity['zend_auth_credential_match']);
439
+ $this->_resultRow = $resultIdentity;
440
+
441
+ $this->_authenticateResultInfo['code'] = Zend_Auth_Result::SUCCESS;
442
+ $this->_authenticateResultInfo['messages'][] = 'Authentication successful.';
443
+ return $this->_authenticateCreateAuthResult();
444
+ }
445
+
446
+ /**
447
+ * _authenticateCreateAuthResult() - This method creates a Zend_Auth_Result object
448
+ * from the information that has been collected during the authenticate() attempt.
449
+ *
450
+ * @return Zend_Auth_Result
451
+ */
452
+ protected function _authenticateCreateAuthResult()
453
+ {
454
+ return new Zend_Auth_Result(
455
+ $this->_authenticateResultInfo['code'],
456
+ $this->_authenticateResultInfo['identity'],
457
+ $this->_authenticateResultInfo['messages']
458
+ );
459
+ }
460
+
461
+ }
lib/Zend/Auth/Adapter/Digest.php ADDED
@@ -0,0 +1,230 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Zend Framework
4
+ *
5
+ * LICENSE
6
+ *
7
+ * This source file is subject to the new BSD license that is bundled
8
+ * with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://framework.zend.com/license/new-bsd
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@zend.com so we can send you a copy immediately.
14
+ *
15
+ * @category Zend
16
+ * @package Zend_Auth
17
+ * @subpackage Zend_Ath_Adapter
18
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
19
+ * @license http://framework.zend.com/license/new-bsd New BSD License
20
+ * @version $Id: Digest.php 8862 2008-03-16 15:36:00Z thomas $
21
+ */
22
+
23
+
24
+ /**
25
+ * @see Zend_Auth_Adapter_Interface
26
+ */
27
+ require_once 'Zend/Auth/Adapter/Interface.php';
28
+
29
+
30
+ /**
31
+ * @category Zend
32
+ * @package Zend_Auth
33
+ * @subpackage Zend_Auth_Adapter
34
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
35
+ * @license http://framework.zend.com/license/new-bsd New BSD License
36
+ */
37
+ class Zend_Auth_Adapter_Digest implements Zend_Auth_Adapter_Interface
38
+ {
39
+ /**
40
+ * Filename against which authentication queries are performed
41
+ *
42
+ * @var string
43
+ */
44
+ protected $_filename;
45
+
46
+ /**
47
+ * Digest authentication realm
48
+ *
49
+ * @var string
50
+ */
51
+ protected $_realm;
52
+
53
+ /**
54
+ * Digest authentication user
55
+ *
56
+ * @var string
57
+ */
58
+ protected $_username;
59
+
60
+ /**
61
+ * Password for the user of the realm
62
+ *
63
+ * @var string
64
+ */
65
+ protected $_password;
66
+
67
+ /**
68
+ * Sets adapter options
69
+ *
70
+ * @param mixed $filename
71
+ * @param mixed $realm
72
+ * @param mixed $username
73
+ * @param mixed $password
74
+ * @return void
75
+ */
76
+ public function __construct($filename = null, $realm = null, $username = null, $password = null)
77
+ {
78
+ $options = array('filename', 'realm', 'username', 'password');
79
+ foreach ($options as $option) {
80
+ if (null !== $$option) {
81
+ $methodName = 'set' . ucfirst($option);
82
+ $this->$methodName($$option);
83
+ }
84
+ }
85
+ }
86
+
87
+ /**
88
+ * Returns the filename option value or null if it has not yet been set
89
+ *
90
+ * @return string|null
91
+ */
92
+ public function getFilename()
93
+ {
94
+ return $this->_filename;
95
+ }
96
+
97
+ /**
98
+ * Sets the filename option value
99
+ *
100
+ * @param mixed $filename
101
+ * @return Zend_Auth_Adapter_Digest Provides a fluent interface
102
+ */
103
+ public function setFilename($filename)
104
+ {
105
+ $this->_filename = (string) $filename;
106
+ return $this;
107
+ }
108
+
109
+ /**
110
+ * Returns the realm option value or null if it has not yet been set
111
+ *
112
+ * @return string|null
113
+ */
114
+ public function getRealm()
115
+ {
116
+ return $this->_realm;
117
+ }
118
+
119
+ /**
120
+ * Sets the realm option value
121
+ *
122
+ * @param mixed $realm
123
+ * @return Zend_Auth_Adapter_Digest Provides a fluent interface
124
+ */
125
+ public function setRealm($realm)
126
+ {
127
+ $this->_realm = (string) $realm;
128
+ return $this;
129
+ }
130
+
131
+ /**
132
+ * Returns the username option value or null if it has not yet been set
133
+ *
134
+ * @return string|null
135
+ */
136
+ public function getUsername()
137
+ {
138
+ return $this->_username;
139
+ }
140
+
141
+ /**
142
+ * Sets the username option value
143
+ *
144
+ * @param mixed $username
145
+ * @return Zend_Auth_Adapter_Digest Provides a fluent interface
146
+ */
147
+ public function setUsername($username)
148
+ {
149
+ $this->_username = (string) $username;
150
+ return $this;
151
+ }
152
+
153
+ /**
154
+ * Returns the password option value or null if it has not yet been set
155
+ *
156
+ * @return string|null
157
+ */
158
+ public function getPassword()
159
+ {
160
+ return $this->_password;
161
+ }
162
+
163
+ /**
164
+ * Sets the password option value
165
+ *
166
+ * @param mixed $password
167
+ * @return Zend_Auth_Adapter_Digest Provides a fluent interface
168
+ */
169
+ public function setPassword($password)
170
+ {
171
+ $this->_password = (string) $password;
172
+ return $this;
173
+ }
174
+
175
+ /**
176
+ * Defined by Zend_Auth_Adapter_Interface
177
+ *
178
+ * @throws Zend_Auth_Adapter_Exception
179
+ * @return Zend_Auth_Result
180
+ */
181
+ public function authenticate()
182
+ {
183
+ $optionsRequired = array('filename', 'realm', 'username', 'password');
184
+ foreach ($optionsRequired as $optionRequired) {
185
+ if (null === $this->{"_$optionRequired"}) {
186
+ /**
187
+ * @see Zend_Auth_Adapter_Exception
188
+ */
189
+ require_once 'Zend/Auth/Adapter/Exception.php';
190
+ throw new Zend_Auth_Adapter_Exception("Option '$optionRequired' must be set before authentication");
191
+ }
192
+ }
193
+
194
+ if (false === ($fileHandle = @fopen($this->_filename, 'r'))) {
195
+ /**
196
+ * @see Zend_Auth_Adapter_Exception
197
+ */
198
+ require_once 'Zend/Auth/Adapter/Exception.php';
199
+ throw new Zend_Auth_Adapter_Exception("Cannot open '$this->_filename' for reading");
200
+ }
201
+
202
+ $id = "$this->_username:$this->_realm";
203
+ $idLength = strlen($id);
204
+
205
+ $result = array(
206
+ 'code' => Zend_Auth_Result::FAILURE,
207
+ 'identity' => array(
208
+ 'realm' => $this->_realm,
209
+ 'username' => $this->_username,
210
+ ),
211
+ 'messages' => array()
212
+ );
213
+
214
+ while ($line = trim(fgets($fileHandle))) {
215
+ if (substr($line, 0, $idLength) === $id) {
216
+ if (substr($line, -32) === md5("$this->_username:$this->_realm:$this->_password")) {
217
+ $result['code'] = Zend_Auth_Result::SUCCESS;
218
+ } else {
219
+ $result['code'] = Zend_Auth_Result::FAILURE_CREDENTIAL_INVALID;
220
+ $result['messages'][] = 'Password incorrect';
221
+ }
222
+ return new Zend_Auth_Result($result['code'], $result['identity'], $result['messages']);
223
+ }
224
+ }
225
+
226
+ $result['code'] = Zend_Auth_Result::FAILURE_IDENTITY_NOT_FOUND;
227
+ $result['messages'][] = "Username '$this->_username' and realm '$this->_realm' combination not found";
228
+ return new Zend_Auth_Result($result['code'], $result['identity'], $result['messages']);
229
+ }
230
+ }
lib/Zend/Auth/Adapter/Exception.php ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Zend Framework
4
+ *
5
+ * LICENSE
6
+ *
7
+ * This source file is subject to the new BSD license that is bundled
8
+ * with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://framework.zend.com/license/new-bsd
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@zend.com so we can send you a copy immediately.
14
+ *
15
+ * @category Zend
16
+ * @package Zend_Auth
17
+ * @subpackage Zend_Auth_Adapter
18
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
19
+ * @license http://framework.zend.com/license/new-bsd New BSD License
20
+ * @version $Id: Exception.php 8862 2008-03-16 15:36:00Z thomas $
21
+ */
22
+
23
+
24
+ /**
25
+ * Zend_Auth_Exception
26
+ */
27
+ require_once 'Zend/Auth/Exception.php';
28
+
29
+
30
+ /**
31
+ * @category Zend
32
+ * @package Zend_Auth
33
+ * @subpackage Zend_Auth_Adapter
34
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
35
+ * @license http://framework.zend.com/license/new-bsd New BSD License
36
+ */
37
+ class Zend_Auth_Adapter_Exception extends Zend_Auth_Exception
38
+ {}
lib/Zend/Auth/Adapter/Http.php ADDED
@@ -0,0 +1,841 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Zend Framework
4
+ *
5
+ * LICENSE
6
+ *
7
+ * This source file is subject to the new BSD license that is bundled
8
+ * with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://framework.zend.com/license/new-bsd
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@zend.com so we can send you a copy immediately.
14
+ *
15
+ * @category Zend
16
+ * @package Zend_Auth
17
+ * @subpackage Zend_Auth_Adapter_Http
18
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
19
+ * @license http://framework.zend.com/license/new-bsd New BSD License
20
+ * @version $Id: Http.php 8862 2008-03-16 15:36:00Z thomas $
21
+ */
22
+
23
+
24
+ /**
25
+ * @see Zend_Auth_Adapter_Interface
26
+ */
27
+ require_once 'Zend/Auth/Adapter/Interface.php';
28
+
29
+
30
+ /**
31
+ * HTTP Authentication Adapter
32
+ *
33
+ * Implements a pretty good chunk of RFC 2617.
34
+ *
35
+ * @category Zend
36
+ * @package Zend_Auth
37
+ * @subpackage Zend_Auth_Adapter_Http
38
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
39
+ * @license http://framework.zend.com/license/new-bsd New BSD License
40
+ * @todo Support auth-int
41
+ * @todo Track nonces, nonce-count, opaque for replay protection and stale support
42
+ * @todo Support Authentication-Info header
43
+ */
44
+ class Zend_Auth_Adapter_Http implements Zend_Auth_Adapter_Interface
45
+ {
46
+ /**
47
+ * Reference to the HTTP Request object
48
+ *
49
+ * @var Zend_Controller_Request_Http
50
+ */
51
+ protected $_request;
52
+
53
+ /**
54
+ * Reference to the HTTP Response object
55
+ *
56
+ * @var Zend_Controller_Response_Http
57
+ */
58
+ protected $_response;
59
+
60
+ /**
61
+ * Object that looks up user credentials for the Basic scheme
62
+ *
63
+ * @var Zend_Auth_Adapter_Http_Resolver_Interface
64
+ */
65
+ protected $_basicResolver;
66
+
67
+ /**
68
+ * Object that looks up user credentials for the Digest scheme
69
+ *
70
+ * @var Zend_Auth_Adapter_Http_Resolver_Interface
71
+ */
72
+ protected $_digestResolver;
73
+
74
+ /**
75
+ * List of authentication schemes supported by this class
76
+ *
77
+ * @var array
78
+ */
79
+ protected $_supportedSchemes = array('basic', 'digest');
80
+
81
+ /**
82
+ * List of schemes this class will accept from the client
83
+ *
84
+ * @var array
85
+ */
86
+ protected $_acceptSchemes;
87
+
88
+ /**
89
+ * Space-delimited list of protected domains for Digest Auth
90
+ *
91
+ * @var string
92
+ */
93
+ protected $_domains;
94
+
95
+ /**
96
+ * The protection realm to use
97
+ *
98
+ * @var string
99
+ */
100
+ protected $_realm;
101
+
102
+ /**
103
+ * Nonce timeout period
104
+ *
105
+ * @var integer
106
+ */
107
+ protected $_nonceTimeout;
108
+
109
+ /**
110
+ * Whether to send the opaque value in the header. True by default
111
+ *
112
+ * @var boolean
113
+ */
114
+ protected $_useOpaque;
115
+
116
+ /**
117
+ * List of the supported digest algorithms. I want to support both MD5 and
118
+ * MD5-sess, but MD5-sess won't make it into the first version.
119
+ *
120
+ * @var array
121
+ */
122
+ protected $_supportedAlgos = array('MD5');
123
+
124
+ /**
125
+ * The actual algorithm to use. Defaults to MD5
126
+ *
127
+ * @var string
128
+ */
129
+ protected $_algo;
130
+
131
+ /**
132
+ * List of supported qop options. My intetion is to support both 'auth' and
133
+ * 'auth-int', but 'auth-int' won't make it into the first version.
134
+ *
135
+ * @var array
136
+ */
137
+ protected $_supportedQops = array('auth');
138
+
139
+ /**
140
+ * Whether or not to do Proxy Authentication instead of origin server
141
+ * authentication (send 407's instead of 401's). Off by default.
142
+ *
143
+ * @var boolean
144
+ */
145
+ protected $_imaProxy;
146
+
147
+ /**
148
+ * Flag indicating the client is IE and didn't bother to return the opaque string
149
+ *
150
+ * @var boolean
151
+ */
152
+ protected $_ieNoOpaque;
153
+
154
+ /**
155
+ * Constructor
156
+ *
157
+ * @param array $config Configuration settings:
158
+ * 'accept_schemes' => 'basic'|'digest'|'basic digest'
159
+ * 'realm' => <string>
160
+ * 'digest_domains' => <string> Space-delimited list of URIs
161
+ * 'nonce_timeout' => <int>
162
+ * 'use_opaque' => <bool> Whether to send the opaque value in the header
163
+ * 'alogrithm' => <string> See $_supportedAlgos. Default: MD5
164
+ * 'proxy_auth' => <bool> Whether to do authentication as a Proxy
165
+ * @throws Zend_Auth_Adapter_Exception
166
+ * @return void
167
+ */
168
+ public function __construct(array $config)
169
+ {
170
+ if (!extension_loaded('hash')) {
171
+ /**
172
+ * @see Zend_Auth_Adapter_Exception
173
+ */
174
+ require_once 'Zend/Auth/Adapter/Exception.php';
175
+ throw new Zend_Auth_Adapter_Exception(__CLASS__ . ' requires the \'hash\' extension');
176
+ }
177
+
178
+ $this->_request = null;
179
+ $this->_response = null;
180
+ $this->_ieNoOpaque = false;
181
+
182
+
183
+ if (empty($config['accept_schemes'])) {
184
+ /**
185
+ * @see Zend_Auth_Adapter_Exception
186
+ */
187
+ require_once 'Zend/Auth/Adapter/Exception.php';
188
+ throw new Zend_Auth_Adapter_Exception('Config key \'accept_schemes\' is required');
189
+ }
190
+
191
+ $schemes = explode(' ', $config['accept_schemes']);
192
+ $this->_acceptSchemes = array_intersect($schemes, $this->_supportedSchemes);
193
+ if (empty($this->_acceptSchemes)) {
194
+ /**
195
+ * @see Zend_Auth_Adapter_Exception
196
+ */
197
+ require_once 'Zend/Auth/Adapter/Exception.php';
198
+ throw new Zend_Auth_Adapter_Exception('No supported schemes given in \'accept_schemes\'. Valid values: '
199
+ . implode(', ', $this->_supportedSchemes));
200
+ }
201
+
202
+ // Double-quotes are used to delimit the realm string in the HTTP header,
203
+ // and colons are field delimiters in the password file.
204
+ if (empty($config['realm']) ||
205
+ !ctype_print($config['realm']) ||
206
+ strpos($config['realm'], ':') !== false ||
207
+ strpos($config['realm'], '"') !== false) {
208
+ /**
209
+ * @see Zend_Auth_Adapter_Exception
210
+ */
211
+ require_once 'Zend/Auth/Adapter/Exception.php';
212
+ throw new Zend_Auth_Adapter_Exception('Config key \'realm\' is required, and must contain only printable '
213
+ . 'characters, excluding quotation marks and colons');
214
+ } else {
215
+ $this->_realm = $config['realm'];
216
+ }
217
+
218
+ if (in_array('digest', $this->_acceptSchemes)) {
219
+ if (empty($config['digest_domains']) ||
220
+ !ctype_print($config['digest_domains']) ||
221
+ strpos($config['digest_domains'], '"') !== false) {
222
+ /**
223
+ * @see Zend_Auth_Adapter_Exception
224
+ */
225
+ require_once 'Zend/Auth/Adapter/Exception.php';
226
+ throw new Zend_Auth_Adapter_Exception('Config key \'digest_domains\' is required, and must contain '
227
+ . 'only printable characters, excluding quotation marks');
228
+ } else {
229
+ $this->_domains = $config['digest_domains'];
230
+ }
231
+
232
+ if (empty($config['nonce_timeout']) ||
233
+ !is_numeric($config['nonce_timeout'])) {
234
+ /**
235
+ * @see Zend_Auth_Adapter_Exception
236
+ */
237
+ require_once 'Zend/Auth/Adapter/Exception.php';
238
+ throw new Zend_Auth_Adapter_Exception('Config key \'nonce_timeout\' is required, and must be an '
239
+ . 'integer');
240
+ } else {
241
+ $this->_nonceTimeout = (int) $config['nonce_timeout'];
242
+ }
243
+
244
+ // We use the opaque value unless explicitly told not to
245
+ if (isset($config['use_opaque']) && false == (bool) $config['use_opaque']) {
246
+ $this->_useOpaque = false;
247
+ } else {
248
+ $this->_useOpaque = true;
249
+ }
250
+
251
+ if (isset($config['algorithm']) && in_array($config['algorithm'], $this->_supportedAlgos)) {
252
+ $this->_algo = $config['algorithm'];
253
+ } else {
254
+ $this->_algo = 'MD5';
255
+ }
256
+ }
257
+
258
+ // Don't be a proxy unless explicitly told to do so
259
+ if (isset($config['proxy_auth']) && true == (bool) $config['proxy_auth']) {
260
+ $this->_imaProxy = true; // I'm a Proxy
261
+ } else {
262
+ $this->_imaProxy = false;
263
+ }
264
+ }
265
+
266
+ /**
267
+ * Setter for the _basicResolver property
268
+ *
269
+ * @param Zend_Auth_Adapter_Http_Resolver_Interface $resolver
270
+ * @return Zend_Auth_Adapter_Http Provides a fluent interface
271
+ */
272
+ public function setBasicResolver(Zend_Auth_Adapter_Http_Resolver_Interface $resolver)
273
+ {
274
+ $this->_basicResolver = $resolver;
275
+
276
+ return $this;
277
+ }
278
+
279
+ /**
280
+ * Getter for the _basicResolver property
281
+ *
282
+ * @return Zend_Auth_Adapter_Http_Resolver_Interface
283
+ */
284
+ public function getBasicResolver()
285
+ {
286
+ return $this->_basicResolver;
287
+ }
288
+
289
+ /**
290
+ * Setter for the _digestResolver property
291
+ *
292
+ * @param Zend_Auth_Adapter_Http_Resolver_Interface $resolver
293
+ * @return Zend_Auth_Adapter_Http Provides a fluent interface
294
+ */
295
+ public function setDigestResolver(Zend_Auth_Adapter_Http_Resolver_Interface $resolver)
296
+ {
297
+ $this->_digestResolver = $resolver;
298
+
299
+ return $this;
300
+ }
301
+
302
+ /**
303
+ * Getter for the _digestResolver property
304
+ *
305
+ * @return Zend_Auth_Adapter_Http_Resolver_Interface
306
+ */
307
+ public function getDigestResolver()
308
+ {
309
+ return $this->_digestResolver;
310
+ }
311
+
312
+ /**
313
+ * Setter for the Request object
314
+ *
315
+ * @param Zend_Controller_Request_Http $request
316
+ * @return Zend_Auth_Adapter_Http Provides a fluent interface
317
+ */
318
+ public function setRequest(Zend_Controller_Request_Http $request)
319
+ {
320
+ $this->_request = $request;
321
+
322
+ return $this;
323
+ }
324
+
325
+ /**
326
+ * Getter for the Request object
327
+ *
328
+ * @return Zend_Controller_Request_Http
329
+ */
330
+ public function getRequest()
331
+ {
332
+ return $this->_request;
333
+ }
334
+
335
+ /**
336
+ * Setter for the Response object
337
+ *
338
+ * @param Zend_Controller_Response_Http $response
339
+ * @return Zend_Auth_Adapter_Http Provides a fluent interface
340
+ */
341
+ public function setResponse(Zend_Controller_Response_Http $response)
342
+ {
343
+ $this->_response = $response;
344
+
345
+ return $this;
346
+ }
347
+
348
+ /**
349
+ * Getter for the Response object
350
+ *
351
+ * @return Zend_Controller_Response_Http
352
+ */
353
+ public function getResponse()
354
+ {
355
+ return $this->_response;
356
+ }
357
+
358
+ /**
359
+ * Authenticate
360
+ *
361
+ * @throws Zend_Auth_Adapter_Exception
362
+ * @return Zend_Auth_Result
363
+ */
364
+ public function authenticate()
365
+ {
366
+ if (empty($this->_request) ||
367
+ empty($this->_response)) {
368
+ /**
369
+ * @see Zend_Auth_Adapter_Exception
370
+ */
371
+ require_once 'Zend/Auth/Adapter/Exception.php';
372
+ throw new Zend_Auth_Adapter_Exception('Request and Response objects must be set before calling '
373
+ . 'authenticate()');
374
+ }
375
+
376
+ if ($this->_imaProxy) {
377
+ $getHeader = 'Proxy-Authorization';
378
+ } else {
379
+ $getHeader = 'Authorization';
380
+ }
381
+
382
+ $authHeader = $this->_request->getHeader($getHeader);
383
+ if (!$authHeader) {
384
+ return $this->_challengeClient();
385
+ }
386
+
387
+ list($clientScheme) = explode(' ', $authHeader);
388
+ $clientScheme = strtolower($clientScheme);
389
+
390
+ if (!in_array($clientScheme, $this->_supportedSchemes)) {
391
+ $this->_response->setHttpResponseCode(400);
392
+ return new Zend_Auth_Result(
393
+ Zend_Auth_Result::FAILURE_UNCATEGORIZED,
394
+ array(),
395
+ array('Client requested an unsupported authentication scheme')
396
+ );
397
+ }
398
+
399
+ // The server can issue multiple challenges, but the client should
400
+ // answer with only one selected auth scheme.
401
+ switch ($clientScheme) {
402
+ case 'basic':
403
+ $result = $this->_basicAuth($authHeader);
404
+ break;
405
+ case 'digest':
406
+ $result = $this->_digestAuth($authHeader);
407
+ break;
408
+ default:
409
+ /**
410
+ * @see Zend_Auth_Adapter_Exception
411
+ */
412
+ require_once 'Zend/Auth/Adapter/Exception.php';
413
+ throw new Zend_Auth_Adapter_Exception('Unsupported authentication scheme');
414
+ }
415
+
416
+ return $result;
417
+ }
418
+
419
+ /**
420
+ * Challenge Client
421
+ *
422
+ * Sets a 401 or 407 Unauthorized response code, and creates the
423
+ * appropriate Authenticate header(s) to prompt for credentials.
424
+ *
425
+ * @return Zend_Auth_Result Always returns a non-identity Auth result
426
+ */
427
+ protected function _challengeClient()
428
+ {
429
+ if ($this->_imaProxy) {
430
+ $statusCode = 407;
431
+ $headerName = 'Proxy-Authenticate';
432
+ } else {
433
+ $statusCode = 401;
434
+ $headerName = 'WWW-Authenticate';
435
+ }
436
+
437
+ $this->_response->setHttpResponseCode($statusCode);
438
+
439
+ // Send a challenge in each acceptable authentication scheme
440
+ if (in_array('basic', $this->_acceptSchemes)) {
441
+ $this->_response->setHeader($headerName, $this->_basicHeader());
442
+ }
443
+ if (in_array('digest', $this->_acceptSchemes)) {
444
+ $this->_response->setHeader($headerName, $this->_digestHeader());
445
+ }
446
+ return new Zend_Auth_Result(
447
+ Zend_Auth_Result::FAILURE_CREDENTIAL_INVALID,
448
+ array(),
449
+ array('Invalid or absent credentials; challenging client')
450
+ );
451
+ }
452
+
453
+ /**
454
+ * Basic Header
455
+ *
456
+ * Generates a Proxy- or WWW-Authenticate header value in the Basic
457
+ * authentication scheme.
458
+ *
459
+ * @return string Authenticate header value
460
+ */
461
+ protected function _basicHeader()
462
+ {
463
+ return 'Basic realm="' . $this->_realm . '"';
464
+ }
465
+
466
+ /**
467
+ * Digest Header
468
+ *
469
+ * Generates a Proxy- or WWW-Authenticate header value in the Digest
470
+ * authentication scheme.
471
+ *
472
+ * @return string Authenticate header value
473
+ */
474
+ protected function _digestHeader()
475
+ {
476
+ $wwwauth = 'Digest realm="' . $this->_realm . '", '
477
+ . 'domain="' . $this->_domains . '", '
478
+ . 'nonce="' . $this->_calcNonce() . '", '
479
+ . ($this->_useOpaque ? 'opaque="' . $this->_calcOpaque() . '", ' : '')
480
+ . 'algorithm="' . $this->_algo . '", '
481
+ . 'qop="' . implode(',', $this->_supportedQops) . '"';
482
+
483
+ return $wwwauth;
484
+ }
485
+
486
+ /**
487
+ * Basic Authentication
488
+ *
489
+ * @param string $header Client's Authorization header
490
+ * @throws Zend_Auth_Adapter_Exception
491
+ * @return Zend_Auth_Result
492
+ */
493
+ protected function _basicAuth($header)
494
+ {
495
+ if (empty($header)) {
496
+ /**
497
+ * @see Zend_Auth_Adapter_Exception
498
+ */
499
+ require_once 'Zend/Auth/Adapter/Exception.php';
500
+ throw new Zend_Auth_Adapter_Exception('The value of the client Authorization header is required');
501
+ }
502
+ if (empty($this->_basicResolver)) {
503
+ /**
504
+ * @see Zend_Auth_Adapter_Exception
505
+ */
506
+ require_once 'Zend/Auth/Adapter/Exception.php';
507
+ throw new Zend_Auth_Adapter_Exception('A basicResolver object must be set before doing Basic '
508
+ . 'authentication');
509
+ }
510
+
511
+ // Decode the Authorization header
512
+ $auth = substr($header, strlen('Basic '));
513
+ $auth = base64_decode($auth);
514
+ if (!$auth) {
515
+ /**
516
+ * @see Zend_Auth_Adapter_Exception
517
+ */
518
+ require_once 'Zend/Auth/Adapter/Exception.php';
519
+ throw new Zend_Auth_Adapter_Exception('Unable to base64_decode Authorization header value');
520
+ }
521
+
522
+ // See ZF-1253. Validate the credentials the same way the digest
523
+ // implementation does. If invalid credentials are detected,
524
+ // re-challenge the client.
525
+ if (!ctype_print($auth)) {
526
+ return $this->_challengeClient();
527
+ }
528
+ // Fix for ZF-1515: Now re-challenges on empty username or password
529
+ $creds = array_filter(explode(':', $auth));
530
+ if (count($creds) != 2) {
531
+ return $this->_challengeClient();
532
+ }
533
+
534
+ $password = $this->_basicResolver->resolve($creds[0], $this->_realm);
535
+ if ($password && $password == $creds[1]) {
536
+ $identity = array('username'=>$creds[0], 'realm'=>$this->_realm);
537
+ return new Zend_Auth_Result(Zend_Auth_Result::SUCCESS, $identity);
538
+ } else {
539
+ return $this->_challengeClient();
540
+ }
541
+ }
542
+
543
+ /**
544
+ * Digest Authentication
545
+ *
546
+ * @param string $header Client's Authorization header
547
+ * @throws Zend_Auth_Adapter_Exception
548
+ * @return Zend_Auth_Result Valid auth result only on successful auth
549
+ */
550
+ protected function _digestAuth($header)
551
+ {
552
+ if (empty($header)) {
553
+ /**
554
+ * @see Zend_Auth_Adapter_Exception
555
+ */
556
+ require_once 'Zend/Auth/Adapter/Exception.php';
557
+ throw new Zend_Auth_Adapter_Exception('The value of the client Authorization header is required');
558
+ }
559
+ if (empty($this->_digestResolver)) {
560
+ /**
561
+ * @see Zend_Auth_Adapter_Exception
562
+ */
563
+ require_once 'Zend/Auth/Adapter/Exception.php';
564
+ throw new Zend_Auth_Adapter_Exception('A digestResolver object must be set before doing Digest authentication');
565
+ }
566
+
567
+ $data = $this->_parseDigestAuth($header);
568
+ if ($data === false) {
569
+ $this->_response->setHttpResponseCode(400);
570
+ return new Zend_Auth_Result(
571
+ Zend_Auth_Result::FAILURE_UNCATEGORIZED,
572
+ array(),
573
+ array('Invalid Authorization header format')
574
+ );
575
+ }
576
+
577
+ // See ZF-1052. This code was a bit too unforgiving of invalid
578
+ // usernames. Now, if the username is bad, we re-challenge the client.
579
+ if ('::invalid::' == $data['username']) {
580
+ return $this->_challengeClient();
581
+ }
582
+
583
+ // Verify that the client sent back the same nonce
584
+ if ($this->_calcNonce() != $data['nonce']) {
585
+ return $this->_challengeClient();
586
+ }
587
+ // The opaque value is also required to match, but of course IE doesn't
588
+ // play ball.
589
+ if (!$this->_ieNoOpaque && $this->_calcOpaque() != $data['opaque']) {
590
+ return $this->_challengeClient();
591
+ }
592
+
593
+ // Look up the user's password hash. If not found, deny access.
594
+ // This makes no assumptions about how the password hash was
595
+ // constructed beyond that it must have been built in such a way as
596
+ // to be recreatable with the current settings of this object.
597
+ $ha1 = $this->_digestResolver->resolve($data['username'], $data['realm']);
598
+ if ($ha1 === false) {
599
+ return $this->_challengeClient();
600
+ }
601
+
602
+ // If MD5-sess is used, a1 value is made of the user's password
603
+ // hash with the server and client nonce appended, separated by
604
+ // colons.
605
+ if ($this->_algo == 'MD5-sess') {
606
+ $ha1 = hash('md5', $ha1 . ':' . $data['nonce'] . ':' . $data['cnonce']);
607
+ }
608
+
609
+ // Calculate h(a2). The value of this hash depends on the qop
610
+ // option selected by the client and the supported hash functions
611
+ switch ($data['qop']) {
612
+ case 'auth':
613
+ $a2 = $this->_request->getMethod() . ':' . $data['uri'];
614
+ break;
615
+ case 'auth-int':
616
+ // Should be REQUEST_METHOD . ':' . uri . ':' . hash(entity-body),
617
+ // but this isn't supported yet, so fall through to default case
618
+ default:
619
+ /**
620
+ * @see Zend_Auth_Adapter_Exception
621
+ */
622
+ require_once 'Zend/Auth/Adapter/Exception.php';
623
+ throw new Zend_Auth_Adapter_Exception('Client requested an unsupported qop option');
624
+ }
625
+ // Using hash() should make parameterizing the hash algorithm
626
+ // easier
627
+ $ha2 = hash('md5', $a2);
628
+
629
+
630
+ // Calculate the server's version of the request-digest. This must
631
+ // match $data['response']. See RFC 2617, section 3.2.2.1
632
+ $message = $data['nonce'] . ':' . $data['nc'] . ':' . $data['cnonce'] . ':' . $data['qop'] . ':' . $ha2;
633
+ $digest = hash('md5', $ha1 . ':' . $message);
634
+
635
+ // If our digest matches the client's let them in, otherwise return
636
+ // a 401 code and exit to prevent access to the protected resource.
637
+ if ($digest == $data['response']) {
638
+ $identity = array('username'=>$data['username'], 'realm'=>$data['realm']);
639
+ return new Zend_Auth_Result(Zend_Auth_Result::SUCCESS, $identity);
640
+ } else {
641
+ return $this->_challengeClient();
642
+ }
643
+ }
644
+
645
+ /**
646
+ * Calculate Nonce
647
+ *
648
+ * @return string The nonce value
649
+ */
650
+ protected function _calcNonce()
651
+ {
652
+ // Once subtle consequence of this timeout calculation is that it
653
+ // actually divides all of time into _nonceTimeout-sized sections, such
654
+ // that the value of timeout is the point in time of the next
655
+ // approaching "boundary" of a section. This allows the server to
656
+ // consistently generate the same timeout (and hence the same nonce
657
+ // value) across requests, but only as long as one of those
658
+ // "boundaries" is not crossed between requests. If that happens, the
659
+ // nonce will change on its own, and effectively log the user out. This
660
+ // would be surprising if the user just logged in.
661
+ $timeout = ceil(time() / $this->_nonceTimeout) * $this->_nonceTimeout;
662
+
663
+ $nonce = hash('md5', $timeout . ':' . $this->_request->getServer('HTTP_USER_AGENT') . ':' . __CLASS__);
664
+ return $nonce;
665
+ }
666
+
667
+ /**
668
+ * Calculate Opaque
669
+ *
670
+ * The opaque string can be anything; the client must return it exactly as
671
+ * it was sent. It may be useful to store data in this string in some
672
+ * applications. Ideally, a new value for this would be generated each time
673
+ * a WWW-Authenticate header is sent (in order to reduce predictability),
674
+ * but we would have to be able to create the same exact value across at
675
+ * least two separate requests from the same client.
676
+ *
677
+ * @return string The opaque value
678
+ */
679
+ protected function _calcOpaque()
680
+ {
681
+ return hash('md5', 'Opaque Data:' . __CLASS__);
682
+ }
683
+
684
+ /**
685
+ * Parse Digest Authorization header
686
+ *
687
+ * @param string $header Client's Authorization: HTTP header
688
+ * @return array|false Data elements from header, or false if any part of
689
+ * the header is invalid
690
+ */
691
+ protected function _parseDigestAuth($header)
692
+ {
693
+ $temp = null;
694
+ $data = array();
695
+
696
+ // See ZF-1052. Detect invalid usernames instead of just returning a
697
+ // 400 code.
698
+ $ret = preg_match('/username="([^"]+)"/', $header, $temp);
699
+ if (!$ret || empty($temp[1])
700
+ || !ctype_print($temp[1])
701
+ || strpos($temp[1], ':') !== false) {
702
+ $data['username'] = '::invalid::';
703
+ } else {
704
+ $data['username'] = $temp[1];
705
+ }
706
+ $temp = null;
707
+
708
+ $ret = preg_match('/realm="([^"]+)"/', $header, $temp);
709
+ if (!$ret || empty($temp[1])) {
710
+ return false;
711
+ }
712
+ if (!ctype_print($temp[1]) || strpos($temp[1], ':') !== false) {
713
+ return false;
714
+ } else {
715
+ $data['realm'] = $temp[1];
716
+ }
717
+ $temp = null;
718
+
719
+ $ret = preg_match('/nonce="([^"]+)"/', $header, $temp);
720
+ if (!$ret || empty($temp[1])) {
721
+ return false;
722
+ }
723
+ if (!ctype_xdigit($temp[1])) {
724
+ return false;
725
+ } else {
726
+ $data['nonce'] = $temp[1];
727
+ }
728
+ $temp = null;
729
+
730
+ $ret = preg_match('/uri="([^"]+)"/', $header, $temp);
731
+ if (!$ret || empty($temp[1])) {
732
+ return false;
733
+ }
734
+ // Section 3.2.2.5 in RFC 2617 says the authenticating server must
735
+ // verify that the URI field in the Authorization header is for the
736
+ // same resource requested in the Request Line.
737
+ $rUri = @parse_url($this->_request->getRequestUri());
738
+ $cUri = @parse_url($temp[1]);
739
+ if (false === $rUri || false === $cUri) {
740
+ return false;
741
+ } else {
742
+ // Make sure the path portion of both URIs is the same
743
+ if ($rUri['path'] != $cUri['path']) {
744
+ return false;
745
+ }
746
+ // Section 3.2.2.5 seems to suggest that the value of the URI
747
+ // Authorization field should be made into an absolute URI if the
748
+ // Request URI is absolute, but it's vague, and that's a bunch of
749
+ // code I don't want to write right now.
750
+ $data['uri'] = $temp[1];
751
+ }
752
+ $temp = null;
753
+
754
+ $ret = preg_match('/response="([^"]+)"/', $header, $temp);
755
+ if (!$ret || empty($temp[1])) {
756
+ return false;
757
+ }
758
+ if (32 != strlen($temp[1]) || !ctype_xdigit($temp[1])) {
759
+ return false;
760
+ } else {
761
+ $data['response'] = $temp[1];
762
+ }
763
+ $temp = null;
764
+
765
+ // The spec says this should default to MD5 if omitted. OK, so how does
766
+ // that square with the algo we send out in the WWW-Authenticate header,
767
+ // if it can easily be overridden by the client?
768
+ $ret = preg_match('/algorithm="?(' . $this->_algo . ')"?/', $header, $temp);
769
+ if ($ret && !empty($temp[1])
770
+ && in_array($temp[1], $this->_supportedAlgos)) {
771
+ $data['algorithm'] = $temp[1];
772
+ } else {
773
+ $data['algorithm'] = 'MD5'; // = $this->_algo; ?
774
+ }
775
+ $temp = null;
776
+
777
+ // Not optional in this implementation
778
+ $ret = preg_match('/cnonce="([^"]+)"/', $header, $temp);
779
+ if (!$ret || empty($temp[1])) {
780
+ return false;
781
+ }
782
+ if (!ctype_print($temp[1])) {
783
+ return false;
784
+ } else {
785
+ $data['cnonce'] = $temp[1];
786
+ }
787
+ $temp = null;
788
+
789
+ // If the server sent an opaque value, the client must send it back
790
+ if ($this->_useOpaque) {
791
+ $ret = preg_match('/opaque="([^"]+)"/', $header, $temp);
792
+ if (!$ret || empty($temp[1])) {
793
+
794
+ // Big surprise: IE isn't RFC 2617-compliant.
795
+ if (false !== strpos($this->_request->getHeader('User-Agent'), 'MSIE')) {
796
+ $temp[1] = '';
797
+ $this->_ieNoOpaque = true;
798
+ } else {
799
+ return false;
800
+ }
801
+ }
802
+ // This implementation only sends MD5 hex strings in the opaque value
803
+ if (!$this->_ieNoOpaque &&
804
+ (32 != strlen($temp[1]) || !ctype_xdigit($temp[1]))) {
805
+ return false;
806
+ } else {
807
+ $data['opaque'] = $temp[1];
808
+ }
809
+ $temp = null;
810
+ }
811
+
812
+ // Not optional in this implementation, but must be one of the supported
813
+ // qop types
814
+ $ret = preg_match('/qop="?(' . implode('|', $this->_supportedQops) . ')"?/', $header, $temp);
815
+ if (!$ret || empty($temp[1])) {
816
+ return false;
817
+ }
818
+ if (!in_array($temp[1], $this->_supportedQops)) {
819
+ return false;
820
+ } else {
821
+ $data['qop'] = $temp[1];
822
+ }
823
+ $temp = null;
824
+
825
+ // Not optional in this implementation. The spec says this value
826
+ // shouldn't be a quoted string, but apparently some implementations
827
+ // quote it anyway. See ZF-1544.
828
+ $ret = preg_match('/nc="?([0-9A-Fa-f]{8})"?/', $header, $temp);
829
+ if (!$ret || empty($temp[1])) {
830
+ return false;
831
+ }
832
+ if (8 != strlen($temp[1]) || !ctype_xdigit($temp[1])) {
833
+ return false;
834
+ } else {
835
+ $data['nc'] = $temp[1];
836
+ }
837
+ $temp = null;
838
+
839
+ return $data;
840
+ }
841
+ }
lib/Zend/Auth/Adapter/Http/Resolver/Exception.php ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Zend Framework
4
+ *
5
+ * LICENSE
6
+ *
7
+ * This source file is subject to the new BSD license that is bundled
8
+ * with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://framework.zend.com/license/new-bsd
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@zend.com so we can send you a copy immediately.
14
+ *
15
+ * @category Zend
16
+ * @package Zend_Auth
17
+ * @subpackage Zend_Auth_Adapter_Http
18
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
19
+ * @license http://framework.zend.com/license/new-bsd New BSD License
20
+ * @version $Id: Exception.php 8862 2008-03-16 15:36:00Z thomas $
21
+ */
22
+
23
+
24
+ /**
25
+ * @see Zend_Auth_Exception
26
+ */
27
+ require_once 'Zend/Auth/Exception.php';
28
+
29
+
30
+ /**
31
+ * HTTP Auth Resolver Exception
32
+ *
33
+ * @category Zend
34
+ * @package Zend_Auth
35
+ * @subpackage Zend_Auth_Adapter_Http
36
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
37
+ * @license http://framework.zend.com/license/new-bsd New BSD License
38
+ */
39
+ class Zend_Auth_Adapter_Http_Resolver_Exception extends Zend_Auth_Exception
40
+ {}
lib/Zend/Auth/Adapter/Http/Resolver/File.php ADDED
@@ -0,0 +1,167 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Zend Framework
4
+ *
5
+ * LICENSE
6
+ *
7
+ * This source file is subject to the new BSD license that is bundled
8
+ * with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://framework.zend.com/license/new-bsd
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@zend.com so we can send you a copy immediately.
14
+ *
15
+ * @category Zend
16
+ * @package Zend_Auth
17
+ * @subpackage Zend_Auth_Adapter_Http
18
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
19
+ * @license http://framework.zend.com/license/new-bsd New BSD License
20
+ * @version $Id: File.php 8862 2008-03-16 15:36:00Z thomas $
21
+ */
22
+
23
+
24
+ /**
25
+ * @see Zend_Auth_Adapter_Http_Resolver_Interface
26
+ */
27
+ require_once 'Zend/Auth/Adapter/Http/Resolver/Interface.php';
28
+
29
+
30
+ /**
31
+ * HTTP Authentication File Resolver
32
+ *
33
+ * @category Zend
34
+ * @package Zend_Auth
35
+ * @subpackage Zend_Auth_Adapter_Http
36
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
37
+ * @license http://framework.zend.com/license/new-bsd New BSD License
38
+ */
39
+ class Zend_Auth_Adapter_Http_Resolver_File implements Zend_Auth_Adapter_Http_Resolver_Interface
40
+ {
41
+ /**
42
+ * Path to credentials file
43
+ *
44
+ * @var string
45
+ */
46
+ protected $_file;
47
+
48
+ /**
49
+ * Constructor
50
+ *
51
+ * @param string $path Complete filename where the credentials are stored
52
+ * @return void
53
+ */
54
+ public function __construct($path = '')
55
+ {
56
+ if (!empty($path)) {
57
+ $this->setFile($path);
58
+ }
59
+ }
60
+
61
+ /**
62
+ * Set the path to the credentials file
63
+ *
64
+ * @param string $path
65
+ * @throws Zend_Auth_Adapter_Http_Resolver_Exception
66
+ * @return Zend_Auth_Adapter_Http_Resolver_File Provides a fluent interface
67
+ */
68
+ public function setFile($path)
69
+ {
70
+ if (empty($path) || !is_readable($path)) {
71
+ /**
72
+ * @see Zend_Auth_Adapter_Http_Resolver_Exception
73
+ */
74
+ require_once 'Zend/Auth/Adapter/Http/Resolver/Exception.php';
75
+ throw new Zend_Auth_Adapter_Http_Resolver_Exception('Path not readable: ' . $path);
76
+ }
77
+ $this->_file = $path;
78
+
79
+ return $this;
80
+ }
81
+
82
+ /**
83
+ * Returns the path to the credentials file
84
+ *
85
+ * @return string
86
+ */
87
+ public function getFile()
88
+ {
89
+ return $this->_file;
90
+ }
91
+
92
+ /**
93
+ * Resolve credentials
94
+ *
95
+ * Only the first matching username/realm combination in the file is
96
+ * returned. If the file contains credentials for Digest authentication,
97
+ * the returned string is the password hash, or h(a1) from RFC 2617. The
98
+ * returned string is the plain-text password for Basic authentication.
99
+ *
100
+ * The expected format of the file is:
101
+ * username:realm:sharedSecret
102
+ *
103
+ * That is, each line consists of the user's username, the applicable
104
+ * authentication realm, and the password or hash, each delimited by
105
+ * colons.
106
+ *
107
+ * @param string $username Username
108
+ * @param string $realm Authentication Realm
109
+ * @throws Zend_Auth_Adapter_Http_Resolver_Exception
110
+ * @return string|false User's shared secret, if the user is found in the
111
+ * realm, false otherwise.
112
+ */
113
+ public function resolve($username, $realm)
114
+ {
115
+ if (empty($username)) {
116
+ /**
117
+ * @see Zend_Auth_Adapter_Http_Resolver_Exception
118
+ */
119
+ require_once 'Zend/Auth/Adapter/Http/Resolver/Exception.php';
120
+ throw new Zend_Auth_Adapter_Http_Resolver_Exception('Username is required');
121
+ } else if (!ctype_print($username) || strpos($username, ':') !== false) {
122
+ /**
123
+ * @see Zend_Auth_Adapter_Http_Resolver_Exception
124
+ */
125
+ require_once 'Zend/Auth/Adapter/Http/Resolver/Exception.php';
126
+ throw new Zend_Auth_Adapter_Http_Resolver_Exception('Username must consist only of printable characters, '
127
+ . 'excluding the colon');
128
+ }
129
+ if (empty($realm)) {
130
+ /**
131
+ * @see Zend_Auth_Adapter_Http_Resolver_Exception
132
+ */
133
+ require_once 'Zend/Auth/Adapter/Http/Resolver/Exception.php';
134
+ throw new Zend_Auth_Adapter_Http_Resolver_Exception('Realm is required');
135
+ } else if (!ctype_print($realm) || strpos($realm, ':') !== false) {
136
+ /**
137
+ * @see Zend_Auth_Adapter_Http_Resolver_Exception
138
+ */
139
+ require_once 'Zend/Auth/Adapter/Http/Resolver/Exception.php';
140
+ throw new Zend_Auth_Adapter_Http_Resolver_Exception('Realm must consist only of printable characters, '
141
+ . 'excluding the colon.');
142
+ }
143
+
144
+ // Open file, read through looking for matching credentials
145
+ $fp = @fopen($this->_file, 'r');
146
+ if (!$fp) {
147
+ /**
148
+ * @see Zend_Auth_Adapter_Http_Resolver_Exception
149
+ */
150
+ require_once 'Zend/Auth/Adapter/Http/Resolver/Exception.php';
151
+ throw new Zend_Auth_Adapter_Http_Resolver_Exception('Unable to open password file: ' . $this->_file);
152
+ }
153
+
154
+ // No real validation is done on the contents of the password file. The
155
+ // assumption is that we trust the administrators to keep it secure.
156
+ while (($line = fgetcsv($fp, 512, ':')) !== false) {
157
+ if ($line[0] == $username && $line[1] == $realm) {
158
+ $password = $line[2];
159
+ fclose($fp);
160
+ return $password;
161
+ }
162
+ }
163
+
164
+ fclose($fp);
165
+ return false;
166
+ }
167
+ }
lib/Zend/Auth/Adapter/Http/Resolver/Interface.php ADDED
@@ -0,0 +1,47 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Zend Framework
4
+ *
5
+ * LICENSE
6
+ *
7
+ * This source file is subject to the new BSD license that is bundled
8
+ * with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://framework.zend.com/license/new-bsd
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@zend.com so we can send you a copy immediately.
14
+ *
15
+ * @category Zend
16
+ * @package Zend_Auth
17
+ * @subpackage Zend_Auth_Adapter_Http
18
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
19
+ * @license http://framework.zend.com/license/new-bsd New BSD License
20
+ * @version $Id: Interface.php 8862 2008-03-16 15:36:00Z thomas $
21
+ */
22
+
23
+
24
+ /**
25
+ * Auth HTTP Resolver Interface
26
+ *
27
+ * Defines an interace to resolve a username/realm combination into a shared
28
+ * secret usable by HTTP Authentication.
29
+ *
30
+ * @category Zend
31
+ * @package Zend_Auth
32
+ * @subpackage Zend_Auth_Adapter_Http
33
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
34
+ * @license http://framework.zend.com/license/new-bsd New BSD License
35
+ */
36
+ interface Zend_Auth_Adapter_Http_Resolver_Interface
37
+ {
38
+ /**
39
+ * Resolve username/realm to password/hash/etc.
40
+ *
41
+ * @param string $username Username
42
+ * @param string $realm Authentication Realm
43
+ * @return string|false User's shared secret, if the user is found in the
44
+ * realm, false otherwise.
45
+ */
46
+ public function resolve($username, $realm);
47
+ }
lib/Zend/Auth/Adapter/InfoCard.php ADDED
@@ -0,0 +1,263 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Zend Framework
4
+ *
5
+ * LICENSE
6
+ *
7
+ * This source file is subject to the new BSD license that is bundled
8
+ * with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://framework.zend.com/license/new-bsd
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@zend.com so we can send you a copy immediately.
14
+ *
15
+ * @category Zend
16
+ * @package Zend_Auth
17
+ * @subpackage Zend_Auth_Adapter
18
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
19
+ * @license http://framework.zend.com/license/new-bsd New BSD License
20
+ * @version $Id: InfoCard.php 8862 2008-03-16 15:36:00Z thomas $
21
+ * @author John Coggeshall <john@zend.com>
22
+ */
23
+
24
+ /**
25
+ * @see Zend_Auth_Adapter_Interface
26
+ */
27
+ require_once 'Zend/Auth/Adapter/Interface.php';
28
+
29
+ /**
30
+ * @see Zend_Auth_Result
31
+ */
32
+ require_once 'Zend/Auth/Result.php';
33
+
34
+ /**
35
+ * @see Zend_InfoCard
36
+ */
37
+ require_once 'Zend/InfoCard.php';
38
+
39
+ /**
40
+ * A Zend_Auth Authentication Adapter allowing the use of Information Cards as an
41
+ * authentication mechanism
42
+ *
43
+ * @category Zend
44
+ * @package Zend_Auth
45
+ * @subpackage Zend_Auth_Adapter
46
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
47
+ * @license http://framework.zend.com/license/new-bsd New BSD License
48
+ * @author John Coggeshall <john@zend.com>
49
+ */
50
+ class Zend_Auth_Adapter_InfoCard implements Zend_Auth_Adapter_Interface
51
+ {
52
+ /**
53
+ * The XML Token being authenticated
54
+ *
55
+ * @var string
56
+ */
57
+ protected $_xmlToken;
58
+
59
+ /**
60
+ * The instance of Zend_InfoCard
61
+ *
62
+ * @var Zend_InfoCard
63
+ */
64
+ protected $_infoCard;
65
+
66
+ /**
67
+ * Constructor
68
+ *
69
+ * @param string $strXmlDocument The XML Token provided by the client
70
+ * @return void
71
+ */
72
+ public function __construct($strXmlDocument)
73
+ {
74
+ $this->_xmlToken = $strXmlDocument;
75
+ $this->_infoCard = new Zend_InfoCard();
76
+ }
77
+
78
+ /**
79
+ * Sets the InfoCard component Adapter to use
80
+ *
81
+ * @param Zend_InfoCard_Adapter_Interface $a
82
+ * @return Zend_Auth_Adapter_InfoCard Provides a fluent interface
83
+ */
84
+ public function setAdapter(Zend_InfoCard_Adapter_Interface $a)
85
+ {
86
+ $this->_infoCard->setAdapter($a);
87
+ return $this;
88
+ }
89
+
90
+ /**
91
+ * Retrieves the InfoCard component adapter being used
92
+ *
93
+ * @return Zend_InfoCard_Adapter_Interface
94
+ */
95
+ public function getAdapter()
96
+ {
97
+ return $this->_infoCard->getAdapter();
98
+ }
99
+
100
+ /**
101
+ * Retrieves the InfoCard public key cipher object being used
102
+ *
103
+ * @return Zend_InfoCard_Cipher_PKI_Interface
104
+ */
105
+ public function getPKCipherObject()
106
+ {
107
+ return $this->_infoCard->getPKCipherObject();
108
+ }
109
+
110
+ /**
111
+ * Sets the InfoCard public key cipher object to use
112
+ *
113
+ * @param Zend_InfoCard_Cipher_PKI_Interface $cipherObj
114
+ * @return Zend_Auth_Adapter_InfoCard Provides a fluent interface
115
+ */
116
+ public function setPKICipherObject(Zend_InfoCard_Cipher_PKI_Interface $cipherObj)
117
+ {
118
+ $this->_infoCard->setPKICipherObject($cipherObj);
119
+ return $this;
120
+ }
121
+
122
+ /**
123
+ * Retrieves the Symmetric cipher object being used
124
+ *
125
+ * @return Zend_InfoCard_Cipher_Symmetric_Interface
126
+ */
127
+ public function getSymCipherObject()
128
+ {
129
+ return $this->_infoCard->getSymCipherObject();
130
+ }
131
+
132
+ /**
133
+ * Sets the InfoCard symmetric cipher object to use
134
+ *
135
+ * @param Zend_InfoCard_Cipher_Symmetric_Interface $cipherObj
136
+ * @return Zend_Auth_Adapter_InfoCard Provides a fluent interface
137
+ */
138
+ public function setSymCipherObject(Zend_InfoCard_Cipher_Symmetric_Interface $cipherObj)
139
+ {
140
+ $this->_infoCard->setSymCipherObject($cipherObj);
141
+ return $this;
142
+ }
143
+
144
+ /**
145
+ * Remove a Certificate Pair by Key ID from the search list
146
+ *
147
+ * @param string $key_id The Certificate Key ID returned from adding the certificate pair
148
+ * @throws Zend_InfoCard_Exception
149
+ * @return Zend_Auth_Adapter_InfoCard Provides a fluent interface
150
+ */
151
+ public function removeCertificatePair($key_id)
152
+ {
153
+ $this->_infoCard->removeCertificatePair($key_id);
154
+ return $this;
155
+ }
156
+
157
+ /**
158
+ * Add a Certificate Pair to the list of certificates searched by the component
159
+ *
160
+ * @param string $private_key_file The path to the private key file for the pair
161
+ * @param string $public_key_file The path to the certificate / public key for the pair
162
+ * @param string $type (optional) The URI for the type of key pair this is (default RSA with OAEP padding)
163
+ * @param string $password (optional) The password for the private key file if necessary
164
+ * @throws Zend_InfoCard_Exception
165
+ * @return string A key ID representing this key pair in the component
166
+ */
167
+ public function addCertificatePair($private_key_file, $public_key_file, $type = Zend_InfoCard_Cipher::ENC_RSA_OAEP_MGF1P, $password = null)
168
+ {
169
+ return $this->_infoCard->addCertificatePair($private_key_file, $public_key_file, $type, $password);
170
+ }
171
+
172
+ /**
173
+ * Return a Certificate Pair from a key ID
174
+ *
175
+ * @param string $key_id The Key ID of the certificate pair in the component
176
+ * @throws Zend_InfoCard_Exception
177
+ * @return array An array containing the path to the private/public key files,
178
+ * the type URI and the password if provided
179
+ */
180
+ public function getCertificatePair($key_id)
181
+ {
182
+ return $this->_infoCard->getCertificatePair($key_id);
183
+ }
184
+
185
+ /**
186
+ * Set the XML Token to be processed
187
+ *
188
+ * @param string $strXmlToken The XML token to process
189
+ * @return Zend_Auth_Adapter_InfoCard Provides a fluent interface
190
+ */
191
+ public function setXmlToken($strXmlToken)
192
+ {
193
+ $this->_xmlToken = $strXmlToken;
194
+ return $this;
195
+ }
196
+
197
+ /**
198
+ * Get the XML Token being processed
199
+ *
200
+ * @return string The XML token to be processed
201
+ */
202
+ public function getXmlToken()
203
+ {
204
+ return $this->_xmlToken;
205
+ }
206
+
207
+ /**
208
+ * Authenticates the XML token
209
+ *
210
+ * @return Zend_Auth_Result The result of the authentication
211
+ */
212
+ public function authenticate()
213
+ {
214
+ try {
215
+ $claims = $this->_infoCard->process($this->getXmlToken());
216
+ } catch(Exception $e) {
217
+ return new Zend_Auth_Result(Zend_Auth_Result::FAILURE , null, array('Exception Thrown',
218
+ $e->getMessage(),
219
+ $e->getTraceAsString(),
220
+ serialize($e)));
221
+ }
222
+
223
+ if(!$claims->isValid()) {
224
+ switch($claims->getCode()) {
225
+ case Zend_infoCard_Claims::RESULT_PROCESSING_FAILURE:
226
+ return new Zend_Auth_Result(
227
+ Zend_Auth_Result::FAILURE,
228
+ $claims,
229
+ array(
230
+ 'Processing Failure',
231
+ $claims->getErrorMsg()
232
+ )
233
+ );
234
+ break;
235
+ case Zend_InfoCard_Claims::RESULT_VALIDATION_FAILURE:
236
+ return new Zend_Auth_Result(
237
+ Zend_Auth_Result::FAILURE_CREDENTIAL_INVALID,
238
+ $claims,
239
+ array(
240
+ 'Validation Failure',
241
+ $claims->getErrorMsg()
242
+ )
243
+ );
244
+ break;
245
+ default:
246
+ return new Zend_Auth_Result(
247
+ Zend_Auth_Result::FAILURE,
248
+ $claims,
249
+ array(
250
+ 'Unknown Failure',
251
+ $claims->getErrorMsg()
252
+ )
253
+ );
254
+ break;
255
+ }
256
+ }
257
+
258
+ return new Zend_Auth_Result(
259
+ Zend_Auth_Result::SUCCESS,
260
+ $claims
261
+ );
262
+ }
263
+ }
lib/Zend/Auth/Adapter/Interface.php ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Zend Framework
4
+ *
5
+ * LICENSE
6
+ *
7
+ * This source file is subject to the new BSD license that is bundled
8
+ * with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://framework.zend.com/license/new-bsd
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@zend.com so we can send you a copy immediately.
14
+ *
15
+ * @category Zend
16
+ * @package Zend_Auth
17
+ * @subpackage Zend_Auth_Adapter
18
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
19
+ * @license http://framework.zend.com/license/new-bsd New BSD License
20
+ * @version $Id: Interface.php 8862 2008-03-16 15:36:00Z thomas $
21
+ */
22
+
23
+
24
+ /**
25
+ * @see Zend_Auth_Result
26
+ */
27
+ require_once 'Zend/Auth/Result.php';
28
+
29
+
30
+ /**
31
+ * @category Zend
32
+ * @package Zend_Auth
33
+ * @subpackage Zend_Auth_Adapter
34
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
35
+ * @license http://framework.zend.com/license/new-bsd New BSD License
36
+ */
37
+ interface Zend_Auth_Adapter_Interface
38
+ {
39
+ /**
40
+ * Performs an authentication attempt
41
+ *
42
+ * @throws Zend_Auth_Adapter_Exception If authentication cannot be performed
43
+ * @return Zend_Auth_Result
44
+ */
45
+ public function authenticate();
46
+ }
lib/Zend/Auth/Adapter/Ldap.php ADDED
@@ -0,0 +1,273 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Zend Framework
4
+ *
5
+ * LICENSE
6
+ *
7
+ * This source file is subject to the new BSD license that is bundled
8
+ * with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://framework.zend.com/license/new-bsd
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@zend.com so we can send you a copy immediately.
14
+ *
15
+ * @category Zend
16
+ * @package Zend_Auth
17
+ * @subpackage Zend_Auth_Adapter
18
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
19
+ * @license http://framework.zend.com/license/new-bsd New BSD License
20
+ * @version $Id: Ldap.php 8862 2008-03-16 15:36:00Z thomas $
21
+ */
22
+
23
+ /**
24
+ * @see Zend_Auth_Adapter_Interface
25
+ */
26
+ require_once 'Zend/Auth/Adapter/Interface.php';
27
+
28
+ /**
29
+ * @category Zend
30
+ * @package Zend_Auth
31
+ * @subpackage Zend_Auth_Adapter
32
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
33
+ * @license http://framework.zend.com/license/new-bsd New BSD License
34
+ */
35
+ class Zend_Auth_Adapter_Ldap implements Zend_Auth_Adapter_Interface
36
+ {
37
+
38
+ /**
39
+ * The Zend_Ldap context.
40
+ *
41
+ * @var Zend_Ldap
42
+ */
43
+ protected $_ldap = null;
44
+
45
+ /**
46
+ * The array of arrays of Zend_Ldap options passed to the constructor.
47
+ *
48
+ * @var array
49
+ */
50
+ protected $_options = null;
51
+
52
+ /**
53
+ * The username of the account being authenticated.
54
+ *
55
+ * @var string
56
+ */
57
+ protected $_username = null;
58
+
59
+ /**
60
+ * The password of the account being authenticated.
61
+ *
62
+ * @var string
63
+ */
64
+ protected $_password = null;
65
+
66
+ /**
67
+ * Constructor
68
+ *
69
+ * @param array $options An array of arrays of Zend_Ldap options
70
+ * @param string $username The username of the account being authenticated
71
+ * @param string $password The password of the account being authenticated
72
+ * @return void
73
+ */
74
+ public function __construct(array $options = array(), $username = null, $password = null)
75
+ {
76
+ $this->_options = $options;
77
+ if ($username !== null) {
78
+ $this->setUsername($username);
79
+ }
80
+ if ($password !== null) {
81
+ $this->setPassword($password);
82
+ }
83
+ }
84
+
85
+ /**
86
+ * Returns the username of the account being authenticated, or
87
+ * NULL if none is set.
88
+ *
89
+ * @return string|null
90
+ */
91
+ public function getUsername()
92
+ {
93
+ return $this->_username;
94
+ }
95
+
96
+ /**
97
+ * Sets the username for binding
98
+ *
99
+ * @param string $username The username for binding
100
+ * @return Zend_Auth_Adapter_Ldap Provides a fluent interface
101
+ */
102
+ public function setUsername($username)
103
+ {
104
+ $this->_username = (string) $username;
105
+ return $this;
106
+ }
107
+
108
+ /**
109
+ * Returns the password of the account being authenticated, or
110
+ * NULL if none is set.
111
+ *
112
+ * @return string|null
113
+ */
114
+ public function getPassword()
115
+ {
116
+ return $this->_password;
117
+ }
118
+
119
+ /**
120
+ * Sets the passwort for the account
121
+ *
122
+ * @param string $password The password of the account being authenticated
123
+ * @return Zend_Auth_Adapter_Ldap Provides a fluent interface
124
+ */
125
+ public function setPassword($password)
126
+ {
127
+ $this->_password = (string) $password;
128
+ return $this;
129
+ }
130
+
131
+ /**
132
+ * Returns the LDAP Object
133
+ *
134
+ * @return Zend_Ldap The Zend_Ldap object used to authenticate the credentials
135
+ */
136
+ public function getLdap()
137
+ {
138
+ if ($this->_ldap === null) {
139
+ /**
140
+ * @see Zend_Ldap
141
+ */
142
+ require_once 'Zend/Ldap.php';
143
+ $this->_ldap = new Zend_Ldap();
144
+ }
145
+ return $this->_ldap;
146
+ }
147
+
148
+ /**
149
+ * Authenticate the user
150
+ *
151
+ * @throws Zend_Auth_Adapter_Exception
152
+ * @return Zend_Auth_Result
153
+ */
154
+ public function authenticate()
155
+ {
156
+ /**
157
+ * @see Zend_Ldap_Exception
158
+ */
159
+ require_once 'Zend/Ldap/Exception.php';
160
+
161
+ $messages = array();
162
+ $messages[0] = ''; // reserved
163
+ $messages[1] = ''; // reserved
164
+
165
+ $username = $this->_username;
166
+ $password = $this->_password;
167
+
168
+ if (!$username) {
169
+ $code = Zend_Auth_Result::FAILURE_IDENTITY_NOT_FOUND;
170
+ $messages[0] = 'A username is required';
171
+ return new Zend_Auth_Result($code, '', $messages);
172
+ }
173
+ if (!$password) {
174
+ /* A password is required because some servers will
175
+ * treat an empty password as an anonymous bind.
176
+ */
177
+ $code = Zend_Auth_Result::FAILURE_CREDENTIAL_INVALID;
178
+ $messages[0] = 'A password is required';
179
+ return new Zend_Auth_Result($code, '', $messages);
180
+ }
181
+
182
+ $ldap = $this->getLdap();
183
+
184
+ $code = Zend_Auth_Result::FAILURE;
185
+ $messages[0] = "Authority not found: $username";
186
+
187
+ /* Iterate through each server and try to authenticate the supplied
188
+ * credentials against it.
189
+ */
190
+ foreach ($this->_options as $name => $options) {
191
+
192
+ if (!is_array($options)) {
193
+ /**
194
+ * @see Zend_Auth_Adapter_Exception
195
+ */
196
+ require_once 'Zend/Auth/Adapter/Exception.php';
197
+ throw new Zend_Auth_Adapter_Exception('Adapter options array not in array');
198
+ }
199
+ $ldap->setOptions($options);
200
+
201
+ try {
202
+
203
+ $canonicalName = $ldap->getCanonicalAccountName($username);
204
+
205
+ if ($messages[1])
206
+ $messages[] = $messages[1];
207
+ $messages[1] = '';
208
+ $messages[] = $this->_optionsToString($options);
209
+
210
+ $ldap->bind($canonicalName, $password);
211
+
212
+ $messages[0] = '';
213
+ $messages[1] = '';
214
+ $messages[] = "$canonicalName authentication successful";
215
+
216
+ return new Zend_Auth_Result(Zend_Auth_Result::SUCCESS, $canonicalName, $messages);
217
+ } catch (Zend_Ldap_Exception $zle) {
218
+
219
+ /* LDAP based authentication is notoriously difficult to diagnose. Therefore
220
+ * we bend over backwards to capture and record every possible bit of
221
+ * information when something goes wrong.
222
+ */
223
+
224
+ $err = $zle->getCode();
225
+
226
+ if ($err == Zend_Ldap_Exception::LDAP_X_DOMAIN_MISMATCH) {
227
+ /* This error indicates that the domain supplied in the
228
+ * username did not match the domains in the server options
229
+ * and therefore we should just skip to the next set of
230
+ * server options.
231
+ */
232
+ continue;
233
+ } else if ($err == Zend_Ldap_Exception::LDAP_NO_SUCH_OBJECT) {
234
+ $code = Zend_Auth_Result::FAILURE_IDENTITY_NOT_FOUND;
235
+ $messages[0] = "Account not found: $username";
236
+ } else if ($err == Zend_Ldap_Exception::LDAP_INVALID_CREDENTIALS) {
237
+ $code = Zend_Auth_Result::FAILURE_CREDENTIAL_INVALID;
238
+ $messages[0] = 'Invalid credentials';
239
+ } else {
240
+ $line = $zle->getLine();
241
+ $messages[] = $zle->getFile() . "($line): " . $zle->getMessage();
242
+ $messages[] = str_replace($password, '*****', $zle->getTraceAsString());
243
+ $messages[0] = 'An unexpected failure occurred';
244
+ }
245
+ $messages[1] = $zle->getMessage();
246
+ }
247
+ }
248
+
249
+ $msg = isset($messages[1]) ? $messages[1] : $messages[0];
250
+ $messages[] = "$username authentication failed: $msg";
251
+
252
+ return new Zend_Auth_Result($code, $username, $messages);
253
+ }
254
+
255
+ /**
256
+ * Converts options to string
257
+ *
258
+ * @param array $options
259
+ * @return string
260
+ */
261
+ private function _optionsToString(array $options)
262
+ {
263
+ $str = '';
264
+ foreach ($options as $key => $val) {
265
+ if ($key === 'password')
266
+ $val = '*****';
267
+ if ($str)
268
+ $str .= ',';
269
+ $str .= $key . '=' . $val;
270
+ }
271
+ return $str;
272
+ }
273
+ }
lib/Zend/Auth/Adapter/OpenId.php ADDED
@@ -0,0 +1,272 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Zend Framework
4
+ *
5
+ * LICENSE
6
+ *
7
+ * This source file is subject to the new BSD license that is bundled
8
+ * with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://framework.zend.com/license/new-bsd
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@zend.com so we can send you a copy immediately.
14
+ *
15
+ * @category Zend
16
+ * @package Zend_Auth
17
+ * @subpackage Zend_Auth_Adapter
18
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
19
+ * @license http://framework.zend.com/license/new-bsd New BSD License
20
+ * @version $Id: OpenId.php 8862 2008-03-16 15:36:00Z thomas $
21
+ */
22
+
23
+
24
+ /**
25
+ * @see Zend_Auth_Adapter_Interface
26
+ */
27
+ require_once 'Zend/Auth/Adapter/Interface.php';
28
+
29
+
30
+ /**
31
+ * @see Zend_OpenId_Consumer
32
+ */
33
+ require_once 'Zend/OpenId/Consumer.php';
34
+
35
+
36
+ /**
37
+ * A Zend_Auth Authentication Adapter allowing the use of OpenID protocol as an
38
+ * authentication mechanism
39
+ *
40
+ * @category Zend
41
+ * @package Zend_Auth
42
+ * @subpackage Zend_Auth_Adapter
43
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
44
+ * @license http://framework.zend.com/license/new-bsd New BSD License
45
+ */
46
+ class Zend_Auth_Adapter_OpenId implements Zend_Auth_Adapter_Interface
47
+ {
48
+ /**
49
+ * The identity value being authenticated
50
+ *
51
+ * @var string
52
+ */
53
+ private $_id = null;
54
+
55
+ /**
56
+ * Reference to an implementation of a storage object
57
+ *
58
+ * @var Zend_OpenId_Consumer_Storage
59
+ */
60
+ private $_storage = null;
61
+
62
+ /**
63
+ * The URL to redirect response from server to
64
+ *
65
+ * @var string
66
+ */
67
+ private $_returnTo = null;
68
+
69
+ /**
70
+ * The HTTP URL to identify consumer on server
71
+ *
72
+ * @var string
73
+ */
74
+ private $_root = null;
75
+
76
+ /**
77
+ * Extension object or array of extensions objects
78
+ *
79
+ * @var string
80
+ */
81
+ private $_extensions = null;
82
+
83
+ /**
84
+ * The response object to perform HTTP or HTML form redirection
85
+ *
86
+ * @var Zend_Controller_Response_Abstract
87
+ */
88
+ private $_response = null;
89
+
90
+ /**
91
+ * Enables or disables interaction with user during authentication on
92
+ * OpenID provider.
93
+ *
94
+ * @var bool
95
+ */
96
+ private $_check_immediate = false;
97
+
98
+ /**
99
+ * Constructor
100
+ *
101
+ * @param string $id the identity value
102
+ * @param Zend_OpenId_Consumer_Storage $storage an optional implementation
103
+ * of a storage object
104
+ * @param string $returnTo HTTP URL to redirect response from server to
105
+ * @param string $root HTTP URL to identify consumer on server
106
+ * @param mixed $extensions extension object or array of extensions objects
107
+ * @param Zend_Controller_Response_Abstract $response an optional response
108
+ * object to perform HTTP or HTML form redirection
109
+ * @return void
110
+ */
111
+ public function __construct($id = null,
112
+ Zend_OpenId_Consumer_Storage $storage = null,
113
+ $returnTo = null,
114
+ $root = null,
115
+ $extensions = null,
116
+ Zend_Controller_Response_Abstract $response = null) {
117
+ $this->_id = $id;
118
+ $this->_storage = $storage;
119
+ $this->_returnTo = $returnTo;
120
+ $this->_root = $root;
121
+ $this->_extensions = $extensions;
122
+ $this->_response = $response;
123
+ }
124
+
125
+ /**
126
+ * Sets the value to be used as the identity
127
+ *
128
+ * @param string $id the identity value
129
+ * @return Zend_Auth_Adapter_OpenId Provides a fluent interface
130
+ */
131
+ public function setIdentity($id)
132
+ {
133
+ $this->_id = $id;
134
+ return $this;
135
+ }
136
+
137
+ /**
138
+ * Sets the storage implementation which will be use by OpenId
139
+ *
140
+ * @param Zend_OpenId_Consumer_Storage $storage
141
+ * @return Zend_Auth_Adapter_OpenId Provides a fluent interface
142
+ */
143
+ public function setStorage(Zend_OpenId_Consumer_Storage $storage)
144
+ {
145
+ $this->_storage = $storage;
146
+ return $this;
147
+ }
148
+
149
+ /**
150
+ * Sets the HTTP URL to redirect response from server to
151
+ *
152
+ * @param string $returnTo
153
+ * @return Zend_Auth_Adapter_OpenId Provides a fluent interface
154
+ */
155
+ public function setReturnTo($returnTo)
156
+ {
157
+ $this->_returnTo = $returnTo;
158
+ return $this;
159
+ }
160
+
161
+ /**
162
+ * Sets HTTP URL to identify consumer on server
163
+ *
164
+ * @param string $root
165
+ * @return Zend_Auth_Adapter_OpenId Provides a fluent interface
166
+ */
167
+ public function setRoot($root)
168
+ {
169
+ $this->_root = $root;
170
+ return $this;
171
+ }
172
+
173
+ /**
174
+ * Sets OpenID extension(s)
175
+ *
176
+ * @param mixed $extensions
177
+ * @return Zend_Auth_Adapter_OpenId Provides a fluent interface
178
+ */
179
+ public function setExtensions($extensions)
180
+ {
181
+ $this->_extensions = $extensions;
182
+ return $this;
183
+ }
184
+
185
+ /**
186
+ * Sets an optional response object to perform HTTP or HTML form redirection
187
+ *
188
+ * @param string $root
189
+ * @return Zend_Auth_Adapter_OpenId Provides a fluent interface
190
+ */
191
+ public function setResponse($response)
192
+ {
193
+ $this->_response = $response;
194
+ return $this;
195
+ }
196
+
197
+ /**
198
+ * Enables or disables interaction with user during authentication on
199
+ * OpenID provider.
200
+ *
201
+ * @param bool $check_immediate
202
+ * @return Zend_Auth_Adapter_OpenId Provides a fluent interface
203
+ */
204
+ public function setCheckImmediate($check_immediate)
205
+ {
206
+ $this->_check_immediate = $check_immediate;
207
+ return $this;
208
+ }
209
+
210
+ /**
211
+ * Authenticates the given OpenId identity.
212
+ * Defined by Zend_Auth_Adapter_Interface.
213
+ *
214
+ * @throws Zend_Auth_Adapter_Exception If answering the authentication query is impossible
215
+ * @return Zend_Auth_Result
216
+ */
217
+ public function authenticate() {
218
+ $id = $this->_id;
219
+ if (!empty($id)) {
220
+ $consumer = new Zend_OpenId_Consumer($this->_storage);
221
+ /* login() is never returns on success */
222
+ if (!$this->_check_immediate) {
223
+ if (!$consumer->login($id,
224
+ $this->_returnTo,
225
+ $this->_root,
226
+ $this->_extensions,
227
+ $this->_response)) {
228
+ return new Zend_Auth_Result(
229
+ Zend_Auth_Result::FAILURE,
230
+ $id,
231
+ array("Authentication failed"));
232
+ }
233
+ } else {
234
+ if (!$consumer->check($id,
235
+ $this->_returnTo,
236
+ $this->_root,
237
+ $this->_extensions,
238
+ $this->_response)) {
239
+ return new Zend_Auth_Result(
240
+ Zend_Auth_Result::FAILURE,
241
+ $id,
242
+ array("Authentication failed"));
243
+ }
244
+ }
245
+ } else {
246
+ $params = (isset($_SERVER['REQUEST_METHOD']) &&
247
+ $_SERVER['REQUEST_METHOD']=='POST') ? $_POST: $_GET;
248
+ if (!isset($params['openid_mode'])) {
249
+ return new Zend_Auth_Result(
250
+ Zend_Auth_Result::FAILURE,
251
+ $id,
252
+ array("Authentication failed"));
253
+ }
254
+ $consumer = new Zend_OpenId_Consumer($this->_storage);
255
+ if ($consumer->verify(
256
+ $params,
257
+ $id,
258
+ $this->_extensions)) {
259
+ return new Zend_Auth_Result(
260
+ Zend_Auth_Result::SUCCESS,
261
+ $id,
262
+ array("Authentication successful"));
263
+ } else {
264
+ return new Zend_Auth_Result(
265
+ Zend_Auth_Result::FAILURE,
266
+ $id,
267
+ array("Authentication failed"));
268
+ }
269
+ }
270
+ }
271
+
272
+ }
lib/Zend/Auth/Exception.php ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Zend Framework
4
+ *
5
+ * LICENSE
6
+ *
7
+ * This source file is subject to the new BSD license that is bundled
8
+ * with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://framework.zend.com/license/new-bsd
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@zend.com so we can send you a copy immediately.
14
+ *
15
+ * @category Zend
16
+ * @package Zend_Auth
17
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
18
+ * @license http://framework.zend.com/license/new-bsd New BSD License
19
+ * @version $Id: Exception.php 8862 2008-03-16 15:36:00Z thomas $
20
+ */
21
+
22
+
23
+ /**
24
+ * @see Zend_Exception
25
+ */
26
+ require_once 'Zend/Exception.php';
27
+
28
+
29
+ /**
30
+ * @category Zend
31
+ * @package Zend_Auth
32
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
33
+ * @license http://framework.zend.com/license/new-bsd New BSD License
34
+ */
35
+ class Zend_Auth_Exception extends Zend_Exception
36
+ {}
lib/Zend/Auth/Result.php ADDED
@@ -0,0 +1,148 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Zend Framework
4
+ *
5
+ * LICENSE
6
+ *
7
+ * This source file is subject to the new BSD license that is bundled
8
+ * with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://framework.zend.com/license/new-bsd
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@zend.com so we can send you a copy immediately.
14
+ *
15
+ * @category Zend
16
+ * @package Zend_Auth
17
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
18
+ * @license http://framework.zend.com/license/new-bsd New BSD License
19
+ * @version $Id: Result.php 8862 2008-03-16 15:36:00Z thomas $
20
+ */
21
+
22
+
23
+ /**
24
+ * @category Zend
25
+ * @package Zend_Auth
26
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
27
+ * @license http://framework.zend.com/license/new-bsd New BSD License
28
+ */
29
+ class Zend_Auth_Result
30
+ {
31
+ /**
32
+ * General Failure
33
+ */
34
+ const FAILURE = 0;
35
+
36
+ /**
37
+ * Failure due to identity not being found.
38
+ */
39
+ const FAILURE_IDENTITY_NOT_FOUND = -1;
40
+
41
+ /**
42
+ * Failure due to identity being ambiguous.
43
+ */
44
+ const FAILURE_IDENTITY_AMBIGUOUS = -2;
45
+
46
+ /**
47
+ * Failure due to invalid credential being supplied.
48
+ */
49
+ const FAILURE_CREDENTIAL_INVALID = -3;
50
+
51
+ /**
52
+ * Failure due to uncategorized reasons.
53
+ */
54
+ const FAILURE_UNCATEGORIZED = -4;
55
+
56
+ /**
57
+ * Authentication success.
58
+ */
59
+ const SUCCESS = 1;
60
+
61
+ /**
62
+ * Authentication result code
63
+ *
64
+ * @var int
65
+ */
66
+ protected $_code;
67
+
68
+ /**
69
+ * The identity used in the authentication attempt
70
+ *
71
+ * @var mixed
72
+ */
73
+ protected $_identity;
74
+
75
+ /**
76
+ * An array of string reasons why the authentication attempt was unsuccessful
77
+ *
78
+ * If authentication was successful, this should be an empty array.
79
+ *
80
+ * @var array
81
+ */
82
+ protected $_messages;
83
+
84
+ /**
85
+ * Sets the result code, identity, and failure messages
86
+ *
87
+ * @param int $code
88
+ * @param mixed $identity
89
+ * @param array $messages
90
+ * @return void
91
+ */
92
+ public function __construct($code, $identity, array $messages = array())
93
+ {
94
+ $code = (int) $code;
95
+
96
+ if ($code < self::FAILURE_UNCATEGORIZED) {
97
+ $code = self::FAILURE;
98
+ } elseif ($code > self::SUCCESS ) {
99
+ $code = 1;
100
+ }
101
+
102
+ $this->_code = $code;
103
+ $this->_identity = $identity;
104
+ $this->_messages = $messages;
105
+ }
106
+
107
+ /**
108
+ * Returns whether the result represents a successful authentication attempt
109
+ *
110
+ * @return boolean
111
+ */
112
+ public function isValid()
113
+ {
114
+ return ($this->_code > 0) ? true : false;
115
+ }
116
+
117
+ /**
118
+ * getCode() - Get the result code for this authentication attempt
119
+ *
120
+ * @return int
121
+ */
122
+ public function getCode()
123
+ {
124
+ return $this->_code;
125
+ }
126
+
127
+ /**
128
+ * Returns the identity used in the authentication attempt
129
+ *
130
+ * @return mixed
131
+ */
132
+ public function getIdentity()
133
+ {
134
+ return $this->_identity;
135
+ }
136
+
137
+ /**
138
+ * Returns an array of string reasons why the authentication attempt was unsuccessful
139
+ *
140
+ * If authentication was successful, this method returns an empty array.
141
+ *
142
+ * @return array
143
+ */
144
+ public function getMessages()
145
+ {
146
+ return $this->_messages;
147
+ }
148
+ }
lib/Zend/Auth/Storage/Exception.php ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Zend Framework
5
+ *
6
+ * LICENSE
7
+ *
8
+ * This source file is subject to the new BSD license that is bundled
9
+ * with this package in the file LICENSE.txt.
10
+ * It is also available through the world-wide-web at this URL:
11
+ * http://framework.zend.com/license/new-bsd
12
+ * If you did not receive a copy of the license and are unable to
13
+ * obtain it through the world-wide-web, please send an email
14
+ * to license@zend.com so we can send you a copy immediately.
15
+ *
16
+ * @category Zend
17
+ * @package Zend_Auth
18
+ * @subpackage Zend_Auth_Storage
19
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
20
+ * @license http://framework.zend.com/license/new-bsd New BSD License
21
+ * @version $Id: Exception.php 8862 2008-03-16 15:36:00Z thomas $
22
+ */
23
+
24
+
25
+ /**
26
+ * @see Zend_Auth_Exception
27
+ */
28
+ require_once 'Zend/Auth/Exception.php';
29
+
30
+
31
+ /**
32
+ * @category Zend
33
+ * @package Zend_Auth
34
+ * @subpackage Zend_Auth_Storage
35
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
36
+ * @license http://framework.zend.com/license/new-bsd New BSD License
37
+ */
38
+ class Zend_Auth_Storage_Exception extends Zend_Auth_Exception
39
+ {}
lib/Zend/Auth/Storage/Interface.php ADDED
@@ -0,0 +1,67 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Zend Framework
4
+ *
5
+ * LICENSE
6
+ *
7
+ * This source file is subject to the new BSD license that is bundled
8
+ * with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://framework.zend.com/license/new-bsd
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@zend.com so we can send you a copy immediately.
14
+ *
15
+ * @category Zend
16
+ * @package Zend_Auth
17
+ * @subpackage Zend_Auth_Storage
18
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
19
+ * @license http://framework.zend.com/license/new-bsd New BSD License
20
+ * @version $Id: Interface.php 8862 2008-03-16 15:36:00Z thomas $
21
+ */
22
+
23
+
24
+ /**
25
+ * @category Zend
26
+ * @package Zend_Auth
27
+ * @subpackage Zend_Auth_Storage
28
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
29
+ * @license http://framework.zend.com/license/new-bsd New BSD License
30
+ */
31
+ interface Zend_Auth_Storage_Interface
32
+ {
33
+ /**
34
+ * Returns true if and only if storage is empty
35
+ *
36
+ * @throws Zend_Auth_Storage_Exception If it is impossible to determine whether storage is empty
37
+ * @return boolean
38
+ */
39
+ public function isEmpty();
40
+
41
+ /**
42
+ * Returns the contents of storage
43
+ *
44
+ * Behavior is undefined when storage is empty.
45
+ *
46
+ * @throws Zend_Auth_Storage_Exception If reading contents from storage is impossible
47
+ * @return mixed
48
+ */
49
+ public function read();
50
+
51
+ /**
52
+ * Writes $contents to storage
53
+ *
54
+ * @param mixed $contents
55
+ * @throws Zend_Auth_Storage_Exception If writing $contents to storage is impossible
56
+ * @return void
57
+ */
58
+ public function write($contents);
59
+
60
+ /**
61
+ * Clears contents from storage
62
+ *
63
+ * @throws Zend_Auth_Storage_Exception If clearing contents from storage is impossible
64
+ * @return void
65
+ */
66
+ public function clear();
67
+ }
lib/Zend/Auth/Storage/NonPersistent.php ADDED
@@ -0,0 +1,96 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Zend Framework
4
+ *
5
+ * LICENSE
6
+ *
7
+ * This source file is subject to the new BSD license that is bundled
8
+ * with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://framework.zend.com/license/new-bsd
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@zend.com so we can send you a copy immediately.
14
+ *
15
+ * @category Zend
16
+ * @package Zend_Auth
17
+ * @subpackage Zend_Auth_Storage
18
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
19
+ * @license http://framework.zend.com/license/new-bsd New BSD License
20
+ * @version $Id: NonPersistent.php 8862 2008-03-16 15:36:00Z thomas $
21
+ */
22
+
23
+
24
+ /**
25
+ * @see Zend_Auth_Storage_Interface
26
+ */
27
+ require_once 'Zend/Auth/Storage/Interface.php';
28
+
29
+
30
+ /**
31
+ * Non-Persistent Auth Storage
32
+ *
33
+ * Since HTTP Authentication happens again on each request, this will always be
34
+ * re-populated. So there's no need to use sessions, this simple value class
35
+ * will hold the data for rest of the current request.
36
+ *
37
+ * @category Zend
38
+ * @package Zend_Auth
39
+ * @subpackage Zend_Auth_Storage
40
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
41
+ * @license http://framework.zend.com/license/new-bsd New BSD License
42
+ */
43
+ class Zend_Auth_Storage_NonPersistent implements Zend_Auth_Storage_Interface
44
+ {
45
+ /**
46
+ * Holds the actual auth data
47
+ */
48
+ protected $_data;
49
+
50
+
51
+ /**
52
+ * Returns true if and only if storage is empty
53
+ *
54
+ * @throws Zend_Auth_Storage_Exception If it is impossible to determine whether storage is empty
55
+ * @return boolean
56
+ */
57
+ public function isEmpty()
58
+ {
59
+ return empty($this->_data);
60
+ }
61
+
62
+ /**
63
+ * Returns the contents of storage
64
+ * Behavior is undefined when storage is empty.
65
+ *
66
+ * @throws Zend_Auth_Storage_Exception If reading contents from storage is impossible
67
+ * @return mixed
68
+ */
69
+ public function read()
70
+ {
71
+ return $this->_data;
72
+ }
73
+
74
+ /**
75
+ * Writes $contents to storage
76
+ *
77
+ * @param mixed $contents
78
+ * @throws Zend_Auth_Storage_Exception If writing $contents to storage is impossible
79
+ * @return void
80
+ */
81
+ public function write($contents)
82
+ {
83
+ $this->_data = $contents;
84
+ }
85
+
86
+ /**
87
+ * Clears contents from storage
88
+ *
89
+ * @throws Zend_Auth_Storage_Exception If clearing contents from storage is impossible
90
+ * @return void
91
+ */
92
+ public function clear()
93
+ {
94
+ $this->_data = null;
95
+ }
96
+ }
lib/Zend/Auth/Storage/Session.php ADDED
@@ -0,0 +1,150 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Zend Framework
4
+ *
5
+ * LICENSE
6
+ *
7
+ * This source file is subject to the new BSD license that is bundled
8
+ * with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://framework.zend.com/license/new-bsd
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@zend.com so we can send you a copy immediately.
14
+ *
15
+ * @category Zend
16
+ * @package Zend_Auth
17
+ * @subpackage Zend_Auth_Storage
18
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
19
+ * @license http://framework.zend.com/license/new-bsd New BSD License
20
+ * @version $Id: Session.php 8862 2008-03-16 15:36:00Z thomas $
21
+ */
22
+
23
+
24
+ /**
25
+ * @see Zend_Auth_Storage_Interface
26
+ */
27
+ require_once 'Zend/Auth/Storage/Interface.php';
28
+
29
+
30
+ /**
31
+ * @see Zend_Session
32
+ */
33
+ require_once 'Zend/Session.php';
34
+
35
+
36
+ /**
37
+ * @category Zend
38
+ * @package Zend_Auth
39
+ * @subpackage Zend_Auth_Storage
40
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
41
+ * @license http://framework.zend.com/license/new-bsd New BSD License
42
+ */
43
+ class Zend_Auth_Storage_Session implements Zend_Auth_Storage_Interface
44
+ {
45
+ /**
46
+ * Default session namespace
47
+ */
48
+ const NAMESPACE_DEFAULT = 'Zend_Auth';
49
+
50
+ /**
51
+ * Default session object member name
52
+ */
53
+ const MEMBER_DEFAULT = 'storage';
54
+
55
+ /**
56
+ * Object to proxy $_SESSION storage
57
+ *
58
+ * @var Zend_Session_Namespace
59
+ */
60
+ protected $_session;
61
+
62
+ /**
63
+ * Session namespace
64
+ *
65
+ * @var mixed
66
+ */
67
+ protected $_namespace;
68
+
69
+ /**
70
+ * Session object member
71
+ *
72
+ * @var mixed
73
+ */
74
+ protected $_member;
75
+
76
+ /**
77
+ * Sets session storage options and initializes session namespace object
78
+ *
79
+ * @param mixed $namespace
80
+ * @param mixed $member
81
+ * @return void
82
+ */
83
+ public function __construct($namespace = self::NAMESPACE_DEFAULT, $member = self::MEMBER_DEFAULT)
84
+ {
85
+ $this->_namespace = $namespace;
86
+ $this->_member = $member;
87
+ $this->_session = new Zend_Session_Namespace($this->_namespace);
88
+ }
89
+
90
+ /**
91
+ * Returns the session namespace
92
+ *
93
+ * @return string
94
+ */
95
+ public function getNamespace()
96
+ {
97
+ return $this->_namespace;
98
+ }
99
+
100
+ /**
101
+ * Returns the name of the session object member
102
+ *
103
+ * @return string
104
+ */
105
+ public function getMember()
106
+ {
107
+ return $this->_member;
108
+ }
109
+
110
+ /**
111
+ * Defined by Zend_Auth_Storage_Interface
112
+ *
113
+ * @return boolean
114
+ */
115
+ public function isEmpty()
116
+ {
117
+ return !isset($this->_session->{$this->_member});
118
+ }
119
+
120
+ /**
121
+ * Defined by Zend_Auth_Storage_Interface
122
+ *
123
+ * @return mixed
124
+ */
125
+ public function read()
126
+ {
127
+ return $this->_session->{$this->_member};
128
+ }
129
+
130
+ /**
131
+ * Defined by Zend_Auth_Storage_Interface
132
+ *
133
+ * @param mixed $contents
134
+ * @return void
135
+ */
136
+ public function write($contents)
137
+ {
138
+ $this->_session->{$this->_member} = $contents;
139
+ }
140
+
141
+ /**
142
+ * Defined by Zend_Auth_Storage_Interface
143
+ *
144
+ * @return void
145
+ */
146
+ public function clear()
147
+ {
148
+ unset($this->_session->{$this->_member});
149
+ }
150
+ }
lib/Zend/Cache.php ADDED
@@ -0,0 +1,159 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Zend Framework
4
+ *
5
+ * LICENSE
6
+ *
7
+ * This source file is subject to the new BSD license that is bundled
8
+ * with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://framework.zend.com/license/new-bsd
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@zend.com so we can send you a copy immediately.
14
+ *
15
+ * @category Zend
16
+ * @package Zend_Cache
17
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
18
+ * @license http://framework.zend.com/license/new-bsd New BSD License
19
+ */
20
+
21
+
22
+ /**
23
+ * @package Zend_Cache
24
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
25
+ * @license http://framework.zend.com/license/new-bsd New BSD License
26
+ */
27
+ abstract class Zend_Cache
28
+ {
29
+
30
+ /**
31
+ * Standard frontends
32
+ *
33
+ * @var array
34
+ */
35
+ public static $standardFrontends = array('Core', 'Output', 'Class', 'File', 'Function', 'Page');
36
+
37
+ /**
38
+ * Standard backends
39
+ *
40
+ * @var array
41
+ */
42
+ public static $standardBackends = array('File', 'Sqlite', 'Memcached', 'Apc', 'ZendPlatform');
43
+
44
+ /**
45
+ * Only for backward compatibily (will be removed in 1.2.0)
46
+ *
47
+ * @var array
48
+ */
49
+ public static $availableFrontends = array('Core', 'Output', 'Class', 'File', 'Function', 'Page');
50
+
51
+ /**
52
+ * Only for backward compatibily (will be removed in 1.2.0)
53
+ *
54
+ * @var array
55
+ */
56
+ public static $availableBackends = array('File', 'Sqlite', 'Memcached', 'Apc', 'ZendPlatform');
57
+
58
+ /**
59
+ * Consts for clean() method
60
+ */
61
+ const CLEANING_MODE_ALL = 'all';
62
+ const CLEANING_MODE_OLD = 'old';
63
+ const CLEANING_MODE_MATCHING_TAG = 'matchingTag';
64
+ const CLEANING_MODE_NOT_MATCHING_TAG = 'notMatchingTag';
65
+
66
+ /**
67
+ * Factory
68
+ *
69
+ * @param string $frontend frontend name
70
+ * @param string $backend backend name
71
+ * @param array $frontendOptions associative array of options for the corresponding frontend constructor
72
+ * @param array $backendOptions associative array of options for the corresponding backend constructor
73
+ * @throws Zend_Cache_Exception
74
+ * @return Zend_Cache_Frontend
75
+ */
76
+ public static function factory($frontend, $backend, $frontendOptions = array(), $backendOptions = array())
77
+ {
78
+
79
+ // because lowercase will fail
80
+ $frontend = self::_normalizeName($frontend);
81
+ $backend = self::_normalizeName($backend);
82
+
83
+ // working on the frontend
84
+ if (in_array($frontend, self::$availableFrontends)) {
85
+ // we use a standard frontend
86
+ // For perfs reasons, with frontend == 'Core', we can interact with the Core itself
87
+ $frontendClass = 'Zend_Cache_' . ($frontend != 'Core' ? 'Frontend_' : '') . $frontend;
88
+ // For perfs reasons, we do not use the Zend_Loader::loadClass() method
89
+ // (security controls are explicit)
90
+ require_once str_replace('_', DIRECTORY_SEPARATOR, $frontendClass) . '.php';
91
+ } else {
92
+ // we use a custom frontend
93
+ $frontendClass = 'Zend_Cache_Frontend_' . $frontend;
94
+ // To avoid security problems in this case, we use Zend_Loader to load the custom class
95
+ require_once 'Zend/Loader.php';
96
+ $file = str_replace('_', DIRECTORY_SEPARATOR, $frontendClass) . '.php';
97
+ if (!(Zend_Loader::isReadable($file))) {
98
+ self::throwException("file $file not found in include_path");
99
+ }
100
+ Zend_Loader::loadClass($frontendClass);
101
+ }
102
+
103
+ // working on the backend
104
+ if (in_array($backend, Zend_Cache::$availableBackends)) {
105
+ // we use a standard backend
106
+ $backendClass = 'Zend_Cache_Backend_' . $backend;
107
+ // For perfs reasons, we do not use the Zend_Loader::loadClass() method
108
+ // (security controls are explicit)
109
+ require_once str_replace('_', DIRECTORY_SEPARATOR, $backendClass) . '.php';
110
+ } else {
111
+ // we use a custom backend
112
+ $backendClass = 'Zend_Cache_Backend_' . $backend;
113
+ // To avoid security problems in this case, we use Zend_Loader to load the custom class
114
+ require_once 'Zend/Loader.php';
115
+ $file = str_replace('_', DIRECTORY_SEPARATOR, $backendClass) . '.php';
116
+ if (!(Zend_Loader::isReadable($file))) {
117
+ self::throwException("file $file not found in include_path");
118
+ }
119
+ Zend_Loader::loadClass($backendClass);
120
+ }
121
+
122
+ // Making objects
123
+ $frontendObject = new $frontendClass($frontendOptions);
124
+ $backendObject = new $backendClass($backendOptions);
125
+ $frontendObject->setBackend($backendObject);
126
+ return $frontendObject;
127
+
128
+ }
129
+
130
+ /**
131
+ * Throw an exception
132
+ *
133
+ * Note : for perf reasons, the "load" of Zend/Cache/Exception is dynamic
134
+ * @param string $msg Message for the exception
135
+ * @throws Zend_Cache_Exception
136
+ */
137
+ public static function throwException($msg)
138
+ {
139
+ // For perfs reasons, we use this dynamic inclusion
140
+ require_once 'Zend/Cache/Exception.php';
141
+ throw new Zend_Cache_Exception($msg);
142
+ }
143
+
144
+ /**
145
+ * Normalize frontend and backend names to allow multiple words TitleCased
146
+ *
147
+ * @param string $name Name to normalize
148
+ * @return string
149
+ */
150
+ protected static function _normalizeName($name)
151
+ {
152
+ $name = ucfirst(strtolower($name));
153
+ $name = str_replace(array('-', '_', '.'), ' ', $name);
154
+ $name = ucwords($name);
155
+ $name = str_replace(' ', '', $name);
156
+ return $name;
157
+ }
158
+
159
+ }
lib/Zend/Cache/Backend.php ADDED
@@ -0,0 +1,224 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Zend Framework
4
+ *
5
+ * LICENSE
6
+ *
7
+ * This source file is subject to the new BSD license that is bundled
8
+ * with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://framework.zend.com/license/new-bsd
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@zend.com so we can send you a copy immediately.
14
+ *
15
+ * @category Zend
16
+ * @package Zend_Cache
17
+ * @subpackage Zend_Cache_Backend
18
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
19
+ * @license http://framework.zend.com/license/new-bsd New BSD License
20
+ */
21
+
22
+
23
+ /**
24
+ * @package Zend_Cache
25
+ * @subpackage Zend_Cache_Backend
26
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
27
+ * @license http://framework.zend.com/license/new-bsd New BSD License
28
+ */
29
+ class Zend_Cache_Backend
30
+ {
31
+ /**
32
+ * Frontend or Core directives
33
+ *
34
+ * =====> (int) lifetime :
35
+ * - Cache lifetime (in seconds)
36
+ * - If null, the cache is valid forever
37
+ *
38
+ * =====> (int) logging :
39
+ * - if set to true, a logging is activated throw Zend_Log
40
+ *
41
+ * @var array directives
42
+ */
43
+ protected $_directives = array(
44
+ 'lifetime' => 3600,
45
+ 'logging' => false,
46
+ 'logger' => null
47
+ );
48
+
49
+ /**
50
+ * Available options
51
+ *
52
+ * @var array available options
53
+ */
54
+ protected $_options = array();
55
+
56
+ /**
57
+ * Constructor
58
+ *
59
+ * @param array $options Associative array of options
60
+ * @throws Zend_Cache_Exception
61
+ * @return void
62
+ */
63
+ public function __construct($options = array())
64
+ {
65
+ if (!is_array($options)) {
66
+ Zend_Cache::throwException('Options parameter must be an array');
67
+ }
68
+ while (list($name, $value) = each($options)) {
69
+ $this->setOption($name, $value);
70
+ }
71
+ }
72
+
73
+ /**
74
+ * Set the frontend directives
75
+ *
76
+ * @param array $directives Assoc of directives
77
+ * @throws Zend_Cache_Exception
78
+ * @return void
79
+ */
80
+ public function setDirectives($directives)
81
+ {
82
+ if (!is_array($directives)) Zend_Cache::throwException('Directives parameter must be an array');
83
+ while (list($name, $value) = each($directives)) {
84
+ if (!is_string($name)) {
85
+ Zend_Cache::throwException("Incorrect option name : $name");
86
+ }
87
+ $name = strtolower($name);
88
+ if (array_key_exists($name, $this->_directives)) {
89
+ $this->_directives[$name] = $value;
90
+ }
91
+
92
+ }
93
+
94
+ $this->_loggerSanity();
95
+ }
96
+
97
+ /**
98
+ * Set an option
99
+ *
100
+ * @param string $name
101
+ * @param mixed $value
102
+ * @throws Zend_Cache_Exception
103
+ * @return void
104
+ */
105
+ public function setOption($name, $value)
106
+ {
107
+ if (!is_string($name)) {
108
+ Zend_Cache::throwException("Incorrect option name : $name");
109
+ }
110
+ $name = strtolower($name);
111
+ if (!array_key_exists($name, $this->_options)) {
112
+ Zend_Cache::throwException("Incorrect option name : $name");
113
+ }
114
+ $this->_options[$name] = $value;
115
+ }
116
+
117
+ /**
118
+ * Get the life time
119
+ *
120
+ * if $specificLifetime is not false, the given specific life time is used
121
+ * else, the global lifetime is used
122
+ *
123
+ * @param int $specificLifetime
124
+ * @return int Cache life time
125
+ */
126
+ public function getLifetime($specificLifetime)
127
+ {
128
+ if ($specificLifetime === false) {
129
+ return $this->_directives['lifetime'];
130
+ }
131
+ return $specificLifetime;
132
+ }
133
+
134
+ /**
135
+ * Return true if the automatic cleaning is available for the backend
136
+ *
137
+ * @return boolean
138
+ */
139
+ public function isAutomaticCleaningAvailable()
140
+ {
141
+ return true;
142
+ }
143
+
144
+ /**
145
+ * Return a system-wide tmp directory
146
+ *
147
+ * @return string System-wide tmp directory
148
+ */
149
+ static function getTmpDir()
150
+ {
151
+ if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
152
+ // windows...
153
+ foreach (array($_ENV, $_SERVER) as $tab) {
154
+ foreach (array('TEMP', 'TMP', 'windir', 'SystemRoot') as $key) {
155
+ if (isset($tab[$key])) {
156
+ $result = $tab[$key];
157
+ if (($key == 'windir') or ($key == 'SystemRoot')) {
158
+ $result = $result . '\\temp';
159
+ }
160
+ return $result;
161
+ }
162
+ }
163
+ }
164
+ return '\\temp';
165
+ } else {
166
+ // unix...
167
+ if (isset($_ENV['TMPDIR'])) return $_ENV['TMPDIR'];
168
+ if (isset($_SERVER['TMPDIR'])) return $_SERVER['TMPDIR'];
169
+ return '/tmp';
170
+ }
171
+ }
172
+
173
+ /**
174
+ * Make sure if we enable logging that the Zend_Log class
175
+ * is available.
176
+ * Create a default log object if none is set.
177
+ *
178
+ * @throws Zend_Cache_Exception
179
+ * @return void
180
+ */
181
+ protected function _loggerSanity()
182
+ {
183
+ if (!isset($this->_directives['logging']) || !$this->_directives['logging']) {
184
+ return;
185
+ }
186
+ try {
187
+ /**
188
+ * @see Zend_Loader
189
+ * @see Zend_Log
190
+ */
191
+ require_once 'Zend/Loader.php';
192
+ Zend_Loader::loadClass('Zend_Log');
193
+ } catch (Zend_Exception $e) {
194
+ Zend_Cache::throwException('Logging feature is enabled but the Zend_Log class is not available');
195
+ }
196
+ if (isset($this->_directives['logger']) && $this->_directives['logger'] instanceof Zend_Log) {
197
+ return;
198
+ }
199
+ // Create a default logger to the standard output stream
200
+ Zend_Loader::loadClass('Zend_Log_Writer_Stream');
201
+ $logger = new Zend_Log(new Zend_Log_Writer_Stream('php://output'));
202
+ $this->_directives['logger'] = $logger;
203
+ }
204
+
205
+ /**
206
+ * Log a message at the WARN (4) priority.
207
+ *
208
+ * @param string $message
209
+ * @throws Zend_Cache_Exception
210
+ * @return void
211
+ */
212
+ protected function _log($message, $priority = 4)
213
+ {
214
+ if (!$this->_directives['logging']) {
215
+ return;
216
+ }
217
+ if (!(isset($this->_directives['logger']) || $this->_directives['logger'] instanceof Zend_Log)) {
218
+ Zend_Cache::throwException('Logging is enabled but logger is not set');
219
+ }
220
+ $logger = $this->_directives['logger'];
221
+ $logger->log($message, $priority);
222
+ }
223
+
224
+ }
lib/Zend/Cache/Backend/Apc.php ADDED
@@ -0,0 +1,167 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Zend Framework
4
+ *
5
+ * LICENSE
6
+ *
7
+ * This source file is subject to the new BSD license that is bundled
8
+ * with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://framework.zend.com/license/new-bsd
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@zend.com so we can send you a copy immediately.
14
+ *
15
+ * @category Zend
16
+ * @package Zend_Cache
17
+ * @subpackage Zend_Cache_Backend
18
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
19
+ * @license http://framework.zend.com/license/new-bsd New BSD License
20
+ */
21
+
22
+
23
+ /**
24
+ * @see Zend_Cache_Backend_Interface
25
+ */
26
+ require_once 'Zend/Cache/Backend/Interface.php';
27
+
28
+ /**
29
+ * @see Zend_Cache_Backend
30
+ */
31
+ require_once 'Zend/Cache/Backend.php';
32
+
33
+
34
+ /**
35
+ * @package Zend_Cache
36
+ * @subpackage Zend_Cache_Backend
37
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
38
+ * @license http://framework.zend.com/license/new-bsd New BSD License
39
+ */
40
+ class Zend_Cache_Backend_Apc extends Zend_Cache_Backend implements Zend_Cache_Backend_Interface
41
+ {
42
+ /**
43
+ * Constructor
44
+ *
45
+ * @param array $options associative array of options
46
+ * @throws Zend_Cache_Exception
47
+ * @return void
48
+ */
49
+ public function __construct($options = array())
50
+ {
51
+ if (!extension_loaded('apc')) {
52
+ Zend_Cache::throwException('The apc extension must be loaded for using this backend !');
53
+ }
54
+ parent::__construct($options);
55
+ }
56
+
57
+ /**
58
+ * Test if a cache is available for the given id and (if yes) return it (false else)
59
+ *
60
+ * WARNING $doNotTestCacheValidity=true is unsupported by the Apc backend
61
+ *
62
+ * @param string $id cache id
63
+ * @param boolean $doNotTestCacheValidity if set to true, the cache validity won't be tested
64
+ * @return string cached datas (or false)
65
+ */
66
+ public function load($id, $doNotTestCacheValidity = false)
67
+ {
68
+ if ($doNotTestCacheValidity) {
69
+ $this->_log("Zend_Cache_Backend_Apc::load() : \$doNotTestCacheValidity=true is unsupported by the Apc backend");
70
+ }
71
+ $tmp = apc_fetch($id);
72
+ if (is_array($tmp)) {
73
+ return $tmp[0];
74
+ }
75
+ return false;
76
+ }
77
+
78
+ /**
79
+ * Test if a cache is available or not (for the given id)
80
+ *
81
+ * @param string $id cache id
82
+ * @return mixed false (a cache is not available) or "last modified" timestamp (int) of the available cache record
83
+ */
84
+ public function test($id)
85
+ {
86
+ $tmp = apc_fetch($id);
87
+ if (is_array($tmp)) {
88
+ return $tmp[1];
89
+ }
90
+ return false;
91
+ }
92
+
93
+ /**
94
+ * Save some string datas into a cache record
95
+ *
96
+ * Note : $data is always "string" (serialization is done by the
97
+ * core not by the backend)
98
+ *
99
+ * @param string $data datas to cache
100
+ * @param string $id cache id
101
+ * @param array $tags array of strings, the cache record will be tagged by each string entry
102
+ * @param int $specificLifetime if != false, set a specific lifetime for this cache record (null => infinite lifetime)
103
+ * @return boolean true if no problem
104
+ */
105
+ public function save($data, $id, $tags = array(), $specificLifetime = false)
106
+ {
107
+ $lifetime = $this->getLifetime($specificLifetime);
108
+ $result = apc_store($id, array($data, time()), $lifetime);
109
+ if (count($tags) > 0) {
110
+ $this->_log("Zend_Cache_Backend_Apc::save() : tags are unsupported by the Apc backend");
111
+ }
112
+ return $result;
113
+ }
114
+
115
+ /**
116
+ * Remove a cache record
117
+ *
118
+ * @param string $id cache id
119
+ * @return boolean true if no problem
120
+ */
121
+ public function remove($id)
122
+ {
123
+ return apc_delete($id);
124
+ }
125
+
126
+ /**
127
+ * Clean some cache records
128
+ *
129
+ * Available modes are :
130
+ * 'all' (default) => remove all cache entries ($tags is not used)
131
+ * 'old' => remove too old cache entries ($tags is not used)
132
+ * 'matchingTag' => remove cache entries matching all given tags
133
+ * ($tags can be an array of strings or a single string)
134
+ * 'notMatchingTag' => remove cache entries not matching one of the given tags
135
+ * ($tags can be an array of strings or a single string)
136
+ *
137
+ * @param string $mode clean mode
138
+ * @param array $tags array of tags
139
+ * @return boolean true if no problem
140
+ */
141
+ public function clean($mode = Zend_Cache::CLEANING_MODE_ALL, $tags = array())
142
+ {
143
+ if ($mode==Zend_Cache::CLEANING_MODE_ALL) {
144
+ return apc_clear_cache('user');
145
+ }
146
+ if ($mode==Zend_Cache::CLEANING_MODE_OLD) {
147
+ $this->_log("Zend_Cache_Backend_Apc::clean() : CLEANING_MODE_OLD is unsupported by the Apc backend");
148
+ }
149
+ if ($mode==Zend_Cache::CLEANING_MODE_MATCHING_TAG) {
150
+ $this->_log("Zend_Cache_Backend_Apc::clean() : tags are unsupported by the Apc backend");
151
+ }
152
+ if ($mode==Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG) {
153
+ $this->_log("Zend_Cache_Backend_Apc::clean() : tags are unsupported by the Apc backend");
154
+ }
155
+ }
156
+
157
+ /**
158
+ * Return true if the automatic cleaning is available for the backend
159
+ *
160
+ * @return boolean
161
+ */
162
+ public function isAutomaticCleaningAvailable()
163
+ {
164
+ return false;
165
+ }
166
+
167
+ }
lib/Zend/Cache/Backend/File.php ADDED
@@ -0,0 +1,717 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Zend Framework
4
+ *
5
+ * LICENSE
6
+ *
7
+ * This source file is subject to the new BSD license that is bundled
8
+ * with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://framework.zend.com/license/new-bsd
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@zend.com so we can send you a copy immediately.
14
+ *
15
+ * @category Zend
16
+ * @package Zend_Cache
17
+ * @subpackage Zend_Cache_Backend
18
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
19
+ * @license http://framework.zend.com/license/new-bsd New BSD License
20
+ */
21
+
22
+
23
+ /**
24
+ * @see Zend_Cache_Backend_Interface
25
+ */
26
+ require_once 'Zend/Cache/Backend/Interface.php';
27
+
28
+ /**
29
+ * @see Zend_Cache_Backend
30
+ */
31
+ require_once 'Zend/Cache/Backend.php';
32
+
33
+
34
+ /**
35
+ * @package Zend_Cache
36
+ * @subpackage Zend_Cache_Backend
37
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
38
+ * @license http://framework.zend.com/license/new-bsd New BSD License
39
+ */
40
+ class Zend_Cache_Backend_File extends Zend_Cache_Backend implements Zend_Cache_Backend_Interface
41
+ {
42
+ /**
43
+ * Available options
44
+ *
45
+ * =====> (string) cache_dir :
46
+ * - Directory where to put the cache files
47
+ *
48
+ * =====> (boolean) file_locking :
49
+ * - Enable / disable file_locking
50
+ * - Can avoid cache corruption under bad circumstances but it doesn't work on multithread
51
+ * webservers and on NFS filesystems for example
52
+ *
53
+ * =====> (boolean) read_control :
54
+ * - Enable / disable read control
55
+ * - If enabled, a control key is embeded in cache file and this key is compared with the one
56
+ * calculated after the reading.
57
+ *
58
+ * =====> (string) read_control_type :
59
+ * - Type of read control (only if read control is enabled). Available values are :
60
+ * 'md5' for a md5 hash control (best but slowest)
61
+ * 'crc32' for a crc32 hash control (lightly less safe but faster, better choice)
62
+ * 'adler32' for an adler32 hash control (excellent choice too, faster than crc32)
63
+ * 'strlen' for a length only test (fastest)
64
+ *
65
+ * =====> (int) hashed_directory_level :
66
+ * - Hashed directory level
67
+ * - Set the hashed directory structure level. 0 means "no hashed directory
68
+ * structure", 1 means "one level of directory", 2 means "two levels"...
69
+ * This option can speed up the cache only when you have many thousands of
70
+ * cache file. Only specific benchs can help you to choose the perfect value
71
+ * for you. Maybe, 1 or 2 is a good start.
72
+ *
73
+ * =====> (int) hashed_directory_umask :
74
+ * - Umask for hashed directory structure
75
+ *
76
+ * =====> (string) file_name_prefix :
77
+ * - prefix for cache files
78
+ * - be really carefull with this option because a too generic value in a system cache dir
79
+ * (like /tmp) can cause disasters when cleaning the cache
80
+ *
81
+ * =====> (int) cache_file_umask :
82
+ * - Umask for cache files
83
+ *
84
+ * =====> (int) metatadatas_array_max_size :
85
+ * - max size for the metadatas array (don't change this value unless you
86
+ * know what you are doing)
87
+ *
88
+ * @var array available options
89
+ */
90
+ protected $_options = array(
91
+ 'cache_dir' => null,
92
+ 'file_locking' => true,
93
+ 'read_control' => true,
94
+ 'read_control_type' => 'crc32',
95
+ 'hashed_directory_level' => 0,
96
+ 'hashed_directory_umask' => 0700,
97
+ 'file_name_prefix' => 'zend_cache',
98
+ 'cache_file_umask' => 0600,
99
+ 'metadatas_array_max_size' => 100
100
+ );
101
+
102
+ /**
103
+ * Array of metadatas (each item is an associative array)
104
+ *
105
+ * @var array
106
+ */
107
+ private $_metadatasArray = array();
108
+
109
+
110
+ /**
111
+ * Constructor
112
+ *
113
+ * @param array $options associative array of options
114
+ * @throws Zend_Cache_Exception
115
+ * @return void
116
+ */
117
+ public function __construct($options = array())
118
+ {
119
+ parent::__construct($options);
120
+ if (!is_null($this->_options['cache_dir'])) { // particular case for this option
121
+ $this->setCacheDir($this->_options['cache_dir']);
122
+ } else {
123
+ $this->setCacheDir(self::getTmpDir() . DIRECTORY_SEPARATOR, false);
124
+ }
125
+ if (isset($this->_options['file_name_prefix'])) { // particular case for this option
126
+ if (!preg_match('~^[\w]+$~', $this->_options['file_name_prefix'])) {
127
+ Zend_Cache::throwException('Invalid file_name_prefix : must use only [a-zA-A0-9_]');
128
+ }
129
+ }
130
+ if ($this->_options['metadatas_array_max_size'] < 10) {
131
+ Zend_Cache::throwException('Invalid metadatas_array_max_size, must be > 10');
132
+ }
133
+ }
134
+
135
+ /**
136
+ * Set the cache_dir (particular case of setOption() method)
137
+ *
138
+ * @param string $value
139
+ * @param boolean $trailingSeparator If true, add a trailing separator is necessary
140
+ * @throws Zend_Cache_Exception
141
+ * @return void
142
+ */
143
+ public function setCacheDir($value, $trailingSeparator = true)
144
+ {
145
+ if (!is_dir($value)) {
146
+ Zend_Cache::throwException('cache_dir must be a directory');
147
+ }
148
+ if (!is_writable($value)) {
149
+ Zend_Cache::throwException('cache_dir is not writable');
150
+ }
151
+ if ($trailingSeparator) {
152
+ // add a trailing DIRECTORY_SEPARATOR if necessary
153
+ $value = rtrim(realpath($value), '\\/') . DIRECTORY_SEPARATOR;
154
+ }
155
+ $this->_options['cache_dir'] = $value;
156
+ }
157
+
158
+ /**
159
+ * Test if a cache is available for the given id and (if yes) return it (false else)
160
+ *
161
+ * @param string $id cache id
162
+ * @param boolean $doNotTestCacheValidity if set to true, the cache validity won't be tested
163
+ * @return string|false cached datas
164
+ */
165
+ public function load($id, $doNotTestCacheValidity = false)
166
+ {
167
+ if (!($this->_test($id, $doNotTestCacheValidity))) {
168
+ // The cache is not hit !
169
+ return false;
170
+ }
171
+ $metadatas = $this->_getMetadatas($id);
172
+ $file = $this->_file($id);
173
+ $data = $this->_fileGetContents($file);
174
+ if ($this->_options['read_control']) {
175
+ $hashData = $this->_hash($data, $this->_options['read_control_type']);
176
+ $hashControl = $metadatas['hash'];
177
+ if ($hashData != $hashControl) {
178
+ // Problem detected by the read control !
179
+ $this->_log('Zend_Cache_Backend_File::load() / read_control : stored hash and computed hash do not match');
180
+ $this->remove($id);
181
+ return false;
182
+ }
183
+ }
184
+ return $data;
185
+ }
186
+
187
+ /**
188
+ * Test if a cache is available or not (for the given id)
189
+ *
190
+ * @param string $id cache id
191
+ * @return mixed false (a cache is not available) or "last modified" timestamp (int) of the available cache record
192
+ */
193
+ public function test($id)
194
+ {
195
+ clearstatcache();
196
+ return $this->_test($id, false);
197
+ }
198
+
199
+ /**
200
+ * Save some string datas into a cache record
201
+ *
202
+ * Note : $data is always "string" (serialization is done by the
203
+ * core not by the backend)
204
+ *
205
+ * @param string $data Datas to cache
206
+ * @param string $id Cache id
207
+ * @param array $tags Array of strings, the cache record will be tagged by each string entry
208
+ * @param int $specificLifetime If != false, set a specific lifetime for this cache record (null => infinite lifetime)
209
+ * @return boolean true if no problem
210
+ */
211
+ public function save($data, $id, $tags = array(), $specificLifetime = false)
212
+ {
213
+ clearstatcache();
214
+ $file = $this->_file($id);
215
+ $path = $this->_path($id);
216
+ $firstTry = true;
217
+ $result = false;
218
+ if ($this->_options['hashed_directory_level'] > 0) {
219
+ if (!is_writable($path)) {
220
+ // maybe, we just have to build the directory structure
221
+ @mkdir($this->_path($id), $this->_options['hashed_directory_umask'], true);
222
+ @chmod($this->_path($id), $this->_options['hashed_directory_umask']); // see #ZF-320 (this line is required in some configurations)
223
+ }
224
+ if (!is_writable($path)) {
225
+ return false;
226
+ }
227
+ }
228
+ if ($this->_options['read_control']) {
229
+ $hash = $this->_hash($data, $this->_options['read_control_type']);
230
+ } else {
231
+ $hash = '';
232
+ }
233
+ $metadatas = array(
234
+ 'hash' => $hash,
235
+ 'mtime' => time(),
236
+ 'expire' => $this->_expireTime($this->getLifetime($specificLifetime)),
237
+ 'tags' => $tags
238
+ );
239
+ $res = $this->_setMetadatas($id, $metadatas);
240
+ if (!$res) {
241
+ // FIXME : log
242
+ return false;
243
+ }
244
+ $res = $this->_filePutContents($file, $data);
245
+ return $res;
246
+ }
247
+
248
+ /**
249
+ * Remove a cache record
250
+ *
251
+ * @param string $id cache id
252
+ * @return boolean true if no problem
253
+ */
254
+ public function remove($id)
255
+ {
256
+ $file = $this->_file($id);
257
+ return ($this->_delMetadatas($id) && $this->_remove($file));
258
+ }
259
+
260
+ /**
261
+ * Clean some cache records
262
+ *
263
+ * Available modes are :
264
+ * 'all' (default) => remove all cache entries ($tags is not used)
265
+ * 'old' => remove too old cache entries ($tags is not used)
266
+ * 'matchingTag' => remove cache entries matching all given tags
267
+ * ($tags can be an array of strings or a single string)
268
+ * 'notMatchingTag' => remove cache entries not matching one of the given tags
269
+ * ($tags can be an array of strings or a single string)
270
+ *
271
+ * @param string $mode clean mode
272
+ * @param tags array $tags array of tags
273
+ * @return boolean true if no problem
274
+ */
275
+ public function clean($mode = Zend_Cache::CLEANING_MODE_ALL, $tags = array())
276
+ {
277
+ // We use this private method to hide the recursive stuff
278
+ clearstatcache();
279
+ return $this->_clean($this->_options['cache_dir'], $mode, $tags);
280
+ }
281
+
282
+ /**
283
+ * PUBLIC METHOD FOR UNIT TESTING ONLY !
284
+ *
285
+ * Force a cache record to expire
286
+ *
287
+ * @param string $id cache id
288
+ */
289
+ public function ___expire($id)
290
+ {
291
+ $metadatas = $this->_getMetadatas($id);
292
+ if ($metadatas) {
293
+ $metadatas['expire'] = 1;
294
+ $this->_setMetadatas($id, $metadatas);
295
+ }
296
+ }
297
+
298
+ /**
299
+ * Get a metadatas record
300
+ *
301
+ * @param string $id Cache id
302
+ * @return array|false Associative array of metadatas
303
+ */
304
+ private function _getMetadatas($id)
305
+ {
306
+ if (isset($this->_metadatasArray[$id])) {
307
+ return $this->_metadatasArray[$id];
308
+ } else {
309
+ $metadatas = $this->_loadMetadatas($id);
310
+ if (!$metadatas) {
311
+ return false;
312
+ }
313
+ $this->_setMetadatas($id, $metadatas);
314
+ return $metadatas;
315
+ }
316
+ }
317
+
318
+ /**
319
+ * Set a metadatas record
320
+ *
321
+ * @param string $id Cache id
322
+ * @param array $metadatas Associative array of metadatas
323
+ * @return boolean True if no problem
324
+ */
325
+ private function _setMetadatas($id, $metadatas)
326
+ {
327
+ if (count($this->_metadatasArray) >= $this->_options['metadatas_array_max_size']) {
328
+ $n = (int) ($this->_options['metadatas_array_max_size'] / 10);
329
+ $this->_metadatasArray = array_slice($this->_metadatasArray, $n);
330
+ }
331
+ $result = $this->_saveMetadatas($id, $metadatas);
332
+ if (!$result) {
333
+ return false;
334
+ }
335
+ $this->_metadatasArray[$id] = $metadatas;
336
+ return true;
337
+ }
338
+
339
+ /**
340
+ * Drop a metadata record
341
+ *
342
+ * @param string $id Cache id
343
+ * @return boolean True if no problem
344
+ */
345
+ private function _delMetadatas($id)
346
+ {
347
+ if (isset($this->_metadatasArray[$id])) {
348
+ unset($this->_metadatasArray[$id]);
349
+ }
350
+ $file = $this->_metadatasFile($id);
351
+ return $this->_remove($file);
352
+ }
353
+
354
+ /**
355
+ * Clear the metadatas array
356
+ *
357
+ * @return void
358
+ */
359
+ private function _cleanMetadatas()
360
+ {
361
+ $this->_metadatasArray = array();
362
+ }
363
+
364
+ /**
365
+ * Load metadatas from disk
366
+ *
367
+ * @param string $id Cache id
368
+ * @return array|false Metadatas associative array
369
+ */
370
+ private function _loadMetadatas($id)
371
+ {
372
+ $file = $this->_metadatasFile($id);
373
+ $result = $this->_fileGetContents($file);
374
+ if (!$result) {
375
+ return false;
376
+ }
377
+ $tmp = @unserialize($result);
378
+ return $tmp;
379
+ }
380
+
381
+ /**
382
+ * Save metadatas to disk
383
+ *
384
+ * @param string $id Cache id
385
+ * @param array $metadatas Associative array
386
+ * @return boolean True if no problem
387
+ */
388
+ private function _saveMetadatas($id, $metadatas)
389
+ {
390
+ $file = $this->_metadatasFile($id);
391
+ $result = $this->_filePutContents($file, serialize($metadatas));
392
+ if (!$result) {
393
+ return false;
394
+ }
395
+ return true;
396
+ }
397
+
398
+ /**
399
+ * Make and return a file name (with path) for metadatas
400
+ *
401
+ * @param string $id Cache id
402
+ * @return string Metadatas file name (with path)
403
+ */
404
+ private function _metadatasFile($id)
405
+ {
406
+ $path = $this->_path($id);
407
+ $fileName = $this->_idToFileName('internal-metadatas---' . $id);
408
+ return $path . $fileName;
409
+ }
410
+
411
+ /**
412
+ * Check if the given filename is a metadatas one
413
+ *
414
+ * @param string $fileName File name
415
+ * @return boolean True if it's a metadatas one
416
+ */
417
+ private function _isMetadatasFile($fileName)
418
+ {
419
+ $id = $this->_fileNameToId($fileName);
420
+ if (substr($id, 0, 21) == 'internal-metadatas---') {
421
+ return true;
422
+ } else {
423
+ return false;
424
+ }
425
+ }
426
+
427
+ /**
428
+ * Remove a file
429
+ *
430
+ * If we can't remove the file (because of locks or any problem), we will touch
431
+ * the file to invalidate it
432
+ *
433
+ * @param string $file Complete file path
434
+ * @return boolean True if ok
435
+ */
436
+ private function _remove($file)
437
+ {
438
+ if (!is_file($file)) {
439
+ return false;
440
+ }
441
+ if (!@unlink($file)) {
442
+ # we can't remove the file (because of locks or any problem)
443
+ $this->_log("Zend_Cache_Backend_File::_remove() : we can't remove $file");
444
+ return false;
445
+ }
446
+ return true;
447
+ }
448
+
449
+ /**
450
+ * Clean some cache records (private method used for recursive stuff)
451
+ *
452
+ * Available modes are :
453
+ * Zend_Cache::CLEANING_MODE_ALL (default) => remove all cache entries ($tags is not used)
454
+ * Zend_Cache::CLEANING_MODE_OLD => remove too old cache entries ($tags is not used)
455
+ * Zend_Cache::CLEANING_MODE_MATCHING_TAG => remove cache entries matching all given tags
456
+ * ($tags can be an array of strings or a single string)
457
+ * Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG => remove cache entries not {matching one of the given tags}
458
+ * ($tags can be an array of strings or a single string)
459
+ *
460
+ * @param string $dir Directory to clean
461
+ * @param string $mode Clean mode
462
+ * @param array $tags Array of tags
463
+ * @throws Zend_Cache_Exception
464
+ * @return boolean True if no problem
465
+ */
466
+ private function _clean($dir, $mode = Zend_Cache::CLEANING_MODE_ALL, $tags = array())
467
+ {
468
+ if (!is_dir($dir)) {
469
+ return false;
470
+ }
471
+ $result = true;
472
+ $prefix = $this->_options['file_name_prefix'];
473
+ $glob = @glob($dir . $prefix . '--*');
474
+ if ($glob === false) {
475
+ return true;
476
+ }
477
+ foreach ($glob as $file) {
478
+ if (is_file($file)) {
479
+ $fileName = basename($file);
480
+ if ($this->_isMetadatasFile($fileName)) {
481
+ // in CLEANING_MODE_ALL, we drop anything, even remainings old metadatas files
482
+ if ($mode != Zend_Cache::CLEANING_MODE_ALL) {
483
+ continue;
484
+ }
485
+ }
486
+ $id = $this->_fileNameToId($fileName);
487
+ $metadatas = $this->_getMetadatas($id);
488
+ if ($metadatas === FALSE) {
489
+ $metadatas = array('expire' => 1, 'tags' => array());
490
+ }
491
+ switch ($mode) {
492
+ case Zend_Cache::CLEANING_MODE_ALL:
493
+ $res = $this->remove($id);
494
+ if (!$res) {
495
+ // in this case only, we accept a problem with the metadatas file drop
496
+ $res = $this->_remove($file);
497
+ }
498
+ $result = $result && $res;
499
+ break;
500
+ case Zend_Cache::CLEANING_MODE_OLD:
501
+ if (time() > $metadatas['expire']) {
502
+ $result = ($result) && ($this->remove($id));
503
+ }
504
+ break;
505
+ case Zend_Cache::CLEANING_MODE_MATCHING_TAG:
506
+ $matching = true;
507
+ foreach ($tags as $tag) {
508
+ if (!in_array($tag, $metadatas['tags'])) {
509
+ $matching = false;
510
+ break;
511
+ }
512
+ }
513
+ if ($matching) {
514
+ $result = ($result) && ($this->remove($id));
515
+ }
516
+ break;
517
+ case Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG:
518
+ $matching = false;
519
+ foreach ($tags as $tag) {
520
+ if (in_array($tag, $metadatas['tags'])) {
521
+ $matching = true;
522
+ break;
523
+ }
524
+ }
525
+ if (!$matching) {
526
+ $result = ($result) && $this->remove($id);
527
+ }
528
+ break;
529
+ default:
530
+ Zend_Cache::throwException('Invalid mode for clean() method');
531
+ break;
532
+ }
533
+ }
534
+ if ((is_dir($file)) and ($this->_options['hashed_directory_level']>0)) {
535
+ // Recursive call
536
+ $result = ($result) && ($this->_clean($file . DIRECTORY_SEPARATOR, $mode, $tags));
537
+ if ($mode=='all') {
538
+ // if mode=='all', we try to drop the structure too
539
+ @rmdir($file);
540
+ }
541
+ }
542
+ }
543
+ return $result;
544
+ }
545
+
546
+ /**
547
+ * Compute & return the expire time
548
+ *
549
+ * @return int expire time (unix timestamp)
550
+ */
551
+ private function _expireTime($lifetime)
552
+ {
553
+ if (is_null($lifetime)) {
554
+ return 9999999999;
555
+ }
556
+ return time() + $lifetime;
557
+ }
558
+
559
+ /**
560
+ * Make a control key with the string containing datas
561
+ *
562
+ * @param string $data Data
563
+ * @param string $controlType Type of control 'md5', 'crc32' or 'strlen'
564
+ * @throws Zend_Cache_Exception
565
+ * @return string Control key
566
+ */
567
+ private function _hash($data, $controlType)
568
+ {
569
+ switch ($controlType) {
570
+ case 'md5':
571
+ return md5($data);
572
+ case 'crc32':
573
+ return crc32($data);
574
+ case 'strlen':
575
+ return strlen($data);
576
+ case 'adler32':
577
+ return hash('adler32', $data);
578
+ default:
579
+ Zend_Cache::throwException("Incorrect hash function : $controlType");
580
+ }
581
+ }
582
+
583
+ /**
584
+ * Transform a cache id into a file name and return it
585
+ *
586
+ * @param string $id Cache id
587
+ * @return string File name
588
+ */
589
+ private function _idToFileName($id)
590
+ {
591
+ $prefix = $this->_options['file_name_prefix'];
592
+ $result = $prefix . '---' . $id;
593
+ return $result;
594
+ }
595
+
596
+ /**
597
+ * Make and return a file name (with path)
598
+ *
599
+ * @param string $id Cache id
600
+ * @return string File name (with path)
601
+ */
602
+ private function _file($id)
603
+ {
604
+ $path = $this->_path($id);
605
+ $fileName = $this->_idToFileName($id);
606
+ return $path . $fileName;
607
+ }
608
+
609
+ /**
610
+ * Return the complete directory path of a filename (including hashedDirectoryStructure)
611
+ *
612
+ * @param string $id Cache id
613
+ * @return string Complete directory path
614
+ */
615
+ private function _path($id)
616
+ {
617
+ $root = $this->_options['cache_dir'];
618
+ $prefix = $this->_options['file_name_prefix'];
619
+ if ($this->_options['hashed_directory_level']>0) {
620
+ $hash = hash('adler32', $id);
621
+ for ($i=0 ; $i < $this->_options['hashed_directory_level'] ; $i++) {
622
+ $root = $root . $prefix . '--' . substr($hash, 0, $i + 1) . DIRECTORY_SEPARATOR;
623
+ }
624
+ }
625
+ return $root;
626
+ }
627
+
628
+ /**
629
+ * Test if the given cache id is available (and still valid as a cache record)
630
+ *
631
+ * @param string $id Cache id
632
+ * @param boolean $doNotTestCacheValidity If set to true, the cache validity won't be tested
633
+ * @return boolean|mixed false (a cache is not available) or "last modified" timestamp (int) of the available cache record
634
+ */
635
+ private function _test($id, $doNotTestCacheValidity)
636
+ {
637
+ $metadatas = $this->_getMetadatas($id);
638
+ if (!$metadatas) {
639
+ return false;
640
+ }
641
+ if ($doNotTestCacheValidity || (time() <= $metadatas['expire'])) {
642
+ return $metadatas['mtime'];
643
+ }
644
+ return false;
645
+ }
646
+
647
+ /**
648
+ * Return the file content of the given file
649
+ *
650
+ * @param string $file File complete path
651
+ * @return string File content (or false if problem)
652
+ */
653
+ private function _fileGetContents($file)
654
+ {
655
+ $result = false;
656
+ if (!is_file($file)) {
657
+ return false;
658
+ }
659
+ if (function_exists('get_magic_quotes_runtime')) {
660
+ $mqr = @get_magic_quotes_runtime();
661
+ @set_magic_quotes_runtime(0);
662
+ }
663
+ $f = @fopen($file, 'rb');
664
+ if ($f) {
665
+ if ($this->_options['file_locking']) @flock($f, LOCK_SH);
666
+ $fsize = @filesize($file);
667
+ if ($fsize == 0) {
668
+ $result = '';
669
+ } else {
670
+ $result = fread($f, $fsize);
671
+ }
672
+ if ($this->_options['file_locking']) @flock($f, LOCK_UN);
673
+ @fclose($f);
674
+ }
675
+ if (function_exists('set_magic_quotes_runtime')) {
676
+ @set_magic_quotes_runtime($mqr);
677
+ }
678
+ return $result;
679
+ }
680
+
681
+ /**
682
+ * Put the given string into the given file
683
+ *
684
+ * @param string $file File complete path
685
+ * @param string $string String to put in file
686
+ * @return boolean true if no problem
687
+ */
688
+ private function _filePutContents($file, $string)
689
+ {
690
+ $result = false;
691
+ $f = @fopen($file, 'wb');
692
+ if ($f) {
693
+ if ($this->_options['file_locking']) @flock($f, LOCK_EX);
694
+ $tmp = @fwrite($f, $string);
695
+ if (!($tmp === FALSE)) {
696
+ $result = true;
697
+ }
698
+ if ($this->_options['file_locking']) @flock($f, LOCK_UN);
699
+ @fclose($f);
700
+ }
701
+ @chmod($file, $this->_options['cache_file_umask']);
702
+ return $result;
703
+ }
704
+
705
+ /**
706
+ * Transform a file name into cache id and return it
707
+ *
708
+ * @param string $fileName File name
709
+ * @return string Cache id
710
+ */
711
+ private function _fileNameToId($fileName)
712
+ {
713
+ $prefix = $this->_options['file_name_prefix'];
714
+ return preg_replace('~^' . $prefix . '---(.*)$~', '$1', $fileName);
715
+ }
716
+
717
+ }
lib/Zend/Cache/Backend/Interface.php ADDED
@@ -0,0 +1,96 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Zend Framework
4
+ *
5
+ * LICENSE
6
+ *
7
+ * This source file is subject to the new BSD license that is bundled
8
+ * with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://framework.zend.com/license/new-bsd
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@zend.com so we can send you a copy immediately.
14
+ *
15
+ * @category Zend
16
+ * @package Zend_Cache
17
+ * @subpackage Zend_Cache_Backend
18
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
19
+ * @license http://framework.zend.com/license/new-bsd New BSD License
20
+ */
21
+
22
+
23
+ /**
24
+ * @package Zend_Cache
25
+ * @subpackage Zend_Cache_Backend
26
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
27
+ * @license http://framework.zend.com/license/new-bsd New BSD License
28
+ */
29
+ interface Zend_Cache_Backend_Interface
30
+ {
31
+ /**
32
+ * Set the frontend directives
33
+ *
34
+ * @param array $directives assoc of directives
35
+ */
36
+ public function setDirectives($directives);
37
+
38
+ /**
39
+ * Test if a cache is available for the given id and (if yes) return it (false else)
40
+ *
41
+ * Note : return value is always "string" (unserialization is done by the core not by the backend)
42
+ *
43
+ * @param string $id Cache id
44
+ * @param boolean $doNotTestCacheValidity If set to true, the cache validity won't be tested
45
+ * @return string|false cached datas
46
+ */
47
+ public function load($id, $doNotTestCacheValidity = false);
48
+
49
+ /**
50
+ * Test if a cache is available or not (for the given id)
51
+ *
52
+ * @param string $id cache id
53
+ * @return mixed|false (a cache is not available) or "last modified" timestamp (int) of the available cache record
54
+ */
55
+ public function test($id);
56
+
57
+ /**
58
+ * Save some string datas into a cache record
59
+ *
60
+ * Note : $data is always "string" (serialization is done by the
61
+ * core not by the backend)
62
+ *
63
+ * @param string $data Datas to cache
64
+ * @param string $id Cache id
65
+ * @param array $tags Array of strings, the cache record will be tagged by each string entry
66
+ * @param int $specificLifetime If != false, set a specific lifetime for this cache record (null => infinite lifetime)
67
+ * @return boolean true if no problem
68
+ */
69
+ public function save($data, $id, $tags = array(), $specificLifetime = false);
70
+
71
+ /**
72
+ * Remove a cache record
73
+ *
74
+ * @param string $id Cache id
75
+ * @return boolean True if no problem
76
+ */
77
+ public function remove($id);
78
+
79
+ /**
80
+ * Clean some cache records
81
+ *
82
+ * Available modes are :
83
+ * Zend_Cache::CLEANING_MODE_ALL (default) => remove all cache entries ($tags is not used)
84
+ * Zend_Cache::CLEANING_MODE_OLD => remove too old cache entries ($tags is not used)
85
+ * Zend_Cache::CLEANING_MODE_MATCHING_TAG => remove cache entries matching all given tags
86
+ * ($tags can be an array of strings or a single string)
87
+ * Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG => remove cache entries not {matching one of the given tags}
88
+ * ($tags can be an array of strings or a single string)
89
+ *
90
+ * @param string $mode Clean mode
91
+ * @param array $tags Array of tags
92
+ * @return boolean true if no problem
93
+ */
94
+ public function clean($mode = Zend_Cache::CLEANING_MODE_ALL, $tags = array());
95
+
96
+ }
lib/Zend/Cache/Backend/Memcached.php ADDED
@@ -0,0 +1,234 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Zend Framework
4
+ *
5
+ * LICENSE
6
+ *
7
+ * This source file is subject to the new BSD license that is bundled
8
+ * with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://framework.zend.com/license/new-bsd
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@zend.com so we can send you a copy immediately.
14
+ *
15
+ * @category Zend
16
+ * @package Zend_Cache
17
+ * @subpackage Zend_Cache_Backend
18
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
19
+ * @license http://framework.zend.com/license/new-bsd New BSD License
20
+ */
21
+
22
+
23
+ /**
24
+ * @see Zend_Cache_Backend_Interface
25
+ */
26
+ require_once 'Zend/Cache/Backend/Interface.php';
27
+
28
+ /**
29
+ * @see Zend_Cache_Backend
30
+ */
31
+ require_once 'Zend/Cache/Backend.php';
32
+
33
+
34
+ /**
35
+ * @package Zend_Cache
36
+ * @subpackage Zend_Cache_Backend
37
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
38
+ * @license http://framework.zend.com/license/new-bsd New BSD License
39
+ */
40
+ class Zend_Cache_Backend_Memcached extends Zend_Cache_Backend implements Zend_Cache_Backend_Interface
41
+ {
42
+ /**
43
+ * Default Host IP Address or DNS
44
+ */
45
+ const DEFAULT_HOST = '127.0.0.1';
46
+
47
+ /**
48
+ * Default port
49
+ */
50
+ const DEFAULT_PORT = 11211;
51
+
52
+ /**
53
+ * Persistent
54
+ */
55
+ const DEFAULT_PERSISTENT = true;
56
+
57
+ /**
58
+ * Available options
59
+ *
60
+ * =====> (array) servers :
61
+ * an array of memcached server ; each memcached server is described by an associative array :
62
+ * 'host' => (string) : the name of the memcached server
63
+ * 'port' => (int) : the port of the memcached server
64
+ * 'persistent' => (bool) : use or not persistent connections to this memcached server
65
+ *
66
+ * =====> (boolean) compression :
67
+ * true if you want to use on-the-fly compression
68
+ *
69
+ * @var array available options
70
+ */
71
+ protected $_options = array(
72
+ 'servers' => array(array(
73
+ 'host' => Zend_Cache_Backend_Memcached::DEFAULT_HOST,
74
+ 'port' => Zend_Cache_Backend_Memcached::DEFAULT_PORT,
75
+ 'persistent' => Zend_Cache_Backend_Memcached::DEFAULT_PERSISTENT
76
+ )),
77
+ 'compression' => false
78
+ );
79
+
80
+ /**
81
+ * Memcache object
82
+ *
83
+ * @var mixed memcache object
84
+ */
85
+ private $_memcache = null;
86
+
87
+ /**
88
+ * Constructor
89
+ *
90
+ * @param array $options associative array of options
91
+ * @throws Zend_Cache_Exception
92
+ * @return void
93
+ */
94
+ public function __construct($options = array())
95
+ {
96
+ if (!extension_loaded('memcache')) {
97
+ Zend_Cache::throwException('The memcache extension must be loaded for using this backend !');
98
+ }
99
+ parent::__construct($options);
100
+ if (isset($this->_options['servers'])) {
101
+ $value= $this->_options['servers'];
102
+ if (isset($value['host'])) {
103
+ // in this case, $value seems to be a simple associative array (one server only)
104
+ $value = array(0 => $value); // let's transform it into a classical array of associative arrays
105
+ }
106
+ $this->setOption('servers', $value);
107
+ }
108
+ $this->_memcache = new Memcache;
109
+ foreach ($this->_options['servers'] as $server) {
110
+ if (!array_key_exists('persistent', $server)) {
111
+ $server['persistent'] = Zend_Cache_Backend_Memcached::DEFAULT_PERSISTENT;
112
+ }
113
+ if (!array_key_exists('port', $server)) {
114
+ $server['port'] = Zend_Cache_Backend_Memcached::DEFAULT_PORT;
115
+ }
116
+ $this->_memcache->addServer($server['host'], $server['port'], $server['persistent']);
117
+ }
118
+ }
119
+
120
+ /**
121
+ * Test if a cache is available for the given id and (if yes) return it (false else)
122
+ *
123
+ * @param string $id Cache id
124
+ * @param boolean $doNotTestCacheValidity If set to true, the cache validity won't be tested
125
+ * @return string|false cached datas
126
+ */
127
+ public function load($id, $doNotTestCacheValidity = false)
128
+ {
129
+ // WARNING : $doNotTestCacheValidity is not supported !!!
130
+ if ($doNotTestCacheValidity) {
131
+ $this->_log("Zend_Cache_Backend_Memcached::load() : \$doNotTestCacheValidity=true is unsupported by the Memcached backend");
132
+ }
133
+ $tmp = $this->_memcache->get($id);
134
+ if (is_array($tmp)) {
135
+ return $tmp[0];
136
+ }
137
+ return false;
138
+ }
139
+
140
+ /**
141
+ * Test if a cache is available or not (for the given id)
142
+ *
143
+ * @param string $id Cache id
144
+ * @return mixed|false (a cache is not available) or "last modified" timestamp (int) of the available cache record
145
+ */
146
+ public function test($id)
147
+ {
148
+ $tmp = $this->_memcache->get($id);
149
+ if (is_array($tmp)) {
150
+ return $tmp[1];
151
+ }
152
+ return false;
153
+ }
154
+
155
+ /**
156
+ * Save some string datas into a cache record
157
+ *
158
+ * Note : $data is always "string" (serialization is done by the
159
+ * core not by the backend)
160
+ *
161
+ * @param string $data Datas to cache
162
+ * @param string $id Cache id
163
+ * @param array $tags Array of strings, the cache record will be tagged by each string entry
164
+ * @param int $specificLifetime If != false, set a specific lifetime for this cache record (null => infinite lifetime)
165
+ * @return boolean True if no problem
166
+ */
167
+ public function save($data, $id, $tags = array(), $specificLifetime = false)
168
+ {
169
+ $lifetime = $this->getLifetime($specificLifetime);
170
+ if ($this->_options['compression']) {
171
+ $flag = MEMCACHE_COMPRESSED;
172
+ } else {
173
+ $flag = 0;
174
+ }
175
+ $result = $this->_memcache->set($id, array($data, time()), $flag, $lifetime);
176
+ if (count($tags) > 0) {
177
+ $this->_log("Zend_Cache_Backend_Memcached::save() : tags are unsupported by the Memcached backend");
178
+ }
179
+ return $result;
180
+ }
181
+
182
+ /**
183
+ * Remove a cache record
184
+ *
185
+ * @param string $id Cache id
186
+ * @return boolean True if no problem
187
+ */
188
+ public function remove($id)
189
+ {
190
+ return $this->_memcache->delete($id);
191
+ }
192
+
193
+ /**
194
+ * Clean some cache records
195
+ *
196
+ * Available modes are :
197
+ * 'all' (default) => remove all cache entries ($tags is not used)
198
+ * 'old' => remove too old cache entries ($tags is not used)
199
+ * 'matchingTag' => remove cache entries matching all given tags
200
+ * ($tags can be an array of strings or a single string)
201
+ * 'notMatchingTag' => remove cache entries not matching one of the given tags
202
+ * ($tags can be an array of strings or a single string)
203
+ *
204
+ * @param string $mode Clean mode
205
+ * @param array $tags Array of tags
206
+ * @return boolean True if no problem
207
+ */
208
+ public function clean($mode = Zend_Cache::CLEANING_MODE_ALL, $tags = array())
209
+ {
210
+ if ($mode==Zend_Cache::CLEANING_MODE_ALL) {
211
+ return $this->_memcache->flush();
212
+ }
213
+ if ($mode==Zend_Cache::CLEANING_MODE_OLD) {
214
+ $this->_log("Zend_Cache_Backend_Memcached::clean() : CLEANING_MODE_OLD is unsupported by the Memcached backend");
215
+ }
216
+ if ($mode==Zend_Cache::CLEANING_MODE_MATCHING_TAG) {
217
+ $this->_log("Zend_Cache_Backend_Memcached::clean() : tags are unsupported by the Memcached backend");
218
+ }
219
+ if ($mode==Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG) {
220
+ $this->_log("Zend_Cache_Backend_Memcached::clean() : tags are unsupported by the Memcached backend");
221
+ }
222
+ }
223
+
224
+ /**
225
+ * Return true if the automatic cleaning is available for the backend
226
+ *
227
+ * @return boolean
228
+ */
229
+ public function isAutomaticCleaningAvailable()
230
+ {
231
+ return false;
232
+ }
233
+
234
+ }
lib/Zend/Cache/Backend/Sqlite.php ADDED
@@ -0,0 +1,427 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Zend Framework
4
+ *
5
+ * LICENSE
6
+ *
7
+ * This source file is subject to the new BSD license that is bundled
8
+ * with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://framework.zend.com/license/new-bsd
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@zend.com so we can send you a copy immediately.
14
+ *
15
+ * @category Zend
16
+ * @package Zend_Cache
17
+ * @subpackage Zend_Cache_Backend
18
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
19
+ * @license http://framework.zend.com/license/new-bsd New BSD License
20
+ */
21
+
22
+
23
+ /**
24
+ * @see Zend_Cache_Backend_Interface
25
+ */
26
+ require_once 'Zend/Cache/Backend/Interface.php';
27
+
28
+ /**
29
+ * @see Zend_Cache_Backend
30
+ */
31
+ require_once 'Zend/Cache/Backend.php';
32
+
33
+ /**
34
+ * @package Zend_Cache
35
+ * @subpackage Zend_Cache_Backend
36
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
37
+ * @license http://framework.zend.com/license/new-bsd New BSD License
38
+ */
39
+ class Zend_Cache_Backend_Sqlite extends Zend_Cache_Backend implements Zend_Cache_Backend_Interface
40
+ {
41
+ /**
42
+ * Available options
43
+ *
44
+ * =====> (string) cache_db_complete_path :
45
+ * - the complete path (filename included) of the SQLITE database
46
+ *
47
+ * ====> (int) automatic_vacuum_factor :
48
+ * - Disable / Tune the automatic vacuum process
49
+ * - The automatic vacuum process defragment the database file (and make it smaller)
50
+ * when a clean() or delete() is called
51
+ * 0 => no automatic vacuum
52
+ * 1 => systematic vacuum (when delete() or clean() methods are called)
53
+ * x (integer) > 1 => automatic vacuum randomly 1 times on x clean() or delete()
54
+ *
55
+ * @var array Available options
56
+ */
57
+ protected $_options = array(
58
+ 'cache_db_complete_path' => null,
59
+ 'automatic_vacuum_factor' => 1
60
+ );
61
+
62
+ /**
63
+ * DB ressource
64
+ *
65
+ * @var mixed $_db
66
+ */
67
+ private $_db = null;
68
+
69
+ /**
70
+ * Constructor
71
+ *
72
+ * @param array $options Associative array of options
73
+ * @throws Zend_cache_Exception
74
+ * @return void
75
+ */
76
+ public function __construct($options = array())
77
+ {
78
+ parent::__construct($options);
79
+ if (is_null($this->_options['cache_db_complete_path'])) {
80
+ Zend_Cache::throwException('cache_db_complete_path option has to set');
81
+ }
82
+ if (!extension_loaded('sqlite')) {
83
+ Zend_Cache::throwException("Cannot use SQLite storage because the 'sqlite' extension is not loaded in the current PHP environment");
84
+ }
85
+ $this->_getConnection();
86
+ }
87
+
88
+ /**
89
+ * Destructor
90
+ *
91
+ * @return void
92
+ */
93
+ public function __destruct()
94
+ {
95
+ @sqlite_close($this->_getConnection());
96
+ }
97
+
98
+ /**
99
+ * Test if a cache is available for the given id and (if yes) return it (false else)
100
+ *
101
+ * @param string $id Cache id
102
+ * @param boolean $doNotTestCacheValidity If set to true, the cache validity won't be tested
103
+ * @return string|false Cached datas
104
+ */
105
+ public function load($id, $doNotTestCacheValidity = false)
106
+ {
107
+ $sql = "SELECT content FROM cache WHERE id='$id'";
108
+ if (!$doNotTestCacheValidity) {
109
+ $sql = $sql . " AND (expire=0 OR expire>" . time() . ')';
110
+ }
111
+ $result = $this->_query($sql);
112
+ $row = @sqlite_fetch_array($result);
113
+ if ($row) {
114
+ return $row['content'];
115
+ }
116
+ return false;
117
+ }
118
+
119
+ /**
120
+ * Test if a cache is available or not (for the given id)
121
+ *
122
+ * @param string $id Cache id
123
+ * @return mixed|false (a cache is not available) or "last modified" timestamp (int) of the available cache record
124
+ */
125
+ public function test($id)
126
+ {
127
+ $sql = "SELECT lastModified FROM cache WHERE id='$id' AND (expire=0 OR expire>" . time() . ')';
128
+ $result = $this->_query($sql);
129
+ $row = @sqlite_fetch_array($result);
130
+ if ($row) {
131
+ return ((int) $row['lastModified']);
132
+ }
133
+ return false;
134
+ }
135
+
136
+ /**
137
+ * Save some string datas into a cache record
138
+ *
139
+ * Note : $data is always "string" (serialization is done by the
140
+ * core not by the backend)
141
+ *
142
+ * @param string $data Datas to cache
143
+ * @param string $id Cache id
144
+ * @param array $tags Array of strings, the cache record will be tagged by each string entry
145
+ * @param int $specificLifetime If != false, set a specific lifetime for this cache record (null => infinite lifetime)
146
+ * @throws Zend_Cache_Exception
147
+ * @return boolean True if no problem
148
+ */
149
+ public function save($data, $id, $tags = array(), $specificLifetime = false)
150
+ {
151
+ if (!$this->_checkStructureVersion()) {
152
+ $this->_buildStructure();
153
+ if (!$this->_checkStructureVersion()) {
154
+ Zend_Cache::throwException("Impossible to build cache structure in " . $this->_options['cache_db_complete_path']);
155
+ }
156
+ }
157
+ $lifetime = $this->getLifetime($specificLifetime);
158
+ $data = @sqlite_escape_string($data);
159
+ $mktime = time();
160
+ if (is_null($lifetime)) {
161
+ $expire = 0;
162
+ } else {
163
+ $expire = $mktime + $lifetime;
164
+ }
165
+ $this->_query("DELETE FROM cache WHERE id='$id'");
166
+ $sql = "INSERT INTO cache (id, content, lastModified, expire) VALUES ('$id', '$data', $mktime, $expire)";
167
+ $res = $this->_query($sql);
168
+ if (!$res) {
169
+ $this->_log("Zend_Cache_Backend_Sqlite::save() : impossible to store the cache id=$id");
170
+ return false;
171
+ }
172
+ $res = true;
173
+ foreach ($tags as $tag) {
174
+ $res = $res && $this->_registerTag($id, $tag);
175
+ }
176
+ return $res;
177
+ }
178
+
179
+ /**
180
+ * Remove a cache record
181
+ *
182
+ * @param string $id Cache id
183
+ * @return boolean True if no problem
184
+ */
185
+ public function remove($id)
186
+ {
187
+ $res = $this->_query("SELECT COUNT(*) AS nbr FROM cache WHERE id='$id'");
188
+ $result1 = @sqlite_fetch_single($res);
189
+ $result2 = $this->_query("DELETE FROM cache WHERE id='$id'");
190
+ $result3 = $this->_query("DELETE FROM tag WHERE id='$id'");
191
+ $this->_automaticVacuum();
192
+ return ($result1 && $result2 && $result3);
193
+ }
194
+
195
+ /**
196
+ * Clean some cache records
197
+ *
198
+ * Available modes are :
199
+ * Zend_Cache::CLEANING_MODE_ALL (default) => remove all cache entries ($tags is not used)
200
+ * Zend_Cache::CLEANING_MODE_OLD => remove too old cache entries ($tags is not used)
201
+ * Zend_Cache::CLEANING_MODE_MATCHING_TAG => remove cache entries matching all given tags
202
+ * ($tags can be an array of strings or a single string)
203
+ * Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG => remove cache entries not {matching one of the given tags}
204
+ * ($tags can be an array of strings or a single string)
205
+ *
206
+ * @param string $mode Clean mode
207
+ * @param array $tags Array of tags
208
+ * @return boolean True if no problem
209
+ */
210
+ public function clean($mode = Zend_Cache::CLEANING_MODE_ALL, $tags = array())
211
+ {
212
+ $return = $this->_clean($mode, $tags);
213
+ $this->_automaticVacuum();
214
+ return $return;
215
+ }
216
+
217
+ /**
218
+ * PUBLIC METHOD FOR UNIT TESTING ONLY !
219
+ *
220
+ * Force a cache record to expire
221
+ *
222
+ * @param string $id Cache id
223
+ */
224
+ public function ___expire($id)
225
+ {
226
+ $time = time() - 1;
227
+ $this->_query("UPDATE cache SET lastModified=$time, expire=$time WHERE id='$id'");
228
+ }
229
+
230
+ /**
231
+ * Return the connection resource
232
+ *
233
+ * If we are not connected, the connection is made
234
+ *
235
+ * @throws Zend_Cache_Exception
236
+ * @return resource Connection resource
237
+ */
238
+ private function _getConnection()
239
+ {
240
+ if (is_resource($this->_db)) {
241
+ return $this->_db;
242
+ } else {
243
+ $this->_db = @sqlite_open($this->_options['cache_db_complete_path']);
244
+ if (!(is_resource($this->_db))) {
245
+ Zend_Cache::throwException("Impossible to open " . $this->_options['cache_db_complete_path'] . " cache DB file");
246
+ }
247
+ return $this->_db;
248
+ }
249
+ }
250
+
251
+ /**
252
+ * Execute an SQL query silently
253
+ *
254
+ * @param string $query SQL query
255
+ * @return mixed|false query results
256
+ */
257
+ private function _query($query)
258
+ {
259
+ $db = $this->_getConnection();
260
+ if (is_resource($db)) {
261
+ $res = @sqlite_query($db, $query);
262
+ if ($res === false) {
263
+ return false;
264
+ } else {
265
+ return $res;
266
+ }
267
+ }
268
+ return false;
269
+ }
270
+
271
+ /**
272
+ * Deal with the automatic vacuum process
273
+ *
274
+ * @return void
275
+ */
276
+ private function _automaticVacuum()
277
+ {
278
+ if ($this->_options['automatic_vacuum_factor'] > 0) {
279
+ $rand = rand(1, $this->_options['automatic_vacuum_factor']);
280
+ if ($rand == 1) {
281
+ $this->_query('VACUUM');
282
+ @sqlite_close($this->_getConnection());
283
+ }
284
+ }
285
+ }
286
+
287
+ /**
288
+ * Register a cache id with the given tag
289
+ *
290
+ * @param string $id Cache id
291
+ * @param string $tag Tag
292
+ * @return boolean True if no problem
293
+ */
294
+ private function _registerTag($id, $tag) {
295
+ $res = $this->_query("DELETE FROM TAG WHERE name='$tag' AND id='$id'");
296
+ $res = $this->_query("INSERT INTO tag (name, id) VALUES ('$tag', '$id')");
297
+ if (!$res) {
298
+ $this->_log("Zend_Cache_Backend_Sqlite::_registerTag() : impossible to register tag=$tag on id=$id");
299
+ return false;
300
+ }
301
+ return true;
302
+ }
303
+
304
+ /**
305
+ * Build the database structure
306
+ *
307
+ * @return false
308
+ */
309
+ private function _buildStructure()
310
+ {
311
+ $this->_query('DROP INDEX tag_id_index');
312
+ $this->_query('DROP INDEX tag_name_index');
313
+ $this->_query('DROP INDEX cache_id_expire_index');
314
+ $this->_query('DROP TABLE version');
315
+ $this->_query('DROP TABLE cache');
316
+ $this->_query('DROP TABLE tag');
317
+ $this->_query('CREATE TABLE version (num INTEGER PRIMARY KEY)');
318
+ $this->_query('CREATE TABLE cache (id TEXT PRIMARY KEY, content BLOB, lastModified INTEGER, expire INTEGER)');
319
+ $this->_query('CREATE TABLE tag (name TEXT, id TEXT)');
320
+ $this->_query('CREATE INDEX tag_id_index ON tag(id)');
321
+ $this->_query('CREATE INDEX tag_name_index ON tag(name)');
322
+ $this->_query('CREATE INDEX cache_id_expire_index ON cache(id, expire)');
323
+ $this->_query('INSERT INTO version (num) VALUES (1)');
324
+ }
325
+
326
+ /**
327
+ * Check if the database structure is ok (with the good version)
328
+ *
329
+ * @return boolean True if ok
330
+ */
331
+ private function _checkStructureVersion()
332
+ {
333
+ $result = $this->_query("SELECT num FROM version");
334
+ if (!$result) return false;
335
+ $row = @sqlite_fetch_array($result);
336
+ if (!$row) {
337
+ return false;
338
+ }
339
+ if (((int) $row['num']) != 1) {
340
+ // old cache structure
341
+ $this->_log('Zend_Cache_Backend_Sqlite::_checkStructureVersion() : old cache structure version detected => the cache is going to be dropped');
342
+ return false;
343
+ }
344
+ return true;
345
+ }
346
+
347
+ /**
348
+ * Clean some cache records
349
+ *
350
+ * Available modes are :
351
+ * Zend_Cache::CLEANING_MODE_ALL (default) => remove all cache entries ($tags is not used)
352
+ * Zend_Cache::CLEANING_MODE_OLD => remove too old cache entries ($tags is not used)
353
+ * Zend_Cache::CLEANING_MODE_MATCHING_TAG => remove cache entries matching all given tags
354
+ * ($tags can be an array of strings or a single string)
355
+ * Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG => remove cache entries not {matching one of the given tags}
356
+ * ($tags can be an array of strings or a single string)
357
+ *
358
+ * @param string $mode Clean mode
359
+ * @param array $tags Array of tags
360
+ * @return boolean True if no problem
361
+ */
362
+ private function _clean($mode = Zend_Cache::CLEANING_MODE_ALL, $tags = array())
363
+ {
364
+ if ($mode==Zend_Cache::CLEANING_MODE_ALL) {
365
+ $res1 = $this->_query('DELETE FROM cache');
366
+ $res2 = $this->_query('DELETE FROM tag');
367
+ return $res1 && $res2;
368
+ }
369
+ if ($mode==Zend_Cache::CLEANING_MODE_OLD) {
370
+ $mktime = time();
371
+ $res1 = $this->_query("DELETE FROM tag WHERE id IN (SELECT id FROM cache WHERE expire>0 AND expire<=$mktime)");
372
+ $res2 = $this->_query("DELETE FROM cache WHERE expire>0 AND expire<=$mktime");
373
+ return $res1 && $res2;
374
+ }
375
+ if ($mode==Zend_Cache::CLEANING_MODE_MATCHING_TAG) {
376
+ $first = true;
377
+ $ids = array();
378
+ foreach ($tags as $tag) {
379
+ $res = $this->_query("SELECT DISTINCT(id) AS id FROM tag WHERE name='$tag'");
380
+ if (!$res) {
381
+ return false;
382
+ }
383
+ $rows = @sqlite_fetch_all($res, SQLITE_ASSOC);
384
+ $ids2 = array();
385
+ foreach ($rows as $row) {
386
+ $ids2[] = $row['id'];
387
+ }
388
+ if ($first) {
389
+ $ids = $ids2;
390
+ $first = false;
391
+ } else {
392
+ $ids = array_intersect($ids, $ids2);
393
+ }
394
+ }
395
+ $result = true;
396
+ foreach ($ids as $id) {
397
+ $result = $result && ($this->remove($id));
398
+ }
399
+ return $result;
400
+ }
401
+ if ($mode==Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG) {
402
+ $res = $this->_query("SELECT id FROM cache");
403
+ $rows = @sqlite_fetch_all($res, SQLITE_ASSOC);
404
+ $result = true;
405
+ foreach ($rows as $row) {
406
+ $id = $row['id'];
407
+ $matching = false;
408
+ foreach ($tags as $tag) {
409
+ $res = $this->_query("SELECT COUNT(*) AS nbr FROM tag WHERE name='$tag' AND id='$id'");
410
+ if (!$res) {
411
+ return false;
412
+ }
413
+ $nbr = (int) @sqlite_fetch_single($res);
414
+ if ($nbr > 0) {
415
+ $matching = true;
416
+ }
417
+ }
418
+ if (!$matching) {
419
+ $result = $result && $this->remove($id);
420
+ }
421
+ }
422
+ return $result;
423
+ }
424
+ return false;
425
+ }
426
+
427
+ }
lib/Zend/Cache/Backend/Test.php ADDED
@@ -0,0 +1,265 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Zend Framework
4
+ *
5
+ * LICENSE
6
+ *
7
+ * This source file is subject to the new BSD license that is bundled
8
+ * with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://framework.zend.com/license/new-bsd
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@zend.com so we can send you a copy immediately.
14
+ *
15
+ * @category Zend
16
+ * @package Zend_Cache
17
+ * @subpackage Zend_Cache_Backend
18
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
19
+ * @license http://framework.zend.com/license/new-bsd New BSD License
20
+ */
21
+
22
+
23
+ /**
24
+ * @see Zend_Cache_Backend_Interface
25
+ */
26
+ require_once 'Zend/Cache/Backend/Interface.php';
27
+
28
+
29
+ /**
30
+ * @package Zend_Cache
31
+ * @subpackage Zend_Cache_Backend
32
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
33
+ * @license http://framework.zend.com/license/new-bsd New BSD License
34
+ */
35
+ class Zend_Cache_Backend_Test implements Zend_Cache_Backend_Interface
36
+ {
37
+ /**
38
+ * Available options
39
+ *
40
+ * @var array available options
41
+ */
42
+ private $_options = array();
43
+
44
+ /**
45
+ * Frontend or Core directives
46
+ *
47
+ * @var array directives
48
+ */
49
+ private $_directives = array();
50
+
51
+ /**
52
+ * Array to log actions
53
+ *
54
+ * @var array $_log
55
+ */
56
+ private $_log = array();
57
+
58
+ /**
59
+ * Current index for log array
60
+ *
61
+ * @var int $_index
62
+ */
63
+ private $_index = 0;
64
+
65
+ /**
66
+ * Constructor
67
+ *
68
+ * @param array $options associative array of options
69
+ * @return void
70
+ */
71
+ public function __construct($options = array())
72
+ {
73
+ $this->_addLog('construct', array($options));
74
+ }
75
+
76
+ /**
77
+ * Set the frontend directives
78
+ *
79
+ * @param array $directives assoc of directives
80
+ * @return void
81
+ */
82
+ public function setDirectives($directives)
83
+ {
84
+ $this->_addLog('setDirectives', array($directives));
85
+ }
86
+
87
+ /**
88
+ * Test if a cache is available for the given id and (if yes) return it (false else)
89
+ *
90
+ * For this test backend only, if $id == 'false', then the method will return false
91
+ * if $id == 'serialized', the method will return a serialized array
92
+ * ('foo' else)
93
+ *
94
+ * @param string $id Cache id
95
+ * @param boolean $doNotTestCacheValidity If set to true, the cache validity won't be tested
96
+ * @return string Cached datas (or false)
97
+ */
98
+ public function load($id, $doNotTestCacheValidity = false)
99
+ {
100
+ $this->_addLog('get', array($id, $doNotTestCacheValidity));
101
+ if ($id=='false') {
102
+ return false;
103
+ }
104
+ if ($id=='serialized') {
105
+ return serialize(array('foo'));
106
+ }
107
+ if ($id=='serialized2') {
108
+ return serialize(array('contentType' => null, 'data' => 'foo'));
109
+ }
110
+ if (($id=='71769f39054f75894288e397df04e445') or ($id=='615d222619fb20b527168340cebd0578')) {
111
+ return serialize(array('foo', 'bar'));
112
+ }
113
+ if (($id=='8a02d218a5165c467e7a5747cc6bd4b6') or ($id=='648aca1366211d17cbf48e65dc570bee')) {
114
+ return serialize(array('foo', 'bar'));
115
+ }
116
+ return 'foo';
117
+ }
118
+
119
+ /**
120
+ * Test if a cache is available or not (for the given id)
121
+ *
122
+ * For this test backend only, if $id == 'false', then the method will return false
123
+ * (123456 else)
124
+ *
125
+ * @param string $id Cache id
126
+ * @return mixed|false false (a cache is not available) or "last modified" timestamp (int) of the available cache record
127
+ */
128
+ public function test($id)
129
+ {
130
+ $this->_addLog('test', array($id));
131
+ if ($id=='false') {
132
+ return false;
133
+ }
134
+ if (($id=='d8523b3ee441006261eeffa5c3d3a0a7') or ($id=='3c439c922209e2cb0b54d6deffccd75a')) {
135
+ return false;
136
+ }
137
+ if (($id=='40f649b94977c0a6e76902e2a0b43587') or ($id=='e83249ea22178277d5befc2c5e2e9ace')) {
138
+ return false;
139
+ }
140
+ return 123456;
141
+ }
142
+
143
+ /**
144
+ * Save some string datas into a cache record
145
+ *
146
+ * For this test backend only, if $id == 'false', then the method will return false
147
+ * (true else)
148
+ *
149
+ * @param string $data Datas to cache
150
+ * @param string $id Cache id
151
+ * @param array $tags Array of strings, the cache record will be tagged by each string entry
152
+ * @param int $specificLifetime If != false, set a specific lifetime for this cache record (null => infinite lifetime)
153
+ * @return boolean True if no problem
154
+ */
155
+ public function save($data, $id, $tags = array(), $specificLifetime = false)
156
+ {
157
+ $this->_addLog('save', array($data, $id, $tags));
158
+ if ($id=='false') {
159
+ return false;
160
+ }
161
+ return true;
162
+ }
163
+
164
+ /**
165
+ * Remove a cache record
166
+ *
167
+ * For this test backend only, if $id == 'false', then the method will return false
168
+ * (true else)
169
+ *
170
+ * @param string $id Cache id
171
+ * @return boolean True if no problem
172
+ */
173
+ public function remove($id)
174
+ {
175
+ $this->_addLog('remove', array($id));
176
+ if ($id=='false') {
177
+ return false;
178
+ }
179
+ return true;
180
+ }
181
+
182
+ /**
183
+ * Clean some cache records
184
+ *
185
+ * For this test backend only, if $mode == 'false', then the method will return false
186
+ * (true else)
187
+ *
188
+ * Available modes are :
189
+ * Zend_Cache::CLEANING_MODE_ALL (default) => remove all cache entries ($tags is not used)
190
+ * Zend_Cache::CLEANING_MODE_OLD => remove too old cache entries ($tags is not used)
191
+ * Zend_Cache::CLEANING_MODE_MATCHING_TAG => remove cache entries matching all given tags
192
+ * ($tags can be an array of strings or a single string)
193
+ * Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG => remove cache entries not {matching one of the given tags}
194
+ * ($tags can be an array of strings or a single string)
195
+ *
196
+ * @param string $mode Clean mode
197
+ * @param array $tags Array of tags
198
+ * @return boolean True if no problem
199
+ */
200
+ public function clean($mode = Zend_Cache::CLEANING_MODE_ALL, $tags = array())
201
+ {
202
+ $this->_addLog('clean', array($mode, $tags));
203
+ if ($mode=='false') {
204
+ return false;
205
+ }
206
+ return true;
207
+ }
208
+
209
+ /**
210
+ * Get the last log
211
+ *
212
+ * @return string The last log
213
+ */
214
+ public function getLastLog()
215
+ {
216
+ return $this->_log[$this->_index - 1];
217
+ }
218
+
219
+ /**
220
+ * Get the log index
221
+ *
222
+ * @return int Log index
223
+ */
224
+ public function getLogIndex()
225
+ {
226
+ return $this->_index;
227
+ }
228
+
229
+ /**
230
+ * Get the complete log array
231
+ *
232
+ * @return array Complete log array
233
+ */
234
+ public function getAllLogs()
235
+ {
236
+ return $this->_log;
237
+ }
238
+
239
+ /**
240
+ * Return true if the automatic cleaning is available for the backend
241
+ *
242
+ * @return boolean
243
+ */
244
+ public function isAutomaticCleaningAvailable()
245
+ {
246
+ return true;
247
+ }
248
+
249
+ /**
250
+ * Add an event to the log array
251
+ *
252
+ * @param string $methodName MethodName
253
+ * @param array $args Arguments
254
+ * @return void
255
+ */
256
+ private function _addLog($methodName, $args)
257
+ {
258
+ $this->_log[$this->_index] = array(
259
+ 'methodName' => $methodName,
260
+ 'args' => $args
261
+ );
262
+ $this->_index = $this->_index + 1;
263
+ }
264
+
265
+ }
lib/Zend/Cache/Backend/ZendPlatform.php ADDED
@@ -0,0 +1,285 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Zend Framework
4
+ *
5
+ * LICENSE
6
+ *
7
+ * This source file is subject to the new BSD license that is bundled
8
+ * with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://framework.zend.com/license/new-bsd
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@zend.com so we can send you a copy immediately.
14
+ *
15
+ * @category Zend
16
+ * @package Zend_Cache
17
+ * @subpackage Zend_Cache_Backend
18
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
19
+ * @license http://framework.zend.com/license/new-bsd New BSD License
20
+ */
21
+
22
+ /**
23
+ * @see Zend_Cache_Backend_Interface
24
+ */
25
+ require_once 'Zend/Cache/Backend.php';
26
+
27
+ /**
28
+ * @see Zend_Cache_Backend_Interface
29
+ */
30
+ require_once 'Zend/Cache/Backend/Interface.php';
31
+
32
+
33
+ /**
34
+ * Impementation of Zend Cache Backend using the Zend Platform (Output Content Caching)
35
+ *
36
+ * @package Zend_Cache
37
+ * @subpackage Zend_Cache_Backend
38
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
39
+ * @license http://framework.zend.com/license/new-bsd New BSD License
40
+ */
41
+ class Zend_Cache_Backend_ZendPlatform extends Zend_Cache_Backend implements Zend_Cache_Backend_Interface
42
+ {
43
+ /**
44
+ * internal ZP prefix
45
+ */
46
+ const TAGS_PREFIX = "internal_ZPtag:";
47
+
48
+ /**
49
+ * Constructor
50
+ * Validate that the Zend Platform is loaded and licensed
51
+ *
52
+ * @param array $options Associative array of options
53
+ * @throws Zend_Cache_Exception
54
+ * @return void
55
+ */
56
+ public function __construct($options = array())
57
+ {
58
+ if (!function_exists('accelerator_license_info')) {
59
+ Zend_Cache::throwException('The Zend Platform extension must be loaded for using this backend !');
60
+ }
61
+ if (!function_exists('accelerator_get_configuration')) {
62
+ $licenseInfo = accelerator_license_info();
63
+ Zend_Cache::throwException('The Zend Platform extension is not loaded correctly: '.$licenseInfo['failure_reason']);
64
+ }
65
+ $accConf = accelerator_get_configuration();
66
+ if (@!$accConf['output_cache_licensed']) {
67
+ Zend_Cache::throwException('The Zend Platform extension does not have the proper license to use content caching features');
68
+ }
69
+ if (@!$accConf['output_cache_enabled']) {
70
+ Zend_Cache::throwException('The Zend Platform content caching feature must be enabled for using this backend, set the \'zend_accelerator.output_cache_enabled\' directive to On !');
71
+ }
72
+ if (!is_writable($accConf['output_cache_dir'])) {
73
+ Zend_Cache::throwException('The cache copies directory \''. ini_get('zend_accelerator.output_cache_dir') .'\' must be writable !');
74
+ }
75
+ parent:: __construct($options);
76
+ }
77
+
78
+ /**
79
+ * Test if a cache is available for the given id and (if yes) return it (false else)
80
+ *
81
+ * @param string $id Cache id
82
+ * @param boolean $doNotTestCacheValidity If set to true, the cache validity won't be tested
83
+ * @return string Cached data (or false)
84
+ */
85
+ public function load($id, $doNotTestCacheValidity = false)
86
+ {
87
+ // doNotTestCacheValidity implemented by giving zero lifetime to the cache
88
+ if ($doNotTestCacheValidity) {
89
+ $lifetime = 0;
90
+ } else {
91
+ $lifetime = $this->_directives['lifetime'];
92
+ }
93
+ $res = output_cache_get($id, $lifetime);
94
+ if($res) {
95
+ return $res[0];
96
+ } else {
97
+ return false;
98
+ }
99
+ }
100
+
101
+
102
+ /**
103
+ * Test if a cache is available or not (for the given id)
104
+ *
105
+ * @param string $id Cache id
106
+ * @return mixed|false false (a cache is not available) or "last modified" timestamp (int) of the available cache record
107
+ */
108
+ public function test($id)
109
+ {
110
+ $result = output_cache_get($id, $this->_directives['lifetime']);
111
+ if ($result) {
112
+ return $result[1];
113
+ }
114
+ return false;
115
+ }
116
+
117
+ /**
118
+ * Save some string datas into a cache record
119
+ *
120
+ * Note : $data is always "string" (serialization is done by the
121
+ * core not by the backend)
122
+ *
123
+ * @param string $data Data to cache
124
+ * @param string $id Cache id
125
+ * @param array $tags Array of strings, the cache record will be tagged by each string entry
126
+ * @param int $specificLifetime If != false, set a specific lifetime for this cache record (null => infinite lifetime)
127
+ * @return boolean true if no problem
128
+ */
129
+ public function save($data, $id, $tags = array(), $specificLifetime = false)
130
+ {
131
+ if (!($specificLifetime === false)) {
132
+ $this->_log("Zend_Cache_Backend_ZendPlatform::save() : non false specifc lifetime is unsuported for this backend");
133
+ }
134
+
135
+ $lifetime = $this->_directives['lifetime'];
136
+ $result1 = output_cache_put($id, array($data, time()));
137
+ $result2 = (count($tags) == 0);
138
+
139
+ foreach ($tags as $tag) {
140
+ $tagid = self::TAGS_PREFIX.$tag;
141
+ $old_tags = output_cache_get($tagid, $lifetime);
142
+ if ($old_tags === false) {
143
+ $old_tags = array();
144
+ }
145
+ $old_tags[$id] = $id;
146
+ output_cache_remove_key($tagid);
147
+ $result2 = output_cache_put($tagid, $old_tags);
148
+ }
149
+
150
+ return $result1 && $result2;
151
+ }
152
+
153
+
154
+ /**
155
+ * Remove a cache record
156
+ *
157
+ * @param string $id Cache id
158
+ * @return boolean True if no problem
159
+ */
160
+ public function remove($id)
161
+ {
162
+ return output_cache_remove_key($id);
163
+ }
164
+
165
+
166
+ /**
167
+ * Clean some cache records
168
+ *
169
+ * Available modes are :
170
+ * Zend_Cache::CLEANING_MODE_ALL (default) => remove all cache entries ($tags is not used)
171
+ * Zend_Cache::CLEANING_MODE_OLD => remove too old cache entries ($tags is not used)
172
+ * This mode is not supported in this backend
173
+ * Zend_Cache::CLEANING_MODE_MATCHING_TAG => remove cache entries matching all given tags
174
+ * ($tags can be an array of strings or a single string)
175
+ * This mode is not supported in this backend
176
+ * Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG => remove cache entries not matching one of the given tags
177
+ * ($tags can be an array of strings or a single string)
178
+ * This mode is not supported in this backend
179
+ *
180
+ * @param string $mode Clean mode
181
+ * @param array $tags Array of tags
182
+ * @return boolean True if no problem
183
+ */
184
+ public function clean($mode = Zend_Cache::CLEANING_MODE_ALL, $tags = array())
185
+ {
186
+ if ($mode==Zend_Cache::CLEANING_MODE_MATCHING_TAG) {
187
+ $idlist = null;
188
+ foreach ($tags as $tag) {
189
+ $next_idlist = output_cache_get(self::TAGS_PREFIX.$tag, $this->_directives['lifetime']);
190
+ if ($idlist) {
191
+ $idlist = array_intersect_assoc($idlist, $next_idlist);
192
+ } else {
193
+ $idlist = $next_idlist;
194
+ }
195
+ if (count($idlist) == 0) {
196
+ // if ID list is already empty - we may skip checking other IDs
197
+ $idlist = null;
198
+ break;
199
+ }
200
+ }
201
+ if ($idlist) {
202
+ foreach ($idlist as $id) {
203
+ output_cache_remove_key($id);
204
+ }
205
+ }
206
+ return true;
207
+ }
208
+ if ($mode==Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG) {
209
+ $this->_log("Zend_Cache_Backend_ZendPlatform::clean() : CLEANING_MODE_NOT_MATCHING_TAG is not supported by the Zend Platform backend");
210
+ }
211
+ $cache_dir = ini_get('zend_accelerator.output_cache_dir');
212
+ if (!$cache_dir) {
213
+ return false;
214
+ }
215
+ $cache_dir .= '/.php_cache_api/';
216
+ return $this->_clean($cache_dir, $mode);
217
+ }
218
+
219
+ /**
220
+ * Clean a directory and recursivly go over it's subdirectories
221
+ *
222
+ * Remove all the cached files that need to be cleaned (according to mode and files mtime)
223
+ *
224
+ * @param string $dir Path of directory ot clean
225
+ * @param string $mode The same parameter as in Zend_Cache_Backend_ZendPlatform::clean()
226
+ * @return boolean True if ok
227
+ */
228
+ private function _clean($dir, $mode)
229
+ {
230
+ $d = @dir($dir);
231
+ if (!$d) {
232
+ return false;
233
+ }
234
+ $result = true;
235
+ while (false !== ($file = $d->read())) {
236
+ if ($file == '.' || $file == '..') {
237
+ continue;
238
+ }
239
+ $file = $d->path . $file;
240
+ if (is_dir($file)) {
241
+ $result = ($this->_clean($file .'/', $mode)) && ($result);
242
+ } else {
243
+ if ($mode == Zend_Cache::CLEANING_MODE_ALL) {
244
+ $result = ($this->_remove($file)) && ($result);
245
+ } else if ($mode == Zend_Cache::CLEANING_MODE_OLD) {
246
+ // Files older than lifetime get deleted from cache
247
+ if (!is_null($this->_directives['lifetime'])) {
248
+ if ((time() - @filemtime($file)) > $this->_directives['lifetime']) {
249
+ $result = ($this->_remove($file)) && ($result);
250
+ }
251
+ }
252
+ }
253
+ }
254
+ }
255
+ $d->close();
256
+ return $result;
257
+ }
258
+
259
+ /**
260
+ * Remove a file
261
+ *
262
+ * If we can't remove the file (because of locks or any problem), we will touch
263
+ * the file to invalidate it
264
+ *
265
+ * @param string $file Complete file path
266
+ * @return boolean True if ok
267
+ */
268
+ private function _remove($file)
269
+ {
270
+ if (!@unlink($file)) {
271
+ # If we can't remove the file (because of locks or any problem), we will touch
272
+ # the file to invalidate it
273
+ $this->_log("Zend_Cache_Backend_ZendPlatform::_remove() : we can't remove $file => we are going to try to invalidate it");
274
+ if (is_null($this->_directives['lifetime'])) {
275
+ return false;
276
+ }
277
+ if (!file_exists($file)) {
278
+ return false;
279
+ }
280
+ return @touch($file, time() - 2*abs($this->_directives['lifetime']));
281
+ }
282
+ return true;
283
+ }
284
+
285
+ }
lib/Zend/Cache/Core.php ADDED
@@ -0,0 +1,474 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Zend Framework
4
+ *
5
+ * LICENSE
6
+ *
7
+ * This source file is subject to the new BSD license that is bundled
8
+ * with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://framework.zend.com/license/new-bsd
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@zend.com so we can send you a copy immediately.
14
+ *
15
+ * @category Zend
16
+ * @package Zend_Cache
17
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
18
+ * @license http://framework.zend.com/license/new-bsd New BSD License
19
+ */
20
+
21
+
22
+ /**
23
+ * @package Zend_Cache
24
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
25
+ * @license http://framework.zend.com/license/new-bsd New BSD License
26
+ */
27
+ class Zend_Cache_Core
28
+ {
29
+ /**
30
+ * Backend Object
31
+ *
32
+ * @var object $_backend
33
+ */
34
+ private $_backend = null;
35
+
36
+ /**
37
+ * Available options
38
+ *
39
+ * ====> (boolean) write_control :
40
+ * - Enable / disable write control (the cache is read just after writing to detect corrupt entries)
41
+ * - Enable write control will lightly slow the cache writing but not the cache reading
42
+ * Write control can detect some corrupt cache files but maybe it's not a perfect control
43
+ *
44
+ * ====> (boolean) caching :
45
+ * - Enable / disable caching
46
+ * (can be very useful for the debug of cached scripts)
47
+ *
48
+ * =====> (string) cache_id_prefix :
49
+ * - prefix for cache ids (namespace)
50
+ *
51
+ * ====> (boolean) automatic_serialization :
52
+ * - Enable / disable automatic serialization
53
+ * - It can be used to save directly datas which aren't strings (but it's slower)
54
+ *
55
+ * ====> (int) automatic_cleaning_factor :
56
+ * - Disable / Tune the automatic cleaning process
57
+ * - The automatic cleaning process destroy too old (for the given life time)
58
+ * cache files when a new cache file is written :
59
+ * 0 => no automatic cache cleaning
60
+ * 1 => systematic cache cleaning
61
+ * x (integer) > 1 => automatic cleaning randomly 1 times on x cache write
62
+ *
63
+ * ====> (int) lifetime :
64
+ * - Cache lifetime (in seconds)
65
+ * - If null, the cache is valid forever.
66
+ *
67
+ * ====> (boolean) logging :
68
+ * - If set to true, logging is activated (but the system is slower)
69
+ *
70
+ * ====> (boolean) ignore_user_abort
71
+ * - If set to true, the core will set the ignore_user_abort PHP flag inside the
72
+ * save() method to avoid cache corruptions in some cases (default false)
73
+ *
74
+ * @var array $_options available options
75
+ */
76
+ protected $_options = array(
77
+ 'write_control' => true,
78
+ 'caching' => true,
79
+ 'cache_id_prefix' => null,
80
+ 'automatic_serialization' => false,
81
+ 'automatic_cleaning_factor' => 10,
82
+ 'lifetime' => 3600,
83
+ 'logging' => false,
84
+ 'logger' => null,
85
+ 'ignore_user_abort' => false
86
+ );
87
+
88
+ /**
89
+ * Array of options which have to be transfered to backend
90
+ *
91
+ * @var array $_directivesList
92
+ */
93
+ protected static $_directivesList = array('lifetime', 'logging', 'logger');
94
+
95
+ /**
96
+ * Not used for the core, just a sort a hint to get a common setOption() method (for the core and for frontends)
97
+ *
98
+ * @var array $_specificOptions
99
+ */
100
+ protected $_specificOptions = array();
101
+
102
+ /**
103
+ * Last used cache id
104
+ *
105
+ * @var string $_lastId
106
+ */
107
+ private $_lastId = null;
108
+
109
+ /**
110
+ * Constructor
111
+ *
112
+ * @param array $options Associative array of options
113
+ * @throws Zend_Cache_Exception
114
+ * @return void
115
+ */
116
+ public function __construct($options = array())
117
+ {
118
+ if (!is_array($options)) {
119
+ Zend_Cache::throwException('Options parameter must be an array');
120
+ }
121
+ while (list($name, $value) = each($options)) {
122
+ $this->setOption($name, $value);
123
+ }
124
+ $this->_loggerSanity();
125
+ }
126
+
127
+ /**
128
+ * Set the backend
129
+ *
130
+ * @param object $backendObject
131
+ * @throws Zend_Cache_Exception
132
+ * @return void
133
+ */
134
+ public function setBackend($backendObject)
135
+ {
136
+ if (!is_object($backendObject)) {
137
+ Zend_Cache::throwException('Incorrect backend object !');
138
+ }
139
+ $this->_backend= $backendObject;
140
+ // some options (listed in $_directivesList) have to be given
141
+ // to the backend too (even if they are not "backend specific")
142
+ $directives = array();
143
+ foreach (Zend_Cache_Core::$_directivesList as $directive) {
144
+ $directives[$directive] = $this->_options[$directive];
145
+ }
146
+ $this->_backend->setDirectives($directives);
147
+ }
148
+
149
+ /**
150
+ * Public frontend to set an option
151
+ *
152
+ * There is an additional validation (relatively to the protected _setOption method)
153
+ *
154
+ * @param string $name Name of the option
155
+ * @param mixed $value Value of the option
156
+ * @throws Zend_Cache_Exception
157
+ * @return void
158
+ */
159
+ public function setOption($name, $value)
160
+ {
161
+ if (is_string($name)) {
162
+ $name = strtolower($name);
163
+ if (array_key_exists($name, $this->_options)) {
164
+ // This is a Core option
165
+ $this->_setOption($name, $value);
166
+ return;
167
+ }
168
+ if (array_key_exists($name, $this->_specificOptions)) {
169
+ // This a specic option of this frontend
170
+ $this->_specificOptions[$name] = $value;
171
+ return;
172
+ }
173
+ }
174
+ Zend_Cache::throwException("Incorrect option name : $name");
175
+ }
176
+
177
+ /**
178
+ * Set an option
179
+ *
180
+ * @param string $name Name of the option
181
+ * @param mixed $value Value of the option
182
+ * @throws Zend_Cache_Exception
183
+ * @return void
184
+ */
185
+ private function _setOption($name, $value)
186
+ {
187
+ if (!is_string($name) || !array_key_exists($name, $this->_options)) {
188
+ Zend_Cache::throwException("Incorrect option name : $name");
189
+ }
190
+ $this->_options[$name] = $value;
191
+ }
192
+
193
+ /**
194
+ * Force a new lifetime
195
+ *
196
+ * The new value is set for the core/frontend but for the backend too (directive)
197
+ *
198
+ * @param int $newLifetime New lifetime (in seconds)
199
+ * @return void
200
+ */
201
+ public function setLifetime($newLifetime)
202
+ {
203
+ $this->_options['lifetime'] = $newLifetime;
204
+ $this->_backend->setDirectives(array(
205
+ 'lifetime' => $newLifetime
206
+ ));
207
+ }
208
+
209
+ /**
210
+ * Test if a cache is available for the given id and (if yes) return it (false else)
211
+ *
212
+ * @param string $id Cache id
213
+ * @param boolean $doNotTestCacheValidity If set to true, the cache validity won't be tested
214
+ * @param boolean $doNotUnserialize Do not serialize (even if automatic_serialization is true) => for internal use
215
+ * @return mixed|false Cached datas
216
+ */
217
+ public function load($id, $doNotTestCacheValidity = false, $doNotUnserialize = false)
218
+ {
219
+ if (!$this->_options['caching']) {
220
+ return false;
221
+ }
222
+ $id = $this->_id($id); // cache id may need prefix
223
+ $this->_lastId = $id;
224
+ self::_validateIdOrTag($id);
225
+ $data = $this->_backend->load($id, $doNotTestCacheValidity);
226
+ if ($data===false) {
227
+ // no cache available
228
+ return false;
229
+ }
230
+ if ((!$doNotUnserialize) && $this->_options['automatic_serialization']) {
231
+ // we need to unserialize before sending the result
232
+ return unserialize($data);
233
+ }
234
+ return $data;
235
+ }
236
+
237
+ /**
238
+ * Test if a cache is available for the given id
239
+ *
240
+ * @param string $id Cache id
241
+ * @return boolean True is a cache is available, false else
242
+ */
243
+ public function test($id)
244
+ {
245
+ if (!$this->_options['caching']) {
246
+ return false;
247
+ }
248
+ $id = $this->_id($id); // cache id may need prefix
249
+ self::_validateIdOrTag($id);
250
+ $this->_lastId = $id;
251
+ return $this->_backend->test($id);
252
+ }
253
+
254
+ /**
255
+ * Save some data in a cache
256
+ *
257
+ * @param mixed $data Data to put in cache (can be another type than string if automatic_serialization is on)
258
+ * @param cache $id Cache id (if not set, the last cache id will be used)
259
+ * @param array $tags Cache tags
260
+ * @param int $specificLifetime If != false, set a specific lifetime for this cache record (null => infinite lifetime)
261
+ * @throws Zend_Cache_Exception
262
+ * @return boolean True if no problem
263
+ */
264
+ public function save($data, $id = null, $tags = array(), $specificLifetime = false)
265
+ {
266
+ if (!$this->_options['caching']) {
267
+ return true;
268
+ }
269
+ if (is_null($id)) {
270
+ $id = $this->_lastId;
271
+ } else {
272
+ $id = $this->_id($id);
273
+ }
274
+ self::_validateIdOrTag($id);
275
+ self::_validateTagsArray($tags);
276
+ if ($this->_options['automatic_serialization']) {
277
+ // we need to serialize datas before storing them
278
+ $data = serialize($data);
279
+ } else {
280
+ if (!is_string($data)) {
281
+ Zend_Cache::throwException("Datas must be string or set automatic_serialization = true");
282
+ }
283
+ }
284
+ // automatic cleaning
285
+ if ($this->_options['automatic_cleaning_factor'] > 0) {
286
+ $rand = rand(1, $this->_options['automatic_cleaning_factor']);
287
+ if ($rand==1) {
288
+ if ($this->_backend->isAutomaticCleaningAvailable()) {
289
+ $this->clean(Zend_Cache::CLEANING_MODE_OLD);
290
+ } else {
291
+ $this->_log('Zend_Cache_Core::save() / automatic cleaning is not available with this backend');
292
+ }
293
+ }
294
+ }
295
+ if ($this->_options['ignore_user_abort']) {
296
+ $abort = ignore_user_abort(true);
297
+ }
298
+ $result = $this->_backend->save($data, $id, $tags, $specificLifetime);
299
+ if ($this->_options['ignore_user_abort']) {
300
+ ignore_user_abort($abort);
301
+ }
302
+ if (!$result) {
303
+ // maybe the cache is corrupted, so we remove it !
304
+ if ($this->_options['logging']) {
305
+ $this->_log("Zend_Cache_Core::save() : impossible to save cache (id=$id)");
306
+ }
307
+ $this->remove($id);
308
+ return false;
309
+ }
310
+ if ($this->_options['write_control']) {
311
+ $data2 = $this->_backend->load($id, true);
312
+ if ($data!=$data2) {
313
+ $this->_log('Zend_Cache_Core::save() / write_control : written and read data do not match');
314
+ $this->remove($id);
315
+ return false;
316
+ }
317
+ }
318
+ return true;
319
+ }
320
+
321
+ /**
322
+ * Remove a cache
323
+ *
324
+ * @param string $id Cache id to remove
325
+ * @return boolean True if ok
326
+ */
327
+ public function remove($id)
328
+ {
329
+ if (!$this->_options['caching']) {
330
+ return true;
331
+ }
332
+ $id = $this->_id($id); // cache id may need prefix
333
+ self::_validateIdOrTag($id);
334
+ return $this->_backend->remove($id);
335
+ }
336
+
337
+ /**
338
+ * Clean cache entries
339
+ *
340
+ * Available modes are :
341
+ * 'all' (default) => remove all cache entries ($tags is not used)
342
+ * 'old' => remove too old cache entries ($tags is not used)
343
+ * 'matchingTag' => remove cache entries matching all given tags
344
+ * ($tags can be an array of strings or a single string)
345
+ * 'notMatchingTag' => remove cache entries not matching one of the given tags
346
+ * ($tags can be an array of strings or a single string)
347
+ *
348
+ * @param string $mode
349
+ * @param array|string $tags
350
+ * @throws Zend_Cache_Exception
351
+ * @return boolean True if ok
352
+ */
353
+ public function clean($mode = 'all', $tags = array())
354
+ {
355
+ if (!$this->_options['caching']) {
356
+ return true;
357
+ }
358
+ if (!in_array($mode, array(Zend_Cache::CLEANING_MODE_ALL, Zend_Cache::CLEANING_MODE_OLD, Zend_Cache::CLEANING_MODE_MATCHING_TAG, Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG))) {
359
+ Zend_Cache::throwException('Invalid cleaning mode');
360
+ }
361
+ self::_validateTagsArray($tags);
362
+ return $this->_backend->clean($mode, $tags);
363
+ }
364
+
365
+ /**
366
+ * Validate a cache id or a tag (security, reliable filenames, reserved prefixes...)
367
+ *
368
+ * Throw an exception if a problem is found
369
+ *
370
+ * @param string $string Cache id or tag
371
+ * @throws Zend_Cache_Exception
372
+ * @return void
373
+ */
374
+ private static function _validateIdOrTag($string)
375
+ {
376
+ if (!is_string($string)) {
377
+ Zend_Cache::throwException('Invalid id or tag : must be a string');
378
+ }
379
+ if (substr($string, 0, 9) == 'internal-') {
380
+ Zend_Cache::throwException('"internal-*" ids or tags are reserved');
381
+ }
382
+ if (!preg_match('~^[\w]+$~D', $string)) {
383
+ Zend_Cache::throwException("Invalid id or tag '$string' : must use only [a-zA-Z0-9_]");
384
+ }
385
+ }
386
+
387
+ /**
388
+ * Validate a tags array (security, reliable filenames, reserved prefixes...)
389
+ *
390
+ * Throw an exception if a problem is found
391
+ *
392
+ * @param array $tags Array of tags
393
+ * @throws Zend_Cache_Exception
394
+ * @return void
395
+ */
396
+ private static function _validateTagsArray($tags)
397
+ {
398
+ if (!is_array($tags)) {
399
+ Zend_Cache::throwException('Invalid tags array : must be an array');
400
+ }
401
+ foreach($tags as $tag) {
402
+ self::_validateIdOrTag($tag);
403
+ }
404
+ reset($tags);
405
+ }
406
+
407
+ /**
408
+ * Make sure if we enable logging that the Zend_Log class
409
+ * is available.
410
+ * Create a default log object if none is set.
411
+ *
412
+ * @throws Zend_Cache_Exception
413
+ * @return void
414
+ */
415
+ protected function _loggerSanity()
416
+ {
417
+ if (!isset($this->_options['logging']) || !$this->_options['logging']) {
418
+ return;
419
+ }
420
+ try {
421
+ /**
422
+ * @see Zend_Loader
423
+ * @see Zend_Log
424
+ */
425
+ require_once 'Zend/Loader.php';
426
+ Zend_Loader::loadClass('Zend_Log');
427
+ } catch (Zend_Exception $e) {
428
+ Zend_Cache::throwException('Logging feature is enabled but the Zend_Log class is not available');
429
+ }
430
+ if (isset($this->_options['logger']) && $this->_options['logger'] instanceof Zend_Log) {
431
+ return;
432
+ }
433
+ // Create a default logger to the standard output stream
434
+ Zend_Loader::loadClass('Zend_Log_Writer_Stream');
435
+ $logger = new Zend_Log(new Zend_Log_Writer_Stream('php://output'));
436
+ $this->_options['logger'] = $logger;
437
+ }
438
+
439
+ /**
440
+ * Log a message at the WARN (4) priority.
441
+ *
442
+ * @param string $message
443
+ * @throws Zend_Cache_Exception
444
+ * @return void
445
+ */
446
+ protected function _log($message, $priority = 4)
447
+ {
448
+ if (!$this->_options['logging']) {
449
+ return;
450
+ }
451
+ if (!(isset($this->_options['logger']) || $this->_options['logger'] instanceof Zend_Log)) {
452
+ Zend_Cache::throwException('Logging is enabled but logger is not set');
453
+ }
454
+ $logger = $this->_options['logger'];
455
+ $logger->log($message, $priority);
456
+ }
457
+
458
+ /**
459
+ * Make and return a cache id
460
+ *
461
+ * Checks 'cache_id_prefix' and returns new id with prefix or simply the id if null
462
+ *
463
+ * @param string $id Cache id
464
+ * @return string Cache id (with or without prefix)
465
+ */
466
+ private function _id($id)
467
+ {
468
+ if (!is_null($id) && isset($this->_options['cache_id_prefix'])) {
469
+ return $this->_options['cache_id_prefix'] . $id; // return with prefix
470
+ }
471
+ return $id; // no prefix, just return the $id passed
472
+ }
473
+
474
+ }
lib/Zend/Cache/Exception.php ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Zend Framework
4
+ *
5
+ * LICENSE
6
+ *
7
+ * This source file is subject to the new BSD license that is bundled
8
+ * with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://framework.zend.com/license/new-bsd
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@zend.com so we can send you a copy immediately.
14
+ *
15
+ * @category Zend
16
+ * @package Zend_Cache
17
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
18
+ * @license http://framework.zend.com/license/new-bsd New BSD License
19
+ */
20
+
21
+ /**
22
+ * @see Zend_Exception
23
+ */
24
+ require_once 'Zend/Exception.php';
25
+
26
+ /**
27
+ * @package Zend_Cache
28
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
29
+ * @license http://framework.zend.com/license/new-bsd New BSD License
30
+ */
31
+ class Zend_Cache_Exception extends Zend_Exception {}
lib/Zend/Cache/Frontend/Class.php ADDED
@@ -0,0 +1,193 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Zend Framework
4
+ *
5
+ * LICENSE
6
+ *
7
+ * This source file is subject to the new BSD license that is bundled
8
+ * with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://framework.zend.com/license/new-bsd
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@zend.com so we can send you a copy immediately.
14
+ *
15
+ * @category Zend
16
+ * @package Zend_Cache
17
+ * @subpackage Zend_Cache_Frontend
18
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
19
+ * @license http://framework.zend.com/license/new-bsd New BSD License
20
+ */
21
+
22
+ /**
23
+ * @see Zend_Cache_Core
24
+ */
25
+ require_once 'Zend/Cache/Core.php';
26
+
27
+
28
+ /**
29
+ * @package Zend_Cache
30
+ * @subpackage Zend_Cache_Frontend
31
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
32
+ * @license http://framework.zend.com/license/new-bsd New BSD License
33
+ */
34
+ class Zend_Cache_Frontend_Class extends Zend_Cache_Core
35
+ {
36
+ /**
37
+ * Available options
38
+ *
39
+ * ====> (mixed) cached_entity :
40
+ * - if set to a class name, we will cache an abstract class and will use only static calls
41
+ * - if set to an object, we will cache this object methods
42
+ *
43
+ * ====> (boolean) cache_by_default :
44
+ * - if true, method calls will be cached by default
45
+ *
46
+ * ====> (array) cached_methods :
47
+ * - an array of method names which will be cached (even if cache_by_default = false)
48
+ *
49
+ * ====> (array) non_cached_methods :
50
+ * - an array of method names which won't be cached (even if cache_by_default = true)
51
+ *
52
+ * @var array available options
53
+ */
54
+ protected $_specificOptions = array(
55
+ 'cached_entity' => null,
56
+ 'cache_by_default' => true,
57
+ 'cached_methods' => array(),
58
+ 'non_cached_methods' => array()
59
+ );
60
+
61
+ /**
62
+ * Tags array
63
+ *
64
+ * @var array
65
+ */
66
+ private $_tags = array();
67
+
68
+ /**
69
+ * SpecificLifetime value
70
+ *
71
+ * false => no specific life time
72
+ *
73
+ * @var int
74
+ */
75
+ private $_specificLifetime = false;
76
+
77
+ /**
78
+ * The cached object or the name of the cached abstract class
79
+ *
80
+ * @var mixed
81
+ */
82
+ private $_cachedEntity = null;
83
+
84
+ /**
85
+ * The class name of the cached object or cached abstract class
86
+ *
87
+ * Used to differentiate between different classes with the same method calls.
88
+ *
89
+ * @var string
90
+ */
91
+ private $_cachedEntityLabel = '';
92
+
93
+ /**
94
+ * Constructor
95
+ *
96
+ * @param array $options Associative array of options
97
+ * @throws Zend_Cache_Exception
98
+ * @return void
99
+ */
100
+ public function __construct($options = array())
101
+ {
102
+ while (list($name, $value) = each($options)) {
103
+ $this->setOption($name, $value);
104
+ }
105
+ if (is_null($this->_specificOptions['cached_entity'])) {
106
+ Zend_Cache::throwException('cached_entity must be set !');
107
+ } else {
108
+ if (!is_string($this->_specificOptions['cached_entity']) && !is_object($this->_specificOptions['cached_entity'])) {
109
+ Zend_Cache::throwException('cached_entity must be an object or a class name');
110
+ }
111
+ }
112
+ $this->_cachedEntity = $this->_specificOptions['cached_entity'];
113
+ if(is_string($this->_cachedEntity)){
114
+ $this->_cachedEntityLabel = $this->_cachedEntity;
115
+ } else {
116
+ $ro = new ReflectionObject($this->_cachedEntity);
117
+ $this->_cachedEntityLabel = $ro->getName();
118
+ }
119
+ $this->setOption('automatic_serialization', true);
120
+ }
121
+
122
+ /**
123
+ * Set a specific life time
124
+ *
125
+ * @param int $specificLifetime
126
+ * @return void
127
+ */
128
+ public function setSpecificLifetime($specificLifetime = false)
129
+ {
130
+ $this->_specificLifetime = $specificLifetime;
131
+ }
132
+
133
+ /**
134
+ * Set the cache array
135
+ *
136
+ * @param array $tags
137
+ * @return void
138
+ */
139
+ public function setTagsArray($tags = array())
140
+ {
141
+ $this->_tags = $tags;
142
+ }
143
+
144
+ /**
145
+ * Main method : call the specified method or get the result from cache
146
+ *
147
+ * @param string $name Method name
148
+ * @param array $parameters Method parameters
149
+ * @return mixed Result
150
+ */
151
+ public function __call($name, $parameters)
152
+ {
153
+ $cacheBool1 = $this->_specificOptions['cache_by_default'];
154
+ $cacheBool2 = in_array($name, $this->_specificOptions['cached_methods']);
155
+ $cacheBool3 = in_array($name, $this->_specificOptions['non_cached_methods']);
156
+ $cache = (($cacheBool1 || $cacheBool2) && (!$cacheBool3));
157
+ if (!$cache) {
158
+ // We do not have not cache
159
+ return call_user_func_array(array($this->_cachedEntity, $name), $parameters);
160
+ }
161
+ $id = $this->_makeId($name, $parameters);
162
+ if ($this->test($id)) {
163
+ // A cache is available
164
+ $result = $this->load($id);
165
+ $output = $result[0];
166
+ $return = $result[1];
167
+ } else {
168
+ // A cache is not available
169
+ ob_start();
170
+ ob_implicit_flush(false);
171
+ $return = call_user_func_array(array($this->_cachedEntity, $name), $parameters);
172
+ $output = ob_get_contents();
173
+ ob_end_clean();
174
+ $data = array($output, $return);
175
+ $this->save($data, $id, $this->_tags, $this->_specificLifetime);
176
+ }
177
+ echo $output;
178
+ return $return;
179
+ }
180
+
181
+ /**
182
+ * Make a cache id from the method name and parameters
183
+ *
184
+ * @param string $name Method name
185
+ * @param array $parameters Method parameters
186
+ * @return string Cache id
187
+ */
188
+ private function _makeId($name, $parameters)
189
+ {
190
+ return md5($this->_cachedEntityLabel . '__' . $name . '__' . serialize($parameters));
191
+ }
192
+
193
+ }
lib/Zend/Cache/Frontend/File.php ADDED
@@ -0,0 +1,115 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Zend Framework
4
+ *
5
+ * LICENSE
6
+ *
7
+ * This source file is subject to the new BSD license that is bundled
8
+ * with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://framework.zend.com/license/new-bsd
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@zend.com so we can send you a copy immediately.
14
+ *
15
+ * @category Zend
16
+ * @package Zend_Cache
17
+ * @subpackage Zend_Cache_Frontend
18
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
19
+ * @license http://framework.zend.com/license/new-bsd New BSD License
20
+ */
21
+
22
+
23
+ /**
24
+ * @see Zend_Cache_Core
25
+ */
26
+ require_once 'Zend/Cache/Core.php';
27
+
28
+
29
+ /**
30
+ * @package Zend_Cache
31
+ * @subpackage Zend_Cache_Frontend
32
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
33
+ * @license http://framework.zend.com/license/new-bsd New BSD License
34
+ */
35
+ class Zend_Cache_Frontend_File extends Zend_Cache_Core
36
+ {
37
+ /**
38
+ * Available options
39
+ *
40
+ * ====> (string) master_file :
41
+ * - the complete path and name of the master file
42
+ * - this option has to be set !
43
+ *
44
+ * @var array available options
45
+ */
46
+ protected $_specificOptions = array(
47
+ 'master_file' => ''
48
+ );
49
+
50
+ /**
51
+ * Master file mtime
52
+ *
53
+ * @var int
54
+ */
55
+ private $_masterFile_mtime = null;
56
+
57
+ /**
58
+ * Constructor
59
+ *
60
+ * @param array $options Associative array of options
61
+ * @throws Zend_Cache_Exception
62
+ * @return void
63
+ */
64
+ public function __construct($options = array())
65
+ {
66
+ while (list($name, $value) = each($options)) {
67
+ $this->setOption($name, $value);
68
+ }
69
+ if (!isset($this->_specificOptions['master_file'])) {
70
+ Zend_Cache::throwException('master_file option must be set');
71
+ }
72
+ clearstatcache();
73
+ if (!($this->_masterFile_mtime = @filemtime($this->_specificOptions['master_file']))) {
74
+ Zend_Cache::throwException('Unable to read master_file : '.$this->_specificOptions['master_file']);
75
+ }
76
+ }
77
+
78
+ /**
79
+ * Test if a cache is available for the given id and (if yes) return it (false else)
80
+ *
81
+ * @param string $id Cache id
82
+ * @param boolean $doNotTestCacheValidity If set to true, the cache validity won't be tested
83
+ * @param boolean $doNotUnserialize Do not serialize (even if automatic_serialization is true) => for internal use
84
+ * @return mixed|false Cached datas
85
+ */
86
+ public function load($id, $doNotTestCacheValidity = false, $doNotUnserialize = false)
87
+ {
88
+ if (!$doNotTestCacheValidity) {
89
+ if ($this->test($id)) {
90
+ return parent::load($id, true, $doNotUnserialize);
91
+ }
92
+ return false;
93
+ }
94
+ return parent::load($id, true, $doNotUnserialize);
95
+ }
96
+
97
+ /**
98
+ * Test if a cache is available for the given id
99
+ *
100
+ * @param string $id Cache id
101
+ * @return boolean True is a cache is available, false else
102
+ */
103
+ public function test($id)
104
+ {
105
+ $lastModified = parent::test($id);
106
+ if ($lastModified) {
107
+ if ($lastModified > $this->_masterFile_mtime) {
108
+ return $lastModified;
109
+ }
110
+ }
111
+ return false;
112
+ }
113
+
114
+ }
115
+
lib/Zend/Cache/Frontend/Function.php ADDED
@@ -0,0 +1,129 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Zend Framework
4
+ *
5
+ * LICENSE
6
+ *
7
+ * This source file is subject to the new BSD license that is bundled
8
+ * with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://framework.zend.com/license/new-bsd
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@zend.com so we can send you a copy immediately.
14
+ *
15
+ * @category Zend
16
+ * @package Zend_Cache
17
+ * @subpackage Zend_Cache_Frontend
18
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
19
+ * @license http://framework.zend.com/license/new-bsd New BSD License
20
+ */
21
+
22
+
23
+ /**
24
+ * @see Zend_Cache_Core
25
+ */
26
+ require_once 'Zend/Cache/Core.php';
27
+
28
+
29
+ /**
30
+ * @package Zend_Cache
31
+ * @subpackage Zend_Cache_Frontend
32
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
33
+ * @license http://framework.zend.com/license/new-bsd New BSD License
34
+ */
35
+ class Zend_Cache_Frontend_Function extends Zend_Cache_Core
36
+ {
37
+ /**
38
+ * This frontend specific options
39
+ *
40
+ * ====> (boolean) cache_by_default :
41
+ * - if true, function calls will be cached by default
42
+ *
43
+ * ====> (array) cached_functions :
44
+ * - an array of function names which will be cached (even if cache_by_default = false)
45
+ *
46
+ * ====> (array) non_cached_functions :
47
+ * - an array of function names which won't be cached (even if cache_by_default = true)
48
+ *
49
+ * @var array options
50
+ */
51
+ protected $_specificOptions = array(
52
+ 'cache_by_default' => true,
53
+ 'cached_functions' => array(),
54
+ 'non_cached_functions' => array()
55
+ );
56
+
57
+ /**
58
+ * Constructor
59
+ *
60
+ * @param array $options Associative array of options
61
+ * @return void
62
+ */
63
+ public function __construct($options = array())
64
+ {
65
+ while (list($name, $value) = each($options)) {
66
+ $this->setOption($name, $value);
67
+ }
68
+ $this->setOption('automatic_serialization', true);
69
+ }
70
+
71
+ /**
72
+ * Main method : call the specified function or get the result from cache
73
+ *
74
+ * @param string $name Function name
75
+ * @param array $parameters Function parameters
76
+ * @param array $tags Cache tags
77
+ * @param int $specificLifetime If != false, set a specific lifetime for this cache record (null => infinite lifetime)
78
+ * @return mixed Result
79
+ */
80
+ public function call($name, $parameters = array(), $tags = array(), $specificLifetime = false)
81
+ {
82
+ $cacheBool1 = $this->_specificOptions['cache_by_default'];
83
+ $cacheBool2 = in_array($name, $this->_specificOptions['cached_functions']);
84
+ $cacheBool3 = in_array($name, $this->_specificOptions['non_cached_functions']);
85
+ $cache = (($cacheBool1 || $cacheBool2) && (!$cacheBool3));
86
+ if (!$cache) {
87
+ // We do not have not cache
88
+ return call_user_func_array($name, $parameters);
89
+ }
90
+ $id = $this->_makeId($name, $parameters);
91
+ if ($this->test($id)) {
92
+ // A cache is available
93
+ $result = $this->load($id);
94
+ $output = $result[0];
95
+ $return = $result[1];
96
+ } else {
97
+ // A cache is not available
98
+ ob_start();
99
+ ob_implicit_flush(false);
100
+ $return = call_user_func_array($name, $parameters);
101
+ $output = ob_get_contents();
102
+ ob_end_clean();
103
+ $data = array($output, $return);
104
+ $this->save($data, $id, $tags, $specificLifetime);
105
+ }
106
+ echo $output;
107
+ return $return;
108
+ }
109
+
110
+ /**
111
+ * Make a cache id from the function name and parameters
112
+ *
113
+ * @param string $name Function name
114
+ * @param array $parameters Function parameters
115
+ * @throws Zend_Cache_Exception
116
+ * @return string Cache id
117
+ */
118
+ private function _makeId($name, $parameters)
119
+ {
120
+ if (!is_string($name)) {
121
+ Zend_Cache::throwException('Incorrect function name');
122
+ }
123
+ if (!is_array($parameters)) {
124
+ Zend_Cache::throwException('parameters argument must be an array');
125
+ }
126
+ return md5($name . serialize($parameters));
127
+ }
128
+
129
+ }
lib/Zend/Cache/Frontend/Output.php ADDED
@@ -0,0 +1,82 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Zend Framework
4
+ *
5
+ * LICENSE
6
+ *
7
+ * This source file is subject to the new BSD license that is bundled
8
+ * with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://framework.zend.com/license/new-bsd
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@zend.com so we can send you a copy immediately.
14
+ *
15
+ * @category Zend
16
+ * @package Zend_Cache
17
+ * @subpackage Zend_Cache_Frontend
18
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
19
+ * @license http://framework.zend.com/license/new-bsd New BSD License
20
+ */
21
+
22
+
23
+ /**
24
+ * @see Zend_Cache_Core
25
+ */
26
+ require_once 'Zend/Cache/Core.php';
27
+
28
+
29
+ /**
30
+ * @package Zend_Cache
31
+ * @subpackage Zend_Cache_Frontend
32
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
33
+ * @license http://framework.zend.com/license/new-bsd New BSD License
34
+ */
35
+ class Zend_Cache_Frontend_Output extends Zend_Cache_Core
36
+ {
37
+ /**
38
+ * Constructor
39
+ *
40
+ * @param array $options Associative array of options
41
+ * @return void
42
+ */
43
+ public function __construct($options = array())
44
+ {
45
+ parent::__construct($options);
46
+ }
47
+
48
+ /**
49
+ * Start the cache
50
+ *
51
+ * @param string $id Cache id
52
+ * @param boolean $doNotTestCacheValidity If set to true, the cache validity won't be tested
53
+ * @return boolean True if the cache is hit (false else)
54
+ */
55
+ public function start($id, $doNotTestCacheValidity = false)
56
+ {
57
+ $data = $this->load($id, $doNotTestCacheValidity);
58
+ if ($data !== false) {
59
+ echo($data);
60
+ return true;
61
+ }
62
+ ob_start();
63
+ ob_implicit_flush(false);
64
+ return false;
65
+ }
66
+
67
+ /**
68
+ * Stop the cache
69
+ *
70
+ * @param array $tags Tags array
71
+ * @param int $specificLifetime If != false, set a specific lifetime for this cache record (null => infinite lifetime)
72
+ * @return void
73
+ */
74
+ public function end($tags = array(), $specificLifetime = false)
75
+ {
76
+ $data = ob_get_contents();
77
+ ob_end_clean();
78
+ $this->save($data, null, $tags, $specificLifetime);
79
+ echo($data);
80
+ }
81
+
82
+ }
lib/Zend/Cache/Frontend/Page.php ADDED
@@ -0,0 +1,330 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Zend Framework
4
+ *
5
+ * LICENSE
6
+ *
7
+ * This source file is subject to the new BSD license that is bundled
8
+ * with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://framework.zend.com/license/new-bsd
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@zend.com so we can send you a copy immediately.
14
+ *
15
+ * @category Zend
16
+ * @package Zend_Cache
17
+ * @subpackage Zend_Cache_Frontend
18
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
19
+ * @license http://framework.zend.com/license/new-bsd New BSD License
20
+ */
21
+
22
+
23
+ /**
24
+ * @see Zend_Cache_Core
25
+ */
26
+ require_once 'Zend/Cache/Core.php';
27
+
28
+
29
+ /**
30
+ * @package Zend_Cache
31
+ * @subpackage Zend_Cache_Frontend
32
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
33
+ * @license http://framework.zend.com/license/new-bsd New BSD License
34
+ */
35
+ class Zend_Cache_Frontend_Page extends Zend_Cache_Core
36
+ {
37
+ /**
38
+ * This frontend specific options
39
+ *
40
+ * ====> (boolean) http_conditional :
41
+ * - if true, http conditional mode is on
42
+ * WARNING : http_conditional OPTION IS NOT IMPLEMENTED FOR THE MOMENT (TODO)
43
+ *
44
+ * ====> (boolean) debug_header :
45
+ * - if true, a debug text is added before each cached pages
46
+ *
47
+ * ====> (boolean) content_type_memorization :
48
+ * - if the Content-Type header is sent after the cache was started, the
49
+ * corresponding value can be memorized and replayed when the cache is hit
50
+ * (if false (default), the frontend doesn't take care of Content-Type header)
51
+ *
52
+ * ====> (array) default_options :
53
+ * - an associative array of default options :
54
+ * - (boolean) cache : cache is on by default if true
55
+ * - (boolean) cacheWithXXXVariables (XXXX = 'Get', 'Post', 'Session', 'Files' or 'Cookie') :
56
+ * if true, cache is still on even if there are some variables in this superglobal array
57
+ * if false, cache is off if there are some variables in this superglobal array
58
+ * - (boolean) makeIdWithXXXVariables (XXXX = 'Get', 'Post', 'Session', 'Files' or 'Cookie') :
59
+ * if true, we have to use the content of this superglobal array to make a cache id
60
+ * if false, the cache id won't be dependent of the content of this superglobal array
61
+ *
62
+ * ====> (array) regexps :
63
+ * - an associative array to set options only for some REQUEST_URI
64
+ * - keys are (pcre) regexps
65
+ * - values are associative array with specific options to set if the regexp matchs on $_SERVER['REQUEST_URI']
66
+ * (see default_options for the list of available options)
67
+ * - if several regexps match the $_SERVER['REQUEST_URI'], only the last one will be used
68
+ *
69
+ * @var array options
70
+ */
71
+ protected $_specificOptions = array(
72
+ 'http_conditional' => false,
73
+ 'debug_header' => false,
74
+ 'content_type_memorization' => false,
75
+ 'default_options' => array(
76
+ 'cache_with_get_variables' => false,
77
+ 'cache_with_post_variables' => false,
78
+ 'cache_with_session_variables' => false,
79
+ 'cache_with_files_variables' => false,
80
+ 'cache_with_cookie_variables' => false,
81
+ 'make_id_with_get_variables' => true,
82
+ 'make_id_with_post_variables' => true,
83
+ 'make_id_with_session_variables' => true,
84
+ 'make_id_with_files_variables' => true,
85
+ 'make_id_with_cookie_variables' => true,
86
+ 'cache' => true
87
+ ),
88
+ 'regexps' => array()
89
+ );
90
+
91
+ /**
92
+ * Internal array to store some options
93
+ *
94
+ * @var array associative array of options
95
+ */
96
+ protected $_activeOptions = array();
97
+
98
+ /**
99
+ * Constructor
100
+ *
101
+ * @param array $options Associative array of options
102
+ * @param boolean $doNotTestCacheValidity If set to true, the cache validity won't be tested
103
+ * @throws Zend_Cache_Exception
104
+ * @return void
105
+ */
106
+ public function __construct($options = array())
107
+ {
108
+ while (list($name, $value) = each($options)) {
109
+ $name = strtolower($name);
110
+ switch ($name) {
111
+ case 'regexps':
112
+ $this->_setRegexps($value);
113
+ break;
114
+ case 'default_options':
115
+ $this->_setDefaultOptions($value);
116
+ break;
117
+ default:
118
+ $this->setOption($name, $value);
119
+ }
120
+ }
121
+ if (isset($this->_specificOptions['http_conditional'])) {
122
+ if ($this->_specificOptions['http_conditional']) {
123
+ Zend_Cache::throwException('http_conditional is not implemented for the moment !');
124
+ }
125
+ }
126
+ $this->setOption('automatic_serialization', true);
127
+ }
128
+
129
+ /**
130
+ * Specific setter for the 'default_options' option (with some additional tests)
131
+ *
132
+ * @param array $options Associative array
133
+ * @throws Zend_Cache_Exception
134
+ * @return void
135
+ */
136
+ protected function _setDefaultOptions($options)
137
+ {
138
+ if (!is_array($options)) {
139
+ Zend_Cache::throwException('default_options must be an array !');
140
+ }
141
+ foreach ($options as $key=>$value) {
142
+ $key = strtolower($key);
143
+ if (!isset($this->_specificOptions['default_options'][$key])) {
144
+ Zend_Cache::throwException("unknown option [$key] !");
145
+ } else {
146
+ $this->_specificOptions['default_options'][$key] = $value;
147
+ }
148
+ }
149
+ }
150
+
151
+ /**
152
+ * Specific setter for the 'regexps' option (with some additional tests)
153
+ *
154
+ * @param array $options Associative array
155
+ * @throws Zend_Cache_Exception
156
+ * @return void
157
+ */
158
+ protected function _setRegexps($regexps)
159
+ {
160
+ if (!is_array($regexps)) {
161
+ Zend_Cache::throwException('regexps option must be an array !');
162
+ }
163
+ foreach ($regexps as $regexp=>$conf) {
164
+ if (!is_array($conf)) {
165
+ Zend_Cache::throwException('regexps option must be an array of arrays !');
166
+ }
167
+ $validKeys = array_keys($this->_specificOptions['default_options']);
168
+ foreach ($conf as $key=>$value) {
169
+ $key = strtolower($key);
170
+ if (!in_array($key, $validKeys)) {
171
+ Zend_Cache::throwException("unknown option [$key] !");
172
+ }
173
+ }
174
+ }
175
+ $this->setOption('regexps', $regexps);
176
+ }
177
+
178
+ /**
179
+ * Start the cache
180
+ *
181
+ * @param string $id (optional) A cache id (if you set a value here, maybe you have to use Output frontend instead)
182
+ * @param boolean $doNotDie For unit testing only !
183
+ * @return boolean True if the cache is hit (false else)
184
+ */
185
+ public function start($id = false, $doNotDie = false)
186
+ {
187
+ $lastMatchingRegexp = null;
188
+ foreach ($this->_specificOptions['regexps'] as $regexp => $conf) {
189
+ if (preg_match("`$regexp`", $_SERVER['REQUEST_URI'])) {
190
+ $lastMatchingRegexp = $regexp;
191
+ }
192
+ }
193
+ $this->_activeOptions = $this->_specificOptions['default_options'];
194
+ if (!is_null($lastMatchingRegexp)) {
195
+ $conf = $this->_specificOptions['regexps'][$lastMatchingRegexp];
196
+ foreach ($conf as $key=>$value) {
197
+ $this->_activeOptions[$key] = $value;
198
+ }
199
+ }
200
+ if (!($this->_activeOptions['cache'])) {
201
+ return false;
202
+ }
203
+ if (!$id) {
204
+ $id = $this->_makeId();
205
+ if (!$id) {
206
+ return false;
207
+ }
208
+ }
209
+ $array = $this->load($id);
210
+ if ($array !== false) {
211
+ $data = $array['data'];
212
+ $contentType = $array['contentType'];
213
+ if ($this->_specificOptions['debug_header']) {
214
+ echo 'DEBUG HEADER : This is a cached page !';
215
+ }
216
+ if ($this->_specificOptions['content_type_memorization']) {
217
+ if (!is_null($contentType)) {
218
+ if (!headers_sent()) {
219
+ header("Content-Type: $contentType");
220
+ }
221
+ }
222
+ }
223
+ echo $data;
224
+ if ($doNotDie) {
225
+ return true;
226
+ }
227
+ die();
228
+ }
229
+ ob_start(array($this, '_flush'));
230
+ ob_implicit_flush(false);
231
+ return false;
232
+ }
233
+
234
+ /**
235
+ * callback for output buffering
236
+ * (shouldn't really be called manually)
237
+ *
238
+ * @param string $data Buffered output
239
+ * @return string Data to send to browser
240
+ */
241
+ public function _flush($data)
242
+ {
243
+ $contentType = null;
244
+ if ($this->_specificOptions['content_type_memorization']) {
245
+ if (headers_sent()) {
246
+ $headersList = headers_list();
247
+ foreach ($headersList as $header) {
248
+ $tmp = split(':', $header);
249
+ if (strtolower(trim($tmp[0])) == 'content-type') {
250
+ $contentType = trim($tmp[1]);
251
+ }
252
+ }
253
+ }
254
+ }
255
+ $array = array(
256
+ 'data' => $data,
257
+ 'contentType' => $contentType
258
+ );
259
+ $this->save($array);
260
+ return $data;
261
+ }
262
+
263
+ /**
264
+ * Make an id depending on REQUEST_URI and superglobal arrays (depending on options)
265
+ *
266
+ * @return mixed|false a cache id (string), false if the cache should have not to be used
267
+ */
268
+ private function _makeId()
269
+ {
270
+ $tmp = $_SERVER['REQUEST_URI'];
271
+ foreach (array('Get', 'Post', 'Session', 'Files', 'Cookie') as $arrayName) {
272
+ $tmp2 = $this->_makePartialId($arrayName, $this->_activeOptions['cache_with_' . strtolower($arrayName) . '_variables'], $this->_activeOptions['make_id_with_' . strtolower($arrayName) . '_variables']);
273
+ if ($tmp2===false) {
274
+ return false;
275
+ }
276
+ $tmp = $tmp . $tmp2;
277
+ }
278
+ return md5($tmp);
279
+ }
280
+
281
+ /**
282
+ * Make a partial id depending on options
283
+ *
284
+ * @param string $arrayName Superglobal array name
285
+ * @param bool $bool1 If true, cache is still on even if there are some variables in the superglobal array
286
+ * @param bool $bool2 If true, we have to use the content of the superglobal array to make a partial id
287
+ * @return mixed|false Partial id (string) or false if the cache should have not to be used
288
+ */
289
+ private function _makePartialId($arrayName, $bool1, $bool2)
290
+ {
291
+ switch ($arrayName) {
292
+ case 'Get':
293
+ $var = $_GET;
294
+ break;
295
+ case 'Post':
296
+ $var = $_POST;
297
+ break;
298
+ case 'Session':
299
+ if (isset($_SESSION)) {
300
+ $var = $_SESSION;
301
+ } else {
302
+ $var = null;
303
+ }
304
+ break;
305
+ case 'Cookie':
306
+ if (isset($_COOKIE)) {
307
+ $var = $_COOKIE;
308
+ } else {
309
+ $var = null;
310
+ }
311
+ break;
312
+ case 'Files':
313
+ $var = $_FILES;
314
+ break;
315
+ default:
316
+ return false;
317
+ }
318
+ if ($bool1) {
319
+ if ($bool2) {
320
+ return serialize($var);
321
+ }
322
+ return '';
323
+ }
324
+ if (count($var) > 0) {
325
+ return false;
326
+ }
327
+ return '';
328
+ }
329
+
330
+ }
lib/Zend/Config.php ADDED
@@ -0,0 +1,348 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Zend Framework
5
+ *
6
+ * LICENSE
7
+ *
8
+ * This source file is subject to the new BSD license that is bundled
9
+ * with this package in the file LICENSE.txt.
10
+ * It is also available through the world-wide-web at this URL:
11
+ * http://framework.zend.com/license/new-bsd
12
+ * If you did not receive a copy of the license and are unable to
13
+ * obtain it through the world-wide-web, please send an email
14
+ * to license@zend.com so we can send you a copy immediately.
15
+ *
16
+ * @category Zend
17
+ * @package Zend_Config
18
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
19
+ * @license http://framework.zend.com/license/new-bsd New BSD License
20
+ * @version $Id: Config.php 8064 2008-02-16 10:58:39Z thomas $
21
+ */
22
+
23
+
24
+ /**
25
+ * @category Zend
26
+ * @package Zend_Config
27
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
28
+ * @license http://framework.zend.com/license/new-bsd New BSD License
29
+ */
30
+ class Zend_Config implements Countable, Iterator
31
+ {
32
+ /**
33
+ * Whether in-memory modifications to configuration data are allowed
34
+ *
35
+ * @var boolean
36
+ */
37
+ protected $_allowModifications;
38
+
39
+ /**
40
+ * Iteration index
41
+ *
42
+ * @var integer
43
+ */
44
+ protected $_index;
45
+
46
+ /**
47
+ * Number of elements in configuration data
48
+ *
49
+ * @var integer
50
+ */
51
+ protected $_count;
52
+
53
+ /**
54
+ * Contains array of configuration data
55
+ *
56
+ * @var array
57
+ */
58
+ protected $_data;
59
+
60
+
61
+ /**
62
+ * Contains which config file sections were loaded. This is null
63
+ * if all sections were loaded, a string name if one section is loaded
64
+ * and an array of string names if multiple sections were loaded.
65
+ *
66
+ * @var mixed
67
+ */
68
+ protected $_loadedSection;
69
+
70
+ /**
71
+ * This is used to track section inheritance. The keys are names of sections that
72
+ * extend other sections, and the values are the extended sections.
73
+ *
74
+ * @var array
75
+ */
76
+ protected $_extends = array();
77
+
78
+ /**
79
+ * Zend_Config provides a property based interface to
80
+ * an array. The data are read-only unless $allowModifications
81
+ * is set to true on construction.
82
+ *
83
+ * Zend_Config also implements Countable and Iterator to
84
+ * facilitate easy access to the data.
85
+ *
86
+ * @param array $array
87
+ * @param boolean $allowModifications
88
+ * @return void
89
+ */
90
+ public function __construct($array, $allowModifications = false)
91
+ {
92
+ $this->_allowModifications = (boolean) $allowModifications;
93
+ $this->_loadedSection = null;
94
+ $this->_index = 0;
95
+ $this->_data = array();
96
+ foreach ($array as $key => $value) {
97
+ if (is_array($value)) {
98
+ $this->_data[$key] = new self($value, $this->_allowModifications);
99
+ } else {
100
+ $this->_data[$key] = $value;
101
+ }
102
+ }
103
+ $this->_count = count($this->_data);
104
+ }
105
+
106
+ /**
107
+ * Retrieve a value and return $default if there is no element set.
108
+ *
109
+ * @param string $name
110
+ * @param mixed $default
111
+ * @return mixed
112
+ */
113
+ public function get($name, $default = null)
114
+ {
115
+ $result = $default;
116
+ if (array_key_exists($name, $this->_data)) {
117
+ $result = $this->_data[$name];
118
+ }
119
+ return $result;
120
+ }
121
+
122
+ /**
123
+ * Magic function so that $obj->value will work.
124
+ *
125
+ * @param string $name
126
+ * @return mixed
127
+ */
128
+ public function __get($name)
129
+ {
130
+ return $this->get($name);
131
+ }
132
+
133
+ /**
134
+ * Only allow setting of a property if $allowModifications
135
+ * was set to true on construction. Otherwise, throw an exception.
136
+ *
137
+ * @param string $name
138
+ * @param mixed $value
139
+ * @throws Zend_Config_Exception
140
+ * @return void
141
+ */
142
+ public function __set($name, $value)
143
+ {
144
+ if ($this->_allowModifications) {
145
+ if (is_array($value)) {
146
+ $this->_data[$name] = new self($value, true);
147
+ } else {
148
+ $this->_data[$name] = $value;
149
+ }
150
+ $this->_count = count($this->_data);
151
+ } else {
152
+ /** @see Zend_Config_Exception */
153
+ require_once 'Zend/Config/Exception.php';
154
+ throw new Zend_Config_Exception('Zend_Config is read only');
155
+ }
156
+ }
157
+
158
+ /**
159
+ * Return an associative array of the stored data.
160
+ *
161
+ * @return array
162
+ */
163
+ public function toArray()
164
+ {
165
+ $array = array();
166
+ foreach ($this->_data as $key => $value) {
167
+ if ($value instanceof Zend_Config) {
168
+ $array[$key] = $value->toArray();
169
+ } else {
170
+ $array[$key] = $value;
171
+ }
172
+ }
173
+ return $array;
174
+ }
175
+
176
+ /**
177
+ * Support isset() overloading on PHP 5.1
178
+ *
179
+ * @param string $name
180
+ * @return boolean
181
+ */
182
+ protected function __isset($name)
183
+ {
184
+ return isset($this->_data[$name]);
185
+ }
186
+
187
+ /**
188
+ * Support unset() overloading on PHP 5.1
189
+ *
190
+ * @param string $name
191
+ * @throws Zend_Config_Exception
192
+ * @return void
193
+ */
194
+ protected function __unset($name)
195
+ {
196
+ if ($this->_allowModifications) {
197
+ unset($this->_data[$name]);
198
+ } else {
199
+ /** @see Zend_Config_Exception */
200
+ require_once 'Zend/Config/Exception.php';
201
+ throw new Zend_Config_Exception('Zend_Config is read only');
202
+ }
203
+
204
+ }
205
+
206
+ /**
207
+ * Defined by Countable interface
208
+ *
209
+ * @return int
210
+ */
211
+ public function count()
212
+ {
213
+ return $this->_count;
214
+ }
215
+
216
+ /**
217
+ * Defined by Iterator interface
218
+ *
219
+ * @return mixed
220
+ */
221
+ public function current()
222
+ {
223
+ return current($this->_data);
224
+ }
225
+
226
+ /**
227
+ * Defined by Iterator interface
228
+ *
229
+ * @return mixed
230
+ */
231
+ public function key()
232
+ {
233
+ return key($this->_data);
234
+ }
235
+
236
+ /**
237
+ * Defined by Iterator interface
238
+ *
239
+ */
240
+ public function next()
241
+ {
242
+ next($this->_data);
243
+ $this->_index++;
244
+ }
245
+
246
+ /**
247
+ * Defined by Iterator interface
248
+ *
249
+ */
250
+ public function rewind()
251
+ {
252
+ reset($this->_data);
253
+ $this->_index = 0;
254
+ }
255
+
256
+ /**
257
+ * Defined by Iterator interface
258
+ *
259
+ * @return boolean
260
+ */
261
+ public function valid()
262
+ {
263
+ return $this->_index < $this->_count;
264
+ }
265
+
266
+ /**
267
+ * Returns the section name(s) loaded.
268
+ *
269
+ * @return mixed
270
+ */
271
+ public function getSectionName()
272
+ {
273
+ return $this->_loadedSection;
274
+ }
275
+
276
+ /**
277
+ * Returns true if all sections were loaded
278
+ *
279
+ * @return boolean
280
+ */
281
+ public function areAllSectionsLoaded()
282
+ {
283
+ return $this->_loadedSection === null;
284
+ }
285
+
286
+
287
+ /**
288
+ * Merge another Zend_Config with this one. The items
289
+ * in $merge will override the same named items in
290
+ * the current config.
291
+ *
292
+ * @param Zend_Config $merge
293
+ * @return Zend_Config
294
+ */
295
+ public function merge(Zend_Config $merge)
296
+ {
297
+ foreach($merge as $key => $item) {
298
+ if(array_key_exists($key, $this->_data)) {
299
+ if($item instanceof Zend_Config && $this->$key instanceof Zend_Config) {
300
+ $this->$key = $this->$key->merge($item);
301
+ } else {
302
+ $this->$key = $item;
303
+ }
304
+ } else {
305
+ $this->$key = $item;
306
+ }
307
+ }
308
+
309
+ return $this;
310
+ }
311
+
312
+ /**
313
+ * Prevent any more modifications being made to this instance. Useful
314
+ * after merge() has been used to merge multiple Zend_Config objects
315
+ * into one object which should then not be modified again.
316
+ *
317
+ */
318
+ public function setReadOnly()
319
+ {
320
+ $this->_allowModifications = false;
321
+ }
322
+
323
+ /**
324
+ * Throws an exception if $extendingSection may not extend $extendedSection,
325
+ * and tracks the section extension if it is valid.
326
+ *
327
+ * @param string $extendingSection
328
+ * @param string $extendedSection
329
+ * @throws Zend_Config_Exception
330
+ * @return void
331
+ */
332
+ protected function _assertValidExtend($extendingSection, $extendedSection)
333
+ {
334
+ // detect circular section inheritance
335
+ $extendedSectionCurrent = $extendedSection;
336
+ while (array_key_exists($extendedSectionCurrent, $this->_extends)) {
337
+ if ($this->_extends[$extendedSectionCurrent] == $extendingSection) {
338
+ /** @see Zend_Config_Exception */
339
+ require_once 'Zend/Config/Exception.php';
340
+ throw new Zend_Config_Exception('Illegal circular inheritance detected');
341
+ }
342
+ $extendedSectionCurrent = $this->_extends[$extendedSectionCurrent];
343
+ }
344
+ // remember that this section extends another section
345
+ $this->_extends[$extendingSection] = $extendedSection;
346
+ }
347
+
348
+ }
lib/Zend/Config/Exception.php ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Zend Framework
4
+ *
5
+ * LICENSE
6
+ *
7
+ * This source file is subject to the new BSD license that is bundled
8
+ * with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://framework.zend.com/license/new-bsd
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@zend.com so we can send you a copy immediately.
14
+ *
15
+ * @category Zend
16
+ * @package Zend_Config
17
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
18
+ * @license http://framework.zend.com/license/new-bsd New BSD License
19
+ */
20
+
21
+ /**
22
+ * @see Zend_Exception
23
+ */
24
+ require_once 'Zend/Exception.php';
25
+
26
+ /**
27
+ * @category Zend
28
+ * @package Zend_Config
29
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
30
+ * @license http://framework.zend.com/license/new-bsd New BSD License
31
+ */
32
+ class Zend_Config_Exception extends Zend_Exception {}
lib/Zend/Config/Ini.php ADDED
@@ -0,0 +1,244 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Zend Framework
4
+ *
5
+ * LICENSE
6
+ *
7
+ * This source file is subject to the new BSD license that is bundled
8
+ * with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://framework.zend.com/license/new-bsd
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@zend.com so we can send you a copy immediately.
14
+ *
15
+ * @category Zend
16
+ * @package Zend_Config
17
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
18
+ * @license http://framework.zend.com/license/new-bsd New BSD License
19
+ * @version $Id: Ini.php 8867 2008-03-16 20:36:34Z thomas $
20
+ */
21
+
22
+
23
+ /**
24
+ * @see Zend_Config
25
+ */
26
+ require_once 'Zend/Config.php';
27
+
28
+
29
+ /**
30
+ * @category Zend
31
+ * @package Zend_Config
32
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
33
+ * @license http://framework.zend.com/license/new-bsd New BSD License
34
+ */
35
+ class Zend_Config_Ini extends Zend_Config
36
+ {
37
+ /**
38
+ * String that separates nesting levels of configuration data identifiers
39
+ *
40
+ * @var string
41
+ */
42
+ protected $_nestSeparator = '.';
43
+
44
+ /**
45
+ * Loads the section $section from the config file $filename for
46
+ * access facilitated by nested object properties.
47
+ *
48
+ * If the section name contains a ":" then the section name to the right
49
+ * is loaded and included into the properties. Note that the keys in
50
+ * this $section will override any keys of the same
51
+ * name in the sections that have been included via ":".
52
+ *
53
+ * If the $section is null, then all sections in the ini file are loaded.
54
+ *
55
+ * If any key includes a ".", then this will act as a separator to
56
+ * create a sub-property.
57
+ *
58
+ * example ini file:
59
+ * [all]
60
+ * db.connection = database
61
+ * hostname = live
62
+ *
63
+ * [staging : all]
64
+ * hostname = staging
65
+ *
66
+ * after calling $data = new Zend_Config_Ini($file, 'staging'); then
67
+ * $data->hostname === "staging"
68
+ * $data->db->connection === "database"
69
+ *
70
+ * The $options parameter may be provided as either a boolean or an array.
71
+ * If provided as a boolean, this sets the $allowModifications option of
72
+ * Zend_Config. If provided as an array, there are two configuration
73
+ * directives that may be set. For example:
74
+ *
75
+ * $options = array(
76
+ * 'allowModifications' => false,
77
+ * 'nestSeparator' => '->'
78
+ * );
79
+ *
80
+ * @param string $filename
81
+ * @param string|null $section
82
+ * @param boolean|array $options
83
+ * @throws Zend_Config_Exception
84
+ * @return void
85
+ */
86
+ public function __construct($filename, $section = null, $options = false)
87
+ {
88
+ if (empty($filename)) {
89
+ /**
90
+ * @see Zend_Config_Exception
91
+ */
92
+ require_once 'Zend/Config/Exception.php';
93
+ throw new Zend_Config_Exception('Filename is not set');
94
+ }
95
+
96
+ $allowModifications = false;
97
+ if (is_bool($options)) {
98
+ $allowModifications = $options;
99
+ } elseif (is_array($options)) {
100
+ if (isset($options['allowModifications'])) {
101
+ $allowModifications = (bool) $options['allowModifications'];
102
+ }
103
+ if (isset($options['nestSeparator'])) {
104
+ $this->_nestSeparator = (string) $options['nestSeparator'];
105
+ }
106
+ }
107
+
108
+ $iniArray = parse_ini_file($filename, true);
109
+ $preProcessedArray = array();
110
+ foreach ($iniArray as $key => $data)
111
+ {
112
+ $bits = explode(':', $key);
113
+ $thisSection = trim($bits[0]);
114
+ switch (count($bits)) {
115
+ case 1:
116
+ $preProcessedArray[$thisSection] = $data;
117
+ break;
118
+
119
+ case 2:
120
+ $extendedSection = trim($bits[1]);
121
+ $preProcessedArray[$thisSection] = array_merge(array(';extends'=>$extendedSection), $data);
122
+ break;
123
+
124
+ default:
125
+ /**
126
+ * @see Zend_Config_Exception
127
+ */
128
+ require_once 'Zend/Config/Exception.php';
129
+ throw new Zend_Config_Exception("Section '$thisSection' may not extend multiple sections in $filename");
130
+ }
131
+ }
132
+
133
+ if (null === $section) {
134
+ $dataArray = array();
135
+ foreach ($preProcessedArray as $sectionName => $sectionData) {
136
+ if(!is_array($sectionData)) {
137
+ $dataArray = array_merge_recursive($dataArray, $this->_processKey(array(), $sectionName, $sectionData));
138
+ } else {
139
+ $dataArray[$sectionName] = $this->_processExtends($preProcessedArray, $sectionName);
140
+ }
141
+ }
142
+ parent::__construct($dataArray, $allowModifications);
143
+ } elseif (is_array($section)) {
144
+ $dataArray = array();
145
+ foreach ($section as $sectionName) {
146
+ if (!isset($preProcessedArray[$sectionName])) {
147
+ /**
148
+ * @see Zend_Config_Exception
149
+ */
150
+ require_once 'Zend/Config/Exception.php';
151
+ throw new Zend_Config_Exception("Section '$sectionName' cannot be found in $filename");
152
+ }
153
+ $dataArray = array_merge($this->_processExtends($preProcessedArray, $sectionName), $dataArray);
154
+
155
+ }
156
+ parent::__construct($dataArray, $allowModifications);
157
+ } else {
158
+ if (!isset($preProcessedArray[$section])) {
159
+ /**
160
+ * @see Zend_Config_Exception
161
+ */
162
+ require_once 'Zend/Config/Exception.php';
163
+ throw new Zend_Config_Exception("Section '$section' cannot be found in $filename");
164
+ }
165
+ parent::__construct($this->_processExtends($preProcessedArray, $section), $allowModifications);
166
+ }
167
+
168
+ $this->_loadedSection = $section;
169
+ }
170
+
171
+ /**
172
+ * Helper function to process each element in the section and handle
173
+ * the "extends" inheritance keyword. Passes control to _processKey()
174
+ * to handle the "dot" sub-property syntax in each key.
175
+ *
176
+ * @param array $iniArray
177
+ * @param string $section
178
+ * @param array $config
179
+ * @throws Zend_Config_Exception
180
+ * @return array
181
+ */
182
+ protected function _processExtends($iniArray, $section, $config = array())
183
+ {
184
+ $thisSection = $iniArray[$section];
185
+
186
+ foreach ($thisSection as $key => $value) {
187
+ if (strtolower($key) == ';extends') {
188
+ if (isset($iniArray[$value])) {
189
+ $this->_assertValidExtend($section, $value);
190
+ $config = $this->_processExtends($iniArray, $value, $config);
191
+ } else {
192
+ /**
193
+ * @see Zend_Config_Exception
194
+ */
195
+ require_once 'Zend/Config/Exception.php';
196
+ throw new Zend_Config_Exception("Section '$section' cannot be found");
197
+ }
198
+ } else {
199
+ $config = $this->_processKey($config, $key, $value);
200
+ }
201
+ }
202
+ return $config;
203
+ }
204
+
205
+ /**
206
+ * Assign the key's value to the property list. Handle the "dot"
207
+ * notation for sub-properties by passing control to
208
+ * processLevelsInKey().
209
+ *
210
+ * @param array $config
211
+ * @param string $key
212
+ * @param string $value
213
+ * @throws Zend_Config_Exception
214
+ * @return array
215
+ */
216
+ protected function _processKey($config, $key, $value)
217
+ {
218
+ if (strpos($key, $this->_nestSeparator) !== false) {
219
+ $pieces = explode($this->_nestSeparator, $key, 2);
220
+ if (strlen($pieces[0]) && strlen($pieces[1])) {
221
+ if (!isset($config[$pieces[0]])) {
222
+ $config[$pieces[0]] = array();
223
+ } elseif (!is_array($config[$pieces[0]])) {
224
+ /**
225
+ * @see Zend_Config_Exception
226
+ */
227
+ require_once 'Zend/Config/Exception.php';
228
+ throw new Zend_Config_Exception("Cannot create sub-key for '{$pieces[0]}' as key already exists");
229
+ }
230
+ $config[$pieces[0]] = $this->_processKey($config[$pieces[0]], $pieces[1], $value);
231
+ } else {
232
+ /**
233
+ * @see Zend_Config_Exception
234
+ */
235
+ require_once 'Zend/Config/Exception.php';
236
+ throw new Zend_Config_Exception("Invalid key '$key'");
237
+ }
238
+ } else {
239
+ $config[$key] = $value;
240
+ }
241
+ return $config;
242
+ }
243
+
244
+ }
lib/Zend/Config/Xml.php ADDED
@@ -0,0 +1,199 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Zend Framework
4
+ *
5
+ * LICENSE
6
+ *
7
+ * This source file is subject to the new BSD license that is bundled
8
+ * with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://framework.zend.com/license/new-bsd
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@zend.com so we can send you a copy immediately.
14
+ *
15
+ * @category Zend
16
+ * @package Zend_Config
17
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
18
+ * @license http://framework.zend.com/license/new-bsd New BSD License
19
+ * @version $Id: Xml.php 8867 2008-03-16 20:36:34Z thomas $
20
+ */
21
+
22
+
23
+ /**
24
+ * @see Zend_Config
25
+ */
26
+ require_once 'Zend/Config.php';
27
+
28
+
29
+ /**
30
+ * @category Zend
31
+ * @package Zend_Config
32
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
33
+ * @license http://framework.zend.com/license/new-bsd New BSD License
34
+ */
35
+ class Zend_Config_Xml extends Zend_Config
36
+ {
37
+ /**
38
+ * Loads the section $section from the config file $filename for
39
+ * access facilitated by nested object properties.
40
+ *
41
+ * Sections are defined in the XML as children of the root element.
42
+ *
43
+ * In order to extend another section, a section defines the "extends"
44
+ * attribute having a value of the section name from which the extending
45
+ * section inherits values.
46
+ *
47
+ * Note that the keys in $section will override any keys of the same
48
+ * name in the sections that have been included via "extends".
49
+ *
50
+ * @param string $filename
51
+ * @param mixed $section
52
+ * @param boolean $allowModifications
53
+ * @throws Zend_Config_Exception
54
+ * @return void
55
+ */
56
+ public function __construct($filename, $section = null, $allowModifications = false)
57
+ {
58
+ if (empty($filename)) {
59
+ /**
60
+ * @see Zend_Config_Exception
61
+ */
62
+ require_once 'Zend/Config/Exception.php';
63
+ throw new Zend_Config_Exception('Filename is not set');
64
+ }
65
+
66
+ $config = simplexml_load_file($filename);
67
+
68
+ if (null === $section) {
69
+ $dataArray = array();
70
+ foreach ($config as $sectionName => $sectionData) {
71
+ $dataArray[$sectionName] = $this->_processExtends($config, $sectionName);
72
+ }
73
+ parent::__construct($dataArray, $allowModifications);
74
+ } elseif (is_array($section)) {
75
+ $dataArray = array();
76
+ foreach ($section as $sectionName) {
77
+ if (!isset($config->$sectionName)) {
78
+ /**
79
+ * @see Zend_Config_Exception
80
+ */
81
+ require_once 'Zend/Config/Exception.php';
82
+ throw new Zend_Config_Exception("Section '$sectionName' cannot be found in $filename");
83
+ }
84
+ $dataArray = array_merge($this->_processExtends($config, $sectionName), $dataArray);
85
+ }
86
+ parent::__construct($dataArray, $allowModifications);
87
+ } else {
88
+ if (!isset($config->$section)) {
89
+ /**
90
+ * @see Zend_Config_Exception
91
+ */
92
+ require_once 'Zend/Config/Exception.php';
93
+ throw new Zend_Config_Exception("Section '$section' cannot be found in $filename");
94
+ }
95
+ $dataArray = $this->_processExtends($config, $section);
96
+ if(!is_array($dataArray)) {
97
+ // section in the XML file contains just one top level string
98
+ $dataArray = array($section=>$dataArray);
99
+ }
100
+ parent::__construct($dataArray, $allowModifications);
101
+ }
102
+
103
+ $this->_loadedSection = $section;
104
+ }
105
+
106
+
107
+ /**
108
+ * Helper function to process each element in the section and handle
109
+ * the "extends" inheritance attribute.
110
+ *
111
+ * @param SimpleXMLElement $element
112
+ * @param string $section
113
+ * @param array $config
114
+ * @throws Zend_Config_Exception
115
+ * @return array
116
+ */
117
+ protected function _processExtends($element, $section, $config = array())
118
+ {
119
+ if (!$element->$section) {
120
+ /**
121
+ * @see Zend_Config_Exception
122
+ */
123
+ require_once 'Zend/Config/Exception.php';
124
+ throw new Zend_Config_Exception("Section '$section' cannot be found");
125
+ }
126
+
127
+ $thisSection = $element->$section;
128
+
129
+ if (isset($thisSection['extends'])) {
130
+ $extendedSection = (string) $thisSection['extends'];
131
+ $this->_assertValidExtend($section, $extendedSection);
132
+ $config = $this->_processExtends($element, $extendedSection, $config);
133
+ }
134
+
135
+ $config = $this->_arrayMergeRecursive($config, $this->_toArray($thisSection));
136
+
137
+ return $config;
138
+ }
139
+
140
+
141
+ /**
142
+ * Returns a string or an associative and possibly multidimensional array from
143
+ * a SimpleXMLElement.
144
+ *
145
+ * @param SimpleXMLElement $xmlObject
146
+ * @return array|string
147
+ */
148
+ protected function _toArray($xmlObject)
149
+ {
150
+
151
+ $config = array();
152
+ if (count($xmlObject->children())) {
153
+ foreach ($xmlObject->children() as $key => $value) {
154
+ if ($value->children()) {
155
+ $value = $this->_toArray($value);
156
+ } else {
157
+ $value = (string) $value;
158
+ }
159
+ if (array_key_exists($key, $config)) {
160
+ if (!is_array($config[$key]) || !array_key_exists(0, $config[$key])) {
161
+ $config[$key] = array($config[$key]);
162
+ }
163
+ $config[$key][] = $value;
164
+ } else {
165
+ $config[$key] = $value;
166
+ }
167
+ }
168
+ } elseif (!isset($xmlObject['extends'])) {
169
+ // object has no children and doesn't use the extends attribute: it's a string
170
+ $config = (string) $xmlObject;
171
+ }
172
+ return $config;
173
+ }
174
+
175
+ /**
176
+ * Merge two arrays recursively, overwriting keys of the same name
177
+ * in $array1 with the value in $array2.
178
+ *
179
+ * @param array $array1
180
+ * @param array $array2
181
+ * @return array
182
+ */
183
+ protected function _arrayMergeRecursive($array1, $array2)
184
+ {
185
+ if (is_array($array1) && is_array($array2)) {
186
+ foreach ($array2 as $key => $value) {
187
+ if (isset($array1[$key])) {
188
+ $array1[$key] = $this->_arrayMergeRecursive($array1[$key], $value);
189
+ } else {
190
+ $array1[$key] = $value;
191
+ }
192
+ }
193
+ } else {
194
+ $array1 = $array2;
195
+ }
196
+ return $array1;
197
+ }
198
+
199
+ }
lib/Zend/Console/Getopt.php ADDED
@@ -0,0 +1,949 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Zend_Console_Getopt is a class to parse options for command-line
4
+ * applications.
5
+ *
6
+ * LICENSE
7
+ *
8
+ * This source file is subject to the new BSD license that is bundled
9
+ * with this package in the file LICENSE.txt.
10
+ * It is also available through the world-wide-web at this URL:
11
+ * http://framework.zend.com/license/new-bsd
12
+ * If you did not receive a copy of the license and are unable to
13
+ * obtain it through the world-wide-web, please send an email
14
+ * to license@zend.com so we can send you a copy immediately.
15
+ *
16
+ * @category Zend
17
+ * @package Zend_Console_Getopt
18
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
19
+ * @version $Id$
20
+ * @license http://framework.zend.com/license/new-bsd New BSD License
21
+ */
22
+
23
+ /**
24
+ * @see Zend_Console_Getopt_Exception
25
+ */
26
+ require_once 'Zend/Console/Getopt/Exception.php';
27
+
28
+ /**
29
+ * Zend_Console_Getopt is a class to parse options for command-line
30
+ * applications.
31
+ *
32
+ * Terminology:
33
+ * Argument: an element of the argv array. This may be part of an option,
34
+ * or it may be a non-option command-line argument.
35
+ * Flag: the letter or word set off by a '-' or '--'. Example: in '--output filename',
36
+ * '--output' is the flag.
37
+ * Parameter: the additional argument that is associated with the option.
38
+ * Example: in '--output filename', the 'filename' is the parameter.
39
+ * Option: the combination of a flag and its parameter, if any.
40
+ * Example: in '--output filename', the whole thing is the option.
41
+ *
42
+ * The following features are supported:
43
+ *
44
+ * - Short flags like '-a'. Short flags are preceded by a single
45
+ * dash. Short flags may be clustered e.g. '-abc', which is the
46
+ * same as '-a' '-b' '-c'.
47
+ * - Long flags like '--verbose'. Long flags are preceded by a
48
+ * double dash. Long flags may not be clustered.
49
+ * - Options may have a parameter, e.g. '--output filename'.
50
+ * - Parameters for long flags may also be set off with an equals sign,
51
+ * e.g. '--output=filename'.
52
+ * - Parameters for long flags may be checked as string, word, or integer.
53
+ * - Automatic generation of a helpful usage message.
54
+ * - Signal end of options with '--'; subsequent arguments are treated
55
+ * as non-option arguments, even if they begin with '-'.
56
+ * - Raise exception Zend_Console_Getopt_Exception in several cases
57
+ * when invalid flags or parameters are given. Usage message is
58
+ * returned in the exception object.
59
+ *
60
+ * The format for specifying options uses a PHP associative array.
61
+ * The key is has the format of a list of pipe-separated flag names,
62
+ * followed by an optional '=' to indicate a required parameter or
63
+ * '-' to indicate an optional parameter. Following that, the type
64
+ * of parameter may be specified as 's' for string, 'w' for word,
65
+ * or 'i' for integer.
66
+ *
67
+ * Examples:
68
+ * - 'user|username|u=s' this means '--user' or '--username' or '-u'
69
+ * are synonyms, and the option requires a string parameter.
70
+ * - 'p=i' this means '-p' requires an integer parameter. No synonyms.
71
+ * - 'verbose|v-i' this means '--verbose' or '-v' are synonyms, and
72
+ * they take an optional integer parameter.
73
+ * - 'help|h' this means '--help' or '-h' are synonyms, and
74
+ * they take no parameter.
75
+ *
76
+ * The values in the associative array are strings that are used as
77
+ * brief descriptions of the options when printing a usage message.
78
+ *
79
+ * The simpler format for specifying options used by PHP's getopt()
80
+ * function is also supported. This is similar to GNU getopt and shell
81
+ * getopt format.
82
+ *
83
+ * Example: 'abc:' means options '-a', '-b', and '-c'
84
+ * are legal, and the latter requires a string parameter.
85
+ *
86
+ * @category Zend
87
+ * @package Zend_Console_Getopt
88
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
89
+ * @license http://framework.zend.com/license/new-bsd New BSD License
90
+ * @version Release: @package_version@
91
+ * @since Class available since Release 0.6.0
92
+ *
93
+ * @todo Handle params with multiple values, e.g. --colors=red,green,blue
94
+ * Set value of parameter to the array of values. Allow user to specify
95
+ * the separator with Zend_Console_Getopt::CONFIG_PARAMETER_SEPARATOR.
96
+ * If this config value is null or empty string, do not split values
97
+ * into arrays. Default separator is comma (',').
98
+ *
99
+ * @todo Handle params with multiple values specified with separate options
100
+ * e.g. --colors red --colors green --colors blue should give one
101
+ * option with an array(red, green, blue).
102
+ * Enable with Zend_Console_Getopt::CONFIG_CUMULATIVE_PARAMETERS.
103
+ * Default is that subsequent options overwrite the parameter value.
104
+ *
105
+ * @todo Handle flags occurring multiple times, e.g. -v -v -v
106
+ * Set value of the option's parameter to the integer count of instances
107
+ * instead of a boolean.
108
+ * Enable with Zend_Console_Getopt::CONFIG_CUMULATIVE_FLAGS.
109
+ * Default is that the value is simply boolean true regardless of
110
+ * how many instances of the flag appear.
111
+ *
112
+ * @todo Handle flags that implicitly print usage message, e.g. --help
113
+ *
114
+ * @todo Handle freeform options, e.g. --set-variable
115
+ * Enable with Zend_Console_Getopt::CONFIG_FREEFORM_FLAGS
116
+ * All flag-like syntax is recognized, no flag generates an exception.
117
+ *
118
+ * @todo Handle numeric options, e.g. -1, -2, -3, -1000
119
+ * Enable with Zend_Console_Getopt::CONFIG_NUMERIC_FLAGS
120
+ * The rule must specify a named flag and the '#' symbol as the
121
+ * parameter type. e.g., 'lines=#'
122
+ *
123
+ * @todo Enable user to specify header and footer content in the help message.
124
+ *
125
+ * @todo Feature request to handle option interdependencies.
126
+ * e.g. if -b is specified, -a must be specified or else the
127
+ * usage is invalid.
128
+ *
129
+ * @todo Feature request to implement callbacks.
130
+ * e.g. if -a is specified, run function 'handleOptionA'().
131
+ */
132
+ class Zend_Console_Getopt
133
+ {
134
+ /**
135
+ * The options for a given application can be in multiple formats.
136
+ * modeGnu is for traditional 'ab:c:' style getopt format.
137
+ * modeZend is for a more structured format.
138
+ */
139
+ const MODE_ZEND = 'zend';
140
+ const MODE_GNU = 'gnu';
141
+
142
+ /**
143
+ * Constant tokens for various symbols used in the mode_zend
144
+ * rule format.
145
+ */
146
+ const PARAM_REQUIRED = '=';
147
+ const PARAM_OPTIONAL = '-';
148
+ const TYPE_STRING = 's';
149
+ const TYPE_WORD = 'w';
150
+ const TYPE_INTEGER = 'i';
151
+
152
+ /**
153
+ * These are constants for optional behavior of this class.
154
+ * ruleMode is either 'zend' or 'gnu' or a user-defined mode.
155
+ * dashDash is true if '--' signifies the end of command-line options.
156
+ * ignoreCase is true if '--opt' and '--OPT' are implicitly synonyms.
157
+ */
158
+ const CONFIG_RULEMODE = 'ruleMode';
159
+ const CONFIG_DASHDASH = 'dashDash';
160
+ const CONFIG_IGNORECASE = 'ignoreCase';
161
+
162
+ /**
163
+ * Defaults for getopt configuration are:
164
+ * ruleMode is 'zend' format,
165
+ * dashDash (--) token is enabled,
166
+ * ignoreCase is not enabled.
167
+ *
168
+ * @var array Config
169
+ */
170
+ protected $_getoptConfig = array(
171
+ self::CONFIG_RULEMODE => self::MODE_ZEND,
172
+ self::CONFIG_DASHDASH => true,
173
+ self::CONFIG_IGNORECASE => false
174
+ );
175
+
176
+ /**
177
+ * Stores the command-line arguments for the calling applicaion.
178
+ *
179
+ * @var array
180
+ */
181
+ protected $_argv = array();
182
+
183
+ /**
184
+ * Stores the name of the calling applicaion.
185
+ *
186
+ * @var string
187
+ */
188
+ protected $_progname = '';
189
+
190
+ /**
191
+ * Stores the list of legal options for this application.
192
+ *
193
+ * @var array
194
+ */
195
+ protected $_rules = array();
196
+
197
+ /**
198
+ * Stores alternate spellings of legal options.
199
+ *
200
+ * @var array
201
+ */
202
+ protected $_ruleMap = array();
203
+
204
+ /**
205
+ * Stores options given by the user in the current invocation
206
+ * of the application, as well as parameters given in options.
207
+ *
208
+ * @var array
209
+ */
210
+ protected $_options = array();
211
+
212
+ /**
213
+ * Stores the command-line arguments other than options.
214
+ *
215
+ * @var array
216
+ */
217
+ protected $_remainingArgs = array();
218
+
219
+ /**
220
+ * State of the options: parsed or not yet parsed?
221
+ *
222
+ * @var boolean
223
+ */
224
+ protected $_parsed = false;
225
+
226
+ /**
227
+ * The constructor takes one to three parameters.
228
+ *
229
+ * The first parameter is $rules, which may be a string for
230
+ * gnu-style format, or a structured array for Zend-style format.
231
+ *
232
+ * The second parameter is $argv, and it is optional. If not
233
+ * specified, $argv is inferred from the global argv.
234
+ *
235
+ * The third parameter is an array of configuration parameters
236
+ * to control the behavior of this instance of Getopt; it is optional.
237
+ *
238
+ * @param array $rules
239
+ * @param array $argv
240
+ * @param array $getoptConfig
241
+ * @return void
242
+ */
243
+ public function __construct($rules, $argv = null, $getoptConfig = array())
244
+ {
245
+ $this->_progname = $_SERVER['argv'][0];
246
+ $this->setOptions($getoptConfig);
247
+ $this->addRules($rules);
248
+ if (!is_array($argv)) {
249
+ $argv = array_slice($_SERVER['argv'], 1);
250
+ }
251
+ if (isset($argv)) {
252
+ $this->addArguments((array)$argv);
253
+ }
254
+ }
255
+
256
+ /**
257
+ * Return the state of the option seen on the command line of the
258
+ * current application invocation. This function returns true, or the
259
+ * parameter to the option, if any. If the option was not given,
260
+ * this function returns null.
261
+ *
262
+ * The magic __get method works in the context of naming the option
263
+ * as a virtual member of this class.
264
+ *
265
+ * @param string $key
266
+ * @return string
267
+ */
268
+ protected function __get($key)
269
+ {
270
+ return $this->getOption($key);
271
+ }
272
+
273
+ /**
274
+ * Test whether a given option has been seen.
275
+ *
276
+ * @param string $key
277
+ * @return boolean
278
+ */
279
+ protected function __isset($key)
280
+ {
281
+ $this->parse();
282
+ if (isset($this->_ruleMap[$key])) {
283
+ $key = $this->_ruleMap[$key];
284
+ return isset($this->_options[$key]);
285
+ }
286
+ return false;
287
+ }
288
+
289
+ /**
290
+ * Set the value for a given option.
291
+ *
292
+ * @param string $key
293
+ * @param string $value
294
+ * @return void
295
+ */
296
+ protected function __set($key, $value)
297
+ {
298
+ $this->parse();
299
+ if (isset($this->_ruleMap[$key])) {
300
+ $key = $this->_ruleMap[$key];
301
+ $this->_options[$key] = $value;
302
+ }
303
+ }
304
+
305
+ /**
306
+ * Return the current set of options and parameters seen as a string.
307
+ *
308
+ * @return string
309
+ */
310
+ public function __toString()
311
+ {
312
+ return $this->toString();
313
+ }
314
+
315
+ /**
316
+ * Unset an option.
317
+ *
318
+ * @param string $key
319
+ * @return void
320
+ */
321
+ public function __unset($key)
322
+ {
323
+ $this->parse();
324
+ if (isset($this->_ruleMap[$key])) {
325
+ $key = $this->_ruleMap[$key];
326
+ unset($this->_options[$key]);
327
+ }
328
+ }
329
+
330
+ /**
331
+ * Define additional command-line arguments.
332
+ * These are appended to those defined when the constructor was called.
333
+ *
334
+ * @param array $argv
335
+ * @return Zend_Console_Getopt Provides a fluent interface
336
+ */
337
+ public function addArguments($argv)
338
+ {
339
+ $this->_argv = array_merge($this->_argv, $argv);
340
+ $this->_parsed = false;
341
+ return $this;
342
+ }
343
+
344
+ /**
345
+ * Define full set of command-line arguments.
346
+ * These replace any currently defined.
347
+ *
348
+ * @param array $argv
349
+ * @return Zend_Console_Getopt Provides a fluent interface
350
+ */
351
+ public function setArguments($argv)
352
+ {
353
+ $this->_argv = $argv;
354
+ $this->_parsed = false;
355
+ return $this;
356
+ }
357
+
358
+ /**
359
+ * Define multiple configuration options from an associative array.
360
+ * These are not program options, but properties to configure
361
+ * the behavior of Zend_Console_Getopt.
362
+ *
363
+ * @param array $getoptConfig
364
+ * @return Zend_Console_Getopt Provides a fluent interface
365
+ */
366
+ public function setOptions($getoptConfig)
367
+ {
368
+ if (isset($getoptConfig)) {
369
+ foreach ($getoptConfig as $key => $value) {
370
+ $this->setOption($key, $value);
371
+ }
372
+ }
373
+ return $this;
374
+ }
375
+
376
+ /**
377
+ * Define one configuration option as a key/value pair.
378
+ * These are not program options, but properties to configure
379
+ * the behavior of Zend_Console_Getopt.
380
+ *
381
+ * @param string $configKey
382
+ * @param string $configValue
383
+ * @return Zend_Console_Getopt Provides a fluent interface
384
+ */
385
+ public function setOption($configKey, $configValue)
386
+ {
387
+ if ($configKey !== null) {
388
+ $this->_getoptConfig[$configKey] = $configValue;
389
+ }
390
+ return $this;
391
+ }
392
+
393
+ /**
394
+ * Define additional option rules.
395
+ * These are appended to the rules defined when the constructor was called.
396
+ *
397
+ * @param array $rules
398
+ * @return Zend_Console_Getopt Provides a fluent interface
399
+ */
400
+ public function addRules($rules)
401
+ {
402
+ $ruleMode = $this->_getoptConfig['ruleMode'];
403
+ switch ($this->_getoptConfig['ruleMode']) {
404
+ case self::MODE_ZEND:
405
+ if (is_array($rules)) {
406
+ $this->_addRulesModeZend($rules);
407
+ break;
408
+ }
409
+ $this->_getoptConfig['ruleMode'] = self::MODE_GNU;
410
+ // intentional fallthrough
411
+ case self::MODE_GNU:
412
+ $this->_addRulesModeGnu($rules);
413
+ break;
414
+ default:
415
+ /**
416
+ * Call addRulesModeFoo() for ruleMode 'foo'.
417
+ * The developer should subclass Getopt and
418
+ * provide this method.
419
+ */
420
+ $method = '_addRulesMode' . ucfirst($ruleMode);
421
+ $this->$method($rules);
422
+ }
423
+ $this->_parsed = false;
424
+ return $this;
425
+ }
426
+
427
+ /**
428
+ * Return the current set of options and parameters seen as a string.
429
+ *
430
+ * @return string
431
+ */
432
+ public function toString()
433
+ {
434
+ $this->parse();
435
+ $s = array();
436
+ foreach ($this->_options as $flag => $value) {
437
+ $s[] = $flag . '=' . ($value === true ? 'true' : $value);
438
+ }
439
+ return implode(' ', $s);
440
+ }
441
+
442
+ /**
443
+ * Return the current set of options and parameters seen
444
+ * as an array of canonical options and parameters.
445
+ *
446
+ * Clusters have been expanded, and option aliases
447
+ * have been mapped to their primary option names.
448
+ *
449
+ * @return array
450
+ */
451
+ public function toArray()
452
+ {
453
+ $this->parse();
454
+ $s = array();
455
+ foreach ($this->_options as $flag => $value) {
456
+ $s[] = $flag;
457
+ if ($value !== true) {
458
+ $s[] = $value;
459
+ }
460
+ }
461
+ return $s;
462
+ }
463
+
464
+ /**
465
+ * Return the current set of options and parameters seen in Json format.
466
+ *
467
+ * @return string
468
+ */
469
+ public function toJson()
470
+ {
471
+ $this->parse();
472
+ $j = array();
473
+ foreach ($this->_options as $flag => $value) {
474
+ $j['options'][] = array(
475
+ 'option' => array(
476
+ 'flag' => $flag,
477
+ 'parameter' => $value
478
+ )
479
+ );
480
+ }
481
+
482
+ /**
483
+ * @see Zend_Json
484
+ */
485
+ require_once 'Zend/Json.php';
486
+ $json = Zend_Json::encode($j);
487
+
488
+ return $json;
489
+ }
490
+
491
+ /**
492
+ * Return the current set of options and parameters seen in XML format.
493
+ *
494
+ * @return string
495
+ */
496
+ public function toXml()
497
+ {
498
+ $this->parse();
499
+ $doc = new DomDocument('1.0', 'utf-8');
500
+ $optionsNode = $doc->createElement('options');
501
+ $doc->appendChild($optionsNode);
502
+ foreach ($this->_options as $flag => $value) {
503
+ $optionNode = $doc->createElement('option');
504
+ $optionNode->setAttribute('flag', utf8_encode($flag));
505
+ if ($value !== true) {
506
+ $optionNode->setAttribute('parameter', utf8_encode($value));
507
+ }
508
+ $optionsNode->appendChild($optionNode);
509
+ }
510
+ $xml = $doc->saveXML();
511
+ return $xml;
512
+ }
513
+
514
+ /**
515
+ * Return a list of options that have been seen in the current argv.
516
+ *
517
+ * @return array
518
+ */
519
+ public function getOptions()
520
+ {
521
+ $this->parse();
522
+ return array_keys($this->_options);
523
+ }
524
+
525
+ /**
526
+ * Return the state of the option seen on the command line of the
527
+ * current application invocation.
528
+ *
529
+ * This function returns true, or the parameter value to the option, if any.
530
+ * If the option was not given, this function returns false.
531
+ *
532
+ * @param string $flag
533
+ * @return mixed
534
+ */
535
+ public function getOption($flag)
536
+ {
537
+ $this->parse();
538
+ if ($this->_getoptConfig[self::CONFIG_IGNORECASE]) {
539
+ $flag = strtolower($flag);
540
+ }
541
+ if (isset($this->_ruleMap[$flag])) {
542
+ $flag = $this->_ruleMap[$flag];
543
+ if (isset($this->_options[$flag])) {
544
+ return $this->_options[$flag];
545
+ }
546
+ }
547
+ return null;
548
+ }
549
+
550
+ /**
551
+ * Return the arguments from the command-line following all options found.
552
+ *
553
+ * @return array
554
+ */
555
+ public function getRemainingArgs()
556
+ {
557
+ $this->parse();
558
+ return $this->_remainingArgs;
559
+ }
560
+
561
+ /**
562
+ * Return a useful option reference, formatted for display in an
563
+ * error message.
564
+ *
565
+ * Note that this usage information is provided in most Exceptions
566
+ * generated by this class.
567
+ *
568
+ * @return string
569
+ */
570
+ public function getUsageMessage()
571
+ {
572
+ $usage = "Usage: {$this->_progname} [ options ]\n";
573
+ $maxLen = 20;
574
+ foreach ($this->_rules as $rule) {
575
+ $flags = array();
576
+ if (is_array($rule['alias'])) {
577
+ foreach ($rule['alias'] as $flag) {
578
+ $flags[] = (strlen($flag) == 1 ? '-' : '--') . $flag;
579
+ }
580
+ }
581
+ $linepart['name'] = implode('|', $flags);
582
+ if (isset($rule['param']) && $rule['param'] != 'none') {
583
+ $linepart['name'] .= ' ';
584
+ switch ($rule['param']) {
585
+ case 'optional':
586
+ $linepart['name'] .= "[ <{$rule['paramType']}> ]";
587
+ break;
588
+ case 'required':
589
+ $linepart['name'] .= "<{$rule['paramType']}>";
590
+ break;
591
+ }
592
+ }
593
+ if (strlen($linepart['name']) > $maxLen) {
594
+ $maxLen = strlen($linepart['name']);
595
+ }
596
+ $linepart['help'] = '';
597
+ if (isset($rule['help'])) {
598
+ $linepart['help'] .= $rule['help'];
599
+ }
600
+ $lines[] = $linepart;
601
+ }
602
+ foreach ($lines as $linepart) {
603
+ $usage .= sprintf("%s %s\n",
604
+ str_pad($linepart['name'], $maxLen),
605
+ $linepart['help']);
606
+ }
607
+ return $usage;
608
+ }
609
+
610
+ /**
611
+ * Define aliases for options.
612
+ *
613
+ * The parameter $aliasMap is an associative array
614
+ * mapping option name (short or long) to an alias.
615
+ *
616
+ * @param array $aliasMap
617
+ * @throws Zend_Console_Getopt_Exception
618
+ * @return Zend_Console_Getopt Provides a fluent interface
619
+ */
620
+ public function setAliases($aliasMap)
621
+ {
622
+ foreach ($aliasMap as $flag => $alias)
623
+ {
624
+ if ($this->_getoptConfig[self::CONFIG_IGNORECASE]) {
625
+ $flag = strtolower($flag);
626
+ $alias = strtolower($alias);
627
+ }
628
+ if (!isset($this->_ruleMap[$flag])) {
629
+ continue;
630
+ }
631
+ $flag = $this->_ruleMap[$flag];
632
+ if (isset($this->_rules[$alias]) || isset($this->_ruleMap[$alias])) {
633
+ $o = (strlen($alias) == 1 ? '-' : '--') . $alias;
634
+ /**
635
+ * @see Zend_Console_Getopt_Exception
636
+ */
637
+ throw new Zend_Console_Getopt_Exception(
638
+ "Option \"$o\" is being defined more than once.");
639
+ }
640
+ $this->_rules[$flag]['alias'][] = $alias;
641
+ $this->_ruleMap[$alias] = $flag;
642
+ }
643
+ return $this;
644
+ }
645
+
646
+ /**
647
+ * Define help messages for options.
648
+ *
649
+ * The parameter $help_map is an associative array
650
+ * mapping option name (short or long) to the help string.
651
+ *
652
+ * @param array $helpMap
653
+ * @return Zend_Console_Getopt Provides a fluent interface
654
+ */
655
+ public function setHelp($helpMap)
656
+ {
657
+ foreach ($helpMap as $flag => $help)
658
+ {
659
+ if (!isset($this->_ruleMap[$flag])) {
660
+ continue;
661
+ }
662
+ $flag = $this->_ruleMap[$flag];
663
+ $this->_rules[$flag]['help'] = $help;
664
+ }
665
+ return $this;
666
+ }
667
+
668
+ /**
669
+ * Parse command-line arguments and find both long and short
670
+ * options.
671
+ *
672
+ * Also find option parameters, and remaining arguments after
673
+ * all options have been parsed.
674
+ *
675
+ * @return Zend_Console_Getopt|null Provides a fluent interface
676
+ */
677
+ public function parse()
678
+ {
679
+ if ($this->_parsed === true) {
680
+ return;
681
+ }
682
+ $argv = $this->_argv;
683
+ $this->_options = array();
684
+ $this->_remainingArgs = array();
685
+ while (count($argv) > 0) {
686
+ if ($argv[0] == '--') {
687
+ array_shift($argv);
688
+ if ($this->_getoptConfig[self::CONFIG_DASHDASH]) {
689
+ $this->_remainingArgs = array_merge($this->_remainingArgs, $argv);
690
+ break;
691
+ }
692
+ }
693
+ if (substr($argv[0], 0, 2) == '--') {
694
+ $this->_parseLongOption($argv);
695
+ } else if (substr($argv[0], 0, 1) == '-') {
696
+ $this->_parseShortOptionCluster($argv);
697
+ } else {
698
+ $this->_remainingArgs[] = array_shift($argv);
699
+ }
700
+ }
701
+ $this->_parsed = true;
702
+ return $this;
703
+ }
704
+
705
+ /**
706
+ * Parse command-line arguments for a single long option.
707
+ * A long option is preceded by a double '--' character.
708
+ * Long options may not be clustered.
709
+ *
710
+ * @param mixed &$argv
711
+ * @return void
712
+ */
713
+ protected function _parseLongOption(&$argv)
714
+ {
715
+ $optionWithParam = ltrim(array_shift($argv), '-');
716
+ $l = explode('=', $optionWithParam);
717
+ $flag = array_shift($l);
718
+ $param = array_shift($l);
719
+ if (isset($param)) {
720
+ array_unshift($argv, $param);
721
+ }
722
+ $this->_parseSingleOption($flag, $argv);
723
+ }
724
+
725
+ /**
726
+ * Parse command-line arguments for short options.
727
+ * Short options are those preceded by a single '-' character.
728
+ * Short options may be clustered.
729
+ *
730
+ * @param mixed &$argv
731
+ * @return void
732
+ */
733
+ protected function _parseShortOptionCluster(&$argv)
734
+ {
735
+ $flagCluster = ltrim(array_shift($argv), '-');
736
+ foreach (str_split($flagCluster) as $flag) {
737
+ $this->_parseSingleOption($flag, $argv);
738
+ }
739
+ }
740
+
741
+ /**
742
+ * Parse command-line arguments for a single option.
743
+ *
744
+ * @param string $flag
745
+ * @param mixed $argv
746
+ * @throws Zend_Console_Getopt_Exception
747
+ * @return void
748
+ */
749
+ protected function _parseSingleOption($flag, &$argv)
750
+ {
751
+ if ($this->_getoptConfig[self::CONFIG_IGNORECASE]) {
752
+ $flag = strtolower($flag);
753
+ }
754
+ if (!isset($this->_ruleMap[$flag])) {
755
+ /**
756
+ * @see Zend_Console_Getopt_Exception
757
+ */
758
+ throw new Zend_Console_Getopt_Exception(
759
+ "Option \"$flag\" is not recognized.",
760
+ $this->getUsageMessage());
761
+ }
762
+ $realFlag = $this->_ruleMap[$flag];
763
+ switch ($this->_rules[$realFlag]['param']) {
764
+ case 'required':
765
+ if (count($argv) > 0) {
766
+ $param = array_shift($argv);
767
+ $this->_checkParameterType($realFlag, $param);
768
+ } else {
769
+ /**
770
+ * @see Zend_Console_Getopt_Exception
771
+ */
772
+ throw new Zend_Console_Getopt_Exception(
773
+ "Option \"$flag\" requires a parameter.",
774
+ $this->getUsageMessage());
775
+ }
776
+ break;
777
+ case 'optional':
778
+ if (count($argv) > 0 && substr($argv[0], 0, 1) != '-') {
779
+ $param = array_shift($argv);
780
+ $this->_checkParameterType($realFlag, $param);
781
+ } else {
782
+ $param = true;
783
+ }
784
+ break;
785
+ default:
786
+ $param = true;
787
+ }
788
+ $this->_options[$realFlag] = $param;
789
+ }
790
+
791
+ /**
792
+ * Return true if the parameter is in a valid format for
793
+ * the option $flag.
794
+ * Throw an exception in most other cases.
795
+ *
796
+ * @param string $flag
797
+ * @param string $param
798
+ * @throws Zend_Console_Getopt_Exception
799
+ * @return bool
800
+ */
801
+ protected function _checkParameterType($flag, $param)
802
+ {
803
+ $type = 'string';
804
+ if (isset($this->_rules[$flag]['paramType'])) {
805
+ $type = $this->_rules[$flag]['paramType'];
806
+ }
807
+ switch ($type) {
808
+ case 'word':
809
+ if (preg_match('/\W/', $param)) {
810
+ /**
811
+ * @see Zend_Console_Getopt_Exception
812
+ */
813
+ throw new Zend_Console_Getopt_Exception(
814
+ "Option \"$flag\" requires a single-word parameter, but was given \"$param\".",
815
+ $this->getUsageMessage());
816
+ }
817
+ break;
818
+ case 'integer':
819
+ if (preg_match('/\D/', $param)) {
820
+ /**
821
+ * @see Zend_Console_Getopt_Exception
822
+ */
823
+ throw new Zend_Console_Getopt_Exception(
824
+ "Option \"$flag\" requires an integer parameter, but was given \"$param\".",
825
+ $this->getUsageMessage());
826
+ }
827
+ break;
828
+ case 'string':
829
+ default:
830
+ break;
831
+ }
832
+ return true;
833
+ }
834
+
835
+ /**
836
+ * Define legal options using the gnu-style format.
837
+ *
838
+ * @param string $rules
839
+ * @return void
840
+ */
841
+ protected function _addRulesModeGnu($rules)
842
+ {
843
+ $ruleArray = array();
844
+
845
+ /**
846
+ * Options may be single alphanumeric characters.
847
+ * Options may have a ':' which indicates a required string parameter.
848
+ * No long options or option aliases are supported in GNU style.
849
+ */
850
+ preg_match_all('/([a-zA-Z0-9]:?)/', $rules, $ruleArray);
851
+ foreach ($ruleArray[1] as $rule) {
852
+ $r = array();
853
+ $flag = substr($rule, 0, 1);
854
+ if ($this->_getoptConfig[self::CONFIG_IGNORECASE]) {
855
+ $flag = strtolower($flag);
856
+ }
857
+ $r['alias'][] = $flag;
858
+ if (substr($rule, 1, 1) == ':') {
859
+ $r['param'] = 'required';
860
+ $r['paramType'] = 'string';
861
+ } else {
862
+ $r['param'] = 'none';
863
+ }
864
+ $this->_rules[$flag] = $r;
865
+ $this->_ruleMap[$flag] = $flag;
866
+ }
867
+ }
868
+
869
+ /**
870
+ * Define legal options using the Zend-style format.
871
+ *
872
+ * @param array $rules
873
+ * @throws Zend_Console_Getopt_Exception
874
+ * @return void
875
+ */
876
+ protected function _addRulesModeZend($rules)
877
+ {
878
+ foreach ($rules as $ruleCode => $helpMessage)
879
+ {
880
+ $tokens = preg_split('/([=-])/',
881
+ $ruleCode, 2, PREG_SPLIT_DELIM_CAPTURE);
882
+ $flagList = array_shift($tokens);
883
+ $delimiter = array_shift($tokens);
884
+ $paramType = array_shift($tokens);
885
+ if ($this->_getoptConfig[self::CONFIG_IGNORECASE]) {
886
+ $flagList = strtolower($flagList);
887
+ }
888
+ $flags = explode('|', $flagList);
889
+ $rule = array();
890
+ $mainFlag = $flags[0];
891
+ foreach ($flags as $flag) {
892
+ if (empty($flag)) {
893
+ /**
894
+ * @see Zend_Console_Getopt_Exception
895
+ */
896
+ throw new Zend_Console_Getopt_Exception(
897
+ "Blank flag not allowed in rule \"$ruleCode\".");
898
+ }
899
+ if (strlen($flag) == 1) {
900
+ if (isset($this->_ruleMap[$flag])) {
901
+ /**
902
+ * @see Zend_Console_Getopt_Exception
903
+ */
904
+ throw new Zend_Console_Getopt_Exception(
905
+ "Option \"-$flag\" is being defined more than once.");
906
+ }
907
+ $this->_ruleMap[$flag] = $mainFlag;
908
+ $rule['alias'][] = $flag;
909
+ } else {
910
+ if (isset($this->_rules[$flag]) || isset($this->_ruleMap[$flag])) {
911
+ /**
912
+ * @see Zend_Console_Getopt_Exception
913
+ */
914
+ throw new Zend_Console_Getopt_Exception(
915
+ "Option \"--$flag\" is being defined more than once.");
916
+ }
917
+ $this->_ruleMap[$flag] = $mainFlag;
918
+ $rule['alias'][] = $flag;
919
+ }
920
+ }
921
+ if (isset($delimiter)) {
922
+ switch ($delimiter) {
923
+ case self::PARAM_REQUIRED:
924
+ $rule['param'] = 'required';
925
+ break;
926
+ case self::PARAM_OPTIONAL:
927
+ default:
928
+ $rule['param'] = 'optional';
929
+ }
930
+ switch (substr($paramType, 0, 1)) {
931
+ case self::TYPE_WORD:
932
+ $rule['paramType'] = 'word';
933
+ break;
934
+ case self::TYPE_INTEGER:
935
+ $rule['paramType'] = 'integer';
936
+ break;
937
+ case self::TYPE_STRING:
938
+ default:
939
+ $rule['paramType'] = 'string';
940
+ }
941
+ } else {
942
+ $rule['param'] = 'none';
943
+ }
944
+ $rule['help'] = $helpMessage;
945
+ $this->_rules[$mainFlag] = $rule;
946
+ }
947
+ }
948
+
949
+ }
lib/Zend/Console/Getopt/Exception.php ADDED
@@ -0,0 +1,65 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Zend Framework
4
+ *
5
+ * LICENSE
6
+ *
7
+ * This source file is subject to the new BSD license that is bundled
8
+ * with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://framework.zend.com/license/new-bsd
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@zend.com so we can send you a copy immediately.
14
+ *
15
+ * @category Zend
16
+ * @package Zend_Console_Getopt
17
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
18
+ * @license http://framework.zend.com/license/new-bsd New BSD License
19
+ */
20
+
21
+
22
+ /**
23
+ * @see Zend_Console_Getopt_Exception
24
+ */
25
+ require_once 'Zend/Exception.php';
26
+
27
+
28
+ /**
29
+ * @category Zend
30
+ * @package Zend_Console_Getopt
31
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
32
+ * @license http://framework.zend.com/license/new-bsd New BSD License
33
+ */
34
+ class Zend_Console_Getopt_Exception extends Zend_Exception
35
+ {
36
+ /**
37
+ * Usage
38
+ *
39
+ * @var string
40
+ */
41
+ protected $usage = '';
42
+
43
+ /**
44
+ * Constructor
45
+ *
46
+ * @param string $message
47
+ * @param string $usage
48
+ * @return void
49
+ */
50
+ public function __construct($message, $usage = '')
51
+ {
52
+ $this->usage = $usage;
53
+ parent::__construct($message);
54
+ }
55
+
56
+ /**
57
+ * Returns the usage
58
+ *
59
+ * @return string
60
+ */
61
+ public function getUsageMessage()
62
+ {
63
+ return $this->usage;
64
+ }
65
+ }
lib/Zend/Controller/Action.php ADDED
@@ -0,0 +1,677 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Zend Framework
4
+ *
5
+ * LICENSE
6
+ *
7
+ * This source file is subject to the new BSD license that is bundled
8
+ * with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://framework.zend.com/license/new-bsd
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@zend.com so we can send you a copy immediately.
14
+ *
15
+ * @category Zend
16
+ * @package Zend_Controller
17
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
18
+ * @license http://framework.zend.com/license/new-bsd New BSD License
19
+ */
20
+
21
+
22
+ /** Zend_Controller_Exception */
23
+ require_once 'Zend/Controller/Action/Exception.php';
24
+
25
+ /** Zend_Controller_Action_HelperBroker */
26
+ require_once 'Zend/Controller/Action/HelperBroker.php';
27
+
28
+ /** Zend_Controller_Front */
29
+ require_once 'Zend/Controller/Front.php';
30
+
31
+ /** Zend_Controller_Request_Abstract */
32
+ require_once 'Zend/Controller/Request/Abstract.php';
33
+
34
+ /** Zend_Controller_Response_Abstract */
35
+ require_once 'Zend/Controller/Response/Abstract.php';
36
+
37
+
38
+ /**
39
+ * @category Zend
40
+ * @package Zend_Controller
41
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
42
+ * @license http://framework.zend.com/license/new-bsd New BSD License
43
+ */
44
+ abstract class Zend_Controller_Action
45
+ {
46
+ /**
47
+ * Word delimiters (used for normalizing view script paths)
48
+ * @var array
49
+ */
50
+ protected $_delimiters;
51
+
52
+ /**
53
+ * Array of arguments provided to the constructor, minus the
54
+ * {@link $_request Request object}.
55
+ * @var array
56
+ */
57
+ protected $_invokeArgs = array();
58
+
59
+ /**
60
+ * Front controller instance
61
+ * @var Zend_Controller_Front
62
+ */
63
+ protected $_frontController;
64
+
65
+ /**
66
+ * Zend_Controller_Request_Abstract object wrapping the request environment
67
+ * @var Zend_Controller_Request_Abstract
68
+ */
69
+ protected $_request = null;
70
+
71
+ /**
72
+ * Zend_Controller_Response_Abstract object wrapping the response
73
+ * @var Zend_Controller_Response_Abstract
74
+ */
75
+ protected $_response = null;
76
+
77
+ /**
78
+ * View script suffix; defaults to 'phtml'
79
+ * @see {render()}
80
+ * @var string
81
+ */
82
+ public $viewSuffix = 'phtml';
83
+
84
+ /**
85
+ * View object
86
+ * @var Zend_View_Interface
87
+ */
88
+ public $view;
89
+
90
+ /**
91
+ * Helper Broker to assist in routing help requests to the proper object
92
+ *
93
+ * @var Zend_Controller_Action_HelperBroker
94
+ */
95
+ protected $_helper = null;
96
+
97
+ /**
98
+ * Class constructor
99
+ *
100
+ * The request and response objects should be registered with the
101
+ * controller, as should be any additional optional arguments; these will be
102
+ * available via {@link getRequest()}, {@link getResponse()}, and
103
+ * {@link getInvokeArgs()}, respectively.
104
+ *
105
+ * When overriding the constructor, please consider this usage as a best
106
+ * practice and ensure that each is registered appropriately; the easiest
107
+ * way to do so is to simply call parent::__construct($request, $response,
108
+ * $invokeArgs).
109
+ *
110
+ * After the request, response, and invokeArgs are set, the
111
+ * {@link $_helper helper broker} is initialized.
112
+ *
113
+ * Finally, {@link init()} is called as the final action of
114
+ * instantiation, and may be safely overridden to perform initialization
115
+ * tasks; as a general rule, override {@link init()} instead of the
116
+ * constructor to customize an action controller's instantiation.
117
+ *
118
+ * @param Zend_Controller_Request_Abstract $request
119
+ * @param Zend_Controller_Response_Abstract $response
120
+ * @param array $invokeArgs Any additional invocation arguments
121
+ * @return void
122
+ */
123
+ public function __construct(Zend_Controller_Request_Abstract $request, Zend_Controller_Response_Abstract $response, array $invokeArgs = array())
124
+ {
125
+ $this->setRequest($request)
126
+ ->setResponse($response)
127
+ ->_setInvokeArgs($invokeArgs);
128
+ $this->_helper = new Zend_Controller_Action_HelperBroker($this);
129
+ $this->init();
130
+ }
131
+
132
+ /**
133
+ * Initialize object
134
+ *
135
+ * Called from {@link __construct()} as final step of object instantiation.
136
+ *
137
+ * @return void
138
+ */
139
+ public function init()
140
+ {
141
+ }
142
+
143
+ /**
144
+ * Initialize View object
145
+ *
146
+ * Initializes {@link $view} if not otherwise a Zend_View_Interface.
147
+ *
148
+ * If {@link $view} is not otherwise set, instantiates a new Zend_View
149
+ * object, using the 'views' subdirectory at the same level as the
150
+ * controller directory for the current module as the base directory.
151
+ * It uses this to set the following:
152
+ * - script path = views/scripts/
153
+ * - helper path = views/helpers/
154
+ * - filter path = views/filters/
155
+ *
156
+ * @return Zend_View_Interface
157
+ * @throws Zend_Controller_Exception if base view directory does not exist
158
+ */
159
+ public function initView()
160
+ {
161
+ if (!$this->getInvokeArg('noViewRenderer') && $this->_helper->hasHelper('viewRenderer')) {
162
+ return $this->view;
163
+ }
164
+
165
+ require_once 'Zend/View/Interface.php';
166
+ if (isset($this->view) && ($this->view instanceof Zend_View_Interface)) {
167
+ return $this->view;
168
+ }
169
+
170
+ $request = $this->getRequest();
171
+ $module = $request->getModuleName();
172
+ $dirs = $this->getFrontController()->getControllerDirectory();
173
+ if (empty($module) || !isset($dirs[$module])) {
174
+ $module = $this->getFrontController()->getDispatcher()->getDefaultModule();
175
+ }
176
+ $baseDir = dirname($dirs[$module]) . DIRECTORY_SEPARATOR . 'views';
177
+ if (!file_exists($baseDir) || !is_dir($baseDir)) {
178
+ throw new Zend_Controller_Exception('Missing base view directory ("' . $baseDir . '")');
179
+ }
180
+
181
+ require_once 'Zend/View.php';
182
+ $this->view = new Zend_View(array('basePath' => $baseDir));
183
+
184
+ return $this->view;
185
+ }
186
+
187
+ /**
188
+ * Render a view
189
+ *
190
+ * Renders a view. By default, views are found in the view script path as
191
+ * <controller>/<action>.phtml. You may change the script suffix by
192
+ * resetting {@link $viewSuffix}. You may omit the controller directory
193
+ * prefix by specifying boolean true for $noController.
194
+ *
195
+ * By default, the rendered contents are appended to the response. You may
196
+ * specify the named body content segment to set by specifying a $name.
197
+ *
198
+ * @see Zend_Controller_Response_Abstract::appendBody()
199
+ * @param string|null $action Defaults to action registered in request object
200
+ * @param string|null $name Response object named path segment to use; defaults to null
201
+ * @param bool $noController Defaults to false; i.e. use controller name as subdir in which to search for view script
202
+ * @return void
203
+ */
204
+ public function render($action = null, $name = null, $noController = false)
205
+ {
206
+ if (!$this->getInvokeArg('noViewRenderer') && $this->_helper->hasHelper('viewRenderer')) {
207
+ return $this->_helper->viewRenderer->render($action, $name, $noController);
208
+ }
209
+
210
+ $view = $this->initView();
211
+ $script = $this->getViewScript($action, $noController);
212
+
213
+ $this->getResponse()->appendBody(
214
+ $view->render($script),
215
+ $name
216
+ );
217
+ }
218
+
219
+ /**
220
+ * Render a given view script
221
+ *
222
+ * Similar to {@link render()}, this method renders a view script. Unlike render(),
223
+ * however, it does not autodetermine the view script via {@link getViewScript()},
224
+ * but instead renders the script passed to it. Use this if you know the
225
+ * exact view script name and path you wish to use, or if using paths that do not
226
+ * conform to the spec defined with getViewScript().
227
+ *
228
+ * By default, the rendered contents are appended to the response. You may
229
+ * specify the named body content segment to set by specifying a $name.
230
+ *
231
+ * @param string $script
232
+ * @param string $name
233
+ * @return void
234
+ */
235
+ public function renderScript($script, $name = null)
236
+ {
237
+ if (!$this->getInvokeArg('noViewRenderer') && $this->_helper->hasHelper('viewRenderer')) {
238
+ return $this->_helper->viewRenderer->renderScript($script, $name);
239
+ }
240
+
241
+ $view = $this->initView();
242
+ $this->getResponse()->appendBody(
243
+ $view->render($script),
244
+ $name
245
+ );
246
+ }
247
+
248
+ /**
249
+ * Construct view script path
250
+ *
251
+ * Used by render() to determine the path to the view script.
252
+ *
253
+ * @param string $action Defaults to action registered in request object
254
+ * @param bool $noController Defaults to false; i.e. use controller name as subdir in which to search for view script
255
+ * @return string
256
+ * @throws Zend_Controller_Exception with bad $action
257
+ */
258
+ public function getViewScript($action = null, $noController = null)
259
+ {
260
+ if (!$this->getInvokeArg('noViewRenderer') && $this->_helper->hasHelper('viewRenderer')) {
261
+ $viewRenderer = $this->_helper->getHelper('viewRenderer');
262
+ if (null !== $noController) {
263
+ $viewRenderer->setNoController($noController);
264
+ }
265
+ return $viewRenderer->getViewScript($action);
266
+ }
267
+
268
+ $request = $this->getRequest();
269
+ if (null === $action) {
270
+ $action = $request->getActionName();
271
+ } elseif (!is_string($action)) {
272
+ throw new Zend_Controller_Exception('Invalid action specifier for view render');
273
+ }
274
+
275
+ if (null === $this->_delimiters) {
276
+ $dispatcher = Zend_Controller_Front::getInstance()->getDispatcher();
277
+ $wordDelimiters = $dispatcher->getWordDelimiter();
278
+ $pathDelimiters = $dispatcher->getPathDelimiter();
279
+ $this->_delimiters = array_unique(array_merge($wordDelimiters, (array) $pathDelimiters));
280
+ }
281
+
282
+ $action = str_replace($this->_delimiters, '-', $action);
283
+ $script = $action . '.' . $this->viewSuffix;
284
+
285
+ if (!$noController) {
286
+ $controller = $request->getControllerName();
287
+ $controller = str_replace($this->_delimiters, '-', $controller);
288
+ $script = $controller . DIRECTORY_SEPARATOR . $script;
289
+ }
290
+
291
+ return $script;
292
+ }
293
+
294
+ /**
295
+ * Return the Request object
296
+ *
297
+ * @return Zend_Controller_Request_Abstract
298
+ */
299
+ public function getRequest()
300
+ {
301
+ return $this->_request;
302
+ }
303
+
304
+ /**
305
+ * Set the Request object
306
+ *
307
+ * @param Zend_Controller_Request_Abstract $request
308
+ * @return Zend_Controller_Action
309
+ */
310
+ public function setRequest(Zend_Controller_Request_Abstract $request)
311
+ {
312
+ $this->_request = $request;
313
+ return $this;
314
+ }
315
+
316
+ /**
317
+ * Return the Response object
318
+ *
319
+ * @return Zend_Controller_Response_Abstract
320
+ */
321
+ public function getResponse()
322
+ {
323
+ return $this->_response;
324
+ }
325
+
326
+ /**
327
+ * Set the Response object
328
+ *
329
+ * @param Zend_Controller_Response_Abstract $response
330
+ * @return Zend_Controller_Action
331
+ */
332
+ public function setResponse(Zend_Controller_Response_Abstract $response)
333
+ {
334
+ $this->_response = $response;
335
+ return $this;
336
+ }
337
+
338
+ /**
339
+ * Set invocation arguments
340
+ *
341
+ * @param array $args
342
+ * @return Zend_Controller_Action
343
+ */
344
+ protected function _setInvokeArgs(array $args = array())
345
+ {
346
+ $this->_invokeArgs = $args;
347
+ return $this;
348
+ }
349
+
350
+ /**
351
+ * Return the array of constructor arguments (minus the Request object)
352
+ *
353
+ * @return array
354
+ */
355
+ public function getInvokeArgs()
356
+ {
357
+ return $this->_invokeArgs;
358
+ }
359
+
360
+ /**
361
+ * Return a single invocation argument
362
+ *
363
+ * @param string $key
364
+ * @return mixed
365
+ */
366
+ public function getInvokeArg($key)
367
+ {
368
+ if (isset($this->_invokeArgs[$key])) {
369
+ return $this->_invokeArgs[$key];
370
+ }
371
+
372
+ return null;
373
+ }
374
+
375
+ /**
376
+ * Get a helper by name
377
+ *
378
+ * @param string $helperName
379
+ * @return Zend_Controller_Action_Helper_Abstract
380
+ */
381
+ public function getHelper($helperName)
382
+ {
383
+ return $this->_helper->{$helperName};
384
+ }
385
+
386
+ /**
387
+ * Get a clone of a helper by name
388
+ *
389
+ * @param string $helperName
390
+ * @return Zend_Controller_Action_Helper_Abstract
391
+ */
392
+ public function getHelperCopy($helperName)
393
+ {
394
+ return clone $this->_helper->{$helperName};
395
+ }
396
+
397
+ /**
398
+ * Set the front controller instance
399
+ *
400
+ * @param Zend_Controller_Front $front
401
+ * @return Zend_Controller_Action
402
+ */
403
+ public function setFrontController(Zend_Controller_Front $front)
404
+ {
405
+ $this->_frontController = $front;
406
+ return $this;
407
+ }
408
+
409
+ /**
410
+ * Retrieve Front Controller
411
+ *
412
+ * @return Zend_Controller_Front
413
+ */
414
+ public function getFrontController()
415
+ {
416
+ // Used cache version if found
417
+ if (null !== $this->_frontController) {
418
+ return $this->_frontController;
419
+ }
420
+
421
+ // Grab singleton instance, if class has been loaded
422
+ if (class_exists('Zend_Controller_Front')) {
423
+ $this->_frontController = Zend_Controller_Front::getInstance();
424
+ return $this->_frontController;
425
+ }
426
+
427
+ // Throw exception in all other cases
428
+ require_once 'Zend/Controller/Exception.php';
429
+ throw new Zend_Controller_Exception('Front controller class has not been loaded');
430
+ }
431
+
432
+ /**
433
+ * Pre-dispatch routines
434
+ *
435
+ * Called before action method. If using class with
436
+ * {@link Zend_Controller_Front}, it may modify the
437
+ * {@link $_request Request object} and reset its dispatched flag in order
438
+ * to skip processing the current action.
439
+ *
440
+ * @return void
441
+ */
442
+ public function preDispatch()
443
+ {
444
+ }
445
+
446
+ /**
447
+ * Post-dispatch routines
448
+ *
449
+ * Called after action method execution. If using class with
450
+ * {@link Zend_Controller_Front}, it may modify the
451
+ * {@link $_request Request object} and reset its dispatched flag in order
452
+ * to process an additional action.
453
+ *
454
+ * Common usages for postDispatch() include rendering content in a sitewide
455
+ * template, link url correction, setting headers, etc.
456
+ *
457
+ * @return void
458
+ */
459
+ public function postDispatch()
460
+ {
461
+ }
462
+
463
+ /**
464
+ * Proxy for undefined methods. Default behavior is to throw an
465
+ * exception on undefined methods, however this function can be
466
+ * overridden to implement magic (dynamic) actions, or provide run-time
467
+ * dispatching.
468
+ *
469
+ * @param string $methodName
470
+ * @param array $args
471
+ */
472
+ public function __call($methodName, $args)
473
+ {
474
+ if ('Action' == substr($methodName, -6)) {
475
+ require_once 'Zend/Controller/Action/Exception.php';
476
+ $action = substr($methodName, 0, strlen($methodName) - 6);
477
+ throw new Zend_Controller_Action_Exception(sprintf('Action "%s" does not exist and was not trapped in __call()', $action), 404);
478
+ }
479
+
480
+ require_once 'Zend/Controller/Action/Exception.php';
481
+ throw new Zend_Controller_Action_Exception(sprintf('Method "%s" does not exist and was not trapped in __call()', $methodName), 500);
482
+ }
483
+
484
+ /**
485
+ * Dispatch the requested action
486
+ *
487
+ * @param string $action Method name of action
488
+ * @return void
489
+ */
490
+ public function dispatch($action)
491
+ {
492
+ // Notify helpers of action preDispatch state
493
+ $this->_helper->notifyPreDispatch();
494
+
495
+ $this->preDispatch();
496
+ if ($this->getRequest()->isDispatched()) {
497
+ // preDispatch() didn't change the action, so we can continue
498
+ if ($this->getInvokeArg('useCaseSensitiveActions') || in_array($action, get_class_methods($this))) {
499
+ if ($this->getInvokeArg('useCaseSensitiveActions')) {
500
+ trigger_error('Using case sensitive actions without word separators is deprecated; please do not rely on this "feature"');
501
+ }
502
+ $this->$action();
503
+ } else {
504
+ $this->__call($action, array());
505
+ }
506
+ $this->postDispatch();
507
+ }
508
+
509
+ // whats actually important here is that this action controller is
510
+ // shutting down, regardless of dispatching; notify the helpers of this
511
+ // state
512
+ $this->_helper->notifyPostDispatch();
513
+ }
514
+
515
+ /**
516
+ * Call the action specified in the request object, and return a response
517
+ *
518
+ * Not used in the Action Controller implementation, but left for usage in
519
+ * Page Controller implementations. Dispatches a method based on the
520
+ * request.
521
+ *
522
+ * Returns a Zend_Controller_Response_Abstract object, instantiating one
523
+ * prior to execution if none exists in the controller.
524
+ *
525
+ * {@link preDispatch()} is called prior to the action,
526
+ * {@link postDispatch()} is called following it.
527
+ *
528
+ * @param null|Zend_Controller_Request_Abstract $request Optional request
529
+ * object to use
530
+ * @param null|Zend_Controller_Response_Abstract $response Optional response
531
+ * object to use
532
+ * @return Zend_Controller_Response_Abstract
533
+ */
534
+ public function run(Zend_Controller_Request_Abstract $request = null, Zend_Controller_Response_Abstract $response = null)
535
+ {
536
+ if (null !== $request) {
537
+ $this->setRequest($request);
538
+ } else {
539
+ $request = $this->getRequest();
540
+ }
541
+
542
+ if (null !== $response) {
543
+ $this->setResponse($response);
544
+ }
545
+
546
+ $action = $request->getActionName();
547
+ if (empty($action)) {
548
+ $action = 'index';
549
+ }
550
+ $action = $action . 'Action';
551
+
552
+ $request->setDispatched(true);
553
+ $this->dispatch($action);
554
+
555
+ return $this->getResponse();
556
+ }
557
+
558
+ /**
559
+ * Gets a parameter from the {@link $_request Request object}. If the
560
+ * parameter does not exist, NULL will be returned.
561
+ *
562
+ * If the parameter does not exist and $default is set, then
563
+ * $default will be returned instead of NULL.
564
+ *
565
+ * @param string $paramName
566
+ * @param mixed $default
567
+ * @return mixed
568
+ */
569
+ final protected function _getParam($paramName, $default = null)
570
+ {
571
+ $value = $this->getRequest()->getParam($paramName);
572
+ if ((null == $value) && (null !== $default)) {
573
+ $value = $default;
574
+ }
575
+
576
+ return $value;
577
+ }
578
+
579
+ /**
580
+ * Set a parameter in the {@link $_request Request object}.
581
+ *
582
+ * @param string $paramName
583
+ * @param mixed $value
584
+ * @return Zend_Controller_Action
585
+ */
586
+ final protected function _setParam($paramName, $value)
587
+ {
588
+ $this->getRequest()->setParam($paramName, $value);
589
+
590
+ return $this;
591
+ }
592
+
593
+ /**
594
+ * Determine whether a given parameter exists in the
595
+ * {@link $_request Request object}.
596
+ *
597
+ * @param string $paramName
598
+ * @return boolean
599
+ */
600
+ final protected function _hasParam($paramName)
601
+ {
602
+ return null !== $this->getRequest()->getParam($paramName);
603
+ }
604
+
605
+ /**
606
+ * Return all parameters in the {@link $_request Request object}
607
+ * as an associative array.
608
+ *
609
+ * @return array
610
+ */
611
+ final protected function _getAllParams()
612
+ {
613
+ return $this->getRequest()->getParams();
614
+ }
615
+
616
+
617
+ /**
618
+ * Forward to another controller/action.
619
+ *
620
+ * It is important to supply the unformatted names, i.e. "article"
621
+ * rather than "ArticleController". The dispatcher will do the
622
+ * appropriate formatting when the request is received.
623
+ *
624
+ * If only an action name is provided, forwards to that action in this
625
+ * controller.
626
+ *
627
+ * If an action and controller are specified, forwards to that action and
628
+ * controller in this module.
629
+ *
630
+ * Specifying an action, controller, and module is the most specific way to
631
+ * forward.
632
+ *
633
+ * A fourth argument, $params, will be used to set the request parameters.
634
+ * If either the controller or module are unnecessary for forwarding,
635
+ * simply pass null values for them before specifying the parameters.
636
+ *
637
+ * @param string $action
638
+ * @param string $controller
639
+ * @param string $module
640
+ * @param array $params
641
+ * @return void
642
+ */
643
+ final protected function _forward($action, $controller = null, $module = null, array $params = null)
644
+ {
645
+ $request = $this->getRequest();
646
+
647
+ if (null !== $params) {
648
+ $request->setParams($params);
649
+ }
650
+
651
+ if (null !== $controller) {
652
+ $request->setControllerName($controller);
653
+
654
+ // Module should only be reset if controller has been specified
655
+ if (null !== $module) {
656
+ $request->setModuleName($module);
657
+ }
658
+ }
659
+
660
+ $request->setActionName($action)
661
+ ->setDispatched(false);
662
+ }
663
+
664
+ /**
665
+ * Redirect to another URL
666
+ *
667
+ * Proxies to {@link Zend_Controller_Action_Helper_Redirector::gotoUrl()}.
668
+ *
669
+ * @param string $url
670
+ * @param array $options Options to be used when redirecting
671
+ * @return void
672
+ */
673
+ protected function _redirect($url, array $options = array())
674
+ {
675
+ $this->_helper->redirector->gotoUrl($url, $options);
676
+ }
677
+ }
lib/Zend/Controller/Action/Exception.php ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Zend Framework
4
+ *
5
+ * LICENSE
6
+ *
7
+ * This source file is subject to the new BSD license that is bundled
8
+ * with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://framework.zend.com/license/new-bsd
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@zend.com so we can send you a copy immediately.
14
+ *
15
+ * @category Zend
16
+ * @package Zend_Controller
17
+ * @subpackage Zend_Controller_Action
18
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
19
+ * @license http://framework.zend.com/license/new-bsd New BSD License
20
+ */
21
+
22
+
23
+ /**
24
+ * @see Zend_Controller_Exception
25
+ */
26
+ require_once 'Zend/Controller/Exception.php';
27
+
28
+
29
+ /**
30
+ * @category Zend
31
+ * @package Zend_Controller
32
+ * @subpackage Zend_Controller_Action
33
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
34
+ * @license http://framework.zend.com/license/new-bsd New BSD License
35
+ */
36
+ class Zend_Controller_Action_Exception extends Zend_Controller_Exception
37
+ {}
lib/Zend/Controller/Action/Helper/Abstract.php ADDED
@@ -0,0 +1,164 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Zend Framework
4
+ *
5
+ * LICENSE
6
+ *
7
+ * This source file is subject to the new BSD license that is bundled
8
+ * with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://framework.zend.com/license/new-bsd
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@zend.com so we can send you a copy immediately.
14
+ *
15
+ * @category Zend
16
+ * @package Zend_Controller
17
+ * @subpackage Zend_Controller_Action_Helper
18
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
19
+ * @license http://framework.zend.com/license/new-bsd New BSD License
20
+ */
21
+
22
+
23
+ /**
24
+ * @see Zend_Controller_Exception
25
+ */
26
+ require_once 'Zend/Controller/Action/Exception.php';
27
+
28
+ /**
29
+ * @see Zend_Controller_Action
30
+ */
31
+ require_once 'Zend/Controller/Action.php';
32
+
33
+
34
+ /**
35
+ * @category Zend
36
+ * @package Zend_Controller
37
+ * @subpackage Zend_Controller_Action_Helper
38
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
39
+ * @license http://framework.zend.com/license/new-bsd New BSD License
40
+ */
41
+ abstract class Zend_Controller_Action_Helper_Abstract
42
+ {
43
+ /**
44
+ * $_actionController
45
+ *
46
+ * @var Zend_Controller_Action $_actionController
47
+ */
48
+ protected $_actionController = null;
49
+
50
+ /**
51
+ * @var mixed $_frontController
52
+ */
53
+ protected $_frontController = null;
54
+
55
+ /**
56
+ * setActionController()
57
+ *
58
+ * @param Zend_Controller_Action $actionController
59
+ * @return Zend_Controller_ActionHelper_Abstract Provides a fluent interface
60
+ */
61
+ public function setActionController(Zend_Controller_Action $actionController = null)
62
+ {
63
+ $this->_actionController = $actionController;
64
+ return $this;
65
+ }
66
+
67
+ /**
68
+ * Retrieve current action controller
69
+ *
70
+ * @return Zend_Controller_Action
71
+ */
72
+ public function getActionController()
73
+ {
74
+ return $this->_actionController;
75
+ }
76
+
77
+ /**
78
+ * Retrieve front controller instance
79
+ *
80
+ * @return Zend_Controller_Front
81
+ */
82
+ public function getFrontController()
83
+ {
84
+ if (null === $this->_frontController) {
85
+ $this->_frontController = Zend_Controller_Front::getInstance();
86
+ }
87
+
88
+ return $this->_frontController;
89
+ }
90
+
91
+ /**
92
+ * Hook into action controller initialization
93
+ *
94
+ * @return void
95
+ */
96
+ public function init()
97
+ {
98
+ }
99
+
100
+ /**
101
+ * Hook into action controller preDispatch() workflow
102
+ *
103
+ * @return void
104
+ */
105
+ public function preDispatch()
106
+ {
107
+ }
108
+
109
+ /**
110
+ * Hook into action controller postDispatch() workflow
111
+ *
112
+ * @return void
113
+ */
114
+ public function postDispatch()
115
+ {
116
+ }
117
+
118
+ /**
119
+ * getRequest() -
120
+ *
121
+ * @return Zend_Controller_Request_Abstract $request
122
+ */
123
+ public function getRequest()
124
+ {
125
+ $controller = $this->getActionController();
126
+ if (null === $controller) {
127
+ $controller = $this->getFrontController();
128
+ }
129
+
130
+ return $controller->getRequest();
131
+ }
132
+
133
+ /**
134
+ * getResponse() -
135
+ *
136
+ * @return Zend_Controller_Response_Abstract $response
137
+ */
138
+ public function getResponse()
139
+ {
140
+ $controller = $this->getActionController();
141
+ if (null === $controller) {
142
+ $controller = $this->getFrontController();
143
+ }
144
+
145
+ return $controller->getResponse();
146
+ }
147
+
148
+ /**
149
+ * getName()
150
+ *
151
+ * @return string
152
+ */
153
+ public function getName()
154
+ {
155
+ $full_class_name = get_class($this);
156
+
157
+ if (strpos($full_class_name, '_') !== false) {
158
+ $helper_name = strrchr($full_class_name, '_');
159
+ return ltrim($helper_name, '_');
160
+ } else {
161
+ return $full_class_name;
162
+ }
163
+ }
164
+ }
lib/Zend/Controller/Action/Helper/ActionStack.php ADDED
@@ -0,0 +1,143 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Zend Framework
4
+ *
5
+ * LICENSE
6
+ *
7
+ * This source file is subject to version 1.0 of the Zend Framework
8
+ * license, that is bundled with this package in the file LICENSE.txt, and
9
+ * is available through the world-wide-web at the following URL:
10
+ * http://framework.zend.com/license/new-bsd. If you did not receive
11
+ * a copy of the Zend Framework license and are unable to obtain it
12
+ * through the world-wide-web, please send a note to license@zend.com
13
+ * so we can mail you a copy immediately.
14
+ *
15
+ * @category Zend
16
+ * @package Zend_Controller
17
+ * @subpackage Zend_Controller_Action_Helper
18
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
19
+ * @version $Id: ActionStack.php 8892 2008-03-18 19:47:46Z thomas $
20
+ * @license http://framework.zend.com/license/new-bsd New BSD License
21
+ */
22
+
23
+ /**
24
+ * @see Zend_Controller_Action_Helper_Abstract
25
+ */
26
+ require_once 'Zend/Controller/Action/Helper/Abstract.php';
27
+
28
+ /**
29
+ * @see Zend_Registry
30
+ */
31
+ require_once 'Zend/Registry.php';
32
+
33
+ /**
34
+ * Add to action stack
35
+ *
36
+ * @uses Zend_Controller_Action_Helper_Abstract
37
+ * @category Zend
38
+ * @package Zend_Controller
39
+ * @subpackage Zend_Controller_Action_Helper
40
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
41
+ * @license http://framework.zend.com/license/new-bsd New BSD License
42
+ */
43
+ class Zend_Controller_Action_Helper_ActionStack extends Zend_Controller_Action_Helper_Abstract
44
+ {
45
+ /**
46
+ * @var Zend_Controller_Plugin_ActionStack
47
+ */
48
+ protected $_actionStack;
49
+
50
+ /**
51
+ * Constructor
52
+ *
53
+ * Register action stack plugin
54
+ *
55
+ * @return void
56
+ */
57
+ public function __construct()
58
+ {
59
+ $front = Zend_Controller_Front::getInstance();
60
+ if (!$front->hasPlugin('Zend_Controller_Plugin_ActionStack')) {
61
+ /**
62
+ * @see Zend_Controller_Plugin_ActionStack
63
+ */
64
+ require_once 'Zend/Controller/Plugin/ActionStack.php';
65
+ $this->_actionStack = new Zend_Controller_Plugin_ActionStack();
66
+ $front->registerPlugin($this->_actionStack, 97);
67
+ } else {
68
+ $this->_actionStack = $front->getPlugin('Zend_Controller_Plugin_ActionStack');
69
+ }
70
+ }
71
+
72
+ /**
73
+ * Push onto the stack
74
+ *
75
+ * @param Zend_Controller_Request_Abstract $next
76
+ * @return Zend_Controller_Action_Helper_ActionStack Provides a fluent interface
77
+ */
78
+ public function pushStack(Zend_Controller_Request_Abstract $next)
79
+ {
80
+ $this->_actionStack->pushStack($next);
81
+ return $this;
82
+ }
83
+
84
+ /**
85
+ * Push a new action onto the stack
86
+ *
87
+ * @param string $action
88
+ * @param string $controller
89
+ * @param string $module
90
+ * @param array $params
91
+ * @throws Zend_Controller_Action_Exception
92
+ * @return Zend_Controller_Action_Helper_ActionStack
93
+ */
94
+ public function actionToStack($action, $controller = null, $module = null, array $params = array())
95
+ {
96
+ if ($action instanceof Zend_Controller_Request_Abstract) {
97
+ return $this->pushStack($action);
98
+ } elseif (!is_string($action)) {
99
+ /**
100
+ * @see Zend_Controller_Action_Exception
101
+ */
102
+ require_once 'Zend/Controller/Action/Exception.php';
103
+ throw new Zend_Controller_Action_Exception('ActionStack requires either a request object or minimally a string action');
104
+ }
105
+
106
+ $request = $this->getRequest();
107
+
108
+ if ($request instanceof Zend_Controller_Request_Abstract === false){
109
+ /**
110
+ * @see Zend_Controller_Action_Exception
111
+ */
112
+ require_once 'Zend/Controller/Action/Exception.php';
113
+ throw new Zend_Controller_Action_Exception('Request object not set yet');
114
+ }
115
+
116
+ $controller = (null === $controller) ? $request->getControllerName() : $controller;
117
+ $module = (null === $module) ? $request->getModuleName() : $module;
118
+
119
+ /**
120
+ * @see Zend_Controller_Request_Simple
121
+ */
122
+ require_once 'Zend/Controller/Request/Simple.php';
123
+ $newRequest = new Zend_Controller_Request_Simple($action, $controller, $module, $params);
124
+
125
+ return $this->pushStack($newRequest);
126
+ }
127
+
128
+ /**
129
+ * Perform helper when called as $this->_helper->actionStack() from an action controller
130
+ *
131
+ * Proxies to {@link simple()}
132
+ *
133
+ * @param string $action
134
+ * @param string $controller
135
+ * @param string $module
136
+ * @param array $params
137
+ * @return boolean
138
+ */
139
+ public function direct($action, $controller = null, $module = null, array $params = array())
140
+ {
141
+ return $this->actionToStack($action, $controller, $module, $params);
142
+ }
143
+ }
lib/Zend/Controller/Action/Helper/AjaxContext.php ADDED
@@ -0,0 +1,77 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Zend Framework
4
+ *
5
+ * LICENSE
6
+ *
7
+ * This source file is subject to version 1.0 of the Zend Framework
8
+ * license, that is bundled with this package in the file LICENSE.txt, and
9
+ * is available through the world-wide-web at the following URL:
10
+ * http://framework.zend.com/license/new-bsd. If you did not receive
11
+ * a copy of the Zend Framework license and are unable to obtain it
12
+ * through the world-wide-web, please send a note to license@zend.com
13
+ * so we can mail you a copy immediately.
14
+ *
15
+ * @category Zend
16
+ * @package Zend_Controller
17
+ * @subpackage Zend_Controller_Action_Helper
18
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
19
+ * @version $Id: AjaxContext.php 8892 2008-03-18 19:47:46Z thomas $
20
+ * @license http://framework.zend.com/license/new-bsd New BSD License
21
+ */
22
+
23
+ /**
24
+ * @see Zend_Controller_Action_Helper_ContextSwitch
25
+ */
26
+ require_once 'Zend/Controller/Action/Helper/ContextSwitch.php';
27
+
28
+ /**
29
+ * Simplify AJAX context switching based on requested format
30
+ *
31
+ * @uses Zend_Controller_Action_Helper_Abstract
32
+ * @category Zend
33
+ * @package Zend_Controller
34
+ * @subpackage Zend_Controller_Action_Helper
35
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
36
+ * @license http://framework.zend.com/license/new-bsd New BSD License
37
+ */
38
+ class Zend_Controller_Action_Helper_AjaxContext extends Zend_Controller_Action_Helper_ContextSwitch
39
+ {
40
+ /**
41
+ * Controller property to utilize for context switching
42
+ * @var string
43
+ */
44
+ protected $_contextKey = 'ajaxable';
45
+
46
+ /**
47
+ * Constructor
48
+ *
49
+ * Add HTML context
50
+ *
51
+ * @return void
52
+ */
53
+ public function __construct()
54
+ {
55
+ parent::__construct();
56
+ $this->addContext('html', array('suffix' => 'ajax'));
57
+ }
58
+
59
+ /**
60
+ * Initialize AJAX context switching
61
+ *
62
+ * Checks for XHR requests; if detected, attempts to perform context switch.
63
+ *
64
+ * @param string $format
65
+ * @return void
66
+ */
67
+ public function initContext($format = null)
68
+ {
69
+ $this->_currentContext = null;
70
+
71
+ if (!$this->getRequest()->isXmlHttpRequest()) {
72
+ return;
73
+ }
74
+
75
+ return parent::initContext($format);
76
+ }
77
+ }
lib/Zend/Controller/Action/Helper/AutoComplete/Abstract.php ADDED
@@ -0,0 +1,149 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Zend Framework
4
+ *
5
+ * LICENSE
6
+ *
7
+ * This source file is subject to version 1.0 of the Zend Framework
8
+ * license, that is bundled with this package in the file LICENSE.txt, and
9
+ * is available through the world-wide-web at the following URL:
10
+ * http://framework.zend.com/license/new-bsd. If you did not receive
11
+ * a copy of the Zend Framework license and are unable to obtain it
12
+ * through the world-wide-web, please send a note to license@zend.com
13
+ * so we can mail you a copy immediately.
14
+ *
15
+ * @category Zend
16
+ * @package Zend_Controller
17
+ * @subpackage Zend_Controller_Action_Helper
18
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
19
+ * @version $Id: Abstract.php 8892 2008-03-18 19:47:46Z thomas $
20
+ * @license http://framework.zend.com/license/new-bsd New BSD License
21
+ */
22
+
23
+ /**
24
+ * @see Zend_Controller_Action_Helper_Abstract
25
+ */
26
+ require_once 'Zend/Controller/Action/Helper/Abstract.php';
27
+
28
+ /**
29
+ * Create and send autocompletion lists
30
+ *
31
+ * @uses Zend_Controller_Action_Helper_Abstract
32
+ * @category Zend
33
+ * @package Zend_Controller
34
+ * @subpackage Zend_Controller_Action_Helper
35
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
36
+ * @license http://framework.zend.com/license/new-bsd New BSD License
37
+ */
38
+ abstract class Zend_Controller_Action_Helper_AutoComplete_Abstract extends Zend_Controller_Action_Helper_Abstract
39
+ {
40
+ /**
41
+ * Suppress exit when sendJson() called
42
+ *
43
+ * @var boolean
44
+ */
45
+ public $suppressExit = false;
46
+
47
+ /**
48
+ * Validate autocompletion data
49
+ *
50
+ * @param mixed $data
51
+ * @return boolean
52
+ */
53
+ abstract public function validateData($data);
54
+
55
+ /**
56
+ * Prepare autocompletion data
57
+ *
58
+ * @param mixed $data
59
+ * @param boolean $keepLayouts
60
+ * @return mixed
61
+ */
62
+ abstract public function prepareAutoCompletion($data, $keepLayouts = false);
63
+
64
+ /**
65
+ * Disable layouts and view renderer
66
+ *
67
+ * @return Zend_Controller_Action_Helper_AutoComplete_Abstract Provides a fluent interface
68
+ */
69
+ public function disableLayouts()
70
+ {
71
+ /**
72
+ * @see Zend_Layout
73
+ */
74
+ require_once 'Zend/Layout.php';
75
+ if (null !== ($layout = Zend_Layout::getMvcInstance())) {
76
+ $layout->disableLayout();
77
+ }
78
+
79
+ Zend_Controller_Action_HelperBroker::getStaticHelper('viewRenderer')->setNoRender(true);
80
+
81
+ return $this;
82
+ }
83
+
84
+ /**
85
+ * Encode data to JSON
86
+ *
87
+ * @param mixed $data
88
+ * @param bool $keepLayouts
89
+ * @throws Zend_Controller_Action_Exception
90
+ * @return string
91
+ */
92
+ public function encodeJson($data, $keepLayouts = false)
93
+ {
94
+ if ($this->validateData($data)) {
95
+ return Zend_Controller_Action_HelperBroker::getStaticHelper('Json')->encodeJson($data, $keepLayouts);
96
+ }
97
+
98
+ /**
99
+ * @see Zend_Controller_Action_Exception
100
+ */
101
+ require_once 'Zend/Controller/Action/Exception.php';
102
+ throw new Zend_Controller_Action_Exception('Invalid data passed for autocompletion');
103
+ }
104
+
105
+ /**
106
+ * Send autocompletion data
107
+ *
108
+ * Calls prepareAutoCompletion, populates response body with this
109
+ * information, and sends response.
110
+ *
111
+ * @param mixed $data
112
+ * @param bool $keepLayouts
113
+ * @return string|void
114
+ */
115
+ public function sendAutoCompletion($data, $keepLayouts = false)
116
+ {
117
+ $data = $this->prepareAutoCompletion($data, $keepLayouts);
118
+
119
+ $response = $this->getResponse();
120
+ $response->setBody($data);
121
+
122
+ if (!$this->suppressExit) {
123
+ $response->sendResponse();
124
+ exit;
125
+ }
126
+
127
+ return $data;
128
+ }
129
+
130
+ /**
131
+ * Strategy pattern: allow calling helper as broker method
132
+ *
133
+ * Prepares autocompletion data and, if $sendNow is true, immediately sends
134
+ * response.
135
+ *
136
+ * @param mixed $data
137
+ * @param bool $sendNow
138
+ * @param bool $keepLayouts
139
+ * @return string|void
140
+ */
141
+ public function direct($data, $sendNow = true, $keepLayouts = false)
142
+ {
143
+ if ($sendNow) {
144
+ return $this->sendAutoCompletion($data, $keepLayouts);
145
+ }
146
+
147
+ return $this->prepareAutoCompletion($data, $keepLayouts);
148
+ }
149
+ }
lib/Zend/Controller/Action/Helper/AutoCompleteDojo.php ADDED
@@ -0,0 +1,74 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Zend Framework
4
+ *
5
+ * LICENSE
6
+ *
7
+ * This source file is subject to version 1.0 of the Zend Framework
8
+ * license, that is bundled with this package in the file LICENSE.txt, and
9
+ * is available through the world-wide-web at the following URL:
10
+ * http://framework.zend.com/license/new-bsd. If you did not receive
11
+ * a copy of the Zend Framework license and are unable to obtain it
12
+ * through the world-wide-web, please send a note to license@zend.com
13
+ * so we can mail you a copy immediately.
14
+ *
15
+ * @category Zend
16
+ * @package Zend_Controller
17
+ * @subpackage Zend_Controller_Action_Helper
18
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
19
+ * @version $Id: AutoCompleteDojo.php 8892 2008-03-18 19:47:46Z thomas $
20
+ * @license http://framework.zend.com/license/new-bsd New BSD License
21
+ */
22
+
23
+ /**
24
+ * @see Zend_Controller_Action_Helper_AutoComplete_Abstract
25
+ */
26
+ require_once 'Zend/Controller/Action/Helper/AutoComplete/Abstract.php';
27
+
28
+ /**
29
+ * Create and send Dojo-compatible autocompletion lists
30
+ *
31
+ * @uses Zend_Controller_Action_Helper_AutoComplete_Abstract
32
+ * @category Zend
33
+ * @package Zend_Controller
34
+ * @subpackage Zend_Controller_Action_Helper
35
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
36
+ * @license http://framework.zend.com/license/new-bsd New BSD License
37
+ */
38
+ class Zend_Controller_Action_Helper_AutoCompleteDojo extends Zend_Controller_Action_Helper_AutoComplete_Abstract
39
+ {
40
+ /**
41
+ * Validate data for autocompletion
42
+ *
43
+ * @param mixed $data
44
+ * @return boolean
45
+ */
46
+ public function validateData($data)
47
+ {
48
+ if (is_array($data) && isset($data['items']) && is_array($data['items'])) {
49
+ return true;
50
+ }
51
+
52
+ return false;
53
+ }
54
+
55
+ /**
56
+ * Prepare data for autocompletion
57
+ *
58
+ * @param mixed $data
59
+ * @param boolean $keepLayouts
60
+ * @return string
61
+ */
62
+ public function prepareAutoCompletion($data, $keepLayouts = false)
63
+ {
64
+ $items = array();
65
+ foreach ($data as $key => $value) {
66
+ $items[] = array('label' => $value, 'name' => $value);
67
+ }
68
+ $final = array(
69
+ 'identifier' => 'name',
70
+ 'items' => $items,
71
+ );
72
+ return $this->encodeJson($final, $keepLayouts);
73
+ }
74
+ }
lib/Zend/Controller/Action/Helper/AutoCompleteScriptaculous.php ADDED
@@ -0,0 +1,82 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Zend Framework
4
+ *
5
+ * LICENSE
6
+ *
7
+ * This source file is subject to version 1.0 of the Zend Framework
8
+ * license, that is bundled with this package in the file LICENSE.txt, and
9
+ * is available through the world-wide-web at the following URL:
10
+ * http://framework.zend.com/license/new-bsd. If you did not receive
11
+ * a copy of the Zend Framework license and are unable to obtain it
12
+ * through the world-wide-web, please send a note to license@zend.com
13
+ * so we can mail you a copy immediately.
14
+ *
15
+ * @category Zend
16
+ * @package Zend_Controller
17
+ * @subpackage Zend_Controller_Action_Helper
18
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
19
+ * @version $Id: AutoCompleteScriptaculous.php 8892 2008-03-18 19:47:46Z thomas $
20
+ * @license http://framework.zend.com/license/new-bsd New BSD License
21
+ */
22
+
23
+ /**
24
+ * @see Zend_Controller_Action_Helper_AutoComplete_Abstract
25
+ */
26
+ require_once 'Zend/Controller/Action/Helper/AutoComplete/Abstract.php';
27
+
28
+ /**
29
+ * Create and send Scriptaculous-compatible autocompletion lists
30
+ *
31
+ * @uses Zend_Controller_Action_Helper_AutoComplete_Abstract
32
+ * @category Zend
33
+ * @package Zend_Controller
34
+ * @subpackage Zend_Controller_Action_Helper
35
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
36
+ * @license http://framework.zend.com/license/new-bsd New BSD License
37
+ */
38
+ class Zend_Controller_Action_Helper_AutoCompleteScriptaculous extends Zend_Controller_Action_Helper_AutoComplete_Abstract
39
+ {
40
+ /**
41
+ * Validate data for autocompletion
42
+ *
43
+ * @param mixed $data
44
+ * @return bool
45
+ */
46
+ public function validateData($data)
47
+ {
48
+ if (!is_array($data) && !is_scalar($data)) {
49
+ return false;
50
+ }
51
+
52
+ return true;
53
+ }
54
+
55
+ /**
56
+ * Prepare data for autocompletion
57
+ *
58
+ * @param mixed $data
59
+ * @param boolean $keepLayouts
60
+ * @throws Zend_Controller_Action_Exception
61
+ * @return string
62
+ */
63
+ public function prepareAutoCompletion($data, $keepLayouts = false)
64
+ {
65
+ if (!$this->validateData($data)) {
66
+ /**
67
+ * @see Zend_Controller_Action_Exception
68
+ */
69
+ require_once 'Zend/Controller/Action/Exception.php';
70
+ throw new Zend_Controller_Action_Exception('Invalid data passed for autocompletion');
71
+ }
72
+
73
+ $data = (array) $data;
74
+ $data = '<ul><li>' . implode('</li><li>', $data) . '</li></ul>';
75
+
76
+ if (!$keepLayouts) {
77
+ $this->disableLayouts();
78
+ }
79
+
80
+ return $data;
81
+ }
82
+ }
lib/Zend/Controller/Action/Helper/ContextSwitch.php ADDED
@@ -0,0 +1,1357 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Zend Framework
4
+ *
5
+ * LICENSE
6
+ *
7
+ * This source file is subject to version 1.0 of the Zend Framework
8
+ * license, that is bundled with this package in the file LICENSE.txt, and
9
+ * is available through the world-wide-web at the following URL:
10
+ * http://framework.zend.com/license/new-bsd. If you did not receive
11
+ * a copy of the Zend Framework license and are unable to obtain it
12
+ * through the world-wide-web, please send a note to license@zend.com
13
+ * so we can mail you a copy immediately.
14
+ *
15
+ * @category Zend
16
+ * @package Zend_Controller
17
+ * @subpackage Zend_Controller_Action_Helper
18
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
19
+ * @version $Id: ContextSwitch.php 8892 2008-03-18 19:47:46Z thomas $
20
+ * @license http://framework.zend.com/license/new-bsd New BSD License
21
+ */
22
+
23
+ /**
24
+ * @see Zend_Controller_Action_Helper_Abstract
25
+ */
26
+ require_once 'Zend/Controller/Action/Helper/Abstract.php';
27
+
28
+ /**
29
+ * Simplify context switching based on requested format
30
+ *
31
+ * @uses Zend_Controller_Action_Helper_Abstract
32
+ * @category Zend
33
+ * @package Zend_Controller
34
+ * @subpackage Zend_Controller_Action_Helper
35
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
36
+ * @license http://framework.zend.com/license/new-bsd New BSD License
37
+ */
38
+ class Zend_Controller_Action_Helper_ContextSwitch extends Zend_Controller_Action_Helper_Abstract
39
+ {
40
+ /**
41
+ * Trigger type constants
42
+ */
43
+ const TRIGGER_INIT = 'TRIGGER_INIT';
44
+ const TRIGGER_POST = 'TRIGGER_POST';
45
+
46
+ /**
47
+ * Supported contexts
48
+ * @var array
49
+ */
50
+ protected $_contexts = array();
51
+
52
+ /**
53
+ * JSON auto-serialization flag
54
+ * @var boolean
55
+ */
56
+ protected $_autoJsonSerialization = true;
57
+
58
+ /**
59
+ * Controller property key to utilize for context switching
60
+ * @var string
61
+ */
62
+ protected $_contextKey = 'contexts';
63
+
64
+ /**
65
+ * Request parameter containing requested context
66
+ * @var string
67
+ */
68
+ protected $_contextParam = 'format';
69
+
70
+ /**
71
+ * Current context
72
+ * @var string
73
+ */
74
+ protected $_currentContext;
75
+
76
+ /**
77
+ * Default context (xml)
78
+ * @var string
79
+ */
80
+ protected $_defaultContext = 'xml';
81
+
82
+ /**
83
+ * Whether or not to disable layouts when switching contexts
84
+ * @var boolean
85
+ */
86
+ protected $_disableLayout = true;
87
+
88
+ /**
89
+ * Methods that require special configuration
90
+ * @var array
91
+ */
92
+ protected $_specialConfig = array(
93
+ 'setSuffix',
94
+ 'setHeaders',
95
+ 'setCallbacks',
96
+ );
97
+
98
+ /**
99
+ * Methods that are not configurable via setOptions and setConfig
100
+ * @var array
101
+ */
102
+ protected $_unconfigurable = array(
103
+ 'setOptions',
104
+ 'setConfig',
105
+ 'setHeader',
106
+ 'setCallback',
107
+ 'setContext',
108
+ 'setActionContext',
109
+ 'setActionContexts',
110
+ );
111
+
112
+ /**
113
+ * @var Zend_Controller_Action_Helper_ViewRenderer
114
+ */
115
+ protected $_viewRenderer;
116
+
117
+ /**
118
+ * Constructor
119
+ *
120
+ * @param array|Zend_Config $options
121
+ * @return void
122
+ */
123
+ public function __construct($options = null)
124
+ {
125
+ if (empty($this->_contexts)) {
126
+ $this->addContexts(array(
127
+ 'json' => array(
128
+ 'suffix' => 'json',
129
+ 'headers' => array('Content-Type' => 'application/json'),
130
+ 'callbacks' => array(
131
+ 'init' => 'initJsonContext',
132
+ 'post' => 'postJsonContext'
133
+ )
134
+ ),
135
+ 'xml' => array(
136
+ 'suffix' => 'xml',
137
+ 'headers' => array('Content-Type' => 'text/xml'),
138
+ )
139
+ ));
140
+ }
141
+ }
142
+
143
+ /**
144
+ * Configure object from array of options
145
+ *
146
+ * @param array $options
147
+ * @return Zend_Controller_Action_Helper_ContextSwitch Provides a fluent interface
148
+ */
149
+ public function setOptions(array $options)
150
+ {
151
+ if (isset($options['contexts'])) {
152
+ $this->setContexts($options['contexts']);
153
+ unset($options['contexts']);
154
+ }
155
+
156
+ foreach ($options as $key => $value) {
157
+ $method = 'set' . ucfirst($key);
158
+ if (in_array($method, $this->_unconfigurable)) {
159
+ continue;
160
+ }
161
+
162
+ if (in_array($method, $this->_specialConfig)) {
163
+ $method = '_' . $method;
164
+ }
165
+
166
+ if (method_exists($this, $method)) {
167
+ $this->$method($value);
168
+ }
169
+ }
170
+ return $this;
171
+ }
172
+
173
+ /**
174
+ * Set object state from config object
175
+ *
176
+ * @param Zend_Config $config
177
+ * @return Zend_Controller_Action_Helper_ContextSwitch Provides a fluent interface
178
+ */
179
+ public function setConfig(Zend_Config $config)
180
+ {
181
+ return $this->setOptions($config->toArray());
182
+ }
183
+
184
+ /**
185
+ * Strategy pattern: return object
186
+ *
187
+ * @return Zend_Controller_Action_Helper_ContextSwitch Provides a fluent interface
188
+ */
189
+ public function direct()
190
+ {
191
+ return $this;
192
+ }
193
+
194
+ /**
195
+ * Initialize context detection and switching
196
+ *
197
+ * @param mixed $format
198
+ * @throws Zend_Controller_Action_Exception
199
+ * @return void
200
+ */
201
+ public function initContext($format = null)
202
+ {
203
+ $this->_currentContext = null;
204
+
205
+ $controller = $this->getActionController();
206
+ $request = $this->getRequest();
207
+ $action = $request->getActionName();
208
+
209
+ // Return if no context switching enabled, or no context switching
210
+ // enabled for this action
211
+ $contexts = $this->getActionContexts($action);
212
+ if (empty($contexts)) {
213
+ return;
214
+ }
215
+
216
+ // Return if no context parameter provided
217
+ if (!$context = $request->getParam($this->getContextParam())) {
218
+ if ($format === null) {
219
+ return;
220
+ }
221
+ $context = $format;
222
+ $format = null;
223
+ }
224
+
225
+ // Check if context allowed by action controller
226
+ if (!$this->hasActionContext($action, $context)) {
227
+ return;
228
+ }
229
+
230
+ // Return if invalid context parameter provided and no format or invalid
231
+ // format provided
232
+ if (!$this->hasContext($context)) {
233
+ if (empty($format) || !$this->hasContext($format)) {
234
+
235
+ return;
236
+ }
237
+ }
238
+
239
+ // Use provided format if passed
240
+ if (!empty($format) && $this->hasContext($format)) {
241
+ $context = $format;
242
+ }
243
+
244
+ $suffix = $this->getSuffix($context);
245
+ $this->_getViewRenderer()->setViewSuffix($suffix);
246
+
247
+ $headers = $this->getHeaders($context);
248
+ if (!empty($headers)) {
249
+ $response = $this->getResponse();
250
+ foreach ($headers as $header => $content) {
251
+ $response->setHeader($header, $content);
252
+ }
253
+ }
254
+
255
+ if ($this->getAutoDisableLayout()) {
256
+ /**
257
+ * @see Zend_Layout
258
+ */
259
+ require_once 'Zend/Layout.php';
260
+ $layout = Zend_Layout::getMvcInstance();
261
+ if (null !== $layout) {
262
+ $layout->disableLayout();
263
+ }
264
+ }
265
+
266
+ if (null !== ($callback = $this->getCallback($context, self::TRIGGER_INIT))) {
267
+ if (is_string($callback) && method_exists($this, $callback)) {
268
+ $this->$callback();
269
+ } elseif (is_string($callback) && function_exists($callback)) {
270
+ $callback();
271
+ } elseif (is_array($callback)) {
272
+ call_user_func($callback);
273
+ } else {
274
+ /**
275
+ * @see Zend_Controller_Action_Exception
276
+ */
277
+ require_once 'Zend/Controller/Action/Exception.php';
278
+ throw new Zend_Controller_Action_Exception(sprintf('Invalid context callback registered for context "%s"', $context));
279
+ }
280
+ }
281
+
282
+ $this->_currentContext = $context;
283
+ }
284
+
285
+ /**
286
+ * JSON context extra initialization
287
+ *
288
+ * Turns off viewRenderer auto-rendering
289
+ *
290
+ * @return void
291
+ */
292
+ public function initJsonContext()
293
+ {
294
+ if (!$this->getAutoJsonSerialization()) {
295
+ return;
296
+ }
297
+
298
+ $viewRenderer = Zend_Controller_Action_HelperBroker::getStaticHelper('viewRenderer');
299
+ $view = $viewRenderer->view;
300
+ if ($view instanceof Zend_View_Interface) {
301
+ $viewRenderer->setNoRender(true);
302
+ }
303
+ }
304
+
305
+ /**
306
+ * Should JSON contexts auto-serialize?
307
+ *
308
+ * @param boolean $flag
309
+ * @return Zend_Controller_Action_Helper_ContextSwitch Provides a fluent interface
310
+ */
311
+ public function setAutoJsonSerialization($flag)
312
+ {
313
+ $this->_autoJsonSerialization = (bool) $flag;
314
+ return $this;
315
+ }
316
+
317
+ /**
318
+ * Get JSON context auto-serialization flag
319
+ *
320
+ * @return boolean
321
+ */
322
+ public function getAutoJsonSerialization()
323
+ {
324
+ return $this->_autoJsonSerialization;
325
+ }
326
+
327
+ /**
328
+ * Set suffix from array
329
+ *
330
+ * @param array $spec
331
+ * @return Zend_Controller_Action_Helper_ContextSwitch Provides a fluent interface
332
+ */
333
+ protected function _setSuffix(array $spec)
334
+ {
335
+ foreach ($spec as $context => $suffixInfo) {
336
+ if (!is_string($context)) {
337
+ $context = null;
338
+ }
339
+
340
+ if (is_string($suffixInfo)) {
341
+ $this->setSuffix($context, $suffixInfo);
342
+ continue;
343
+ } elseif (is_array($suffixInfo)) {
344
+ if (isset($suffixInfo['suffix'])) {
345
+ $suffix = $suffixInfo['suffix'];
346
+ $prependViewRendererSuffix = true;
347
+
348
+ if ((null === $context) && isset($suffixInfo['context'])) {
349
+ $context = $suffixInfo['context'];
350
+ }
351
+
352
+ if (isset($suffixInfo['prependViewRendererSuffix'])) {
353
+ $prependViewRendererSuffix = $suffixInfo['prependViewRendererSuffix'];
354
+ }
355
+
356
+ $this->setSuffix($context, $suffix, $prependViewRendererSuffix);
357
+ continue;
358
+ }
359
+
360
+ $count = count($suffixInfo);
361
+ switch (true) {
362
+ case (($count < 2) && (null === $context)):
363
+ /**
364
+ * @see Zend_Controller_Action_Exception
365
+ */
366
+ require_once 'Zend/Controller/Action/Exception.php';
367
+ throw new Zend_Controller_Action_Exception('Invalid suffix information provided in config');
368
+ case ($count < 2):
369
+ $suffix = array_shift($suffixInfo);
370
+ $this->setSuffix($context, $suffix);
371
+ break;
372
+ case (($count < 3) && (null === $context)):
373
+ $context = array_shift($suffixInfo);
374
+ $suffix = array_shift($suffixInfo);
375
+ $this->setSuffix($context, $suffix);
376
+ break;
377
+ case (($count == 3) && (null === $context)):
378
+ $context = array_shift($suffixInfo);
379
+ $suffix = array_shift($suffixInfo);
380
+ $prependViewRendererSuffix = array_shift($suffixInfo);
381
+ $this->setSuffix($context, $suffix, $prependViewRendererSuffix);
382
+ break;
383
+ case ($count >= 2):
384
+ $suffix = array_shift($suffixInfo);
385
+ $prependViewRendererSuffix = array_shift($suffixInfo);
386
+ $this->setSuffix($context, $suffix, $prependViewRendererSuffix);
387
+ break;
388
+ }
389
+ }
390
+ }
391
+ return $this;
392
+ }
393
+
394
+ /**
395
+ * Customize view script suffix to use when switching context.
396
+ *
397
+ * Passing an empty suffix value to the setters disables the view script
398
+ * suffix change.
399
+ *
400
+ * @param string $context Context type for which to set suffix
401
+ * @param string $suffix Suffix to use
402
+ * @param boolean $prependViewRendererSuffix Whether or not to prepend the new suffix to the viewrenderer suffix
403
+ * @throws Zend_Controller_Action_Exception
404
+ * @return Zend_Controller_Action_Helper_ContextSwitch Provides a fluent interface
405
+ */
406
+ public function setSuffix($context, $suffix, $prependViewRendererSuffix = true)
407
+ {
408
+ if (!isset($this->_contexts[$context])) {
409
+ /**
410
+ * @see Zend_Controller_Action_Exception
411
+ */
412
+ require_once 'Zend/Controller/Action/Exception.php';
413
+ throw new Zend_Controller_Action_Exception(sprintf('Cannot set suffix; invalid context type "%s"', $context));
414
+ }
415
+
416
+ if (empty($suffix)) {
417
+ $suffix = '';
418
+ }
419
+
420
+ if (is_array($suffix)) {
421
+ if (isset($suffix['prependViewRendererSuffix'])) {
422
+ $prependViewRendererSuffix = $suffix['prependViewRendererSuffix'];
423
+ }
424
+ if (isset($suffix['suffix'])) {
425
+ $suffix = $suffix['suffix'];
426
+ } else {
427
+ $suffix = '';
428
+ }
429
+ }
430
+
431
+ $suffix = (string) $suffix;
432
+
433
+ if ($prependViewRendererSuffix) {
434
+ if (empty($suffix)) {
435
+ $suffix = $this->_getViewRenderer()->getViewSuffix();
436
+ } else {
437
+ $suffix .= '.' . $this->_getViewRenderer()->getViewSuffix();
438
+ }
439
+ }
440
+
441
+ $this->_contexts[$context]['suffix'] = $suffix;
442
+ return $this;
443
+ }
444
+
445
+ /**
446
+ * Retrieve suffix for given context type
447
+ *
448
+ * @param string $type Context type
449
+ * @throws Zend_Controller_Action_Exception
450
+ * @return string
451
+ */
452
+ public function getSuffix($type)
453
+ {
454
+ if (!isset($this->_contexts[$type])) {
455
+ /**
456
+ * @see Zend_Controller_Action_Exception
457
+ */
458
+ require_once 'Zend/Controller/Action/Exception.php';
459
+ throw new Zend_Controller_Action_Exception(sprintf('Cannot retrieve suffix; invalid context type "%s"', $type));
460
+ }
461
+
462
+ return $this->_contexts[$type]['suffix'];
463
+ }
464
+
465
+ /**
466
+ * Does the given context exist?
467
+ *
468
+ * @param string $context
469
+ * @param boolean $throwException
470
+ * @throws Zend_Controller_Action_Exception if context does not exist and throwException is true
471
+ * @return bool
472
+ */
473
+ public function hasContext($context, $throwException = false)
474
+ {
475
+ if (is_string($context)) {
476
+ if (isset($this->_contexts[$context])) {
477
+ return true;
478
+ }
479
+ } elseif (is_array($context)) {
480
+ $error = false;
481
+ foreach ($context as $test) {
482
+ if (!isset($this->_contexts[$test])) {
483
+ $error = (string) $test;
484
+ break;
485
+ }
486
+ }
487
+ if (false === $error) {
488
+ return true;
489
+ }
490
+ $context = $error;
491
+ } elseif (true === $context) {
492
+ return true;
493
+ }
494
+
495
+ if ($throwException) {
496
+ /**
497
+ * @see Zend_Controller_Action_Exception
498
+ */
499
+ require_once 'Zend/Controller/Action/Exception.php';
500
+ throw new Zend_Controller_Action_Exception(sprintf('Context "%s" does not exist', $context));
501
+ }
502
+
503
+ return false;
504
+ }
505
+
506
+ /**
507
+ * Add header to context
508
+ *
509
+ * @param string $context
510
+ * @param string $header
511
+ * @param string $content
512
+ * @throws Zend_Controller_Action_Exception
513
+ * @return Zend_Controller_Action_Helper_ContextSwitch Provides a fluent interface
514
+ */
515
+ public function addHeader($context, $header, $content)
516
+ {
517
+ $context = (string) $context;
518
+ $this->hasContext($context, true);
519
+
520
+ $header = (string) $header;
521
+ $content = (string) $content;
522
+
523
+ if (isset($this->_contexts[$context]['headers'][$header])) {
524
+ /**
525
+ * @see Zend_Controller_Action_Exception
526
+ */
527
+ require_once 'Zend/Controller/Action/Exception.php';
528
+ throw new Zend_Controller_Action_Exception(sprintf('Cannot add "%s" header to context "%s": already exists', $header, $context));
529
+ }
530
+
531
+ $this->_contexts[$context]['headers'][$header] = $content;
532
+ return $this;
533
+ }
534
+
535
+ /**
536
+ * Customize response header to use when switching context
537
+ *
538
+ * Passing an empty header value to the setters disables the response
539
+ * header.
540
+ *
541
+ * @param string $type Context type for which to set suffix
542
+ * @param string $header Header to set
543
+ * @param string $content Header content
544
+ * @return Zend_Controller_Action_Helper_ContextSwitch Provides a fluent interface
545
+ */
546
+ public function setHeader($context, $header, $content)
547
+ {
548
+ $this->hasContext($context, true);
549
+ $context = (string) $context;
550
+ $header = (string) $header;
551
+ $content = (string) $content;
552
+
553
+ $this->_contexts[$context]['headers'][$header] = $content;
554
+ return $this;
555
+ }
556
+
557
+ /**
558
+ * Add multiple headers at once for a given context
559
+ *
560
+ * @param string $context
561
+ * @param array $headers
562
+ * @return Zend_Controller_Action_Helper_ContextSwitch Provides a fluent interface
563
+ */
564
+ public function addHeaders($context, array $headers)
565
+ {
566
+ foreach ($headers as $header => $content) {
567
+ $this->addHeader($context, $header, $content);
568
+ }
569
+
570
+ return $this;
571
+ }
572
+
573
+ /**
574
+ * Set headers from context => headers pairs
575
+ *
576
+ * @param array $options
577
+ * @return Zend_Controller_Action_Helper_ContextSwitch Provides a fluent interface
578
+ */
579
+ protected function _setHeaders(array $options)
580
+ {
581
+ foreach ($options as $context => $headers) {
582
+ if (!is_array($headers)) {
583
+ continue;
584
+ }
585
+ $this->setHeaders($context, $headers);
586
+ }
587
+
588
+ return $this;
589
+ }
590
+
591
+ /**
592
+ * Set multiple headers at once for a given context
593
+ *
594
+ * @param string $context
595
+ * @param array $headers
596
+ * @return Zend_Controller_Action_Helper_ContextSwitch Provides a fluent interface
597
+ */
598
+ public function setHeaders($context, array $headers)
599
+ {
600
+ $this->clearHeaders($context);
601
+ foreach ($headers as $header => $content) {
602
+ $this->setHeader($context, $header, $content);
603
+ }
604
+
605
+ return $this;
606
+ }
607
+
608
+ /**
609
+ * Retrieve context header
610
+ *
611
+ * Returns the value of a given header for a given context type
612
+ *
613
+ * @param string $context
614
+ * @param string $header
615
+ * @return string|null
616
+ */
617
+ public function getHeader($context, $header)
618
+ {
619
+ $this->hasContext($context, true);
620
+ $context = (string) $context;
621
+ $header = (string) $header;
622
+ if (isset($this->_contexts[$context]['headers'][$header])) {
623
+ return $this->_contexts[$context]['headers'][$header];
624
+ }
625
+
626
+ return null;
627
+ }
628
+
629
+ /**
630
+ * Retrieve context headers
631
+ *
632
+ * Returns all headers for a context as key/value pairs
633
+ *
634
+ * @param string $context
635
+ * @return array
636
+ */
637
+ public function getHeaders($context)
638
+ {
639
+ $this->hasContext($context, true);
640
+ $context = (string) $context;
641
+ return $this->_contexts[$context]['headers'];
642
+ }
643
+
644
+ /**
645
+ * Remove a single header from a context
646
+ *
647
+ * @param string $context
648
+ * @param string $header
649
+ * @return boolean
650
+ */
651
+ public function removeHeader($context, $header)
652
+ {
653
+ $this->hasContext($context, true);
654
+ $context = (string) $context;
655
+ $header = (string) $header;
656
+ if (isset($this->_contexts[$context]['headers'][$header])) {
657
+ unset($this->_contexts[$context]['headers'][$header]);
658
+ return true;
659
+ }
660
+
661
+ return false;
662
+ }
663
+
664
+ /**
665
+ * Clear all headers for a given context
666
+ *
667
+ * @param string $context
668
+ * @return Zend_Controller_Action_Helper_ContextSwitch Provides a fluent interface
669
+ */
670
+ public function clearHeaders($context)
671
+ {
672
+ $this->hasContext($context, true);
673
+ $context = (string) $context;
674
+ $this->_contexts[$context]['headers'] = array();
675
+ return $this;
676
+ }
677
+
678
+ /**
679
+ * Validate trigger and return in normalized form
680
+ *
681
+ * @param string $trigger
682
+ * @throws Zend_Controller_Action_Exception
683
+ * @return string
684
+ */
685
+ protected function _validateTrigger($trigger)
686
+ {
687
+ $trigger = strtoupper($trigger);
688
+ if ('TRIGGER_' !== substr($trigger, 0, 8)) {
689
+ $trigger = 'TRIGGER_' . $trigger;
690
+ }
691
+
692
+ if (!in_array($trigger, array(self::TRIGGER_INIT, self::TRIGGER_POST))) {
693
+ /**
694
+ * @see Zend_Controller_Action_Exception
695
+ */
696
+ require_once 'Zend/Controller/Action/Exception.php';
697
+ throw new Zend_Controller_Action_Exception(sprintf('Invalid trigger "%s"', $trigger));
698
+ }
699
+
700
+ return $trigger;
701
+ }
702
+
703
+ /**
704
+ * Set a callback for a given context and trigger
705
+ *
706
+ * @param string $context
707
+ * @param string $trigger
708
+ * @param string|array $callback
709
+ * @throws Zend_Controller_Action_Exception
710
+ * @return Zend_Controller_Action_Helper_ContextSwitch Provides a fluent interface
711
+ */
712
+ public function setCallback($context, $trigger, $callback)
713
+ {
714
+ $this->hasContext($context, true);
715
+ $trigger = $this->_validateTrigger($trigger);
716
+
717
+ if (!is_string($callback)) {
718
+ if (!is_array($callback) || (2 != count($callback))) {
719
+ /**
720
+ * @see Zend_Controller_Action_Exception
721
+ */
722
+ require_once 'Zend/Controller/Action/Exception.php';
723
+ throw new Zend_Controller_Action_Exception('Invalid callback specified');
724
+ }
725
+ }
726
+
727
+ $this->_contexts[$context]['callbacks'][$trigger] = $callback;
728
+ return $this;
729
+ }
730
+
731
+ /**
732
+ * Set callbacks from array of context => callbacks pairs
733
+ *
734
+ * @param array $options
735
+ * @return Zend_Controller_Action_Helper_ContextSwitch Provides a fluent interface
736
+ */
737
+ protected function _setCallbacks(array $options)
738
+ {
739
+ foreach ($options as $context => $callbacks) {
740
+ if (!is_array($callbacks)) {
741
+ continue;
742
+ }
743
+
744
+ $this->setCallbacks($context, $callbacks);
745
+ }
746
+ return $this;
747
+ }
748
+
749
+ /**
750
+ * Set callbacks for a given context
751
+ *
752
+ * Callbacks should be in trigger/callback pairs.
753
+ *
754
+ * @param string $context
755
+ * @param array $callbacks
756
+ * @return Zend_Controller_Action_Helper_ContextSwitch Provides a fluent interface
757
+ */
758
+ public function setCallbacks($context, array $callbacks)
759
+ {
760
+ $this->hasContext($context, true);
761
+ $context = (string) $context;
762
+ if (!isset($this->_contexts[$context]['callbacks'])) {
763
+ $this->_contexts[$context]['callbacks'] = array();
764
+ }
765
+
766
+ foreach ($callbacks as $trigger => $callback) {
767
+ $this->setCallback($context, $trigger, $callback);
768
+ }
769
+ return $this;
770
+ }
771
+
772
+ /**
773
+ * Get a single callback for a given context and trigger
774
+ *
775
+ * @param string $context
776
+ * @param string $trigger
777
+ * @return string|array|null
778
+ */
779
+ public function getCallback($context, $trigger)
780
+ {
781
+ $this->hasContext($context, true);
782
+ $trigger = $this->_validateTrigger($trigger);
783
+ if (isset($this->_contexts[$context]['callbacks'][$trigger])) {
784
+ return $this->_contexts[$context]['callbacks'][$trigger];
785
+ }
786
+
787
+ return null;
788
+ }
789
+
790
+ /**
791
+ * Get all callbacks for a given context
792
+ *
793
+ * @param string $context
794
+ * @return array
795
+ */
796
+ public function getCallbacks($context)
797
+ {
798
+ $this->hasContext($context, true);
799
+ return $this->_contexts[$context]['callbacks'];
800
+ }
801
+
802
+ /**
803
+ * Clear a callback for a given context and trigger
804
+ *
805
+ * @param string $context
806
+ * @param string $trigger
807
+ * @return boolean
808
+ */
809
+ public function removeCallback($context, $trigger)
810
+ {
811
+ $this->hasContext($context, true);
812
+ $trigger = $this->_validateTrigger($trigger);
813
+ if (isset($this->_contexts[$context]['callbacks'][$trigger])) {
814
+ unset($this->_contexts[$context]['callbacks'][$trigger]);
815
+ return true;
816
+ }
817
+
818
+ return false;
819
+ }
820
+
821
+ /**
822
+ * Clear all callbacks for a given context
823
+ *
824
+ * @param string $context
825
+ * @return Zend_Controller_Action_Helper_ContextSwitch Provides a fluent interface
826
+ */
827
+ public function clearCallbacks($context)
828
+ {
829
+ $this->hasContext($context, true);
830
+ $this->_contexts[$context]['callbacks'] = array();
831
+ return $this;
832
+ }
833
+
834
+ /**
835
+ * Set name of parameter to use when determining context format
836
+ *
837
+ * @param string $name
838
+ * @return Zend_Controller_Action_Helper_ContextSwitch Provides a fluent interface
839
+ */
840
+ public function setContextParam($name)
841
+ {
842
+ $this->_contextParam = (string) $name;
843
+ return $this;
844
+ }
845
+
846
+ /**
847
+ * Return context format request parameter name
848
+ *
849
+ * @return string
850
+ */
851
+ public function getContextParam()
852
+ {
853
+ return $this->_contextParam;
854
+ }
855
+
856
+ /**
857
+ * Indicate default context to use when no context format provided
858
+ *
859
+ * @param string $type
860
+ * @throws Zend_Controller_Action_Exception
861
+ * @return Zend_Controller_Action_Helper_ContextSwitch Provides a fluent interface
862
+ */
863
+ public function setDefaultContext($type)
864
+ {
865
+ if (!isset($this->_contexts[$type])) {
866
+ /**
867
+ * @see Zend_Controller_Action_Exception
868
+ */
869
+ require_once 'Zend/Controller/Action/Exception.php';
870
+ throw new Zend_Controller_Action_Exception(sprintf('Cannot set default context; invalid context type "%s"', $type));
871
+ }
872
+
873
+ $this->_defaultContext = $type;
874
+ return $this;
875
+ }
876
+
877
+ /**
878
+ * Return default context
879
+ *
880
+ * @return string
881
+ */
882
+ public function getDefaultContext()
883
+ {
884
+ return $this->_defaultContext;
885
+ }
886
+
887
+ /**
888
+ * Set flag indicating if layout should be disabled
889
+ *
890
+ * @param boolean $flag
891
+ * @return Zend_Controller_Action_Helper_ContextSwitch Provides a fluent interface
892
+ */
893
+ public function setAutoDisableLayout($flag)
894
+ {
895
+ $this->_disableLayout = ($flag) ? true : false;
896
+ return $this;
897
+ }
898
+
899
+ /**
900
+ * Retrieve auto layout disable flag
901
+ *
902
+ * @return boolean
903
+ */
904
+ public function getAutoDisableLayout()
905
+ {
906
+ return $this->_disableLayout;
907
+ }
908
+
909
+ /**
910
+ * Add new context
911
+ *
912
+ * @param string $context Context type
913
+ * @param array $spec Context specification
914
+ * @throws Zend_Controller_Action_Exception
915
+ * @return Zend_Controller_Action_Helper_ContextSwitch Provides a fluent interface
916
+ */
917
+ public function addContext($context, array $spec)
918
+ {
919
+ if ($this->hasContext($context)) {
920
+ /**
921
+ * @see Zend_Controller_Action_Exception
922
+ */
923
+ require_once 'Zend/Controller/Action/Exception.php';
924
+ throw new Zend_Controller_Action_Exception(sprintf('Cannot add context "%s"; already exists', $context));
925
+ }
926
+ $context = (string) $context;
927
+
928
+ $this->_contexts[$context] = array();
929
+
930
+ $this->setSuffix($context, (isset($spec['suffix']) ? $spec['suffix'] : ''))
931
+ ->setHeaders($context, (isset($spec['headers']) ? $spec['headers'] : array()))
932
+ ->setCallbacks($context, (isset($spec['callbacks']) ? $spec['callbacks'] : array()));
933
+ return $this;
934
+ }
935
+
936
+ /**
937
+ * Overwrite existing context
938
+ *
939
+ * @param string $context Context type
940
+ * @param array $spec Context specification
941
+ * @return Zend_Controller_Action_Helper_ContextSwitch Provides a fluent interface
942
+ */
943
+ public function setContext($context, array $spec)
944
+ {
945
+ $this->removeContext($context);
946
+ return $this->addContext($context, $spec);
947
+ }
948
+
949
+ /**
950
+ * Add multiple contexts
951
+ *
952
+ * @param array $contexts
953
+ * @return Zend_Controller_Action_Helper_ContextSwitch Provides a fluent interface
954
+ */
955
+ public function addContexts(array $contexts)
956
+ {
957
+ foreach ($contexts as $context => $spec) {
958
+ $this->addContext($context, $spec);
959
+ }
960
+ return $this;
961
+ }
962
+
963
+ /**
964
+ * Set multiple contexts, after first removing all
965
+ *
966
+ * @param array $contexts
967
+ * @return Zend_Controller_Action_Helper_ContextSwitch Provides a fluent interface
968
+ */
969
+ public function setContexts(array $contexts)
970
+ {
971
+ $this->clearContexts();
972
+ foreach ($contexts as $context => $spec) {
973
+ $this->addContext($context, $spec);
974
+ }
975
+ return $this;
976
+ }
977
+
978
+ /**
979
+ * Retrieve context specification
980
+ *
981
+ * @param string $context
982
+ * @return array|null
983
+ */
984
+ public function getContext($context)
985
+ {
986
+ if ($this->hasContext($context)) {
987
+ return $this->_contexts[(string) $context];
988
+ }
989
+ return null;
990
+ }
991
+
992
+ /**
993
+ * Retrieve context definitions
994
+ *
995
+ * @return array
996
+ */
997
+ public function getContexts()
998
+ {
999
+ return $this->_contexts;
1000
+ }
1001
+
1002
+ /**
1003
+ * Remove a context
1004
+ *
1005
+ * @param string $context
1006
+ * @return boolean
1007
+ */
1008
+ public function removeContext($context)
1009
+ {
1010
+ if ($this->hasContext($context)) {
1011
+ unset($this->_contexts[(string) $context]);
1012
+ return true;
1013
+ }
1014
+ return false;
1015
+ }
1016
+
1017
+ /**
1018
+ * Remove all contexts
1019
+ *
1020
+ * @return Zend_Controller_Action_Helper_ContextSwitch Provides a fluent interface
1021
+ */
1022
+ public function clearContexts()
1023
+ {
1024
+ $this->_contexts = array();
1025
+ return $this;
1026
+ }
1027
+
1028
+ /**
1029
+ * Return current context, if any
1030
+ *
1031
+ * @return null|string
1032
+ */
1033
+ public function getCurrentContext()
1034
+ {
1035
+ return $this->_currentContext;
1036
+ }
1037
+
1038
+ /**
1039
+ * Post dispatch processing
1040
+ *
1041
+ * Execute postDispatch callback for current context, if available
1042
+ *
1043
+ * @throws Zend_Controller_Action_Exception
1044
+ * @return void
1045
+ */
1046
+ public function postDispatch()
1047
+ {
1048
+ $context = $this->getCurrentContext();
1049
+ if (null !== $context) {
1050
+ if (null !== ($callback = $this->getCallback($context, self::TRIGGER_POST))) {
1051
+ if (is_string($callback) && method_exists($this, $callback)) {
1052
+ $this->$callback();
1053
+ } elseif (is_string($callback) && function_exists($callback)) {
1054
+ $callback();
1055
+ } elseif (is_array($callback)) {
1056
+ call_user_func($callback);
1057
+ } else {
1058
+ /**
1059
+ * @see Zend_Controller_Action_Exception
1060
+ */
1061
+ require_once 'Zend/Controller/Action/Exception.php';
1062
+ throw new Zend_Controller_Action_Exception(sprintf('Invalid postDispatch context callback registered for context "%s"', $context));
1063
+ }
1064
+ }
1065
+ }
1066
+ }
1067
+
1068
+ /**
1069
+ * JSON post processing
1070
+ *
1071
+ * JSON serialize view variables to response body
1072
+ *
1073
+ * @return void
1074
+ */
1075
+ public function postJsonContext()
1076
+ {
1077
+ if (!$this->getAutoJsonSerialization()) {
1078
+ return;
1079
+ }
1080
+
1081
+ $viewRenderer = Zend_Controller_Action_HelperBroker::getStaticHelper('viewRenderer');
1082
+ $view = $viewRenderer->view;
1083
+ if ($view instanceof Zend_View_Interface) {
1084
+ /**
1085
+ * @see Zend_Json
1086
+ */
1087
+ require_once 'Zend/Json.php';
1088
+ $vars = Zend_Json::encode($view->getVars());
1089
+ $this->getResponse()->setBody($vars);
1090
+ }
1091
+ }
1092
+
1093
+ /**
1094
+ * Add one or more contexts to an action
1095
+ *
1096
+ * @param string $action
1097
+ * @param string|array $context
1098
+ * @return Zend_Controller_Action_Helper_ContextSwitch|void Provides a fluent interface
1099
+ */
1100
+ public function addActionContext($action, $context)
1101
+ {
1102
+ $this->hasContext($context, true);
1103
+ $controller = $this->getActionController();
1104
+ if (null === $controller) {
1105
+ return;
1106
+ }
1107
+ $action = (string) $action;
1108
+ $contextKey = $this->_contextKey;
1109
+
1110
+ if (!isset($controller->$contextKey)) {
1111
+ $controller->$contextKey = array();
1112
+ }
1113
+
1114
+ if (true === $context) {
1115
+ $contexts = $this->getContexts();
1116
+ $controller->{$contextKey}[$action] = array_keys($contexts);
1117
+ return $this;
1118
+ }
1119
+
1120
+ $context = (array) $context;
1121
+ if (!isset($controller->{$contextKey}[$action])) {
1122
+ $controller->{$contextKey}[$action] = $context;
1123
+ } else {
1124
+ $controller->{$contextKey}[$action] = array_merge(
1125
+ $controller->{$contextKey}[$action],
1126
+ $context
1127
+ );
1128
+ }
1129
+
1130
+ return $this;
1131
+ }
1132
+
1133
+ /**
1134
+ * Set a context as available for a given controller action
1135
+ *
1136
+ * @param string $action
1137
+ * @param string|array $context
1138
+ * @return Zend_Controller_Action_Helper_ContextSwitch|void Provides a fluent interface
1139
+ */
1140
+ public function setActionContext($action, $context)
1141
+ {
1142
+ $this->hasContext($context, true);
1143
+ $controller = $this->getActionController();
1144
+ if (null === $controller) {
1145
+ return;
1146
+ }
1147
+ $action = (string) $action;
1148
+ $contextKey = $this->_contextKey;
1149
+
1150
+ if (!isset($controller->$contextKey)) {
1151
+ $controller->$contextKey = array();
1152
+ }
1153
+
1154
+ if (true === $context) {
1155
+ $contexts = $this->getContexts();
1156
+ $controller->{$contextKey}[$action] = array_keys($contexts);
1157
+ } else {
1158
+ $controller->{$contextKey}[$action] = (array) $context;
1159
+ }
1160
+
1161
+ return $this;
1162
+ }
1163
+
1164
+ /**
1165
+ * Add multiple action/context pairs at once
1166
+ *
1167
+ * @param array $contexts
1168
+ * @return Zend_Controller_Action_Helper_ContextSwitch Provides a fluent interface
1169
+ */
1170
+ public function addActionContexts(array $contexts)
1171
+ {
1172
+ foreach ($contexts as $action => $context) {
1173
+ $this->addActionContext($action, $context);
1174
+ }
1175
+ return $this;
1176
+ }
1177
+
1178
+ /**
1179
+ * Overwrite and set multiple action contexts at once
1180
+ *
1181
+ * @param array $contexts
1182
+ * @return Zend_Controller_Action_Helper_ContextSwitch Provides a fluent interface
1183
+ */
1184
+ public function setActionContexts(array $contexts)
1185
+ {
1186
+ foreach ($contexts as $action => $context) {
1187
+ $this->setActionContext($action, $context);
1188
+ }
1189
+ return $this;
1190
+ }
1191
+
1192
+ /**
1193
+ * Does a particular controller action have the given context(s)?
1194
+ *
1195
+ * @param string $action
1196
+ * @param string|array $context
1197
+ * @throws Zend_Controller_Action_Exception
1198
+ * @return boolean
1199
+ */
1200
+ public function hasActionContext($action, $context)
1201
+ {
1202
+ $this->hasContext($context, true);
1203
+ $controller = $this->getActionController();
1204
+ if (null === $controller) {
1205
+ return false;
1206
+ }
1207
+ $action = (string) $action;
1208
+ $contextKey = $this->_contextKey;
1209
+
1210
+ if (!isset($controller->{$contextKey})) {
1211
+ return false;
1212
+ }
1213
+
1214
+ $allContexts = $controller->{$contextKey};
1215
+
1216
+ if (!is_array($allContexts)) {
1217
+ /**
1218
+ * @see Zend_Controller_Action_Exception
1219
+ */
1220
+ require_once 'Zend/Controller/Action/Exception.php';
1221
+ throw new Zend_Controller_Action_Exception("Invalid contexts found for controller");
1222
+ }
1223
+
1224
+ if (!isset($allContexts[$action])) {
1225
+ return false;
1226
+ }
1227
+
1228
+ if (true === $allContexts[$action]) {
1229
+ return true;
1230
+ }
1231
+
1232
+ $contexts = $allContexts[$action];
1233
+
1234
+ if (!is_array($contexts)) {
1235
+ /**
1236
+ * @see Zend_Controller_Action_Exception
1237
+ */
1238
+ require_once 'Zend/Controller/Action/Exception.php';
1239
+ throw new Zend_Controller_Action_Exception(sprintf("Invalid contexts found for action '%s'", $action));
1240
+ }
1241
+
1242
+ if (is_string($context) && in_array($context, $contexts)) {
1243
+ return true;
1244
+ } elseif (is_array($context)) {
1245
+ $found = true;
1246
+ foreach ($context as $test) {
1247
+ if (!in_array($test, $contexts)) {
1248
+ $found = false;
1249
+ break;
1250
+ }
1251
+ }
1252
+ return $found;
1253
+ }
1254
+
1255
+ return false;
1256
+ }
1257
+
1258
+ /**
1259
+ * Get contexts for a given action or all actions in the controller
1260
+ *
1261
+ * @param string $action
1262
+ * @return array
1263
+ */
1264
+ public function getActionContexts($action = null)
1265
+ {
1266
+ $controller = $this->getActionController();
1267
+ if (null === $controller) {
1268
+ return array();
1269
+ }
1270
+ $action = (string) $action;
1271
+ $contextKey = $this->_contextKey;
1272
+
1273
+ if (!isset($controller->$contextKey)) {
1274
+ return array();
1275
+ }
1276
+
1277
+ if (null !== $action) {
1278
+ if (isset($controller->{$contextKey}[$action])) {
1279
+ return $controller->{$contextKey}[$action];
1280
+ } else {
1281
+ return array();
1282
+ }
1283
+ }
1284
+
1285
+ return $controller->$contextKey;
1286
+ }
1287
+
1288
+ /**
1289
+ * Remove one or more contexts for a given controller action
1290
+ *
1291
+ * @param string $action
1292
+ * @param string|array $context
1293
+ * @return boolean
1294
+ */
1295
+ public function removeActionContext($action, $context)
1296
+ {
1297
+ if ($this->hasActionContext($action, $context)) {
1298
+ $controller = $this->getActionController();
1299
+ $contextKey = $this->_contextKey;
1300
+ $action = (string) $action;
1301
+ $contexts = $controller->$contextKey;
1302
+ $actionContexts = $contexts[$action];
1303
+ $contexts = (array) $context;
1304
+ foreach ($contexts as $context) {
1305
+ $index = array_search($context, $actionContexts);
1306
+ if (false !== $index) {
1307
+ unset($controller->{$contextKey}[$action][$index]);
1308
+ }
1309
+ }
1310
+ return true;
1311
+ }
1312
+ return false;
1313
+ }
1314
+
1315
+ /**
1316
+ * Clear all contexts for a given controller action or all actions
1317
+ *
1318
+ * @param string $action
1319
+ * @return Zend_Controller_Action_Helper_ContextSwitch Provides a fluent interface
1320
+ */
1321
+ public function clearActionContexts($action = null)
1322
+ {
1323
+ $controller = $this->getActionController();
1324
+ $contextKey = $this->_contextKey;
1325
+
1326
+ if (!isset($controller->$contextKey) || empty($controller->$contextKey)) {
1327
+ return $this;
1328
+ }
1329
+
1330
+ if (null === $action) {
1331
+ $controller->$contextKey = array();
1332
+ return $this;
1333
+ }
1334
+
1335
+ $action = (string) $action;
1336
+ if (isset($controller->{$contextKey}[$action])) {
1337
+ unset($controller->{$contextKey}[$action]);
1338
+ }
1339
+
1340
+ return $this;
1341
+ }
1342
+
1343
+ /**
1344
+ * Retrieve ViewRenderer
1345
+ *
1346
+ * @return Zend_Controller_Action_Helper_ViewRenderer Provides a fluent interface
1347
+ */
1348
+ protected function _getViewRenderer()
1349
+ {
1350
+ if (null === $this->_viewRenderer) {
1351
+ $this->_viewRenderer = Zend_Controller_Action_HelperBroker::getStaticHelper('viewRenderer');
1352
+ }
1353
+
1354
+ return $this->_viewRenderer;
1355
+ }
1356
+ }
1357
+
lib/Zend/Controller/Action/Helper/FlashMessenger.php ADDED
@@ -0,0 +1,261 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Zend Framework
4
+ *
5
+ * LICENSE
6
+ *
7
+ * This source file is subject to the new BSD license that is bundled
8
+ * with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://framework.zend.com/license/new-bsd
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@zend.com so we can send you a copy immediately.
14
+ *
15
+ * @category Zend
16
+ * @package Zend_Controller
17
+ * @subpackage Zend_Controller_Action_Helper
18
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
19
+ * @license http://framework.zend.com/license/new-bsd New BSD License
20
+ */
21
+
22
+ /**
23
+ * @see Zend_Session
24
+ */
25
+ require_once 'Zend/Session.php';
26
+
27
+ /**
28
+ * Flash Messenger - implement session-based messages
29
+ *
30
+ * @uses Zend_Controller_Action_Helper_Abstract
31
+ * @category Zend
32
+ * @package Zend_Controller
33
+ * @subpackage Zend_Controller_Action_Helper
34
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
35
+ * @license http://framework.zend.com/license/new-bsd New BSD License
36
+ * @version $Id: $
37
+ */
38
+ class Zend_Controller_Action_Helper_FlashMessenger extends Zend_Controller_Action_Helper_Abstract implements IteratorAggregate, Countable
39
+ {
40
+ /**
41
+ * $_messages - Messages from previous request
42
+ *
43
+ * @var array
44
+ */
45
+ static protected $_messages = array();
46
+
47
+ /**
48
+ * $_session - Zend_Session storage object
49
+ *
50
+ * @var Zend_Session
51
+ */
52
+ static protected $_session = null;
53
+
54
+ /**
55
+ * $_messageAdded - Wether a message has been previously added
56
+ *
57
+ * @var boolean
58
+ */
59
+ static protected $_messageAdded = false;
60
+
61
+ /**
62
+ * $_namespace - Instance namespace, default is 'default'
63
+ *
64
+ * @var string
65
+ */
66
+ protected $_namespace = 'default';
67
+
68
+ /**
69
+ * __construct() - Instance constructor, needed to get iterators, etc
70
+ *
71
+ * @param string $namespace
72
+ * @return void
73
+ */
74
+ public function __construct()
75
+ {
76
+ if (!self::$_session instanceof Zend_Session_Namespace) {
77
+ self::$_session = new Zend_Session_Namespace($this->getName());
78
+ foreach (self::$_session as $namespace => $messages) {
79
+ self::$_messages[$namespace] = $messages;
80
+ unset(self::$_session->{$namespace});
81
+ }
82
+ }
83
+ }
84
+
85
+ /**
86
+ * postDispatch() - runs after action is dispatched, in this
87
+ * case, it is resetting the namespace in case we have forwarded to a different
88
+ * action, Flashmessage will be 'clean' (default namespace)
89
+ *
90
+ * @return Zend_Controller_Action_Helper_FlashMessenger Provides a fluent interface
91
+ */
92
+ public function postDispatch()
93
+ {
94
+ $this->resetNamespace();
95
+ return $this;
96
+ }
97
+
98
+ /**
99
+ * setNamespace() - change the namespace messages are added to, useful for
100
+ * per action controller messaging between requests
101
+ *
102
+ * @param string $namespace
103
+ * @return Zend_Controller_Action_Helper_FlashMessenger Provides a fluent interface
104
+ */
105
+ public function setNamespace($namespace = 'default')
106
+ {
107
+ $this->_namespace = $namespace;
108
+ return $this;
109
+ }
110
+
111
+ /**
112
+ * resetNamespace() - reset the namespace to the default
113
+ *
114
+ * @return Zend_Controller_Action_Helper_FlashMessenger Provides a fluent interface
115
+ */
116
+ public function resetNamespace()
117
+ {
118
+ $this->setNamespace();
119
+ return $this;
120
+ }
121
+
122
+ /**
123
+ * addMessage() - Add a message to flash message
124
+ *
125
+ * @param string $message
126
+ * @return Zend_Controller_Action_Helper_FlashMessenger Provides a fluent interface
127
+ */
128
+ public function addMessage($message)
129
+ {
130
+ if (self::$_messageAdded === false) {
131
+ self::$_session->setExpirationHops(1, null, true);
132
+ }
133
+
134
+ if (!is_array(self::$_session->{$this->_namespace})) {
135
+ self::$_session->{$this->_namespace} = array();
136
+ }
137
+
138
+ self::$_session->{$this->_namespace}[] = $message;
139
+
140
+ return $this;
141
+ }
142
+
143
+ /**
144
+ * hasMessages() - Wether a specific namespace has messages
145
+ *
146
+ * @return boolean
147
+ */
148
+ public function hasMessages()
149
+ {
150
+ return isset(self::$_messages[$this->_namespace]);
151
+ }
152
+
153
+ /**
154
+ * getMessages() - Get messages from a specific namespace
155
+ *
156
+ * @return array
157
+ */
158
+ public function getMessages()
159
+ {
160
+ if ($this->hasMessages()) {
161
+ return self::$_messages[$this->_namespace];
162
+ }
163
+
164
+ return array();
165
+ }
166
+
167
+ /**
168
+ * Clear all messages from the previous request & current namespace
169
+ *
170
+ * @return boolean True if messages were cleared, false if none existed
171
+ */
172
+ public function clearMessages()
173
+ {
174
+ if ($this->hasMessages()) {
175
+ unset(self::$_messages[$this->_namespace]);
176
+ return true;
177
+ }
178
+
179
+ return false;
180
+ }
181
+
182
+ /**
183
+ * hasCurrentMessages() - check to see if messages have been added to current
184
+ * namespace within this request
185
+ *
186
+ * @return boolean
187
+ */
188
+ public function hasCurrentMessages()
189
+ {
190
+ return isset(self::$_session->{$this->_namespace});
191
+ }
192
+
193
+ /**
194
+ * getCurrentMessages() - get messages that have been added to the current
195
+ * namespace within this request
196
+ *
197
+ * @return array
198
+ */
199
+ public function getCurrentMessages()
200
+ {
201
+ if ($this->hasCurrentMessages()) {
202
+ return self::$_session->{$this->_namespace};
203
+ }
204
+
205
+ return array();
206
+ }
207
+
208
+ /**
209
+ * clear messages from the current request & current namespace
210
+ *
211
+ * @return boolean
212
+ */
213
+ public function clearCurrentMessages()
214
+ {
215
+ if ($this->hasCurrentMessages()) {
216
+ unset(self::$_session->{$this->_namespace});
217
+ return true;
218
+ }
219
+
220
+ return false;
221
+ }
222
+
223
+ /**
224
+ * getIterator() - complete the IteratorAggregate interface, for iterating
225
+ *
226
+ * @return ArrayObject
227
+ */
228
+ public function getIterator()
229
+ {
230
+ if ($this->hasMessages()) {
231
+ return new ArrayObject($this->getMessages());
232
+ }
233
+
234
+ return new ArrayObject();
235
+ }
236
+
237
+ /**
238
+ * count() - Complete the countable interface
239
+ *
240
+ * @return int
241
+ */
242
+ public function count()
243
+ {
244
+ if ($this->hasMessages()) {
245
+ return count($this->getMessages());
246
+ }
247
+
248
+ return 0;
249
+ }
250
+
251
+ /**
252
+ * Strategy pattern: proxy to addMessage()
253
+ *
254
+ * @param string $message
255
+ * @return void
256
+ */
257
+ public function direct($message)
258
+ {
259
+ return $this->addMessage($message);
260
+ }
261
+ }
lib/Zend/Controller/Action/Helper/Json.php ADDED
@@ -0,0 +1,117 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Zend Framework
4
+ *
5
+ * LICENSE
6
+ *
7
+ * This source file is subject to version 1.0 of the Zend Framework
8
+ * license, that is bundled with this package in the file LICENSE.txt, and
9
+ * is available through the world-wide-web at the following URL:
10
+ * http://framework.zend.com/license/new-bsd. If you did not receive
11
+ * a copy of the Zend Framework license and are unable to obtain it
12
+ * through the world-wide-web, please send a note to license@zend.com
13
+ * so we can mail you a copy immediately.
14
+ *
15
+ * @category Zend
16
+ * @package Zend_Controller
17
+ * @subpackage Zend_Controller_Action_Helper
18
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
19
+ * @version $Id: Json.php 8892 2008-03-18 19:47:46Z thomas $
20
+ * @license http://framework.zend.com/license/new-bsd New BSD License
21
+ */
22
+
23
+ /**
24
+ * @see Zend_Controller_Action_Helper_Abstract
25
+ */
26
+ require_once 'Zend/Controller/Action/Helper/Abstract.php';
27
+
28
+ /**
29
+ * Simplify AJAX context switching based on requested format
30
+ *
31
+ * @uses Zend_Controller_Action_Helper_Abstract
32
+ * @category Zend
33
+ * @package Zend_Controller
34
+ * @subpackage Zend_Controller_Action_Helper
35
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
36
+ * @license http://framework.zend.com/license/new-bsd New BSD License
37
+ */
38
+ class Zend_Controller_Action_Helper_Json extends Zend_Controller_Action_Helper_Abstract
39
+ {
40
+ /**
41
+ * Suppress exit when sendJson() called
42
+ * @var boolean
43
+ */
44
+ public $suppressExit = false;
45
+
46
+ /**
47
+ * Create JSON response
48
+ *
49
+ * Encodes and returns data to JSON. Content-Type header set to
50
+ * 'application/json', and disables layouts and viewRenderer (if being
51
+ * used).
52
+ *
53
+ * @param mixed $data
54
+ * @param boolean $keepLayouts
55
+ * @throws Zend_Controller_Action_Helper_Json
56
+ * @return string
57
+ */
58
+ public function encodeJson($data, $keepLayouts = false)
59
+ {
60
+ /**
61
+ * @see Zend_View_Helper_Json
62
+ */
63
+ require_once 'Zend/View/Helper/Json.php';
64
+ $jsonHelper = new Zend_View_Helper_Json();
65
+ $data = $jsonHelper->json($data, $keepLayouts);
66
+
67
+ if (!$keepLayouts) {
68
+ /**
69
+ * @see Zend_Controller_Action_HelperBroker
70
+ */
71
+ require_once 'Zend/Controller/Action/HelperBroker.php';
72
+ Zend_Controller_Action_HelperBroker::getStaticHelper('viewRenderer')->setNoRender(true);
73
+ }
74
+
75
+ return $data;
76
+ }
77
+
78
+ /**
79
+ * Encode JSON response and immediately send
80
+ *
81
+ * @param mixed $data
82
+ * @param boolean $keepLayouts
83
+ * @return string|void
84
+ */
85
+ public function sendJson($data, $keepLayouts = false)
86
+ {
87
+ $data = $this->encodeJson($data, $keepLayouts);
88
+ $response = $this->getResponse();
89
+ $response->setBody($data);
90
+
91
+ if (!$this->suppressExit) {
92
+ $response->sendResponse();
93
+ exit;
94
+ }
95
+
96
+ return $data;
97
+ }
98
+
99
+ /**
100
+ * Strategy pattern: call helper as helper broker method
101
+ *
102
+ * Allows encoding JSON. If $sendNow is true, immediately sends JSON
103
+ * response.
104
+ *
105
+ * @param mixed $data
106
+ * @param boolean $sendNow
107
+ * @param boolean $keepLayouts
108
+ * @return string|void
109
+ */
110
+ public function direct($data, $sendNow = true, $keepLayouts = false)
111
+ {
112
+ if ($sendNow) {
113
+ return $this->sendJson($data, $keepLayouts);
114
+ }
115
+ return $this->encodeJson($data, $keepLayouts);
116
+ }
117
+ }
lib/Zend/Controller/Action/Helper/Redirector.php ADDED
@@ -0,0 +1,505 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Zend Framework
4
+ *
5
+ * LICENSE
6
+ *
7
+ * This source file is subject to the new BSD license that is bundled
8
+ * with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://framework.zend.com/license/new-bsd
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@zend.com so we can send you a copy immediately.
14
+ *
15
+ * @category Zend
16
+ * @package Zend_Controller
17
+ * @subpackage Zend_Controller_Action_Helper
18
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
19
+ * @license http://framework.zend.com/license/new-bsd New BSD License
20
+ */
21
+
22
+ /**
23
+ * @see Zend_Controller_Action_Exception
24
+ */
25
+ require_once 'Zend/Controller/Action/Exception.php';
26
+
27
+ /**
28
+ * @see Zend_Controller_Action_Helper_Abstract
29
+ */
30
+ require_once 'Zend/Controller/Action/Helper/Abstract.php';
31
+
32
+ /**
33
+ * @category Zend
34
+ * @package Zend_Controller
35
+ * @subpackage Zend_Controller_Action_Helper
36
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
37
+ * @license http://framework.zend.com/license/new-bsd New BSD License
38
+ */
39
+ class Zend_Controller_Action_Helper_Redirector extends Zend_Controller_Action_Helper_Abstract
40
+ {
41
+ /**
42
+ * HTTP status code for redirects
43
+ * @var int
44
+ */
45
+ protected $_code = 302;
46
+
47
+ /**
48
+ * Whether or not calls to _redirect() should exit script execution
49
+ * @var boolean
50
+ */
51
+ protected $_exit = true;
52
+
53
+ /**
54
+ * Whether or not _redirect() should attempt to prepend the base URL to the
55
+ * passed URL (if it's a relative URL)
56
+ * @var boolean
57
+ */
58
+ protected $_prependBase = true;
59
+
60
+ /**
61
+ * Url to which to redirect
62
+ * @var string
63
+ */
64
+ protected $_redirectUrl = null;
65
+
66
+ /**
67
+ * Whether or not to use an absolute URI when redirecting
68
+ * @var boolean
69
+ */
70
+ protected $_useAbsoluteUri = false;
71
+
72
+ /**
73
+ * Retrieve HTTP status code to emit on {@link _redirect()} call
74
+ *
75
+ * @return int
76
+ */
77
+ public function getCode()
78
+ {
79
+ return $this->_code;
80
+ }
81
+
82
+ /**
83
+ * Validate HTTP status redirect code
84
+ *
85
+ * @param int $code
86
+ * @throws Zend_Controller_Action_Exception on invalid HTTP status code
87
+ * @return true
88
+ */
89
+ protected function _checkCode($code)
90
+ {
91
+ if (!is_int($code) || (300 > $code) || (307 < $code)) {
92
+ /**
93
+ * @see Zend_Controller_Exception
94
+ */
95
+ require_once 'Zend/Controller/Exception.php';
96
+ throw new Zend_Controller_Action_Exception('Invalid redirect HTTP status code (' . $code . ')');
97
+ }
98
+
99
+ return true;
100
+ }
101
+
102
+ /**
103
+ * Retrieve HTTP status code for {@link _redirect()} behaviour
104
+ *
105
+ * @param int $code
106
+ * @return Zend_Controller_Action_Helper_Redirector Provides a fluent interface
107
+ */
108
+ public function setCode($code)
109
+ {
110
+ $this->_checkCode($code);
111
+ $this->_code = $code;
112
+ return $this;
113
+ }
114
+
115
+ /**
116
+ * Retrieve flag for whether or not {@link _redirect()} will exit when finished.
117
+ *
118
+ * @return boolean
119
+ */
120
+ public function getExit()
121
+ {
122
+ return $this->_exit;
123
+ }
124
+
125
+ /**
126
+ * Retrieve exit flag for {@link _redirect()} behaviour
127
+ *
128
+ * @param boolean $flag
129
+ * @return Zend_Controller_Action_Helper_Redirector Provides a fluent interface
130
+ */
131
+ public function setExit($flag)
132
+ {
133
+ $this->_exit = ($flag) ? true : false;
134
+ return $this;
135
+ }
136
+
137
+ /**
138
+ * Retrieve flag for whether or not {@link _redirect()} will prepend the
139
+ * base URL on relative URLs
140
+ *
141
+ * @return boolean
142
+ */
143
+ public function getPrependBase()
144
+ {
145
+ return $this->_prependBase;
146
+ }
147
+
148
+ /**
149
+ * Retrieve 'prepend base' flag for {@link _redirect()} behaviour
150
+ *
151
+ * @param boolean $flag
152
+ * @return Zend_Controller_Action_Helper_Redirector Provides a fluent interface
153
+ */
154
+ public function setPrependBase($flag)
155
+ {
156
+ $this->_prependBase = ($flag) ? true : false;
157
+ return $this;
158
+ }
159
+
160
+ /**
161
+ * Return use absolute URI flag
162
+ *
163
+ * @return boolean
164
+ */
165
+ public function getUseAbsoluteUri()
166
+ {
167
+ return $this->_useAbsoluteUri;
168
+ }
169
+
170
+ /**
171
+ * Set use absolute URI flag
172
+ *
173
+ * @param boolean $flag
174
+ * @return Zend_Controller_Action_Helper_Redirector Provides a fluent interface
175
+ */
176
+ public function setUseAbsoluteUri($flag = true)
177
+ {
178
+ $this->_useAbsoluteUri = ($flag) ? true : false;
179
+ return $this;
180
+ }
181
+
182
+ /**
183
+ * Set redirect in response object
184
+ *
185
+ * @return void
186
+ */
187
+ protected function _redirect($url)
188
+ {
189
+ $this->_redirectUrl = $url;
190
+ if ($this->getUseAbsoluteUri() && !preg_match('#^(https?|ftp)://#', $url)) {
191
+ $host = $_SERVER['HTTP_HOST'];
192
+ $proto = (empty($_SERVER['HTTPS'])) ? 'http' : 'https';
193
+ $port = $_SERVER['SERVER_PORT'];
194
+ $uri = $proto . '://' . $host;
195
+ if ((('http' == $proto) && (80 != $port)) || (('https' == $proto) && (443 != $port))) {
196
+ $uri .= ':' . $port;
197
+ }
198
+ $url = $uri . '/' . ltrim($url, '/');
199
+ }
200
+ $this->getResponse()->setRedirect($url, $this->getCode());
201
+ }
202
+
203
+ /**
204
+ * Retrieve currently set URL for redirect
205
+ *
206
+ * @return string
207
+ */
208
+ public function getRedirectUrl()
209
+ {
210
+ return $this->_redirectUrl;
211
+ }
212
+
213
+ /**
214
+ * Determine if the baseUrl should be prepended, and prepend if necessary
215
+ *
216
+ * @param string $url
217
+ * @return string
218
+ */
219
+ protected function _prependBase($url)
220
+ {
221
+ if ($this->getPrependBase()) {
222
+ $request = $this->getRequest();
223
+ if ($request instanceof Zend_Controller_Request_Http) {
224
+ $base = rtrim($request->getBaseUrl(), '/');
225
+ if (!empty($base) && ('/' != $base)) {
226
+ $url = $base . '/' . ltrim($url, '/');
227
+ } else {
228
+ $url = '/' . ltrim($url, '/');
229
+ }
230
+ }
231
+ }
232
+
233
+ return $url;
234
+ }
235
+
236
+ /**
237
+ * Set a redirect URL of the form /module/controller/action/params
238
+ *
239
+ * @param string $action
240
+ * @param string $controller
241
+ * @param string $module
242
+ * @param array $params
243
+ * @return void
244
+ */
245
+ public function setGoto($action, $controller = null, $module = null, array $params = array())
246
+ {
247
+ $dispatcher = Zend_Controller_Front::getInstance()->getDispatcher();
248
+ $request = $this->getRequest();
249
+
250
+ if (null === $module) {
251
+ $module = $request->getModuleName();
252
+ if ($module == $dispatcher->getDefaultModule()) {
253
+ $module = '';
254
+ }
255
+ }
256
+
257
+ if (null === $controller) {
258
+ $controller = $request->getControllerName();
259
+ if (empty($controller)) {
260
+ $controller = $dispatcher->getDefaultControllerName();
261
+ }
262
+ }
263
+
264
+ $paramsNormalized = array();
265
+ foreach ($params as $key => $value) {
266
+ $paramsNormalized[] = $key . '/' . $value;
267
+ }
268
+ $paramsString = implode('/', $paramsNormalized);
269
+
270
+ if (!empty($paramsString)) {
271
+ $url = $module . '/' . $controller . '/' . $action . '/' . $paramsString;
272
+ } else {
273
+ if ($action != $dispatcher->getDefaultAction()) {
274
+ $url = $module . '/' . $controller . '/' . $action;
275
+ } else {
276
+ if ($controller != $dispatcher->getDefaultControllerName()) {
277
+ $url = $module . '/' . $controller;
278
+ } else {
279
+ $url = $module;
280
+ }
281
+ }
282
+ }
283
+
284
+ $url = '/' . trim($url, '/');
285
+
286
+ $url = $this->_prependBase($url);
287
+
288
+ $this->_redirect($url);
289
+ }
290
+
291
+ /**
292
+ * Build a URL based on a route
293
+ *
294
+ * @param array $urlOptions
295
+ * @param string $name Route name
296
+ * @param boolean $reset
297
+ * @return void
298
+ */
299
+ public function setGotoRoute(array $urlOptions = array(), $name = null, $reset = false)
300
+ {
301
+ $router = Zend_Controller_Front::getInstance()->getRouter();
302
+
303
+ if (empty($name)) {
304
+ try {
305
+ $name = $router->getCurrentRouteName();
306
+ } catch (Zend_Controller_Router_Exception $e) {
307
+ if ($router->hasRoute('default')) {
308
+ $name = 'default';
309
+ }
310
+ }
311
+ }
312
+
313
+ $route = $router->getRoute($name);
314
+ $request = $this->getRequest();
315
+
316
+ $url = rtrim($request->getBaseUrl(), '/') . '/';
317
+ $url .= $route->assemble($urlOptions, $reset);
318
+
319
+ $this->_redirect($url);
320
+ }
321
+
322
+ /**
323
+ * Set a redirect URL string
324
+ *
325
+ * By default, emits a 302 HTTP status header, prepends base URL as defined
326
+ * in request object if url is relative, and halts script execution by
327
+ * calling exit().
328
+ *
329
+ * $options is an optional associative array that can be used to control
330
+ * redirect behaviour. The available option keys are:
331
+ * - exit: boolean flag indicating whether or not to halt script execution when done
332
+ * - prependBase: boolean flag indicating whether or not to prepend the base URL when a relative URL is provided
333
+ * - code: integer HTTP status code to use with redirect. Should be between 300 and 307.
334
+ *
335
+ * _redirect() sets the Location header in the response object. If you set
336
+ * the exit flag to false, you can override this header later in code
337
+ * execution.
338
+ *
339
+ * If the exit flag is true (true by default), _redirect() will write and
340
+ * close the current session, if any.
341
+ *
342
+ * @param string $url
343
+ * @param array $options
344
+ * @return void
345
+ */
346
+ public function setGotoUrl($url, array $options = array())
347
+ {
348
+ // prevent header injections
349
+ $url = str_replace(array("\n", "\r"), '', $url);
350
+
351
+ $exit = $this->getExit();
352
+ $prependBase = $this->getPrependBase();
353
+ $code = $this->getCode();
354
+ if (null !== $options) {
355
+ if (isset($options['exit'])) {
356
+ $this->setExit(($options['exit']) ? true : false);
357
+ }
358
+ if (isset($options['prependBase'])) {
359
+ $this->setPrependBase(($options['prependBase']) ? true : false);
360
+ }
361
+ if (isset($options['code'])) {
362
+ $this->setCode($options['code']);
363
+ }
364
+ }
365
+
366
+ // If relative URL, decide if we should prepend base URL
367
+ if (!preg_match('|^[a-z]+://|', $url)) {
368
+ $url = $this->_prependBase($url);
369
+ }
370
+
371
+ $this->_redirect($url);
372
+ }
373
+
374
+ /**
375
+ * Perform a redirect to an action/controller/module with params
376
+ *
377
+ * @param string $action
378
+ * @param string $controller
379
+ * @param string $module
380
+ * @param array $params
381
+ * @return void
382
+ */
383
+ public function goto($action, $controller = null, $module = null, array $params = array())
384
+ {
385
+ $this->setGoto($action, $controller, $module, $params);
386
+
387
+ if ($this->getExit()) {
388
+ $this->redirectAndExit();
389
+ }
390
+ }
391
+
392
+ /**
393
+ * Perform a redirect to an action/controller/module with params, forcing an immdiate exit
394
+ *
395
+ * @param mixed $action
396
+ * @param mixed $controller
397
+ * @param mixed $module
398
+ * @param array $params
399
+ * @return void
400
+ */
401
+ public function gotoAndExit($action, $controller = null, $module = null, array $params = array())
402
+ {
403
+ $this->setGoto($action, $controller, $module, $params);
404
+ $this->redirectAndExit();
405
+ }
406
+
407
+ /**
408
+ * Redirect to a route-based URL
409
+ *
410
+ * Uses route's assemble method tobuild the URL; route is specified by $name;
411
+ * default route is used if none provided.
412
+ *
413
+ * @param array $urlOptions Array of key/value pairs used to assemble URL
414
+ * @param string $name
415
+ * @param boolean $reset
416
+ * @return void
417
+ */
418
+ public function gotoRoute(array $urlOptions = array(), $name = null, $reset = false)
419
+ {
420
+ $this->setGotoRoute($urlOptions, $name, $reset);
421
+
422
+ if ($this->getExit()) {
423
+ $this->redirectAndExit();
424
+ }
425
+ }
426
+
427
+ /**
428
+ * Redirect to a route-based URL, and immediately exit
429
+ *
430
+ * Uses route's assemble method tobuild the URL; route is specified by $name;
431
+ * default route is used if none provided.
432
+ *
433
+ * @param array $urlOptions Array of key/value pairs used to assemble URL
434
+ * @param string $name
435
+ * @param boolean $reset
436
+ * @return void
437
+ */
438
+ public function gotoRouteAndExit(array $urlOptions = array(), $name = null, $reset = false)
439
+ {
440
+ $this->setGotoRoute($urlOptions, $name, $reset);
441
+ $this->redirectAndExit();
442
+ }
443
+
444
+ /**
445
+ * Perform a redirect to a url
446
+ *
447
+ * @param string $url
448
+ * @param array $options
449
+ * @return void
450
+ */
451
+ public function gotoUrl($url, array $options = array())
452
+ {
453
+ $this->setGotoUrl($url, $options);
454
+
455
+ if ($this->getExit()) {
456
+ $this->redirectAndExit();
457
+ }
458
+ }
459
+
460
+ /**
461
+ * Set a URL string for a redirect, perform redirect, and immediately exit
462
+ *
463
+ * @param string $url
464
+ * @param array $options
465
+ * @return void
466
+ */
467
+ public function gotoUrlAndExit($url, array $options = array())
468
+ {
469
+ $this->gotoUrl($url, $options);
470
+ $this->redirectAndExit();
471
+ }
472
+
473
+ /**
474
+ * exit(): Perform exit for redirector
475
+ *
476
+ * @return void
477
+ */
478
+ public function redirectAndExit()
479
+ {
480
+ // Close session, if started
481
+ if (class_exists('Zend_Session', false) && Zend_Session::isStarted()) {
482
+ Zend_Session::writeClose();
483
+ } elseif (isset($_SESSION)) {
484
+ session_write_close();
485
+ }
486
+
487
+ $this->getResponse()->sendHeaders();
488
+ exit();
489
+ }
490
+
491
+ /**
492
+ * direct(): Perform helper when called as
493
+ * $this->_helper->redirector($action, $controller, $module, $params)
494
+ *
495
+ * @param string $action
496
+ * @param string $controller
497
+ * @param string $module
498
+ * @param array $params
499
+ * @return void
500
+ */
501
+ public function direct($action, $controller = null, $module = null, array $params = array())
502
+ {
503
+ $this->goto($action, $controller, $module, $params);
504
+ }
505
+ }
lib/Zend/Controller/Action/Helper/Url.php ADDED
@@ -0,0 +1,139 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Zend Framework
4
+ *
5
+ * LICENSE
6
+ *
7
+ * This source file is subject to version 1.0 of the Zend Framework
8
+ * license, that is bundled with this package in the file LICENSE.txt, and
9
+ * is available through the world-wide-web at the following URL:
10
+ * http://framework.zend.com/license/new-bsd. If you did not receive
11
+ * a copy of the Zend Framework license and are unable to obtain it
12
+ * through the world-wide-web, please send a note to license@zend.com
13
+ * so we can mail you a copy immediately.
14
+ *
15
+ * @category Zend
16
+ * @package Zend_Controller
17
+ * @subpackage Zend_Controller_Action_Helper
18
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
19
+ * @version $Id: Url.php 8892 2008-03-18 19:47:46Z thomas $
20
+ * @license http://framework.zend.com/license/new-bsd New BSD License
21
+ */
22
+
23
+ /**
24
+ * @see Zend_Controller_Action_Helper_Abstract
25
+ */
26
+ require_once 'Zend/Controller/Action/Helper/Abstract.php';
27
+
28
+ /**
29
+ * @see Zend_Controller_Front
30
+ */
31
+ require_once 'Zend/Controller/Front.php';
32
+
33
+ /**
34
+ * Helper for creating URLs for redirects and other tasks
35
+ *
36
+ * @uses Zend_Controller_Action_Helper_Abstract
37
+ * @category Zend
38
+ * @package Zend_Controller
39
+ * @subpackage Zend_Controller_Action_Helper
40
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
41
+ * @license http://framework.zend.com/license/new-bsd New BSD License
42
+ */
43
+ class Zend_Controller_Action_Helper_Url extends Zend_Controller_Action_Helper_Abstract
44
+ {
45
+ /**
46
+ * Create URL based on default route
47
+ *
48
+ * @param string $action
49
+ * @param string $controller
50
+ * @param string $module
51
+ * @param array $params
52
+ * @return string
53
+ */
54
+ public function simple($action, $controller = null, $module = null, array $params = null)
55
+ {
56
+ $request = $this->getRequest();
57
+
58
+ if (null === $controller) {
59
+ $controller = $request->getControllerName();
60
+ }
61
+
62
+ if (null === $module) {
63
+ $module = $request->getModuleName();
64
+ }
65
+
66
+ $url = $controller . '/' . $action;
67
+ if ($module != Zend_Controller_Front::getInstance()->getDispatcher()->getDefaultModule()) {
68
+ $url = $module . '/' . $url;
69
+ }
70
+
71
+ if (null !== $params) {
72
+ $paramPairs = array();
73
+ foreach ($params as $key => $value) {
74
+ $paramPairs[] = urlencode($key) . '/' . urlencode($value);
75
+ }
76
+ $paramString = implode('/', $paramPairs);
77
+ $url .= '/' . $paramString;
78
+ }
79
+
80
+ $url = '/' . ltrim($url, '/');
81
+
82
+ return $url;
83
+ }
84
+
85
+ /**
86
+ * Assembles a URL based on a given route
87
+ *
88
+ * This method will typically be used for more complex operations, as it
89
+ * ties into the route objects registered with the router.
90
+ *
91
+ * @param array $urlOptions Options passed to the assemble method of the Route object.
92
+ * @param mixed $name The name of a Route to use. If null it will use the current Route
93
+ * @param boolean $reset
94
+ * @param boolean $encode
95
+ * @return string Url for the link href attribute.
96
+ */
97
+ public function url($urlOptions = array(), $name = null, $reset = false, $encode = true)
98
+ {
99
+ $front = Zend_Controller_Front::getInstance();
100
+ $router = $front->getRouter();
101
+
102
+ if (empty($name)) {
103
+ try {
104
+ $name = $router->getCurrentRouteName();
105
+ } catch (Zend_Controller_Router_Exception $e) {
106
+ $name = 'default';
107
+ }
108
+ }
109
+
110
+ if ($encode) {
111
+ foreach ($urlOptions as $key => $option) {
112
+ $urlOptions[$key] = urlencode($option);
113
+ }
114
+ }
115
+
116
+ $route = $router->getRoute($name);
117
+
118
+ $url = rtrim($front->getBaseUrl(), '/') . '/';
119
+ $url .= $route->assemble($urlOptions, $reset);
120
+
121
+ return $url;
122
+ }
123
+
124
+ /**
125
+ * Perform helper when called as $this->_helper->url() from an action controller
126
+ *
127
+ * Proxies to {@link simple()}
128
+ *
129
+ * @param string $action
130
+ * @param string $controller
131
+ * @param string $module
132
+ * @param array $params
133
+ * @return string
134
+ */
135
+ public function direct($action, $controller = null, $module = null, array $params = null)
136
+ {
137
+ return $this->simple($action, $controller, $module, $params);
138
+ }
139
+ }
lib/Zend/Controller/Action/Helper/ViewRenderer.php ADDED
@@ -0,0 +1,1000 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Zend Framework
4
+ *
5
+ * LICENSE
6
+ *
7
+ * This source file is subject to the new BSD license that is bundled
8
+ * with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://framework.zend.com/license/new-bsd
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@zend.com so we can send you a copy immediately.
14
+ *
15
+ * @category Zend
16
+ * @package Zend_Controller
17
+ * @subpackage Zend_Controller_Action_Helper
18
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
19
+ * @license http://framework.zend.com/license/new-bsd New BSD License
20
+ */
21
+
22
+ /**
23
+ * @see Zend_Controller_Action_Helper_Abstract
24
+ */
25
+ require_once 'Zend/Controller/Action/Helper/Abstract.php';
26
+
27
+ /**
28
+ * @see Zend_View_Interface
29
+ */
30
+ require_once 'Zend/View/Interface.php';
31
+
32
+ /**
33
+ * @see Zend_View
34
+ */
35
+ require_once 'Zend/View.php';
36
+
37
+ /**
38
+ * View script integration
39
+ *
40
+ * Zend_Controller_Action_Helper_ViewRenderer provides transparent view
41
+ * integration for action controllers. It allows you to create a view object
42
+ * once, and populate it throughout all actions. Several global options may be
43
+ * set:
44
+ *
45
+ * - noController: if set true, render() will not look for view scripts in
46
+ * subdirectories named after the controller
47
+ * - viewSuffix: what view script filename suffix to use
48
+ *
49
+ * The helper autoinitializes the action controller view preDispatch(). It
50
+ * determines the path to the class file, and then determines the view base
51
+ * directory from there. It also uses the module name as a class prefix for
52
+ * helpers and views such that if your module name is 'Search', it will set the
53
+ * helper class prefix to 'Search_View_Helper' and the filter class prefix to ;
54
+ * 'Search_View_Filter'.
55
+ *
56
+ * Usage:
57
+ * <code>
58
+ * // In your bootstrap:
59
+ * Zend_Controller_Action_HelperBroker::addHelper(new Zend_Controller_Action_Helper_ViewRenderer());
60
+ *
61
+ * // In your action controller methods:
62
+ * $viewHelper = $this->_helper->getHelper('view');
63
+ *
64
+ * // Don't use controller subdirectories
65
+ * $viewHelper->setNoController(true);
66
+ *
67
+ * // Specify a different script to render:
68
+ * $this->_helper->view('form');
69
+ *
70
+ * </code>
71
+ *
72
+ * @uses Zend_Controller_Action_Helper_Abstract
73
+ * @package Zend_Controller
74
+ * @subpackage Zend_Controller_Action_Helper
75
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
76
+ * @license http://framework.zend.com/license/new-bsd New BSD License
77
+ */
78
+ class Zend_Controller_Action_Helper_ViewRenderer extends Zend_Controller_Action_Helper_Abstract
79
+ {
80
+ /**
81
+ * @var Zend_View_Interface
82
+ */
83
+ public $view;
84
+
85
+ /**
86
+ * Word delimiters
87
+ * @var array
88
+ */
89
+ protected $_delimiters;
90
+
91
+ /**
92
+ * Front controller instance
93
+ * @var Zend_Controller_Front
94
+ */
95
+ protected $_frontController;
96
+
97
+ /**
98
+ * @var Zend_Filter_Inflector
99
+ */
100
+ protected $_inflector;
101
+
102
+ /**
103
+ * Inflector target
104
+ * @var string
105
+ */
106
+ protected $_inflectorTarget = '';
107
+
108
+ /**
109
+ * Current module directory
110
+ * @var string
111
+ */
112
+ protected $_moduleDir = '';
113
+
114
+ /**
115
+ * Whether or not to autorender using controller name as subdirectory;
116
+ * global setting (not reset at next invocation)
117
+ * @var boolean
118
+ */
119
+ protected $_neverController = false;
120
+
121
+ /**
122
+ * Whether or not to autorender postDispatch; global setting (not reset at
123
+ * next invocation)
124
+ * @var boolean
125
+ */
126
+ protected $_neverRender = false;
127
+
128
+ /**
129
+ * Whether or not to use a controller name as a subdirectory when rendering
130
+ * @var boolean
131
+ */
132
+ protected $_noController = false;
133
+
134
+ /**
135
+ * Whether or not to autorender postDispatch; per controller/action setting (reset
136
+ * at next invocation)
137
+ * @var boolean
138
+ */
139
+ protected $_noRender = false;
140
+
141
+ /**
142
+ * Characters representing path delimiters in the controller
143
+ * @var string|array
144
+ */
145
+ protected $_pathDelimiters;
146
+
147
+ /**
148
+ * Which named segment of the response to utilize
149
+ * @var string
150
+ */
151
+ protected $_responseSegment = null;
152
+
153
+ /**
154
+ * Which action view script to render
155
+ * @var string
156
+ */
157
+ protected $_scriptAction = null;
158
+
159
+ /**
160
+ * View object basePath
161
+ * @var string
162
+ */
163
+ protected $_viewBasePathSpec = ':moduleDir/views';
164
+
165
+ /**
166
+ * View script path specification string
167
+ * @var string
168
+ */
169
+ protected $_viewScriptPathSpec = ':controller/:action.:suffix';
170
+
171
+ /**
172
+ * View script path specification string, minus controller segment
173
+ * @var string
174
+ */
175
+ protected $_viewScriptPathNoControllerSpec = ':action.:suffix';
176
+
177
+ /**
178
+ * View script suffix
179
+ * @var string
180
+ */
181
+ protected $_viewSuffix = 'phtml';
182
+
183
+ /**
184
+ * Constructor
185
+ *
186
+ * Optionally set view object and options.
187
+ *
188
+ * @param Zend_View_Interface $view
189
+ * @param array $options
190
+ * @return void
191
+ */
192
+ public function __construct(Zend_View_Interface $view = null, array $options = array())
193
+ {
194
+ if (null !== $view) {
195
+ $this->setView($view);
196
+ }
197
+
198
+ if (!empty($options)) {
199
+ $this->_setOptions($options);
200
+ }
201
+ }
202
+
203
+ /**
204
+ * Clone - also make sure the view is cloned.
205
+ *
206
+ * @return void
207
+ */
208
+ public function __clone()
209
+ {
210
+ if (isset($this->view) && $this->view instanceof Zend_View_Interface) {
211
+ $this->view = clone $this->view;
212
+
213
+ }
214
+ }
215
+
216
+ /**
217
+ * Set the view object
218
+ *
219
+ * @param Zend_View_Interface $view
220
+ * @return Zend_Controller_Action_Helper_ViewRenderer Provides a fluent interface
221
+ */
222
+ public function setView(Zend_View_Interface $view)
223
+ {
224
+ $this->view = $view;
225
+ return $this;
226
+ }
227
+
228
+ /**
229
+ * Retrieve front controller instance
230
+ *
231
+ * @return Zend_Controller_Front
232
+ */
233
+ public function getFrontController()
234
+ {
235
+ if (null === $this->_frontController) {
236
+ $this->_frontController = Zend_Controller_Front::getInstance();
237
+ }
238
+
239
+ return $this->_frontController;
240
+ }
241
+
242
+ /**
243
+ * Get current module name
244
+ *
245
+ * @return string
246
+ */
247
+ public function getModule()
248
+ {
249
+ $request = $this->getRequest();
250
+ $module = $request->getModuleName();
251
+ if (null === $module) {
252
+ $module = $this->getFrontController()->getDispatcher()->getDefaultModule();
253
+ }
254
+
255
+ return $module;
256
+ }
257
+
258
+ /**
259
+ * Get module directory
260
+ *
261
+ * @throws Zend_Controller_Action_Exception
262
+ * @return string
263
+ */
264
+ public function getModuleDirectory()
265
+ {
266
+ $module = $this->getModule();
267
+ $moduleDir = $this->getFrontController()->getControllerDirectory($module);
268
+ if ((null === $moduleDir) || is_array($moduleDir)) {
269
+ /**
270
+ * @see Zend_Controller_Action_Exception
271
+ */
272
+ throw new Zend_Controller_Action_Exception('ViewRenderer cannot locate module directory');
273
+ }
274
+ $this->_moduleDir = dirname($moduleDir);
275
+ return $this->_moduleDir;
276
+ }
277
+
278
+ /**
279
+ * Get inflector
280
+ *
281
+ * @return Zend_Filter_Inflector
282
+ */
283
+ public function getInflector()
284
+ {
285
+ if (null === $this->_inflector) {
286
+ /**
287
+ * @see Zend_Filter_Inflector
288
+ */
289
+ require_once 'Zend/Filter/Inflector.php';
290
+ /**
291
+ * @see Zend_Filter_PregReplace
292
+ */
293
+ require_once 'Zend/Filter/PregReplace.php';
294
+ /**
295
+ * @see Zend_Filter_Word_UnderscoreToSeparator
296
+ */
297
+ require_once 'Zend/Filter/Word/UnderscoreToSeparator.php';
298
+ $this->_inflector = new Zend_Filter_Inflector();
299
+ $this->_inflector->setStaticRuleReference('moduleDir', $this->_moduleDir) // moduleDir must be specified before the less specific 'module'
300
+ ->addRules(array(
301
+ ':module' => array('Word_CamelCaseToDash', 'StringToLower'),
302
+ ':controller' => array('Word_CamelCaseToDash', new Zend_Filter_Word_UnderscoreToSeparator('/'), 'StringToLower'),
303
+ ':action' => array('Word_CamelCaseToDash', new Zend_Filter_PregReplace('#[^a-z0-9' . preg_quote('/', '#') . ']+#i', '-'), 'StringToLower'),
304
+ ))
305
+ ->setStaticRuleReference('suffix', $this->_viewSuffix)
306
+ ->setTargetReference($this->_inflectorTarget);
307
+ }
308
+
309
+ // Ensure that module directory is current
310
+ $this->getModuleDirectory();
311
+
312
+ return $this->_inflector;
313
+ }
314
+
315
+ /**
316
+ * Set inflector
317
+ *
318
+ * @param Zend_Filter_Inflector $inflector
319
+ * @param boolean $reference Whether the moduleDir, target, and suffix should be set as references to ViewRenderer properties
320
+ * @return Zend_Controller_Action_Helper_ViewRenderer Provides a fluent interface
321
+ */
322
+ public function setInflector(Zend_Filter_Inflector $inflector, $reference = false)
323
+ {
324
+ $this->_inflector = $inflector;
325
+ if ($reference) {
326
+ $this->_inflector->setStaticRuleReference('suffix', $this->_viewSuffix)
327
+ ->setStaticRuleReference('moduleDir', $this->_moduleDir)
328
+ ->setTargetReference($this->_inflectorTarget);
329
+ }
330
+ return $this;
331
+ }
332
+
333
+ /**
334
+ * Set inflector target
335
+ *
336
+ * @param string $target
337
+ * @return void
338
+ */
339
+ protected function _setInflectorTarget($target)
340
+ {
341
+ $this->_inflectorTarget = (string) $target;
342
+ }
343
+
344
+ /**
345
+ * Set internal module directory representation
346
+ *
347
+ * @param string $dir
348
+ * @return void
349
+ */
350
+ protected function _setModuleDir($dir)
351
+ {
352
+ $this->_moduleDir = (string) $dir;
353
+ }
354
+
355
+ /**
356
+ * Get internal module directory representation
357
+ *
358
+ * @return string
359
+ */
360
+ protected function _getModuleDir()
361
+ {
362
+ return $this->_moduleDir;
363
+ }
364
+
365
+ /**
366
+ * Generate a class prefix for helper and filter classes
367
+ *
368
+ * @return string
369
+ */
370
+ protected function _generateDefaultPrefix()
371
+ {
372
+ if ((null === $this->_actionController) || !strstr(get_class($this->_actionController), '_')) {
373
+ $prefix = 'Zend_View';
374
+ } else {
375
+ $class = get_class($this->_actionController);
376
+ $prefix = substr($class, 0, strpos($class, '_')) . '_View';
377
+ }
378
+
379
+ return $prefix;
380
+ }
381
+
382
+ /**
383
+ * Retrieve base path based on location of current action controller
384
+ *
385
+ * @return string
386
+ */
387
+ protected function _getBasePath()
388
+ {
389
+ if (null === $this->_actionController) {
390
+ return './views';
391
+ }
392
+
393
+ $inflector = $this->getInflector();
394
+ $this->_setInflectorTarget($this->getViewBasePathSpec());
395
+
396
+ $dispatcher = $this->_frontController->getDispatcher();
397
+ $request = $this->getRequest();
398
+
399
+ $parts = array(
400
+ 'module' => (($moduleName = $request->getModuleName()) != '') ? $dispatcher->formatModuleName($moduleName) : $moduleName,
401
+ 'controller' => substr($dispatcher->formatControllerName($request->getControllerName()), 0, -10),
402
+ 'action' => $dispatcher->formatActionName($request->getActionName())
403
+ );
404
+
405
+ $path = $inflector->filter($parts);
406
+ return $path;
407
+ }
408
+
409
+ /**
410
+ * Set options
411
+ *
412
+ * @param array $options
413
+ * @return Zend_Controller_Action_Helper_ViewRenderer Provides a fluent interface
414
+ */
415
+ protected function _setOptions(array $options)
416
+ {
417
+ foreach ($options as $key => $value)
418
+ {
419
+ switch ($key) {
420
+ case 'neverRender':
421
+ case 'neverController':
422
+ case 'noController':
423
+ case 'noRender':
424
+ $property = '_' . $key;
425
+ $this->{$property} = ($value) ? true : false;
426
+ break;
427
+ case 'responseSegment':
428
+ case 'scriptAction':
429
+ case 'viewBasePathSpec':
430
+ case 'viewScriptPathSpec':
431
+ case 'viewScriptPathNoControllerSpec':
432
+ case 'viewSuffix':
433
+ $property = '_' . $key;
434
+ $this->{$property} = (string) $value;
435
+ break;
436
+ default:
437
+ break;
438
+ }
439
+ }
440
+
441
+ return $this;
442
+ }
443
+
444
+ /**
445
+ * Initialize the view object
446
+ *
447
+ * $options may contain the following keys:
448
+ * - neverRender - flag dis/enabling postDispatch() autorender (affects all subsequent calls)
449
+ * - noController - flag indicating whether or not to look for view scripts in subdirectories named after the controller
450
+ * - noRender - flag indicating whether or not to autorender postDispatch()
451
+ * - responseSegment - which named response segment to render a view script to
452
+ * - scriptAction - what action script to render
453
+ * - viewBasePathSpec - specification to use for determining view base path
454
+ * - viewScriptPathSpec - specification to use for determining view script paths
455
+ * - viewScriptPathNoControllerSpec - specification to use for determining view script paths when noController flag is set
456
+ * - viewSuffix - what view script filename suffix to use
457
+ *
458
+ * @param string $path
459
+ * @param string $prefix
460
+ * @param array $options
461
+ * @throws Zend_Controller_Action_Exception
462
+ * @return void
463
+ */
464
+ public function initView($path = null, $prefix = null, array $options = array())
465
+ {
466
+ if (null === $this->view) {
467
+ $this->setView(new Zend_View());
468
+ }
469
+
470
+ // Reset some flags every time
471
+ $options['noController'] = (isset($options['noController'])) ? $options['noController'] : false;
472
+ $options['noRender'] = (isset($options['noRender'])) ? $options['noRender'] : false;
473
+ $this->_scriptAction = null;
474
+ $this->_responseSegment = null;
475
+
476
+ // Set options first; may be used to determine other initializations
477
+ $this->_setOptions($options);
478
+
479
+ // Get base view path
480
+ if (empty($path)) {
481
+ $path = $this->_getBasePath();
482
+ if (empty($path)) {
483
+ /**
484
+ * @see Zend_Controller_Action_Exception
485
+ */
486
+ throw new Zend_Controller_Action_Exception('ViewRenderer initialization failed: retrieved view base path is empty');
487
+ }
488
+ }
489
+
490
+ if (null === $prefix) {
491
+ $prefix = $this->_generateDefaultPrefix();
492
+ }
493
+
494
+ // Determine if this path has already been registered
495
+ $currentPaths = $this->view->getScriptPaths();
496
+ $path = str_replace(array('/', '\\'), '/', $path);
497
+ $pathExists = false;
498
+ foreach ($currentPaths as $tmpPath) {
499
+ $tmpPath = str_replace(array('/', '\\'), '/', $tmpPath);
500
+ if (strstr($tmpPath, $path)) {
501
+ $pathExists = true;
502
+ break;
503
+ }
504
+ }
505
+ if (!$pathExists) {
506
+ $this->view->addBasePath($path, $prefix);
507
+ }
508
+
509
+ // Register view with action controller (unless already registered)
510
+ if ((null !== $this->_actionController) && (null === $this->_actionController->view)) {
511
+ $this->_actionController->view = $this->view;
512
+ $this->_actionController->viewSuffix = $this->_viewSuffix;
513
+ }
514
+ }
515
+
516
+ /**
517
+ * init - initialize view
518
+ *
519
+ * @return void
520
+ */
521
+ public function init()
522
+ {
523
+ if ($this->getFrontController()->getParam('noViewRenderer')) {
524
+ return;
525
+ }
526
+
527
+ $this->initView();
528
+ }
529
+
530
+ /**
531
+ * Set view basePath specification
532
+ *
533
+ * Specification can contain one or more of the following:
534
+ * - :moduleDir - current module directory
535
+ * - :controller - name of current controller in the request
536
+ * - :action - name of current action in the request
537
+ * - :module - name of current module in the request
538
+ *
539
+ * @param string $path
540
+ * @return Zend_Controller_Action_Helper_ViewRenderer Provides a fluent interface
541
+ */
542
+ public function setViewBasePathSpec($path)
543
+ {
544
+ $this->_viewBasePathSpec = (string) $path;
545
+ return $this;
546
+ }
547
+
548
+ /**
549
+ * Retrieve the current view basePath specification string
550
+ *
551
+ * @return string
552
+ */
553
+ public function getViewBasePathSpec()
554
+ {
555
+ return $this->_viewBasePathSpec;
556
+ }
557
+
558
+ /**
559
+ * Set view script path specification
560
+ *
561
+ * Specification can contain one or more of the following:
562
+ * - :moduleDir - current module directory
563
+ * - :controller - name of current controller in the request
564
+ * - :action - name of current action in the request
565
+ * - :module - name of current module in the request
566
+ *
567
+ * @param string $path
568
+ * @return Zend_Controller_Action_Helper_ViewRenderer Provides a fluent interface
569
+ */
570
+ public function setViewScriptPathSpec($path)
571
+ {
572
+ $this->_viewScriptPathSpec = (string) $path;
573
+ return $this;
574
+ }
575
+
576
+ /**
577
+ * Retrieve the current view script path specification string
578
+ *
579
+ * @return string
580
+ */
581
+ public function getViewScriptPathSpec()
582
+ {
583
+ return $this->_viewScriptPathSpec;
584
+ }
585
+
586
+ /**
587
+ * Set view script path specification (no controller variant)
588
+ *
589
+ * Specification can contain one or more of the following:
590
+ * - :moduleDir - current module directory
591
+ * - :controller - name of current controller in the request
592
+ * - :action - name of current action in the request
593
+ * - :module - name of current module in the request
594
+ *
595
+ * :controller will likely be ignored in this variant.
596
+ *
597
+ * @param string $path
598
+ * @return Zend_Controller_Action_Helper_ViewRenderer Provides a fluent interface
599
+ */
600
+ public function setViewScriptPathNoControllerSpec($path)
601
+ {
602
+ $this->_viewScriptPathNoControllerSpec = (string) $path;
603
+ return $this;
604
+ }
605
+
606
+ /**
607
+ * Retrieve the current view script path specification string (no controller variant)
608
+ *
609
+ * @return string
610
+ */
611
+ public function getViewScriptPathNoControllerSpec()
612
+ {
613
+ return $this->_viewScriptPathNoControllerSpec;
614
+ }
615
+
616
+ /**
617
+ * Get a view script based on an action and/or other variables
618
+ *
619
+ * Uses values found in current request if no values passed in $vars.
620
+ *
621
+ * If {@link $_noController} is set, uses {@link $_viewScriptPathNoControllerSpec};
622
+ * otherwise, uses {@link $_viewScriptPathSpec}.
623
+ *
624
+ * @param string $action
625
+ * @param array $vars
626
+ * @return string
627
+ */
628
+ public function getViewScript($action = null, array $vars = array())
629
+ {
630
+ $request = $this->getRequest();
631
+ if ((null === $action) && (!isset($vars['action']))) {
632
+ $action = $this->getScriptAction();
633
+ if (null === $action) {
634
+ $action = $request->getActionName();
635
+ }
636
+ $vars['action'] = $action;
637
+ } elseif (null !== $action) {
638
+ $vars['action'] = $action;
639
+ }
640
+
641
+ $inflector = $this->getInflector();
642
+ if ($this->getNoController() || $this->getNeverController()) {
643
+ $this->_setInflectorTarget($this->getViewScriptPathNoControllerSpec());
644
+ } else {
645
+ $this->_setInflectorTarget($this->getViewScriptPathSpec());
646
+ }
647
+ return $this->_translateSpec($vars);
648
+ }
649
+
650
+ /**
651
+ * Set the neverRender flag (i.e., globally dis/enable autorendering)
652
+ *
653
+ * @param boolean $flag
654
+ * @return Zend_Controller_Action_Helper_ViewRenderer Provides a fluent interface
655
+ */
656
+ public function setNeverRender($flag = true)
657
+ {
658
+ $this->_neverRender = ($flag) ? true : false;
659
+ return $this;
660
+ }
661
+
662
+ /**
663
+ * Retrieve neverRender flag value
664
+ *
665
+ * @return boolean
666
+ */
667
+ public function getNeverRender()
668
+ {
669
+ return $this->_neverRender;
670
+ }
671
+
672
+ /**
673
+ * Set the noRender flag (i.e., whether or not to autorender)
674
+ *
675
+ * @param boolean $flag
676
+ * @return Zend_Controller_Action_Helper_ViewRenderer Provides a fluent interface
677
+ */
678
+ public function setNoRender($flag = true)
679
+ {
680
+ $this->_noRender = ($flag) ? true : false;
681
+ return $this;
682
+ }
683
+
684
+ /**
685
+ * Retrieve noRender flag value
686
+ *
687
+ * @return boolean
688
+ */
689
+ public function getNoRender()
690
+ {
691
+ return $this->_noRender;
692
+ }
693
+
694
+ /**
695
+ * Set the view script to use
696
+ *
697
+ * @param string $name
698
+ * @return Zend_Controller_Action_Helper_ViewRenderer Provides a fluent interface
699
+ */
700
+ public function setScriptAction($name)
701
+ {
702
+ $this->_scriptAction = (string) $name;
703
+ return $this;
704
+ }
705
+
706
+ /**
707
+ * Retrieve view script name
708
+ *
709
+ * @return string
710
+ */
711
+ public function getScriptAction()
712
+ {
713
+ return $this->_scriptAction;
714
+ }
715
+
716
+ /**
717
+ * Set the response segment name
718
+ *
719
+ * @param string $name
720
+ * @return Zend_Controller_Action_Helper_ViewRenderer Provides a fluent interface
721
+ */
722
+ public function setResponseSegment($name)
723
+ {
724
+ if (null === $name) {
725
+ $this->_responseSegment = null;
726
+ } else {
727
+ $this->_responseSegment = (string) $name;
728
+ }
729
+
730
+ return $this;
731
+ }
732
+
733
+ /**
734
+ * Retrieve named response segment name
735
+ *
736
+ * @return string
737
+ */
738
+ public function getResponseSegment()
739
+ {
740
+ return $this->_responseSegment;
741
+ }
742
+
743
+ /**
744
+ * Set the noController flag (i.e., whether or not to render into controller subdirectories)
745
+ *
746
+ * @param boolean $flag
747
+ * @return Zend_Controller_Action_Helper_ViewRenderer Provides a fluent interface
748
+ */
749
+ public function setNoController($flag = true)
750
+ {
751
+ $this->_noController = ($flag) ? true : false;
752
+ return $this;
753
+ }
754
+
755
+ /**
756
+ * Retrieve noController flag value
757
+ *
758
+ * @return boolean
759
+ */
760
+ public function getNoController()
761
+ {
762
+ return $this->_noController;
763
+ }
764
+
765
+ /**
766
+ * Set the neverController flag (i.e., whether or not to render into controller subdirectories)
767
+ *
768
+ * @param boolean $flag
769
+ * @return Zend_Controller_Action_Helper_ViewRenderer Provides a fluent interface
770
+ */
771
+ public function setNeverController($flag = true)
772
+ {
773
+ $this->_neverController = ($flag) ? true : false;
774
+ return $this;
775
+ }
776
+
777
+ /**
778
+ * Retrieve neverController flag value
779
+ *
780
+ * @return boolean
781
+ */
782
+ public function getNeverController()
783
+ {
784
+ return $this->_neverController;
785
+ }
786
+
787
+ /**
788
+ * Set view script suffix
789
+ *
790
+ * @param string $suffix
791
+ * @return Zend_Controller_Action_Helper_ViewRenderer Provides a fluent interface
792
+ */
793
+ public function setViewSuffix($suffix)
794
+ {
795
+ $this->_viewSuffix = (string) $suffix;
796
+ return $this;
797
+ }
798
+
799
+ /**
800
+ * Get view script suffix
801
+ *
802
+ * @return string
803
+ */
804
+ public function getViewSuffix()
805
+ {
806
+ return $this->_viewSuffix;
807
+ }
808
+
809
+ /**
810
+ * Set options for rendering a view script
811
+ *
812
+ * @param string $action View script to render
813
+ * @param string $name Response named segment to render to
814
+ * @param boolean $noController Whether or not to render within a subdirectory named after the controller
815
+ * @return Zend_Controller_Action_Helper_ViewRenderer Provides a fluent interface
816
+ */
817
+ public function setRender($action = null, $name = null, $noController = null)
818
+ {
819
+ if (null !== $action) {
820
+ $this->setScriptAction($action);
821
+ }
822
+
823
+ if (null !== $name) {
824
+ $this->setResponseSegment($name);
825
+ }
826
+
827
+ if (null !== $noController) {
828
+ $this->setNoController($noController);
829
+ }
830
+
831
+ return $this;
832
+ }
833
+
834
+ /**
835
+ * Inflect based on provided vars
836
+ *
837
+ * Allowed variables are:
838
+ * - :moduleDir - current module directory
839
+ * - :module - current module name
840
+ * - :controller - current controller name
841
+ * - :action - current action name
842
+ * - :suffix - view script file suffix
843
+ *
844
+ * @param array $vars
845
+ * @return string
846
+ */
847
+ protected function _translateSpec(array $vars = array())
848
+ {
849
+ $inflector = $this->getInflector();
850
+ $request = $this->getRequest();
851
+ $dispatcher = $this->_frontController->getDispatcher();
852
+ $module = $dispatcher->formatModuleName($request->getModuleName());
853
+ $controller = substr($dispatcher->formatControllerName($request->getControllerName()), 0, -10);
854
+ $action = $dispatcher->formatActionName($request->getActionName());
855
+
856
+ $params = compact('module', 'controller', 'action');
857
+ foreach ($vars as $key => $value) {
858
+ switch ($key) {
859
+ case 'module':
860
+ case 'controller':
861
+ case 'action':
862
+ case 'moduleDir':
863
+ case 'suffix':
864
+ $params[$key] = (string) $value;
865
+ break;
866
+ default:
867
+ break;
868
+ }
869
+ }
870
+
871
+ if (isset($params['suffix'])) {
872
+ $origSuffix = $this->getViewSuffix();
873
+ $this->setViewSuffix($params['suffix']);
874
+ }
875
+ if (isset($moduleDir)) {
876
+ $origModuleDir = $this->_getModuleDir();
877
+ $this->_setModuleDir($params['moduleDir']);
878
+ }
879
+
880
+ $filtered = $inflector->filter($params);
881
+
882
+ if (isset($params['suffix'])) {
883
+ $this->setViewSuffix($origSuffix);
884
+ }
885
+ if (isset($moduleDir)) {
886
+ $this->_setModuleDir($origModuleDir);
887
+ }
888
+
889
+ return $filtered;
890
+ }
891
+
892
+ /**
893
+ * Render a view script (optionally to a named response segment)
894
+ *
895
+ * Sets the noRender flag to true when called.
896
+ *
897
+ * @param string $script
898
+ * @param string $name
899
+ * @return void
900
+ */
901
+ public function renderScript($script, $name = null)
902
+ {
903
+ if (null === $name) {
904
+ $name = $this->getResponseSegment();
905
+ }
906
+
907
+ $this->getResponse()->appendBody(
908
+ $this->view->render($script),
909
+ $name
910
+ );
911
+
912
+ $this->setNoRender();
913
+ }
914
+
915
+ /**
916
+ * Render a view based on path specifications
917
+ *
918
+ * Renders a view based on the view script path specifications.
919
+ *
920
+ * @param string $action
921
+ * @param string $name
922
+ * @param boolean $noController
923
+ * @return void
924
+ */
925
+ public function render($action = null, $name = null, $noController = null)
926
+ {
927
+ $this->setRender($action, $name, $noController);
928
+ $path = $this->getViewScript();
929
+ $this->renderScript($path, $name);
930
+ }
931
+
932
+ /**
933
+ * Render a script based on specification variables
934
+ *
935
+ * Pass an action, and one or more specification variables (view script suffix)
936
+ * to determine the view script path, and render that script.
937
+ *
938
+ * @param string $action
939
+ * @param array $vars
940
+ * @param string $name
941
+ * @return void
942
+ */
943
+ public function renderBySpec($action = null, array $vars = array(), $name = null)
944
+ {
945
+ if (null !== $name) {
946
+ $this->setResponseSegment($name);
947
+ }
948
+
949
+ $path = $this->getViewScript($action, $vars);
950
+
951
+ $this->renderScript($path);
952
+ }
953
+
954
+ /**
955
+ * postDispatch - auto render a view
956
+ *
957
+ * Only autorenders if:
958
+ * - _noRender is false
959
+ * - action controller is present
960
+ * - request has not been re-dispatched (i.e., _forward() has not been called)
961
+ * - response is not a redirect
962
+ *
963
+ * @return void
964
+ */
965
+ public function postDispatch()
966
+ {
967
+ if ($this->_shouldRender()) {
968
+ $this->render();
969
+ }
970
+ }
971
+
972
+ /**
973
+ * Should the ViewRenderer render a view script?
974
+ *
975
+ * @return boolean
976
+ */
977
+ protected function _shouldRender()
978
+ {
979
+ return (!$this->getFrontController()->getParam('noViewRenderer')
980
+ && !$this->_neverRender
981
+ && !$this->_noRender
982
+ && (null !== $this->_actionController)
983
+ && $this->getRequest()->isDispatched()
984
+ && !$this->getResponse()->isRedirect()
985
+ );
986
+ }
987
+
988
+ /**
989
+ * Use this helper as a method; proxies to setRender()
990
+ *
991
+ * @param string $action
992
+ * @param string $name
993
+ * @param boolean $noController
994
+ * @return void
995
+ */
996
+ public function direct($action = null, $name = null, $noController = null)
997
+ {
998
+ $this->setRender($action, $name, $noController);
999
+ }
1000
+ }
lib/Zend/Controller/Action/HelperBroker.php ADDED
@@ -0,0 +1,378 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Zend Framework
4
+ *
5
+ * LICENSE
6
+ *
7
+ * This source file is subject to the new BSD license that is bundled
8
+ * with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://framework.zend.com/license/new-bsd
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@zend.com so we can send you a copy immediately.
14
+ *
15
+ * @category Zend
16
+ * @package Zend_Controller
17
+ * @subpackage Zend_Controller_Action
18
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
19
+ * @license http://framework.zend.com/license/new-bsd New BSD License
20
+ */
21
+
22
+
23
+ /**
24
+ * @see Zend_Controller_Action_Exception
25
+ */
26
+ require_once 'Zend/Controller/Action/Exception.php';
27
+
28
+ /**
29
+ * @see Zend_Controller_Action_Helper_Abstract
30
+ */
31
+ require_once 'Zend/Controller/Action/Helper/Abstract.php';
32
+
33
+ /**
34
+ * @see Zend_Loader
35
+ */
36
+ require_once 'Zend/Loader.php';
37
+
38
+ /**
39
+ * @category Zend
40
+ * @package Zend_Controller
41
+ * @subpackage Zend_Controller_Action
42
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
43
+ * @license http://framework.zend.com/license/new-bsd New BSD License
44
+ */
45
+ class Zend_Controller_Action_HelperBroker
46
+ {
47
+ /**
48
+ * $_helpers - Helper array
49
+ *
50
+ * @var Zend_Controller_Action_Helper_Abstract[]
51
+ */
52
+ static protected $_helpers = array();
53
+
54
+ /**
55
+ * $_paths - paths to Action_Helpers
56
+ *
57
+ * @var array
58
+ */
59
+ static protected $_paths = array(array(
60
+ 'dir' => 'Zend/Controller/Action/Helper/',
61
+ 'prefix' => 'Zend_Controller_Action_Helper_'
62
+ ));
63
+
64
+ /**
65
+ * $_actionController - ActionController reference
66
+ *
67
+ * @var Zend_Controller_Action
68
+ */
69
+ protected $_actionController;
70
+
71
+ /**
72
+ * addHelper() - Add helper objects
73
+ *
74
+ * @param Zend_Controller_Action_Helper_Abstract $helper
75
+ * @return void
76
+ */
77
+ static public function addHelper(Zend_Controller_Action_Helper_Abstract $helper)
78
+ {
79
+ $helper_name = $helper->getName();
80
+ self::$_helpers[$helper_name] = $helper;
81
+ return;
82
+ }
83
+
84
+ /**
85
+ * addPrefix() - Add repository of helpers by prefix
86
+ *
87
+ * @param string $prefix
88
+ */
89
+ static public function addPrefix($prefix)
90
+ {
91
+ $prefix = rtrim($prefix, '_');
92
+ $path = str_replace('_', DIRECTORY_SEPARATOR, $prefix);
93
+ self::addPath($path, $prefix);
94
+ return;
95
+ }
96
+
97
+ /**
98
+ * resetHelpers()
99
+ *
100
+ * @return void
101
+ */
102
+ static public function resetHelpers()
103
+ {
104
+ self::$_helpers = array();
105
+ return;
106
+ }
107
+
108
+ /**
109
+ * addPath() - Add path to repositories where Action_Helpers could be found.
110
+ *
111
+ * @param string $path
112
+ * @param string $prefix Optional; defaults to 'Zend_Controller_Action_Helper'
113
+ * @return void
114
+ */
115
+ static public function addPath($path, $prefix = 'Zend_Controller_Action_Helper')
116
+ {
117
+ // make sure it ends in a PATH_SEPARATOR
118
+ if (substr($path, -1, 1) != DIRECTORY_SEPARATOR) {
119
+ $path .= DIRECTORY_SEPARATOR;
120
+ }
121
+
122
+ // make sure it ends in a PATH_SEPARATOR
123
+ $prefix = rtrim($prefix, '_') . '_';
124
+
125
+ $info['dir'] = $path;
126
+ $info['prefix'] = $prefix;
127
+
128
+ self::$_paths[] = $info;
129
+ return;
130
+ }
131
+
132
+ /**
133
+ * __construct() -
134
+ *
135
+ * @param Zend_Controller_Action $actionController
136
+ * @return void
137
+ */
138
+ public function __construct(Zend_Controller_Action $actionController)
139
+ {
140
+ $this->_actionController = $actionController;
141
+ foreach (self::$_helpers as $helper) {
142
+ $helper->setActionController($actionController);
143
+ $helper->init();
144
+ }
145
+ }
146
+
147
+ /**
148
+ * notifyPreDispatch() - called by action controller dispatch method
149
+ *
150
+ * @return void
151
+ */
152
+ public function notifyPreDispatch()
153
+ {
154
+ foreach (self::$_helpers as $helper) {
155
+ $helper->preDispatch();
156
+ }
157
+ }
158
+
159
+ /**
160
+ * notifyPostDispatch() - called by action controller dispatch method
161
+ *
162
+ * @return void
163
+ */
164
+ public function notifyPostDispatch()
165
+ {
166
+ foreach (self::$_helpers as $helper) {
167
+ $helper->postDispatch();
168
+ }
169
+ }
170
+
171
+ /**
172
+ * Normalize helper name for lookups
173
+ *
174
+ * @param string $name
175
+ * @return string
176
+ */
177
+ protected static function _normalizeHelperName($name)
178
+ {
179
+ if (strpos($name, '_') !== false) {
180
+ $name = str_replace(' ', '', ucwords(str_replace('_', ' ', $name)));
181
+ }
182
+
183
+ return ucfirst($name);
184
+ }
185
+
186
+ /**
187
+ * getHelper() - get helper by name
188
+ *
189
+ * @param string $name
190
+ * @return Zend_Controller_Action_Helper_Abstract
191
+ */
192
+ public function getHelper($name)
193
+ {
194
+ $name = self::_normalizeHelperName($name);
195
+
196
+ if (!array_key_exists($name, self::$_helpers)) {
197
+ self::_loadHelper($name);
198
+ }
199
+
200
+ $helper = self::$_helpers[$name];
201
+
202
+ $initialize = false;
203
+ if (null === ($actionController = $helper->getActionController())) {
204
+ $initialize = true;
205
+ } elseif ($actionController !== $this->_actionController) {
206
+ $initialize = true;
207
+ }
208
+
209
+ if ($initialize) {
210
+ $helper->setActionController($this->_actionController)
211
+ ->init();
212
+ }
213
+
214
+ return $helper;
215
+ }
216
+
217
+ /**
218
+ * Retrieve or initialize a helper statically
219
+ *
220
+ * Retrieves a helper object statically, loading on-demand if the helper
221
+ * does not already exist in the stack. Always returns a helper, unless
222
+ * the helper class cannot be found.
223
+ *
224
+ * @param string $name
225
+ * @return Zend_Controller_Action_Helper_Abstract
226
+ */
227
+ public static function getStaticHelper($name)
228
+ {
229
+ $name = self::_normalizeHelperName($name);
230
+
231
+ if (!array_key_exists($name, self::$_helpers)) {
232
+ self::_loadHelper($name);
233
+ }
234
+
235
+ $helper = self::$_helpers[$name];
236
+
237
+ return $helper;
238
+ }
239
+
240
+ /**
241
+ * getExistingHelper() - get helper by name
242
+ *
243
+ * Static method to retrieve helper object. Only retrieves helpers already
244
+ * initialized with the broker (either via addHelper() or on-demand loading
245
+ * via getHelper()).
246
+ *
247
+ * Throws an exception if the referenced helper does not exist in the
248
+ * stack; use {@link hasHelper()} to check if the helper is registered
249
+ * prior to retrieving it.
250
+ *
251
+ * @param string $name
252
+ * @return Zend_Controller_Action_Helper_Abstract
253
+ * @throws Zend_Controller_Action_Exception
254
+ */
255
+ public static function getExistingHelper($name)
256
+ {
257
+ $name = self::_normalizeHelperName($name);
258
+
259
+ if (array_key_exists($name, self::$_helpers)) {
260
+ return self::$_helpers[$name];
261
+ }
262
+
263
+ throw new Zend_Controller_Action_Exception('Action helper "' . $name . '" has not been registered with the helper broker');
264
+ }
265
+
266
+ /**
267
+ * Return all registered helpers as helper => object pairs
268
+ *
269
+ * @return array
270
+ */
271
+ public static function getExistingHelpers()
272
+ {
273
+ return self::$_helpers;
274
+ }
275
+
276
+ /**
277
+ * Is a particular helper loaded in the broker?
278
+ *
279
+ * @param string $name
280
+ * @return boolean
281
+ */
282
+ public static function hasHelper($name)
283
+ {
284
+ $name = self::_normalizeHelperName($name);
285
+ return array_key_exists($name, self::$_helpers);
286
+ }
287
+
288
+ /**
289
+ * Remove a particular helper from the broker
290
+ *
291
+ * @param string $name
292
+ * @return boolean
293
+ */
294
+ public static function removeHelper($name)
295
+ {
296
+ $name = self::_normalizeHelperName($name);
297
+ if (array_key_exists($name, self::$_helpers)) {
298
+ unset(self::$_helpers[$name]);
299
+ return true;
300
+ }
301
+
302
+ return false;
303
+ }
304
+
305
+ /**
306
+ * _loadHelper()
307
+ *
308
+ * @param string $name
309
+ * @return void
310
+ */
311
+ protected static function _loadHelper($name)
312
+ {
313
+ $file = $name . '.php';
314
+
315
+ $paths = array_reverse(self::$_paths);
316
+ foreach ($paths as $info) {
317
+ $dir = $info['dir'];
318
+ $prefix = $info['prefix'];
319
+
320
+ $class = $prefix . $name;
321
+
322
+ if (class_exists($class, false)) {
323
+ $helper = new $class();
324
+
325
+ if (!$helper instanceof Zend_Controller_Action_Helper_Abstract) {
326
+ throw new Zend_Controller_Action_Exception('Helper name ' . $name . ' -> class ' . $class . ' is not of type Zend_Controller_Action_Helper_Abstract');
327
+ }
328
+
329
+ self::$_helpers[$helper->getName()] = $helper;
330
+ return;
331
+
332
+ } elseif (Zend_Loader::isReadable($dir . $file)) {
333
+ include_once $dir . $file;
334
+
335
+ if (class_exists($class, false)) {
336
+ $helper = new $class();
337
+ if (!$helper instanceof Zend_Controller_Action_Helper_Abstract) {
338
+ throw new Zend_Controller_Action_Exception('Helper name ' . $name . ' -> class ' . $class . ' is not of type Zend_Controller_Action_Helper_Abstract');
339
+ }
340
+
341
+ self::$_helpers[$helper->getName()] = $helper;
342
+ return;
343
+ }
344
+ }
345
+ }
346
+
347
+ throw new Zend_Controller_Action_Exception('Action Helper by name ' . $name . ' not found.');
348
+ }
349
+
350
+ /**
351
+ * __call()
352
+ *
353
+ * @param string $method
354
+ * @param array $args
355
+ * @return mixed
356
+ * @throws Zend_Controller_Action_Exception if helper does not have a direct() method
357
+ */
358
+ public function __call($method, $args)
359
+ {
360
+ $helper = $this->getHelper($method);
361
+ if (method_exists($helper, 'direct')) {
362
+ return call_user_func_array(array($helper, 'direct'), $args);
363
+ }
364
+
365
+ throw new Zend_Controller_Action_Exception('Helper "' . $method . '" does not support overloading via direct()');
366
+ }
367
+
368
+ /**
369
+ * __get()
370
+ *
371
+ * @param string $name
372
+ * @return Zend_Controller_Action_Helper_Abstract
373
+ */
374
+ public function __get($name)
375
+ {
376
+ return $this->getHelper($name);
377
+ }
378
+ }
lib/Zend/Controller/Dispatcher/Abstract.php ADDED
@@ -0,0 +1,448 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Zend Framework
4
+ *
5
+ * LICENSE
6
+ *
7
+ * This source file is subject to the new BSD license that is bundled
8
+ * with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://framework.zend.com/license/new-bsd
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@zend.com so we can send you a copy immediately.
14
+ *
15
+ * @category Zend
16
+ * @package Zend_Controller
17
+ * @subpackage Dispatcher
18
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
19
+ * @license http://framework.zend.com/license/new-bsd New BSD License
20
+ */
21
+
22
+ /** Zend_Controller_Dispatcher_Interface */
23
+ require_once 'Zend/Controller/Dispatcher/Interface.php';
24
+
25
+ /** Zend_Controller_Request_Abstract */
26
+ require_once 'Zend/Controller/Request/Abstract.php';
27
+
28
+ /** Zend_Controller_Response_Abstract */
29
+ require_once 'Zend/Controller/Response/Abstract.php';
30
+
31
+ /** Zend_Controller_Front */
32
+ require_once 'Zend/Controller/Front.php';
33
+
34
+ /**
35
+ * @category Zend
36
+ * @package Zend_Controller
37
+ * @subpackage Dispatcher
38
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
39
+ * @license http://framework.zend.com/license/new-bsd New BSD License
40
+ */
41
+ abstract class Zend_Controller_Dispatcher_Abstract implements Zend_Controller_Dispatcher_Interface
42
+ {
43
+ /**
44
+ * Default action
45
+ * @var string
46
+ */
47
+ protected $_defaultAction = 'index';
48
+
49
+ /**
50
+ * Default controller
51
+ * @var string
52
+ */
53
+ protected $_defaultController = 'index';
54
+
55
+ /**
56
+ * Default module
57
+ * @var string
58
+ */
59
+ protected $_defaultModule = 'default';
60
+
61
+ /**
62
+ * Front Controller instance
63
+ * @var Zend_Controller_Front
64
+ */
65
+ protected $_frontController;
66
+
67
+ /**
68
+ * Array of invocation parameters to use when instantiating action
69
+ * controllers
70
+ * @var array
71
+ */
72
+ protected $_invokeParams = array();
73
+
74
+ /**
75
+ * Path delimiter character
76
+ * @var string
77
+ */
78
+ protected $_pathDelimiter = '_';
79
+
80
+ /**
81
+ * Response object to pass to action controllers, if any
82
+ * @var Zend_Controller_Response_Abstract|null
83
+ */
84
+ protected $_response = null;
85
+
86
+ /**
87
+ * Word delimiter characters
88
+ * @var array
89
+ */
90
+ protected $_wordDelimiter = array('-', '.');
91
+
92
+ /**
93
+ * Constructor
94
+ *
95
+ * @return void
96
+ */
97
+ public function __construct(array $params = array())
98
+ {
99
+ $this->setParams($params);
100
+ }
101
+
102
+ /**
103
+ * Formats a string into a controller name. This is used to take a raw
104
+ * controller name, such as one stored inside a Zend_Controller_Request_Abstract
105
+ * object, and reformat it to a proper class name that a class extending
106
+ * Zend_Controller_Action would use.
107
+ *
108
+ * @param string $unformatted
109
+ * @return string
110
+ */
111
+ public function formatControllerName($unformatted)
112
+ {
113
+ return ucfirst($this->_formatName($unformatted)) . 'Controller';
114
+ }
115
+
116
+ /**
117
+ * Formats a string into an action name. This is used to take a raw
118
+ * action name, such as one that would be stored inside a Zend_Controller_Request_Abstract
119
+ * object, and reformat into a proper method name that would be found
120
+ * inside a class extending Zend_Controller_Action.
121
+ *
122
+ * @param string $unformatted
123
+ * @return string
124
+ */
125
+ public function formatActionName($unformatted)
126
+ {
127
+ $formatted = $this->_formatName($unformatted, true);
128
+ return strtolower(substr($formatted, 0, 1)) . substr($formatted, 1) . 'Action';
129
+ }
130
+
131
+ /**
132
+ * Verify delimiter
133
+ *
134
+ * Verify a delimiter to use in controllers or actions. May be a single
135
+ * string or an array of strings.
136
+ *
137
+ * @param string|array $spec
138
+ * @return array
139
+ * @throws Zend_Controller_Dispatcher_Exception with invalid delimiters
140
+ */
141
+ public function _verifyDelimiter($spec)
142
+ {
143
+ if (is_string($spec)) {
144
+ return (array) $spec;
145
+ } elseif (is_array($spec)) {
146
+ $allStrings = true;
147
+ foreach ($spec as $delim) {
148
+ if (!is_string($delim)) {
149
+ $allStrings = false;
150
+ break;
151
+ }
152
+ }
153
+
154
+ if (!$allStrings) {
155
+ require_once 'Zend/Controller/Dispatcher/Exception.php';
156
+ throw new Zend_Controller_Dispatcher_Exception('Word delimiter array must contain only strings');
157
+ }
158
+
159
+ return $spec;
160
+ }
161
+
162
+ require_once 'Zend/Controller/Dispatcher/Exception.php';
163
+ throw new Zend_Controller_Dispatcher_Exception('Invalid word delimiter');
164
+ }
165
+
166
+ /**
167
+ * Retrieve the word delimiter character(s) used in
168
+ * controller or action names
169
+ *
170
+ * @return array
171
+ */
172
+ public function getWordDelimiter()
173
+ {
174
+ return $this->_wordDelimiter;
175
+ }
176
+
177
+ /**
178
+ * Set word delimiter
179
+ *
180
+ * Set the word delimiter to use in controllers and actions. May be a
181
+ * single string or an array of strings.
182
+ *
183
+ * @param string|array $spec
184
+ * @return Zend_Controller_Dispatcher_Abstract
185
+ */
186
+ public function setWordDelimiter($spec)
187
+ {
188
+ $spec = $this->_verifyDelimiter($spec);
189
+ $this->_wordDelimiter = $spec;
190
+
191
+ return $this;
192
+ }
193
+
194
+ /**
195
+ * Retrieve the path delimiter character(s) used in
196
+ * controller names
197
+ *
198
+ * @return array
199
+ */
200
+ public function getPathDelimiter()
201
+ {
202
+ return $this->_pathDelimiter;
203
+ }
204
+
205
+ /**
206
+ * Set path delimiter
207
+ *
208
+ * Set the path delimiter to use in controllers. May be a single string or
209
+ * an array of strings.
210
+ *
211
+ * @param string $spec
212
+ * @return Zend_Controller_Dispatcher_Abstract
213
+ */
214
+ public function setPathDelimiter($spec)
215
+ {
216
+ if (!is_string($spec)) {
217
+ require_once 'Zend/Controller/Dispatcher/Exception.php';
218
+ throw new Zend_Controller_Dispatcher_Exception('Invalid path delimiter');
219
+ }
220
+ $this->_pathDelimiter = $spec;
221
+
222
+ return $this;
223
+ }
224
+
225
+ /**
226
+ * Formats a string from a URI into a PHP-friendly name.
227
+ *
228
+ * By default, replaces words separated by the word separator character(s)
229
+ * with camelCaps. If $isAction is false, it also preserves replaces words
230
+ * separated by the path separation character with an underscore, making
231
+ * the following word Title cased. All non-alphanumeric characters are
232
+ * removed.
233
+ *
234
+ * @param string $unformatted
235
+ * @param boolean $isAction Defaults to false
236
+ * @return string
237
+ */
238
+ protected function _formatName($unformatted, $isAction = false)
239
+ {
240
+ // preserve directories
241
+ if (!$isAction) {
242
+ $segments = explode($this->getPathDelimiter(), $unformatted);
243
+ } else {
244
+ $segments = (array) $unformatted;
245
+ }
246
+
247
+ foreach ($segments as $key => $segment) {
248
+ $segment = str_replace($this->getWordDelimiter(), ' ', strtolower($segment));
249
+ $segment = preg_replace('/[^a-z0-9 ]/', '', $segment);
250
+ $segments[$key] = str_replace(' ', '', ucwords($segment));
251
+ }
252
+
253
+ return implode('_', $segments);
254
+ }
255
+
256
+ /**
257
+ * Retrieve front controller instance
258
+ *
259
+ * @return Zend_Controller_Front
260
+ */
261
+ public function getFrontController()
262
+ {
263
+ if (null === $this->_frontController) {
264
+ require_once 'Zend/Controller/Front.php';
265
+ $this->_frontController = Zend_Controller_Front::getInstance();
266
+ }
267
+
268
+ return $this->_frontController;
269
+ }
270
+
271
+ /**
272
+ * Set front controller instance
273
+ *
274
+ * @param Zend_Controller_Front $controller
275
+ * @return Zend_Controller_Dispatcher_Abstract
276
+ */
277
+ public function setFrontController(Zend_Controller_Front $controller)
278
+ {
279
+ $this->_frontController = $controller;
280
+ return $this;
281
+ }
282
+
283
+ /**
284
+ * Add or modify a parameter to use when instantiating an action controller
285
+ *
286
+ * @param string $name
287
+ * @param mixed $value
288
+ * @return Zend_Controller_Dispatcher_Abstract
289
+ */
290
+ public function setParam($name, $value)
291
+ {
292
+ $name = (string) $name;
293
+ $this->_invokeParams[$name] = $value;
294
+ return $this;
295
+ }
296
+
297
+ /**
298
+ * Set parameters to pass to action controller constructors
299
+ *
300
+ * @param array $params
301
+ * @return Zend_Controller_Dispatcher_Abstract
302
+ */
303
+ public function setParams(array $params)
304
+ {
305
+ $this->_invokeParams = array_merge($this->_invokeParams, $params);
306
+ return $this;
307
+ }
308
+
309
+ /**
310
+ * Retrieve a single parameter from the controller parameter stack
311
+ *
312
+ * @param string $name
313
+ * @return mixed
314
+ */
315
+ public function getParam($name)
316
+ {
317
+ if(isset($this->_invokeParams[$name])) {
318
+ return $this->_invokeParams[$name];
319
+ }
320
+
321
+ return null;
322
+ }
323
+
324
+ /**
325
+ * Retrieve action controller instantiation parameters
326
+ *
327
+ * @return array
328
+ */
329
+ public function getParams()
330
+ {
331
+ return $this->_invokeParams;
332
+ }
333
+
334
+ /**
335
+ * Clear the controller parameter stack
336
+ *
337
+ * By default, clears all parameters. If a parameter name is given, clears
338
+ * only that parameter; if an array of parameter names is provided, clears
339
+ * each.
340
+ *
341
+ * @param null|string|array single key or array of keys for params to clear
342
+ * @return Zend_Controller_Dispatcher_Abstract
343
+ */
344
+ public function clearParams($name = null)
345
+ {
346
+ if (null === $name) {
347
+ $this->_invokeParams = array();
348
+ } elseif (is_string($name) && isset($this->_invokeParams[$name])) {
349
+ unset($this->_invokeParams[$name]);
350
+ } elseif (is_array($name)) {
351
+ foreach ($name as $key) {
352
+ if (is_string($key) && isset($this->_invokeParams[$key])) {
353
+ unset($this->_invokeParams[$key]);
354
+ }
355
+ }
356
+ }
357
+
358
+ return $this;
359
+ }
360
+
361
+ /**
362
+ * Set response object to pass to action controllers
363
+ *
364
+ * @param Zend_Controller_Response_Abstract|null $response
365
+ * @return Zend_Controller_Dispatcher_Abstract
366
+ */
367
+ public function setResponse(Zend_Controller_Response_Abstract $response = null)
368
+ {
369
+ $this->_response = $response;
370
+ return $this;
371
+ }
372
+
373
+ /**
374
+ * Return the registered response object
375
+ *
376
+ * @return Zend_Controller_Response_Abstract|null
377
+ */
378
+ public function getResponse()
379
+ {
380
+ return $this->_response;
381
+ }
382
+
383
+ /**
384
+ * Set the default controller (minus any formatting)
385
+ *
386
+ * @param string $controller
387
+ * @return Zend_Controller_Dispatcher_Abstract
388
+ */
389
+ public function setDefaultControllerName($controller)
390
+ {
391
+ $this->_defaultController = (string) $controller;
392
+ return $this;
393
+ }
394
+
395
+ /**
396
+ * Retrieve the default controller name (minus formatting)
397
+ *
398
+ * @return string
399
+ */
400
+ public function getDefaultControllerName()
401
+ {
402
+ return $this->_defaultController;
403
+ }
404
+
405
+ /**
406
+ * Set the default action (minus any formatting)
407
+ *
408
+ * @param string $action
409
+ * @return Zend_Controller_Dispatcher_Abstract
410
+ */
411
+ public function setDefaultAction($action)
412
+ {
413
+ $this->_defaultAction = (string) $action;
414
+ return $this;
415
+ }
416
+
417
+ /**
418
+ * Retrieve the default action name (minus formatting)
419
+ *
420
+ * @return string
421
+ */
422
+ public function getDefaultAction()
423
+ {
424
+ return $this->_defaultAction;
425
+ }
426
+
427
+ /**
428
+ * Set the default module
429
+ *
430
+ * @param string $module
431
+ * @return Zend_Controller_Dispatcher_Abstract
432
+ */
433
+ public function setDefaultModule($module)
434
+ {
435
+ $this->_defaultModule = (string) $module;
436
+ return $this;
437
+ }
438
+
439
+ /**
440
+ * Retrieve the default module
441
+ *
442
+ * @return string
443
+ */
444
+ public function getDefaultModule()
445
+ {
446
+ return $this->_defaultModule;
447
+ }
448
+ }
lib/Zend/Controller/Dispatcher/Exception.php ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Zend Framework
4
+ *
5
+ * LICENSE
6
+ *
7
+ * This source file is subject to the new BSD license that is bundled
8
+ * with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://framework.zend.com/license/new-bsd
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@zend.com so we can send you a copy immediately.
14
+ *
15
+ * @category Zend
16
+ * @package Zend_Controller
17
+ * @subpackage Dispatcher
18
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
19
+ * @license http://framework.zend.com/license/new-bsd New BSD License
20
+ */
21
+
22
+
23
+ /** Zend_Controller_Exception */
24
+ require_once 'Zend/Controller/Exception.php';
25
+
26
+
27
+ /**
28
+ * @category Zend
29
+ * @package Zend_Controller
30
+ * @subpackage Dispatcher
31
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
32
+ * @license http://framework.zend.com/license/new-bsd New BSD License
33
+ */
34
+ class Zend_Controller_Dispatcher_Exception extends Zend_Controller_Exception
35
+ {}
36
+
lib/Zend/Controller/Dispatcher/Interface.php ADDED
@@ -0,0 +1,172 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Zend Framework
4
+ *
5
+ * LICENSE
6
+ *
7
+ * This source file is subject to the new BSD license that is bundled
8
+ * with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://framework.zend.com/license/new-bsd
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@zend.com so we can send you a copy immediately.
14
+ *
15
+ * @package Zend_Controller
16
+ * @subpackage Dispatcher
17
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
18
+ * @license http://framework.zend.com/license/new-bsd New BSD License
19
+ */
20
+
21
+ /**
22
+ * Zend_Controller_Request_Abstract
23
+ */
24
+ require_once 'Zend/Controller/Request/Abstract.php';
25
+
26
+ /**
27
+ * Zend_Controller_Response_Abstract
28
+ */
29
+ require_once 'Zend/Controller/Response/Abstract.php';
30
+
31
+ /**
32
+ * @package Zend_Controller
33
+ * @subpackage Dispatcher
34
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
35
+ * @license http://framework.zend.com/license/new-bsd New BSD License
36
+ */
37
+ interface Zend_Controller_Dispatcher_Interface
38
+ {
39
+ /**
40
+ * Formats a string into a controller name. This is used to take a raw
41
+ * controller name, such as one that would be packaged inside a request
42
+ * object, and reformat it to a proper class name that a class extending
43
+ * Zend_Controller_Action would use.
44
+ *
45
+ * @param string $unformatted
46
+ * @return string
47
+ */
48
+ public function formatControllerName($unformatted);
49
+
50
+ /**
51
+ * Formats a string into an action name. This is used to take a raw
52
+ * action name, such as one that would be packaged inside a request
53
+ * object, and reformat into a proper method name that would be found
54
+ * inside a class extending Zend_Controller_Action.
55
+ *
56
+ * @param string $unformatted
57
+ * @return string
58
+ */
59
+ public function formatActionName($unformatted);
60
+
61
+ /**
62
+ * Returns TRUE if an action can be dispatched, or FALSE otherwise.
63
+ *
64
+ * @param Zend_Controller_Request_Abstract $request
65
+ * @return boolean
66
+ */
67
+ public function isDispatchable(Zend_Controller_Request_Abstract $request);
68
+
69
+ /**
70
+ * Add or modify a parameter with which to instantiate an Action Controller
71
+ *
72
+ * @param string $name
73
+ * @param mixed $value
74
+ * @return Zend_Controller_Dispatcher_Interface
75
+ */
76
+ public function setParam($name, $value);
77
+
78
+ /**
79
+ * Set an array of a parameters to pass to the Action Controller constructor
80
+ *
81
+ * @param array $params
82
+ * @return Zend_Controller_Dispatcher_Interface
83
+ */
84
+ public function setParams(array $params);
85
+
86
+ /**
87
+ * Retrieve a single parameter from the controller parameter stack
88
+ *
89
+ * @param string $name
90
+ * @return mixed
91
+ */
92
+ public function getParam($name);
93
+
94
+ /**
95
+ * Retrieve the parameters to pass to the Action Controller constructor
96
+ *
97
+ * @return array
98
+ */
99
+ public function getParams();
100
+
101
+ /**
102
+ * Clear the controller parameter stack
103
+ *
104
+ * By default, clears all parameters. If a parameter name is given, clears
105
+ * only that parameter; if an array of parameter names is provided, clears
106
+ * each.
107
+ *
108
+ * @param null|string|array single key or array of keys for params to clear
109
+ * @return Zend_Controller_Dispatcher_Interface
110
+ */
111
+ public function clearParams($name = null);
112
+
113
+ /**
114
+ * Set the response object to use, if any
115
+ *
116
+ * @param Zend_Controller_Response_Abstract|null $response
117
+ * @return void
118
+ */
119
+ public function setResponse(Zend_Controller_Response_Abstract $response = null);
120
+
121
+ /**
122
+ * Retrieve the response object, if any
123
+ *
124
+ * @return Zend_Controller_Response_Abstract|null
125
+ */
126
+ public function getResponse();
127
+
128
+ /**
129
+ * Add a controller directory to the controller directory stack
130
+ *
131
+ * @param string $path
132
+ * @param string $args
133
+ * @return Zend_Controller_Dispatcher_Interface
134
+ */
135
+ public function addControllerDirectory($path, $args = null);
136
+
137
+ /**
138
+ * Set the directory where controller files are stored
139
+ *
140
+ * Specify a string or an array; if an array is specified, all paths will be
141
+ * added.
142
+ *
143
+ * @param string|array $dir
144
+ * @return Zend_Controller_Dispatcher_Interface
145
+ */
146
+ public function setControllerDirectory($path);
147
+
148
+ /**
149
+ * Return the currently set directory(ies) for controller file lookup
150
+ *
151
+ * @return array
152
+ */
153
+ public function getControllerDirectory();
154
+
155
+ /**
156
+ * Dispatches a request object to a controller/action. If the action
157
+ * requests a forward to another action, a new request will be returned.
158
+ *
159
+ * @param Zend_Controller_Request_Abstract $request
160
+ * @param Zend_Controller_Response_Abstract $response
161
+ * @return Zend_Controller_Request_Abstract|boolean
162
+ */
163
+ public function dispatch(Zend_Controller_Request_Abstract $request, Zend_Controller_Response_Abstract $response);
164
+
165
+ /**
166
+ * Whether or not a given module is valid
167
+ *
168
+ * @param string $module
169
+ * @return boolean
170
+ */
171
+ public function isValidModule($module);
172
+ }
lib/Zend/Controller/Dispatcher/Standard.php ADDED
@@ -0,0 +1,489 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Zend Framework
4
+ *
5
+ * LICENSE
6
+ *
7
+ * This source file is subject to the new BSD license that is bundled
8
+ * with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://framework.zend.com/license/new-bsd
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@zend.com so we can send you a copy immediately.
14
+ *
15
+ * @category Zend
16
+ * @package Zend_Controller
17
+ * @subpackage Dispatcher
18
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
19
+ * @license http://framework.zend.com/license/new-bsd New BSD License
20
+ */
21
+
22
+ /** Zend_Loader */
23
+ require_once 'Zend/Loader.php';
24
+
25
+ /** Zend_Controller_Dispatcher_Abstract */
26
+ require_once 'Zend/Controller/Dispatcher/Abstract.php';
27
+
28
+ /** Zend_Controller_Request_Abstract */
29
+ require_once 'Zend/Controller/Request/Abstract.php';
30
+
31
+ /** Zend_Controller_Response_Abstract */
32
+ require_once 'Zend/Controller/Response/Abstract.php';
33
+
34
+ /** Zend_Controller_Action */
35
+ require_once 'Zend/Controller/Action.php';
36
+
37
+ /**
38
+ * @category Zend
39
+ * @package Zend_Controller
40
+ * @subpackage Dispatcher
41
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
42
+ * @license http://framework.zend.com/license/new-bsd New BSD License
43
+ */
44
+ class Zend_Controller_Dispatcher_Standard extends Zend_Controller_Dispatcher_Abstract
45
+ {
46
+ /**
47
+ * Current dispatchable directory
48
+ * @var string
49
+ */
50
+ protected $_curDirectory;
51
+
52
+ /**
53
+ * Current module (formatted)
54
+ * @var string
55
+ */
56
+ protected $_curModule;
57
+
58
+ /**
59
+ * Controller directory(ies)
60
+ * @var array
61
+ */
62
+ protected $_controllerDirectory = array();
63
+
64
+ /**
65
+ * Constructor: Set current module to default value
66
+ *
67
+ * @param array $params
68
+ * @return void
69
+ */
70
+ public function __construct(array $params = array())
71
+ {
72
+ parent::__construct($params);
73
+ $this->_curModule = $this->getDefaultModule();
74
+ }
75
+
76
+ /**
77
+ * Add a single path to the controller directory stack
78
+ *
79
+ * @param string $path
80
+ * @param string $module
81
+ * @return Zend_Controller_Dispatcher_Standard
82
+ */
83
+ public function addControllerDirectory($path, $module = null)
84
+ {
85
+ if (null === $module) {
86
+ $module = $this->_defaultModule;
87
+ }
88
+
89
+ $module = (string) $module;
90
+ $path = rtrim((string) $path, '/\\');
91
+
92
+ $this->_controllerDirectory[$module] = $path;
93
+ return $this;
94
+ }
95
+
96
+ /**
97
+ * Set controller directory
98
+ *
99
+ * @param array|string $directory
100
+ * @return Zend_Controller_Dispatcher_Standard
101
+ */
102
+ public function setControllerDirectory($directory, $module = null)
103
+ {
104
+ $this->_controllerDirectory = array();
105
+
106
+ if (is_string($directory)) {
107
+ $this->addControllerDirectory($directory, $module);
108
+ } elseif (is_array($directory)) {
109
+ foreach ((array) $directory as $module => $path) {
110
+ $this->addControllerDirectory($path, $module);
111
+ }
112
+ } else {
113
+ throw new Zend_Controller_Exception('Controller directory spec must be either a string or an array');
114
+ }
115
+
116
+ return $this;
117
+ }
118
+
119
+ /**
120
+ * Return the currently set directories for Zend_Controller_Action class
121
+ * lookup
122
+ *
123
+ * If a module is specified, returns just that directory.
124
+ *
125
+ * @param string $module Module name
126
+ * @return array|string Returns array of all directories by default, single
127
+ * module directory if module argument provided
128
+ */
129
+ public function getControllerDirectory($module = null)
130
+ {
131
+ if (null === $module) {
132
+ return $this->_controllerDirectory;
133
+ }
134
+
135
+ $module = (string) $module;
136
+ if (array_key_exists($module, $this->_controllerDirectory)) {
137
+ return $this->_controllerDirectory[$module];
138
+ }
139
+
140
+ return null;
141
+ }
142
+
143
+ /**
144
+ * Remove a controller directory by module name
145
+ *
146
+ * @param string $module
147
+ * @return bool
148
+ */
149
+ public function removeControllerDirectory($module)
150
+ {
151
+ $module = (string) $module;
152
+ if (array_key_exists($module, $this->_controllerDirectory)) {
153
+ unset($this->_controllerDirectory[$module]);
154
+ return true;
155
+ }
156
+ return false;
157
+ }
158
+
159
+ /**
160
+ * Format the module name.
161
+ *
162
+ * @param string $unformatted
163
+ * @return string
164
+ */
165
+ public function formatModuleName($unformatted)
166
+ {
167
+ if (($this->_defaultModule == $unformatted) && !$this->getParam('prefixDefaultModule')) {
168
+ return $unformatted;
169
+ }
170
+
171
+ return ucfirst($this->_formatName($unformatted));
172
+ }
173
+
174
+ /**
175
+ * Format action class name
176
+ *
177
+ * @param string $moduleName Name of the current module
178
+ * @param string $className Name of the action class
179
+ * @return string Formatted class name
180
+ */
181
+ public function formatClassName($moduleName, $className)
182
+ {
183
+ return $this->formatModuleName($moduleName) . '_' . $className;
184
+ }
185
+
186
+ /**
187
+ * Convert a class name to a filename
188
+ *
189
+ * @param string $class
190
+ * @return string
191
+ */
192
+ public function classToFilename($class)
193
+ {
194
+ return str_replace('_', DIRECTORY_SEPARATOR, $class) . '.php';
195
+ }
196
+
197
+ /**
198
+ * Returns TRUE if the Zend_Controller_Request_Abstract object can be
199
+ * dispatched to a controller.
200
+ *
201
+ * Use this method wisely. By default, the dispatcher will fall back to the
202
+ * default controller (either in the module specified or the global default)
203
+ * if a given controller does not exist. This method returning false does
204
+ * not necessarily indicate the dispatcher will not still dispatch the call.
205
+ *
206
+ * @param Zend_Controller_Request_Abstract $action
207
+ * @return boolean
208
+ */
209
+ public function isDispatchable(Zend_Controller_Request_Abstract $request)
210
+ {
211
+ $className = $this->getControllerClass($request);
212
+ if (!$className) {
213
+ return false;
214
+ }
215
+
216
+ if (class_exists($className, false)) {
217
+ return true;
218
+ }
219
+
220
+ $fileSpec = $this->classToFilename($className);
221
+ $dispatchDir = $this->getDispatchDirectory();
222
+ $test = $dispatchDir . DIRECTORY_SEPARATOR . $fileSpec;
223
+ return Zend_Loader::isReadable($test);
224
+ }
225
+
226
+ /**
227
+ * Dispatch to a controller/action
228
+ *
229
+ * By default, if a controller is not dispatchable, dispatch() will throw
230
+ * an exception. If you wish to use the default controller instead, set the
231
+ * param 'useDefaultControllerAlways' via {@link setParam()}.
232
+ *
233
+ * @param Zend_Controller_Request_Abstract $request
234
+ * @param Zend_Controller_Response_Abstract $response
235
+ * @return boolean
236
+ * @throws Zend_Controller_Dispatcher_Exception
237
+ */
238
+ public function dispatch(Zend_Controller_Request_Abstract $request, Zend_Controller_Response_Abstract $response)
239
+ {
240
+ $this->setResponse($response);
241
+
242
+ /**
243
+ * Get controller class
244
+ */
245
+ if (!$this->isDispatchable($request)) {
246
+ $controller = $request->getControllerName();
247
+ if (!$this->getParam('useDefaultControllerAlways') && !empty($controller)) {
248
+ require_once 'Zend/Controller/Dispatcher/Exception.php';
249
+ throw new Zend_Controller_Dispatcher_Exception('Invalid controller specified (' . $request->getControllerName() . ')');
250
+ }
251
+
252
+ $className = $this->getDefaultControllerClass($request);
253
+ } else {
254
+ $className = $this->getControllerClass($request);
255
+ if (!$className) {
256
+ $className = $this->getDefaultControllerClass($request);
257
+ }
258
+ }
259
+
260
+ /**
261
+ * Load the controller class file
262
+ */
263
+ $className = $this->loadClass($className);
264
+
265
+ /**
266
+ * Instantiate controller with request, response, and invocation
267
+ * arguments; throw exception if it's not an action controller
268
+ */
269
+ $controller = new $className($request, $this->getResponse(), $this->getParams());
270
+ if (!$controller instanceof Zend_Controller_Action) {
271
+ require_once 'Zend/Controller/Dispatcher/Exception.php';
272
+ throw new Zend_Controller_Dispatcher_Exception("Controller '$className' is not an instance of Zend_Controller_Action");
273
+ }
274
+
275
+ /**
276
+ * Retrieve the action name
277
+ */
278
+ $action = $this->getActionMethod($request);
279
+
280
+ /**
281
+ * Dispatch the method call
282
+ */
283
+ $request->setDispatched(true);
284
+
285
+ // by default, buffer output
286
+ $disableOb = $this->getParam('disableOutputBuffering');
287
+ $obLevel = ob_get_level();
288
+ if (empty($disableOb)) {
289
+ ob_start();
290
+ }
291
+
292
+ try {
293
+ $controller->dispatch($action);
294
+ } catch (Exception $e) {
295
+ // Clean output buffer on error
296
+ $curObLevel = ob_get_level();
297
+ if ($curObLevel > $obLevel) {
298
+ do {
299
+ ob_get_clean();
300
+ $curObLevel = ob_get_level();
301
+ } while ($curObLevel > $obLevel);
302
+ }
303
+
304
+ throw $e;
305
+ }
306
+
307
+ if (empty($disableOb)) {
308
+ $content = ob_get_clean();
309
+ $response->appendBody($content);
310
+ }
311
+
312
+ // Destroy the page controller instance and reflection objects
313
+ $controller = null;
314
+ }
315
+
316
+ /**
317
+ * Load a controller class
318
+ *
319
+ * Attempts to load the controller class file from
320
+ * {@link getControllerDirectory()}. If the controller belongs to a
321
+ * module, looks for the module prefix to the controller class.
322
+ *
323
+ * @param string $className
324
+ * @return string Class name loaded
325
+ * @throws Zend_Controller_Dispatcher_Exception if class not loaded
326
+ */
327
+ public function loadClass($className)
328
+ {
329
+ $finalClass = $className;
330
+ if (($this->_defaultModule != $this->_curModule)
331
+ || $this->getParam('prefixDefaultModule'))
332
+ {
333
+ $finalClass = $this->formatClassName($this->_curModule, $className);
334
+ }
335
+ if (class_exists($finalClass, false)) {
336
+ return $finalClass;
337
+ }
338
+
339
+ $dispatchDir = $this->getDispatchDirectory();
340
+ $loadFile = $dispatchDir . DIRECTORY_SEPARATOR . $this->classToFilename($className);
341
+ $dir = dirname($loadFile);
342
+ $file = basename($loadFile);
343
+
344
+ try {
345
+ Zend_Loader::loadFile($file, $dir, true);
346
+ } catch (Zend_Exception $e) {
347
+ require_once 'Zend/Controller/Dispatcher/Exception.php';
348
+ throw new Zend_Controller_Dispatcher_Exception('Cannot load controller class "' . $className . '" from file "' . $file . '" in directory "' . $dir . '"');
349
+ }
350
+
351
+ if (!class_exists($finalClass, false)) {
352
+ require_once 'Zend/Controller/Dispatcher/Exception.php';
353
+ throw new Zend_Controller_Dispatcher_Exception('Invalid controller class ("' . $finalClass . '")');
354
+ }
355
+
356
+ return $finalClass;
357
+ }
358
+
359
+ /**
360
+ * Get controller class name
361
+ *
362
+ * Try request first; if not found, try pulling from request parameter;
363
+ * if still not found, fallback to default
364
+ *
365
+ * @param Zend_Controller_Request_Abstract $request
366
+ * @return string|false Returns class name on success
367
+ */
368
+ public function getControllerClass(Zend_Controller_Request_Abstract $request)
369
+ {
370
+ $controllerName = $request->getControllerName();
371
+ if (empty($controllerName)) {
372
+ if (!$this->getParam('useDefaultControllerAlways')) {
373
+ return false;
374
+ }
375
+ $controllerName = $this->getDefaultControllerName();
376
+ $request->setControllerName($controllerName);
377
+ }
378
+
379
+ $className = $this->formatControllerName($controllerName);
380
+
381
+ $controllerDirs = $this->getControllerDirectory();
382
+ $module = $request->getModuleName();
383
+ if ($this->isValidModule($module)) {
384
+ $this->_curModule = $module;
385
+ $this->_curDirectory = $controllerDirs[$module];
386
+ } elseif ($this->isValidModule($this->_defaultModule)) {
387
+ $request->setModuleName($this->_defaultModule);
388
+ $this->_curModule = $this->_defaultModule;
389
+ $this->_curDirectory = $controllerDirs[$this->_defaultModule];
390
+ } else {
391
+ require_once 'Zend/Controller/Exception.php';
392
+ throw new Zend_Controller_Exception('No default module defined for this application');
393
+ }
394
+
395
+ return $className;
396
+ }
397
+
398
+ /**
399
+ * Determine if a given module is valid
400
+ *
401
+ * @param string $module
402
+ * @return bool
403
+ */
404
+ public function isValidModule($module)
405
+ {
406
+ $controllerDir = $this->getControllerDirectory();
407
+ return (is_string($module) && isset($controllerDir[$module]));
408
+ }
409
+
410
+ /**
411
+ * Retrieve default controller class
412
+ *
413
+ * Determines whether the default controller to use lies within the
414
+ * requested module, or if the global default should be used.
415
+ *
416
+ * By default, will only use the module default unless that controller does
417
+ * not exist; if this is the case, it falls back to the default controller
418
+ * in the default module.
419
+ *
420
+ * @param Zend_Controller_Request_Abstract $request
421
+ * @return string
422
+ */
423
+ public function getDefaultControllerClass(Zend_Controller_Request_Abstract $request)
424
+ {
425
+ $controller = $this->getDefaultControllerName();
426
+ $default = $this->formatControllerName($controller);
427
+ $request->setControllerName($controller)
428
+ ->setActionName(null);
429
+
430
+ $module = $request->getModuleName();
431
+ $controllerDirs = $this->getControllerDirectory();
432
+ $this->_curModule = $this->_defaultModule;
433
+ $this->_curDirectory = $controllerDirs[$this->_defaultModule];
434
+ if ($this->isValidModule($module)) {
435
+ $found = false;
436
+ if (class_exists($default, false)) {
437
+ $found = true;
438
+ } else {
439
+ $moduleDir = $controllerDirs[$module];
440
+ $fileSpec = $moduleDir . DIRECTORY_SEPARATOR . $this->classToFilename($default);
441
+ if (Zend_Loader::isReadable($fileSpec)) {
442
+ $found = true;
443
+ $this->_curDirectory = $moduleDir;
444
+ }
445
+ }
446
+ if ($found) {
447
+ $request->setModuleName($module);
448
+ $this->_curModule = $this->formatModuleName($module);
449
+ }
450
+ } else {
451
+ $request->setModuleName($this->_defaultModule);
452
+ }
453
+
454
+ return $default;
455
+ }
456
+
457
+ /**
458
+ * Return the value of the currently selected dispatch directory (as set by
459
+ * {@link getController()})
460
+ *
461
+ * @return string
462
+ */
463
+ public function getDispatchDirectory()
464
+ {
465
+ return $this->_curDirectory;
466
+ }
467
+
468
+ /**
469
+ * Determine the action name
470
+ *
471
+ * First attempt to retrieve from request; then from request params
472
+ * using action key; default to default action
473
+ *
474
+ * Returns formatted action name
475
+ *
476
+ * @param Zend_Controller_Request_Abstract $request
477
+ * @return string
478
+ */
479
+ public function getActionMethod(Zend_Controller_Request_Abstract $request)
480
+ {
481
+ $action = $request->getActionName();
482
+ if (empty($action)) {
483
+ $action = $this->getDefaultAction();
484
+ $request->setActionName($action);
485
+ }
486
+
487
+ return $this->formatActionName($action);
488
+ }
489
+ }
lib/Zend/Controller/Exception.php ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Zend Framework
4
+ *
5
+ * LICENSE
6
+ *
7
+ * This source file is subject to the new BSD license that is bundled
8
+ * with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://framework.zend.com/license/new-bsd
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@zend.com so we can send you a copy immediately.
14
+ *
15
+ * @category Zend
16
+ * @package Zend_Controller
17
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
18
+ * @license http://framework.zend.com/license/new-bsd New BSD License
19
+ */
20
+
21
+
22
+ /** Zend_Exception */
23
+ require_once 'Zend/Exception.php';
24
+
25
+
26
+ /**
27
+ * @category Zend
28
+ * @package Zend_Controller
29
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
30
+ * @license http://framework.zend.com/license/new-bsd New BSD License
31
+ */
32
+ class Zend_Controller_Exception extends Zend_Exception
33
+ {}
34
+
lib/Zend/Controller/Front.php ADDED
@@ -0,0 +1,954 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Zend Framework
4
+ *
5
+ * LICENSE
6
+ *
7
+ * This source file is subject to the new BSD license that is bundled
8
+ * with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://framework.zend.com/license/new-bsd
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@zend.com so we can send you a copy immediately.
14
+ *
15
+ * @category Zend
16
+ * @package Zend_Controller
17
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
18
+ * @license http://framework.zend.com/license/new-bsd New BSD License
19
+ */
20
+
21
+
22
+ /** Zend_Loader */
23
+ require_once 'Zend/Loader.php';
24
+
25
+ /** Zend_Controller_Action_HelperBroker */
26
+ require_once 'Zend/Controller/Action/HelperBroker.php';
27
+
28
+ /** Zend_Controller_Exception */
29
+ require_once 'Zend/Controller/Exception.php';
30
+
31
+ /** Zend_Controller_Plugin_Broker */
32
+ require_once 'Zend/Controller/Plugin/Broker.php';
33
+
34
+ /** Zend_Controller_Request_Abstract */
35
+ require_once 'Zend/Controller/Request/Abstract.php';
36
+
37
+ /** Zend_Controller_Router_Interface */
38
+ require_once 'Zend/Controller/Router/Interface.php';
39
+
40
+ /** Zend_Controller_Dispatcher_Interface */
41
+ require_once 'Zend/Controller/Dispatcher/Interface.php';
42
+
43
+ /** Zend_Controller_Response_Abstract */
44
+ require_once 'Zend/Controller/Response/Abstract.php';
45
+
46
+ /**
47
+ * @category Zend
48
+ * @package Zend_Controller
49
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
50
+ * @license http://framework.zend.com/license/new-bsd New BSD License
51
+ */
52
+ class Zend_Controller_Front
53
+ {
54
+ /**
55
+ * Base URL
56
+ * @var string
57
+ */
58
+ protected $_baseUrl = null;
59
+
60
+ /**
61
+ * Directory|ies where controllers are stored
62
+ *
63
+ * @var string|array
64
+ */
65
+ protected $_controllerDir = null;
66
+
67
+ /**
68
+ * Instance of Zend_Controller_Dispatcher_Interface
69
+ * @var Zend_Controller_Dispatcher_Interface
70
+ */
71
+ protected $_dispatcher = null;
72
+
73
+ /**
74
+ * Singleton instance
75
+ *
76
+ * Marked only as protected to allow extension of the class. To extend,
77
+ * simply override {@link getInstance()}.
78
+ *
79
+ * @var Zend_Controller_Front
80
+ */
81
+ protected static $_instance = null;
82
+
83
+ /**
84
+ * Array of invocation parameters to use when instantiating action
85
+ * controllers
86
+ * @var array
87
+ */
88
+ protected $_invokeParams = array();
89
+
90
+ /**
91
+ * Subdirectory within a module containing controllers; defaults to 'controllers'
92
+ * @var string
93
+ */
94
+ protected $_moduleControllerDirectoryName = 'controllers';
95
+
96
+ /**
97
+ * Instance of Zend_Controller_Plugin_Broker
98
+ * @var Zend_Controller_Plugin_Broker
99
+ */
100
+ protected $_plugins = null;
101
+
102
+ /**
103
+ * Instance of Zend_Controller_Request_Abstract
104
+ * @var Zend_Controller_Request_Abstract
105
+ */
106
+ protected $_request = null;
107
+
108
+ /**
109
+ * Instance of Zend_Controller_Response_Abstract
110
+ * @var Zend_Controller_Response_Abstract
111
+ */
112
+ protected $_response = null;
113
+
114
+ /**
115
+ * Whether or not to return the response prior to rendering output while in
116
+ * {@link dispatch()}; default is to send headers and render output.
117
+ * @var boolean
118
+ */
119
+ protected $_returnResponse = false;
120
+
121
+ /**
122
+ * Instance of Zend_Controller_Router_Interface
123
+ * @var Zend_Controller_Router_Interface
124
+ */
125
+ protected $_router = null;
126
+
127
+ /**
128
+ * Whether or not exceptions encountered in {@link dispatch()} should be
129
+ * thrown or trapped in the response object
130
+ * @var boolean
131
+ */
132
+ protected $_throwExceptions = false;
133
+
134
+ /**
135
+ * Constructor
136
+ *
137
+ * Instantiate using {@link getInstance()}; front controller is a singleton
138
+ * object.
139
+ *
140
+ * Instantiates the plugin broker.
141
+ *
142
+ * @return void
143
+ */
144
+ protected function __construct()
145
+ {
146
+ $this->_plugins = new Zend_Controller_Plugin_Broker();
147
+ }
148
+
149
+ /**
150
+ * Enforce singleton; disallow cloning
151
+ *
152
+ * @return void
153
+ */
154
+ private function __clone()
155
+ {
156
+ }
157
+
158
+ /**
159
+ * Singleton instance
160
+ *
161
+ * @return Zend_Controller_Front
162
+ */
163
+ public static function getInstance()
164
+ {
165
+ if (null === self::$_instance) {
166
+ self::$_instance = new self();
167
+ }
168
+
169
+ return self::$_instance;
170
+ }
171
+
172
+ /**
173
+ * Resets all object properties of the singleton instance
174
+ *
175
+ * Primarily used for testing; could be used to chain front controllers.
176
+ *
177
+ * @return void
178
+ */
179
+ public function resetInstance()
180
+ {
181
+ $reflection = new ReflectionObject($this);
182
+ foreach ($reflection->getProperties() as $property) {
183
+ $name = $property->getName();
184
+ switch ($name) {
185
+ case '_instance':
186
+ break;
187
+ case '_controllerDir':
188
+ case '_invokeParams':
189
+ $this->{$name} = array();
190
+ break;
191
+ case '_plugins':
192
+ $this->{$name} = new Zend_Controller_Plugin_Broker();
193
+ break;
194
+ case '_throwExceptions':
195
+ case '_returnResponse':
196
+ $this->{$name} = false;
197
+ break;
198
+ case '_moduleControllerDirectoryName':
199
+ $this->{$name} = 'controllers';
200
+ break;
201
+ default:
202
+ $this->{$name} = null;
203
+ break;
204
+ }
205
+ }
206
+ }
207
+
208
+ /**
209
+ * Convenience feature, calls setControllerDirectory()->setRouter()->dispatch()
210
+ *
211
+ * In PHP 5.1.x, a call to a static method never populates $this -- so run()
212
+ * may actually be called after setting up your front controller.
213
+ *
214
+ * @param string|array $controllerDirectory Path to Zend_Controller_Action
215
+ * controller classes or array of such paths
216
+ * @return void
217
+ * @throws Zend_Controller_Exception if called from an object instance
218
+ */
219
+ public static function run($controllerDirectory)
220
+ {
221
+ self::getInstance()
222
+ ->setControllerDirectory($controllerDirectory)
223
+ ->dispatch();
224
+ }
225
+
226
+ /**
227
+ * Add a controller directory to the controller directory stack
228
+ *
229
+ * If $args is presented and is a string, uses it for the array key mapping
230
+ * to the directory specified.
231
+ *
232
+ * @param string $directory
233
+ * @param string $module Optional argument; module with which to associate directory. If none provided, assumes 'default'
234
+ * @return Zend_Controller_Front
235
+ * @throws Zend_Controller_Exception if directory not found or readable
236
+ */
237
+ public function addControllerDirectory($directory, $module = null)
238
+ {
239
+ $this->getDispatcher()->addControllerDirectory($directory, $module);
240
+ return $this;
241
+ }
242
+
243
+ /**
244
+ * Set controller directory
245
+ *
246
+ * Stores controller directory(ies) in dispatcher. May be an array of
247
+ * directories or a string containing a single directory.
248
+ *
249
+ * @param string|array $directory Path to Zend_Controller_Action controller
250
+ * classes or array of such paths
251
+ * @param string $module Optional module name to use with string $directory
252
+ * @return Zend_Controller_Front
253
+ */
254
+ public function setControllerDirectory($directory, $module = null)
255
+ {
256
+ $this->getDispatcher()->setControllerDirectory($directory, $module);
257
+ return $this;
258
+ }
259
+
260
+ /**
261
+ * Retrieve controller directory
262
+ *
263
+ * Retrieves:
264
+ * - Array of all controller directories if no $name passed
265
+ * - String path if $name passed and exists as a key in controller directory array
266
+ * - null if $name passed but does not exist in controller directory keys
267
+ *
268
+ * @param string $name Default null
269
+ * @return array|string|null
270
+ */
271
+ public function getControllerDirectory($name = null)
272
+ {
273
+ return $this->getDispatcher()->getControllerDirectory($name);
274
+ }
275
+
276
+ /**
277
+ * Remove a controller directory by module name
278
+ *
279
+ * @param string $module
280
+ * @return bool
281
+ */
282
+ public function removeControllerDirectory($module)
283
+ {
284
+ return $this->getDispatcher()->removeControllerDirectory($module);
285
+ }
286
+
287
+ /**
288
+ * Specify a directory as containing modules
289
+ *
290
+ * Iterates through the directory, adding any subdirectories as modules;
291
+ * the subdirectory within each module named after {@link $_moduleControllerDirectoryName}
292
+ * will be used as the controller directory path.
293
+ *
294
+ * @param string $path
295
+ * @return Zend_Controller_Front
296
+ */
297
+ public function addModuleDirectory($path)
298
+ {
299
+ try{
300
+ $dir = new DirectoryIterator($path);
301
+ }catch(Exception $e){
302
+ throw new Zend_Controller_Exception("Directory $path not readable");
303
+ }
304
+ foreach ($dir as $file) {
305
+ if ($file->isDot() || !$file->isDir()) {
306
+ continue;
307
+ }
308
+
309
+ $module = $file->getFilename();
310
+
311
+ // Don't use SCCS directories as modules
312
+ if (preg_match('/^[^a-z]/i', $module) || ('CVS' == $module)) {
313
+ continue;
314
+ }
315
+
316
+ $moduleDir = $file->getPathname() . DIRECTORY_SEPARATOR . $this->getModuleControllerDirectoryName();
317
+ $this->addControllerDirectory($moduleDir, $module);
318
+ }
319
+
320
+ return $this;
321
+ }
322
+
323
+ /**
324
+ * Set the directory name within a module containing controllers
325
+ *
326
+ * @param string $name
327
+ * @return Zend_Controller_Front
328
+ */
329
+ public function setModuleControllerDirectoryName($name = 'controllers')
330
+ {
331
+ $this->_moduleControllerDirectoryName = (string) $name;
332
+
333
+ return $this;
334
+ }
335
+
336
+ /**
337
+ * Return the directory name within a module containing controllers
338
+ *
339
+ * @return string
340
+ */
341
+ public function getModuleControllerDirectoryName()
342
+ {
343
+ return $this->_moduleControllerDirectoryName;
344
+ }
345
+
346
+ /**
347
+ * Set the default controller (unformatted string)
348
+ *
349
+ * @param string $controller
350
+ * @return Zend_Controller_Front
351
+ */
352
+ public function setDefaultControllerName($controller)
353
+ {
354
+ $dispatcher = $this->getDispatcher();
355
+ $dispatcher->setDefaultControllerName($controller);
356
+ return $this;
357
+ }
358
+
359
+ /**
360
+ * Retrieve the default controller (unformatted string)
361
+ *
362
+ * @return string
363
+ */
364
+ public function getDefaultControllerName()
365
+ {
366
+ return $this->getDispatcher()->getDefaultControllerName();
367
+ }
368
+
369
+ /**
370
+ * Set the default action (unformatted string)
371
+ *
372
+ * @param string $action
373
+ * @return Zend_Controller_Front
374
+ */
375
+ public function setDefaultAction($action)
376
+ {
377
+ $dispatcher = $this->getDispatcher();
378
+ $dispatcher->setDefaultAction($action);
379
+ return $this;
380
+ }
381
+
382
+ /**
383
+ * Retrieve the default action (unformatted string)
384
+ *
385
+ * @return string
386
+ */
387
+ public function getDefaultAction()
388
+ {
389
+ return $this->getDispatcher()->getDefaultAction();
390
+ }
391
+
392
+ /**
393
+ * Set the default module name
394
+ *
395
+ * @param string $module
396
+ * @return Zend_Controller_Front
397
+ */
398
+ public function setDefaultModule($module)
399
+ {
400
+ $dispatcher = $this->getDispatcher();
401
+ $dispatcher->setDefaultModule($module);
402
+ return $this;
403
+ }
404
+
405
+ /**
406
+ * Retrieve the default module
407
+ *
408
+ * @return string
409
+ */
410
+ public function getDefaultModule()
411
+ {
412
+ return $this->getDispatcher()->getDefaultModule();
413
+ }
414
+
415
+ /**
416
+ * Set request class/object
417
+ *
418
+ * Set the request object. The request holds the request environment.
419
+ *
420
+ * If a class name is provided, it will instantiate it
421
+ *
422
+ * @param string|Zend_Controller_Request_Abstract $request
423
+ * @throws Zend_Controller_Exception if invalid request class
424
+ * @return Zend_Controller_Front
425
+ */
426
+ public function setRequest($request)
427
+ {
428
+ if (is_string($request)) {
429
+ Zend_Loader::loadClass($request);
430
+ $request = new $request();
431
+ }
432
+ if (!$request instanceof Zend_Controller_Request_Abstract) {
433
+ throw new Zend_Controller_Exception('Invalid request class');
434
+ }
435
+
436
+ $this->_request = $request;
437
+
438
+ return $this;
439
+ }
440
+
441
+ /**
442
+ * Return the request object.
443
+ *
444
+ * @return null|Zend_Controller_Request_Abstract
445
+ */
446
+ public function getRequest()
447
+ {
448
+ return $this->_request;
449
+ }
450
+
451
+ /**
452
+ * Set router class/object
453
+ *
454
+ * Set the router object. The router is responsible for mapping
455
+ * the request to a controller and action.
456
+ *
457
+ * If a class name is provided, instantiates router with any parameters
458
+ * registered via {@link setParam()} or {@link setParams()}.
459
+ *
460
+ * @param string|Zend_Controller_Router_Interface $router
461
+ * @throws Zend_Controller_Exception if invalid router class
462
+ * @return Zend_Controller_Front
463
+ */
464
+ public function setRouter($router)
465
+ {
466
+ if (is_string($router)) {
467
+ Zend_Loader::loadClass($router);
468
+ $router = new $router();
469
+ }
470
+ if (!$router instanceof Zend_Controller_Router_Interface) {
471
+ throw new Zend_Controller_Exception('Invalid router class');
472
+ }
473
+
474
+ $this->_router = $router;
475
+
476
+ return $this;
477
+ }
478
+
479
+ /**
480
+ * Return the router object.
481
+ *
482
+ * Instantiates a Zend_Controller_Router_Rewrite object if no router currently set.
483
+ *
484
+ * @return Zend_Controller_Router_Interface
485
+ */
486
+ public function getRouter()
487
+ {
488
+ if (null == $this->_router) {
489
+ require_once 'Zend/Controller/Router/Rewrite.php';
490
+ $this->setRouter(new Zend_Controller_Router_Rewrite());
491
+ }
492
+
493
+ return $this->_router;
494
+ }
495
+
496
+ /**
497
+ * Set the base URL used for requests
498
+ *
499
+ * Use to set the base URL segment of the REQUEST_URI to use when
500
+ * determining PATH_INFO, etc. Examples:
501
+ * - /admin
502
+ * - /myapp
503
+ * - /subdir/index.php
504
+ *
505
+ * Note that the URL should not include the full URI. Do not use:
506
+ * - http://example.com/admin
507
+ * - http://example.com/myapp
508
+ * - http://example.com/subdir/index.php
509
+ *
510
+ * If a null value is passed, this can be used as well for autodiscovery (default).
511
+ *
512
+ * @param string $base
513
+ * @return Zend_Controller_Front
514
+ * @throws Zend_Controller_Exception for non-string $base
515
+ */
516
+ public function setBaseUrl($base = null)
517
+ {
518
+ if (!is_string($base) && (null !== $base)) {
519
+ throw new Zend_Controller_Exception('Rewrite base must be a string');
520
+ }
521
+
522
+ $this->_baseUrl = $base;
523
+
524
+ if ((null !== ($request = $this->getRequest())) && (method_exists($request, 'setBaseUrl'))) {
525
+ $request->setBaseUrl($base);
526
+ }
527
+
528
+ return $this;
529
+ }
530
+
531
+ /**
532
+ * Retrieve the currently set base URL
533
+ *
534
+ * @return string
535
+ */
536
+ public function getBaseUrl()
537
+ {
538
+ $request = $this->getRequest();
539
+ if ((null !== $request) && method_exists($request, 'getBaseUrl')) {
540
+ return $request->getBaseUrl();
541
+ }
542
+
543
+ return $this->_baseUrl;
544
+ }
545
+
546
+ /**
547
+ * Set the dispatcher object. The dispatcher is responsible for
548
+ * taking a Zend_Controller_Dispatcher_Token object, instantiating the controller, and
549
+ * call the action method of the controller.
550
+ *
551
+ * @param Zend_Controller_Dispatcher_Interface $dispatcher
552
+ * @return Zend_Controller_Front
553
+ */
554
+ public function setDispatcher(Zend_Controller_Dispatcher_Interface $dispatcher)
555
+ {
556
+ $this->_dispatcher = $dispatcher;
557
+ return $this;
558
+ }
559
+
560
+ /**
561
+ * Return the dispatcher object.
562
+ *
563
+ * @return Zend_Controller_Dispatcher_Interface
564
+ */
565
+ public function getDispatcher()
566
+ {
567
+ /**
568
+ * Instantiate the default dispatcher if one was not set.
569
+ */
570
+ if (!$this->_dispatcher instanceof Zend_Controller_Dispatcher_Interface) {
571
+ require_once 'Zend/Controller/Dispatcher/Standard.php';
572
+ $this->_dispatcher = new Zend_Controller_Dispatcher_Standard();
573
+ }
574
+ return $this->_dispatcher;
575
+ }
576
+
577
+ /**
578
+ * Set response class/object
579
+ *
580
+ * Set the response object. The response is a container for action
581
+ * responses and headers. Usage is optional.
582
+ *
583
+ * If a class name is provided, instantiates a response object.
584
+ *
585
+ * @param string|Zend_Controller_Response_Abstract $response
586
+ * @throws Zend_Controller_Exception if invalid response class
587
+ * @return Zend_Controller_Front
588
+ */
589
+ public function setResponse($response)
590
+ {
591
+ if (is_string($response)) {
592
+ Zend_Loader::loadClass($response);
593
+ $response = new $response();
594
+ }
595
+ if (!$response instanceof Zend_Controller_Response_Abstract) {
596
+ throw new Zend_Controller_Exception('Invalid response class');
597
+ }
598
+
599
+ $this->_response = $response;
600
+
601
+ return $this;
602
+ }
603
+
604
+ /**
605
+ * Return the response object.
606
+ *
607
+ * @return null|Zend_Controller_Response_Abstract
608
+ */
609
+ public function getResponse()
610
+ {
611
+ return $this->_response;
612
+ }
613
+
614
+ /**
615
+ * Add or modify a parameter to use when instantiating an action controller
616
+ *
617
+ * @param string $name
618
+ * @param mixed $value
619
+ * @return Zend_Controller_Front
620
+ */
621
+ public function setParam($name, $value)
622
+ {
623
+ $name = (string) $name;
624
+ $this->_invokeParams[$name] = $value;
625
+ return $this;
626
+ }
627
+
628
+ /**
629
+ * Set parameters to pass to action controller constructors
630
+ *
631
+ * @param array $params
632
+ * @return Zend_Controller_Front
633
+ */
634
+ public function setParams(array $params)
635
+ {
636
+ $this->_invokeParams = array_merge($this->_invokeParams, $params);
637
+ return $this;
638
+ }
639
+
640
+ /**
641
+ * Retrieve a single parameter from the controller parameter stack
642
+ *
643
+ * @param string $name
644
+ * @return mixed
645
+ */
646
+ public function getParam($name)
647
+ {
648
+ if(isset($this->_invokeParams[$name])) {
649
+ return $this->_invokeParams[$name];
650
+ }
651
+
652
+ return null;
653
+ }
654
+
655
+ /**
656
+ * Retrieve action controller instantiation parameters
657
+ *
658
+ * @return array
659
+ */
660
+ public function getParams()
661
+ {
662
+ return $this->_invokeParams;
663
+ }
664
+
665
+ /**
666
+ * Clear the controller parameter stack
667
+ *
668
+ * By default, clears all parameters. If a parameter name is given, clears
669
+ * only that parameter; if an array of parameter names is provided, clears
670
+ * each.
671
+ *
672
+ * @param null|string|array single key or array of keys for params to clear
673
+ * @return Zend_Controller_Front
674
+ */
675
+ public function clearParams($name = null)
676
+ {
677
+ if (null === $name) {
678
+ $this->_invokeParams = array();
679
+ } elseif (is_string($name) && isset($this->_invokeParams[$name])) {
680
+ unset($this->_invokeParams[$name]);
681
+ } elseif (is_array($name)) {
682
+ foreach ($name as $key) {
683
+ if (is_string($key) && isset($this->_invokeParams[$key])) {
684
+ unset($this->_invokeParams[$key]);
685
+ }
686
+ }
687
+ }
688
+
689
+ return $this;
690
+ }
691
+
692
+ /**
693
+ * Register a plugin.
694
+ *
695
+ * @param Zend_Controller_Plugin_Abstract $plugin
696
+ * @param int $stackIndex Optional; stack index for plugin
697
+ * @return Zend_Controller_Front
698
+ */
699
+ public function registerPlugin(Zend_Controller_Plugin_Abstract $plugin, $stackIndex = null)
700
+ {
701
+ $this->_plugins->registerPlugin($plugin, $stackIndex);
702
+ return $this;
703
+ }
704
+
705
+ /**
706
+ * Unregister a plugin.
707
+ *
708
+ * @param string|Zend_Controller_Plugin_Abstract $plugin Plugin class or object to unregister
709
+ * @return Zend_Controller_Front
710
+ */
711
+ public function unregisterPlugin($plugin)
712
+ {
713
+ $this->_plugins->unregisterPlugin($plugin);
714
+ return $this;
715
+ }
716
+
717
+ /**
718
+ * Is a particular plugin registered?
719
+ *
720
+ * @param string $class
721
+ * @return bool
722
+ */
723
+ public function hasPlugin($class)
724
+ {
725
+ return $this->_plugins->hasPlugin($class);
726
+ }
727
+
728
+ /**
729
+ * Retrieve a plugin or plugins by class
730
+ *
731
+ * @param string $class
732
+ * @return false|Zend_Controller_Plugin_Abstract|array
733
+ */
734
+ public function getPlugin($class)
735
+ {
736
+ return $this->_plugins->getPlugin($class);
737
+ }
738
+
739
+ /**
740
+ * Retrieve all plugins
741
+ *
742
+ * @return array
743
+ */
744
+ public function getPlugins()
745
+ {
746
+ return $this->_plugins->getPlugins();
747
+ }
748
+
749
+ /**
750
+ * Set the throwExceptions flag and retrieve current status
751
+ *
752
+ * Set whether exceptions encounted in the dispatch loop should be thrown
753
+ * or caught and trapped in the response object.
754
+ *
755
+ * Default behaviour is to trap them in the response object; call this
756
+ * method to have them thrown.
757
+ *
758
+ * Passing no value will return the current value of the flag; passing a
759
+ * boolean true or false value will set the flag and return the current
760
+ * object instance.
761
+ *
762
+ * @param boolean $flag Defaults to null (return flag state)
763
+ * @return boolean|Zend_Controller_Front Used as a setter, returns object; as a getter, returns boolean
764
+ */
765
+ public function throwExceptions($flag = null)
766
+ {
767
+ if ($flag !== null) {
768
+ $this->_throwExceptions = (bool) $flag;
769
+ return $this;
770
+ }
771
+
772
+ return $this->_throwExceptions;
773
+ }
774
+
775
+ /**
776
+ * Set whether {@link dispatch()} should return the response without first
777
+ * rendering output. By default, output is rendered and dispatch() returns
778
+ * nothing.
779
+ *
780
+ * @param boolean $flag
781
+ * @return boolean|Zend_Controller_Front Used as a setter, returns object; as a getter, returns boolean
782
+ */
783
+ public function returnResponse($flag = null)
784
+ {
785
+ if (true === $flag) {
786
+ $this->_returnResponse = true;
787
+ return $this;
788
+ } elseif (false === $flag) {
789
+ $this->_returnResponse = false;
790
+ return $this;
791
+ }
792
+
793
+ return $this->_returnResponse;
794
+ }
795
+
796
+ /**
797
+ * Dispatch an HTTP request to a controller/action.
798
+ *
799
+ * @param Zend_Controller_Request_Abstract|null $request
800
+ * @param Zend_Controller_Response_Abstract|null $response
801
+ * @return void|Zend_Controller_Response_Abstract Returns response object if returnResponse() is true
802
+ */
803
+ public function dispatch(Zend_Controller_Request_Abstract $request = null, Zend_Controller_Response_Abstract $response = null)
804
+ {
805
+ if (!$this->getParam('noErrorHandler') && !$this->_plugins->hasPlugin('Zend_Controller_Plugin_ErrorHandler')) {
806
+ // Register with stack index of 100
807
+ require_once 'Zend/Controller/Plugin/ErrorHandler.php';
808
+ $this->_plugins->registerPlugin(new Zend_Controller_Plugin_ErrorHandler(), 100);
809
+ }
810
+
811
+ if (!$this->getParam('noViewRenderer') && !Zend_Controller_Action_HelperBroker::hasHelper('viewRenderer')) {
812
+ require_once 'Zend/Controller/Action/Helper/ViewRenderer.php';
813
+ Zend_Controller_Action_HelperBroker::addHelper(new Zend_Controller_Action_Helper_ViewRenderer());
814
+ }
815
+
816
+ /**
817
+ * Instantiate default request object (HTTP version) if none provided
818
+ */
819
+ if (null !== $request) {
820
+ $this->setRequest($request);
821
+ } elseif ((null === $request) && (null === ($request = $this->getRequest()))) {
822
+ require_once 'Zend/Controller/Request/Http.php';
823
+ $request = new Zend_Controller_Request_Http();
824
+ $this->setRequest($request);
825
+ }
826
+
827
+ /**
828
+ * Set base URL of request object, if available
829
+ */
830
+ if (is_callable(array($this->_request, 'setBaseUrl'))) {
831
+ if (null !== $this->_baseUrl) {
832
+ $this->_request->setBaseUrl($this->_baseUrl);
833
+ }
834
+ }
835
+
836
+ /**
837
+ * Instantiate default response object (HTTP version) if none provided
838
+ */
839
+ if (null !== $response) {
840
+ $this->setResponse($response);
841
+ } elseif ((null === $this->_response) && (null === ($this->_response = $this->getResponse()))) {
842
+ require_once 'Zend/Controller/Response/Http.php';
843
+ $response = new Zend_Controller_Response_Http();
844
+ $this->setResponse($response);
845
+ }
846
+
847
+ /**
848
+ * Register request and response objects with plugin broker
849
+ */
850
+ $this->_plugins
851
+ ->setRequest($this->_request)
852
+ ->setResponse($this->_response);
853
+
854
+ /**
855
+ * Initialize router
856
+ */
857
+ $router = $this->getRouter();
858
+ $router->setParams($this->getParams());
859
+
860
+ /**
861
+ * Initialize dispatcher
862
+ */
863
+ $dispatcher = $this->getDispatcher();
864
+ $dispatcher->setParams($this->getParams())
865
+ ->setResponse($this->_response);
866
+
867
+ // Begin dispatch
868
+ try {
869
+ /**
870
+ * Route request to controller/action, if a router is provided
871
+ */
872
+
873
+ /**
874
+ * Notify plugins of router startup
875
+ */
876
+ $this->_plugins->routeStartup($this->_request);
877
+
878
+ $router->route($this->_request);
879
+
880
+ /**
881
+ * Notify plugins of router completion
882
+ */
883
+ $this->_plugins->routeShutdown($this->_request);
884
+
885
+ /**
886
+ * Notify plugins of dispatch loop startup
887
+ */
888
+ $this->_plugins->dispatchLoopStartup($this->_request);
889
+
890
+ /**
891
+ * Attempt to dispatch the controller/action. If the $this->_request
892
+ * indicates that it needs to be dispatched, move to the next
893
+ * action in the request.
894
+ */
895
+ do {
896
+ $this->_request->setDispatched(true);
897
+
898
+ /**
899
+ * Notify plugins of dispatch startup
900
+ */
901
+ $this->_plugins->preDispatch($this->_request);
902
+
903
+ /**
904
+ * Skip requested action if preDispatch() has reset it
905
+ */
906
+ if (!$this->_request->isDispatched()) {
907
+ continue;
908
+ }
909
+
910
+ /**
911
+ * Dispatch request
912
+ */
913
+ try {
914
+ $dispatcher->dispatch($this->_request, $this->_response);
915
+ } catch (Exception $e) {
916
+ if ($this->throwExceptions()) {
917
+ throw $e;
918
+ }
919
+ $this->_response->setException($e);
920
+ }
921
+
922
+ /**
923
+ * Notify plugins of dispatch completion
924
+ */
925
+ $this->_plugins->postDispatch($this->_request);
926
+ } while (!$this->_request->isDispatched());
927
+ } catch (Exception $e) {
928
+ if ($this->throwExceptions()) {
929
+ throw $e;
930
+ }
931
+
932
+ $this->_response->setException($e);
933
+ }
934
+
935
+ /**
936
+ * Notify plugins of dispatch loop completion
937
+ */
938
+ try {
939
+ $this->_plugins->dispatchLoopShutdown();
940
+ } catch (Exception $e) {
941
+ if ($this->throwExceptions()) {
942
+ throw $e;
943
+ }
944
+
945
+ $this->_response->setException($e);
946
+ }
947
+
948
+ if ($this->returnResponse()) {
949
+ return $this->_response;
950
+ }
951
+
952
+ $this->_response->sendResponse();
953
+ }
954
+ }
lib/Zend/Controller/Plugin/Abstract.php ADDED
@@ -0,0 +1,156 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Zend Framework
4
+ *
5
+ * LICENSE
6
+ *
7
+ * This source file is subject to the new BSD license that is bundled
8
+ * with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://framework.zend.com/license/new-bsd
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@zend.com so we can send you a copy immediately.
14
+ *
15
+ * @category Zend
16
+ * @package Zend_Controller
17
+ * @subpackage Plugins
18
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
19
+ * @license http://framework.zend.com/license/new-bsd New BSD License
20
+ */
21
+
22
+ /** Zend_Controller_Request_Abstract */
23
+ require_once 'Zend/Controller/Request/Abstract.php';
24
+
25
+ /** Zend_Controller_Response_Abstract */
26
+ require_once 'Zend/Controller/Response/Abstract.php';
27
+
28
+ /**
29
+ * @category Zend
30
+ * @package Zend_Controller
31
+ * @subpackage Plugins
32
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
33
+ * @license http://framework.zend.com/license/new-bsd New BSD License
34
+ */
35
+ abstract class Zend_Controller_Plugin_Abstract
36
+ {
37
+ /**
38
+ * @var Zend_Controller_Request_Abstract
39
+ */
40
+ protected $_request;
41
+
42
+ /**
43
+ * @var Zend_Controller_Response_Abstract
44
+ */
45
+ protected $_response;
46
+
47
+ /**
48
+ * Set request object
49
+ *
50
+ * @param Zend_Controller_Request_Abstract $request
51
+ * @return Zend_Controller_Plugin_Abstract
52
+ */
53
+ public function setRequest(Zend_Controller_Request_Abstract $request)
54
+ {
55
+ $this->_request = $request;
56
+ return $this;
57
+ }
58
+
59
+ /**
60
+ * Get request object
61
+ *
62
+ * @return Zend_Controller_Request_Abstract $request
63
+ */
64
+ public function getRequest()
65
+ {
66
+ return $this->_request;
67
+ }
68
+
69
+ /**
70
+ * Set response object
71
+ *
72
+ * @param Zend_Controller_Response_Abstract $response
73
+ * @return Zend_Controller_Plugin_Abstract
74
+ */
75
+ public function setResponse(Zend_Controller_Response_Abstract $response)
76
+ {
77
+ $this->_response = $response;
78
+ return $this;
79
+ }
80
+
81
+ /**
82
+ * Get response object
83
+ *
84
+ * @return Zend_Controller_Response_Abstract $response
85
+ */
86
+ public function getResponse()
87
+ {
88
+ return $this->_response;
89
+ }
90
+
91
+ /**
92
+ * Called before Zend_Controller_Front begins evaluating the
93
+ * request against its routes.
94
+ *
95
+ * @param Zend_Controller_Request_Abstract $request
96
+ * @return void
97
+ */
98
+ public function routeStartup(Zend_Controller_Request_Abstract $request)
99
+ {}
100
+
101
+ /**
102
+ * Called after Zend_Controller_Router exits.
103
+ *
104
+ * Called after Zend_Controller_Front exits from the router.
105
+ *
106
+ * @param Zend_Controller_Request_Abstract $request
107
+ * @return void
108
+ */
109
+ public function routeShutdown(Zend_Controller_Request_Abstract $request)
110
+ {}
111
+
112
+ /**
113
+ * Called before Zend_Controller_Front enters its dispatch loop.
114
+ *
115
+ * @param Zend_Controller_Request_Abstract $request
116
+ * @return void
117
+ */
118
+ public function dispatchLoopStartup(Zend_Controller_Request_Abstract $request)
119
+ {}
120
+
121
+ /**
122
+ * Called before an action is dispatched by Zend_Controller_Dispatcher.
123
+ *
124
+ * This callback allows for proxy or filter behavior. By altering the
125
+ * request and resetting its dispatched flag (via
126
+ * {@link Zend_Controller_Request_Abstract::setDispatched() setDispatched(false)}),
127
+ * the current action may be skipped.
128
+ *
129
+ * @param Zend_Controller_Request_Abstract $request
130
+ * @return void
131
+ */
132
+ public function preDispatch(Zend_Controller_Request_Abstract $request)
133
+ {}
134
+
135
+ /**
136
+ * Called after an action is dispatched by Zend_Controller_Dispatcher.
137
+ *
138
+ * This callback allows for proxy or filter behavior. By altering the
139
+ * request and resetting its dispatched flag (via
140
+ * {@link Zend_Controller_Request_Abstract::setDispatched() setDispatched(false)}),
141
+ * a new action may be specified for dispatching.
142
+ *
143
+ * @param Zend_Controller_Request_Abstract $request
144
+ * @return void
145
+ */
146
+ public function postDispatch(Zend_Controller_Request_Abstract $request)
147
+ {}
148
+
149
+ /**
150
+ * Called before Zend_Controller_Front exits its dispatch loop.
151
+ *
152
+ * @return void
153
+ */
154
+ public function dispatchLoopShutdown()
155
+ {}
156
+ }
lib/Zend/Controller/Plugin/ActionStack.php ADDED
@@ -0,0 +1,245 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Zend Framework
4
+ *
5
+ * LICENSE
6
+ *
7
+ * This source file is subject to the new BSD license that is bundled
8
+ * with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://framework.zend.com/license/new-bsd
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@zend.com so we can send you a copy immediately.
14
+ *
15
+ * @category Zend
16
+ * @package Zend_Controller
17
+ * @subpackage Plugins
18
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
19
+ * @license http://framework.zend.com/license/new-bsd New BSD License
20
+ */
21
+
22
+ /** Zend_Controller_Plugin_Abstract */
23
+ require_once 'Zend/Controller/Plugin/Abstract.php';
24
+
25
+ /** Zend_Registry */
26
+ require_once 'Zend/Registry.php';
27
+
28
+ /**
29
+ * Manage a stack of actions
30
+ *
31
+ * @uses Zend_Controller_Plugin_Abstract
32
+ * @category Zend
33
+ * @package Zend_Controller
34
+ * @subpackage Plugins
35
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
36
+ * @license http://framework.zend.com/license/new-bsd New BSD License
37
+ * @version $Id: ActionStack.php 8064 2008-02-16 10:58:39Z thomas $
38
+ */
39
+ class Zend_Controller_Plugin_ActionStack extends Zend_Controller_Plugin_Abstract
40
+ {
41
+ /** @var Zend_Registry */
42
+ protected $_registry;
43
+
44
+ /**
45
+ * Registry key under which actions are stored
46
+ * @var string
47
+ */
48
+ protected $_registryKey = 'Zend_Controller_Plugin_ActionStack';
49
+
50
+ /**
51
+ * Valid keys for stack items
52
+ * @var array
53
+ */
54
+ protected $_validKeys = array(
55
+ 'module',
56
+ 'controller',
57
+ 'action',
58
+ 'params'
59
+ );
60
+
61
+ /**
62
+ * Constructor
63
+ *
64
+ * @param Zend_Registry $registry
65
+ * @param string $key
66
+ * @return void
67
+ */
68
+ public function __construct(Zend_Registry $registry = null, $key = null)
69
+ {
70
+ if (null === $registry) {
71
+ $registry = Zend_Registry::getInstance();
72
+ }
73
+ $this->setRegistry($registry);
74
+
75
+ if (null !== $key) {
76
+ $this->setRegistryKey($key);
77
+ } else {
78
+ $key = $this->getRegistryKey();
79
+ }
80
+
81
+ $registry[$key] = array();
82
+ }
83
+
84
+ /**
85
+ * Set registry object
86
+ *
87
+ * @param Zend_Registry $registry
88
+ * @return Zend_Controller_Plugin_ActionStack
89
+ */
90
+ public function setRegistry(Zend_Registry $registry)
91
+ {
92
+ $this->_registry = $registry;
93
+ return $this;
94
+ }
95
+
96
+ /**
97
+ * Retrieve registry object
98
+ *
99
+ * @return Zend_Registry
100
+ */
101
+ public function getRegistry()
102
+ {
103
+ return $this->_registry;
104
+ }
105
+
106
+ /**
107
+ * Retrieve registry key
108
+ *
109
+ * @return string
110
+ */
111
+ public function getRegistryKey()
112
+ {
113
+ return $this->_registryKey;
114
+ }
115
+
116
+ /**
117
+ * Set registry key
118
+ *
119
+ * @param string $key
120
+ * @return Zend_Controller_Plugin_ActionStack
121
+ */
122
+ public function setRegistryKey($key)
123
+ {
124
+ $this->_registryKey = (string) $key;
125
+ return $this;
126
+ }
127
+
128
+ /**
129
+ * Retrieve action stack
130
+ *
131
+ * @return array
132
+ */
133
+ public function getStack()
134
+ {
135
+ $registry = $this->getRegistry();
136
+ $stack = $registry[$this->getRegistryKey()];
137
+ return $stack;
138
+ }
139
+
140
+ /**
141
+ * Save stack to registry
142
+ *
143
+ * @param array $stack
144
+ * @return Zend_Controller_Plugin_ActionStack
145
+ */
146
+ protected function _saveStack(array $stack)
147
+ {
148
+ $registry = $this->getRegistry();
149
+ $registry[$this->getRegistryKey()] = $stack;
150
+ return $this;
151
+ }
152
+
153
+ /**
154
+ * Push an item onto the stack
155
+ *
156
+ * @param Zend_Controller_Request_Abstract $next
157
+ * @return Zend_Controller_Plugin_ActionStack
158
+ */
159
+ public function pushStack(Zend_Controller_Request_Abstract $next)
160
+ {
161
+ $stack = $this->getStack();
162
+ array_push($stack, $next);
163
+ return $this->_saveStack($stack);
164
+ }
165
+
166
+ /**
167
+ * Pop an item off the action stack
168
+ *
169
+ * @return false|Zend_Controller_Request_Abstract
170
+ */
171
+ public function popStack()
172
+ {
173
+ $stack = $this->getStack();
174
+ if (0 == count($stack)) {
175
+ return false;
176
+ }
177
+
178
+ $next = array_pop($stack);
179
+ $this->_saveStack($stack);
180
+
181
+ if (!$next instanceof Zend_Controller_Request_Abstract) {
182
+ require_once 'Zend/Controller/Exception.php';
183
+ throw new Zend_Controller_Exception('ArrayStack should only contain request objects');
184
+ }
185
+ $action = $next->getActionName();
186
+ if (empty($action)) {
187
+ return $this->popStack($stack);
188
+ }
189
+
190
+ $request = $this->getRequest();
191
+ $controller = $next->getControllerName();
192
+ if (empty($controller)) {
193
+ $next->setControllerName($request->getControllerName());
194
+ }
195
+
196
+ $module = $next->getModuleName();
197
+ if (empty($module)) {
198
+ $next->setModuleName($request->getModuleName());
199
+ }
200
+
201
+ return $next;
202
+ }
203
+
204
+ /**
205
+ * postDispatch() plugin hook -- check for actions in stack, and dispatch if any found
206
+ *
207
+ * @param Zend_Controller_Request_Abstract $request
208
+ * @return void
209
+ */
210
+ public function postDispatch(Zend_Controller_Request_Abstract $request)
211
+ {
212
+ // Don't move on to next request if this is already an attempt to
213
+ // forward
214
+ if (!$request->isDispatched()) {
215
+ return;
216
+ }
217
+
218
+ $this->setRequest($request);
219
+ $stack = $this->getStack();
220
+ if (empty($stack)) {
221
+ return;
222
+ }
223
+ $next = $this->popStack();
224
+ if (!$next) {
225
+ return;
226
+ }
227
+
228
+ $this->forward($next);
229
+ }
230
+
231
+ /**
232
+ * Forward request with next action
233
+ *
234
+ * @param array $next
235
+ * @return void
236
+ */
237
+ public function forward(Zend_Controller_Request_Abstract $next)
238
+ {
239
+ $this->getRequest()->setModuleName($next->getModuleName())
240
+ ->setControllerName($next->getControllerName())
241
+ ->setActionName($next->getActionName())
242
+ ->setParams($next->getParams())
243
+ ->setDispatched(false);
244
+ }
245
+ }
lib/Zend/Controller/Plugin/Broker.php ADDED
@@ -0,0 +1,369 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Zend Framework
4
+ *
5
+ * LICENSE
6
+ *
7
+ * This source file is subject to the new BSD license that is bundled
8
+ * with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://framework.zend.com/license/new-bsd
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@zend.com so we can send you a copy immediately.
14
+ *
15
+ * @category Zend
16
+ * @package Zend_Controller
17
+ * @subpackage Plugins
18
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
19
+ * @license http://framework.zend.com/license/new-bsd New BSD License
20
+ */
21
+
22
+
23
+ /** Zend_Controller_Exception */
24
+ require_once 'Zend/Controller/Exception.php';
25
+
26
+ /** Zend_Controller_Plugin_Abstract */
27
+ require_once 'Zend/Controller/Plugin/Abstract.php';
28
+
29
+ /** Zend_Controller_Request_Abstract */
30
+ require_once 'Zend/Controller/Request/Abstract.php';
31
+
32
+ /** Zend_Controller_Response_Abstract */
33
+ require_once 'Zend/Controller/Response/Abstract.php';
34
+
35
+ /**
36
+ * @category Zend
37
+ * @package Zend_Controller
38
+ * @subpackage Plugins
39
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
40
+ * @license http://framework.zend.com/license/new-bsd New BSD License
41
+ */
42
+ class Zend_Controller_Plugin_Broker extends Zend_Controller_Plugin_Abstract
43
+ {
44
+
45
+ /**
46
+ * Array of instance of objects extending Zend_Controller_Plugin_Abstract
47
+ *
48
+ * @var array
49
+ */
50
+ protected $_plugins = array();
51
+
52
+
53
+ /**
54
+ * Register a plugin.
55
+ *
56
+ * @param Zend_Controller_Plugin_Abstract $plugin
57
+ * @param int $stackIndex
58
+ * @return Zend_Controller_Plugin_Broker
59
+ */
60
+ public function registerPlugin(Zend_Controller_Plugin_Abstract $plugin, $stackIndex = null)
61
+ {
62
+ if (false !== array_search($plugin, $this->_plugins, true)) {
63
+ throw new Zend_Controller_Exception('Plugin already registered');
64
+ }
65
+
66
+ $stackIndex = (int) $stackIndex;
67
+
68
+ if ($stackIndex) {
69
+ if (isset($this->_plugins[$stackIndex])) {
70
+ throw new Zend_Controller_Exception('Plugin with stackIndex "' . $stackIndex . '" already registered');
71
+ }
72
+ $this->_plugins[$stackIndex] = $plugin;
73
+ } else {
74
+ $stackIndex = count($this->_plugins);
75
+ while (isset($this->_plugins[$stackIndex])) {
76
+ ++$stackIndex;
77
+ }
78
+ $this->_plugins[$stackIndex] = $plugin;
79
+ }
80
+
81
+ $request = $this->getRequest();
82
+ if ($request) {
83
+ $this->_plugins[$stackIndex]->setRequest($request);
84
+ }
85
+ $response = $this->getResponse();
86
+ if ($response) {
87
+ $this->_plugins[$stackIndex]->setResponse($response);
88
+ }
89
+
90
+ ksort($this->_plugins);
91
+
92
+ return $this;
93
+ }
94
+
95
+ /**
96
+ * Unregister a plugin.
97
+ *
98
+ * @param string|Zend_Controller_Plugin_Abstract $plugin Plugin object or class name
99
+ * @return Zend_Controller_Plugin_Broker
100
+ */
101
+ public function unregisterPlugin($plugin)
102
+ {
103
+ if ($plugin instanceof Zend_Controller_Plugin_Abstract) {
104
+ // Given a plugin object, find it in the array
105
+ $key = array_search($plugin, $this->_plugins, true);
106
+ if (false === $key) {
107
+ throw new Zend_Controller_Exception('Plugin never registered.');
108
+ }
109
+ unset($this->_plugins[$key]);
110
+ } elseif (is_string($plugin)) {
111
+ // Given a plugin class, find all plugins of that class and unset them
112
+ foreach ($this->_plugins as $key => $_plugin) {
113
+ $type = get_class($_plugin);
114
+ if ($plugin == $type) {
115
+ unset($this->_plugins[$key]);
116
+ }
117
+ }
118
+ }
119
+ return $this;
120
+ }
121
+
122
+ /**
123
+ * Is a plugin of a particular class registered?
124
+ *
125
+ * @param string $class
126
+ * @return bool
127
+ */
128
+ public function hasPlugin($class)
129
+ {
130
+ foreach ($this->_plugins as $plugin) {
131
+ $type = get_class($plugin);
132
+ if ($class == $type) {
133
+ return true;
134
+ }
135
+ }
136
+
137
+ return false;
138
+ }
139
+
140
+ /**
141
+ * Retrieve a plugin or plugins by class
142
+ *
143
+ * @param string $class Class name of plugin(s) desired
144
+ * @return false|Zend_Controller_Plugin_Abstract|array Returns false if none found, plugin if only one found, and array of plugins if multiple plugins of same class found
145
+ */
146
+ public function getPlugin($class)
147
+ {
148
+ $found = array();
149
+ foreach ($this->_plugins as $plugin) {
150
+ $type = get_class($plugin);
151
+ if ($class == $type) {
152
+ $found[] = $plugin;
153
+ }
154
+ }
155
+
156
+ switch (count($found)) {
157
+ case 0:
158
+ return false;
159
+ case 1:
160
+ return $found[0];
161
+ default:
162
+ return $found;
163
+ }
164
+ }
165
+
166
+ /**
167
+ * Retrieve all plugins
168
+ *
169
+ * @return array
170
+ */
171
+ public function getPlugins()
172
+ {
173
+ return $this->_plugins;
174
+ }
175
+
176
+ /**
177
+ * Set request object, and register with each plugin
178
+ *
179
+ * @param Zend_Controller_Request_Abstract $request
180
+ * @return Zend_Controller_Plugin_Broker
181
+ */
182
+ public function setRequest(Zend_Controller_Request_Abstract $request)
183
+ {
184
+ $this->_request = $request;
185
+
186
+ foreach ($this->_plugins as $plugin) {
187
+ $plugin->setRequest($request);
188
+ }
189
+
190
+ return $this;
191
+ }
192
+
193
+ /**
194
+ * Get request object
195
+ *
196
+ * @return Zend_Controller_Request_Abstract $request
197
+ */
198
+ public function getRequest()
199
+ {
200
+ return $this->_request;
201
+ }
202
+
203
+ /**
204
+ * Set response object
205
+ *
206
+ * @param Zend_Controller_Response_Abstract $response
207
+ * @return Zend_Controller_Plugin_Broker
208
+ */
209
+ public function setResponse(Zend_Controller_Response_Abstract $response)
210
+ {
211
+ $this->_response = $response;
212
+
213
+ foreach ($this->_plugins as $plugin) {
214
+ $plugin->setResponse($response);
215
+ }
216
+
217
+
218
+ return $this;
219
+ }
220
+
221
+ /**
222
+ * Get response object
223
+ *
224
+ * @return Zend_Controller_Response_Abstract $response
225
+ */
226
+ public function getResponse()
227
+ {
228
+ return $this->_response;
229
+ }
230
+
231
+
232
+ /**
233
+ * Called before Zend_Controller_Front begins evaluating the
234
+ * request against its routes.
235
+ *
236
+ * @param Zend_Controller_Request_Abstract $request
237
+ * @return void
238
+ */
239
+ public function routeStartup(Zend_Controller_Request_Abstract $request)
240
+ {
241
+ foreach ($this->_plugins as $plugin) {
242
+ try {
243
+ $plugin->routeStartup($request);
244
+ } catch (Exception $e) {
245
+ if (Zend_Controller_Front::getInstance()->throwExceptions()) {
246
+ throw $e;
247
+ } else {
248
+ $this->getResponse()->setException($e);
249
+ }
250
+ }
251
+ }
252
+ }
253
+
254
+
255
+ /**
256
+ * Called before Zend_Controller_Front exits its iterations over
257
+ * the route set.
258
+ *
259
+ * @param Zend_Controller_Request_Abstract $request
260
+ * @return void
261
+ */
262
+ public function routeShutdown(Zend_Controller_Request_Abstract $request)
263
+ {
264
+ foreach ($this->_plugins as $plugin) {
265
+ try {
266
+ $plugin->routeShutdown($request);
267
+ } catch (Exception $e) {
268
+ if (Zend_Controller_Front::getInstance()->throwExceptions()) {
269
+ throw $e;
270
+ } else {
271
+ $this->getResponse()->setException($e);
272
+ }
273
+ }
274
+ }
275
+ }
276
+
277
+
278
+ /**
279
+ * Called before Zend_Controller_Front enters its dispatch loop.
280
+ *
281
+ * During the dispatch loop, Zend_Controller_Front keeps a
282
+ * Zend_Controller_Request_Abstract object, and uses
283
+ * Zend_Controller_Dispatcher to dispatch the
284
+ * Zend_Controller_Request_Abstract object to controllers/actions.
285
+ *
286
+ * @param Zend_Controller_Request_Abstract $request
287
+ * @return void
288
+ */
289
+ public function dispatchLoopStartup(Zend_Controller_Request_Abstract $request)
290
+ {
291
+ foreach ($this->_plugins as $plugin) {
292
+ try {
293
+ $plugin->dispatchLoopStartup($request);
294
+ } catch (Exception $e) {
295
+ if (Zend_Controller_Front::getInstance()->throwExceptions()) {
296
+ throw $e;
297
+ } else {
298
+ $this->getResponse()->setException($e);
299
+ }
300
+ }
301
+ }
302
+ }
303
+
304
+
305
+ /**
306
+ * Called before an action is dispatched by Zend_Controller_Dispatcher.
307
+ *
308
+ * @param Zend_Controller_Request_Abstract $request
309
+ * @return void
310
+ */
311
+ public function preDispatch(Zend_Controller_Request_Abstract $request)
312
+ {
313
+ foreach ($this->_plugins as $plugin) {
314
+ try {
315
+ $plugin->preDispatch($request);
316
+ } catch (Exception $e) {
317
+ if (Zend_Controller_Front::getInstance()->throwExceptions()) {
318
+ throw $e;
319
+ } else {
320
+ $this->getResponse()->setException($e);
321
+ }
322
+ }
323
+ }
324
+ }
325
+
326
+
327
+ /**
328
+ * Called after an action is dispatched by Zend_Controller_Dispatcher.
329
+ *
330
+ * @param Zend_Controller_Request_Abstract $request
331
+ * @return void
332
+ */
333
+ public function postDispatch(Zend_Controller_Request_Abstract $request)
334
+ {
335
+ foreach ($this->_plugins as $plugin) {
336
+ try {
337
+ $plugin->postDispatch($request);
338
+ } catch (Exception $e) {
339
+ if (Zend_Controller_Front::getInstance()->throwExceptions()) {
340
+ throw $e;
341
+ } else {
342
+ $this->getResponse()->setException($e);
343
+ }
344
+ }
345
+ }
346
+ }
347
+
348
+
349
+ /**
350
+ * Called before Zend_Controller_Front exits its dispatch loop.
351
+ *
352
+ * @param Zend_Controller_Request_Abstract $request
353
+ * @return void
354
+ */
355
+ public function dispatchLoopShutdown()
356
+ {
357
+ foreach ($this->_plugins as $plugin) {
358
+ try {
359
+ $plugin->dispatchLoopShutdown();
360
+ } catch (Exception $e) {
361
+ if (Zend_Controller_Front::getInstance()->throwExceptions()) {
362
+ throw $e;
363
+ } else {
364
+ $this->getResponse()->setException($e);
365
+ }
366
+ }
367
+ }
368
+ }
369
+ }
lib/Zend/Controller/Plugin/ErrorHandler.php ADDED
@@ -0,0 +1,257 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Zend Framework
4
+ *
5
+ * LICENSE
6
+ *
7
+ * This source file is subject to the new BSD license that is bundled
8
+ * with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://framework.zend.com/license/new-bsd
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@zend.com so we can send you a copy immediately.
14
+ *
15
+ * @category Zend
16
+ * @package Zend_Controller
17
+ * @subpackage Plugins
18
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
19
+ * @license http://framework.zend.com/license/new-bsd New BSD License
20
+ */
21
+
22
+ /** Zend_Controller_Plugin_Abstract */
23
+ require_once 'Zend/Controller/Plugin/Abstract.php';
24
+
25
+ /**
26
+ * Handle exceptions that bubble up based on missing controllers, actions, or
27
+ * application errors, and forward to an error handler.
28
+ *
29
+ * @uses Zend_Controller_Plugin_Abstract
30
+ * @category Zend
31
+ * @package Zend_Controller
32
+ * @subpackage Plugins
33
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
34
+ * @license http://framework.zend.com/license/new-bsd New BSD License
35
+ * @version $Id: ErrorHandler.php 8064 2008-02-16 10:58:39Z thomas $
36
+ */
37
+ class Zend_Controller_Plugin_ErrorHandler extends Zend_Controller_Plugin_Abstract
38
+ {
39
+ /**
40
+ * Const - No controller exception; controller does not exist
41
+ */
42
+ const EXCEPTION_NO_CONTROLLER = 'EXCEPTION_NO_CONTROLLER';
43
+
44
+ /**
45
+ * Const - No action exception; controller exists, but action does not
46
+ */
47
+ const EXCEPTION_NO_ACTION = 'EXCEPTION_NO_ACTION';
48
+
49
+ /**
50
+ * Const - Other Exception; exceptions thrown by application controllers
51
+ */
52
+ const EXCEPTION_OTHER = 'EXCEPTION_OTHER';
53
+
54
+ /**
55
+ * Module to use for errors; defaults to default module in dispatcher
56
+ * @var string
57
+ */
58
+ protected $_errorModule;
59
+
60
+ /**
61
+ * Controller to use for errors; defaults to 'error'
62
+ * @var string
63
+ */
64
+ protected $_errorController = 'error';
65
+
66
+ /**
67
+ * Action to use for errors; defaults to 'error'
68
+ * @var string
69
+ */
70
+ protected $_errorAction = 'error';
71
+
72
+ /**
73
+ * Flag; are we already inside the error handler loop?
74
+ * @var bool
75
+ */
76
+ protected $_isInsideErrorHandlerLoop = false;
77
+
78
+ /**
79
+ * Exception count logged at first invocation of plugin
80
+ * @var int
81
+ */
82
+ protected $_exceptionCountAtFirstEncounter = 0;
83
+
84
+ /**
85
+ * Constructor
86
+ *
87
+ * Options may include:
88
+ * - module
89
+ * - controller
90
+ * - action
91
+ *
92
+ * @param Array $options
93
+ * @return void
94
+ */
95
+ public function __construct(Array $options = array())
96
+ {
97
+ $this->setErrorHandler($options);
98
+ }
99
+
100
+ /**
101
+ * setErrorHandler() - setup the error handling options
102
+ *
103
+ * @param array $options
104
+ * @return Zend_Controller_Plugin_ErrorHandler
105
+ */
106
+ public function setErrorHandler(Array $options = array())
107
+ {
108
+ if (isset($options['module'])) {
109
+ $this->setErrorHandlerModule($options['module']);
110
+ }
111
+ if (isset($options['controller'])) {
112
+ $this->setErrorHandlerController($options['controller']);
113
+ }
114
+ if (isset($options['action'])) {
115
+ $this->setErrorHandlerAction($options['action']);
116
+ }
117
+ return $this;
118
+ }
119
+
120
+ /**
121
+ * Set the module name for the error handler
122
+ *
123
+ * @param string $module
124
+ * @return Zend_Controller_Plugin_ErrorHandler
125
+ */
126
+ public function setErrorHandlerModule($module)
127
+ {
128
+ $this->_errorModule = (string) $module;
129
+ return $this;
130
+ }
131
+
132
+ /**
133
+ * Retrieve the current error handler module
134
+ *
135
+ * @return string
136
+ */
137
+ public function getErrorHandlerModule()
138
+ {
139
+ if (null === $this->_errorModule) {
140
+ $this->_errorModule = Zend_Controller_Front::getInstance()->getDispatcher()->getDefaultModule();
141
+ }
142
+ return $this->_errorModule;
143
+ }
144
+
145
+ /**
146
+ * Set the controller name for the error handler
147
+ *
148
+ * @param string $controller
149
+ * @return Zend_Controller_Plugin_ErrorHandler
150
+ */
151
+ public function setErrorHandlerController($controller)
152
+ {
153
+ $this->_errorController = (string) $controller;
154
+ return $this;
155
+ }
156
+
157
+ /**
158
+ * Retrieve the current error handler controller
159
+ *
160
+ * @return string
161
+ */
162
+ public function getErrorHandlerController()
163
+ {
164
+ return $this->_errorController;
165
+ }
166
+
167
+ /**
168
+ * Set the action name for the error handler
169
+ *
170
+ * @param string $action
171
+ * @return Zend_Controller_Plugin_ErrorHandler
172
+ */
173
+ public function setErrorHandlerAction($action)
174
+ {
175
+ $this->_errorAction = (string) $action;
176
+ return $this;
177
+ }
178
+
179
+ /**
180
+ * Retrieve the current error handler action
181
+ *
182
+ * @return string
183
+ */
184
+ public function getErrorHandlerAction()
185
+ {
186
+ return $this->_errorAction;
187
+ }
188
+
189
+ /**
190
+ * postDispatch() plugin hook -- check for exceptions and dispatch error
191
+ * handler if necessary
192
+ *
193
+ * If the 'noErrorHandler' front controller flag has been set,
194
+ * returns early.
195
+ *
196
+ * @param Zend_Controller_Request_Abstract $request
197
+ * @return void
198
+ */
199
+ public function postDispatch(Zend_Controller_Request_Abstract $request)
200
+ {
201
+ $frontController = Zend_Controller_Front::getInstance();
202
+ if ($frontController->getParam('noErrorHandler')) {
203
+ return;
204
+ }
205
+
206
+ $response = $this->getResponse();
207
+
208
+ if ($this->_isInsideErrorHandlerLoop) {
209
+ $exceptions = $response->getException();
210
+ if (count($exceptions) > $this->_exceptionCountAtFirstEncounter) {
211
+ // Exception thrown by error handler; tell the front controller to throw it
212
+ $frontController->throwExceptions(true);
213
+ throw array_pop($exceptions);
214
+ }
215
+ }
216
+
217
+ // check for an exception AND allow the error handler controller the option to forward
218
+ if (($response->isException()) && (!$this->_isInsideErrorHandlerLoop)) {
219
+ $this->_isInsideErrorHandlerLoop = true;
220
+
221
+ // Get exception information
222
+ $error = new ArrayObject(array(), ArrayObject::ARRAY_AS_PROPS);
223
+ $exceptions = $response->getException();
224
+ $exception = $exceptions[0];
225
+ $exceptionType = get_class($exception);
226
+ $error->exception = $exception;
227
+ switch ($exceptionType) {
228
+ case 'Zend_Controller_Dispatcher_Exception':
229
+ $error->type = self::EXCEPTION_NO_CONTROLLER;
230
+ break;
231
+ case 'Zend_Controller_Action_Exception':
232
+ if (404 == $exception->getCode()) {
233
+ $error->type = self::EXCEPTION_NO_ACTION;
234
+ } else {
235
+ $error->type = self::EXCEPTION_OTHER;
236
+ }
237
+ break;
238
+ default:
239
+ $error->type = self::EXCEPTION_OTHER;
240
+ break;
241
+ }
242
+
243
+ // Keep a copy of the original request
244
+ $error->request = clone $request;
245
+
246
+ // get a count of the number of exceptions encountered
247
+ $this->_exceptionCountAtFirstEncounter = count($exceptions);
248
+
249
+ // Forward to the error handler
250
+ $request->setParam('error_handler', $error)
251
+ ->setModuleName($this->getErrorHandlerModule())
252
+ ->setControllerName($this->getErrorHandlerController())
253
+ ->setActionName($this->getErrorHandlerAction())
254
+ ->setDispatched(false);
255
+ }
256
+ }
257
+ }
lib/Zend/Controller/Request/Abstract.php ADDED
@@ -0,0 +1,338 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Zend Framework
4
+ *
5
+ * LICENSE
6
+ *
7
+ * This source file is subject to the new BSD license that is bundled
8
+ * with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://framework.zend.com/license/new-bsd
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@zend.com so we can send you a copy immediately.
14
+ *
15
+ * @category Zend
16
+ * @package Zend_Controller
17
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
18
+ * @license http://framework.zend.com/license/new-bsd New BSD License
19
+ */
20
+
21
+ /**
22
+ * @category Zend
23
+ * @package Zend_Controller
24
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
25
+ * @license http://framework.zend.com/license/new-bsd New BSD License
26
+ */
27
+ abstract class Zend_Controller_Request_Abstract
28
+ {
29
+ /**
30
+ * Has the action been dispatched?
31
+ * @var boolean
32
+ */
33
+ protected $_dispatched = false;
34
+
35
+ /**
36
+ * Module
37
+ * @var string
38
+ */
39
+ protected $_module;
40
+
41
+ /**
42
+ * Module key for retrieving module from params
43
+ * @var string
44
+ */
45
+ protected $_moduleKey = 'module';
46
+
47
+ /**
48
+ * Controller
49
+ * @var string
50
+ */
51
+ protected $_controller;
52
+
53
+ /**
54
+ * Controller key for retrieving controller from params
55
+ * @var string
56
+ */
57
+ protected $_controllerKey = 'controller';
58
+
59
+ /**
60
+ * Action
61
+ * @var string
62
+ */
63
+ protected $_action;
64
+
65
+ /**
66
+ * Action key for retrieving action from params
67
+ * @var string
68
+ */
69
+ protected $_actionKey = 'action';
70
+
71
+ /**
72
+ * Request parameters
73
+ * @var array
74
+ */
75
+ protected $_params = array();
76
+
77
+ /**
78
+ * Retrieve the module name
79
+ *
80
+ * @return string
81
+ */
82
+ public function getModuleName()
83
+ {
84
+ if (null === $this->_module) {
85
+ $this->_module = $this->getParam($this->getModuleKey());
86
+ }
87
+
88
+ return $this->_module;
89
+ }
90
+
91
+ /**
92
+ * Set the module name to use
93
+ *
94
+ * @param string $value
95
+ * @return Zend_Controller_Request_Abstract
96
+ */
97
+ public function setModuleName($value)
98
+ {
99
+ $this->_module = $value;
100
+ return $this;
101
+ }
102
+
103
+ /**
104
+ * Retrieve the controller name
105
+ *
106
+ * @return string
107
+ */
108
+ public function getControllerName()
109
+ {
110
+ if (null === $this->_controller) {
111
+ $this->_controller = $this->getParam($this->getControllerKey());
112
+ }
113
+
114
+ return $this->_controller;
115
+ }
116
+
117
+ /**
118
+ * Set the controller name to use
119
+ *
120
+ * @param string $value
121
+ * @return Zend_Controller_Request_Abstract
122
+ */
123
+ public function setControllerName($value)
124
+ {
125
+ $this->_controller = $value;
126
+ return $this;
127
+ }
128
+
129
+ /**
130
+ * Retrieve the action name
131
+ *
132
+ * @return string
133
+ */
134
+ public function getActionName()
135
+ {
136
+ if (null === $this->_action) {
137
+ $this->_action = $this->getParam($this->getActionKey());
138
+ }
139
+
140
+ return $this->_action;
141
+ }
142
+
143
+ /**
144
+ * Set the action name
145
+ *
146
+ * @param string $value
147
+ * @return Zend_Controller_Request_Abstract
148
+ */
149
+ public function setActionName($value)
150
+ {
151
+ $this->_action = $value;
152
+ return $this;
153
+ }
154
+
155
+ /**
156
+ * Retrieve the module key
157
+ *
158
+ * @return string
159
+ */
160
+ public function getModuleKey()
161
+ {
162
+ return $this->_moduleKey;
163
+ }
164
+
165
+ /**
166
+ * Set the module key
167
+ *
168
+ * @param string $key
169
+ * @return Zend_Controller_Request_Abstract
170
+ */
171
+ public function setModuleKey($key)
172
+ {
173
+ $this->_moduleKey = (string) $key;
174
+ return $this;
175
+ }
176
+
177
+ /**
178
+ * Retrieve the controller key
179
+ *
180
+ * @return string
181
+ */
182
+ public function getControllerKey()
183
+ {
184
+ return $this->_controllerKey;
185
+ }
186
+
187
+ /**
188
+ * Set the controller key
189
+ *
190
+ * @param string $key
191
+ * @return Zend_Controller_Request_Abstract
192
+ */
193
+ public function setControllerKey($key)
194
+ {
195
+ $this->_controllerKey = (string) $key;
196
+ return $this;
197
+ }
198
+
199
+ /**
200
+ * Retrieve the action key
201
+ *
202
+ * @return string
203
+ */
204
+ public function getActionKey()
205
+ {
206
+ return $this->_actionKey;
207
+ }
208
+
209
+ /**
210
+ * Set the action key
211
+ *
212
+ * @param string $key
213
+ * @return Zend_Controller_Request_Abstract
214
+ */
215
+ public function setActionKey($key)
216
+ {
217
+ $this->_actionKey = (string) $key;
218
+ return $this;
219
+ }
220
+
221
+ /**
222
+ * Get an action parameter
223
+ *
224
+ * @param string $key
225
+ * @param mixed $default Default value to use if key not found
226
+ * @return mixed
227
+ */
228
+ public function getParam($key, $default = null)
229
+ {
230
+ $key = (string) $key;
231
+ if (isset($this->_params[$key])) {
232
+ return $this->_params[$key];
233
+ }
234
+
235
+ return $default;
236
+ }
237
+
238
+ /**
239
+ * Retrieve only user params (i.e, any param specific to the object and not the environment)
240
+ *
241
+ * @return array
242
+ */
243
+ public function getUserParams()
244
+ {
245
+ return $this->_params;
246
+ }
247
+
248
+ /**
249
+ * Retrieve a single user param (i.e, a param specific to the object and not the environment)
250
+ *
251
+ * @param string $key
252
+ * @param string $default Default value to use if key not found
253
+ * @return mixed
254
+ */
255
+ public function getUserParam($key, $default = null)
256
+ {
257
+ if (isset($this->_params[$key])) {
258
+ return $this->_params[$key];
259
+ }
260
+
261
+ return $default;
262
+ }
263
+
264
+ /**
265
+ * Set an action parameter
266
+ *
267
+ * A $value of null will unset the $key if it exists
268
+ *
269
+ * @param string $key
270
+ * @param mixed $value
271
+ * @return Zend_Controller_Request_Abstract
272
+ */
273
+ public function setParam($key, $value)
274
+ {
275
+ $key = (string) $key;
276
+
277
+ if ((null === $value) && isset($this->_params[$key])) {
278
+ unset($this->_params[$key]);
279
+ } elseif (null !== $value) {
280
+ $this->_params[$key] = $value;
281
+ }
282
+
283
+ return $this;
284
+ }
285
+
286
+ /**
287
+ * Get all action parameters
288
+ *
289
+ * @return array
290
+ */
291
+ public function getParams()
292
+ {
293
+ return $this->_params;
294
+ }
295
+
296
+ /**
297
+ * Set action parameters en masse; does not overwrite
298
+ *
299
+ * Null values will unset the associated key.
300
+ *
301
+ * @param array $array
302
+ * @return Zend_Controller_Request_Abstract
303
+ */
304
+ public function setParams(array $array)
305
+ {
306
+ $this->_params = $this->_params + (array) $array;
307
+
308
+ foreach ($this->_params as $key => $value) {
309
+ if (null === $value) {
310
+ unset($this->_params[$key]);
311
+ }
312
+ }
313
+
314
+ return $this;
315
+ }
316
+
317
+ /**
318
+ * Set flag indicating whether or not request has been dispatched
319
+ *
320
+ * @param boolean $flag
321
+ * @return Zend_Controller_Request_Abstract
322
+ */
323
+ public function setDispatched($flag = true)
324
+ {
325
+ $this->_dispatched = $flag ? true : false;
326
+ return $this;
327
+ }
328
+
329
+ /**
330
+ * Determine if the request has been dispatched
331
+ *
332
+ * @return boolean
333
+ */
334
+ public function isDispatched()
335
+ {
336
+ return $this->_dispatched;
337
+ }
338
+ }
lib/Zend/Controller/Request/Apache404.php ADDED
@@ -0,0 +1,80 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Zend Framework
4
+ *
5
+ * LICENSE
6
+ *
7
+ * This source file is subject to the new BSD license that is bundled
8
+ * with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://framework.zend.com/license/new-bsd
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@zend.com so we can send you a copy immediately.
14
+ *
15
+ * @category Zend
16
+ * @package Zend_Controller
17
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
18
+ * @license http://framework.zend.com/license/new-bsd New BSD License
19
+ */
20
+
21
+ /** Zend_Controller_Request_Exception */
22
+ require_once 'Zend/Controller/Request/Exception.php';
23
+
24
+ /** Zend_Controller_Request_Http */
25
+ require_once 'Zend/Controller/Request/Http.php';
26
+
27
+ /** Zend_Uri */
28
+ require_once 'Zend/Uri.php';
29
+
30
+ /**
31
+ * Zend_Controller_Request_Apache404
32
+ *
33
+ * HTTP request object for use with Zend_Controller family. Extends basic HTTP
34
+ * request object to allow for two edge cases when using Apache:
35
+ * - Using Apache's 404 handler instead of mod_rewrite to direct requests
36
+ * - Using the PT flag in rewrite rules
37
+ *
38
+ * In each case, the URL to check against is found in REDIRECT_URL, not
39
+ * REQUEST_URI.
40
+ *
41
+ * @uses Zend_Controller_Request_Http
42
+ * @package Zend_Controller
43
+ * @subpackage Request
44
+ */
45
+ class Zend_Controller_Request_Apache404 extends Zend_Controller_Request_Http
46
+ {
47
+ public function setRequestUri($requestUri = null)
48
+ {
49
+ if ($requestUri === null) {
50
+ if (isset($_SERVER['HTTP_X_REWRITE_URL'])) { // check this first so IIS will catch
51
+ $requestUri = $_SERVER['HTTP_X_REWRITE_URL'];
52
+ } elseif (isset($_SERVER['REDIRECT_URL'])) { // Check if using mod_rewrite
53
+ $requestUri = $_SERVER['REDIRECT_URL'];
54
+ } elseif (isset($_SERVER['REQUEST_URI'])) {
55
+ $requestUri = $_SERVER['REQUEST_URI'];
56
+ } elseif (isset($_SERVER['ORIG_PATH_INFO'])) { // IIS 5.0, PHP as CGI
57
+ $requestUri = $_SERVER['ORIG_PATH_INFO'];
58
+ if (!empty($_SERVER['QUERY_STRING'])) {
59
+ $requestUri .= '?' . $_SERVER['QUERY_STRING'];
60
+ }
61
+ } else {
62
+ return $this;
63
+ }
64
+ } elseif (!is_string($requestUri)) {
65
+ return $this;
66
+ } else {
67
+ // Set GET items, if available
68
+ $_GET = array();
69
+ if (false !== ($pos = strpos($requestUri, '?'))) {
70
+ // Get key => value pairs and set $_GET
71
+ $query = substr($requestUri, $pos + 1);
72
+ parse_str($query, $vars);
73
+ $_GET = $vars;
74
+ }
75
+ }
76
+
77
+ $this->_requestUri = $requestUri;
78
+ return $this;
79
+ }
80
+ }
lib/Zend/Controller/Request/Exception.php ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Zend Framework
4
+ *
5
+ * LICENSE
6
+ *
7
+ * This source file is subject to the new BSD license that is bundled
8
+ * with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://framework.zend.com/license/new-bsd
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@zend.com so we can send you a copy immediately.
14
+ *
15
+ * @category Zend
16
+ * @package Zend_Controller
17
+ * @subpackage Request
18
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
19
+ * @license http://framework.zend.com/license/new-bsd New BSD License
20
+ */
21
+
22
+
23
+ /** Zend_Controller_Exception */
24
+ require_once 'Zend/Controller/Exception.php';
25
+
26
+
27
+ /**
28
+ * @category Zend
29
+ * @package Zend_Controller
30
+ * @subpackage Request
31
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
32
+ * @license http://framework.zend.com/license/new-bsd New BSD License
33
+ */
34
+ class Zend_Controller_Request_Exception extends Zend_Controller_Exception
35
+ {}
36
+
lib/Zend/Controller/Request/Http.php ADDED
@@ -0,0 +1,885 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Zend Framework
4
+ *
5
+ * LICENSE
6
+ *
7
+ * This source file is subject to the new BSD license that is bundled
8
+ * with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://framework.zend.com/license/new-bsd
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@zend.com so we can send you a copy immediately.
14
+ *
15
+ * @category Zend
16
+ * @package Zend_Controller
17
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
18
+ * @license http://framework.zend.com/license/new-bsd New BSD License
19
+ */
20
+
21
+ /** Zend_Controller_Request_Exception */
22
+ require_once 'Zend/Controller/Request/Exception.php';
23
+
24
+ /** Zend_Controller_Request_Abstract */
25
+ require_once 'Zend/Controller/Request/Abstract.php';
26
+
27
+ /** Zend_Uri */
28
+ require_once 'Zend/Uri.php';
29
+
30
+ /**
31
+ * Zend_Controller_Request_Http
32
+ *
33
+ * HTTP request object for use with Zend_Controller family.
34
+ *
35
+ * @uses Zend_Controller_Request_Abstract
36
+ * @package Zend_Controller
37
+ * @subpackage Request
38
+ */
39
+ class Zend_Controller_Request_Http extends Zend_Controller_Request_Abstract
40
+ {
41
+ /**
42
+ * Allowed parameter sources
43
+ * @var array
44
+ */
45
+ protected $_paramSources = array('_GET', '_POST');
46
+
47
+ /**
48
+ * REQUEST_URI
49
+ * @var string;
50
+ */
51
+ protected $_requestUri;
52
+
53
+ /**
54
+ * Base URL of request
55
+ * @var string
56
+ */
57
+ protected $_baseUrl = null;
58
+
59
+ /**
60
+ * Base path of request
61
+ * @var string
62
+ */
63
+ protected $_basePath = null;
64
+
65
+ /**
66
+ * PATH_INFO
67
+ * @var string
68
+ */
69
+ protected $_pathInfo = '';
70
+
71
+ /**
72
+ * Instance parameters
73
+ * @var array
74
+ */
75
+ protected $_params = array();
76
+
77
+ /**
78
+ * Alias keys for request parameters
79
+ * @var array
80
+ */
81
+ protected $_aliases = array();
82
+
83
+ /**
84
+ * Constructor
85
+ *
86
+ * If a $uri is passed, the object will attempt to populate itself using
87
+ * that information.
88
+ *
89
+ * @param string|Zend_Uri $uri
90
+ * @return void
91
+ * @throws Zend_Controller_Request_Exception when invalid URI passed
92
+ */
93
+ public function __construct($uri = null)
94
+ {
95
+ if (null !== $uri) {
96
+ if (!$uri instanceof Zend_Uri) {
97
+ $uri = Zend_Uri::factory($uri);
98
+ }
99
+ if ($uri->valid()) {
100
+ $path = $uri->getPath();
101
+ $query = $uri->getQuery();
102
+ if (!empty($query)) {
103
+ $path .= '?' . $query;
104
+ }
105
+
106
+ $this->setRequestUri($path);
107
+ } else {
108
+ require_once 'Zend/Controller/Request/Exception.php';
109
+ throw new Zend_Controller_Request_Exception('Invalid URI provided to constructor');
110
+ }
111
+ } else {
112
+ $this->setRequestUri();
113
+ }
114
+ }
115
+
116
+ /**
117
+ * Access values contained in the superglobals as public members
118
+ * Order of precedence: 1. GET, 2. POST, 3. COOKIE, 4. SERVER, 5. ENV
119
+ *
120
+ * @see http://msdn.microsoft.com/en-us/library/system.web.httprequest.item.aspx
121
+ * @param string $key
122
+ * @return mixed
123
+ */
124
+ public function __get($key)
125
+ {
126
+ switch (true) {
127
+ case isset($this->_params[$key]):
128
+ return $this->_params[$key];
129
+ case isset($_GET[$key]):
130
+ return $_GET[$key];
131
+ case isset($_POST[$key]):
132
+ return $_POST[$key];
133
+ case isset($_COOKIE[$key]):
134
+ return $_COOKIE[$key];
135
+ case ($key == 'REQUEST_URI'):
136
+ return $this->getRequestUri();
137
+ case ($key == 'PATH_INFO'):
138
+ return $this->getPathInfo();
139
+ case isset($_SERVER[$key]):
140
+ return $_SERVER[$key];
141
+ case isset($_ENV[$key]):
142
+ return $_ENV[$key];
143
+ default:
144
+ return null;
145
+ }
146
+ }
147
+
148
+ /**
149
+ * Alias to __get
150
+ *
151
+ * @param string $key
152
+ * @return mixed
153
+ */
154
+ public function get($key)
155
+ {
156
+ return $this->__get($key);
157
+ }
158
+
159
+ /**
160
+ * Set values
161
+ *
162
+ * In order to follow {@link __get()}, which operates on a number of
163
+ * superglobals, setting values through overloading is not allowed and will
164
+ * raise an exception. Use setParam() instead.
165
+ *
166
+ * @param string $key
167
+ * @param mixed $value
168
+ * @return void
169
+ * @throws Zend_Controller_Request_Exception
170
+ */
171
+ public function __set($key, $value)
172
+ {
173
+ require_once 'Zend/Controller/Request/Exception.php';
174
+ throw new Zend_Controller_Request_Exception('Setting values in superglobals not allowed; please use setParam()');
175
+ }
176
+
177
+ /**
178
+ * Alias to __set()
179
+ *
180
+ * @param string $key
181
+ * @param mixed $value
182
+ * @return void
183
+ */
184
+ public function set($key, $value)
185
+ {
186
+ return $this->__set($key, $value);
187
+ }
188
+
189
+ /**
190
+ * Check to see if a property is set
191
+ *
192
+ * @param string $key
193
+ * @return boolean
194
+ */
195
+ public function __isset($key)
196
+ {
197
+ switch (true) {
198
+ case isset($this->_params[$key]):
199
+ return true;
200
+ case isset($_GET[$key]):
201
+ return true;
202
+ case isset($_POST[$key]):
203
+ return true;
204
+ case isset($_COOKIE[$key]):
205
+ return true;
206
+ case isset($_SERVER[$key]):
207
+ return true;
208
+ case isset($_ENV[$key]):
209
+ return true;
210
+ default:
211
+ return false;
212
+ }
213
+ }
214
+
215
+ /**
216
+ * Alias to __isset()
217
+ *
218
+ * @param string $key
219
+ * @return boolean
220
+ */
221
+ public function has($key)
222
+ {
223
+ return $this->__isset($key);
224
+ }
225
+
226
+ /**
227
+ * Retrieve a member of the $_GET superglobal
228
+ *
229
+ * If no $key is passed, returns the entire $_GET array.
230
+ *
231
+ * @todo How to retrieve from nested arrays
232
+ * @param string $key
233
+ * @param mixed $default Default value to use if key not found
234
+ * @return mixed Returns null if key does not exist
235
+ */
236
+ public function getQuery($key = null, $default = null)
237
+ {
238
+ if (null === $key) {
239
+ return $_GET;
240
+ }
241
+
242
+ return (isset($_GET[$key])) ? $_GET[$key] : $default;
243
+ }
244
+
245
+ /**
246
+ * Retrieve a member of the $_POST superglobal
247
+ *
248
+ * If no $key is passed, returns the entire $_POST array.
249
+ *
250
+ * @todo How to retrieve from nested arrays
251
+ * @param string $key
252
+ * @param mixed $default Default value to use if key not found
253
+ * @return mixed Returns null if key does not exist
254
+ */
255
+ public function getPost($key = null, $default = null)
256
+ {
257
+ if (null === $key) {
258
+ return $_POST;
259
+ }
260
+
261
+ return (isset($_POST[$key])) ? $_POST[$key] : $default;
262
+ }
263
+
264
+ /**
265
+ * Retrieve a member of the $_COOKIE superglobal
266
+ *
267
+ * If no $key is passed, returns the entire $_COOKIE array.
268
+ *
269
+ * @todo How to retrieve from nested arrays
270
+ * @param string $key
271
+ * @param mixed $default Default value to use if key not found
272
+ * @return mixed Returns null if key does not exist
273
+ */
274
+ public function getCookie($key = null, $default = null)
275
+ {
276
+ if (null === $key) {
277
+ return $_COOKIE;
278
+ }
279
+
280
+ return (isset($_COOKIE[$key])) ? $_COOKIE[$key] : $default;
281
+ }
282
+
283
+ /**
284
+ * Retrieve a member of the $_SERVER superglobal
285
+ *
286
+ * If no $key is passed, returns the entire $_SERVER array.
287
+ *
288
+ * @param string $key
289
+ * @param mixed $default Default value to use if key not found
290
+ * @return mixed Returns null if key does not exist
291
+ */
292
+ public function getServer($key = null, $default = null)
293
+ {
294
+ if (null === $key) {
295
+ return $_SERVER;
296
+ }
297
+
298
+ return (isset($_SERVER[$key])) ? $_SERVER[$key] : $default;
299
+ }
300
+
301
+ /**
302
+ * Retrieve a member of the $_ENV superglobal
303
+ *
304
+ * If no $key is passed, returns the entire $_ENV array.
305
+ *
306
+ * @param string $key
307
+ * @param mixed $default Default value to use if key not found
308
+ * @return mixed Returns null if key does not exist
309
+ */
310
+ public function getEnv($key = null, $default = null)
311
+ {
312
+ if (null === $key) {
313
+ return $_ENV;
314
+ }
315
+
316
+ return (isset($_ENV[$key])) ? $_ENV[$key] : $default;
317
+ }
318
+
319
+ /**
320
+ * Set the REQUEST_URI on which the instance operates
321
+ *
322
+ * If no request URI is passed, uses the value in $_SERVER['REQUEST_URI'],
323
+ * $_SERVER['HTTP_X_REWRITE_URL'], or $_SERVER['ORIG_PATH_INFO'] + $_SERVER['QUERY_STRING'].
324
+ *
325
+ * @param string $requestUri
326
+ * @return Zend_Controller_Request_Http
327
+ */
328
+ public function setRequestUri($requestUri = null)
329
+ {
330
+ if ($requestUri === null) {
331
+ if (isset($_SERVER['HTTP_X_REWRITE_URL'])) { // check this first so IIS will catch
332
+ $requestUri = $_SERVER['HTTP_X_REWRITE_URL'];
333
+ } elseif (isset($_SERVER['REQUEST_URI'])) {
334
+ $requestUri = $_SERVER['REQUEST_URI'];
335
+ } elseif (isset($_SERVER['ORIG_PATH_INFO'])) { // IIS 5.0, PHP as CGI
336
+ $requestUri = $_SERVER['ORIG_PATH_INFO'];
337
+ if (!empty($_SERVER['QUERY_STRING'])) {
338
+ $requestUri .= '?' . $_SERVER['QUERY_STRING'];
339
+ }
340
+ } else {
341
+ return $this;
342
+ }
343
+ } elseif (!is_string($requestUri)) {
344
+ return $this;
345
+ } else {
346
+ // Set GET items, if available
347
+ $_GET = array();
348
+ if (false !== ($pos = strpos($requestUri, '?'))) {
349
+ // Get key => value pairs and set $_GET
350
+ $query = substr($requestUri, $pos + 1);
351
+ parse_str($query, $vars);
352
+ $_GET = $vars;
353
+ }
354
+ }
355
+
356
+ $this->_requestUri = $requestUri;
357
+ return $this;
358
+ }
359
+
360
+ /**
361
+ * Returns the REQUEST_URI taking into account
362
+ * platform differences between Apache and IIS
363
+ *
364
+ * @return string
365
+ */
366
+ public function getRequestUri()
367
+ {
368
+ if (empty($this->_requestUri)) {
369
+ $this->setRequestUri();
370
+ }
371
+
372
+ return $this->_requestUri;
373
+ }
374
+
375
+ /**
376
+ * Set the base URL of the request; i.e., the segment leading to the script name
377
+ *
378
+ * E.g.:
379
+ * - /admin
380
+ * - /myapp
381
+ * - /subdir/index.php
382
+ *
383
+ * Do not use the full URI when providing the base. The following are
384
+ * examples of what not to use:
385
+ * - http://example.com/admin (should be just /admin)
386
+ * - http://example.com/subdir/index.php (should be just /subdir/index.php)
387
+ *
388
+ * If no $baseUrl is provided, attempts to determine the base URL from the
389
+ * environment, using SCRIPT_FILENAME, SCRIPT_NAME, PHP_SELF, and
390
+ * ORIG_SCRIPT_NAME in its determination.
391
+ *
392
+ * @param mixed $baseUrl
393
+ * @return Zend_Controller_Request_Http
394
+ */
395
+ public function setBaseUrl($baseUrl = null)
396
+ {
397
+ if ((null !== $baseUrl) && !is_string($baseUrl)) {
398
+ return $this;
399
+ }
400
+
401
+ if ($baseUrl === null) {
402
+ $filename = basename($_SERVER['SCRIPT_FILENAME']);
403
+
404
+ if (basename($_SERVER['SCRIPT_NAME']) === $filename) {
405
+ $baseUrl = $_SERVER['SCRIPT_NAME'];
406
+ } elseif (basename($_SERVER['PHP_SELF']) === $filename) {
407
+ $baseUrl = $_SERVER['PHP_SELF'];
408
+ } elseif (isset($_SERVER['ORIG_SCRIPT_NAME']) && basename($_SERVER['ORIG_SCRIPT_NAME']) === $filename) {
409
+ $baseUrl = $_SERVER['ORIG_SCRIPT_NAME']; // 1and1 shared hosting compatibility
410
+ } else {
411
+ // Backtrack up the script_filename to find the portion matching
412
+ // php_self
413
+ $path = $_SERVER['PHP_SELF'];
414
+ $segs = explode('/', trim($_SERVER['SCRIPT_FILENAME'], '/'));
415
+ $segs = array_reverse($segs);
416
+ $index = 0;
417
+ $last = count($segs);
418
+ $baseUrl = '';
419
+ do {
420
+ $seg = $segs[$index];
421
+ $baseUrl = '/' . $seg . $baseUrl;
422
+ ++$index;
423
+ } while (($last > $index) && (false !== ($pos = strpos($path, $baseUrl))) && (0 != $pos));
424
+ }
425
+
426
+ // Does the baseUrl have anything in common with the request_uri?
427
+ $requestUri = $this->getRequestUri();
428
+
429
+ if (0 === strpos($requestUri, $baseUrl)) {
430
+ // full $baseUrl matches
431
+ $this->_baseUrl = $baseUrl;
432
+ return $this;
433
+ }
434
+
435
+ if (0 === strpos($requestUri, dirname($baseUrl))) {
436
+ // directory portion of $baseUrl matches
437
+ $this->_baseUrl = rtrim(dirname($baseUrl), '/');
438
+ return $this;
439
+ }
440
+
441
+ if (!strpos($requestUri, basename($baseUrl))) {
442
+ // no match whatsoever; set it blank
443
+ $this->_baseUrl = '';
444
+ return $this;
445
+ }
446
+
447
+ // If using mod_rewrite or ISAPI_Rewrite strip the script filename
448
+ // out of baseUrl. $pos !== 0 makes sure it is not matching a value
449
+ // from PATH_INFO or QUERY_STRING
450
+ if ((strlen($requestUri) >= strlen($baseUrl))
451
+ && ((false !== ($pos = strpos($requestUri, $baseUrl))) && ($pos !== 0)))
452
+ {
453
+ $baseUrl = substr($requestUri, 0, $pos + strlen($baseUrl));
454
+ }
455
+ }
456
+
457
+ $this->_baseUrl = rtrim($baseUrl, '/');
458
+ return $this;
459
+ }
460
+
461
+ /**
462
+ * Everything in REQUEST_URI before PATH_INFO
463
+ * <form action="<?=$baseUrl?>/news/submit" method="POST"/>
464
+ *
465
+ * @return string
466
+ */
467
+ public function getBaseUrl()
468
+ {
469
+ if (null === $this->_baseUrl) {
470
+ $this->setBaseUrl();
471
+ }
472
+
473
+ return $this->_baseUrl;
474
+ }
475
+
476
+ /**
477
+ * Set the base path for the URL
478
+ *
479
+ * @param string|null $basePath
480
+ * @return Zend_Controller_Request_Http
481
+ */
482
+ public function setBasePath($basePath = null)
483
+ {
484
+ if ($basePath === null) {
485
+ $filename = basename($_SERVER['SCRIPT_FILENAME']);
486
+
487
+ $baseUrl = $this->getBaseUrl();
488
+ if (empty($baseUrl)) {
489
+ $this->_basePath = '';
490
+ return $this;
491
+ }
492
+
493
+ if (basename($baseUrl) === $filename) {
494
+ $basePath = dirname($baseUrl);
495
+ } else {
496
+ $basePath = $baseUrl;
497
+ }
498
+ }
499
+
500
+ $this->_basePath = rtrim($basePath, '/');
501
+ return $this;
502
+ }
503
+
504
+ /**
505
+ * Everything in REQUEST_URI before PATH_INFO not including the filename
506
+ * <img src="<?=$basePath?>/images/zend.png"/>
507
+ *
508
+ * @return string
509
+ */
510
+ public function getBasePath()
511
+ {
512
+ if (null === $this->_basePath) {
513
+ $this->setBasePath();
514
+ }
515
+
516
+ return $this->_basePath;
517
+ }
518
+
519
+ /**
520
+ * Set the PATH_INFO string
521
+ *
522
+ * @param string|null $pathInfo
523
+ * @return Zend_Controller_Request_Http
524
+ */
525
+ public function setPathInfo($pathInfo = null)
526
+ {
527
+ if ($pathInfo === null) {
528
+ $baseUrl = $this->getBaseUrl();
529
+
530
+ if (null === ($requestUri = $this->getRequestUri())) {
531
+ return $this;
532
+ }
533
+
534
+ // Remove the query string from REQUEST_URI
535
+ if ($pos = strpos($requestUri, '?')) {
536
+ $requestUri = substr($requestUri, 0, $pos);
537
+ }
538
+
539
+ if ((null !== $baseUrl)
540
+ && (false === ($pathInfo = substr($requestUri, strlen($baseUrl)))))
541
+ {
542
+ // If substr() returns false then PATH_INFO is set to an empty string
543
+ $pathInfo = '';
544
+ } elseif (null === $baseUrl) {
545
+ $pathInfo = $requestUri;
546
+ }
547
+ }
548
+
549
+ $this->_pathInfo = (string) $pathInfo;
550
+ return $this;
551
+ }
552
+
553
+ /**
554
+ * Returns everything between the BaseUrl and QueryString.
555
+ * This value is calculated instead of reading PATH_INFO
556
+ * directly from $_SERVER due to cross-platform differences.
557
+ *
558
+ * @return string
559
+ */
560
+ public function getPathInfo()
561
+ {
562
+ if (empty($this->_pathInfo)) {
563
+ $this->setPathInfo();
564
+ }
565
+
566
+ return $this->_pathInfo;
567
+ }
568
+
569
+ /**
570
+ * Set allowed parameter sources
571
+ *
572
+ * Can be empty array, or contain one or more of '_GET' or '_POST'.
573
+ *
574
+ * @param array $paramSoures
575
+ * @return Zend_Controller_Request_Http
576
+ */
577
+ public function setParamSources(array $paramSources = array())
578
+ {
579
+ $this->_paramSources = $paramSources;
580
+ return $this;
581
+ }
582
+
583
+ /**
584
+ * Get list of allowed parameter sources
585
+ *
586
+ * @return array
587
+ */
588
+ public function getParamSources()
589
+ {
590
+ return $this->_paramSources;
591
+ }
592
+
593
+ /**
594
+ * Set a userland parameter
595
+ *
596
+ * Uses $key to set a userland parameter. If $key is an alias, the actual
597
+ * key will be retrieved and used to set the parameter.
598
+ *
599
+ * @param mixed $key
600
+ * @param mixed $value
601
+ * @return Zend_Controller_Request_Http
602
+ */
603
+ public function setParam($key, $value)
604
+ {
605
+ $key = (null !== ($alias = $this->getAlias($key))) ? $alias : $key;
606
+ parent::setParam($key, $value);
607
+ return $this;
608
+ }
609
+
610
+ /**
611
+ * Retrieve a parameter
612
+ *
613
+ * Retrieves a parameter from the instance. Priority is in the order of
614
+ * userland parameters (see {@link setParam()}), $_GET, $_POST. If a
615
+ * parameter matching the $key is not found, null is returned.
616
+ *
617
+ * If the $key is an alias, the actual key aliased will be used.
618
+ *
619
+ * @param mixed $key
620
+ * @param mixed $default Default value to use if key not found
621
+ * @return mixed
622
+ */
623
+ public function getParam($key, $default = null)
624
+ {
625
+ $keyName = (null !== ($alias = $this->getAlias($key))) ? $alias : $key;
626
+
627
+ $paramSources = $this->getParamSources();
628
+ if (isset($this->_params[$keyName])) {
629
+ return $this->_params[$keyName];
630
+ } elseif (in_array('_GET', $paramSources) && (isset($_GET[$keyName]))) {
631
+ return $_GET[$keyName];
632
+ } elseif (in_array('_POST', $paramSources) && (isset($_POST[$keyName]))) {
633
+ return $_POST[$keyName];
634
+ }
635
+
636
+ return $default;
637
+ }
638
+
639
+ /**
640
+ * Retrieve an array of parameters
641
+ *
642
+ * Retrieves a merged array of parameters, with precedence of userland
643
+ * params (see {@link setParam()}), $_GET, $POST (i.e., values in the
644
+ * userland params will take precedence over all others).
645
+ *
646
+ * @return array
647
+ */
648
+ public function getParams()
649
+ {
650
+ $return = $this->_params;
651
+ if (isset($_GET) && is_array($_GET)) {
652
+ $return += $_GET;
653
+ }
654
+ if (isset($_POST) && is_array($_POST)) {
655
+ $return += $_POST;
656
+ }
657
+ return $return;
658
+ }
659
+
660
+ /**
661
+ * Set parameters
662
+ *
663
+ * Set one or more parameters. Parameters are set as userland parameters,
664
+ * using the keys specified in the array.
665
+ *
666
+ * @param array $params
667
+ * @return Zend_Controller_Request_Http
668
+ */
669
+ public function setParams(array $params)
670
+ {
671
+ foreach ($params as $key => $value) {
672
+ $this->setParam($key, $value);
673
+ }
674
+ return $this;
675
+ }
676
+
677
+ /**
678
+ * Set a key alias
679
+ *
680
+ * Set an alias used for key lookups. $name specifies the alias, $target
681
+ * specifies the actual key to use.
682
+ *
683
+ * @param string $name
684
+ * @param string $target
685
+ * @return Zend_Controller_Request_Http
686
+ */
687
+ public function setAlias($name, $target)
688
+ {
689
+ $this->_aliases[$name] = $target;
690
+ return $this;
691
+ }
692
+
693
+ /**
694
+ * Retrieve an alias
695
+ *
696
+ * Retrieve the actual key represented by the alias $name.
697
+ *
698
+ * @param string $name
699
+ * @return string|null Returns null when no alias exists
700
+ */
701
+ public function getAlias($name)
702
+ {
703
+ if (isset($this->_aliases[$name])) {
704
+ return $this->_aliases[$name];
705
+ }
706
+
707
+ return null;
708
+ }
709
+
710
+ /**
711
+ * Retrieve the list of all aliases
712
+ *
713
+ * @return array
714
+ */
715
+ public function getAliases()
716
+ {
717
+ return $this->_aliases;
718
+ }
719
+
720
+ /**
721
+ * Return the method by which the request was made
722
+ *
723
+ * @return string
724
+ */
725
+ public function getMethod()
726
+ {
727
+ return $this->getServer('REQUEST_METHOD');
728
+ }
729
+
730
+ /**
731
+ * Was the request made by POST?
732
+ *
733
+ * @return boolean
734
+ */
735
+ public function isPost()
736
+ {
737
+ if ('POST' == $this->getMethod()) {
738
+ return true;
739
+ }
740
+
741
+ return false;
742
+ }
743
+
744
+ /**
745
+ * Was the request made by GET?
746
+ *
747
+ * @return boolean
748
+ */
749
+ public function isGet()
750
+ {
751
+ if ('GET' == $this->getMethod()) {
752
+ return true;
753
+ }
754
+
755
+ return false;
756
+ }
757
+
758
+ /**
759
+ * Was the request made by PUT?
760
+ *
761
+ * @return boolean
762
+ */
763
+ public function isPut()
764
+ {
765
+ if ('PUT' == $this->getMethod()) {
766
+ return true;
767
+ }
768
+
769
+ return false;
770
+ }
771
+
772
+ /**
773
+ * Was the request made by DELETE?
774
+ *
775
+ * @return boolean
776
+ */
777
+ public function isDelete()
778
+ {
779
+ if ('DELETE' == $this->getMethod()) {
780
+ return true;
781
+ }
782
+
783
+ return false;
784
+ }
785
+
786
+ /**
787
+ * Was the request made by HEAD?
788
+ *
789
+ * @return boolean
790
+ */
791
+ public function isHead()
792
+ {
793
+ if ('HEAD' == $this->getMethod()) {
794
+ return true;
795
+ }
796
+
797
+ return false;
798
+ }
799
+
800
+ /**
801
+ * Was the request made by OPTIONS?
802
+ *
803
+ * @return boolean
804
+ */
805
+ public function isOptions()
806
+ {
807
+ if ('OPTIONS' == $this->getMethod()) {
808
+ return true;
809
+ }
810
+
811
+ return false;
812
+ }
813
+
814
+ /**
815
+ * Return the raw body of the request, if present
816
+ *
817
+ * @return string|false Raw body, or false if not present
818
+ */
819
+ public function getRawBody()
820
+ {
821
+ $body = file_get_contents('php://input');
822
+
823
+ if (strlen(trim($body)) > 0) {
824
+ return $body;
825
+ }
826
+
827
+ return false;
828
+ }
829
+
830
+ /**
831
+ * Return the value of the given HTTP header. Pass the header name as the
832
+ * plain, HTTP-specified header name. Ex.: Ask for 'Accept' to get the
833
+ * Accept header, 'Accept-Encoding' to get the Accept-Encoding header.
834
+ *
835
+ * @param string $header HTTP header name
836
+ * @return string|false HTTP header value, or false if not found
837
+ * @throws Zend_Controller_Request_Exception
838
+ */
839
+ public function getHeader($header)
840
+ {
841
+ if (empty($header)) {
842
+ require_once 'Zend/Controller/Request/Exception.php';
843
+ throw new Zend_Controller_Request_Exception('An HTTP header name is required');
844
+ }
845
+
846
+ // Try to get it from the $_SERVER array first
847
+ $temp = 'HTTP_' . strtoupper(str_replace('-', '_', $header));
848
+ if (!empty($_SERVER[$temp])) {
849
+ return $_SERVER[$temp];
850
+ }
851
+
852
+ // This seems to be the only way to get the Authorization header on
853
+ // Apache
854
+ if (function_exists('apache_request_headers')) {
855
+ $headers = apache_request_headers();
856
+ if (!empty($headers[$header])) {
857
+ return $headers[$header];
858
+ }
859
+ }
860
+
861
+ return false;
862
+ }
863
+
864
+ /**
865
+ * Is the request a Javascript XMLHttpRequest?
866
+ *
867
+ * Should work with Prototype/Script.aculo.us, possibly others.
868
+ *
869
+ * @return boolean
870
+ */
871
+ public function isXmlHttpRequest()
872
+ {
873
+ return ($this->getHeader('X_REQUESTED_WITH') == 'XMLHttpRequest');
874
+ }
875
+
876
+ /**
877
+ * Is this a Flash request?
878
+ *
879
+ * @return bool
880
+ */
881
+ public function isFlashRequest()
882
+ {
883
+ return ($this->getHeader('USER_AGENT') == 'Shockwave Flash');
884
+ }
885
+ }
lib/Zend/Controller/Request/Simple.php ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Zend Framework
4
+ *
5
+ * LICENSE
6
+ *
7
+ * This source file is subject to the new BSD license that is bundled
8
+ * with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://framework.zend.com/license/new-bsd
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@zend.com so we can send you a copy immediately.
14
+ *
15
+ * @category Zend
16
+ * @package Zend_Controller
17
+ * @subpackage Request
18
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
19
+ * @license http://framework.zend.com/license/new-bsd New BSD License
20
+ */
21
+
22
+ /** Zend_Controller_Request_Abstract */
23
+ require_once 'Zend/Controller/Request/Abstract.php';
24
+
25
+ /**
26
+ * @category Zend
27
+ * @package Zend_Controller
28
+ * @subpackage Request
29
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
30
+ * @license http://framework.zend.com/license/new-bsd New BSD License
31
+ */
32
+ class Zend_Controller_Request_Simple extends Zend_Controller_Request_Abstract
33
+ {
34
+
35
+ public function __construct($action = null, $controller = null, $module = null, array $params = array())
36
+ {
37
+ if ($action) {
38
+ $this->setActionName($action);
39
+ }
40
+
41
+ if ($controller) {
42
+ $this->setControllerName($controller);
43
+ }
44
+
45
+ if ($module) {
46
+ $this->setModuleName($module);
47
+ }
48
+
49
+ if ($params) {
50
+ $this->setParams($params);
51
+ }
52
+ }
53
+
54
+ }
lib/Zend/Controller/Response/Abstract.php ADDED
@@ -0,0 +1,755 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Zend Framework
4
+ *
5
+ * LICENSE
6
+ *
7
+ * This source file is subject to the new BSD license that is bundled
8
+ * with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://framework.zend.com/license/new-bsd
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@zend.com so we can send you a copy immediately.
14
+ *
15
+ * @category Zend
16
+ * @package Zend_Controller
17
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
18
+ * @license http://framework.zend.com/license/new-bsd New BSD License
19
+ */
20
+
21
+ /**
22
+ * Zend_Controller_Response_Abstract
23
+ *
24
+ * Base class for Zend_Controller responses
25
+ *
26
+ * @package Zend_Controller
27
+ * @subpackage Response
28
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
29
+ * @license http://framework.zend.com/license/new-bsd New BSD License
30
+ */
31
+ abstract class Zend_Controller_Response_Abstract
32
+ {
33
+ /**
34
+ * Body content
35
+ * @var array
36
+ */
37
+ protected $_body = array();
38
+
39
+ /**
40
+ * Exception stack
41
+ * @var Exception
42
+ */
43
+ protected $_exceptions = array();
44
+
45
+ /**
46
+ * Array of headers. Each header is an array with keys 'name' and 'value'
47
+ * @var array
48
+ */
49
+ protected $_headers = array();
50
+
51
+ /**
52
+ * Array of raw headers. Each header is a single string, the entire header to emit
53
+ * @var array
54
+ */
55
+ protected $_headersRaw = array();
56
+
57
+ /**
58
+ * HTTP response code to use in headers
59
+ * @var int
60
+ */
61
+ protected $_httpResponseCode = 200;
62
+
63
+ /**
64
+ * Flag; is this response a redirect?
65
+ * @var boolean
66
+ */
67
+ protected $_isRedirect = false;
68
+
69
+ /**
70
+ * Whether or not to render exceptions; off by default
71
+ * @var boolean
72
+ */
73
+ protected $_renderExceptions = false;
74
+
75
+ /**
76
+ * Flag; if true, when header operations are called after headers have been
77
+ * sent, an exception will be raised; otherwise, processing will continue
78
+ * as normal. Defaults to true.
79
+ *
80
+ * @see canSendHeaders()
81
+ * @var boolean
82
+ */
83
+ public $headersSentThrowsException = true;
84
+
85
+ /**
86
+ * Normalize a header name
87
+ *
88
+ * Normalizes a header name to X-Capitalized-Names
89
+ *
90
+ * @param string $name
91
+ * @return string
92
+ */
93
+ protected function _normalizeHeader($name)
94
+ {
95
+ $filtered = str_replace(array('-', '_'), ' ', (string) $name);
96
+ $filtered = ucwords(strtolower($filtered));
97
+ $filtered = str_replace(' ', '-', $filtered);
98
+ return $filtered;
99
+ }
100
+
101
+ /**
102
+ * Set a header
103
+ *
104
+ * If $replace is true, replaces any headers already defined with that
105
+ * $name.
106
+ *
107
+ * @param string $name
108
+ * @param string $value
109
+ * @param boolean $replace
110
+ * @return Zend_Controller_Response_Abstract
111
+ */
112
+ public function setHeader($name, $value, $replace = false)
113
+ {
114
+ $this->canSendHeaders(true);
115
+ $name = $this->_normalizeHeader($name);
116
+ $value = (string) $value;
117
+
118
+ if ($replace) {
119
+ foreach ($this->_headers as $key => $header) {
120
+ if ($name == $header['name']) {
121
+ unset($this->_headers[$key]);
122
+ }
123
+ }
124
+ }
125
+
126
+ $this->_headers[] = array(
127
+ 'name' => $name,
128
+ 'value' => $value,
129
+ 'replace' => $replace
130
+ );
131
+
132
+ return $this;
133
+ }
134
+
135
+ /**
136
+ * Set redirect URL
137
+ *
138
+ * Sets Location header and response code. Forces replacement of any prior
139
+ * redirects.
140
+ *
141
+ * @param string $url
142
+ * @param int $code
143
+ * @return Zend_Controller_Response_Abstract
144
+ */
145
+ public function setRedirect($url, $code = 302)
146
+ {
147
+ $this->canSendHeaders(true);
148
+ $this->setHeader('Location', $url, true)
149
+ ->setHttpResponseCode($code);
150
+
151
+ return $this;
152
+ }
153
+
154
+ /**
155
+ * Is this a redirect?
156
+ *
157
+ * @return boolean
158
+ */
159
+ public function isRedirect()
160
+ {
161
+ return $this->_isRedirect;
162
+ }
163
+
164
+ /**
165
+ * Return array of headers; see {@link $_headers} for format
166
+ *
167
+ * @return array
168
+ */
169
+ public function getHeaders()
170
+ {
171
+ return $this->_headers;
172
+ }
173
+
174
+ /**
175
+ * Clear headers
176
+ *
177
+ * @return Zend_Controller_Response_Abstract
178
+ */
179
+ public function clearHeaders()
180
+ {
181
+ $this->_headers = array();
182
+
183
+ return $this;
184
+ }
185
+
186
+ /**
187
+ * Set raw HTTP header
188
+ *
189
+ * Allows setting non key => value headers, such as status codes
190
+ *
191
+ * @param string $value
192
+ * @return Zend_Controller_Response_Abstract
193
+ */
194
+ public function setRawHeader($value)
195
+ {
196
+ $this->canSendHeaders(true);
197
+ if ('Location' == substr($value, 0, 8)) {
198
+ $this->_isRedirect = true;
199
+ }
200
+ $this->_headersRaw[] = (string) $value;
201
+ return $this;
202
+ }
203
+
204
+ /**
205
+ * Retrieve all {@link setRawHeader() raw HTTP headers}
206
+ *
207
+ * @return array
208
+ */
209
+ public function getRawHeaders()
210
+ {
211
+ return $this->_headersRaw;
212
+ }
213
+
214
+ /**
215
+ * Clear all {@link setRawHeader() raw HTTP headers}
216
+ *
217
+ * @return Zend_Controller_Response_Abstract
218
+ */
219
+ public function clearRawHeaders()
220
+ {
221
+ $this->_headersRaw = array();
222
+ return $this;
223
+ }
224
+
225
+ /**
226
+ * Clear all headers, normal and raw
227
+ *
228
+ * @return Zend_Controller_Response_Abstract
229
+ */
230
+ public function clearAllHeaders()
231
+ {
232
+ return $this->clearHeaders()
233
+ ->clearRawHeaders();
234
+ }
235
+
236
+ /**
237
+ * Set HTTP response code to use with headers
238
+ *
239
+ * @param int $code
240
+ * @return Zend_Controller_Response_Abstract
241
+ */
242
+ public function setHttpResponseCode($code)
243
+ {
244
+ if (!is_int($code) || (100 > $code) || (599 < $code)) {
245
+ require_once 'Zend/Controller/Response/Exception.php';
246
+ throw new Zend_Controller_Response_Exception('Invalid HTTP response code');
247
+ }
248
+
249
+ if ((300 <= $code) && (307 >= $code)) {
250
+ $this->_isRedirect = true;
251
+ } else {
252
+ $this->_isRedirect = false;
253
+ }
254
+
255
+ $this->_httpResponseCode = $code;
256
+ return $this;
257
+ }
258
+
259
+ /**
260
+ * Retrieve HTTP response code
261
+ *
262
+ * @return int
263
+ */
264
+ public function getHttpResponseCode()
265
+ {
266
+ return $this->_httpResponseCode;
267
+ }
268
+
269
+ /**
270
+ * Can we send headers?
271
+ *
272
+ * @param boolean $throw Whether or not to throw an exception if headers have been sent; defaults to false
273
+ * @return boolean
274
+ * @throws Zend_Controller_Response_Exception
275
+ */
276
+ public function canSendHeaders($throw = false)
277
+ {
278
+ $ok = headers_sent($file, $line);
279
+ if ($ok && $throw && $this->headersSentThrowsException) {
280
+ require_once 'Zend/Controller/Response/Exception.php';
281
+ throw new Zend_Controller_Response_Exception('Cannot send headers; headers already sent in ' . $file . ', line ' . $line);
282
+ }
283
+
284
+ return !$ok;
285
+ }
286
+
287
+ /**
288
+ * Send all headers
289
+ *
290
+ * Sends any headers specified. If an {@link setHttpResponseCode() HTTP response code}
291
+ * has been specified, it is sent with the first header.
292
+ *
293
+ * @return Zend_Controller_Response_Abstract
294
+ */
295
+ public function sendHeaders()
296
+ {
297
+ // Only check if we can send headers if we have headers to send
298
+ if (count($this->_headersRaw) || count($this->_headers) || (200 != $this->_httpResponseCode)) {
299
+ $this->canSendHeaders(true);
300
+ } elseif (200 == $this->_httpResponseCode) {
301
+ // Haven't changed the response code, and we have no headers
302
+ return $this;
303
+ }
304
+
305
+ $httpCodeSent = false;
306
+
307
+ foreach ($this->_headersRaw as $header) {
308
+ if (!$httpCodeSent && $this->_httpResponseCode) {
309
+ header($header, true, $this->_httpResponseCode);
310
+ $httpCodeSent = true;
311
+ } else {
312
+ header($header);
313
+ }
314
+ }
315
+
316
+ foreach ($this->_headers as $header) {
317
+ if (!$httpCodeSent && $this->_httpResponseCode) {
318
+ header($header['name'] . ': ' . $header['value'], $header['replace'], $this->_httpResponseCode);
319
+ $httpCodeSent = true;
320
+ } else {
321
+ header($header['name'] . ': ' . $header['value'], $header['replace']);
322
+ }
323
+ }
324
+
325
+ if (!$httpCodeSent) {
326
+ header('HTTP/1.1 ' . $this->_httpResponseCode);
327
+ $httpCodeSent = true;
328
+ }
329
+
330
+ return $this;
331
+ }
332
+
333
+ /**
334
+ * Set body content
335
+ *
336
+ * If $name is not passed, or is not a string, resets the entire body and
337
+ * sets the 'default' key to $content.
338
+ *
339
+ * If $name is a string, sets the named segment in the body array to
340
+ * $content.
341
+ *
342
+ * @param string $content
343
+ * @param null|string $name
344
+ * @return Zend_Controller_Response_Abstract
345
+ */
346
+ public function setBody($content, $name = null)
347
+ {
348
+ if ((null === $name) || !is_string($name)) {
349
+ $this->_body = array('default' => (string) $content);
350
+ } else {
351
+ $this->_body[$name] = (string) $content;
352
+ }
353
+
354
+ return $this;
355
+ }
356
+
357
+ /**
358
+ * Append content to the body content
359
+ *
360
+ * @param string $content
361
+ * @param null|string $name
362
+ * @return Zend_Controller_Response_Abstract
363
+ */
364
+ public function appendBody($content, $name = null)
365
+ {
366
+ if ((null === $name) || !is_string($name)) {
367
+ if (isset($this->_body['default'])) {
368
+ $this->_body['default'] .= (string) $content;
369
+ } else {
370
+ return $this->append('default', $content);
371
+ }
372
+ } elseif (isset($this->_body[$name])) {
373
+ $this->_body[$name] .= (string) $content;
374
+ } else {
375
+ return $this->append($name, $content);
376
+ }
377
+
378
+ return $this;
379
+ }
380
+
381
+ /**
382
+ * Clear body array
383
+ *
384
+ * With no arguments, clears the entire body array. Given a $name, clears
385
+ * just that named segment; if no segment matching $name exists, returns
386
+ * false to indicate an error.
387
+ *
388
+ * @param string $name Named segment to clear
389
+ * @return boolean
390
+ */
391
+ public function clearBody($name = null)
392
+ {
393
+ if (null !== $name) {
394
+ $name = (string) $name;
395
+ if (isset($this->_body[$name])) {
396
+ unset($this->_body[$name]);
397
+ return true;
398
+ }
399
+
400
+ return false;
401
+ }
402
+
403
+ $this->_body = array();
404
+ return true;
405
+ }
406
+
407
+ /**
408
+ * Return the body content
409
+ *
410
+ * If $spec is false, returns the concatenated values of the body content
411
+ * array. If $spec is boolean true, returns the body content array. If
412
+ * $spec is a string and matches a named segment, returns the contents of
413
+ * that segment; otherwise, returns null.
414
+ *
415
+ * @param boolean $spec
416
+ * @return string|array|null
417
+ */
418
+ public function getBody($spec = false)
419
+ {
420
+ if (false === $spec) {
421
+ ob_start();
422
+ $this->outputBody();
423
+ return ob_get_clean();
424
+ } elseif (true === $spec) {
425
+ return $this->_body;
426
+ } elseif (is_string($spec) && isset($this->_body[$spec])) {
427
+ return $this->_body[$spec];
428
+ }
429
+
430
+ return null;
431
+ }
432
+
433
+ /**
434
+ * Append a named body segment to the body content array
435
+ *
436
+ * If segment already exists, replaces with $content and places at end of
437
+ * array.
438
+ *
439
+ * @param string $name
440
+ * @param string $content
441
+ * @return Zend_Controller_Response_Abstract
442
+ */
443
+ public function append($name, $content)
444
+ {
445
+ if (!is_string($name)) {
446
+ require_once 'Zend/Controller/Response/Exception.php';
447
+ throw new Zend_Controller_Response_Exception('Invalid body segment key ("' . gettype($name) . '")');
448
+ }
449
+
450
+ if (isset($this->_body[$name])) {
451
+ unset($this->_body[$name]);
452
+ }
453
+ $this->_body[$name] = (string) $content;
454
+ return $this;
455
+ }
456
+
457
+ /**
458
+ * Prepend a named body segment to the body content array
459
+ *
460
+ * If segment already exists, replaces with $content and places at top of
461
+ * array.
462
+ *
463
+ * @param string $name
464
+ * @param string $content
465
+ * @return void
466
+ */
467
+ public function prepend($name, $content)
468
+ {
469
+ if (!is_string($name)) {
470
+ require_once 'Zend/Controller/Response/Exception.php';
471
+ throw new Zend_Controller_Response_Exception('Invalid body segment key ("' . gettype($name) . '")');
472
+ }
473
+
474
+ if (isset($this->_body[$name])) {
475
+ unset($this->_body[$name]);
476
+ }
477
+
478
+ $new = array($name => (string) $content);
479
+ $this->_body = $new + $this->_body;
480
+
481
+ return $this;
482
+ }
483
+
484
+ /**
485
+ * Insert a named segment into the body content array
486
+ *
487
+ * @param string $name
488
+ * @param string $content
489
+ * @param string $parent
490
+ * @param boolean $before Whether to insert the new segment before or
491
+ * after the parent. Defaults to false (after)
492
+ * @return Zend_Controller_Response_Abstract
493
+ */
494
+ public function insert($name, $content, $parent = null, $before = false)
495
+ {
496
+ if (!is_string($name)) {
497
+ require_once 'Zend/Controller/Response/Exception.php';
498
+ throw new Zend_Controller_Response_Exception('Invalid body segment key ("' . gettype($name) . '")');
499
+ }
500
+
501
+ if ((null !== $parent) && !is_string($parent)) {
502
+ require_once 'Zend/Controller/Response/Exception.php';
503
+ throw new Zend_Controller_Response_Exception('Invalid body segment parent key ("' . gettype($parent) . '")');
504
+ }
505
+
506
+ if (isset($this->_body[$name])) {
507
+ unset($this->_body[$name]);
508
+ }
509
+
510
+ if ((null === $parent) || !isset($this->_body[$parent])) {
511
+ return $this->append($name, $content);
512
+ }
513
+
514
+ $ins = array($name => (string) $content);
515
+ $keys = array_keys($this->_body);
516
+ $loc = array_search($parent, $keys);
517
+ if (!$before) {
518
+ // Increment location if not inserting before
519
+ ++$loc;
520
+ }
521
+
522
+ if (0 === $loc) {
523
+ // If location of key is 0, we're prepending
524
+ $this->_body = $ins + $this->_body;
525
+ } elseif ($loc >= (count($this->_body))) {
526
+ // If location of key is maximal, we're appending
527
+ $this->_body = $this->_body + $ins;
528
+ } else {
529
+ // Otherwise, insert at location specified
530
+ $pre = array_slice($this->_body, 0, $loc);
531
+ $post = array_slice($this->_body, $loc);
532
+ $this->_body = $pre + $ins + $post;
533
+ }
534
+
535
+ return $this;
536
+ }
537
+
538
+ /**
539
+ * Echo the body segments
540
+ *
541
+ * @return void
542
+ */
543
+ public function outputBody()
544
+ {
545
+ foreach ($this->_body as $content) {
546
+ echo $content;
547
+ }
548
+ }
549
+
550
+ /**
551
+ * Register an exception with the response
552
+ *
553
+ * @param Exception $e
554
+ * @return Zend_Controller_Response_Abstract
555
+ */
556
+ public function setException(Exception $e)
557
+ {
558
+ $this->_exceptions[] = $e;
559
+ return $this;
560
+ }
561
+
562
+ /**
563
+ * Retrieve the exception stack
564
+ *
565
+ * @return array
566
+ */
567
+ public function getException()
568
+ {
569
+ return $this->_exceptions;
570
+ }
571
+
572
+ /**
573
+ * Has an exception been registered with the response?
574
+ *
575
+ * @return boolean
576
+ */
577
+ public function isException()
578
+ {
579
+ return !empty($this->_exceptions);
580
+ }
581
+
582
+ /**
583
+ * Does the response object contain an exception of a given type?
584
+ *
585
+ * @param string $type
586
+ * @return boolean
587
+ */
588
+ public function hasExceptionOfType($type)
589
+ {
590
+ foreach ($this->_exceptions as $e) {
591
+ if ($e instanceof $type) {
592
+ return true;
593
+ }
594
+ }
595
+
596
+ return false;
597
+ }
598
+
599
+ /**
600
+ * Does the response object contain an exception with a given message?
601
+ *
602
+ * @param string $message
603
+ * @return boolean
604
+ */
605
+ public function hasExceptionOfMessage($message)
606
+ {
607
+ foreach ($this->_exceptions as $e) {
608
+ if ($message == $e->getMessage()) {
609
+ return true;
610
+ }
611
+ }
612
+
613
+ return false;
614
+ }
615
+
616
+ /**
617
+ * Does the response object contain an exception with a given code?
618
+ *
619
+ * @param int $code
620
+ * @return boolean
621
+ */
622
+ public function hasExceptionOfCode($code)
623
+ {
624
+ $code = (int) $code;
625
+ foreach ($this->_exceptions as $e) {
626
+ if ($code == $e->getCode()) {
627
+ return true;
628
+ }
629
+ }
630
+
631
+ return false;
632
+ }
633
+
634
+ /**
635
+ * Retrieve all exceptions of a given type
636
+ *
637
+ * @param string $type
638
+ * @return false|array
639
+ */
640
+ public function getExceptionByType($type)
641
+ {
642
+ $exceptions = array();
643
+ foreach ($this->_exceptions as $e) {
644
+ if ($e instanceof $type) {
645
+ $exceptions[] = $e;
646
+ }
647
+ }
648
+
649
+ if (empty($exceptions)) {
650
+ $exceptions = false;
651
+ }
652
+
653
+ return $exceptions;
654
+ }
655
+
656
+ /**
657
+ * Retrieve all exceptions of a given message
658
+ *
659
+ * @param string $message
660
+ * @return false|array
661
+ */
662
+ public function getExceptionByMessage($message)
663
+ {
664
+ $exceptions = array();
665
+ foreach ($this->_exceptions as $e) {
666
+ if ($message == $e->getMessage()) {
667
+ $exceptions[] = $e;
668
+ }
669
+ }
670
+
671
+ if (empty($exceptions)) {
672
+ $exceptions = false;
673
+ }
674
+
675
+ return $exceptions;
676
+ }
677
+
678
+ /**
679
+ * Retrieve all exceptions of a given code
680
+ *
681
+ * @param mixed $code
682
+ * @return void
683
+ */
684
+ public function getExceptionByCode($code)
685
+ {
686
+ $code = (int) $code;
687
+ $exceptions = array();
688
+ foreach ($this->_exceptions as $e) {
689
+ if ($code == $e->getCode()) {
690
+ $exceptions[] = $e;
691
+ }
692
+ }
693
+
694
+ if (empty($exceptions)) {
695
+ $exceptions = false;
696
+ }
697
+
698
+ return $exceptions;
699
+ }
700
+
701
+ /**
702
+ * Whether or not to render exceptions (off by default)
703
+ *
704
+ * If called with no arguments or a null argument, returns the value of the
705
+ * flag; otherwise, sets it and returns the current value.
706
+ *
707
+ * @param boolean $flag Optional
708
+ * @return boolean
709
+ */
710
+ public function renderExceptions($flag = null)
711
+ {
712
+ if (null !== $flag) {
713
+ $this->_renderExceptions = $flag ? true : false;
714
+ }
715
+
716
+ return $this->_renderExceptions;
717
+ }
718
+
719
+ /**
720
+ * Send the response, including all headers, rendering exceptions if so
721
+ * requested.
722
+ *
723
+ * @return void
724
+ */
725
+ public function sendResponse()
726
+ {
727
+ $this->sendHeaders();
728
+
729
+ if ($this->isException() && $this->renderExceptions()) {
730
+ $exceptions = '';
731
+ foreach ($this->getException() as $e) {
732
+ $exceptions .= $e->__toString() . "\n";
733
+ }
734
+ echo $exceptions;
735
+ return;
736
+ }
737
+
738
+ $this->outputBody();
739
+ }
740
+
741
+ /**
742
+ * Magic __toString functionality
743
+ *
744
+ * Proxies to {@link sendResponse()} and returns response value as string
745
+ * using output buffering.
746
+ *
747
+ * @return string
748
+ */
749
+ public function __toString()
750
+ {
751
+ ob_start();
752
+ $this->sendResponse();
753
+ return ob_get_clean();
754
+ }
755
+ }
lib/Zend/Controller/Response/Cli.php ADDED
@@ -0,0 +1,67 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Zend Framework
4
+ *
5
+ * LICENSE
6
+ *
7
+ * This source file is subject to the new BSD license that is bundled
8
+ * with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://framework.zend.com/license/new-bsd
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@zend.com so we can send you a copy immediately.
14
+ *
15
+ * @category Zend
16
+ * @package Zend_Controller
17
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
18
+ * @license http://framework.zend.com/license/new-bsd New BSD License
19
+ */
20
+
21
+
22
+ /** Zend_Controller_Response_Abstract */
23
+ require_once 'Zend/Controller/Response/Abstract.php';
24
+
25
+
26
+ /**
27
+ * Zend_Controller_Response_Cli
28
+ *
29
+ * CLI response for controllers
30
+ *
31
+ * @uses Zend_Controller_Response_Abstract
32
+ * @package Zend_Controller
33
+ * @subpackage Response
34
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
35
+ * @license http://framework.zend.com/license/new-bsd New BSD License
36
+ */
37
+ class Zend_Controller_Response_Cli extends Zend_Controller_Response_Abstract
38
+ {
39
+ /**
40
+ * Flag; if true, when header operations are called after headers have been
41
+ * sent, an exception will be raised; otherwise, processing will continue
42
+ * as normal. Defaults to false.
43
+ *
44
+ * @see canSendHeaders()
45
+ * @var boolean
46
+ */
47
+ public $headersSentThrowsException = false;
48
+
49
+
50
+ /**
51
+ * Magic __toString functionality
52
+ *
53
+ * @return string
54
+ */
55
+ public function __toString()
56
+ {
57
+ if ($this->isException() && $this->renderExceptions()) {
58
+ $exceptions = '';
59
+ foreach ($this->getException() as $e) {
60
+ $exceptions .= $e->__toString() . "\n";
61
+ }
62
+ return $exceptions;
63
+ }
64
+
65
+ return $this->_body;
66
+ }
67
+ }
lib/Zend/Controller/Response/Exception.php ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Zend Framework
4
+ *
5
+ * LICENSE
6
+ *
7
+ * This source file is subject to the new BSD license that is bundled
8
+ * with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://framework.zend.com/license/new-bsd
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@zend.com so we can send you a copy immediately.
14
+ *
15
+ * @package Zend_Controller
16
+ * @subpackage Request
17
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
18
+ * @license http://framework.zend.com/license/new-bsd New BSD License
19
+ */
20
+
21
+
22
+ /** Zend_Controller_Exception */
23
+ require_once 'Zend/Controller/Exception.php';
24
+
25
+
26
+ /**
27
+ * @package Zend_Controller
28
+ * @subpackage Response
29
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
30
+ * @license http://framework.zend.com/license/new-bsd New BSD License
31
+ */
32
+ class Zend_Controller_Response_Exception extends Zend_Controller_Exception
33
+ {}
34
+
lib/Zend/Controller/Response/Http.php ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Zend Framework
4
+ *
5
+ * LICENSE
6
+ *
7
+ * This source file is subject to the new BSD license that is bundled
8
+ * with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://framework.zend.com/license/new-bsd
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@zend.com so we can send you a copy immediately.
14
+ *
15
+ * @category Zend
16
+ * @package Zend_Controller
17
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
18
+ * @license http://framework.zend.com/license/new-bsd New BSD License
19
+ */
20
+
21
+
22
+ /** Zend_Controller_Response_Abstract */
23
+ require_once 'Zend/Controller/Response/Abstract.php';
24
+
25
+
26
+ /**
27
+ * Zend_Controller_Response_Http
28
+ *
29
+ * HTTP response for controllers
30
+ *
31
+ * @uses Zend_Controller_Response_Abstract
32
+ * @package Zend_Controller
33
+ * @subpackage Response
34
+ */
35
+ class Zend_Controller_Response_Http extends Zend_Controller_Response_Abstract
36
+ {
37
+ }
lib/Zend/Controller/Router/Abstract.php ADDED
@@ -0,0 +1,174 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Zend Framework
4
+ *
5
+ * LICENSE
6
+ *
7
+ * This source file is subject to the new BSD license that is bundled
8
+ * with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://framework.zend.com/license/new-bsd
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@zend.com so we can send you a copy immediately.
14
+ *
15
+ * @category Zend
16
+ * @package Zend_Controller
17
+ * @subpackage Router
18
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
19
+ * @license http://framework.zend.com/license/new-bsd New BSD License
20
+ */
21
+
22
+
23
+ /** Zend_Controller_Router_Interface */
24
+ require_once 'Zend/Controller/Router/Interface.php';
25
+
26
+ /**
27
+ * Simple first implementation of a router, to be replaced
28
+ * with rules-based URI processor.
29
+ *
30
+ * @category Zend
31
+ * @package Zend_Controller
32
+ * @subpackage Router
33
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
34
+ * @license http://framework.zend.com/license/new-bsd New BSD License
35
+ */
36
+ abstract class Zend_Controller_Router_Abstract implements Zend_Controller_Router_Interface
37
+ {
38
+ /**
39
+ * Front controller instance
40
+ * @var Zend_Controller_Front
41
+ */
42
+ protected $_frontController;
43
+
44
+ /**
45
+ * Array of invocation parameters to use when instantiating action
46
+ * controllers
47
+ * @var array
48
+ */
49
+ protected $_invokeParams = array();
50
+
51
+ /**
52
+ * Constructor
53
+ *
54
+ * @param array $params
55
+ * @return void
56
+ */
57
+ public function __construct(array $params = array())
58
+ {
59
+ $this->setParams($params);
60
+ }
61
+
62
+ /**
63
+ * Add or modify a parameter to use when instantiating an action controller
64
+ *
65
+ * @param string $name
66
+ * @param mixed $value
67
+ * @return Zend_Controller_Router
68
+ */
69
+ public function setParam($name, $value)
70
+ {
71
+ $name = (string) $name;
72
+ $this->_invokeParams[$name] = $value;
73
+ return $this;
74
+ }
75
+
76
+ /**
77
+ * Set parameters to pass to action controller constructors
78
+ *
79
+ * @param array $params
80
+ * @return Zend_Controller_Router
81
+ */
82
+ public function setParams(array $params)
83
+ {
84
+ $this->_invokeParams = array_merge($this->_invokeParams, $params);
85
+ return $this;
86
+ }
87
+
88
+ /**
89
+ * Retrieve a single parameter from the controller parameter stack
90
+ *
91
+ * @param string $name
92
+ * @return mixed
93
+ */
94
+ public function getParam($name)
95
+ {
96
+ if(isset($this->_invokeParams[$name])) {
97
+ return $this->_invokeParams[$name];
98
+ }
99
+
100
+ return null;
101
+ }
102
+
103
+ /**
104
+ * Retrieve action controller instantiation parameters
105
+ *
106
+ * @return array
107
+ */
108
+ public function getParams()
109
+ {
110
+ return $this->_invokeParams;
111
+ }
112
+
113
+ /**
114
+ * Clear the controller parameter stack
115
+ *
116
+ * By default, clears all parameters. If a parameter name is given, clears
117
+ * only that parameter; if an array of parameter names is provided, clears
118
+ * each.
119
+ *
120
+ * @param null|string|array single key or array of keys for params to clear
121
+ * @return Zend_Controller_Router
122
+ */
123
+ public function clearParams($name = null)
124
+ {
125
+ if (null === $name) {
126
+ $this->_invokeParams = array();
127
+ } elseif (is_string($name) && isset($this->_invokeParams[$name])) {
128
+ unset($this->_invokeParams[$name]);
129
+ } elseif (is_array($name)) {
130
+ foreach ($name as $key) {
131
+ if (is_string($key) && isset($this->_invokeParams[$key])) {
132
+ unset($this->_invokeParams[$key]);
133
+ }
134
+ }
135
+ }
136
+
137
+ return $this;
138
+ }
139
+
140
+ /**
141
+ * Retrieve Front Controller
142
+ *
143
+ * @return Zend_Controller_Front
144
+ */
145
+ public function getFrontController()
146
+ {
147
+ // Used cache version if found
148
+ if (null !== $this->_frontController) {
149
+ return $this->_frontController;
150
+ }
151
+
152
+ if (class_exists('Zend_Controller_Front', false)) {
153
+ require_once 'Zend/Controller/Front.php';
154
+ $this->_frontController = Zend_Controller_Front::getInstance();
155
+ return $this->_frontController;
156
+ }
157
+
158
+ // Throw exception in all other cases
159
+ require_once 'Zend/Controller/Router/Exception.php';
160
+ throw new Zend_Controller_Router_Exception('Front controller class has not been loaded');
161
+ }
162
+
163
+ /**
164
+ * Set Front Controller
165
+ *
166
+ * @param Zend_Controller_Front $controller
167
+ * @return Zend_Controller_Router_Abstract
168
+ */
169
+ public function setFrontController(Zend_Controller_Front $controller)
170
+ {
171
+ $this->_frontController = $controller;
172
+ return $this;
173
+ }
174
+ }
lib/Zend/Controller/Router/Exception.php ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Zend Framework
4
+ *
5
+ * LICENSE
6
+ *
7
+ * This source file is subject to the new BSD license that is bundled
8
+ * with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://framework.zend.com/license/new-bsd
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@zend.com so we can send you a copy immediately.
14
+ *
15
+ * @package Zend_Controller
16
+ * @subpackage Router
17
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
18
+ * @version $Id: Exception.php 8064 2008-02-16 10:58:39Z thomas $
19
+ * @license http://framework.zend.com/license/new-bsd New BSD License
20
+ */
21
+
22
+
23
+ /** Zend_Controller_Exception */
24
+ require_once 'Zend/Controller/Exception.php';
25
+
26
+
27
+ /**
28
+ * @package Zend_Controller
29
+ * @subpackage Router
30
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
31
+ * @license http://framework.zend.com/license/new-bsd New BSD License
32
+ */
33
+ class Zend_Controller_Router_Exception extends Zend_Controller_Exception
34
+ {}
35
+
lib/Zend/Controller/Router/Interface.php ADDED
@@ -0,0 +1,86 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Zend Framework
4
+ *
5
+ * LICENSE
6
+ *
7
+ * This source file is subject to the new BSD license that is bundled
8
+ * with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://framework.zend.com/license/new-bsd
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@zend.com so we can send you a copy immediately.
14
+ *
15
+ * @package Zend_Controller
16
+ * @subpackage Router
17
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
18
+ * @license http://framework.zend.com/license/new-bsd New BSD License
19
+ */
20
+
21
+
22
+ /** Zend_Controller_Request_Abstract */
23
+ require_once 'Zend/Controller/Request/Abstract.php';
24
+
25
+ /**
26
+ * @package Zend_Controller
27
+ * @subpackage Router
28
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
29
+ * @license http://framework.zend.com/license/new-bsd New BSD License
30
+ */
31
+ interface Zend_Controller_Router_Interface
32
+ {
33
+ /**
34
+ * Processes a request and sets its controller and action. If
35
+ * no route was possible, an exception is thrown.
36
+ *
37
+ * @param Zend_Controller_Request_Abstract
38
+ * @throws Zend_Controller_Router_Exception
39
+ * @return Zend_Controller_Request_Abstract|boolean
40
+ */
41
+ public function route(Zend_Controller_Request_Abstract $dispatcher);
42
+
43
+ /**
44
+ * Add or modify a parameter with which to instantiate any helper objects
45
+ *
46
+ * @param string $name
47
+ * @param mixed $param
48
+ * @return Zend_Controller_Router_Interface
49
+ */
50
+ public function setParam($name, $value);
51
+
52
+ /**
53
+ * Set an array of a parameters to pass to helper object constructors
54
+ *
55
+ * @param array $params
56
+ * @return Zend_Controller_Router_Interface
57
+ */
58
+ public function setParams(array $params);
59
+
60
+ /**
61
+ * Retrieve a single parameter from the controller parameter stack
62
+ *
63
+ * @param string $name
64
+ * @return mixed
65
+ */
66
+ public function getParam($name);
67
+
68
+ /**
69
+ * Retrieve the parameters to pass to helper object constructors
70
+ *
71
+ * @return array
72
+ */
73
+ public function getParams();
74
+
75
+ /**
76
+ * Clear the controller parameter stack
77
+ *
78
+ * By default, clears all parameters. If a parameter name is given, clears
79
+ * only that parameter; if an array of parameter names is provided, clears
80
+ * each.
81
+ *
82
+ * @param null|string|array single key or array of keys for params to clear
83
+ * @return Zend_Controller_Router_Interface
84
+ */
85
+ public function clearParams($name = null);
86
+ }
lib/Zend/Controller/Router/Rewrite.php ADDED
@@ -0,0 +1,293 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Zend Framework
4
+ *
5
+ * LICENSE
6
+ *
7
+ * This source file is subject to the new BSD license that is bundled
8
+ * with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://framework.zend.com/license/new-bsd
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@zend.com so we can send you a copy immediately.
14
+ *
15
+ * @package Zend_Controller
16
+ * @subpackage Router
17
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
18
+ * @version $Id: Rewrite.php 8064 2008-02-16 10:58:39Z thomas $
19
+ * @license http://framework.zend.com/license/new-bsd New BSD License
20
+ */
21
+
22
+ /** Zend_Loader */
23
+ require_once 'Zend/Loader.php';
24
+
25
+ /** Zend_Controller_Router_Abstract */
26
+ require_once 'Zend/Controller/Router/Abstract.php';
27
+
28
+ /** Zend_Controller_Router_Route */
29
+ require_once 'Zend/Controller/Router/Route.php';
30
+
31
+ /** Zend_Controller_Router_Route_Static */
32
+ require_once 'Zend/Controller/Router/Route/Static.php';
33
+
34
+ /**
35
+ * Ruby routing based Router.
36
+ *
37
+ * @package Zend_Controller
38
+ * @subpackage Router
39
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
40
+ * @license http://framework.zend.com/license/new-bsd New BSD License
41
+ * @see http://manuals.rubyonrails.com/read/chapter/65
42
+ */
43
+ class Zend_Controller_Router_Rewrite extends Zend_Controller_Router_Abstract
44
+ {
45
+ /**
46
+ * Whether or not to use default routes
47
+ * @var boolean
48
+ */
49
+ protected $_useDefaultRoutes = true;
50
+
51
+ /**
52
+ * Array of routes to match against
53
+ * @var array
54
+ */
55
+ protected $_routes = array();
56
+
57
+ /**
58
+ * Currently matched route
59
+ * @var Zend_Controller_Router_Route_Interface
60
+ */
61
+ protected $_currentRoute = null;
62
+
63
+ /**
64
+ * Add default routes which are used to mimic basic router behaviour
65
+ */
66
+ public function addDefaultRoutes()
67
+ {
68
+ if (!$this->hasRoute('default')) {
69
+
70
+ $dispatcher = $this->getFrontController()->getDispatcher();
71
+ $request = $this->getFrontController()->getRequest();
72
+
73
+ require_once 'Zend/Controller/Router/Route/Module.php';
74
+ $compat = new Zend_Controller_Router_Route_Module(array(), $dispatcher, $request);
75
+
76
+ $this->_routes = array_merge(array('default' => $compat), $this->_routes);
77
+ }
78
+ }
79
+
80
+ /**
81
+ * Add route to the route chain
82
+ *
83
+ * @param string $name Name of the route
84
+ * @param Zend_Controller_Router_Route_Interface Route
85
+ */
86
+ public function addRoute($name, Zend_Controller_Router_Route_Interface $route) {
87
+ $this->_routes[$name] = $route;
88
+ return $this;
89
+ }
90
+
91
+ /**
92
+ * Add routes to the route chain
93
+ *
94
+ * @param array $routes Array of routes with names as keys and routes as values
95
+ */
96
+ public function addRoutes($routes) {
97
+ foreach ($routes as $name => $route) {
98
+ $this->addRoute($name, $route);
99
+ }
100
+ return $this;
101
+ }
102
+
103
+ /**
104
+ * Create routes out of Zend_Config configuration
105
+ *
106
+ * Example INI:
107
+ * routes.archive.route = "archive/:year/*"
108
+ * routes.archive.defaults.controller = archive
109
+ * routes.archive.defaults.action = show
110
+ * routes.archive.defaults.year = 2000
111
+ * routes.archive.reqs.year = "\d+"
112
+ *
113
+ * routes.news.type = "Zend_Controller_Router_Route_Static"
114
+ * routes.news.route = "news"
115
+ * routes.news.defaults.controller = "news"
116
+ * routes.news.defaults.action = "list"
117
+ *
118
+ * And finally after you have created a Zend_Config with above ini:
119
+ * $router = new Zend_Controller_Router_Rewrite();
120
+ * $router->addConfig($config, 'routes');
121
+ *
122
+ * @param Zend_Config $config Configuration object
123
+ * @param string $section Name of the config section containing route's definitions
124
+ * @throws Zend_Controller_Router_Exception
125
+ */
126
+ public function addConfig(Zend_Config $config, $section = null)
127
+ {
128
+ if ($section !== null) {
129
+ if ($config->{$section} === null) {
130
+ require_once 'Zend/Controller/Router/Exception.php';
131
+ throw new Zend_Controller_Router_Exception("No route configuration in section '{$section}'");
132
+ }
133
+ $config = $config->{$section};
134
+ }
135
+
136
+ foreach ($config as $name => $info) {
137
+
138
+ $class = (isset($info->type)) ? $info->type : 'Zend_Controller_Router_Route';
139
+ Zend_Loader::loadClass($class);
140
+
141
+ $route = call_user_func(array($class, 'getInstance'), $info);
142
+ $this->addRoute($name, $route);
143
+ }
144
+
145
+ return $this;
146
+ }
147
+
148
+ /**
149
+ * Remove a route from the route chain
150
+ *
151
+ * @param string $name Name of the route
152
+ * @throws Zend_Controller_Router_Exception
153
+ */
154
+ public function removeRoute($name) {
155
+ if (!isset($this->_routes[$name])) {
156
+ require_once 'Zend/Controller/Router/Exception.php';
157
+ throw new Zend_Controller_Router_Exception("Route $name is not defined");
158
+ }
159
+ unset($this->_routes[$name]);
160
+ return $this;
161
+ }
162
+
163
+ /**
164
+ * Remove all standard default routes
165
+ *
166
+ * @param Zend_Controller_Router_Route_Interface Route
167
+ */
168
+ public function removeDefaultRoutes() {
169
+ $this->_useDefaultRoutes = false;
170
+ return $this;
171
+ }
172
+
173
+ /**
174
+ * Check if named route exists
175
+ *
176
+ * @param string $name Name of the route
177
+ * @return boolean
178
+ */
179
+ public function hasRoute($name)
180
+ {
181
+ return isset($this->_routes[$name]);
182
+ }
183
+
184
+ /**
185
+ * Retrieve a named route
186
+ *
187
+ * @param string $name Name of the route
188
+ * @throws Zend_Controller_Router_Exception
189
+ * @return Zend_Controller_Router_Route_Interface Route object
190
+ */
191
+ public function getRoute($name)
192
+ {
193
+ if (!isset($this->_routes[$name])) {
194
+ require_once 'Zend/Controller/Router/Exception.php';
195
+ throw new Zend_Controller_Router_Exception("Route $name is not defined");
196
+ }
197
+ return $this->_routes[$name];
198
+ }
199
+
200
+ /**
201
+ * Retrieve a currently matched route
202
+ *
203
+ * @throws Zend_Controller_Router_Exception
204
+ * @return Zend_Controller_Router_Route_Interface Route object
205
+ */
206
+ public function getCurrentRoute()
207
+ {
208
+ if (!isset($this->_currentRoute)) {
209
+ require_once 'Zend/Controller/Router/Exception.php';
210
+ throw new Zend_Controller_Router_Exception("Current route is not defined");
211
+ }
212
+ return $this->getRoute($this->_currentRoute);
213
+ }
214
+
215
+ /**
216
+ * Retrieve a name of currently matched route
217
+ *
218
+ * @throws Zend_Controller_Router_Exception
219
+ * @return Zend_Controller_Router_Route_Interface Route object
220
+ */
221
+ public function getCurrentRouteName()
222
+ {
223
+ if (!isset($this->_currentRoute)) {
224
+ require_once 'Zend/Controller/Router/Exception.php';
225
+ throw new Zend_Controller_Router_Exception("Current route is not defined");
226
+ }
227
+ return $this->_currentRoute;
228
+ }
229
+
230
+ /**
231
+ * Retrieve an array of routes added to the route chain
232
+ *
233
+ * @return array All of the defined routes
234
+ */
235
+ public function getRoutes()
236
+ {
237
+ return $this->_routes;
238
+ }
239
+
240
+ /**
241
+ * Find a matching route to the current PATH_INFO and inject
242
+ * returning values to the Request object.
243
+ *
244
+ * @throws Zend_Controller_Router_Exception
245
+ * @return Zend_Controller_Request_Abstract Request object
246
+ */
247
+ public function route(Zend_Controller_Request_Abstract $request)
248
+ {
249
+
250
+ if (!$request instanceof Zend_Controller_Request_Http) {
251
+ require_once 'Zend/Controller/Router/Exception.php';
252
+ throw new Zend_Controller_Router_Exception('Zend_Controller_Router_Rewrite requires a Zend_Controller_Request_Http-based request object');
253
+ }
254
+
255
+ if ($this->_useDefaultRoutes) {
256
+ $this->addDefaultRoutes();
257
+ }
258
+
259
+ $pathInfo = $request->getPathInfo();
260
+
261
+ /** Find the matching route */
262
+ foreach (array_reverse($this->_routes) as $name => $route) {
263
+ if ($params = $route->match($pathInfo)) {
264
+ $this->_setRequestParams($request, $params);
265
+ $this->_currentRoute = $name;
266
+ break;
267
+ }
268
+ }
269
+
270
+ return $request;
271
+
272
+ }
273
+
274
+ protected function _setRequestParams($request, $params)
275
+ {
276
+ foreach ($params as $param => $value) {
277
+
278
+ $request->setParam($param, $value);
279
+
280
+ if ($param === $request->getModuleKey()) {
281
+ $request->setModuleName($value);
282
+ }
283
+ if ($param === $request->getControllerKey()) {
284
+ $request->setControllerName($value);
285
+ }
286
+ if ($param === $request->getActionKey()) {
287
+ $request->setActionName($value);
288
+ }
289
+
290
+ }
291
+ }
292
+
293
+ }
lib/Zend/Controller/Router/Route.php ADDED
@@ -0,0 +1,291 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Zend Framework
4
+ *
5
+ * LICENSE
6
+ *
7
+ * This source file is subject to the new BSD license that is bundled
8
+ * with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://framework.zend.com/license/new-bsd
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@zend.com so we can send you a copy immediately.
14
+ *
15
+ * @package Zend_Controller
16
+ * @subpackage Router
17
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
18
+ * @version $Id: Route.php 8064 2008-02-16 10:58:39Z thomas $
19
+ * @license http://framework.zend.com/license/new-bsd New BSD License
20
+ */
21
+
22
+ /** Zend_Controller_Router_Route_Interface */
23
+ require_once 'Zend/Controller/Router/Route/Interface.php';
24
+
25
+ /**
26
+ * Route
27
+ *
28
+ * @package Zend_Controller
29
+ * @subpackage Router
30
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
31
+ * @license http://framework.zend.com/license/new-bsd New BSD License
32
+ * @see http://manuals.rubyonrails.com/read/chapter/65
33
+ */
34
+ class Zend_Controller_Router_Route implements Zend_Controller_Router_Route_Interface
35
+ {
36
+
37
+ protected $_urlVariable = ':';
38
+ protected $_urlDelimiter = '/';
39
+ protected $_regexDelimiter = '#';
40
+ protected $_defaultRegex = null;
41
+
42
+ protected $_parts;
43
+ protected $_defaults = array();
44
+ protected $_requirements = array();
45
+ protected $_staticCount = 0;
46
+ protected $_vars = array();
47
+ protected $_params = array();
48
+ protected $_values = array();
49
+
50
+ /**
51
+ * Instantiates route based on passed Zend_Config structure
52
+ *
53
+ * @param Zend_Config $config Configuration object
54
+ */
55
+ public static function getInstance(Zend_Config $config)
56
+ {
57
+ $reqs = ($config->reqs instanceof Zend_Config) ? $config->reqs->toArray() : array();
58
+ $defs = ($config->defaults instanceof Zend_Config) ? $config->defaults->toArray() : array();
59
+ return new self($config->route, $defs, $reqs);
60
+ }
61
+
62
+ /**
63
+ * Prepares the route for mapping by splitting (exploding) it
64
+ * to a corresponding atomic parts. These parts are assigned
65
+ * a position which is later used for matching and preparing values.
66
+ *
67
+ * @param string $route Map used to match with later submitted URL path
68
+ * @param array $defaults Defaults for map variables with keys as variable names
69
+ * @param array $reqs Regular expression requirements for variables (keys as variable names)
70
+ */
71
+ public function __construct($route, $defaults = array(), $reqs = array())
72
+ {
73
+
74
+ $route = trim($route, $this->_urlDelimiter);
75
+ $this->_defaults = (array) $defaults;
76
+ $this->_requirements = (array) $reqs;
77
+
78
+ if ($route != '') {
79
+
80
+ foreach (explode($this->_urlDelimiter, $route) as $pos => $part) {
81
+
82
+ if (substr($part, 0, 1) == $this->_urlVariable) {
83
+ $name = substr($part, 1);
84
+ $regex = (isset($reqs[$name]) ? $reqs[$name] : $this->_defaultRegex);
85
+ $this->_parts[$pos] = array('name' => $name, 'regex' => $regex);
86
+ $this->_vars[] = $name;
87
+ } else {
88
+ $this->_parts[$pos] = array('regex' => $part);
89
+ if ($part != '*') {
90
+ $this->_staticCount++;
91
+ }
92
+ }
93
+
94
+ }
95
+
96
+ }
97
+
98
+ }
99
+
100
+ protected function _getWildcardData($parts, $unique)
101
+ {
102
+ $pos = count($parts);
103
+ if ($pos % 2) {
104
+ $parts[] = null;
105
+ }
106
+ foreach(array_chunk($parts, 2) as $part) {
107
+ list($var, $value) = $part;
108
+ $var = urldecode($var);
109
+ if (!array_key_exists($var, $unique)) {
110
+ $this->_params[$var] = urldecode($value);
111
+ $unique[$var] = true;
112
+ }
113
+ }
114
+ }
115
+
116
+ /**
117
+ * Matches a user submitted path with parts defined by a map. Assigns and
118
+ * returns an array of variables on a successful match.
119
+ *
120
+ * @param string $path Path used to match against this routing map
121
+ * @return array|false An array of assigned values or a false on a mismatch
122
+ */
123
+ public function match($path)
124
+ {
125
+
126
+ $pathStaticCount = 0;
127
+ $defaults = $this->_defaults;
128
+
129
+ if (count($defaults)) {
130
+ $unique = array_combine(array_keys($defaults), array_fill(0, count($defaults), true));
131
+ } else {
132
+ $unique = array();
133
+ }
134
+
135
+ $path = trim($path, $this->_urlDelimiter);
136
+
137
+ if ($path != '') {
138
+
139
+ $path = explode($this->_urlDelimiter, $path);
140
+
141
+ foreach ($path as $pos => $pathPart) {
142
+
143
+ if (!isset($this->_parts[$pos])) {
144
+ return false;
145
+ }
146
+
147
+ if ($this->_parts[$pos]['regex'] == '*') {
148
+ $parts = array_slice($path, $pos);
149
+ $this->_getWildcardData($parts, $unique);
150
+ break;
151
+ }
152
+
153
+ $part = $this->_parts[$pos];
154
+ $name = isset($part['name']) ? $part['name'] : null;
155
+ $pathPart = urldecode($pathPart);
156
+
157
+ if ($name === null) {
158
+ if ($part['regex'] != $pathPart) {
159
+ return false;
160
+ }
161
+ } elseif ($part['regex'] === null) {
162
+ if (strlen($pathPart) == 0) {
163
+ return false;
164
+ }
165
+ } else {
166
+ $regex = $this->_regexDelimiter . '^' . $part['regex'] . '$' . $this->_regexDelimiter . 'iu';
167
+ if (!preg_match($regex, $pathPart)) {
168
+ return false;
169
+ }
170
+ }
171
+
172
+ if ($name !== null) {
173
+ // It's a variable. Setting a value
174
+ $this->_values[$name] = $pathPart;
175
+ $unique[$name] = true;
176
+ } else {
177
+ $pathStaticCount++;
178
+ }
179
+
180
+ }
181
+
182
+ }
183
+
184
+ $return = $this->_values + $this->_params + $this->_defaults;
185
+
186
+ // Check if all static mappings have been met
187
+ if ($this->_staticCount != $pathStaticCount) {
188
+ return false;
189
+ }
190
+
191
+ // Check if all map variables have been initialized
192
+ foreach ($this->_vars as $var) {
193
+ if (!array_key_exists($var, $return)) {
194
+ return false;
195
+ }
196
+ }
197
+
198
+ return $return;
199
+
200
+ }
201
+
202
+ /**
203
+ * Assembles user submitted parameters forming a URL path defined by this route
204
+ *
205
+ * @param array $data An array of variable and value pairs used as parameters
206
+ * @param boolean $reset Whether or not to set route defaults with those provided in $data
207
+ * @return string Route path with user submitted parameters
208
+ */
209
+ public function assemble($data = array(), $reset = false)
210
+ {
211
+
212
+ $url = array();
213
+ $flag = false;
214
+
215
+ foreach ($this->_parts as $key => $part) {
216
+
217
+ $resetPart = false;
218
+ if (isset($part['name']) && array_key_exists($part['name'], $data) && $data[$part['name']] === null) {
219
+ $resetPart = true;
220
+ }
221
+
222
+ if (isset($part['name'])) {
223
+
224
+ if (isset($data[$part['name']]) && !$resetPart) {
225
+ $url[$key] = $data[$part['name']];
226
+ unset($data[$part['name']]);
227
+ } elseif (!$reset && !$resetPart && isset($this->_values[$part['name']])) {
228
+ $url[$key] = $this->_values[$part['name']];
229
+ } elseif (!$reset && !$resetPart && isset($this->_params[$part['name']])) {
230
+ $url[$key] = $this->_params[$part['name']];
231
+ } elseif (isset($this->_defaults[$part['name']])) {
232
+ $url[$key] = $this->_defaults[$part['name']];
233
+ } else {
234
+ require_once 'Zend/Controller/Router/Exception.php';
235
+ throw new Zend_Controller_Router_Exception($part['name'] . ' is not specified');
236
+ }
237
+
238
+ } else {
239
+
240
+ if ($part['regex'] != '*') {
241
+ $url[$key] = $part['regex'];
242
+ } else {
243
+ if (!$reset) $data += $this->_params;
244
+ foreach ($data as $var => $value) {
245
+ if ($value !== null) {
246
+ $url[$var] = $var . $this->_urlDelimiter . $value;
247
+ $flag = true;
248
+ }
249
+ }
250
+ }
251
+
252
+ }
253
+
254
+ }
255
+
256
+ $return = '';
257
+
258
+ foreach (array_reverse($url, true) as $key => $value) {
259
+ if ($flag || !isset($this->_parts[$key]['name']) || $value !== $this->getDefault($this->_parts[$key]['name'])) {
260
+ $return = $this->_urlDelimiter . $value . $return;
261
+ $flag = true;
262
+ }
263
+ }
264
+
265
+ return trim($return, $this->_urlDelimiter);
266
+
267
+ }
268
+
269
+ /**
270
+ * Return a single parameter of route's defaults
271
+ *
272
+ * @param string $name Array key of the parameter
273
+ * @return string Previously set default
274
+ */
275
+ public function getDefault($name) {
276
+ if (isset($this->_defaults[$name])) {
277
+ return $this->_defaults[$name];
278
+ }
279
+ return null;
280
+ }
281
+
282
+ /**
283
+ * Return an array of defaults
284
+ *
285
+ * @return array Route defaults
286
+ */
287
+ public function getDefaults() {
288
+ return $this->_defaults;
289
+ }
290
+
291
+ }
lib/Zend/Controller/Router/Route/Interface.php ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Zend Framework
4
+ *
5
+ * LICENSE
6
+ *
7
+ * This source file is subject to the new BSD license that is bundled
8
+ * with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://framework.zend.com/license/new-bsd
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@zend.com so we can send you a copy immediately.
14
+ *
15
+ * @package Zend_Controller
16
+ * @subpackage Router
17
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
18
+ * @version $Id: Interface.php 8064 2008-02-16 10:58:39Z thomas $
19
+ * @license http://framework.zend.com/license/new-bsd New BSD License
20
+ */
21
+
22
+ /** Zend_Config */
23
+ require_once 'Zend/Config.php';
24
+
25
+ /**
26
+ * @package Zend_Controller
27
+ * @subpackage Router
28
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
29
+ * @license http://framework.zend.com/license/new-bsd New BSD License
30
+ */
31
+ interface Zend_Controller_Router_Route_Interface {
32
+ public function match($path);
33
+ public function assemble($data = array());
34
+ public static function getInstance(Zend_Config $config);
35
+ }
36
+
lib/Zend/Controller/Router/Route/Module.php ADDED
@@ -0,0 +1,264 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Zend Framework
4
+ *
5
+ * LICENSE
6
+ *
7
+ * This source file is subject to the new BSD license that is bundled
8
+ * with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://framework.zend.com/license/new-bsd
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@zend.com so we can send you a copy immediately.
14
+ *
15
+ * @package Zend_Controller
16
+ * @subpackage Router
17
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
18
+ * @version $Id: Module.php 8892 2008-03-18 19:47:46Z thomas $
19
+ * @license http://framework.zend.com/license/new-bsd New BSD License
20
+ */
21
+
22
+ /** Zend_Controller_Router_Route_Interface */
23
+ require_once 'Zend/Controller/Router/Route/Interface.php';
24
+
25
+ /** Zend_Controller_Dispatcher_Interface */
26
+ require_once 'Zend/Controller/Dispatcher/Interface.php';
27
+
28
+ /** Zend_Controller_Request_Abstract */
29
+ require_once 'Zend/Controller/Request/Abstract.php';
30
+
31
+ /**
32
+ * Module Route
33
+ *
34
+ * Default route for module functionality
35
+ *
36
+ * @package Zend_Controller
37
+ * @subpackage Router
38
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
39
+ * @license http://framework.zend.com/license/new-bsd New BSD License
40
+ * @see http://manuals.rubyonrails.com/read/chapter/65
41
+ */
42
+ class Zend_Controller_Router_Route_Module implements Zend_Controller_Router_Route_Interface
43
+ {
44
+ /**
45
+ * URI delimiter
46
+ */
47
+ const URI_DELIMITER = '/';
48
+
49
+ /**
50
+ * Default values for the route (ie. module, controller, action, params)
51
+ * @var array
52
+ */
53
+ protected $_defaults;
54
+
55
+ protected $_values = array();
56
+ protected $_moduleValid = false;
57
+ protected $_keysSet = false;
58
+
59
+ /**#@+
60
+ * Array keys to use for module, controller, and action. Should be taken out of request.
61
+ * @var string
62
+ */
63
+ protected $_moduleKey = 'module';
64
+ protected $_controllerKey = 'controller';
65
+ protected $_actionKey = 'action';
66
+ /**#@-*/
67
+
68
+ /**
69
+ * @var Zend_Controller_Dispatcher_Interface
70
+ */
71
+ protected $_dispatcher;
72
+
73
+ /**
74
+ * @var Zend_Controller_Request_Abstract
75
+ */
76
+ protected $_request;
77
+
78
+ /**
79
+ * Instantiates route based on passed Zend_Config structure
80
+ */
81
+ public static function getInstance(Zend_Config $config)
82
+ {
83
+ $defs = ($config->defaults instanceof Zend_Config) ? $config->defaults->toArray() : array();
84
+ return new self($defs);
85
+ }
86
+
87
+ /**
88
+ * Constructor
89
+ *
90
+ * @param array $defaults Defaults for map variables with keys as variable names
91
+ * @param Zend_Controller_Dispatcher_Interface $dispatcher Dispatcher object
92
+ * @param Zend_Controller_Request_Abstract $request Request object
93
+ */
94
+ public function __construct(array $defaults = array(),
95
+ Zend_Controller_Dispatcher_Interface $dispatcher = null,
96
+ Zend_Controller_Request_Abstract $request = null)
97
+ {
98
+ $this->_defaults = $defaults;
99
+
100
+ if (isset($request)) {
101
+ $this->_request = $request;
102
+ }
103
+
104
+ if (isset($dispatcher)) {
105
+ $this->_dispatcher = $dispatcher;
106
+ }
107
+ }
108
+
109
+ /**
110
+ * Set request keys based on values in request object
111
+ *
112
+ * @return void
113
+ */
114
+ protected function _setRequestKeys()
115
+ {
116
+ if (null !== $this->_request) {
117
+ $this->_moduleKey = $this->_request->getModuleKey();
118
+ $this->_controllerKey = $this->_request->getControllerKey();
119
+ $this->_actionKey = $this->_request->getActionKey();
120
+ }
121
+
122
+ if (null !== $this->_dispatcher) {
123
+ $this->_defaults += array(
124
+ $this->_controllerKey => $this->_dispatcher->getDefaultControllerName(),
125
+ $this->_actionKey => $this->_dispatcher->getDefaultAction(),
126
+ $this->_moduleKey => $this->_dispatcher->getDefaultModule()
127
+ );
128
+ }
129
+
130
+ $this->_keysSet = true;
131
+ }
132
+
133
+ /**
134
+ * Matches a user submitted path. Assigns and returns an array of variables
135
+ * on a successful match.
136
+ *
137
+ * If a request object is registered, it uses its setModuleName(),
138
+ * setControllerName(), and setActionName() accessors to set those values.
139
+ * Always returns the values as an array.
140
+ *
141
+ * @param string $path Path used to match against this routing map
142
+ * @return array An array of assigned values or a false on a mismatch
143
+ */
144
+ public function match($path)
145
+ {
146
+ $this->_setRequestKeys();
147
+
148
+ $values = array();
149
+ $params = array();
150
+ $path = trim($path, self::URI_DELIMITER);
151
+
152
+ if ($path != '') {
153
+
154
+ $path = explode(self::URI_DELIMITER, $path);
155
+
156
+ if ($this->_dispatcher && $this->_dispatcher->isValidModule($path[0])) {
157
+ $values[$this->_moduleKey] = array_shift($path);
158
+ $this->_moduleValid = true;
159
+ }
160
+
161
+ if (count($path) && !empty($path[0])) {
162
+ $values[$this->_controllerKey] = array_shift($path);
163
+ }
164
+
165
+ if (count($path) && !empty($path[0])) {
166
+ $values[$this->_actionKey] = array_shift($path);
167
+ }
168
+
169
+ if ($numSegs = count($path)) {
170
+ for ($i = 0; $i < $numSegs; $i = $i + 2) {
171
+ $key = urldecode($path[$i]);
172
+ $val = isset($path[$i + 1]) ? urldecode($path[$i + 1]) : null;
173
+ $params[$key] = $val;
174
+ }
175
+ }
176
+ }
177
+
178
+ $this->_values = $values + $params;
179
+
180
+ return $this->_values + $this->_defaults;
181
+ }
182
+
183
+ /**
184
+ * Assembles user submitted parameters forming a URL path defined by this route
185
+ *
186
+ * @param array $data An array of variable and value pairs used as parameters
187
+ * @param bool $reset Weither to reset the current params
188
+ * @return string Route path with user submitted parameters
189
+ */
190
+ public function assemble($data = array(), $reset = false)
191
+ {
192
+ if (!$this->_keysSet) {
193
+ $this->_setRequestKeys();
194
+ }
195
+
196
+ $params = (!$reset) ? $this->_values : array();
197
+
198
+ foreach ($data as $key => $value) {
199
+ if ($value !== null) {
200
+ $params[$key] = $value;
201
+ } elseif (isset($params[$key])) {
202
+ unset($params[$key]);
203
+ }
204
+ }
205
+
206
+ $params += $this->_defaults;
207
+
208
+ $url = '';
209
+
210
+ if ($this->_moduleValid || array_key_exists($this->_moduleKey, $data)) {
211
+ if ($params[$this->_moduleKey] != $this->_defaults[$this->_moduleKey]) {
212
+ $module = $params[$this->_moduleKey];
213
+ }
214
+ }
215
+ unset($params[$this->_moduleKey]);
216
+
217
+ $controller = $params[$this->_controllerKey];
218
+ unset($params[$this->_controllerKey]);
219
+
220
+ $action = $params[$this->_actionKey];
221
+ unset($params[$this->_actionKey]);
222
+
223
+ foreach ($params as $key => $value) {
224
+ $url .= '/' . $key;
225
+ $url .= '/' . $value;
226
+ }
227
+
228
+ if (!empty($url) || $action !== $this->_defaults[$this->_actionKey]) {
229
+ $url = '/' . $action . $url;
230
+ }
231
+
232
+ if (!empty($url) || $controller !== $this->_defaults[$this->_controllerKey]) {
233
+ $url = '/' . $controller . $url;
234
+ }
235
+
236
+ if (isset($module)) {
237
+ $url = '/' . $module . $url;
238
+ }
239
+
240
+ return ltrim($url, self::URI_DELIMITER);
241
+ }
242
+
243
+ /**
244
+ * Return a single parameter of route's defaults
245
+ *
246
+ * @param string $name Array key of the parameter
247
+ * @return string Previously set default
248
+ */
249
+ public function getDefault($name) {
250
+ if (isset($this->_defaults[$name])) {
251
+ return $this->_defaults[$name];
252
+ }
253
+ }
254
+
255
+ /**
256
+ * Return an array of defaults
257
+ *
258
+ * @return array Route defaults
259
+ */
260
+ public function getDefaults() {
261
+ return $this->_defaults;
262
+ }
263
+
264
+ }
lib/Zend/Controller/Router/Route/Regex.php ADDED
@@ -0,0 +1,220 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Zend Framework
4
+ *
5
+ * LICENSE
6
+ *
7
+ * This source file is subject to the new BSD license that is bundled
8
+ * with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://framework.zend.com/license/new-bsd
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@zend.com so we can send you a copy immediately.
14
+ *
15
+ * @package Zend_Controller
16
+ * @subpackage Router
17
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
18
+ * @version $Id: Regex.php 8933 2008-03-20 20:54:58Z darby $
19
+ * @license http://framework.zend.com/license/new-bsd New BSD License
20
+ */
21
+
22
+ /** Zend_Controller_Router_Route_Interface */
23
+ require_once 'Zend/Controller/Router/Route/Interface.php';
24
+
25
+ /**
26
+ * Regex Route
27
+ *
28
+ * @package Zend_Controller
29
+ * @subpackage Router
30
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
31
+ * @license http://framework.zend.com/license/new-bsd New BSD License
32
+ */
33
+ class Zend_Controller_Router_Route_Regex implements Zend_Controller_Router_Route_Interface
34
+ {
35
+ protected $_regex = null;
36
+ protected $_defaults = array();
37
+ protected $_reverse = null;
38
+ protected $_map = array();
39
+ protected $_values = array();
40
+
41
+ /**
42
+ * Instantiates route based on passed Zend_Config structure
43
+ *
44
+ * @param Zend_Config $config Configuration object
45
+ */
46
+ public static function getInstance(Zend_Config $config)
47
+ {
48
+ $defs = ($config->defaults instanceof Zend_Config) ? $config->defaults->toArray() : array();
49
+ $map = ($config->map instanceof Zend_Config) ? $config->map->toArray() : array();
50
+ $reverse = (isset($config->reverse)) ? $config->reverse : null;
51
+ return new self($config->route, $defs, $map, $reverse);
52
+ }
53
+
54
+ public function __construct($route, $defaults = array(), $map = array(), $reverse = null)
55
+ {
56
+ $this->_regex = '#^' . $route . '$#i';
57
+ $this->_defaults = (array) $defaults;
58
+ $this->_map = (array) $map;
59
+ $this->_reverse = $reverse;
60
+ }
61
+
62
+ /**
63
+ * Matches a user submitted path with a previously defined route.
64
+ * Assigns and returns an array of defaults on a successful match.
65
+ *
66
+ * @param string $path Path used to match against this routing map
67
+ * @return array|false An array of assigned values or a false on a mismatch
68
+ */
69
+ public function match($path)
70
+ {
71
+ $path = trim(urldecode($path), '/');
72
+ $res = preg_match($this->_regex, $path, $values);
73
+
74
+ if ($res === 0) return false;
75
+
76
+ // array_filter_key()? Why isn't this in a standard PHP function set yet? :)
77
+ foreach ($values as $i => $value) {
78
+ if (!is_int($i) || $i === 0) {
79
+ unset($values[$i]);
80
+ }
81
+ }
82
+
83
+ $this->_values = $values;
84
+
85
+ $values = $this->_getMappedValues($values);
86
+ $defaults = $this->_getMappedValues($this->_defaults, false, true);
87
+
88
+ $return = $values + $defaults;
89
+
90
+ return $return;
91
+ }
92
+
93
+ /**
94
+ * Maps numerically indexed array values to it's associative mapped counterpart.
95
+ * Or vice versa. Uses user provided map array which consists of index => name
96
+ * parameter mapping. If map is not found, it returns original array.
97
+ *
98
+ * Method strips destination type of keys form source array. Ie. if source array is
99
+ * indexed numerically then every associative key will be stripped. Vice versa if reversed
100
+ * is set to true.
101
+ *
102
+ * @param array $values Indexed or associative array of values to map
103
+ * @param boolean $reversed False means translation of index to association. True means reverse.
104
+ * @param boolean $preserve Should wrong type of keys be preserved or stripped.
105
+ * @return array An array of mapped values
106
+ */
107
+ protected function _getMappedValues($values, $reversed = false, $preserve = false)
108
+ {
109
+ if (count($this->_map) == 0) {
110
+ return $values;
111
+ }
112
+
113
+ $return = array();
114
+
115
+ foreach ($values as $key => $value) {
116
+ if (is_int($key) && !$reversed) {
117
+ if (array_key_exists($key, $this->_map)) {
118
+ $index = $this->_map[$key];
119
+ } elseif (false === ($index = array_search($key, $this->_map))) {
120
+ $index = $key;
121
+ }
122
+ $return[$index] = $values[$key];
123
+ } elseif ($reversed) {
124
+ $index = (!is_int($key)) ? array_search($key, $this->_map, true) : $key;
125
+ if (false !== $index) {
126
+ $return[$index] = $values[$key];
127
+ }
128
+ } elseif ($preserve) {
129
+ $return[$key] = $value;
130
+ }
131
+ }
132
+
133
+ return $return;
134
+ }
135
+
136
+ /**
137
+ * Assembles a URL path defined by this route
138
+ *
139
+ * @param array $data An array of name (or index) and value pairs used as parameters
140
+ * @return string Route path with user submitted parameters
141
+ */
142
+ public function assemble($data = array())
143
+ {
144
+ if ($this->_reverse === null) {
145
+ require_once 'Zend/Controller/Router/Exception.php';
146
+ throw new Zend_Controller_Router_Exception('Cannot assemble. Reversed route is not specified.');
147
+ }
148
+
149
+ $defaultValuesMapped = $this->_getMappedValues($this->_defaults, true, false);
150
+ $matchedValuesMapped = $this->_getMappedValues($this->_values, true, false);
151
+ $dataValuesMapped = $this->_getMappedValues($data, true, false);
152
+
153
+ // handle resets, if so requested (By null value) to do so
154
+ if (($resetKeys = array_search(null, $dataValuesMapped, true)) !== false) {
155
+ foreach ((array) $resetKeys as $resetKey) {
156
+ if (isset($matchedValuesMapped[$resetKey])) {
157
+ unset($matchedValuesMapped[$resetKey]);
158
+ unset($dataValuesMapped[$resetKey]);
159
+ }
160
+ }
161
+ }
162
+
163
+ // merge all the data together, first defaults, then values matched, then supplied
164
+ $mergedData = $defaultValuesMapped;
165
+ $mergedData = $this->_arrayMergeNumericKeys($mergedData, $matchedValuesMapped);
166
+ $mergedData = $this->_arrayMergeNumericKeys($mergedData, $dataValuesMapped);
167
+
168
+ ksort($mergedData);
169
+
170
+ $return = @vsprintf($this->_reverse, $mergedData);
171
+
172
+ if ($return === false) {
173
+ require_once 'Zend/Controller/Router/Exception.php';
174
+ throw new Zend_Controller_Router_Exception('Cannot assemble. Too few arguments?');
175
+ }
176
+
177
+ return $return;
178
+
179
+ }
180
+
181
+ /**
182
+ * Return a single parameter of route's defaults
183
+ *
184
+ * @param string $name Array key of the parameter
185
+ * @return string Previously set default
186
+ */
187
+ public function getDefault($name) {
188
+ if (isset($this->_defaults[$name])) {
189
+ return $this->_defaults[$name];
190
+ }
191
+ }
192
+
193
+ /**
194
+ * Return an array of defaults
195
+ *
196
+ * @return array Route defaults
197
+ */
198
+ public function getDefaults() {
199
+ return $this->_defaults;
200
+ }
201
+
202
+ /**
203
+ * _arrayMergeNumericKeys() - allows for a strict key (numeric's included) array_merge.
204
+ * php's array_merge() lacks the ability to merge with numeric keys.
205
+ *
206
+ * @param array $array1
207
+ * @param array $array2
208
+ * @return array
209
+ */
210
+ protected function _arrayMergeNumericKeys(Array $array1, Array $array2)
211
+ {
212
+ $returnArray = $array1;
213
+ foreach ($array2 as $array2Index => $array2Value) {
214
+ $returnArray[$array2Index] = $array2Value;
215
+ }
216
+ return $returnArray;
217
+ }
218
+
219
+
220
+ }
lib/Zend/Controller/Router/Route/Static.php ADDED
@@ -0,0 +1,112 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Zend Framework
4
+ *
5
+ * LICENSE
6
+ *
7
+ * This source file is subject to the new BSD license that is bundled
8
+ * with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://framework.zend.com/license/new-bsd
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@zend.com so we can send you a copy immediately.
14
+ *
15
+ * @package Zend_Controller
16
+ * @subpackage Router
17
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
18
+ * @version $Id: Route.php 1847 2006-11-23 11:36:41Z martel $
19
+ * @license http://framework.zend.com/license/new-bsd New BSD License
20
+ */
21
+
22
+ /** Zend_Controller_Router_Route_Interface */
23
+ require_once 'Zend/Controller/Router/Route/Interface.php';
24
+
25
+ /**
26
+ * StaticRoute is used for managing static URIs.
27
+ *
28
+ * It's a lot faster compared to the standard Route implementation.
29
+ *
30
+ * @package Zend_Controller
31
+ * @subpackage Router
32
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
33
+ * @license http://framework.zend.com/license/new-bsd New BSD License
34
+ */
35
+ class Zend_Controller_Router_Route_Static implements Zend_Controller_Router_Route_Interface
36
+ {
37
+
38
+ protected $_route = null;
39
+ protected $_defaults = array();
40
+
41
+ /**
42
+ * Instantiates route based on passed Zend_Config structure
43
+ *
44
+ * @param Zend_Config $config Configuration object
45
+ */
46
+ public static function getInstance(Zend_Config $config)
47
+ {
48
+ $defs = ($config->defaults instanceof Zend_Config) ? $config->defaults->toArray() : array();
49
+ return new self($config->route, $defs);
50
+ }
51
+
52
+ /**
53
+ * Prepares the route for mapping.
54
+ *
55
+ * @param string $route Map used to match with later submitted URL path
56
+ * @param array $defaults Defaults for map variables with keys as variable names
57
+ */
58
+ public function __construct($route, $defaults = array())
59
+ {
60
+ $this->_route = trim($route, '/');
61
+ $this->_defaults = (array) $defaults;
62
+ }
63
+
64
+ /**
65
+ * Matches a user submitted path with a previously defined route.
66
+ * Assigns and returns an array of defaults on a successful match.
67
+ *
68
+ * @param string $path Path used to match against this routing map
69
+ * @return array|false An array of assigned values or a false on a mismatch
70
+ */
71
+ public function match($path)
72
+ {
73
+ if (trim($path, '/') == $this->_route) {
74
+ return $this->_defaults;
75
+ }
76
+ return false;
77
+ }
78
+
79
+ /**
80
+ * Assembles a URL path defined by this route
81
+ *
82
+ * @param array $data An array of variable and value pairs used as parameters
83
+ * @return string Route path with user submitted parameters
84
+ */
85
+ public function assemble($data = array())
86
+ {
87
+ return $this->_route;
88
+ }
89
+
90
+ /**
91
+ * Return a single parameter of route's defaults
92
+ *
93
+ * @param string $name Array key of the parameter
94
+ * @return string Previously set default
95
+ */
96
+ public function getDefault($name) {
97
+ if (isset($this->_defaults[$name])) {
98
+ return $this->_defaults[$name];
99
+ }
100
+ return null;
101
+ }
102
+
103
+ /**
104
+ * Return an array of defaults
105
+ *
106
+ * @return array Route defaults
107
+ */
108
+ public function getDefaults() {
109
+ return $this->_defaults;
110
+ }
111
+
112
+ }
lib/Zend/Currency.php ADDED
@@ -0,0 +1,525 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Zend Framework
4
+ *
5
+ * LICENSE
6
+ *
7
+ * This source file is subject to the new BSD license that is bundled
8
+ * with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://framework.zend.com/license/new-bsd
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@zend.com so we can send you a copy immediately.
14
+ *
15
+ * @category Zend
16
+ * @package Zend_Currency
17
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
18
+ * @version $Id: Currency.php 6137 2007-08-19 14:55:27Z shreef $
19
+ * @license http://framework.zend.com/license/new-bsd New BSD License
20
+ */
21
+
22
+
23
+ /**
24
+ * include needed classes
25
+ */
26
+ require_once 'Zend/Locale.php';
27
+ require_once 'Zend/Locale/Data.php';
28
+ require_once 'Zend/Locale/Format.php';
29
+
30
+
31
+ /**
32
+ * @category Zend
33
+ * @package Zend_Currency
34
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
35
+ * @license http://framework.zend.com/license/new-bsd New BSD License
36
+ */
37
+ class Zend_Currency
38
+ {
39
+ // constants for defining what currency symbol should be displayed
40
+ const NO_SYMBOL = 1;
41
+ const USE_SYMBOL = 2;
42
+ const USE_SHORTNAME = 3;
43
+ const USE_NAME = 4;
44
+
45
+ // constants for defining the position of the currencysign
46
+ const STANDARD = 8;
47
+ const RIGHT = 16;
48
+ const LEFT = 32;
49
+
50
+ /**
51
+ * locale for this currency
52
+ *
53
+ * @var string
54
+ */
55
+ private $_locale = null;
56
+
57
+ protected $_options = array(
58
+ 'position' => self::STANDARD, // position for the currency sign
59
+ 'script' => null, // script for output
60
+ 'format' => null, // locale for numeric output
61
+ 'display' => self::NO_SYMBOL, // currency detail to show
62
+ 'precision' => 2, // precision for currency
63
+ 'name' => null, // name for this currency
64
+ 'currency' => null, // 3 lettered international abbreviation
65
+ 'symbol' => null // currency symbol
66
+ );
67
+
68
+ /**
69
+ * Creates a currency instance. Every supressed parameter is used from the actual or the given locale.
70
+ *
71
+ * @param string $currency OPTIONAL currency short name
72
+ * @param string|Zend_Locale $locale OPTIONAL locale name
73
+ * @return Zend_Currency
74
+ * @throws Zend_Currency_Exception
75
+ */
76
+ public function __construct($currency = null, $locale = null)
77
+ {
78
+ if (Zend_Locale::isLocale($currency)) {
79
+ $temp = $locale;
80
+ $locale = $currency;
81
+ $currency = $temp;
82
+ }
83
+
84
+ $this->setLocale($locale);
85
+
86
+ // get currency details
87
+ $this->_options['currency'] = self::getShortName($currency, $this->_locale);
88
+ $this->_options['name'] = self::getName ($currency, $this->_locale);
89
+ $this->_options['symbol'] = self::getSymbol ($currency, $this->_locale);
90
+
91
+ if (($this->_options['currency'] === null) and ($this->_options['name'] === null)) {
92
+ require_once 'Zend/Currency/Exception.php';
93
+ throw new Zend_Currency_Exception("Currency '$currency' not found");
94
+ }
95
+ // get the format
96
+ $this->_options['position'] = $this->_updateFormat();
97
+ $this->_options['display'] = self::NO_SYMBOL;
98
+ if (!empty($this->_options['symbol'])) {
99
+ $this->_options['display'] = self::USE_SYMBOL;
100
+ } else if (!empty($this->_options['currency'])) {
101
+ $this->_options['display'] = self::USE_SHORTNAME;
102
+ }
103
+ return $this;
104
+ }
105
+
106
+
107
+ /**
108
+ * Gets the information required for formating the currency from Zend_Locale
109
+ *
110
+ * @return Zend_Currency
111
+ * @throws Zend_Currency_Exception
112
+ */
113
+ protected function _updateFormat()
114
+ {
115
+ $locale = empty($this->_options['format']) ? $this->_locale : $this->_options['format'];
116
+
117
+ //getting the format information of the currency
118
+ $format = Zend_Locale_Data::getContent($locale, 'currencynumber');
119
+
120
+ iconv_set_encoding('internal_encoding', 'UTF-8');
121
+ if (iconv_strpos($format, ';')) {
122
+ $format = iconv_substr($format, 0, iconv_strpos($format, ';'));
123
+ }
124
+
125
+ //knowing the sign positioning information
126
+ if (iconv_strpos($format, '¤') == 0) {
127
+ $position = self::LEFT;
128
+ } else if (iconv_strpos($format, '¤') == iconv_strlen($format)-1) {
129
+ $position = self::RIGHT;
130
+ }
131
+
132
+ return $position;
133
+ }
134
+
135
+
136
+ /**
137
+ * Returns a localized currency string
138
+ *
139
+ * @param int|float $value Currency value
140
+ * @param array $options OPTIONAL options to set temporary
141
+ * @return string
142
+ */
143
+ public function toCurrency($value, array $options = array())
144
+ {
145
+ //validate the passed number
146
+ if (!isset($value) || !is_numeric($value)) {
147
+ require_once 'Zend/Currency/Exception.php';
148
+ throw new Zend_Currency_Exception("Value '$value' has to be numeric");
149
+ }
150
+
151
+ $options = array_merge($this->_options, $this->checkOptions($options));
152
+
153
+ //format the number
154
+ if (empty($options['format'])) {
155
+ $options['format'] = $this->_locale;
156
+ }
157
+ $value = Zend_Locale_Format::toNumber($value, array('locale' => $options['format'], 'precision' => $options['precision']));
158
+
159
+ //localize the number digits
160
+ if (!empty ($options['script'])) {
161
+ $value = Zend_Locale_Format::convertNumerals($value, 'Latn', $options['script']);
162
+ }
163
+ //get the sign to be placed next to the number
164
+ if (!is_numeric($options['display'])) {
165
+ $sign = " " . $options['display'] . " ";
166
+ } else {
167
+ switch($options['display']) {
168
+ case self::USE_SYMBOL:
169
+ $sign = " " . $options['symbol'] . " ";
170
+ break;
171
+ case self::USE_SHORTNAME:
172
+ $sign = " " . $options['currency'] . " ";
173
+ break;
174
+ case self::USE_NAME:
175
+ $sign = " " . $options['name'] . " ";
176
+ break;
177
+ default:
178
+ $sign = "";
179
+ break;
180
+ }
181
+ }
182
+
183
+ //place the sign next to the number
184
+ if ($options['position'] == self::RIGHT) {
185
+ $value = $value . $sign;
186
+ } else if ($options['position'] == self::LEFT) {
187
+ $value = $sign . $value;
188
+ }
189
+ return trim($value);
190
+ }
191
+
192
+
193
+ /**
194
+ * Sets the formating options of the localized currency string
195
+ * If no parameter is passed, the standard setting of the
196
+ * actual set locale will be used
197
+ *
198
+ * @param const|string $rules OPTIONAL formating rules for currency
199
+ * - USE_SYMBOL|NOSYMBOL : display currency symbol
200
+ * - USE_NAME|NONAME : display currency name
201
+ * - STANDARD|RIGHT|LEFT : where to display currency symbol/name
202
+ * - string: gives the currency string/name/sign to set
203
+ * @param string $script OPTIONAL Number script to use for output
204
+ * @param string|Zend_Locale $locale OPTIONAL Locale for output formatting
205
+ * @return Zend_Currency
206
+ */
207
+ public function setFormat(array $options = array())
208
+ {
209
+ $this->_options = array_merge($this->_options, $this->checkOptions($options));
210
+ return $this;
211
+ }
212
+
213
+ /**
214
+ * Internal function for checking static given locale parameter
215
+ *
216
+ * @param string $currency OPTIONAL Currency name
217
+ * @param string|Zend_Locale $locale OPTIONAL Locale to display informations
218
+ * @return string the extracted locale representation as string
219
+ * @throws Zend_Currency_Exception
220
+ */
221
+ private function _checkParams($currency = null, $locale = null)
222
+ {
223
+ //manage the params
224
+ if (empty($locale) && !empty($currency) && (Zend_Locale::isLocale($currency))) {
225
+ $locale = $currency;
226
+ $currency = null;
227
+ }
228
+
229
+ if ($locale instanceof Zend_Locale) {
230
+ $locale = $locale->toString();
231
+ }
232
+
233
+ //validate the locale and get the country short name
234
+ $country = null;
235
+ if ($locale = Zend_Locale::isLocale($locale) and (strlen($locale) > 4)) {
236
+ $country = substr($locale, strpos($locale, '_')+1 );
237
+ } else {
238
+ require_once 'Zend/Currency/Exception.php';
239
+ throw new Zend_Currency_Exception("No region found within the locale '$locale'");
240
+ }
241
+
242
+ //get the available currencies for this country
243
+ $data = Zend_Locale_Data::getContent($locale, 'currencytoregion', $country);
244
+ if (!empty($currency) and (!empty($data))) {
245
+ $abbreviation = $currency;
246
+ } else {
247
+ $abbreviation = $data;
248
+ }
249
+
250
+ return array('locale' => $locale, 'currency' => $currency, 'name' => $abbreviation, 'country' => $country);
251
+ }
252
+
253
+ /**
254
+ * Returns the actual or details of other currency symbols,
255
+ * when no symbol is available it returns the currency shortname (f.e. FIM for Finnian Mark)
256
+ *
257
+ * @param string $currency OPTIONAL Currency name
258
+ * @param string|Zend_Locale $locale OPTIONAL Locale to display informations
259
+ * @return string
260
+ * @throws Zend_Currency_Exception
261
+ */
262
+ public function getSymbol($currency = null, $locale = null)
263
+ {
264
+ if (($currency === null) and ($locale === null)) {
265
+ return $this->_options['symbol'];
266
+ }
267
+
268
+ $params = self::_checkParams($currency, $locale);
269
+
270
+ //get the symbol
271
+ $symbol = Zend_Locale_Data::getContent($params['locale'], 'currencysymbol', $params['currency']);
272
+ if (empty($symbol)) {
273
+ $symbol = Zend_Locale_Data::getContent($params['locale'], 'currencysymbol', $params['name']);
274
+ }
275
+ if (empty($symbol)) {
276
+ return null;
277
+ }
278
+ return $symbol;
279
+ }
280
+
281
+
282
+ /**
283
+ * Returns the actual or details of other currency shortnames
284
+ *
285
+ * @param string $currency OPTIONAL Currency's name
286
+ * @param string|Zend_Locale $locale OPTIONAL the locale
287
+ * @return string
288
+ * @throws Zend_Currency_Exception
289
+ */
290
+ public function getShortName($currency = null, $locale = null)
291
+ {
292
+ if (($currency === null) and ($locale === null)) {
293
+ return $this->_options['currency'];
294
+ }
295
+
296
+ $params = self::_checkParams($currency, $locale);
297
+
298
+ //get the shortname
299
+ if (empty($params['currency'])) {
300
+ return $params['name'];
301
+ }
302
+ $list = Zend_Locale_Data::getContent($params['locale'], 'currencytoname', $params['currency']);
303
+ if (empty($list)) {
304
+ $list = Zend_Locale_Data::getContent($params['locale'], 'nametocurrency', $params['currency']);
305
+ if (!empty($list)) {
306
+ $list = $params['currency'];
307
+ }
308
+ }
309
+ if (empty($list)) {
310
+ return null;
311
+ }
312
+ return $list;
313
+ }
314
+
315
+
316
+ /**
317
+ * Returns the actual or details of other currency names
318
+ *
319
+ * @param string $currency OPTIONAL Currency's short name
320
+ * @param string|Zend_Locale $locale OPTIONAL the locale
321
+ * @return string
322
+ * @throws Zend_Currency_Exception
323
+ */
324
+ public function getName($currency = null, $locale = null)
325
+ {
326
+ if (($currency === null) and ($locale === null)) {
327
+ return $this->_options['name'];
328
+ }
329
+
330
+ $params = self::_checkParams($currency, $locale);
331
+
332
+ //get the name
333
+ $name = Zend_Locale_Data::getContent($params['locale'], 'nametocurrency', $params['currency']);
334
+ if (empty($name)) {
335
+ $name = Zend_Locale_Data::getContent($params['locale'], 'nametocurrency', $params['name']);
336
+ }
337
+ if (empty($name)) {
338
+ return null;
339
+ }
340
+ return $name;
341
+ }
342
+
343
+
344
+ /**
345
+ * Returns a list of regions where this currency is or was known
346
+ *
347
+ * @param string $currency OPTIONAL Currency's short name
348
+ * @return array List of regions
349
+ */
350
+ public function getRegionList($currency = null)
351
+ {
352
+ if ($currency === null) {
353
+ $currency = $this->_options['currency'];
354
+ }
355
+ if (empty($currency)) {
356
+ require_once 'Zend/Currency/Exception.php';
357
+ throw new Zend_Currency_Exception("No currency defined");
358
+ }
359
+ $data = Zend_Locale_Data::getContent('', 'regiontocurrency', $currency);
360
+
361
+ $result = explode(' ', $data);
362
+ return $result;
363
+ }
364
+
365
+
366
+ /**
367
+ * Returns a list of currencies which are used in this region
368
+ * a region name should be 2 charachters only (f.e. EG, DE, US)
369
+ * If no region is given, the actual region is used
370
+ *
371
+ * @param string $region OPTIONAL Region to return the currencies for
372
+ * @return array List of currencies
373
+ */
374
+ public function getCurrencyList($region = null)
375
+ {
376
+ if (empty($region)) {
377
+ if (strlen($this->_locale) > 4) {
378
+ $region = substr($this->_locale, strpos($this->_locale, '_')+1 );
379
+ }
380
+ }
381
+ return Zend_Locale_Data::getList('', 'regiontocurrency', $region);
382
+ }
383
+
384
+
385
+ /**
386
+ * Returns the actual currency name
387
+ *
388
+ * @return string
389
+ */
390
+ public function toString()
391
+ {
392
+ return !empty($this->_options['name']) ? $this->_options['name'] : $this->_options['currency'];
393
+ }
394
+
395
+
396
+ /**
397
+ * Returns the currency name
398
+ *
399
+ * @return string
400
+ */
401
+ public function __toString()
402
+ {
403
+ return $this->toString();
404
+ }
405
+
406
+ /**
407
+ * sets a cache for Zend_Currency
408
+ *
409
+ * @param Zend_Cache_Core $cache Cache to set
410
+ */
411
+ public static function setCache(Zend_Cache_Core $cache)
412
+ {
413
+ Zend_Locale_Data::setCache($cache);
414
+ }
415
+
416
+
417
+ /**
418
+ * Sets a new locale for data retreivement
419
+ * Returned is the really set locale.
420
+ * Example: 'de_XX' will be set to 'de' because 'de_XX' does not exist
421
+ * 'xx_YY' will be set to 'root' because 'xx' does not exist
422
+ *
423
+ * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
424
+ * @return string
425
+ */
426
+ public function setLocale($locale = null)
427
+ {
428
+ if ($locale instanceof Zend_Locale) {
429
+ $this->_locale = $locale->toString();
430
+ } else if (!$this->_locale = Zend_Locale::isLocale($locale, true)) {
431
+ require_once 'Zend/Currency/Exception.php';
432
+ throw new Zend_Currency_Exception("Given locale ($locale) does not exist");
433
+ }
434
+
435
+ // get currency details
436
+ $this->_options['currency'] = $this->getShortName(null, $this->_locale);
437
+ $this->_options['name'] = $this->getName (null, $this->_locale);
438
+ $this->_options['symbol'] = $this->getSymbol (null, $this->_locale);
439
+
440
+ return $this->getLocale();
441
+ }
442
+
443
+
444
+ /**
445
+ * Returns the actual set locale
446
+ *
447
+ * @return string
448
+ */
449
+ public function getLocale()
450
+ {
451
+ return $this->_locale;
452
+ }
453
+
454
+ /**
455
+ * Internal method for checking the options array
456
+ *
457
+ * @param array $options
458
+ * @return array
459
+ * @throws Zend_Currency_Exception
460
+ */
461
+ private function checkOptions(array $options = array())
462
+ {
463
+ if (count($options) == 0) {
464
+ return $this->_options;
465
+ }
466
+ foreach($options as $name => $value) {
467
+ $name = strtolower($name);
468
+ if ($name !== 'format') {
469
+ if (gettype($value) === 'string') {
470
+ $value = strtolower($value);
471
+ }
472
+ }
473
+ if (array_key_exists($name, $this->_options)) {
474
+ switch($name) {
475
+ case 'position' :
476
+ if (($value !== self::STANDARD) and ($value !== self::RIGHT) and ($value !== self::LEFT)) {
477
+ require_once 'Zend/Currency/Exception.php';
478
+ throw new Zend_Currency_Exception("Unknown position '" . $value . "'");
479
+ }
480
+ if ($value === self::STANDARD) {
481
+ $options['position'] = $this->_updateFormat();
482
+ }
483
+ break;
484
+ case 'format' :
485
+ if (!empty($value) && (!Zend_Locale::isLocale($value))) {
486
+ require_once 'Zend/Currency/Exception.php';
487
+ throw new Zend_Currency_Exception("'" .
488
+ (gettype($value) === 'object' ? get_class($value) : $value)
489
+ . "' is not a known locale.");
490
+ }
491
+ break;
492
+ case 'display' :
493
+ if (is_numeric($value) and ($value !== self::NO_SYMBOL) and ($value !== self::USE_SYMBOL) and
494
+ ($value !== self::USE_SHORTNAME) and ($value !== self::USE_NAME)) {
495
+ require_once 'Zend/Currency/Exception.php';
496
+ throw new Zend_Currency_Exception("Unknown display '$value'");
497
+ }
498
+ break;
499
+ case 'precision' :
500
+ if ($value === NULL) {
501
+ $value = -1;
502
+ }
503
+ if (($value < -1) || ($value > 30)) {
504
+ require_once 'Zend/Currency/Exception.php';
505
+ throw new Zend_Currency_Exception("'$value' precision has to be between -1 and 30.");
506
+ }
507
+ break;
508
+ case 'script' :
509
+ try {
510
+ Zend_Locale_Format::convertNumerals(0,$options['script']);
511
+ } catch (Zend_Locale_Exception $e) {
512
+ require_once 'Zend/Currency/Exception.php';
513
+ throw new Zend_Currency_Exception($e->getMessage());
514
+ }
515
+ break;
516
+ }
517
+ }
518
+ else {
519
+ require_once 'Zend/Currency/Exception.php';
520
+ throw new Zend_Currency_Exception("Unknown option: '$name' = '$value'");
521
+ }
522
+ }
523
+ return $options;
524
+ }
525
+ }
lib/Zend/Currency/Exception.php ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Zend Framework
4
+ *
5
+ * LICENSE
6
+ *
7
+ * This source file is subject to the new BSD license that is bundled
8
+ * with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://framework.zend.com/license/new-bsd
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@zend.com so we can send you a copy immediately.
14
+ *
15
+ * @category Zend
16
+ * @package Zend_Currency
17
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
18
+ * @version $Id
19
+ * @license http://framework.zend.com/license/new-bsd New BSD License
20
+ */
21
+
22
+
23
+ /**
24
+ * Zend_Exception
25
+ */
26
+ require_once 'Zend/Exception.php';
27
+
28
+
29
+ /**
30
+ * @category Zend
31
+ * @package Zend_Currency
32
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
33
+ * @license http://framework.zend.com/license/new-bsd New BSD License
34
+ */
35
+ class Zend_Currency_Exception extends Zend_Exception
36
+ {
37
+ }
lib/Zend/Date.php ADDED
@@ -0,0 +1,4727 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Zend Framework
4
+ *
5
+ * LICENSE
6
+ *
7
+ * This source file is subject to the new BSD license that is bundled
8
+ * with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://framework.zend.com/license/new-bsd
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@zend.com so we can send you a copy immediately.
14
+ *
15
+ * @category Zend
16
+ * @package Zend_Date
17
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
18
+ * @version $Id: Date.php 8857 2008-03-16 12:04:03Z thomas $
19
+ * @license http://framework.zend.com/license/new-bsd New BSD License
20
+ */
21
+
22
+
23
+ /**
24
+ * Include needed Date classes
25
+ */
26
+ require_once 'Zend/Date/DateObject.php';
27
+ require_once 'Zend/Locale.php';
28
+ require_once 'Zend/Locale/Format.php';
29
+ require_once 'Zend/Locale/Math.php';
30
+
31
+
32
+ /**
33
+ * @category Zend
34
+ * @package Zend_Date
35
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
36
+ * @license http://framework.zend.com/license/new-bsd New BSD License
37
+ */
38
+ class Zend_Date extends Zend_Date_DateObject {
39
+
40
+ private $_Locale = null;
41
+
42
+ // Fractional second variables
43
+ private $_Fractional = 0;
44
+ private $_Precision = 3;
45
+
46
+ private static $_Options = array(
47
+ 'format_type' => 'iso', // format for date strings 'iso' or 'php'
48
+ 'fix_dst' => true, // fix dst on summer/winter time change
49
+ 'extend_month' => false, // false - addMonth like SQL, true like excel
50
+ 'cache' => null, // cache to set
51
+ 'timesync' => null // timesync server to set
52
+ );
53
+
54
+ // Class wide Date Constants
55
+ // day formats
56
+ const DAY = 'DAY'; // d - 2 digit day of month, 01-31
57
+ const DAY_SHORT = 'DAY_SHORT'; // j - 1,2 digit day of month, 1-31
58
+
59
+ const DAY_SUFFIX = 'DAY_SUFFIX'; // S - english suffix day of month, st-th
60
+ const DAY_OF_YEAR = 'DAY_OF_YEAR'; // z - Number of day of year
61
+
62
+ const WEEKDAY = 'WEEKDAY'; // l - full day name - locale aware, Monday - Sunday
63
+ const WEEKDAY_SHORT = 'WEEKDAY_SHORT'; // --- 3 letter day of week - locale aware, Mon-Sun
64
+ const WEEKDAY_NARROW = 'WEEKDAY_NARROW'; // --- 1 letter day name - locale aware, M-S
65
+ const WEEKDAY_NAME = 'WEEKDAY_NAME'; // D - abbreviated day name, 1-3 letters - locale aware, Mon-Sun
66
+
67
+ const WEEKDAY_8601 = 'WEEKDAY_8601'; // N - digit weekday ISO 8601, 1-7 1 = monday, 7=sunday
68
+ const WEEKDAY_DIGIT = 'WEEKDAY_DIGIT'; // w - weekday, 0-6 0=sunday, 6=saturday
69
+
70
+ // week formats
71
+ const WEEK = 'WEEK'; // W - number of week ISO8601, 1-53
72
+
73
+ // month formats
74
+ const MONTH = 'MONTH'; // m - 2 digit month, 01-12
75
+ const MONTH_SHORT = 'MONTH_SHORT'; // n - 1 digit month, no leading zeros, 1-12
76
+
77
+ const MONTH_DAYS = 'MONTH_DAYS'; // t - Number of days this month
78
+
79
+ const MONTH_NAME = 'MONTH_NAME'; // F - full month name - locale aware, January-December
80
+ const MONTH_NAME_SHORT = 'MONTH_NAME_SHORT'; // M - 3 letter monthname - locale aware, Jan-Dec
81
+ const MONTH_NAME_NARROW = 'MONTH_NAME_NARROW'; // --- 1 letter month name - locale aware, J-D
82
+
83
+ // year formats
84
+ const YEAR = 'YEAR'; // Y - 4 digit year
85
+ const YEAR_SHORT = 'YEAR_SHORT'; // y - 2 digit year, leading zeros 00-99
86
+
87
+ const YEAR_8601 = 'YEAR_8601'; // o - number of year ISO8601
88
+ const YEAR_SHORT_8601= 'YEAR_SHORT_8601';// --- 2 digit number of year ISO8601
89
+
90
+ const LEAPYEAR = 'LEAPYEAR'; // L - is leapyear ?, 0-1
91
+
92
+ // time formats
93
+ const MERIDIEM = 'MERIDIEM'; // A,a - AM/PM - locale aware, AM/PM
94
+ const SWATCH = 'SWATCH'; // B - Swatch Internet Time
95
+
96
+ const HOUR = 'HOUR'; // H - 2 digit hour, leading zeros, 00-23
97
+ const HOUR_SHORT = 'HOUR_SHORT'; // G - 1 digit hour, no leading zero, 0-23
98
+
99
+ const HOUR_AM = 'HOUR_AM'; // h - 2 digit hour, leading zeros, 01-12 am/pm
100
+ const HOUR_SHORT_AM = 'HOUR_SHORT_AM'; // g - 1 digit hour, no leading zero, 1-12 am/pm
101
+
102
+ const MINUTE = 'MINUTE'; // i - 2 digit minute, leading zeros, 00-59
103
+ const MINUTE_SHORT = 'MINUTE_SHORT'; // --- 1 digit minute, no leading zero, 0-59
104
+
105
+ const SECOND = 'SECOND'; // s - 2 digit second, leading zeros, 00-59
106
+ const SECOND_SHORT = 'SECOND_SHORT'; // --- 1 digit second, no leading zero, 0-59
107
+
108
+ const MILLISECOND = 'MILLISECOND'; // --- milliseconds
109
+
110
+ // timezone formats
111
+ const TIMEZONE_NAME = 'TIMEZONE_NAME'; // e - timezone string
112
+ const DAYLIGHT = 'DAYLIGHT'; // I - is Daylight saving time ?, 0-1
113
+ const GMT_DIFF = 'GMT_DIFF'; // O - GMT difference, -1200 +1200
114
+ const GMT_DIFF_SEP = 'GMT_DIFF_SEP'; // P - seperated GMT diff, -12:00 +12:00
115
+ const TIMEZONE = 'TIMEZONE'; // T - timezone, EST, GMT, MDT
116
+ const TIMEZONE_SECS = 'TIMEZONE_SECS'; // Z - timezone offset in seconds, -43200 +43200
117
+
118
+ // date strings
119
+ const ISO_8601 = 'ISO_8601'; // c - ISO 8601 date string
120
+ const RFC_2822 = 'RFC_2822'; // r - RFC 2822 date string
121
+ const TIMESTAMP = 'TIMESTAMP'; // U - unix timestamp
122
+
123
+ // additional formats
124
+ const ERA = 'ERA'; // --- short name of era, locale aware,
125
+ const ERA_NAME = 'ERA_NAME'; // --- full name of era, locale aware,
126
+ const DATES = 'DATES'; // --- standard date, locale aware
127
+ const DATE_FULL = 'DATE_FULL'; // --- full date, locale aware
128
+ const DATE_LONG = 'DATE_LONG'; // --- long date, locale aware
129
+ const DATE_MEDIUM = 'DATE_MEDIUM'; // --- medium date, locale aware
130
+ const DATE_SHORT = 'DATE_SHORT'; // --- short date, locale aware
131
+ const TIMES = 'TIMES'; // --- standard time, locale aware
132
+ const TIME_FULL = 'TIME_FULL'; // --- full time, locale aware
133
+ const TIME_LONG = 'TIME_LONG'; // --- long time, locale aware
134
+ const TIME_MEDIUM = 'TIME_MEDIUM'; // --- medium time, locale aware
135
+ const TIME_SHORT = 'TIME_SHORT'; // --- short time, locale aware
136
+ const ATOM = 'ATOM'; // --- DATE_ATOM
137
+ const COOKIE = 'COOKIE'; // --- DATE_COOKIE
138
+ const RFC_822 = 'RFC_822'; // --- DATE_RFC822
139
+ const RFC_850 = 'RFC_850'; // --- DATE_RFC850
140
+ const RFC_1036 = 'RFC_1036'; // --- DATE_RFC1036
141
+ const RFC_1123 = 'RFC_1123'; // --- DATE_RFC1123
142
+ const RFC_3339 = 'RFC_3339'; // --- DATE_RFC3339
143
+ const RSS = 'RSS'; // --- DATE_RSS
144
+ const W3C = 'W3C'; // --- DATE_W3C
145
+
146
+
147
+ /**
148
+ * Generates the standard date object, could be a unix timestamp, localized date,
149
+ * string, integer, array and so on. Also parts of dates or time are supported
150
+ * Always set the default timezone: http://php.net/date_default_timezone_set
151
+ * For example, in your bootstrap: date_default_timezone_set('America/Los_Angeles');
152
+ * For detailed instructions please look in the docu.
153
+ *
154
+ * @param string|integer|Zend_Date|array $date OPTIONAL Date value or value of date part to set
155
+ * ,depending on $part. If null the actual time is set
156
+ * @param string $part OPTIONAL Defines the input format of $date
157
+ * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
158
+ * @return Zend_Date
159
+ * @throws Zend_Date_Exception
160
+ */
161
+ public function __construct($date = null, $part = null, $locale = null)
162
+ {
163
+ if (Zend_Locale::isLocale($date)) {
164
+ $locale = $date;
165
+ $date = null;
166
+ $part = null;
167
+ } else if (Zend_Locale::isLocale($part)) {
168
+ $locale = $part;
169
+ $part = null;
170
+ }
171
+
172
+ $this->setLocale($locale);
173
+
174
+ if (is_string($date) && defined("self::".$date)) {
175
+ $part = $date;
176
+ $date = null;
177
+ }
178
+
179
+ if (is_null($date)) {
180
+ $date = Zend_Date::now($locale);
181
+ if (($part !== null) && ($part !== Zend_Date::TIMESTAMP)) {
182
+ $date = $date->get($part);
183
+ }
184
+ }
185
+
186
+ if ($date instanceof Zend_TimeSync_Protocol) {
187
+ $date = $date->getInfo();
188
+ $date = $this->_getTime($date['offset']);
189
+ $part = null;
190
+ } else if (parent::$_defaultOffset != 0) {
191
+ $date = $this->_getTime(parent::$_defaultOffset);
192
+ }
193
+
194
+ // set the timezone and offset for $this
195
+ $zone = @date_default_timezone_get();
196
+ $this->setTimezone($zone);
197
+
198
+ // try to get timezone from date-string
199
+ $zone = $this->getTimezoneFromString($date);
200
+ $this->setTimezone($zone);
201
+
202
+ // set datepart
203
+ if (($part !== null && $part !== Zend_Date::TIMESTAMP) or (!is_numeric($date))) {
204
+ // switch off dst handling for value setting
205
+ $this->setUnixTimestamp($this->getGmtOffset());
206
+ $this->set($date, $part, $this->_Locale);
207
+
208
+ // DST fix
209
+ if (is_array($date) and array_key_exists('hour', $date)) {
210
+ $hour = $this->toString('H');
211
+ $hour = $date['hour'] - $hour;
212
+ if ($hour !== 0) {
213
+ $this->addTimestamp($hour * 3600);
214
+ }
215
+ }
216
+ } else {
217
+ $this->setUnixTimestamp($date);
218
+ }
219
+ }
220
+
221
+
222
+ /**
223
+ * Sets class wide options, if no option was given, the actual set options will be returned
224
+ *
225
+ * @param array $options Options to set
226
+ * @throws Zend_Date_Exception
227
+ * @return Options array if no option was given
228
+ */
229
+ public static function setOptions(array $options = array())
230
+ {
231
+ if (empty($options)) {
232
+ return self::$_Options;
233
+ }
234
+ foreach ($options as $name => $value) {
235
+ $name = strtolower($name);
236
+
237
+ if (array_key_exists($name, self::$_Options)) {
238
+ switch($name) {
239
+ case 'format_type' :
240
+ if ((strtolower($value) != 'php') && (strtolower($value) != 'iso')) {
241
+ require_once 'Zend/Date/Exception.php';
242
+ throw new Zend_Date_Exception("Unknown format type ($value) for dates, only 'iso' and 'php' supported", $value);
243
+ }
244
+ break;
245
+ case 'fix_dst' :
246
+ if (!is_bool($value)) {
247
+ require_once 'Zend/Date/Exception.php';
248
+ throw new Zend_Date_Exception("'fix_dst' has to be boolean", $value);
249
+ }
250
+ break;
251
+ case 'extend_month' :
252
+ if (!is_bool($value)) {
253
+ require_once 'Zend/Date/Exception.php';
254
+ throw new Zend_Date_Exception("'extend_month' has to be boolean", $value);
255
+ }
256
+ break;
257
+ case 'cache' :
258
+ if (!$value instanceof Zend_Cache_Core) {
259
+ require_once 'Zend/Date/Exception.php';
260
+ throw new Zend_Date_Exception("Instance of Zend_Cache expected");
261
+ }
262
+ parent::$_cache = $value;
263
+ Zend_Locale_Data::setCache($value);
264
+ break;
265
+ case 'timesync' :
266
+ if (!$value instanceof Zend_TimeSync_Protocol) {
267
+ require_once 'Zend/Date/Exception.php';
268
+ throw new Zend_Date_Exception("Instance of Zend_TimeSync expected");
269
+ }
270
+ $date = $value->getInfo();
271
+ parent::$_defaultOffset = $date['offset'];
272
+ break;
273
+ }
274
+ self::$_Options[$name] = $value;
275
+ }
276
+ else {
277
+ require_once 'Zend/Date/Exception.php';
278
+ throw new Zend_Date_Exception("Unknown option: $name = $value");
279
+ }
280
+ }
281
+ }
282
+
283
+
284
+ /**
285
+ * Returns this object's internal UNIX timestamp (equivalent to Zend_Date::TIMESTAMP).
286
+ * If the timestamp is too large for integers, then the return value will be a string.
287
+ * This function does not return the timestamp as an object.
288
+ * Use clone() or copyPart() instead.
289
+ *
290
+ * @return integer|string UNIX timestamp
291
+ */
292
+ public function getTimestamp()
293
+ {
294
+ return $this->getUnixTimestamp();
295
+ }
296
+
297
+
298
+ /**
299
+ * Returns the calculated timestamp
300
+ * HINT: timestamps are always GMT
301
+ *
302
+ * @param string $calc Type of calculation to make
303
+ * @param string|integer|array|Zend_Date $stamp Timestamp to calculate, when null the actual timestamp is calculated
304
+ * @return Zend_Date|integer
305
+ * @throws Zend_Date_Exception
306
+ */
307
+ private function _timestamp($calc, $stamp)
308
+ {
309
+ if ($stamp instanceof Zend_Date) {
310
+ // extract timestamp from object
311
+ $stamp = $stamp->get(Zend_Date::TIMESTAMP, true);
312
+ }
313
+
314
+ if (is_array($stamp)) {
315
+ if (array_key_exists('timestamp', $stamp)) {
316
+ $stamp = $stamp['timestamp'];
317
+ } else {
318
+ require_once 'Zend/Date/Exception.php';
319
+ throw new Zend_Date_Exception('no timestamp given in array');
320
+ }
321
+ }
322
+
323
+ if ($calc === 'set') {
324
+ $return = $this->setUnixTimestamp($stamp);
325
+ } else {
326
+ $return = $this->_calcdetail($calc, $stamp, Zend_Date::TIMESTAMP, null);
327
+ }
328
+ if ($calc != 'cmp') {
329
+ return $this;
330
+ }
331
+ return $return;
332
+ }
333
+
334
+
335
+ /**
336
+ * Sets a new timestamp
337
+ *
338
+ * @param integer|string|array|Zend_Date $timestamp Timestamp to set
339
+ * @return Zend_Date
340
+ * @throws Zend_Date_Exception
341
+ */
342
+ public function setTimestamp($timestamp)
343
+ {
344
+ return $this->_timestamp('set', $timestamp);
345
+ }
346
+
347
+
348
+ /**
349
+ * Adds a timestamp
350
+ *
351
+ * @param integer|string|array|Zend_Date $timestamp Timestamp to add
352
+ * @return Zend_Date
353
+ * @throws Zend_Date_Exception
354
+ */
355
+ public function addTimestamp($timestamp)
356
+ {
357
+ return $this->_timestamp('add', $timestamp);
358
+ }
359
+
360
+
361
+ /**
362
+ * Subtracts a timestamp
363
+ *
364
+ * @param integer|string|array|Zend_Date $timestamp Timestamp to sub
365
+ * @return Zend_Date
366
+ * @throws Zend_Date_Exception
367
+ */
368
+ public function subTimestamp($timestamp)
369
+ {
370
+ return $this->_timestamp('sub', $timestamp);
371
+ }
372
+
373
+
374
+ /**
375
+ * Compares two timestamps, returning the difference as integer
376
+ *
377
+ * @param integer|string|array|Zend_Date $timestamp Timestamp to compare
378
+ * @return integer 0 = equal, 1 = later, -1 = earlier
379
+ * @throws Zend_Date_Exception
380
+ */
381
+ public function compareTimestamp($timestamp)
382
+ {
383
+ return $this->_timestamp('cmp', $timestamp);
384
+ }
385
+
386
+
387
+ /**
388
+ * Returns a string representation of the object
389
+ * Supported format tokens are:
390
+ * G - era, y - year, Y - ISO year, M - month, w - week of year, D - day of year, d - day of month
391
+ * E - day of week, e - number of weekday (1-7), h - hour 1-12, H - hour 0-23, m - minute, s - second
392
+ * A - milliseconds of day, z - timezone, Z - timezone offset, S - fractional second, a - period of day
393
+ *
394
+ * Additionally format tokens but non ISO conform are:
395
+ * SS - day suffix, eee - php number of weekday(0-6), ddd - number of days per month
396
+ * l - Leap year, B - swatch internet time, I - daylight saving time, X - timezone offset in seconds
397
+ * r - RFC2822 format, U - unix timestamp
398
+ *
399
+ * Not supported ISO tokens are
400
+ * u - extended year, Q - quarter, q - quarter, L - stand alone month, W - week of month
401
+ * F - day of week of month, g - modified julian, c - stand alone weekday, k - hour 0-11, K - hour 1-24
402
+ * v - wall zone
403
+ *
404
+ * @param string $format OPTIONAL Rule for formatting output. If null the default date format is used
405
+ * @param string $type OPTIONAL Type for the format string which overrides the standard setting
406
+ * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
407
+ * @return string
408
+ */
409
+ public function toString($format = null, $type = null, $locale = null)
410
+ {
411
+ if ((strlen($format) != 2) and (Zend_Locale::isLocale($format))) {
412
+ $locale = $format;
413
+ $format = null;
414
+ }
415
+
416
+ if (Zend_Locale::isLocale($type)) {
417
+ $locale = $type;
418
+ $type = null;
419
+ }
420
+
421
+ if ($locale === null) {
422
+ $locale = $this->getLocale();
423
+ }
424
+
425
+ if ($format === null) {
426
+ $format = Zend_Locale_Format::getDateFormat($locale) . ' ' . Zend_Locale_Format::getTimeFormat($locale);
427
+ } else if (((self::$_Options['format_type'] == 'php') && ($type === null)) or ($type == 'php')) {
428
+ $format = Zend_Locale_Format::convertPhpToIsoFormat($format);
429
+ }
430
+
431
+ // get format tokens
432
+ $j = 0;
433
+ $comment = false;
434
+ $output = array();
435
+ for($i = 0; $i < strlen($format); ++$i) {
436
+
437
+ if ($format[$i] == "'") {
438
+ if ($comment == false) {
439
+ $comment = true;
440
+ ++$j;
441
+ $output[$j] = "'";
442
+ } else if (isset($format[$i+1]) and ($format[$i+1] == "'")) {
443
+ $output[$j] .= "'";
444
+ ++$i;
445
+ } else {
446
+ $comment = false;
447
+ }
448
+ continue;
449
+ }
450
+
451
+ if (isset($output[$j]) and ($output[$j][0] == $format[$i]) or
452
+ ($comment == true)) {
453
+ $output[$j] .= $format[$i];
454
+ } else {
455
+ ++$j;
456
+ $output[$j] = $format[$i];
457
+ }
458
+ }
459
+
460
+ $notset = false;
461
+ // fill format tokens with date information
462
+ for($i = 1; $i <= count($output); ++$i) {
463
+ // fill fixed tokens
464
+ switch ($output[$i]) {
465
+
466
+ // special formats
467
+ case 'SS' :
468
+ $output[$i] = $this->date('S', $this->getUnixTimestamp(), false);
469
+ break;
470
+
471
+ case 'eee' :
472
+ $output[$i] = $this->date('N', $this->getUnixTimestamp(), false);
473
+ break;
474
+
475
+ case 'ddd' :
476
+ $output[$i] = $this->date('t', $this->getUnixTimestamp(), false);
477
+ break;
478
+
479
+ case 'l' :
480
+ $output[$i] = $this->date('L', $this->getUnixTimestamp(), false);
481
+ break;
482
+
483
+ case 'B' :
484
+ $output[$i] = $this->date('B', $this->getUnixTimestamp(), false);
485
+ break;
486
+
487
+ case 'I' :
488
+ $output[$i] = $this->date('I', $this->getUnixTimestamp(), false);
489
+ break;
490
+
491
+ case 'X' :
492
+ $output[$i] = $this->date('Z', $this->getUnixTimestamp(), false);
493
+ break;
494
+
495
+ case 'r' :
496
+ $output[$i] = $this->date('r', $this->getUnixTimestamp(), false);
497
+ break;
498
+
499
+ case 'U' :
500
+ $output[$i] = $this->getUnixTimestamp();
501
+ break;
502
+
503
+
504
+ // eras
505
+ case 'GGGGG' :
506
+ $output[$i] = substr($this->get(Zend_Date::ERA, $locale), 0, 1) . ".";
507
+ break;
508
+
509
+ case 'GGGG' :
510
+ $output[$i] = $this->get(Zend_Date::ERA_NAME, $locale);
511
+ break;
512
+
513
+ case 'GGG' :
514
+ case 'GG' :
515
+ case 'G' :
516
+ $output[$i] = $this->get(Zend_Date::ERA, $locale);
517
+ break;
518
+
519
+
520
+ // years
521
+ case 'yy' :
522
+ $output[$i] = str_pad($this->get(Zend_Date::YEAR_SHORT, $locale), 2, '0', STR_PAD_LEFT);
523
+ break;
524
+
525
+
526
+ // ISO years
527
+ case 'YY' :
528
+ $output[$i] = str_pad($this->get(Zend_Date::YEAR_SHORT_8601, $locale), 2, '0', STR_PAD_LEFT);
529
+ break;
530
+
531
+
532
+ // months
533
+ case 'MMMMM' :
534
+ $output[$i] = substr($this->get(Zend_Date::MONTH_NAME_NARROW, $locale), 0, 1);
535
+ break;
536
+
537
+ case 'MMMM' :
538
+ $output[$i] = $this->get(Zend_Date::MONTH_NAME, $locale);
539
+ break;
540
+
541
+ case 'MMM' :
542
+ $output[$i] = $this->get(Zend_Date::MONTH_NAME_SHORT, $locale);
543
+ break;
544
+
545
+ case 'MM' :
546
+ $output[$i] = $this->get(Zend_Date::MONTH, $locale);
547
+ break;
548
+
549
+ case 'M' :
550
+ $output[$i] = $this->get(Zend_Date::MONTH_SHORT, $locale);
551
+ break;
552
+
553
+
554
+ // week
555
+ case 'ww' :
556
+ $output[$i] = str_pad($this->get(Zend_Date::WEEK, $locale), 2, '0', STR_PAD_LEFT);
557
+ break;
558
+
559
+ case 'w' :
560
+ $output[$i] = $this->get(Zend_Date::WEEK, $locale);
561
+ break;
562
+
563
+
564
+ // monthday
565
+ case 'dd' :
566
+ $output[$i] = $this->get(Zend_Date::DAY, $locale);
567
+ break;
568
+
569
+ case 'd' :
570
+ $output[$i] = $this->get(Zend_Date::DAY_SHORT, $locale);
571
+ break;
572
+
573
+
574
+ // yearday
575
+ case 'DDD' :
576
+ $output[$i] = str_pad($this->get(Zend_Date::DAY_OF_YEAR, $locale), 3, '0', STR_PAD_LEFT);
577
+ break;
578
+
579
+ case 'DD' :
580
+ $output[$i] = str_pad($this->get(Zend_Date::DAY_OF_YEAR, $locale), 2, '0', STR_PAD_LEFT);
581
+ break;
582
+
583
+ case 'D' :
584
+ $output[$i] = $this->get(Zend_Date::DAY_OF_YEAR, $locale);
585
+ break;
586
+
587
+
588
+ // weekday
589
+ case 'EEEEE' :
590
+ $output[$i] = $this->get(Zend_Date::WEEKDAY_NARROW, $locale);
591
+ break;
592
+
593
+ case 'EEEE' :
594
+ $output[$i] = $this->get(Zend_Date::WEEKDAY, $locale);
595
+ break;
596
+
597
+ case 'EEE' :
598
+ $output[$i] = $this->get(Zend_Date::WEEKDAY_SHORT, $locale);
599
+ break;
600
+
601
+ case 'EE' :
602
+ $output[$i] = $this->get(Zend_Date::WEEKDAY_NAME, $locale);
603
+ break;
604
+
605
+ case 'E' :
606
+ $output[$i] = $this->get(Zend_Date::WEEKDAY_NARROW, $locale);
607
+ break;
608
+
609
+
610
+ // weekday number
611
+ case 'ee' :
612
+ $output[$i] = str_pad($this->get(Zend_Date::WEEKDAY_8601, $locale), 2, '0', STR_PAD_LEFT);
613
+ break;
614
+
615
+ case 'e' :
616
+ $output[$i] = $this->get(Zend_Date::WEEKDAY_8601, $locale);
617
+ break;
618
+
619
+
620
+ // period
621
+ case 'a' :
622
+ $output[$i] = $this->get(Zend_Date::MERIDIEM, $locale);
623
+ break;
624
+
625
+
626
+ // hour
627
+ case 'hh' :
628
+ $output[$i] = $this->get(Zend_Date::HOUR_AM, $locale);
629
+ break;
630
+
631
+ case 'h' :
632
+ $output[$i] = $this->get(Zend_Date::HOUR_SHORT_AM, $locale);
633
+ break;
634
+
635
+ case 'HH' :
636
+ $output[$i] = $this->get(Zend_Date::HOUR, $locale);
637
+ break;
638
+
639
+ case 'H' :
640
+ $output[$i] = $this->get(Zend_Date::HOUR_SHORT, $locale);
641
+ break;
642
+
643
+
644
+ // minute
645
+ case 'mm' :
646
+ $output[$i] = $this->get(Zend_Date::MINUTE, $locale);
647
+ break;
648
+
649
+ case 'm' :
650
+ $output[$i] = $this->get(Zend_Date::MINUTE_SHORT, $locale);
651
+ break;
652
+
653
+
654
+ // second
655
+ case 'ss' :
656
+ $output[$i] = $this->get(Zend_Date::SECOND, $locale);
657
+ break;
658
+
659
+ case 's' :
660
+ $output[$i] = $this->get(Zend_Date::SECOND_SHORT, $locale);
661
+ break;
662
+
663
+ case 'S' :
664
+ $output[$i] = $this->get(Zend_Date::MILLISECOND, $locale);
665
+ break;
666
+
667
+
668
+ // zone
669
+ // @todo v needs to be reworked as it's the long wall time and not the timezone
670
+ case 'vvvv' :
671
+ case 'zzzz' :
672
+ $output[$i] = $this->get(Zend_Date::TIMEZONE_NAME, $locale);
673
+ break;
674
+
675
+ // @todo v needs to be reworked as it's the short wall time and not the timezone
676
+ case 'v' :
677
+ case 'zzz' :
678
+ case 'zz' :
679
+ case 'z' :
680
+ $output[$i] = $this->get(Zend_Date::TIMEZONE, $locale);
681
+ break;
682
+
683
+
684
+ // zone offset
685
+ case 'ZZZZ' :
686
+ $output[$i] = $this->get(Zend_Date::GMT_DIFF_SEP, $locale);
687
+ break;
688
+
689
+ case 'ZZZ' :
690
+ case 'ZZ' :
691
+ case 'Z' :
692
+ $output[$i] = $this->get(Zend_Date::GMT_DIFF, $locale);
693
+ break;
694
+
695
+ default :
696
+ $notset = true;
697
+ break;
698
+ }
699
+
700
+ // fill variable tokens
701
+ if ($notset == true) {
702
+ if (($output[$i][0] !== "'") and (preg_match('/y+/', $output[$i]))) {
703
+ $length = strlen($output[$i]);
704
+ $output[$i] = $this->get(Zend_Date::YEAR, $locale);
705
+ $output[$i] = str_pad($output[$i], $length, '0', STR_PAD_LEFT);
706
+ }
707
+
708
+ if (($output[$i][0] !== "'") and (preg_match('/Y+/', $output[$i]))) {
709
+ $length = strlen($output[$i]);
710
+ $output[$i] = $this->get(Zend_Date::YEAR_8601, $locale);
711
+ $output[$i] = str_pad($output[$i], $length, '0', STR_PAD_LEFT);
712
+ }
713
+
714
+ if (($output[$i][0] !== "'") and (preg_match('/A+/', $output[$i]))) {
715
+ $length = strlen($output[$i]);
716
+ $seconds = $this->get(Zend_Date::TIMESTAMP, $locale);
717
+ $month = $this->get(Zend_Date::MONTH_SHORT, $locale);
718
+ $day = $this->get(Zend_Date::DAY_SHORT, $locale);
719
+ $year = $this->get(Zend_Date::YEAR, $locale);
720
+
721
+ $seconds -= $this->mktime(0, 0, 0, $month, $day, $year, false);
722
+ $output[$i] = str_pad($seconds, $length, '0', STR_PAD_LEFT);
723
+ }
724
+
725
+ if ($output[$i][0] === "'") {
726
+ $output[$i] = substr($output[$i], 1);
727
+ }
728
+ }
729
+ $notset = false;
730
+ }
731
+
732
+ return implode('', $output);
733
+ }
734
+
735
+
736
+ /**
737
+ * Returns a string representation of the date which is equal with the timestamp
738
+ *
739
+ * @return string
740
+ */
741
+ public function __toString()
742
+ {
743
+ return $this->toString(null, $this->_Locale);
744
+ }
745
+
746
+
747
+ /**
748
+ * Returns a integer representation of the object
749
+ * But returns false when the given part is no value f.e. Month-Name
750
+ *
751
+ * @param string|integer|Zend_Date $part OPTIONAL Defines the date or datepart to return as integer
752
+ * @return integer|false
753
+ */
754
+ public function toValue($part = null)
755
+ {
756
+ $result = $this->get($part);
757
+ if (is_numeric($result)) {
758
+ return intval("$result");
759
+ } else {
760
+ return false;
761
+ }
762
+ }
763
+
764
+
765
+ /**
766
+ * Returns an array representation of the object
767
+ *
768
+ * @return array
769
+ */
770
+ public function toArray()
771
+ {
772
+ return array('day' => $this->get(Zend_Date::DAY_SHORT),
773
+ 'month' => $this->get(Zend_Date::MONTH_SHORT),
774
+ 'year' => $this->get(Zend_Date::YEAR),
775
+ 'hour' => $this->get(Zend_Date::HOUR_SHORT),
776
+ 'minute' => $this->get(Zend_Date::MINUTE_SHORT),
777
+ 'second' => $this->get(Zend_Date::SECOND_SHORT),
778
+ 'timezone' => $this->get(Zend_Date::TIMEZONE),
779
+ 'timestamp' => $this->get(Zend_Date::TIMESTAMP),
780
+ 'weekday' => $this->get(Zend_Date::WEEKDAY_DIGIT),
781
+ 'dayofyear' => $this->get(Zend_Date::DAY_OF_YEAR),
782
+ 'week' => $this->get(Zend_Date::WEEK),
783
+ 'gmtsecs' => $this->get(Zend_Date::TIMEZONE_SECS));
784
+ }
785
+
786
+
787
+ /**
788
+ * Returns a representation of a date or datepart
789
+ * This could be for example a localized monthname, the time without date,
790
+ * the era or only the fractional seconds. There are about 50 different supported date parts.
791
+ * For a complete list of supported datepart values look into the docu
792
+ *
793
+ * @param string $part OPTIONAL Part of the date to return, if null the timestamp is returned
794
+ * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
795
+ * @return integer|string date or datepart
796
+ */
797
+ public function get($part = null, $locale = null)
798
+ {
799
+ if ($locale === null) {
800
+ $locale = $this->getLocale();
801
+ }
802
+
803
+ if (Zend_Locale::isLocale($part)) {
804
+ $locale = $part;
805
+ $part = null;
806
+ }
807
+
808
+ if ($part === null) {
809
+ $part = Zend_Date::TIMESTAMP;
810
+ }
811
+
812
+ if (!defined("self::".$part)) {
813
+ return $this->toString($part, $locale);
814
+ }
815
+
816
+ switch($part) {
817
+
818
+ // day formats
819
+ case Zend_Date::DAY :
820
+ return $this->date('d', $this->getUnixTimestamp(), false);
821
+ break;
822
+
823
+ case Zend_Date::WEEKDAY_SHORT :
824
+ $weekday = strtolower($this->date('D', $this->getUnixTimestamp(), false));
825
+ $day = Zend_Locale_Data::getContent($locale, 'day', array('gregorian', 'format', 'wide', $weekday));
826
+ return substr($day, 0, 3);
827
+ break;
828
+
829
+ case Zend_Date::DAY_SHORT :
830
+ return $this->date('j', $this->getUnixTimestamp(), false);
831
+ break;
832
+
833
+ case Zend_Date::WEEKDAY :
834
+ $weekday = strtolower($this->date('D', $this->getUnixTimestamp(), false));
835
+ return Zend_Locale_Data::getContent($locale, 'day', array('gregorian', 'format', 'wide', $weekday));
836
+ break;
837
+
838
+ case Zend_Date::WEEKDAY_8601 :
839
+ return $this->date('N', $this->getUnixTimestamp(), false);
840
+ break;
841
+
842
+ case Zend_Date::DAY_SUFFIX :
843
+ return $this->date('S', $this->getUnixTimestamp(), false);
844
+ break;
845
+
846
+ case Zend_Date::WEEKDAY_DIGIT :
847
+ return $this->date('w', $this->getUnixTimestamp(), false);
848
+ break;
849
+
850
+ case Zend_Date::DAY_OF_YEAR :
851
+ return $this->date('z', $this->getUnixTimestamp(), false);
852
+ break;
853
+
854
+
855
+ case Zend_Date::WEEKDAY_NARROW :
856
+ $weekday = strtolower($this->date('D', $this->getUnixTimestamp(), false));
857
+ $day = Zend_Locale_Data::getContent($locale, 'day', array('gregorian', 'format', 'abbreviated', $weekday));
858
+ return substr($day, 0, 1);
859
+ break;
860
+
861
+ case Zend_Date::WEEKDAY_NAME :
862
+ $weekday = strtolower($this->date('D', $this->getUnixTimestamp(), false));
863
+ return Zend_Locale_Data::getContent($locale, 'day', array('gregorian', 'format', 'abbreviated', $weekday));
864
+ break;
865
+
866
+
867
+ // week formats
868
+ case Zend_Date::WEEK :
869
+ return $this->date('W', $this->getUnixTimestamp(), false);
870
+ break;
871
+
872
+
873
+ // month formats
874
+ case Zend_Date::MONTH_NAME :
875
+ $month = $this->date('n', $this->getUnixTimestamp(), false);
876
+ return Zend_Locale_Data::getContent($locale, 'month', array('gregorian', 'format', 'wide', $month));
877
+ break;
878
+
879
+ case Zend_Date::MONTH :
880
+ return $this->date('m', $this->getUnixTimestamp(), false);
881
+ break;
882
+
883
+ case Zend_Date::MONTH_NAME_SHORT :
884
+ $month = $this->date('n', $this->getUnixTimestamp(), false);
885
+ return Zend_Locale_Data::getContent($locale, 'month', array('gregorian', 'format', 'abbreviated', $month));
886
+ break;
887
+
888
+ case Zend_Date::MONTH_SHORT :
889
+ return $this->date('n', $this->getUnixTimestamp(), false);
890
+ break;
891
+
892
+ case Zend_Date::MONTH_DAYS :
893
+ return $this->date('t', $this->getUnixTimestamp(), false);
894
+ break;
895
+
896
+
897
+ case Zend_Date::MONTH_NAME_NARROW :
898
+ $month = $this->date('n', $this->getUnixTimestamp(), false);
899
+ $mon = Zend_Locale_Data::getContent($locale, 'month', array('gregorian', 'format', 'abbreviated', $month));
900
+ return substr($mon, 0, 1);
901
+ break;
902
+
903
+
904
+ // year formats
905
+ case Zend_Date::LEAPYEAR :
906
+ return $this->date('L', $this->getUnixTimestamp(), false);
907
+ break;
908
+
909
+ case Zend_Date::YEAR_8601 :
910
+ return $this->date('o', $this->getUnixTimestamp(), false);
911
+ break;
912
+
913
+ case Zend_Date::YEAR :
914
+ return $this->date('Y', $this->getUnixTimestamp(), false);
915
+ break;
916
+
917
+ case Zend_Date::YEAR_SHORT :
918
+ return $this->date('y', $this->getUnixTimestamp(), false);
919
+ break;
920
+
921
+
922
+ case Zend_Date::YEAR_SHORT_8601 :
923
+ $year = $this->date('o', $this->getUnixTimestamp(), false);
924
+ return substr($year, -2);
925
+ break;
926
+
927
+
928
+ // time formats
929
+ case Zend_Date::MERIDIEM :
930
+ $am = $this->date('a', $this->getUnixTimestamp(), false);
931
+ if ($am == 'am') {
932
+ return Zend_Locale_Data::getContent($locale, 'am');
933
+ }
934
+ return Zend_Locale_Data::getContent($locale, 'pm');
935
+ break;
936
+
937
+ case Zend_Date::SWATCH :
938
+ return $this->date('B', $this->getUnixTimestamp(), false);
939
+ break;
940
+
941
+ case Zend_Date::HOUR_SHORT_AM :
942
+ return $this->date('g', $this->getUnixTimestamp(), false);
943
+ break;
944
+
945
+ case Zend_Date::HOUR_SHORT :
946
+ return $this->date('G', $this->getUnixTimestamp(), false);
947
+ break;
948
+
949
+ case Zend_Date::HOUR_AM :
950
+ return $this->date('h', $this->getUnixTimestamp(), false);
951
+ break;
952
+
953
+ case Zend_Date::HOUR :
954
+ return $this->date('H', $this->getUnixTimestamp(), false);
955
+ break;
956
+
957
+ case Zend_Date::MINUTE :
958
+ return $this->date('i', $this->getUnixTimestamp(), false);
959
+ break;
960
+
961
+ case Zend_Date::SECOND :
962
+ return $this->date('s', $this->getUnixTimestamp(), false);
963
+ break;
964
+
965
+
966
+ case Zend_Date::MINUTE_SHORT :
967
+ return $this->date('i', $this->getUnixTimestamp(), false);
968
+ break;
969
+
970
+ case Zend_Date::SECOND_SHORT :
971
+ return $this->date('s', $this->getUnixTimestamp(), false);
972
+ break;
973
+
974
+ case Zend_Date::MILLISECOND :
975
+ return $this->_Fractional;
976
+ break;
977
+
978
+
979
+ // timezone formats
980
+ case Zend_Date::TIMEZONE_NAME :
981
+ return $this->date('e', $this->getUnixTimestamp(), false);
982
+ break;
983
+
984
+ case Zend_Date::DAYLIGHT :
985
+ return $this->date('I', $this->getUnixTimestamp(), false);
986
+ break;
987
+
988
+ case Zend_Date::GMT_DIFF :
989
+ return $this->date('O', $this->getUnixTimestamp(), false);
990
+ break;
991
+
992
+ case Zend_Date::GMT_DIFF_SEP :
993
+ return $this->date('P', $this->getUnixTimestamp(), false);
994
+ break;
995
+
996
+ case Zend_Date::TIMEZONE :
997
+ return $this->date('T', $this->getUnixTimestamp(), false);
998
+ break;
999
+
1000
+ case Zend_Date::TIMEZONE_SECS :
1001
+ return $this->date('Z', $this->getUnixTimestamp(), false);
1002
+ break;
1003
+
1004
+
1005
+ // date strings
1006
+ case Zend_Date::ISO_8601 :
1007
+ return $this->date('c', $this->getUnixTimestamp(), false);
1008
+ break;
1009
+
1010
+ case Zend_Date::RFC_2822 :
1011
+ return $this->date('r', $this->getUnixTimestamp(), false);
1012
+ break;
1013
+
1014
+ case Zend_Date::TIMESTAMP :
1015
+ return $this->getUnixTimestamp();
1016
+ break;
1017
+
1018
+
1019
+ // additional formats
1020
+ case Zend_Date::ERA :
1021
+ $year = $this->date('Y', $this->getUnixTimestamp(), false);
1022
+ if ($year < 0) {
1023
+ return Zend_Locale_Data::getContent($locale, 'era', array('gregorian', 'Abbr', '0'));
1024
+ }
1025
+ return Zend_Locale_Data::getContent($locale, 'era', array('gregorian', 'Abbr', '1'));
1026
+ break;
1027
+
1028
+ case Zend_Date::ERA_NAME :
1029
+ $year = $this->date('Y', $this->getUnixTimestamp(), false);
1030
+ if ($year < 0) {
1031
+ return Zend_Locale_Data::getContent($locale, 'era', array('gregorian', 'Names', '0'));
1032
+ }
1033
+ return Zend_Locale_Data::getContent($locale, 'era', array('gregorian', 'Names', '1'));
1034
+ break;
1035
+
1036
+ case Zend_Date::DATES :
1037
+ return $this->toString(Zend_Locale_Format::getDateFormat($locale), 'iso', $locale);
1038
+ break;
1039
+
1040
+ case Zend_Date::DATE_FULL :
1041
+ $date = Zend_Locale_Data::getContent($locale, 'date', array('gregorian', 'full'));
1042
+ return $this->toString($date, 'iso', $locale);
1043
+ break;
1044
+
1045
+ case Zend_Date::DATE_LONG :
1046
+ $date = Zend_Locale_Data::getContent($locale, 'date', array('gregorian', 'long'));
1047
+ return $this->toString($date, 'iso', $locale);
1048
+ break;
1049
+
1050
+ case Zend_Date::DATE_MEDIUM :
1051
+ $date = Zend_Locale_Data::getContent($locale, 'date', array('gregorian', 'medium'));
1052
+ return $this->toString($date, 'iso', $locale);
1053
+ break;
1054
+
1055
+ case Zend_Date::DATE_SHORT :
1056
+ $date = Zend_Locale_Data::getContent($locale, 'date', array('gregorian', 'short'));
1057
+ return $this->toString($date, 'iso', $locale);
1058
+ break;
1059
+
1060
+ case Zend_Date::TIMES :
1061
+ return $this->toString(Zend_Locale_Format::getTimeFormat($locale), 'iso', $locale);
1062
+ break;
1063
+
1064
+ case Zend_Date::TIME_FULL :
1065
+ $time = Zend_Locale_Data::getContent($locale, 'time', 'full');
1066
+ return $this->toString($time, 'iso', $locale);
1067
+ break;
1068
+
1069
+ case Zend_Date::TIME_LONG :
1070
+ $time = Zend_Locale_Data::getContent($locale, 'time', 'long');
1071
+ return $this->toString($time, 'iso', $locale);
1072
+ break;
1073
+
1074
+ case Zend_Date::TIME_MEDIUM :
1075
+ $time = Zend_Locale_Data::getContent($locale, 'time', 'medium');
1076
+ return $this->toString($time, 'iso', $locale);
1077
+ break;
1078
+
1079
+ case Zend_Date::TIME_SHORT :
1080
+ $time = Zend_Locale_Data::getContent($locale, 'time', 'short');
1081
+ return $this->toString($time, 'iso', $locale);
1082
+ break;
1083
+
1084
+ case Zend_Date::ATOM :
1085
+ return $this->date('Y\-m\-d\TH\:i\:sP', $this->getUnixTimestamp(), false);
1086
+ break;
1087
+
1088
+ case Zend_Date::COOKIE :
1089
+ return $this->date('l\, d\-M\-y H\:i\:s e', $this->getUnixTimestamp(), false);
1090
+ break;
1091
+
1092
+ case Zend_Date::RFC_822 :
1093
+ return $this->date('D\, d M y H\:i\:s O', $this->getUnixTimestamp(), false);
1094
+ break;
1095
+
1096
+ case Zend_Date::RFC_850 :
1097
+ return $this->date('l\, d\-M\-y H\:i\:s e', $this->getUnixTimestamp(), false);
1098
+ break;
1099
+
1100
+ case Zend_Date::RFC_1036 :
1101
+ return $this->date('D\, d M y H\:i\:s O', $this->getUnixTimestamp(), false);
1102
+ break;
1103
+
1104
+ case Zend_Date::RFC_1123 :
1105
+ return $this->date('D\, d M Y H\:i\:s O', $this->getUnixTimestamp(), false);
1106
+ break;
1107
+
1108
+ case Zend_Date::RFC_3339 :
1109
+ return $this->date('Y\-m\-d\TH\:i\:sP', $this->getUnixTimestamp(), false);
1110
+ break;
1111
+
1112
+ case Zend_Date::RSS :
1113
+ return $this->date('D\, d M Y H\:i\:s O', $this->getUnixTimestamp(), false);
1114
+ break;
1115
+
1116
+ case Zend_Date::W3C :
1117
+ return $this->date('Y\-m\-d\TH\:i\:sP', $this->getUnixTimestamp(), false);
1118
+ break;
1119
+ }
1120
+ }
1121
+
1122
+
1123
+ /**
1124
+ * Return digit from standard names (english)
1125
+ * Faster implementation than locale aware searching
1126
+ *
1127
+ * @param string $name
1128
+ * @return integer Number of this month
1129
+ * @throws Zend_Date_Exception
1130
+ */
1131
+ private function getDigitFromName($name)
1132
+ {
1133
+ switch($name) {
1134
+ case "Jan":
1135
+ return 1;
1136
+
1137
+ case "Feb":
1138
+ return 2;
1139
+
1140
+ case "Mar":
1141
+ return 3;
1142
+
1143
+ case "Apr":
1144
+ return 4;
1145
+
1146
+ case "May":
1147
+ return 5;
1148
+
1149
+ case "Jun":
1150
+ return 6;
1151
+
1152
+ case "Jul":
1153
+ return 7;
1154
+
1155
+ case "Aug":
1156
+ return 8;
1157
+
1158
+ case "Sep":
1159
+ return 9;
1160
+
1161
+ case "Oct":
1162
+ return 10;
1163
+
1164
+ case "Nov":
1165
+ return 11;
1166
+
1167
+ case "Dec":
1168
+ return 12;
1169
+
1170
+ default:
1171
+ require_once 'Zend/Date/Exception.php';
1172
+ throw new Zend_Date_Exception('Month ($name) is not a known month');
1173
+ }
1174
+ }
1175
+
1176
+
1177
+ /**
1178
+ * Counts the exact year number
1179
+ * < 70 - 2000 added, >70 < 100 - 1900, others just returned
1180
+ *
1181
+ * @param integer $value year number
1182
+ * @return integer Number of year
1183
+ */
1184
+ private static function _century($value)
1185
+ {
1186
+ if ($value >= 0) {
1187
+ if ($value < 70) {
1188
+ $value += 2000;
1189
+ } else if ($value < 100) {
1190
+ $value += 1900;
1191
+ }
1192
+ }
1193
+ return $value;
1194
+ }
1195
+
1196
+
1197
+ /**
1198
+ * Sets the given date as new date or a given datepart as new datepart returning the new datepart
1199
+ * This could be for example a localized dayname, the date without time,
1200
+ * the month or only the seconds. There are about 50 different supported date parts.
1201
+ * For a complete list of supported datepart values look into the docu
1202
+ *
1203
+ * @param string|integer|array|Zend_Date $date Date or datepart to set
1204
+ * @param string $part OPTIONAL Part of the date to set, if null the timestamp is set
1205
+ * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
1206
+ * @return integer|string new datepart
1207
+ * @throws Zend_Date_Exception
1208
+ */
1209
+ public function set($date, $part = null, $locale = null)
1210
+ {
1211
+ $zone = $this->getTimezoneFromString($date);
1212
+ $this->setTimezone($zone);
1213
+
1214
+ $result = $this->_calculate('set', $date, $part, $locale);
1215
+ return $result;
1216
+ }
1217
+
1218
+
1219
+ /**
1220
+ * Adds a date or datepart to the existing date, by extracting $part from $date,
1221
+ * and modifying this object by adding that part. The $part is then extracted from
1222
+ * this object and returned as an integer or numeric string (for large values, or $part's
1223
+ * corresponding to pre-defined formatted date strings).
1224
+ * This could be for example a ISO 8601 date, the hour the monthname or only the minute.
1225
+ * There are about 50 different supported date parts.
1226
+ * For a complete list of supported datepart values look into the docu.
1227
+ *
1228
+ * @param string|integer|array|Zend_Date $date Date or datepart to add
1229
+ * @param string $part OPTIONAL Part of the date to add, if null the timestamp is added
1230
+ * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
1231
+ * @return integer|string new datepart
1232
+ * @throws Zend_Date_Exception
1233
+ */
1234
+ public function add($date, $part = null, $locale = null)
1235
+ {
1236
+ $this->_calculate('add', $date, $part, $locale);
1237
+ $result = $this->get($part, $locale);
1238
+
1239
+ return $result;
1240
+ }
1241
+
1242
+
1243
+ /**
1244
+ * Subtracts a date from another date.
1245
+ * This could be for example a RFC2822 date, the time,
1246
+ * the year or only the timestamp. There are about 50 different supported date parts.
1247
+ * For a complete list of supported datepart values look into the docu
1248
+ * Be aware: Adding -2 Months is not equal to Subtracting 2 Months !!!
1249
+ *
1250
+ * @param string|integer|array|Zend_Date $date Date or datepart to subtract
1251
+ * @param string $part OPTIONAL Part of the date to sub, if null the timestamp is subtracted
1252
+ * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
1253
+ * @return integer|string new datepart
1254
+ * @throws Zend_Date_Exception
1255
+ */
1256
+ public function sub($date, $part = null, $locale = null)
1257
+ {
1258
+ $this->_calculate('sub', $date, $part, $locale);
1259
+ $result = $this->get($part, $locale);
1260
+
1261
+ return $result;
1262
+ }
1263
+
1264
+
1265
+ /**
1266
+ * Compares a date or datepart with the existing one.
1267
+ * Returns -1 if earlier, 0 if equal and 1 if later.
1268
+ *
1269
+ * @param string|integer|array|Zend_Date $date Date or datepart to compare with the date object
1270
+ * @param string $part OPTIONAL Part of the date to compare, if null the timestamp is subtracted
1271
+ * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
1272
+ * @return integer 0 = equal, 1 = later, -1 = earlier
1273
+ * @throws Zend_Date_Exception
1274
+ */
1275
+ public function compare($date, $part = null, $locale = null)
1276
+ {
1277
+ $compare = $this->_calculate('cmp', $date, $part, $locale);
1278
+
1279
+ if ($compare > 0) {
1280
+ return 1;
1281
+ } else if ($compare < 0) {
1282
+ return -1;
1283
+ }
1284
+ return 0;
1285
+ }
1286
+
1287
+
1288
+ /**
1289
+ * Returns a new instance of Zend_Date with the selected part copied.
1290
+ * To make an exact copy, use PHP's clone keyword.
1291
+ * For a complete list of supported date part values look into the docu.
1292
+ * If a date part is copied, all other date parts are set to standard values.
1293
+ * For example: If only YEAR is copied, the returned date object is equal to
1294
+ * 01-01-YEAR 00:00:00 (01-01-1970 00:00:00 is equal to timestamp 0)
1295
+ * If only HOUR is copied, the returned date object is equal to
1296
+ * 01-01-1970 HOUR:00:00 (so $this contains a timestamp equal to a timestamp of 0 plus HOUR).
1297
+ *
1298
+ * @param string $part Part of the date to compare, if null the timestamp is subtracted
1299
+ * @param string|Zend_Locale $locale OPTIONAL New object's locale. No adjustments to timezone are made.
1300
+ * @return Zend_Date
1301
+ */
1302
+ public function copyPart($part, $locale = null)
1303
+ {
1304
+ $clone = clone $this; // copy all instance variables
1305
+ $clone->setUnixTimestamp(0); // except the timestamp
1306
+ if ($locale != null) {
1307
+ $clone->setLocale($locale); // set an other locale if selected
1308
+ }
1309
+ $clone->set($this, $part);
1310
+ return $clone;
1311
+ }
1312
+
1313
+ /**
1314
+ * Internal function, returns the offset of a given timezone
1315
+ *
1316
+ * @param string $zone
1317
+ * @return integer
1318
+ */
1319
+ public function getTimezoneFromString($zone)
1320
+ {
1321
+ if (is_array($zone)) {
1322
+ return $this->getTimezone();
1323
+ }
1324
+ if ($zone instanceof Zend_Date) {
1325
+ return $zone->getTimezone();
1326
+ }
1327
+ preg_match('/([+-]\d{2}):{0,1}\d{2}/', $zone, $match);
1328
+ if (!empty($match) and ($match[count($match) - 1] <= 12) and ($match[count($match) - 1] >= -12)) {
1329
+ $zone = "Etc/GMT";
1330
+ $zone .= ($match[count($match) - 1] < 0) ? "+" : "-";
1331
+ $zone .= (int) abs($match[count($match) - 1]);
1332
+ return $zone;
1333
+ }
1334
+ preg_match('/(\w{3,30})/', $zone, $match);
1335
+ try {
1336
+ if (!empty($match)) {
1337
+ $oldzone = $this->getTimezone();
1338
+ $result = $this->setTimezone($match[count($match) - 1]);
1339
+ $this->setTimezone($oldzone);
1340
+ if ($result !== $oldzone) {
1341
+ return $match[count($match) - 1];
1342
+ }
1343
+ }
1344
+ } catch (Exception $e) {
1345
+ // fall through
1346
+ }
1347
+ return $this->getTimezone();
1348
+ }
1349
+
1350
+ /**
1351
+ * Calculates the date or object
1352
+ *
1353
+ * @param string $calc Calculation to make
1354
+ * @param string|integer $date Date for calculation
1355
+ * @param string|integer $comp Second date for calculation
1356
+ * @param boolean|integer $dst Use dst correction if option is set
1357
+ * @return integer|string|Zend_Date new timestamp or Zend_Date depending on calculation
1358
+ */
1359
+ private function _assign($calc, $date, $comp = 0, $dst = false)
1360
+ {
1361
+ switch ($calc) {
1362
+ case 'set' :
1363
+ if (!empty($comp)) {
1364
+ $this->setUnixTimestamp(call_user_func(Zend_Locale_Math::$sub, $this->getUnixTimestamp(), $comp));
1365
+ }
1366
+ $this->setUnixTimestamp(call_user_func(Zend_Locale_Math::$add, $this->getUnixTimestamp(), $date));
1367
+ $value = $this->getUnixTimestamp();
1368
+ break;
1369
+ case 'add' :
1370
+ $this->setUnixTimestamp(call_user_func(Zend_Locale_Math::$add, $this->getUnixTimestamp(), $date));
1371
+ $value = $this->getUnixTimestamp();
1372
+ break;
1373
+ case 'sub' :
1374
+ $this->setUnixTimestamp(call_user_func(Zend_Locale_Math::$sub, $this->getUnixTimestamp(), $date));
1375
+ $value = $this->getUnixTimestamp();
1376
+ break;
1377
+ default :
1378
+ // cmp - compare
1379
+ return call_user_func(Zend_Locale_Math::$comp, $comp, $date);
1380
+ break;
1381
+ }
1382
+
1383
+ // dst-correction if 'fix_dst' = true and dst !== false but only for non UTC and non GMT
1384
+ if ((self::$_Options['fix_dst'] === true) and ($dst !== false) and ($this->_dst === true)) {
1385
+ $hour = $this->get(Zend_Date::HOUR);
1386
+ if ($hour != $dst) {
1387
+ if (($dst == ($hour + 1)) or ($dst == ($hour - 23))) {
1388
+ $value += 3600;
1389
+ } else if (($dst == ($hour - 1)) or ($dst == ($hour + 23))) {
1390
+ $value -= 3600;
1391
+ }
1392
+ $this->setUnixTimestamp($value);
1393
+ }
1394
+ }
1395
+ return $this->getUnixTimestamp();
1396
+ }
1397
+
1398
+
1399
+ /**
1400
+ * Calculates the date or object
1401
+ *
1402
+ * @param string $calc Calculation to make, one of: 'add'|'sub'|'cmp'|'copy'|'set'
1403
+ * @param string|integer|array|Zend_Date $date Date or datepart to calculate with
1404
+ * @param string $part Part of the date to calculate, if null the timestamp is used
1405
+ * @param string|Zend_Locale $locale Locale for parsing input
1406
+ * @return integer|string|Zend_Date new timestamp
1407
+ * @throws Zend_Date_Exception
1408
+ */
1409
+ private function _calculate($calc, $date, $part, $locale)
1410
+ {
1411
+ if (is_null($date)) {
1412
+ require_once 'Zend/Date/Exception.php';
1413
+ throw new Zend_Date_Exception('parameter $date must be set, null is not allowed');
1414
+ }
1415
+
1416
+ if (Zend_Locale::isLocale($part)) {
1417
+ $locale = $part;
1418
+ $part = null;
1419
+ }
1420
+
1421
+ if ($locale === null) {
1422
+ $locale = $this->getLocale();
1423
+ }
1424
+
1425
+ if ($locale instanceof Zend_Locale) {
1426
+ $locale = $locale->toString();
1427
+ }
1428
+
1429
+ // create date parts
1430
+ $year = $this->get(Zend_Date::YEAR);
1431
+ $month = $this->get(Zend_Date::MONTH_SHORT);
1432
+ $day = $this->get(Zend_Date::DAY_SHORT);
1433
+ $hour = $this->get(Zend_Date::HOUR_SHORT);
1434
+ $minute = $this->get(Zend_Date::MINUTE_SHORT);
1435
+ $second = $this->get(Zend_Date::SECOND_SHORT);
1436
+ // if object extract value
1437
+ if ($date instanceof Zend_Date) {
1438
+ $date = $date->get($part, $locale);
1439
+ }
1440
+
1441
+ if (is_array($date)) {
1442
+ if (!empty($part)) {
1443
+ switch($part) {
1444
+ // Fall through
1445
+ case Zend_Date::DAY:
1446
+ case Zend_Date::DAY_SHORT:
1447
+ if (array_key_exists('day', $date)) {
1448
+ $date = $date['day'];
1449
+ }
1450
+ break;
1451
+ // Fall through
1452
+ case Zend_Date::WEEKDAY_SHORT:
1453
+ case Zend_Date::WEEKDAY:
1454
+ case Zend_Date::WEEKDAY_8601:
1455
+ case Zend_Date::WEEKDAY_DIGIT:
1456
+ case Zend_Date::WEEKDAY_NARROW:
1457
+ case Zend_Date::WEEKDAY_NAME:
1458
+ if (array_key_exists('weekday', $date)) {
1459
+ $date = $date['weekday'];
1460
+ $part = Zend_Date::WEEKDAY_DIGIT;
1461
+ }
1462
+ break;
1463
+ case Zend_Date::DAY_OF_YEAR:
1464
+ if (array_key_exists('day_of_year', $date)) {
1465
+ $date = $date['day_of_year'];
1466
+ }
1467
+ break;
1468
+ // Fall through
1469
+ case Zend_Date::MONTH:
1470
+ case Zend_Date::MONTH_SHORT:
1471
+ case Zend_Date::MONTH_NAME:
1472
+ case Zend_Date::MONTH_NAME_SHORT:
1473
+ case Zend_Date::MONTH_NAME_NARROW:
1474
+ if (array_key_exists('month', $date)) {
1475
+ $date = $date['month'];
1476
+ }
1477
+ break;
1478
+ // Fall through
1479
+ case Zend_Date::YEAR:
1480
+ case Zend_Date::YEAR_SHORT:
1481
+ case Zend_Date::YEAR_8601:
1482
+ case Zend_Date::YEAR_SHORT_8601:
1483
+ if (array_key_exists('year', $date)) {
1484
+ $date = $date['year'];
1485
+ }
1486
+ break;
1487
+ // Fall through
1488
+ case Zend_Date::HOUR:
1489
+ case Zend_Date::HOUR_AM:
1490
+ case Zend_Date::HOUR_SHORT:
1491
+ case Zend_Date::HOUR_SHORT_AM:
1492
+ if (array_key_exists('hour', $date)) {
1493
+ $date = $date['hour'];
1494
+ }
1495
+ break;
1496
+ // Fall through
1497
+ case Zend_Date::MINUTE:
1498
+ case Zend_Date::MINUTE_SHORT:
1499
+ if (array_key_exists('minute', $date)) {
1500
+ $date = $date['minute'];
1501
+ }
1502
+ break;
1503
+ // Fall through
1504
+ case Zend_Date::SECOND:
1505
+ case Zend_Date::SECOND_SHORT:
1506
+ if (array_key_exists('second', $date)) {
1507
+ $date = $date['second'];
1508
+ }
1509
+ break;
1510
+ // Fall through
1511
+ case Zend_Date::TIMEZONE:
1512
+ case Zend_Date::TIMEZONE_NAME:
1513
+ if (array_key_exists('timezone', $date)) {
1514
+ $date = $date['timezone'];
1515
+ }
1516
+ break;
1517
+ case Zend_Date::TIMESTAMP:
1518
+ if (array_key_exists('timestamp', $date)) {
1519
+ $date = $date['timestamp'];
1520
+ }
1521
+ break;
1522
+ case Zend_Date::WEEK:
1523
+ if (array_key_exists('week', $date)) {
1524
+ $date = $date['week'];
1525
+ }
1526
+ break;
1527
+ case Zend_Date::TIMEZONE_SECS:
1528
+ if (array_key_exists('gmtsecs', $date)) {
1529
+ $date = $date['gmtsecs'];
1530
+ }
1531
+ break;
1532
+ default:
1533
+ require_once 'Zend/Date/Exception.php';
1534
+ throw new Zend_Date_Exception("datepart for part ($part) not found in array");
1535
+ break;
1536
+ }
1537
+ } else {
1538
+ $hours = 0;
1539
+ if (array_key_exists("hour", $date)) {
1540
+ $hours = $date['hour'];
1541
+ }
1542
+ $minutes = 0;
1543
+ if (array_key_exists('minute', $date)) {
1544
+ $minutes = $date['minute'];
1545
+ }
1546
+ $seconds = 0;
1547
+ if (array_key_exists('second', $date)) {
1548
+ $seconds = $date['second'];
1549
+ }
1550
+ $months = 0;
1551
+ if (array_key_exists('month', $date)) {
1552
+ $months = $date['month'];
1553
+ }
1554
+ $days = 0;
1555
+ if (array_key_exists('day', $date)) {
1556
+ $days = $date['day'];
1557
+ }
1558
+ $years = 0;
1559
+ if (array_key_exists('year', $date)) {
1560
+ $years = $date['year'];
1561
+ }
1562
+ return $this->_assign($calc, $this->mktime($hours, $minutes, $seconds, $months, $days, $years, true),
1563
+ $this->mktime($hour, $minute, $second, $month, $day, $year, true), $hour);
1564
+ }
1565
+ }
1566
+
1567
+ // $date as object, part of foreign date as own date
1568
+ switch($part) {
1569
+
1570
+ // day formats
1571
+ case Zend_Date::DAY :
1572
+ if (is_numeric($date)) {
1573
+ return $this->_assign($calc, $this->mktime(0, 0, 0, 1, 1 + intval($date), 1970, true),
1574
+ $this->mktime(0, 0, 0, 1, 1 + intval($day), 1970, true), $hour);
1575
+ }
1576
+ require_once 'Zend/Date/Exception.php';
1577
+ throw new Zend_Date_Exception("invalid date ($date) operand, day expected", $date);
1578
+ break;
1579
+
1580
+ case Zend_Date::WEEKDAY_SHORT :
1581
+ $daylist = Zend_Locale_Data::getList($locale, 'day');
1582
+ $weekday = (int) $this->get(Zend_Date::WEEKDAY_DIGIT, $locale);
1583
+ $cnt = 0;
1584
+
1585
+ foreach ($daylist as $key => $value) {
1586
+ if (strtoupper(substr($value, 0, 3)) == strtoupper($date)) {
1587
+ $found = $cnt;
1588
+ break;
1589
+ }
1590
+ ++$cnt;
1591
+ }
1592
+
1593
+ // Weekday found
1594
+ if ($cnt < 7) {
1595
+ return $this->_assign($calc, $this->mktime(0, 0, 0, 1, 1 + $found, 1970, true),
1596
+ $this->mktime(0, 0, 0, 1, 1 + $weekday, 1970, true), $hour);
1597
+ }
1598
+
1599
+ // Weekday not found
1600
+ require_once 'Zend/Date/Exception.php';
1601
+ throw new Zend_Date_Exception("invalid date ($date) operand, weekday expected", $date);
1602
+ break;
1603
+
1604
+ case Zend_Date::DAY_SHORT :
1605
+ if (is_numeric($date)) {
1606
+ return $this->_assign($calc, $this->mktime(0, 0, 0, 1, 1 + intval($date), 1970, true),
1607
+ $this->mktime(0, 0, 0, 1, 1 + intval($day), 1970, true), $hour);
1608
+ }
1609
+ require_once 'Zend/Date/Exception.php';
1610
+ throw new Zend_Date_Exception("invalid date ($date) operand, day expected", $date);
1611
+ break;
1612
+
1613
+ case Zend_Date::WEEKDAY :
1614
+ $daylist = Zend_Locale_Data::getList($locale, 'day');
1615
+ $weekday = (int) $this->get(Zend_Date::WEEKDAY_DIGIT, $locale);
1616
+ $cnt = 0;
1617
+
1618
+ foreach ($daylist as $key => $value) {
1619
+ if (strtoupper($value) == strtoupper($date)) {
1620
+ $found = $cnt;
1621
+ break;
1622
+ }
1623
+ ++$cnt;
1624
+ }
1625
+
1626
+ // Weekday found
1627
+ if ($cnt < 7) {
1628
+ return $this->_assign($calc, $this->mktime(0, 0, 0, 1, 1 + $found, 1970, true),
1629
+ $this->mktime(0, 0, 0, 1, 1 + $weekday, 1970, true), $hour);
1630
+ }
1631
+
1632
+ // Weekday not found
1633
+ require_once 'Zend/Date/Exception.php';
1634
+ throw new Zend_Date_Exception("invalid date ($date) operand, weekday expected", $date);
1635
+ break;
1636
+
1637
+ case Zend_Date::WEEKDAY_8601 :
1638
+ $weekday = (int) $this->get(Zend_Date::WEEKDAY_8601, $locale);
1639
+ if ((intval($date) > 0) and (intval($date) < 8)) {
1640
+ return $this->_assign($calc, $this->mktime(0, 0, 0, 1, 1 + intval($date), 1970, true),
1641
+ $this->mktime(0, 0, 0, 1, 1 + $weekday, 1970, true), $hour);
1642
+ }
1643
+
1644
+ // Weekday not found
1645
+ require_once 'Zend/Date/Exception.php';
1646
+ throw new Zend_Date_Exception("invalid date ($date) operand, weekday expected", $date);
1647
+ break;
1648
+
1649
+ case Zend_Date::DAY_SUFFIX :
1650
+ require_once 'Zend/Date/Exception.php';
1651
+ throw new Zend_Date_Exception('day suffix not supported', $date);
1652
+ break;
1653
+
1654
+ case Zend_Date::WEEKDAY_DIGIT :
1655
+ $weekday = (int) $this->get(Zend_Date::WEEKDAY_DIGIT, $locale);
1656
+ if (is_numeric($date) and (intval($date) >= 0) and (intval($date) < 7)) {
1657
+ return $this->_assign($calc, $this->mktime(0, 0, 0, 1, 1 + $date, 1970, true),
1658
+ $this->mktime(0, 0, 0, 1, 1 + $weekday, 1970, true), $hour);
1659
+ }
1660
+
1661
+ // Weekday not found
1662
+ require_once 'Zend/Date/Exception.php';
1663
+ throw new Zend_Date_Exception("invalid date ($date) operand, weekday expected", $date);
1664
+ break;
1665
+
1666
+ case Zend_Date::DAY_OF_YEAR :
1667
+ if (is_numeric($date)) {
1668
+ return $this->_assign($calc, $this->mktime(0, 0, 0, 1, 1 + $date, 1970, true),
1669
+ $this->mktime(0, 0, 0, $month, 1 + $day, 1970, true), $hour);
1670
+ }
1671
+ require_once 'Zend/Date/Exception.php';
1672
+ throw new Zend_Date_Exception("invalid date ($date) operand, day expected", $date);
1673
+ break;
1674
+
1675
+ case Zend_Date::WEEKDAY_NARROW :
1676
+ $daylist = Zend_Locale_Data::getList($locale, 'day', array('gregorian', 'format', 'abbreviated'));
1677
+ $weekday = (int) $this->get(Zend_Date::WEEKDAY_DIGIT, $locale);
1678
+ $cnt = 0;
1679
+ foreach ($daylist as $key => $value) {
1680
+ if (strtoupper(substr($value, 0, 1)) == strtoupper($date)) {
1681
+ $found = $cnt;
1682
+ break;
1683
+ }
1684
+ ++$cnt;
1685
+ }
1686
+
1687
+ // Weekday found
1688
+ if ($cnt < 7) {
1689
+ return $this->_assign($calc, $this->mktime(0, 0, 0, 1, 1 + $found, 1970, true),
1690
+ $this->mktime(0, 0, 0, 1, 1 + $weekday, 1970, true), $hour);
1691
+ }
1692
+
1693
+ // Weekday not found
1694
+ require_once 'Zend/Date/Exception.php';
1695
+ throw new Zend_Date_Exception("invalid date ($date) operand, weekday expected", $date);
1696
+ break;
1697
+
1698
+ case Zend_Date::WEEKDAY_NAME :
1699
+ $daylist = Zend_Locale_Data::getList($locale, 'day', array('gregorian', 'format', 'abbreviated'));
1700
+ $weekday = (int) $this->get(Zend_Date::WEEKDAY_DIGIT, $locale);
1701
+ $cnt = 0;
1702
+ foreach ($daylist as $key => $value) {
1703
+ if (strtoupper($value) == strtoupper($date)) {
1704
+ $found = $cnt;
1705
+ break;
1706
+ }
1707
+ ++$cnt;
1708
+ }
1709
+
1710
+ // Weekday found
1711
+ if ($cnt < 7) {
1712
+ return $this->_assign($calc, $this->mktime(0, 0, 0, 1, 1 + $found, 1970, true),
1713
+ $this->mktime(0, 0, 0, 1, 1 + $weekday, 1970, true), $hour);
1714
+ }
1715
+
1716
+ // Weekday not found
1717
+ require_once 'Zend/Date/Exception.php';
1718
+ throw new Zend_Date_Exception("invalid date ($date) operand, weekday expected", $date);
1719
+ break;
1720
+
1721
+
1722
+ // week formats
1723
+ case Zend_Date::WEEK :
1724
+ if (is_numeric($date)) {
1725
+ $week = (int) $this->get(Zend_Date::WEEK, $locale);
1726
+ return $this->_assign($calc, parent::mktime(0, 0, 0, 1, 1 + ($date * 7), 1970, true),
1727
+ parent::mktime(0, 0, 0, 1, 1 + ($week * 7), 1970, true), $hour);
1728
+ }
1729
+ require_once 'Zend/Date/Exception.php';
1730
+ throw new Zend_Date_Exception("invalid date ($date) operand, week expected", $date);
1731
+ break;
1732
+
1733
+
1734
+ // month formats
1735
+ case Zend_Date::MONTH_NAME :
1736
+ $monthlist = Zend_Locale_Data::getList($locale, 'month');
1737
+ $cnt = 0;
1738
+ foreach ($monthlist as $key => $value) {
1739
+ if (strtoupper($value) == strtoupper($date)) {
1740
+ $found = $key;
1741
+ break;
1742
+ }
1743
+ ++$cnt;
1744
+ }
1745
+ $date = array_search($date, $monthlist);
1746
+
1747
+ // Monthname found
1748
+ if ($cnt < 12) {
1749
+ $fixday = 0;
1750
+ if ($calc == 'add') {
1751
+ $date += $found;
1752
+ $calc = 'set';
1753
+ if (self::$_Options['extend_month'] == false) {
1754
+ $parts = $this->getDateParts($this->mktime(0, 0, 0, $date, $day, $year, true));
1755
+ if ($parts['mday'] != $day) {
1756
+ $fixday -= $parts['mday'];
1757
+ }
1758
+ }
1759
+ } else if ($calc == 'sub') {
1760
+ $date = $month - $found;
1761
+ $calc = 'set';
1762
+ if (self::$_Options['extend_month'] == false) {
1763
+ $parts = $this->getDateParts($this->mktime(0, 0, 0, $date, $day, $year, true));
1764
+ if ($parts['mday'] != $day) {
1765
+ $fixday -= $parts['mday'];
1766
+ }
1767
+ }
1768
+ }
1769
+ return $this->_assign($calc, $this->mktime(0, 0, 0, $date, $day + $fixday, $year, true),
1770
+ $this->mktime(0, 0, 0, $month, $day, $year, true), $hour);
1771
+ }
1772
+
1773
+ // Monthname not found
1774
+ require_once 'Zend/Date/Exception.php';
1775
+ throw new Zend_Date_Exception("invalid date ($date) operand, month expected", $date);
1776
+ break;
1777
+
1778
+ case Zend_Date::MONTH :
1779
+ if (is_numeric($date)) {
1780
+ $fixday = 0;
1781
+ if ($calc == 'add') {
1782
+ $date += $month;
1783
+ $calc = 'set';
1784
+ if (self::$_Options['extend_month'] == false) {
1785
+ $parts = $this->getDateParts($this->mktime(0, 0, 0, $date, $day, $year, true));
1786
+ if ($parts['mday'] != $day) {
1787
+ $fixday -= $parts['mday'];
1788
+ }
1789
+ }
1790
+ } else if ($calc == 'sub') {
1791
+ $date = $month - $date;
1792
+ $calc = 'set';
1793
+ if (self::$_Options['extend_month'] == false) {
1794
+ $parts = $this->getDateParts($this->mktime(0, 0, 0, $date, $day, $year, true));
1795
+ if ($parts['mday'] != $day) {
1796
+ $fixday -= $parts['mday'];
1797
+ }
1798
+ }
1799
+ }
1800
+ return $this->_assign($calc, $this->mktime(0, 0, 0, $date, $day + $fixday, $year, true),
1801
+ $this->mktime(0, 0, 0, $month, $day, $year, true), $hour);
1802
+ }
1803
+ require_once 'Zend/Date/Exception.php';
1804
+ throw new Zend_Date_Exception("invalid date ($date) operand, month expected", $date);
1805
+ break;
1806
+
1807
+ case Zend_Date::MONTH_NAME_SHORT :
1808
+ $monthlist = Zend_Locale_Data::getList($locale, 'month', array('gregorian', 'format', 'abbreviated'));
1809
+ $cnt = 0;
1810
+ foreach ($monthlist as $key => $value) {
1811
+ if (strtoupper($value) == strtoupper($date)) {
1812
+ $found = $key;
1813
+ break;
1814
+ }
1815
+ ++$cnt;
1816
+ }
1817
+ $date = array_search($date, $monthlist);
1818
+
1819
+ // Monthname found
1820
+ if ($cnt < 12) {
1821
+ $fixday = 0;
1822
+ if ($calc == 'add') {
1823
+ $date += $found;
1824
+ $calc = 'set';
1825
+ if (self::$_Options['extend_month'] == false) {
1826
+ $parts = $this->getDateParts($this->mktime(0, 0, 0, $date, $day, $year, true));
1827
+ if ($parts['mday'] != $day) {
1828
+ $fixday -= $parts['mday'];
1829
+ }
1830
+ }
1831
+ } else if ($calc == 'sub') {
1832
+ $date = $month - $found;
1833
+ $calc = 'set';
1834
+ if (self::$_Options['extend_month'] == false) {
1835
+ $parts = $this->getDateParts($this->mktime(0, 0, 0, $date, $day, $year, true));
1836
+ if ($parts['mday'] != $day) {
1837
+ $fixday -= $parts['mday'];
1838
+ }
1839
+ }
1840
+ }
1841
+ return $this->_assign($calc, $this->mktime(0, 0, 0, $date, $day + $fixday, $year, true),
1842
+ $this->mktime(0, 0, 0, $month, $day, $year, true), $hour);
1843
+ }
1844
+
1845
+ // Monthname not found
1846
+ require_once 'Zend/Date/Exception.php';
1847
+ throw new Zend_Date_Exception("invalid date ($date) operand, month expected", $date);
1848
+ break;
1849
+
1850
+ case Zend_Date::MONTH_SHORT :
1851
+ if (is_numeric($date)) {
1852
+ $fixday = 0;
1853
+ if ($calc == 'add') {
1854
+ $date += $month;
1855
+ $calc = 'set';
1856
+ if (self::$_Options['extend_month'] == false) {
1857
+ $parts = $this->getDateParts($this->mktime(0, 0, 0, $date, $day, $year, true));
1858
+ if ($parts['mday'] != $day) {
1859
+ $fixday -= $parts['mday'];
1860
+ }
1861
+ }
1862
+ } else if ($calc == 'sub') {
1863
+ $date = $month - $date;
1864
+ $calc = 'set';
1865
+ if (self::$_Options['extend_month'] == false) {
1866
+ $parts = $this->getDateParts($this->mktime(0, 0, 0, $date, $day, $year, true));
1867
+ if ($parts['mday'] != $day) {
1868
+ $fixday -= $parts['mday'];
1869
+ }
1870
+ }
1871
+ }
1872
+
1873
+ return $this->_assign($calc, $this->mktime(0, 0, 0, $date, $day + $fixday, $year, true),
1874
+ $this->mktime(0, 0, 0, $month, $day, $year, true), $hour);
1875
+ }
1876
+ require_once 'Zend/Date/Exception.php';
1877
+ throw new Zend_Date_Exception("invalid date ($date) operand, month expected", $date);
1878
+ break;
1879
+
1880
+ case Zend_Date::MONTH_DAYS :
1881
+ require_once 'Zend/Date/Exception.php';
1882
+ throw new Zend_Date_Exception('month days not supported', $date);
1883
+ break;
1884
+
1885
+
1886
+ case Zend_Date::MONTH_NAME_NARROW :
1887
+ $monthlist = Zend_Locale_Data::getList($locale, 'month', array('gregorian', 'stand-alone', 'narrow'));
1888
+ $cnt = 0;
1889
+ foreach ($monthlist as $key => $value) {
1890
+ if (strtoupper($value) == strtoupper($date)) {
1891
+ $found = $key;
1892
+ break;
1893
+ }
1894
+ ++$cnt;
1895
+ }
1896
+ $date = array_search($date, $monthlist);
1897
+
1898
+ // Monthname found
1899
+ if ($cnt < 12) {
1900
+ $fixday = 0;
1901
+ if ($calc == 'add') {
1902
+ $date += $found;
1903
+ $calc = 'set';
1904
+ if (self::$_Options['extend_month'] == false) {
1905
+ $parts = $this->getDateParts($this->mktime(0, 0, 0, $date, $day, $year, true));
1906
+ if ($parts['mday'] != $day) {
1907
+ $fixday -= $parts['mday'];
1908
+ }
1909
+ }
1910
+ } else if ($calc == 'sub') {
1911
+ $date = $month - $found;
1912
+ $calc = 'set';
1913
+ if (self::$_Options['extend_month'] == false) {
1914
+ $parts = $this->getDateParts($this->mktime(0, 0, 0, $date, $day, $year, true));
1915
+ if ($parts['mday'] != $day) {
1916
+ $fixday -= $parts['mday'];
1917
+ }
1918
+ }
1919
+ }
1920
+ return $this->_assign($calc, $this->mktime(0, 0, 0, $date, $day + $fixday, $year, true),
1921
+ $this->mktime(0, 0, 0, $month, $day, $year, true), $hour);
1922
+ }
1923
+
1924
+ // Monthname not found
1925
+ require_once 'Zend/Date/Exception.php';
1926
+ throw new Zend_Date_Exception("invalid date ($date) operand, month expected", $date);
1927
+ break;
1928
+
1929
+
1930
+ // year formats
1931
+ case Zend_Date::LEAPYEAR :
1932
+ require_once 'Zend/Date/Exception.php';
1933
+ throw new Zend_Date_Exception('leap year not supported', $date);
1934
+ break;
1935
+
1936
+ case Zend_Date::YEAR_8601 :
1937
+ if (is_numeric($date)) {
1938
+ if ($calc == 'add') {
1939
+ $date += $year;
1940
+ $calc = 'set';
1941
+ } else if ($calc == 'sub') {
1942
+ $date = $year - $date;
1943
+ $calc = 'set';
1944
+ }
1945
+ return $this->_assign($calc, $this->mktime(0, 0, 0, $month, $day, intval($date), true),
1946
+ $this->mktime(0, 0, 0, $month, $day, $year, true), false);
1947
+ }
1948
+ require_once 'Zend/Date/Exception.php';
1949
+ throw new Zend_Date_Exception("invalid date ($date) operand, year expected", $date);
1950
+ break;
1951
+
1952
+ case Zend_Date::YEAR :
1953
+ if (is_numeric($date)) {
1954
+ if ($calc == 'add') {
1955
+ $date += $year;
1956
+ $calc = 'set';
1957
+ } else if ($calc == 'sub') {
1958
+ $date = $year - $date;
1959
+ $calc = 'set';
1960
+ }
1961
+ return $this->_assign($calc, $this->mktime(0, 0, 0, $month, $day, intval($date), true),
1962
+ $this->mktime(0, 0, 0, $month, $day, $year, true), false);
1963
+ }
1964
+ require_once 'Zend/Date/Exception.php';
1965
+ throw new Zend_Date_Exception("invalid date ($date) operand, year expected", $date);
1966
+ break;
1967
+
1968
+ case Zend_Date::YEAR_SHORT :
1969
+ if (is_numeric($date)) {
1970
+ $date = intval($date);
1971
+ if ($calc == 'set') {
1972
+ $date = self::_century($date);
1973
+ }
1974
+ if ($calc == 'add') {
1975
+ $date += $year;
1976
+ $calc = 'set';
1977
+ } else if ($calc == 'sub') {
1978
+ $date = $year - $date;
1979
+ $calc = 'set';
1980
+ }
1981
+ return $this->_assign($calc, $this->mktime(0, 0, 0, $month, $day, $date, true),
1982
+ $this->mktime(0, 0, 0, $month, $day, $year, true), false);
1983
+ }
1984
+ require_once 'Zend/Date/Exception.php';
1985
+ throw new Zend_Date_Exception("invalid date ($date) operand, year expected", $date);
1986
+ break;
1987
+
1988
+
1989
+ case Zend_Date::YEAR_SHORT_8601 :
1990
+ if (is_numeric($date)) {
1991
+ $date = intval($date);
1992
+ if ($calc == 'set') {
1993
+ $date = self::_century($date);
1994
+ }
1995
+ if ($calc == 'add') {
1996
+ $date += $year;
1997
+ $calc = 'set';
1998
+ } else if ($calc == 'sub') {
1999
+ $date = $year - $date;
2000
+ $calc = 'set';
2001
+ }
2002
+ return $this->_assign($calc, $this->mktime(0, 0, 0, $month, $day, $date, true),
2003
+ $this->mktime(0, 0, 0, $month, $day, $year, true), false);
2004
+ }
2005
+ require_once 'Zend/Date/Exception.php';
2006
+ throw new Zend_Date_Exception("invalid date ($date) operand, year expected", $date);
2007
+ break;
2008
+
2009
+
2010
+ // time formats
2011
+ case Zend_Date::MERIDIEM :
2012
+ require_once 'Zend/Date/Exception.php';
2013
+ throw new Zend_Date_Exception('meridiem not supported', $date);
2014
+ break;
2015
+
2016
+ case Zend_Date::SWATCH :
2017
+ if (is_numeric($date)) {
2018
+ $rest = intval($date);
2019
+ $hours = floor($rest * 24 / 1000);
2020
+ $rest = $rest - ($hours * 1000 / 24);
2021
+ $minutes = floor($rest * 1440 / 1000);
2022
+ $rest = $rest - ($minutes * 1000 / 1440);
2023
+ $seconds = floor($rest * 86400 / 1000);
2024
+ return $this->_assign($calc, $this->mktime($hours, $minutes, $seconds, 1, 1, 1970, true),
2025
+ $this->mktime($hour, $minute, $second, 1, 1, 1970, true), false);
2026
+ }
2027
+ require_once 'Zend/Date/Exception.php';
2028
+ throw new Zend_Date_Exception("invalid date ($date) operand, swatchstamp expected", $date);
2029
+ break;
2030
+
2031
+ case Zend_Date::HOUR_SHORT_AM :
2032
+ if (is_numeric($date)) {
2033
+ return $this->_assign($calc, $this->mktime(intval($date), 0, 0, 1, 1, 1970, true),
2034
+ $this->mktime($hour, 0, 0, 1, 1, 1970, true), false);
2035
+ }
2036
+ require_once 'Zend/Date/Exception.php';
2037
+ throw new Zend_Date_Exception("invalid date ($date) operand, hour expected", $date);
2038
+ break;
2039
+
2040
+ case Zend_Date::HOUR_SHORT :
2041
+ if (is_numeric($date)) {
2042
+ return $this->_assign($calc, $this->mktime(intval($date), 0, 0, 1, 1, 1970, true),
2043
+ $this->mktime($hour, 0, 0, 1, 1, 1970, true), false);
2044
+ }
2045
+ require_once 'Zend/Date/Exception.php';
2046
+ throw new Zend_Date_Exception("invalid date ($date) operand, hour expected", $date);
2047
+ break;
2048
+
2049
+ case Zend_Date::HOUR_AM :
2050
+ if (is_numeric($date)) {
2051
+ return $this->_assign($calc, $this->mktime(intval($date), 0, 0, 1, 1, 1970, true),
2052
+ $this->mktime($hour, 0, 0, 1, 1, 1970, true), false);
2053
+ }
2054
+ require_once 'Zend/Date/Exception.php';
2055
+ throw new Zend_Date_Exception("invalid date ($date) operand, hour expected", $date);
2056
+ break;
2057
+
2058
+ case Zend_Date::HOUR :
2059
+ if (is_numeric($date)) {
2060
+ return $this->_assign($calc, $this->mktime(intval($date), 0, 0, 1, 1, 1970, true),
2061
+ $this->mktime($hour, 0, 0, 1, 1, 1970, true), false);
2062
+ }
2063
+ require_once 'Zend/Date/Exception.php';
2064
+ throw new Zend_Date_Exception("invalid date ($date) operand, hour expected", $date);
2065
+ break;
2066
+
2067
+ case Zend_Date::MINUTE :
2068
+ if (is_numeric($date)) {
2069
+ return $this->_assign($calc, $this->mktime(0, intval($date), 0, 1, 1, 1970, true),
2070
+ $this->mktime(0, $minute, 0, 1, 1, 1970, true), false);
2071
+ }
2072
+ require_once 'Zend/Date/Exception.php';
2073
+ throw new Zend_Date_Exception("invalid date ($date) operand, minute expected", $date);
2074
+ break;
2075
+
2076
+ case Zend_Date::SECOND :
2077
+ if (is_numeric($date)) {
2078
+ return $this->_assign($calc, $this->mktime(0, 0, intval($date), 1, 1, 1970, true),
2079
+ $this->mktime(0, 0, $second, 1, 1, 1970, true), false);
2080
+ }
2081
+ require_once 'Zend/Date/Exception.php';
2082
+ throw new Zend_Date_Exception("invalid date ($date) operand, second expected", $date);
2083
+ break;
2084
+
2085
+ case Zend_Date::MILLISECOND :
2086
+ if (is_numeric($date)) {
2087
+ switch($calc) {
2088
+ case 'set' :
2089
+ return $this->setMillisecond($date);
2090
+ break;
2091
+ case 'add' :
2092
+ return $this->addMillisecond($date);
2093
+ break;
2094
+ case 'sub' :
2095
+ return $this->subMillisecond($date);
2096
+ break;
2097
+ }
2098
+ return $this->compareMillisecond($date);
2099
+ }
2100
+ require_once 'Zend/Date/Exception.php';
2101
+ throw new Zend_Date_Exception("invalid date ($date) operand, milliseconds expected", $date);
2102
+ break;
2103
+
2104
+ case Zend_Date::MINUTE_SHORT :
2105
+ if (is_numeric($date)) {
2106
+ return $this->_assign($calc, $this->mktime(0, intval($date), 0, 1, 1, 1970, true),
2107
+ $this->mktime(0, $minute, 0, 1, 1, 1970, true), false);
2108
+ }
2109
+ require_once 'Zend/Date/Exception.php';
2110
+ throw new Zend_Date_Exception("invalid date ($date) operand, minute expected", $date);
2111
+ break;
2112
+
2113
+ case Zend_Date::SECOND_SHORT :
2114
+ if (is_numeric($date)) {
2115
+ return $this->_assign($calc, $this->mktime(0, 0, intval($date), 1, 1, 1970, true),
2116
+ $this->mktime(0, 0, $second, 1, 1, 1970, true), false);
2117
+ }
2118
+ require_once 'Zend/Date/Exception.php';
2119
+ throw new Zend_Date_Exception("invalid date ($date) operand, second expected", $date);
2120
+ break;
2121
+
2122
+
2123
+ // timezone formats
2124
+ // break intentionally omitted
2125
+ case Zend_Date::TIMEZONE_NAME :
2126
+ case Zend_Date::TIMEZONE :
2127
+ case Zend_Date::TIMEZONE_SECS :
2128
+ require_once 'Zend/Date/Exception.php';
2129
+ throw new Zend_Date_Exception('timezone not supported', $date);
2130
+ break;
2131
+
2132
+ case Zend_Date::DAYLIGHT :
2133
+ require_once 'Zend/Date/Exception.php';
2134
+ throw new Zend_Date_Exception('daylight not supported', $date);
2135
+ break;
2136
+
2137
+ case Zend_Date::GMT_DIFF :
2138
+ case Zend_Date::GMT_DIFF_SEP :
2139
+ require_once 'Zend/Date/Exception.php';
2140
+ throw new Zend_Date_Exception('gmtdiff not supported', $date);
2141
+ break;
2142
+
2143
+
2144
+ // date strings
2145
+ case Zend_Date::ISO_8601 :
2146
+ // (-)YYYY-MM-dd
2147
+ preg_match('/^(-{0,1}\d{4})-(\d{2})-(\d{2})/', $date, $datematch);
2148
+ // (-)YY-MM-dd
2149
+ if (empty($datematch)) {
2150
+ preg_match('/^(-{0,1}\d{2})-(\d{2})-(\d{2})/', $date, $datematch);
2151
+ }
2152
+ // (-)YYYYMMdd
2153
+ if (empty($datematch)) {
2154
+ preg_match('/^(-{0,1}\d{4})(\d{2})(\d{2})/', $date, $datematch);
2155
+ }
2156
+ // (-)YYMMdd
2157
+ if (empty($datematch)) {
2158
+ preg_match('/^(-{0,1}\d{2})(\d{2})(\d{2})/', $date, $datematch);
2159
+ }
2160
+ $tmpdate = $date;
2161
+ if (!empty($datematch)) {
2162
+ $tmpdate = substr($date, strlen($datematch[0]));
2163
+ }
2164
+ // (T)hh:mm:ss
2165
+ preg_match('/[T,\s]{0,1}(\d{2}):(\d{2}):(\d{2})/', $tmpdate, $timematch);
2166
+ if (empty($timematch)) {
2167
+ preg_match('/[T,\s]{0,1}(\d{2})(\d{2})(\d{2})/', $tmpdate, $timematch);
2168
+ }
2169
+ if (empty($datematch) and empty($timematch)) {
2170
+ require_once 'Zend/Date/Exception.php';
2171
+ throw new Zend_Date_Exception("unsupported ISO8601 format ($date)", $date);
2172
+ }
2173
+ if (!empty($timematch)) {
2174
+ $tmpdate = substr($tmpdate, strlen($timematch[0]));
2175
+ }
2176
+ if (empty($datematch)) {
2177
+ $datematch[1] = 1970;
2178
+ $datematch[2] = 1;
2179
+ $datematch[3] = 1;
2180
+ } else if (strlen($datematch[1]) == 2) {
2181
+ $datematch[1] = self::_century($datematch[1]);
2182
+ }
2183
+ if (empty($timematch)) {
2184
+ $timematch[1] = 0;
2185
+ $timematch[2] = 0;
2186
+ $timematch[3] = 0;
2187
+ }
2188
+
2189
+ if ($calc == 'set') {
2190
+ --$datematch[2];
2191
+ --$month;
2192
+ --$datematch[3];
2193
+ --$day;
2194
+ $datematch[1] -= 1970;
2195
+ $year -= 1970;
2196
+ }
2197
+ return $this->_assign($calc, $this->mktime($timematch[1], $timematch[2], $timematch[3], 1 + $datematch[2], 1 + $datematch[3], 1970 + $datematch[1], false),
2198
+ $this->mktime($hour, $minute, $second, 1 + $month, 1 + $day, 1970 + $year, false), false);
2199
+ break;
2200
+
2201
+ case Zend_Date::RFC_2822 :
2202
+ $result = preg_match('/^\w{3},\s(\d{2})\s(\w{3})\s(\d{4})\s(\d{2}):(\d{2}):(\d{2})\s\+\d{4}$/', $date, $match);
2203
+ if (!$result) {
2204
+ require_once 'Zend/Date/Exception.php';
2205
+ throw new Zend_Date_Exception("no RFC 2822 format ($date)", $date);
2206
+ }
2207
+
2208
+ $months = $this->getDigitFromName($match[2]);
2209
+
2210
+ if ($calc == 'set') {
2211
+ --$months;
2212
+ --$month;
2213
+ --$match[1];
2214
+ --$day;
2215
+ $match[3] -= 1970;
2216
+ $year -= 1970;
2217
+ }
2218
+ return $this->_assign($calc, $this->mktime($match[4], $match[5], $match[6], 1 + $months, 1 + $match[1], 1970 + $match[3], false),
2219
+ $this->mktime($hour, $minute, $second, 1 + $month, 1 + $day, 1970 + $year, false), false);
2220
+ break;
2221
+
2222
+ case Zend_Date::TIMESTAMP :
2223
+ if (is_numeric($date)) {
2224
+ return $this->_assign($calc, $date, $this->getUnixTimestamp());
2225
+ }
2226
+ require_once 'Zend/Date/Exception.php';
2227
+ throw new Zend_Date_Exception("invalid date ($date) operand, timestamp expected", $date);
2228
+ break;
2229
+
2230
+
2231
+ // additional formats
2232
+ // break intentionally omitted
2233
+ case Zend_Date::ERA :
2234
+ case Zend_Date::ERA_NAME :
2235
+ require_once 'Zend/Date/Exception.php';
2236
+ throw new Zend_Date_Exception('era not supported', $date);
2237
+ break;
2238
+
2239
+ case Zend_Date::DATES :
2240
+ try {
2241
+ $parsed = Zend_Locale_Format::getDate($date, array('locale' => $locale, 'format_type' => 'iso', 'fix_date' => true));
2242
+
2243
+ if ($calc == 'set') {
2244
+ --$parsed['month'];
2245
+ --$month;
2246
+ --$parsed['day'];
2247
+ --$day;
2248
+ $parsed['year'] -= 1970;
2249
+ $year -= 1970;
2250
+ }
2251
+ return $this->_assign($calc, $this->mktime(0, 0, 0, 1 + $parsed['month'], 1 + $parsed['day'], 1970 + $parsed['year'], true),
2252
+ $this->mktime(0, 0, 0, 1 + $month, 1 + $day, 1970 + $year, true), $hour);
2253
+ } catch (Zend_Locale_Exception $e) {
2254
+ require_once 'Zend/Date/Exception.php';
2255
+ throw new Zend_Date_Exception($e->getMessage(), $date);
2256
+ }
2257
+ break;
2258
+
2259
+ case Zend_Date::DATE_FULL :
2260
+ try {
2261
+ $format = Zend_Locale_Data::getContent($locale, 'date', array('gregorian', 'full'));
2262
+ $parsed = Zend_Locale_Format::getDate($date, array('date_format' => $format, 'format_type' => 'iso', 'locale' => $locale));
2263
+
2264
+ if ($calc == 'set') {
2265
+ --$parsed['month'];
2266
+ --$month;
2267
+ --$parsed['day'];
2268
+ --$day;
2269
+ $parsed['year'] -= 1970;
2270
+ $year -= 1970;
2271
+ }
2272
+ return $this->_assign($calc, $this->mktime(0, 0, 0, 1 + $parsed['month'], 1 + $parsed['day'], 1970 + $parsed['year'], true),
2273
+ $this->mktime(0, 0, 0, 1 + $month, 1 + $day, 1970 + $year, true), $hour);
2274
+ } catch (Zend_Locale_Exception $e) {
2275
+ require_once 'Zend/Date/Exception.php';
2276
+ throw new Zend_Date_Exception($e->getMessage(), $date);
2277
+ }
2278
+ break;
2279
+
2280
+ case Zend_Date::DATE_LONG :
2281
+ try {
2282
+ $format = Zend_Locale_Data::getContent($locale, 'date', array('gregorian', 'long'));
2283
+ $parsed = Zend_Locale_Format::getDate($date, array('date_format' => $format, 'format_type' => 'iso', 'locale' => $locale));
2284
+
2285
+ if ($calc == 'set') {
2286
+ --$parsed['month'];
2287
+ --$month;
2288
+ --$parsed['day'];
2289
+ --$day;
2290
+ $parsed['year'] -= 1970;
2291
+ $year -= 1970;
2292
+ }
2293
+ return $this->_assign($calc, $this->mktime(0, 0, 0, 1 + $parsed['month'], 1 + $parsed['day'], 1970 + $parsed['year'], true),
2294
+ $this->mktime(0, 0, 0, 1 + $month, 1 + $day, 1970 + $year, true), $hour);
2295
+ } catch (Zend_Locale_Exception $e) {
2296
+ require_once 'Zend/Date/Exception.php';
2297
+ throw new Zend_Date_Exception($e->getMessage(), $date);
2298
+ }
2299
+ break;
2300
+
2301
+ case Zend_Date::DATE_MEDIUM :
2302
+ try {
2303
+ $format = Zend_Locale_Data::getContent($locale, 'date', array('gregorian', 'medium'));
2304
+ $parsed = Zend_Locale_Format::getDate($date, array('date_format' => $format, 'format_type' => 'iso', 'locale' => $locale));
2305
+
2306
+ if ($calc == 'set') {
2307
+ --$parsed['month'];
2308
+ --$month;
2309
+ --$parsed['day'];
2310
+ --$day;
2311
+ $parsed['year'] -= 1970;
2312
+ $year -= 1970;
2313
+ }
2314
+ return $this->_assign($calc, $this->mktime(0, 0, 0, 1 + $parsed['month'], 1 + $parsed['day'], 1970 + $parsed['year'], true),
2315
+ $this->mktime(0, 0, 0, 1 + $month, 1 + $day, 1970 + $year, true), $hour);
2316
+ } catch (Zend_Locale_Exception $e) {
2317
+ require_once 'Zend/Date/Exception.php';
2318
+ throw new Zend_Date_Exception($e->getMessage(), $date);
2319
+ }
2320
+ break;
2321
+
2322
+ case Zend_Date::DATE_SHORT :
2323
+ try {
2324
+ $format = Zend_Locale_Data::getContent($locale, 'date', array('gregorian', 'short'));
2325
+ $parsed = Zend_Locale_Format::getDate($date, array('date_format' => $format, 'format_type' => 'iso', 'locale' => $locale));
2326
+
2327
+ $parsed['year'] = self::_century($parsed['year']);
2328
+
2329
+ if ($calc == 'set') {
2330
+ --$parsed['month'];
2331
+ --$month;
2332
+ --$parsed['day'];
2333
+ --$day;
2334
+ $parsed['year'] -= 1970;
2335
+ $year -= 1970;
2336
+ }
2337
+ return $this->_assign($calc, $this->mktime(0, 0, 0, 1 + $parsed['month'], 1 + $parsed['day'], 1970 + $parsed['year'], true),
2338
+ $this->mktime(0, 0, 0, 1 + $month, 1 + $day, 1970 + $year, true), $hour);
2339
+ } catch (Zend_Locale_Exception $e) {
2340
+ require_once 'Zend/Date/Exception.php';
2341
+ throw new Zend_Date_Exception($e->getMessage(), $date);
2342
+ }
2343
+ break;
2344
+
2345
+ case Zend_Date::TIMES :
2346
+ try {
2347
+ if ($calc != 'set') {
2348
+ $month = 1;
2349
+ $day = 1;
2350
+ $year = 1970;
2351
+ }
2352
+ $parsed = Zend_Locale_Format::getTime($date, array('locale' => $locale, 'format_type' => 'iso', 'fix_date' => true));
2353
+ return $this->_assign($calc, $this->mktime($parsed['hour'], $parsed['minute'], $parsed['second'], $month, $day, $year, true),
2354
+ $this->mktime($hour, $minute, $second, $month, $day, $year, true), false);
2355
+ } catch (Zend_Locale_Exception $e) {
2356
+ require_once 'Zend/Date/Exception.php';
2357
+ throw new Zend_Date_Exception($e->getMessage(), $date);
2358
+ }
2359
+ break;
2360
+
2361
+ case Zend_Date::TIME_FULL :
2362
+ try {
2363
+ $format = Zend_Locale_Data::getContent($locale, 'time', array('gregorian', 'full'));
2364
+ $parsed = Zend_Locale_Format::getTime($date, array('date_format' => $format, 'format_type' => 'iso', 'locale' => $locale));
2365
+ if ($calc != 'set') {
2366
+ $month = 1;
2367
+ $day = 1;
2368
+ $year = 1970;
2369
+ }
2370
+ return $this->_assign($calc, $this->mktime($parsed['hour'], $parsed['minute'], 0, $month, $day, $year, true),
2371
+ $this->mktime($hour, $minute, $second, $month, $day, $year, true), false);
2372
+ } catch (Zend_Locale_Exception $e) {
2373
+ require_once 'Zend/Date/Exception.php';
2374
+ throw new Zend_Date_Exception($e->getMessage(), $date);
2375
+ }
2376
+ break;
2377
+
2378
+ case Zend_Date::TIME_LONG :
2379
+ try {
2380
+ $format = Zend_Locale_Data::getContent($locale, 'time', array('gregorian', 'long'));
2381
+ $parsed = Zend_Locale_Format::getTime($date, array('date_format' => $format, 'format_type' => 'iso', 'locale' => $locale));
2382
+ if ($calc != 'set') {
2383
+ $month = 1;
2384
+ $day = 1;
2385
+ $year = 1970;
2386
+ }
2387
+ return $this->_assign($calc, $this->mktime($parsed['hour'], $parsed['minute'], $parsed['second'], $month, $day, $year, true),
2388
+ $this->mktime($hour, $minute, $second, $month, $day, $year, true), false);
2389
+ } catch (Zend_Locale_Exception $e) {
2390
+ require_once 'Zend/Date/Exception.php';
2391
+ throw new Zend_Date_Exception($e->getMessage(), $date);
2392
+ }
2393
+ break;
2394
+
2395
+ case Zend_Date::TIME_MEDIUM :
2396
+ try {
2397
+ $format = Zend_Locale_Data::getContent($locale, 'time', array('gregorian', 'medium'));
2398
+ $parsed = Zend_Locale_Format::getTime($date, array('date_format' => $format, 'format_type' => 'iso', 'locale' => $locale));
2399
+ if ($calc != 'set') {
2400
+ $month = 1;
2401
+ $day = 1;
2402
+ $year = 1970;
2403
+ }
2404
+ return $this->_assign($calc, $this->mktime($parsed['hour'], $parsed['minute'], $parsed['second'], $month, $day, $year, true),
2405
+ $this->mktime($hour, $minute, $second, $month, $day, $year, true), false);
2406
+ } catch (Zend_Locale_Exception $e) {
2407
+ require_once 'Zend/Date/Exception.php';
2408
+ throw new Zend_Date_Exception($e->getMessage(), $date);
2409
+ }
2410
+ break;
2411
+
2412
+ case Zend_Date::TIME_SHORT :
2413
+ try {
2414
+ $format = Zend_Locale_Data::getContent($locale, 'time', array('gregorian', 'short'));
2415
+ $parsed = Zend_Locale_Format::getTime($date, array('date_format' => $format, 'format_type' => 'iso', 'locale' => $locale));
2416
+ if ($calc != 'set') {
2417
+ $month = 1;
2418
+ $day = 1;
2419
+ $year = 1970;
2420
+ }
2421
+ return $this->_assign($calc, $this->mktime($parsed['hour'], $parsed['minute'], 0, $month, $day, $year, true),
2422
+ $this->mktime($hour, $minute, $second, $month, $day, $year, true), false);
2423
+ } catch (Zend_Locale_Exception $e) {
2424
+ require_once 'Zend/Date/Exception.php';
2425
+ throw new Zend_Date_Exception($e->getMessage(), $date);
2426
+ }
2427
+ break;
2428
+
2429
+ // ATOM and RFC_3339 are identical
2430
+ case Zend_Date::ATOM :
2431
+ case Zend_Date::RFC_3339:
2432
+ $result = preg_match('/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})\d{0,4}([+-]{1}\d{2}:\d{2}|Z)$/', $date, $match);
2433
+ if (!$result) {
2434
+ require_once 'Zend/Date/Exception.php';
2435
+ throw new Zend_Date_Exception("invalid date ($date) operand, ATOM format expected", $date);
2436
+ }
2437
+
2438
+ if ($calc == 'set') {
2439
+ --$match[2];
2440
+ --$month;
2441
+ --$match[3];
2442
+ --$day;
2443
+ $match[1] -= 1970;
2444
+ $year -= 1970;
2445
+ }
2446
+ return $this->_assign($calc, $this->mktime($match[4], $match[5], $match[6], 1 + $match[2], 1 + $match[3], 1970 + $match[1], true),
2447
+ $this->mktime($hour, $minute, $second, 1 + $month, 1 + $day, 1970 + $year, true), false);
2448
+ break;
2449
+
2450
+ case Zend_Date::COOKIE :
2451
+ $result = preg_match("/^\w{6,9},\s(\d{2})-(\w{3})-(\d{2})\s(\d{2}):(\d{2}):(\d{2})\s.{3,20}$/", $date, $match);
2452
+ if (!$result) {
2453
+ require_once 'Zend/Date/Exception.php';
2454
+ throw new Zend_Date_Exception("invalid date ($date) operand, COOKIE format expected", $date);
2455
+ }
2456
+ $match[0] = substr($match[0], strpos($match[0], ' ')+1);
2457
+
2458
+ $months = $this->getDigitFromName($match[2]);
2459
+ $match[3] = self::_century($match[3]);
2460
+
2461
+ if ($calc == 'set') {
2462
+ --$months;
2463
+ --$month;
2464
+ --$match[1];
2465
+ --$day;
2466
+ $match[3] -= 1970;
2467
+ $year -= 1970;
2468
+ }
2469
+ return $this->_assign($calc, $this->mktime($match[4], $match[5], $match[6], 1 + $months, 1 + $match[1], 1970 + $match[3], true),
2470
+ $this->mktime($hour, $minute, $second, 1 + $month, 1 + $day, 1970 + $year, true), false);
2471
+ break;
2472
+
2473
+ case Zend_Date::RFC_822 :
2474
+ // new RFC 822 format
2475
+ $result = preg_match('/^\w{3},\s(\d{2})\s(\w{3})\s(\d{2})\s(\d{2}):(\d{2}):(\d{2})\s([+-]{1}\d{4}|\w{1,20})$/', $date, $match);
2476
+ if (!$result) {
2477
+ require_once 'Zend/Date/Exception.php';
2478
+ throw new Zend_Date_Exception("invalid date ($date) operand, RFC 822 date format expected", $date);
2479
+ }
2480
+
2481
+ $months = $this->getDigitFromName($match[2]);
2482
+ $match[3] = self::_century($match[3]);
2483
+
2484
+ if ($calc == 'set') {
2485
+ --$months;
2486
+ --$month;
2487
+ --$match[1];
2488
+ --$day;
2489
+ $match[3] -= 1970;
2490
+ $year -= 1970;
2491
+ }
2492
+ return $this->_assign($calc, $this->mktime($match[4], $match[5], $match[6], 1 + $months, 1 + $match[1], 1970 + $match[3], false),
2493
+ $this->mktime($hour, $minute, $second, 1 + $month, 1 + $day, 1970 + $year, false), false);
2494
+ break;
2495
+
2496
+ case Zend_Date::RFC_850 :
2497
+ $result = preg_match('/^\w{6,9},\s(\d{2})-(\w{3})-(\d{2})\s(\d{2}):(\d{2}):(\d{2})\s.{3,21}$/', $date, $match);
2498
+ if (!$result) {
2499
+ require_once 'Zend/Date/Exception.php';
2500
+ throw new Zend_Date_Exception("invalid date ($date) operand, RFC 850 date format expected", $date);
2501
+ }
2502
+
2503
+ $months = $this->getDigitFromName($match[2]);
2504
+ $match[3] = self::_century($match[3]);
2505
+
2506
+ if ($calc == 'set') {
2507
+ --$months;
2508
+ --$month;
2509
+ --$match[1];
2510
+ --$day;
2511
+ $match[3] -= 1970;
2512
+ $year -= 1970;
2513
+ }
2514
+ return $this->_assign($calc, $this->mktime($match[4], $match[5], $match[6], 1 + $months, 1 + $match[1], 1970 + $match[3], true),
2515
+ $this->mktime($hour, $minute, $second, 1 + $month, 1 + $day, 1970 + $year, true), false);
2516
+ break;
2517
+
2518
+ case Zend_Date::RFC_1036 :
2519
+ $result = preg_match('/^\w{3},\s(\d{2})\s(\w{3})\s(\d{2})\s(\d{2}):(\d{2}):(\d{2})\s[+-]{1}\d{4}$/', $date, $match);
2520
+ if (!$result) {
2521
+ require_once 'Zend/Date/Exception.php';
2522
+ throw new Zend_Date_Exception("invalid date ($date) operand, RFC 1036 date format expected", $date);
2523
+ }
2524
+
2525
+ $months = $this->getDigitFromName($match[2]);
2526
+ $match[3] = self::_century($match[3]);
2527
+
2528
+ if ($calc == 'set') {
2529
+ --$months;
2530
+ --$month;
2531
+ --$match[1];
2532
+ --$day;
2533
+ $match[3] -= 1970;
2534
+ $year -= 1970;
2535
+ }
2536
+ return $this->_assign($calc, $this->mktime($match[4], $match[5], $match[6], 1 + $months, 1 + $match[1], 1970 + $match[3], true),
2537
+ $this->mktime($hour, $minute, $second, 1 + $month, 1 + $day, 1970 + $year, true), false);
2538
+ break;
2539
+
2540
+ case Zend_Date::RFC_1123 :
2541
+ $result = preg_match('/^\w{3},\s(\d{2})\s(\w{3})\s(\d{4})\s(\d{2}):(\d{2}):(\d{2})\s[+-]{1}\d{4}$/', $date, $match);
2542
+ if (!$result) {
2543
+ require_once 'Zend/Date/Exception.php';
2544
+ throw new Zend_Date_Exception("invalid date ($date) operand, RFC 1123 date format expected", $date);
2545
+ }
2546
+
2547
+ $months = $this->getDigitFromName($match[2]);
2548
+
2549
+ if ($calc == 'set') {
2550
+ --$months;
2551
+ --$month;
2552
+ --$match[1];
2553
+ --$day;
2554
+ $match[3] -= 1970;
2555
+ $year -= 1970;
2556
+ }
2557
+ return $this->_assign($calc, $this->mktime($match[4], $match[5], $match[6], 1 + $months, 1 + $match[1], 1970 + $match[3], true),
2558
+ $this->mktime($hour, $minute, $second, 1 + $month, 1 + $day, 1970 + $year, true), false);
2559
+ break;
2560
+
2561
+ case Zend_Date::RSS :
2562
+ $result = preg_match('/^\w{3},\s(\d{2})\s(\w{3})\s(\d{2,4})\s(\d{1,2}):(\d{2}):(\d{2})\s.{1,21}$/', $date, $match);
2563
+ if (!$result) {
2564
+ require_once 'Zend/Date/Exception.php';
2565
+ throw new Zend_Date_Exception("invalid date ($date) operand, RSS date format expected", $date);
2566
+ }
2567
+
2568
+ $months = $this->getDigitFromName($match[2]);
2569
+ $match[3] = self::_century($match[3]);
2570
+
2571
+ if ($calc == 'set') {
2572
+ --$months;
2573
+ --$month;
2574
+ --$match[1];
2575
+ --$day;
2576
+ $match[3] -= 1970;
2577
+ $year -= 1970;
2578
+ }
2579
+ return $this->_assign($calc, $this->mktime($match[4], $match[5], $match[6], 1 + $months, 1 + $match[1], 1970 + $match[3], true),
2580
+ $this->mktime($hour, $minute, $second, 1 + $month, 1 + $day, 1970 + $year, true), false);
2581
+ break;
2582
+
2583
+ case Zend_Date::W3C :
2584
+ $result = preg_match('/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})[+-]{1}\d{2}:\d{2}$/', $date, $match);
2585
+ if (!$result) {
2586
+ require_once 'Zend/Date/Exception.php';
2587
+ throw new Zend_Date_Exception("invalid date ($date) operand, W3C date format expected", $date);
2588
+ }
2589
+
2590
+ if ($calc == 'set') {
2591
+ --$match[2];
2592
+ --$month;
2593
+ --$match[3];
2594
+ --$day;
2595
+ $match[1] -= 1970;
2596
+ $year -= 1970;
2597
+ }
2598
+ return $this->_assign($calc, $this->mktime($match[4], $match[5], $match[6], 1 + $match[2], 1 + $match[3], 1970 + $match[1], true),
2599
+ $this->mktime($hour, $minute, $second, 1 + $month, 1 + $day, 1970 + $year, true), false);
2600
+ break;
2601
+
2602
+ default :
2603
+ if (!is_numeric($date) || !empty($part)) {
2604
+ try {
2605
+ if (self::$_Options['format_type'] == 'php') {
2606
+ $part = Zend_Locale_Format::convertPhpToIsoFormat($part);
2607
+ }
2608
+ if (empty($part)) {
2609
+ $part = Zend_Locale_Format::getDateFormat($locale) . " ";
2610
+ $part .= Zend_Locale_Format::getTimeFormat($locale);
2611
+ }
2612
+ $parsed = Zend_Locale_Format::getDate($date, array('date_format' => $part, 'locale' => $locale, 'fix_date' => true, 'format_type' => 'iso'));
2613
+ if ((strpos(strtoupper($part), 'YY') !== false) and (strpos(strtoupper($part), 'YYYY') === false)) {
2614
+ $parsed['year'] = self::_century($parsed['year']);
2615
+ }
2616
+ if ($calc == 'set') {
2617
+ if (isset($parsed['month'])) {
2618
+ --$parsed['month'];
2619
+ } else {
2620
+ $parsed['month'] = 0;
2621
+ }
2622
+ if (isset($parsed['day'])) {
2623
+ --$parsed['day'];
2624
+ } else {
2625
+ $parsed['day'] = 0;
2626
+ }
2627
+ if (isset($parsed['year'])) {
2628
+ $parsed['year'] -= 1970;
2629
+ } else {
2630
+ $parsed['year'] = 0;
2631
+ }
2632
+ }
2633
+ return $this->_assign($calc, $this->mktime(
2634
+ isset($parsed['hour']) ? $parsed['hour'] : 0,
2635
+ isset($parsed['minute']) ? $parsed['minute'] : 0,
2636
+ isset($parsed['second']) ? $parsed['second'] : 0,
2637
+ 1 + $parsed['month'], 1 + $parsed['day'], 1970 + $parsed['year'],
2638
+ false), $this->getUnixTimestamp(), false);
2639
+ } catch (Zend_Locale_Exception $e) {
2640
+ if (!is_numeric($date)) {
2641
+ require_once 'Zend/Date/Exception.php';
2642
+ throw new Zend_Date_Exception($e->getMessage(), $date);
2643
+ }
2644
+ }
2645
+ }
2646
+ return $this->_assign($calc, $date, $this->getUnixTimestamp(), false);
2647
+ break;
2648
+ }
2649
+ }
2650
+
2651
+
2652
+ /**
2653
+ * Returns true when both date objects or date parts are equal.
2654
+ * For example:
2655
+ * 15.May.2000 <-> 15.June.2000 Equals only for Day or Year... all other will return false
2656
+ *
2657
+ * @param string|integer|array|Zend_Date $date Date or datepart to equal with
2658
+ * @param string $part OPTIONAL Part of the date to compare, if null the timestamp is used
2659
+ * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
2660
+ * @return boolean
2661
+ * @throws Zend_Date_Exception
2662
+ */
2663
+ public function equals($date, $part = null, $locale = null)
2664
+ {
2665
+ $result = $this->compare($date, $part, $locale);
2666
+
2667
+ if ($result == 0) {
2668
+ return true;
2669
+ }
2670
+ return false;
2671
+ }
2672
+
2673
+
2674
+ /**
2675
+ * Returns if the given date or datepart is earlier
2676
+ * For example:
2677
+ * 15.May.2000 <-> 13.June.1999 will return true for day, year and date, but not for month
2678
+ *
2679
+ * @param string|integer|array|Zend_Date $date Date or datepart to compare with
2680
+ * @param string $part OPTIONAL Part of the date to compare, if null the timestamp is used
2681
+ * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
2682
+ * @return boolean
2683
+ * @throws Zend_Date_Exception
2684
+ */
2685
+ public function isEarlier($date, $part = null, $locale = null)
2686
+ {
2687
+ $result = $this->compare($date, $part, $locale);
2688
+
2689
+ if ($result == -1) {
2690
+ return true;
2691
+ }
2692
+ return false;
2693
+ }
2694
+
2695
+
2696
+ /**
2697
+ * Returns if the given date or datepart is later
2698
+ * For example:
2699
+ * 15.May.2000 <-> 13.June.1999 will return true for month but false for day, year and date
2700
+ * Returns if the given date is later
2701
+ *
2702
+ * @param string|integer|array|Zend_Date $date Date or datepart to compare with
2703
+ * @param string $part OPTIONAL Part of the date to compare, if null the timestamp is used
2704
+ * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
2705
+ * @return boolean
2706
+ * @throws Zend_Date_Exception
2707
+ */
2708
+ public function isLater($date, $part = null, $locale = null)
2709
+ {
2710
+ $result = $this->compare($date, $part, $locale);
2711
+
2712
+ if ($result == 1) {
2713
+ return true;
2714
+ }
2715
+ return false;
2716
+ }
2717
+
2718
+
2719
+ /**
2720
+ * Returns only the time of the date as new Zend_Date object
2721
+ * For example:
2722
+ * 15.May.2000 10:11:23 will return a dateobject equal to 01.Jan.1970 10:11:23
2723
+ *
2724
+ * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
2725
+ * @return Zend_Date
2726
+ */
2727
+ public function getTime($locale = null)
2728
+ {
2729
+ return $this->copyPart(Zend_Date::TIME_MEDIUM, $locale);
2730
+ }
2731
+
2732
+
2733
+ /**
2734
+ * Returns the calculated time
2735
+ *
2736
+ * @param string $calc Calculation to make
2737
+ * @param string|integer|array|Zend_Date $time Time to calculate with, if null the actual time is taken
2738
+ * @param string $format Timeformat for parsing input
2739
+ * @param string|Zend_Locale $locale Locale for parsing input
2740
+ * @return integer|Zend_Date new time
2741
+ * @throws Zend_Date_Exception
2742
+ */
2743
+ private function _time($calc, $time, $format, $locale)
2744
+ {
2745
+ if (is_null($time)) {
2746
+ require_once 'Zend/Date/Exception.php';
2747
+ throw new Zend_Date_Exception('parameter $time must be set, null is not allowed');
2748
+ }
2749
+
2750
+ if ($locale === null) {
2751
+ $locale = $this->getLocale();
2752
+ }
2753
+
2754
+ if ($time instanceof Zend_Date) {
2755
+ // extract time from object
2756
+ $time = $time->get(Zend_Date::TIME_MEDIUM, $locale);
2757
+ } else {
2758
+ if (is_array($time)) {
2759
+ if (array_key_exists('hour', $time) or array_key_exists('minute', $time)
2760
+ or array_key_exists('second', $time)) {
2761
+ $parsed = $time;
2762
+ } else {
2763
+ require_once 'Zend/Date/Exception.php';
2764
+ throw new Zend_Date_Exception("no hour, minute or second given in array");
2765
+ }
2766
+ } else {
2767
+ if (self::$_Options['format_type'] == 'php') {
2768
+ $format = Zend_Locale_Format::convertPhpToIsoFormat($format);
2769
+ }
2770
+ try {
2771
+ $parsed = Zend_Locale_Format::getTime($time, array('date_format' => $format, 'locale' => $locale, 'format_type' => 'iso'));
2772
+ } catch (Zend_Locale_Exception $e) {
2773
+ require_once 'Zend/Date/Exception.php';
2774
+ throw new Zend_Date_Exception($e->getMessage());
2775
+ }
2776
+ }
2777
+ $time = new self(0, Zend_Date::TIMESTAMP, $locale);
2778
+ $time->set($parsed['hour'], Zend_Date::HOUR);
2779
+ $time->set($parsed['minute'], Zend_Date::MINUTE);
2780
+ $time->set($parsed['second'], Zend_Date::SECOND);
2781
+ $time = $time->get(Zend_Date::TIME_MEDIUM, $locale);
2782
+ }
2783
+
2784
+ $return = $this->_calcdetail($calc, $time, Zend_Date::TIME_MEDIUM, $locale);
2785
+ if ($calc != 'cmp') {
2786
+ return $this;
2787
+ }
2788
+ return $return;
2789
+ }
2790
+
2791
+
2792
+ /**
2793
+ * Sets a new time for the date object. Format defines how to parse the time string.
2794
+ * Also a complete date can be given, but only the time is used for setting.
2795
+ * For example: dd.MMMM.yyTHH:mm' and 'ss sec'-> 10.May.07T25:11 and 44 sec => 1h11min44sec + 1 day
2796
+ * Returned is the new date object and the existing date is left as it was before
2797
+ *
2798
+ * @param string|integer|array|Zend_Date $time Time to set
2799
+ * @param string $format OPTIONAL Timeformat for parsing input
2800
+ * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
2801
+ * @return Zend_Date new time
2802
+ * @throws Zend_Date_Exception
2803
+ */
2804
+ public function setTime($time, $format = null, $locale = null)
2805
+ {
2806
+ return $this->_time('set', $time, $format, $locale);
2807
+ }
2808
+
2809
+
2810
+ /**
2811
+ * Adds a time to the existing date. Format defines how to parse the time string.
2812
+ * If only parts are given the other parts are set to 0.
2813
+ * If no format is given, the standardformat of this locale is used.
2814
+ * For example: HH:mm:ss -> 10 -> +10 hours
2815
+ *
2816
+ * @param string|integer|array|Zend_Date $time Time to add
2817
+ * @param string $format OPTIONAL Timeformat for parsing input
2818
+ * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
2819
+ * @return Zend_Date new time
2820
+ * @throws Zend_Date_Exception
2821
+ */
2822
+ public function addTime($time, $format = null, $locale = null)
2823
+ {
2824
+ return $this->_time('add', $time, $format, $locale);
2825
+ }
2826
+
2827
+
2828
+ /**
2829
+ * Subtracts a time from the existing date. Format defines how to parse the time string.
2830
+ * If only parts are given the other parts are set to 0.
2831
+ * If no format is given, the standardformat of this locale is used.
2832
+ * For example: HH:mm:ss -> 10 -> -10 hours
2833
+ *
2834
+ * @param string|integer|array|Zend_Date $time Time to sub
2835
+ * @param string $format OPTIONAL Timeformat for parsing input
2836
+ * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
2837
+ * @return Zend_Date new time
2838
+ * @throws Zend_Date_Exception
2839
+ */
2840
+ public function subTime($time, $format = null, $locale = null)
2841
+ {
2842
+ return $this->_time('sub', $time, $format, $locale);
2843
+ }
2844
+
2845
+
2846
+ /**
2847
+ * Compares the time from the existing date. Format defines how to parse the time string.
2848
+ * If only parts are given the other parts are set to default.
2849
+ * If no format us given, the standardformat of this locale is used.
2850
+ * For example: HH:mm:ss -> 10 -> 10 hours
2851
+ *
2852
+ * @param string|integer|array|Zend_Date $time Time to compare
2853
+ * @param string $format OPTIONAL Timeformat for parsing input
2854
+ * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
2855
+ * @return integer 0 = equal, 1 = later, -1 = earlier
2856
+ * @throws Zend_Date_Exception
2857
+ */
2858
+ public function compareTime($time, $format = null, $locale = null)
2859
+ {
2860
+ return $this->_time('cmp', $time, $format, $locale);
2861
+ }
2862
+
2863
+
2864
+ /**
2865
+ * Returns a clone of $this, with the time part set to 00:00:00.
2866
+ *
2867
+ * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
2868
+ * @return Zend_Date
2869
+ */
2870
+ public function getDate($locale = null)
2871
+ {
2872
+ return $this->copyPart(Zend_Date::DATE_FULL, $locale);
2873
+ }
2874
+
2875
+
2876
+ /**
2877
+ * Returns the calculated date
2878
+ *
2879
+ * @param string $calc Calculation to make
2880
+ * @param string|integer|array|Zend_Date $date Date to calculate with, if null the actual date is taken
2881
+ * @param string $format Date format for parsing
2882
+ * @param string|Zend_Locale $locale Locale for parsing input
2883
+ * @return integer|Zend_Date new date
2884
+ * @throws Zend_Date_Exception
2885
+ */
2886
+ private function _date($calc, $date, $format, $locale)
2887
+ {
2888
+ if (is_null($date)) {
2889
+ require_once 'Zend/Date/Exception.php';
2890
+ throw new Zend_Date_Exception('parameter $date must be set, null is not allowed');
2891
+ }
2892
+
2893
+ if ($locale === null) {
2894
+ $locale = $this->getLocale();
2895
+ }
2896
+
2897
+ if ($date instanceof Zend_Date) {
2898
+ // extract date from object
2899
+ $date = $date->get(Zend_Date::DATE_FULL, $locale);
2900
+ } else {
2901
+ if (is_array($date)) {
2902
+ if (array_key_exists('year', $time) or array_key_exists('month', $time)
2903
+ or array_key_exists('day', $time)) {
2904
+ $parsed = $time;
2905
+ } else {
2906
+ require_once 'Zend/Date/Exception.php';
2907
+ throw new Zend_Date_Exception("no day,month or year given in array");
2908
+ }
2909
+ } else {
2910
+ if (self::$_Options['format_type'] == 'php') {
2911
+ $format = Zend_Locale_Format::convertPhpToIsoFormat($format);
2912
+ }
2913
+ try {
2914
+ $parsed = Zend_Locale_Format::getDate($date, array('date_format' => $format, 'locale' => $locale, 'format_type' => 'iso'));
2915
+ if ((strpos(strtoupper($format), 'YY') !== false) and (strpos(strtoupper($format), 'YYYY') === false)) {
2916
+ $parsed['year'] = self::_century($parsed['year']);
2917
+ }
2918
+ } catch (Zend_Locale_Exception $e) {
2919
+ require_once 'Zend/Date/Exception.php';
2920
+ throw new Zend_Date_Exception($e->getMessage());
2921
+ }
2922
+ }
2923
+ $date = new self(0, Zend_Date::TIMESTAMP, $locale);
2924
+ $date->set($parsed['year'], Zend_Date::YEAR);
2925
+ $date->set($parsed['month'], Zend_Date::MONTH);
2926
+ $date->set($parsed['day'], Zend_Date::DAY);
2927
+ $date = $date->get(Zend_Date::DATE_FULL, $locale);
2928
+ }
2929
+
2930
+ $return = $this->_calcdetail($calc, $date, Zend_Date::DATE_FULL, $locale);
2931
+ if ($calc != 'cmp') {
2932
+ return $this;
2933
+ }
2934
+ return $return;
2935
+ }
2936
+
2937
+
2938
+ /**
2939
+ * Sets a new date for the date object. Format defines how to parse the date string.
2940
+ * Also a complete date with time can be given, but only the date is used for setting.
2941
+ * For example: MMMM.yy HH:mm-> May.07 22:11 => 01.May.07 00:00
2942
+ * Returned is the new date object and the existing time is left as it was before
2943
+ *
2944
+ * @param string|integer|array|Zend_Date $date Date to set
2945
+ * @param string $format OPTIONAL Date format for parsing
2946
+ * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
2947
+ * @return integer|Zend_Date new date
2948
+ * @throws Zend_Date_Exception
2949
+ */
2950
+ public function setDate($date, $format = null, $locale = null)
2951
+ {
2952
+ return $this->_date('set', $date, $format, $locale);
2953
+ }
2954
+
2955
+
2956
+ /**
2957
+ * Adds a date to the existing date object. Format defines how to parse the date string.
2958
+ * If only parts are given the other parts are set to 0.
2959
+ * If no format is given, the standardformat of this locale is used.
2960
+ * For example: MM.dd.YYYY -> 10 -> +10 months
2961
+ *
2962
+ * @param string|integer|array|Zend_Date $date Date to add
2963
+ * @param string $format OPTIONAL Date format for parsing input
2964
+ * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
2965
+ * @return Zend_Date new date
2966
+ * @throws Zend_Date_Exception
2967
+ */
2968
+ public function addDate($date, $format = null, $locale = null)
2969
+ {
2970
+ return $this->_date('add', $date, $format, $locale);
2971
+ }
2972
+
2973
+
2974
+ /**
2975
+ * Subtracts a date from the existing date object. Format defines how to parse the date string.
2976
+ * If only parts are given the other parts are set to 0.
2977
+ * If no format is given, the standardformat of this locale is used.
2978
+ * For example: MM.dd.YYYY -> 10 -> -10 months
2979
+ * Be aware: Subtracting 2 months is not equal to Adding -2 months !!!
2980
+ *
2981
+ * @param string|integer|array|Zend_Date $date Date to sub
2982
+ * @param string $format OPTIONAL Date format for parsing input
2983
+ * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
2984
+ * @return Zend_Date new date
2985
+ * @throws Zend_Date_Exception
2986
+ */
2987
+ public function subDate($date, $format = null, $locale = null)
2988
+ {
2989
+ return $this->_date('sub', $date, $format, $locale);
2990
+ }
2991
+
2992
+
2993
+ /**
2994
+ * Compares the date from the existing date object, ignoring the time.
2995
+ * Format defines how to parse the date string.
2996
+ * If only parts are given the other parts are set to 0.
2997
+ * If no format is given, the standardformat of this locale is used.
2998
+ * For example: 10.01.2000 => 10.02.1999 -> false
2999
+ *
3000
+ * @param string|integer|array|Zend_Date $date Date to compare
3001
+ * @param string $format OPTIONAL Date format for parsing input
3002
+ * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
3003
+ * @return Zend_Date new date
3004
+ * @throws Zend_Date_Exception
3005
+ */
3006
+ public function compareDate($date, $format = null, $locale = null)
3007
+ {
3008
+
3009
+ return $this->_date('cmp', $date, $format, $locale);
3010
+ }
3011
+
3012
+
3013
+ /**
3014
+ * Returns the full ISO 8601 date from the date object.
3015
+ * Always the complete ISO 8601 specifiction is used. If an other ISO date is needed
3016
+ * (ISO 8601 defines several formats) use toString() instead.
3017
+ * This function does not return the ISO date as object. Use copy() instead.
3018
+ *
3019
+ * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
3020
+ * @return string
3021
+ */
3022
+ public function getIso($locale = null)
3023
+ {
3024
+ return $this->get(Zend_Date::ISO_8601, $locale);
3025
+ }
3026
+
3027
+
3028
+ /**
3029
+ * Sets a new date for the date object. Not given parts are set to default.
3030
+ * Only supported ISO 8601 formats are accepted.
3031
+ * For example: 050901 -> 01.Sept.2005 00:00:00, 20050201T10:00:30 -> 01.Feb.2005 10h00m30s
3032
+ * Returned is the new date object
3033
+ *
3034
+ * @param string|integer|Zend_Date $date ISO Date to set
3035
+ * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
3036
+ * @return integer|Zend_Date new date
3037
+ * @throws Zend_Date_Exception
3038
+ */
3039
+ public function setIso($date, $locale = null)
3040
+ {
3041
+ return $this->_calcvalue('set', $date, 'iso', Zend_Date::ISO_8601, $locale);
3042
+ }
3043
+
3044
+
3045
+ /**
3046
+ * Adds a ISO date to the date object. Not given parts are set to default.
3047
+ * Only supported ISO 8601 formats are accepted.
3048
+ * For example: 050901 -> + 01.Sept.2005 00:00:00, 10:00:00 -> +10h
3049
+ * Returned is the new date object
3050
+ *
3051
+ * @param string|integer|Zend_Date $date ISO Date to add
3052
+ * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
3053
+ * @return integer|Zend_Date new date
3054
+ * @throws Zend_Date_Exception
3055
+ */
3056
+ public function addIso($date, $locale = null)
3057
+ {
3058
+ return $this->_calcvalue('add', $date, 'iso', Zend_Date::ISO_8601, $locale);
3059
+ }
3060
+
3061
+
3062
+ /**
3063
+ * Subtracts a ISO date from the date object. Not given parts are set to default.
3064
+ * Only supported ISO 8601 formats are accepted.
3065
+ * For example: 050901 -> - 01.Sept.2005 00:00:00, 10:00:00 -> -10h
3066
+ * Returned is the new date object
3067
+ *
3068
+ * @param string|integer|Zend_Date $date ISO Date to sub
3069
+ * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
3070
+ * @return integer|Zend_Date new date
3071
+ * @throws Zend_Date_Exception
3072
+ */
3073
+ public function subIso($date, $locale = null)
3074
+ {
3075
+ return $this->_calcvalue('sub', $date, 'iso', Zend_Date::ISO_8601, $locale);
3076
+ }
3077
+
3078
+
3079
+ /**
3080
+ * Compares a ISO date with the date object. Not given parts are set to default.
3081
+ * Only supported ISO 8601 formats are accepted.
3082
+ * For example: 050901 -> - 01.Sept.2005 00:00:00, 10:00:00 -> -10h
3083
+ * Returns if equal, earlier or later
3084
+ *
3085
+ * @param string|integer|Zend_Date $date ISO Date to sub
3086
+ * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
3087
+ * @return integer 0 = equal, 1 = later, -1 = earlier
3088
+ * @throws Zend_Date_Exception
3089
+ */
3090
+ public function compareIso($date, $locale = null)
3091
+ {
3092
+ return $this->_calcvalue('cmp', $date, 'iso', Zend_Date::ISO_8601, $locale);
3093
+ }
3094
+
3095
+
3096
+ /**
3097
+ * Returns a RFC 822 compilant datestring from the date object.
3098
+ * This function does not return the RFC date as object. Use copy() instead.
3099
+ *
3100
+ * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
3101
+ * @return string
3102
+ */
3103
+ public function getArpa($locale = null)
3104
+ {
3105
+ return $this->get(Zend_Date::RFC_822, $locale);
3106
+ }
3107
+
3108
+
3109
+ /**
3110
+ * Sets a RFC 822 date as new date for the date object.
3111
+ * Only RFC 822 compilant date strings are accepted.
3112
+ * For example: Sat, 14 Feb 09 00:31:30 +0100
3113
+ * Returned is the new date object
3114
+ *
3115
+ * @param string|integer|Zend_Date $date RFC 822 to set
3116
+ * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
3117
+ * @return integer|Zend_Date new date
3118
+ * @throws Zend_Date_Exception
3119
+ */
3120
+ public function setArpa($date, $locale = null)
3121
+ {
3122
+ return $this->_calcvalue('set', $date, 'arpa', Zend_Date::RFC_822, $locale);
3123
+ }
3124
+
3125
+
3126
+ /**
3127
+ * Adds a RFC 822 date to the date object.
3128
+ * ARPA messages are used in emails or HTTP Headers.
3129
+ * Only RFC 822 compilant date strings are accepted.
3130
+ * For example: Sat, 14 Feb 09 00:31:30 +0100
3131
+ * Returned is the new date object
3132
+ *
3133
+ * @param string|integer|Zend_Date $date RFC 822 Date to add
3134
+ * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
3135
+ * @return integer|Zend_Date new date
3136
+ * @throws Zend_Date_Exception
3137
+ */
3138
+ public function addArpa($date, $locale = null)
3139
+ {
3140
+ return $this->_calcvalue('add', $date, 'arpa', Zend_Date::RFC_822, $locale);
3141
+ }
3142
+
3143
+
3144
+ /**
3145
+ * Subtracts a RFC 822 date from the date object.
3146
+ * ARPA messages are used in emails or HTTP Headers.
3147
+ * Only RFC 822 compilant date strings are accepted.
3148
+ * For example: Sat, 14 Feb 09 00:31:30 +0100
3149
+ * Returned is the new date object
3150
+ *
3151
+ * @param string|integer|Zend_Date $date RFC 822 Date to sub
3152
+ * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
3153
+ * @return integer|Zend_Date new date
3154
+ * @throws Zend_Date_Exception
3155
+ */
3156
+ public function subArpa($date, $locale = null)
3157
+ {
3158
+ return $this->_calcvalue('sub', $date, 'arpa', Zend_Date::RFC_822, $locale);
3159
+ }
3160
+
3161
+
3162
+ /**
3163
+ * Compares a RFC 822 compilant date with the date object.
3164
+ * ARPA messages are used in emails or HTTP Headers.
3165
+ * Only RFC 822 compilant date strings are accepted.
3166
+ * For example: Sat, 14 Feb 09 00:31:30 +0100
3167
+ * Returns if equal, earlier or later
3168
+ *
3169
+ * @param string|integer|Zend_Date $date RFC 822 Date to sub
3170
+ * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
3171
+ * @return integer 0 = equal, 1 = later, -1 = earlier
3172
+ * @throws Zend_Date_Exception
3173
+ */
3174
+ public function compareArpa($date, $locale = null)
3175
+ {
3176
+ return $this->_calcvalue('cmp', $date, 'arpa', Zend_Date::RFC_822, $locale);
3177
+ }
3178
+
3179
+
3180
+ /**
3181
+ * Check if location is supported
3182
+ *
3183
+ * @param $location array - locations array
3184
+ * @return $horizon float
3185
+ */
3186
+ private function _checkLocation($location)
3187
+ {
3188
+ if (!isset($location['longitude']) or !isset($location['latitude'])) {
3189
+ require_once 'Zend/Date/Exception.php';
3190
+ throw new Zend_Date_Exception('Location must include \'longitude\' and \'latitude\'', $location);
3191
+ }
3192
+ if (($location['longitude'] > 180) or ($location['longitude'] < -180)) {
3193
+ require_once 'Zend/Date/Exception.php';
3194
+ throw new Zend_Date_Exception('Longitude must be between -180 and 180', $location);
3195
+ }
3196
+ if (($location['latitude'] > 90) or ($location['latitude'] < -90)) {
3197
+ require_once 'Zend/Date/Exception.php';
3198
+ throw new Zend_Date_Exception('Latitude must be between -90 and 90', $location);
3199
+ }
3200
+
3201
+ if (!isset($location['horizon'])){
3202
+ $location['horizon'] = 'effective';
3203
+ }
3204
+
3205
+ switch ($location['horizon']) {
3206
+ case 'civil' :
3207
+ return -0.104528;
3208
+ break;
3209
+ case 'nautic' :
3210
+ return -0.207912;
3211
+ break;
3212
+ case 'astronomic' :
3213
+ return -0.309017;
3214
+ break;
3215
+ default :
3216
+ return -0.0145439;
3217
+ break;
3218
+ }
3219
+ }
3220
+
3221
+
3222
+ /**
3223
+ * Returns the time of sunrise for this date and a given location as new date object
3224
+ * For a list of cities and correct locations use the class Zend_Date_Cities
3225
+ *
3226
+ * @param $location array - location of sunrise
3227
+ * ['horizon'] -> civil, nautic, astronomical, effective (default)
3228
+ * ['longitude'] -> longitude of location
3229
+ * ['latitude'] -> latitude of location
3230
+ * @return Zend_Date
3231
+ * @throws Zend_Date_Exception
3232
+ */
3233
+ public function getSunrise($location)
3234
+ {
3235
+ $horizon = $this->_checkLocation($location);
3236
+ $result = clone $this;
3237
+ $result->set($this->calcSun($location, $horizon, true), 'Zend_Date::TIMESTAMP');
3238
+ return $result;
3239
+ }
3240
+
3241
+
3242
+ /**
3243
+ * Returns the time of sunset for this date and a given location as new date object
3244
+ * For a list of cities and correct locations use the class Zend_Date_Cities
3245
+ *
3246
+ * @param $location array - location of sunset
3247
+ * ['horizon'] -> civil, nautic, astronomical, effective (default)
3248
+ * ['longitude'] -> longitude of location
3249
+ * ['latitude'] -> latitude of location
3250
+ * @return Zend_Date
3251
+ * @throws Zend_Date_Exception
3252
+ */
3253
+ public function getSunset($location)
3254
+ {
3255
+ $horizon = $this->_checkLocation($location);
3256
+ $result = clone $this;
3257
+ $result->set($this->calcSun($location, $horizon, false), 'Zend_Date::TIMESTAMP');
3258
+ return $result;
3259
+ }
3260
+
3261
+
3262
+ /**
3263
+ * Returns an array with the sunset and sunrise dates for all horizon types
3264
+ * For a list of cities and correct locations use the class Zend_Date_Cities
3265
+ *
3266
+ * @param $location array - location of suninfo
3267
+ * ['horizon'] -> civil, nautic, astronomical, effective (default)
3268
+ * ['longitude'] -> longitude of location
3269
+ * ['latitude'] -> latitude of location
3270
+ * @return array - [sunset|sunrise][effective|civil|nautic|astronomic]
3271
+ * @throws Zend_Date_Exception
3272
+ */
3273
+ public function getSunInfo($location)
3274
+ {
3275
+ $suninfo = array();
3276
+ for ($i = 0; $i < 4; ++$i) {
3277
+ switch ($i) {
3278
+ case 0 :
3279
+ $location['horizon'] = 'effective';
3280
+ break;
3281
+ case 1 :
3282
+ $location['horizon'] = 'civil';
3283
+ break;
3284
+ case 2 :
3285
+ $location['horizon'] = 'nautic';
3286
+ break;
3287
+ case 3 :
3288
+ $location['horizon'] = 'astronomic';
3289
+ break;
3290
+ }
3291
+ $horizon = $this->_checkLocation($location);
3292
+ $result = clone $this;
3293
+ $result->set($this->calcSun($location, $horizon, true), 'Zend_Date::TIMESTAMP');
3294
+ $suninfo['sunrise'][$location['horizon']] = $result;
3295
+ $result = clone $this;
3296
+ $result->set($this->calcSun($location, $horizon, false), 'Zend_Date::TIMESTAMP');
3297
+ $suninfo['sunset'][$location['horizon']] = $result;
3298
+ }
3299
+ return $suninfo;
3300
+ }
3301
+
3302
+
3303
+ /**
3304
+ * Check a given year for leap year.
3305
+ *
3306
+ * @param integer|array|Zend_Date $year Year to check
3307
+ * @return boolean
3308
+ */
3309
+ public static function checkLeapYear($year)
3310
+ {
3311
+ if ($year instanceof Zend_Date) {
3312
+ $year = (int) $year->get(Zend_Date::YEAR);
3313
+ }
3314
+ if (is_array($year)) {
3315
+ if (array_key_exists('year', $year)) {
3316
+ $year = $year['year'];
3317
+ } else {
3318
+ require_once 'Zend/Date/Exception.php';
3319
+ throw new Zend_Date_Exception("no year given in array");
3320
+ }
3321
+ }
3322
+ if (!is_numeric($year)) {
3323
+ require_once 'Zend/Date/Exception.php';
3324
+ throw new Zend_Date_Exception("year ($year) has to be integer for checkLeapYear()", $year);
3325
+ }
3326
+
3327
+ return (bool) parent::isYearLeapYear($year);
3328
+ }
3329
+
3330
+
3331
+ /**
3332
+ * Returns true, if the year is a leap year.
3333
+ *
3334
+ * @return boolean
3335
+ */
3336
+ public function isLeapYear()
3337
+ {
3338
+ return self::checkLeapYear($this);
3339
+ }
3340
+
3341
+
3342
+ /**
3343
+ * Returns if the set date is todays date
3344
+ *
3345
+ * @return boolean
3346
+ */
3347
+ public function isToday()
3348
+ {
3349
+ $today = $this->date('Ymd', $this->_getTime());
3350
+ $day = $this->date('Ymd', $this->getUnixTimestamp());
3351
+ return ($today == $day);
3352
+ }
3353
+
3354
+
3355
+ /**
3356
+ * Returns if the set date is yesterdays date
3357
+ *
3358
+ * @return boolean
3359
+ */
3360
+ public function isYesterday()
3361
+ {
3362
+ list($year, $month, $day) = explode('-', $this->date('Y-m-d', $this->_getTime()));
3363
+ // adjusts for leap days and DST changes that are timezone specific
3364
+ $yesterday = $this->date('Ymd', $this->mktime(0, 0, 0, $month, $day -1, $year));
3365
+ $day = $this->date('Ymd', $this->getUnixTimestamp());
3366
+ return $day == $yesterday;
3367
+ }
3368
+
3369
+
3370
+ /**
3371
+ * Returns if the set date is tomorrows date
3372
+ *
3373
+ * @return boolean
3374
+ */
3375
+ public function isTomorrow()
3376
+ {
3377
+ list($year, $month, $day) = explode('-', $this->date('Y-m-d', $this->_getTime()));
3378
+ // adjusts for leap days and DST changes that are timezone specific
3379
+ $tomorrow = $this->date('Ymd', $this->mktime(0, 0, 0, $month, $day +1, $year));
3380
+ $day = $this->date('Ymd', $this->getUnixTimestamp());
3381
+ return $day == $tomorrow;
3382
+ }
3383
+
3384
+
3385
+ /**
3386
+ * Returns the actual date as new date object
3387
+ *
3388
+ * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
3389
+ * @return Zend_Date
3390
+ */
3391
+ public static function now($locale = null)
3392
+ {
3393
+ return new Zend_Date(time(), Zend_Date::TIMESTAMP, $locale);
3394
+ }
3395
+
3396
+
3397
+ /**
3398
+ * Calculate date details
3399
+ *
3400
+ * @param string $calc Calculation to make
3401
+ * @param string|integer|array|Zend_Date $date Date or Part to calculate
3402
+ * @param string $part Datepart for Calculation
3403
+ * @param string|Zend_Locale $locale Locale for parsing input
3404
+ * @return integer|string new date
3405
+ * @throws Zend_Date_Exception
3406
+ */
3407
+ private function _calcdetail($calc, $date, $type, $locale)
3408
+ {
3409
+ switch($calc) {
3410
+ case 'set' :
3411
+ return $this->set($date, $type, $locale);
3412
+ break;
3413
+ case 'add' :
3414
+ return $this->add($date, $type, $locale);
3415
+ break;
3416
+ case 'sub' :
3417
+ return $this->sub($date, $type, $locale);
3418
+ break;
3419
+ }
3420
+ return $this->compare($date, $type, $locale);
3421
+ }
3422
+
3423
+ /**
3424
+ * Internal calculation, returns the requested date type
3425
+ *
3426
+ * @param string $calc Calculation to make
3427
+ * @param string|integer|Zend_Date $value Datevalue to calculate with, if null the actual value is taken
3428
+ * @param string|Zend_Locale $locale Locale for parsing input
3429
+ * @return integer|Zend_Date new date
3430
+ * @throws Zend_Date_Exception
3431
+ */
3432
+ private function _calcvalue($calc, $value, $type, $parameter, $locale)
3433
+ {
3434
+ if (is_null($value)) {
3435
+ require_once 'Zend/Date/Exception.php';
3436
+ throw new Zend_Date_Exception("parameter $type must be set, null is not allowed");
3437
+ }
3438
+
3439
+ if ($locale === null) {
3440
+ $locale = $this->getLocale();
3441
+ }
3442
+
3443
+ if ($value instanceof Zend_Date) {
3444
+ // extract value from object
3445
+ $value = $value->get($parameter, $locale);
3446
+ } else if (!is_array($value) && !is_numeric($value) && ($type != 'iso') && ($type != 'arpa')) {
3447
+ require_once 'Zend/Date/Exception.php';
3448
+ throw new Zend_Date_Exception("invalid $type ($value) operand", $value);
3449
+ }
3450
+
3451
+ $return = $this->_calcdetail($calc, $value, $parameter, $locale);
3452
+ if ($calc != 'cmp') {
3453
+ return $this;
3454
+ }
3455
+ return $return;
3456
+ }
3457
+
3458
+
3459
+ /**
3460
+ * Returns only the year from the date object as new object.
3461
+ * For example: 10.May.2000 10:30:00 -> 01.Jan.2000 00:00:00
3462
+ *
3463
+ * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
3464
+ * @return Zend_Date
3465
+ */
3466
+ public function getYear($locale = null)
3467
+ {
3468
+ return $this->copyPart(Zend_Date::YEAR, $locale);
3469
+ }
3470
+
3471
+
3472
+ /**
3473
+ * Sets a new year
3474
+ * If the year is between 0 and 69, 2000 will be set (2000-2069)
3475
+ * If the year if between 70 and 99, 1999 will be set (1970-1999)
3476
+ * 3 or 4 digit years are set as expected. If you need to set year 0-99
3477
+ * use set() instead.
3478
+ * Returned is the new date object
3479
+ *
3480
+ * @param string|integer|array|Zend_Date $date Year to set
3481
+ * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
3482
+ * @return Zend_Date new date
3483
+ * @throws Zend_Date_Exception
3484
+ */
3485
+ public function setYear($year, $locale = null)
3486
+ {
3487
+ return $this->_calcvalue('set', $year, 'year', Zend_Date::YEAR, $locale);
3488
+ }
3489
+
3490
+
3491
+ /**
3492
+ * Adds the year to the existing date object
3493
+ * If the year is between 0 and 69, 2000 will be added (2000-2069)
3494
+ * If the year if between 70 and 99, 1999 will be added (1970-1999)
3495
+ * 3 or 4 digit years are added as expected. If you need to add years from 0-99
3496
+ * use add() instead.
3497
+ * Returned is the new date object
3498
+ *
3499
+ * @param string|integer|array|Zend_Date $date Year to add
3500
+ * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
3501
+ * @return Zend_Date new date
3502
+ * @throws Zend_Date_Exception
3503
+ */
3504
+ public function addYear($year, $locale = null)
3505
+ {
3506
+ return $this->_calcvalue('add', $year, 'year', Zend_Date::YEAR, $locale);
3507
+ }
3508
+
3509
+
3510
+ /**
3511
+ * Subs the year from the existing date object
3512
+ * If the year is between 0 and 69, 2000 will be subtracted (2000-2069)
3513
+ * If the year if between 70 and 99, 1999 will be subtracted (1970-1999)
3514
+ * 3 or 4 digit years are subtracted as expected. If you need to subtract years from 0-99
3515
+ * use sub() instead.
3516
+ * Returned is the new date object
3517
+ *
3518
+ * @param string|integer|array|Zend_Date $date Year to sub
3519
+ * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
3520
+ * @return Zend_Date new date
3521
+ * @throws Zend_Date_Exception
3522
+ */
3523
+ public function subYear($year, $locale = null)
3524
+ {
3525
+ return $this->_calcvalue('sub', $year, 'year', Zend_Date::YEAR, $locale);
3526
+ }
3527
+
3528
+
3529
+ /**
3530
+ * Compares the year with the existing date object, ignoring other date parts.
3531
+ * For example: 10.03.2000 -> 15.02.2000 -> true
3532
+ * Returns if equal, earlier or later
3533
+ *
3534
+ * @param string|integer|array|Zend_Date $year Year to compare
3535
+ * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
3536
+ * @return integer 0 = equal, 1 = later, -1 = earlier
3537
+ * @throws Zend_Date_Exception
3538
+ */
3539
+ public function compareYear($year, $locale = null)
3540
+ {
3541
+ return $this->_calcvalue('cmp', $year, 'year', Zend_Date::YEAR, $locale);
3542
+ }
3543
+
3544
+
3545
+ /**
3546
+ * Returns only the month from the date object as new object.
3547
+ * For example: 10.May.2000 10:30:00 -> 01.May.1970 00:00:00
3548
+ *
3549
+ * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
3550
+ * @return Zend_Date
3551
+ */
3552
+ public function getMonth($locale = null)
3553
+ {
3554
+ return $this->copyPart(Zend_Date::MONTH, $locale);
3555
+ }
3556
+
3557
+
3558
+ /**
3559
+ * Returns the calculated month
3560
+ *
3561
+ * @param string $calc Calculation to make
3562
+ * @param string|integer|array|Zend_Date $month Month to calculate with, if null the actual month is taken
3563
+ * @param string|Zend_Locale $locale Locale for parsing input
3564
+ * @return integer|Zend_Date new time
3565
+ * @throws Zend_Date_Exception
3566
+ */
3567
+ private function _month($calc, $month, $locale)
3568
+ {
3569
+ if (is_null($month)) {
3570
+ require_once 'Zend/Date/Exception.php';
3571
+ throw new Zend_Date_Exception('parameter $month must be set, null is not allowed');
3572
+ }
3573
+
3574
+ if ($locale === null) {
3575
+ $locale = $this->getLocale();
3576
+ }
3577
+
3578
+ if ($month instanceof Zend_Date) {
3579
+ // extract month from object
3580
+ $found = $month->get(Zend_Date::MONTH_SHORT, $locale);
3581
+ } else {
3582
+ if (is_numeric($month)) {
3583
+ $found = $month;
3584
+ } else if (is_array($month)) {
3585
+ if (array_key_exists('month', $month)) {
3586
+ $month = $month['month'];
3587
+ } else {
3588
+ require_once 'Zend/Date/Exception.php';
3589
+ throw new Zend_Date_Exception("no month given in array");
3590
+ }
3591
+ } else {
3592
+ $monthlist = Zend_Locale_Data::getList($locale, 'month');
3593
+ $monthlist2 = Zend_Locale_Data::getList($locale, 'month', array('gregorian', 'format', 'abbreviated'));
3594
+
3595
+ $monthlist = array_merge($monthlist, $monthlist2);
3596
+ $found = 0;
3597
+ $cnt = 0;
3598
+ foreach ($monthlist as $key => $value) {
3599
+ if (strtoupper($value) == strtoupper($month)) {
3600
+ $found = $key + 1;
3601
+ break;
3602
+ }
3603
+ ++$cnt;
3604
+ }
3605
+ if ($found == 0) {
3606
+ foreach ($monthlist2 as $key => $value) {
3607
+ if (strtoupper(substr($value, 0, 1)) == strtoupper($month)) {
3608
+ $found = $key + 1;
3609
+ break;
3610
+ }
3611
+ ++$cnt;
3612
+ }
3613
+ }
3614
+ if ($found == 0) {
3615
+ require_once 'Zend/Date/Exception.php';
3616
+ throw new Zend_Date_Exception("unknown month name ($month)", $month);
3617
+ }
3618
+ }
3619
+ }
3620
+ $return = $this->_calcdetail($calc, $found, Zend_Date::MONTH_SHORT, $locale);
3621
+ if ($calc != 'cmp') {
3622
+ return $this;
3623
+ }
3624
+ return $return;
3625
+ }
3626
+
3627
+
3628
+ /**
3629
+ * Sets a new month
3630
+ * The month can be a number or a string. Setting months lower then 0 and greater then 12
3631
+ * will result in adding or subtracting the relevant year. (12 months equal one year)
3632
+ * If a localized monthname is given it will be parsed with the default locale or the optional
3633
+ * set locale.
3634
+ * Returned is the new date object
3635
+ *
3636
+ * @param string|integer|array|Zend_Date $month Month to set
3637
+ * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
3638
+ * @return Zend_Date new date
3639
+ * @throws Zend_Date_Exception
3640
+ */
3641
+ public function setMonth($month, $locale = null)
3642
+ {
3643
+ return $this->_month('set', $month, $locale);
3644
+ }
3645
+
3646
+
3647
+ /**
3648
+ * Adds months to the existing date object.
3649
+ * The month can be a number or a string. Adding months lower then 0 and greater then 12
3650
+ * will result in adding or subtracting the relevant year. (12 months equal one year)
3651
+ * If a localized monthname is given it will be parsed with the default locale or the optional
3652
+ * set locale.
3653
+ * Returned is the new date object
3654
+ *
3655
+ * @param string|integer|array|Zend_Date $month Month to add
3656
+ * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
3657
+ * @return Zend_Date new date
3658
+ * @throws Zend_Date_Exception
3659
+ */
3660
+ public function addMonth($month, $locale = null)
3661
+ {
3662
+ return $this->_month('add', $month, $locale);
3663
+ }
3664
+
3665
+
3666
+ /**
3667
+ * Subtracts months from the existing date object.
3668
+ * The month can be a number or a string. Subtracting months lower then 0 and greater then 12
3669
+ * will result in adding or subtracting the relevant year. (12 months equal one year)
3670
+ * If a localized monthname is given it will be parsed with the default locale or the optional
3671
+ * set locale.
3672
+ * Returned is the new date object
3673
+ *
3674
+ * @param string|integer|array|Zend_Date $month Month to sub
3675
+ * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
3676
+ * @return Zend_Date new date
3677
+ * @throws Zend_Date_Exception
3678
+ */
3679
+ public function subMonth($month, $locale = null)
3680
+ {
3681
+ return $this->_month('sub', $month, $locale);
3682
+ }
3683
+
3684
+
3685
+ /**
3686
+ * Compares the month with the existing date object, ignoring other date parts.
3687
+ * For example: 10.03.2000 -> 15.03.1950 -> true
3688
+ * Returns if equal, earlier or later
3689
+ *
3690
+ * @param string|integer|array|Zend_Date $month Month to compare
3691
+ * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
3692
+ * @return integer 0 = equal, 1 = later, -1 = earlier
3693
+ * @throws Zend_Date_Exception
3694
+ */
3695
+ public function compareMonth($month, $locale = null)
3696
+ {
3697
+ return $this->_month('cmp', $month, $locale);
3698
+ }
3699
+
3700
+
3701
+ /**
3702
+ * Returns the day as new date object
3703
+ * Example: 20.May.1986 -> 20.Jan.1970 00:00:00
3704
+ *
3705
+ * @param $locale string|Zend_Locale OPTIONAL Locale for parsing input
3706
+ * @return Zend_Date
3707
+ */
3708
+ public function getDay($locale = null)
3709
+ {
3710
+ return $this->copyPart(Zend_Date::DAY_SHORT, $locale);
3711
+ }
3712
+
3713
+
3714
+ /**
3715
+ * Returns the calculated day
3716
+ *
3717
+ * @param $calc string Type of calculation to make
3718
+ * @param $day string|integer|Zend_Date Day to calculate, when null the actual day is calculated
3719
+ * @param $locale string|Zend_Locale Locale for parsing input
3720
+ * @return Zend_Date|integer
3721
+ */
3722
+ private function _day($calc, $day, $locale)
3723
+ {
3724
+ if (is_null($day)) {
3725
+ require_once 'Zend/Date/Exception.php';
3726
+ throw new Zend_Date_Exception('parameter $day must be set, null is not allowed');
3727
+ }
3728
+
3729
+ if ($locale === null) {
3730
+ $locale = $this->getLocale();
3731
+ }
3732
+
3733
+ if ($day instanceof Zend_Date) {
3734
+ $day = $day->get(Zend_Date::DAY_SHORT, $locale);
3735
+ }
3736
+
3737
+ if (is_numeric($day)) {
3738
+ $type = Zend_Date::DAY_SHORT;
3739
+ } else if (is_array($day)) {
3740
+ if (array_key_exists('day', $day)) {
3741
+ $day = $day['day'];
3742
+ $type = Zend_Date::WEEKDAY;
3743
+ } else {
3744
+ require_once 'Zend/Date/Exception.php';
3745
+ throw new Zend_Date_Exception("no day given in array");
3746
+ }
3747
+ } else {
3748
+ switch (strlen($day)) {
3749
+ case 1 :
3750
+ $type = Zend_Date::WEEKDAY_NARROW;
3751
+ break;
3752
+ case 2:
3753
+ $type = Zend_Date::WEEKDAY_NAME;
3754
+ break;
3755
+ case 3:
3756
+ $type = Zend_Date::WEEKDAY_SHORT;
3757
+ break;
3758
+ default:
3759
+ $type = Zend_Date::WEEKDAY;
3760
+ break;
3761
+ }
3762
+ }
3763
+ $return = $this->_calcdetail($calc, $day, $type, $locale);
3764
+ if ($calc != 'cmp') {
3765
+ return $this;
3766
+ }
3767
+ return $return;
3768
+ }
3769
+
3770
+
3771
+ /**
3772
+ * Sets a new day
3773
+ * The day can be a number or a string. Setting days lower then 0 or greater than the number of this months days
3774
+ * will result in adding or subtracting the relevant month.
3775
+ * If a localized dayname is given it will be parsed with the default locale or the optional
3776
+ * set locale.
3777
+ * Returned is the new date object
3778
+ * Example: setDay('Montag', 'de_AT'); will set the monday of this week as day.
3779
+ *
3780
+ * @param string|integer|array|Zend_Date $month Day to set
3781
+ * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
3782
+ * @return Zend_Date new date
3783
+ * @throws Zend_Date_Exception
3784
+ */
3785
+ public function setDay($day, $locale = null)
3786
+ {
3787
+ return $this->_day('set', $day, $locale);
3788
+ }
3789
+
3790
+
3791
+ /**
3792
+ * Adds days to the existing date object.
3793
+ * The day can be a number or a string. Adding days lower then 0 or greater than the number of this months days
3794
+ * will result in adding or subtracting the relevant month.
3795
+ * If a localized dayname is given it will be parsed with the default locale or the optional
3796
+ * set locale.
3797
+ * Returned is the new date object
3798
+ * Example: addDay('Montag', 'de_AT'); will add the number of days until the next monday
3799
+ *
3800
+ * @param string|integer|array|Zend_Date $month Day to add
3801
+ * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
3802
+ * @return Zend_Date new date
3803
+ * @throws Zend_Date_Exception
3804
+ */
3805
+ public function addDay($day, $locale = null)
3806
+ {
3807
+ return $this->_day('add', $day, $locale);
3808
+ }
3809
+
3810
+
3811
+ /**
3812
+ * Subtracts days from the existing date object.
3813
+ * The day can be a number or a string. Subtracting days lower then 0 or greater than the number of this months days
3814
+ * will result in adding or subtracting the relevant month.
3815
+ * If a localized dayname is given it will be parsed with the default locale or the optional
3816
+ * set locale.
3817
+ * Returned is the new date object
3818
+ * Example: subDay('Montag', 'de_AT'); will sub the number of days until the previous monday
3819
+ *
3820
+ * @param string|integer|array|Zend_Date $month Day to sub
3821
+ * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
3822
+ * @return Zend_Date new date
3823
+ * @throws Zend_Date_Exception
3824
+ */
3825
+ public function subDay($day, $locale = null)
3826
+ {
3827
+ return $this->_day('sub', $day, $locale);
3828
+ }
3829
+
3830
+
3831
+ /**
3832
+ * Compares the day with the existing date object, ignoring other date parts.
3833
+ * For example: 'Monday', 'en' -> 08.Jan.2007 -> 0
3834
+ * Returns if equal, earlier or later
3835
+ *
3836
+ * @param string|integer|array|Zend_Date $day Day to compare
3837
+ * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
3838
+ * @return integer 0 = equal, 1 = later, -1 = earlier
3839
+ * @throws Zend_Date_Exception
3840
+ */
3841
+ public function compareDay($day, $locale = null)
3842
+ {
3843
+ return $this->_day('cmp', $day, $locale);
3844
+ }
3845
+
3846
+
3847
+ /**
3848
+ * Returns the weekday as new date object
3849
+ * Weekday is always from 1-7
3850
+ * Example: 09-Jan-2007 -> 2 = Tuesday -> 02-Jan-1970 (when 02.01.1970 is also Tuesday)
3851
+ *
3852
+ * @param $locale string|Zend_Locale OPTIONAL Locale for parsing input
3853
+ * @return Zend_Date
3854
+ */
3855
+ public function getWeekday($locale = null)
3856
+ {
3857
+ return $this->copyPart(Zend_Date::WEEKDAY, $locale);
3858
+ }
3859
+
3860
+
3861
+ /**
3862
+ * Returns the calculated weekday
3863
+ *
3864
+ * @param $calc string Type of calculation to make
3865
+ * @param $weekday string|integer|array|Zend_Date Weekday to calculate, when null the actual weekday is calculated
3866
+ * @param $locale string|Zend_Locale Locale for parsing input
3867
+ * @return Zend_Date|integer
3868
+ * @throws Zend_Date_Exception
3869
+ */
3870
+ private function _weekday($calc, $weekday, $locale)
3871
+ {
3872
+ if (is_null($weekday)) {
3873
+ require_once 'Zend/Date/Exception.php';
3874
+ throw new Zend_Date_Exception('parameter $weekday must be set, null is not allowed');
3875
+ }
3876
+
3877
+ if ($locale === null) {
3878
+ $locale = $this->getLocale();
3879
+ }
3880
+
3881
+ if ($weekday instanceof Zend_Date) {
3882
+ $weekday = $weekday->get(Zend_Date::WEEKDAY_8601, $locale);
3883
+ }
3884
+
3885
+ if (is_numeric($weekday)) {
3886
+ $type = Zend_Date::WEEKDAY_8601;
3887
+ } else if (is_array($weekday)) {
3888
+ if (array_key_exists('weekday', $weekday)) {
3889
+ $weekday = $weekday['weekday'];
3890
+ $type = Zend_Date::WEEKDAY;
3891
+ } else {
3892
+ require_once 'Zend/Date/Exception.php';
3893
+ throw new Zend_Date_Exception("no weekday given in array");
3894
+ }
3895
+ } else {
3896
+ switch(strlen($weekday)) {
3897
+ case 1:
3898
+ $type = Zend_Date::WEEKDAY_NARROW;
3899
+ break;
3900
+ case 2:
3901
+ $type = Zend_Date::WEEKDAY_NAME;
3902
+ break;
3903
+ case 3:
3904
+ $type = Zend_Date::WEEKDAY_SHORT;
3905
+ break;
3906
+ default:
3907
+ $type = Zend_Date::WEEKDAY;
3908
+ break;
3909
+ }
3910
+ }
3911
+ $return = $this->_calcdetail($calc, $weekday, $type, $locale);
3912
+ if ($calc != 'cmp') {
3913
+ return $this;
3914
+ }
3915
+ return $return;
3916
+ }
3917
+
3918
+
3919
+ /**
3920
+ * Sets a new weekday
3921
+ * The weekday can be a number or a string. If a localized weekday name is given,
3922
+ * then it will be parsed as a date in $locale (defaults to the same locale as $this).
3923
+ * Returned is the new date object.
3924
+ * Example: setWeekday(3); will set the wednesday of this week as day.
3925
+ *
3926
+ * @param string|integer|array|Zend_Date $month Weekday to set
3927
+ * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
3928
+ * @return Zend_Date new date
3929
+ * @throws Zend_Date_Exception
3930
+ */
3931
+ public function setWeekday($weekday, $locale = null)
3932
+ {
3933
+ return $this->_weekday('set', $weekday, $locale);
3934
+ }
3935
+
3936
+
3937
+ /**
3938
+ * Adds weekdays to the existing date object.
3939
+ * The weekday can be a number or a string.
3940
+ * If a localized dayname is given it will be parsed with the default locale or the optional
3941
+ * set locale.
3942
+ * Returned is the new date object
3943
+ * Example: addWeekday(3); will add the difference of days from the begining of the month until
3944
+ * wednesday.
3945
+ *
3946
+ * @param string|integer|array|Zend_Date $month Weekday to add
3947
+ * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
3948
+ * @return Zend_Date new date
3949
+ * @throws Zend_Date_Exception
3950
+ */
3951
+ public function addWeekday($weekday, $locale = null)
3952
+ {
3953
+ return $this->_weekday('add', $weekday, $locale);
3954
+ }
3955
+
3956
+
3957
+ /**
3958
+ * Subtracts weekdays from the existing date object.
3959
+ * The weekday can be a number or a string.
3960
+ * If a localized dayname is given it will be parsed with the default locale or the optional
3961
+ * set locale.
3962
+ * Returned is the new date object
3963
+ * Example: subWeekday(3); will subtract the difference of days from the begining of the month until
3964
+ * wednesday.
3965
+ *
3966
+ * @param string|integer|array|Zend_Date $month Weekday to sub
3967
+ * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
3968
+ * @return Zend_Date new date
3969
+ * @throws Zend_Date_Exception
3970
+ */
3971
+ public function subWeekday($weekday, $locale = null)
3972
+ {
3973
+ return $this->_weekday('sub', $weekday, $locale);
3974
+ }
3975
+
3976
+
3977
+ /**
3978
+ * Compares the weekday with the existing date object, ignoring other date parts.
3979
+ * For example: 'Monday', 'en' -> 08.Jan.2007 -> 0
3980
+ * Returns if equal, earlier or later
3981
+ *
3982
+ * @param string|integer|array|Zend_Date $weekday Weekday to compare
3983
+ * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
3984
+ * @return integer 0 = equal, 1 = later, -1 = earlier
3985
+ * @throws Zend_Date_Exception
3986
+ */
3987
+ public function compareWeekday($weekday, $locale = null)
3988
+ {
3989
+ return $this->_weekday('cmp', $weekday, $locale);
3990
+ }
3991
+
3992
+
3993
+ /**
3994
+ * Returns the day of year as new date object
3995
+ * Example: 02.Feb.1986 10:00:00 -> 02.Feb.1970 00:00:00
3996
+ *
3997
+ * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
3998
+ * @return Zend_Date
3999
+ */
4000
+ public function getDayOfYear($locale = null)
4001
+ {
4002
+ return $this->copyPart(Zend_Date::DAY_OF_YEAR, $locale);
4003
+ }
4004
+
4005
+
4006
+ /**
4007
+ * Sets a new day of year
4008
+ * The day of year is always a number.
4009
+ * Returned is the new date object
4010
+ * Example: 04.May.2004 -> setDayOfYear(10) -> 10.Jan.2004
4011
+ *
4012
+ * @param string|integer|array|Zend_Date $day Day of Year to set
4013
+ * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
4014
+ * @return Zend_Date new date
4015
+ * @throws Zend_Date_Exception
4016
+ */
4017
+ public function setDayOfYear($day, $locale = null)
4018
+ {
4019
+ return $this->_calcvalue('set', $day, 'day of year', Zend_Date::DAY_OF_YEAR, $locale);
4020
+ }
4021
+
4022
+
4023
+ /**
4024
+ * Adds a day of year to the existing date object.
4025
+ * The day of year is always a number.
4026
+ * Returned is the new date object
4027
+ * Example: addDayOfYear(10); will add 10 days to the existing date object.
4028
+ *
4029
+ * @param string|integer|array|Zend_Date $day Day of Year to add
4030
+ * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
4031
+ * @return Zend_Date new date
4032
+ * @throws Zend_Date_Exception
4033
+ */
4034
+ public function addDayOfYear($day, $locale = null)
4035
+ {
4036
+ return $this->_calcvalue('add', $day, 'day of year', Zend_Date::DAY_OF_YEAR, $locale);
4037
+ }
4038
+
4039
+
4040
+ /**
4041
+ * Subtracts a day of year from the existing date object.
4042
+ * The day of year is always a number.
4043
+ * Returned is the new date object
4044
+ * Example: subDayOfYear(10); will subtract 10 days from the existing date object.
4045
+ *
4046
+ * @param string|integer|array|Zend_Date $day Day of Year to sub
4047
+ * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
4048
+ * @return Zend_Date new date
4049
+ * @throws Zend_Date_Exception
4050
+ */
4051
+ public function subDayOfYear($day, $locale = null)
4052
+ {
4053
+ return $this->_calcvalue('sub', $day, 'day of year', Zend_Date::DAY_OF_YEAR, $locale);
4054
+ }
4055
+
4056
+
4057
+ /**
4058
+ * Compares the day of year with the existing date object.
4059
+ * For example: compareDayOfYear(33) -> 02.Feb.2007 -> 0
4060
+ * Returns if equal, earlier or later
4061
+ *
4062
+ * @param string|integer|array|Zend_Date $day Day of Year to compare
4063
+ * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
4064
+ * @return integer 0 = equal, 1 = later, -1 = earlier
4065
+ * @throws Zend_Date_Exception
4066
+ */
4067
+ public function compareDayOfYear($day, $locale = null)
4068
+ {
4069
+ return $this->_calcvalue('cmp', $day, 'day of year', Zend_Date::DAY_OF_YEAR, $locale);
4070
+ }
4071
+
4072
+
4073
+ /**
4074
+ * Returns the hour as new date object
4075
+ * Example: 02.Feb.1986 10:30:25 -> 01.Jan.1970 10:00:00
4076
+ *
4077
+ * @param $locale string|Zend_Locale OPTIONAL Locale for parsing input
4078
+ * @return Zend_Date
4079
+ */
4080
+ public function getHour($locale = null)
4081
+ {
4082
+ return $this->copyPart(Zend_Date::HOUR, $locale);
4083
+ }
4084
+
4085
+
4086
+ /**
4087
+ * Sets a new hour
4088
+ * The hour is always a number.
4089
+ * Returned is the new date object
4090
+ * Example: 04.May.1993 13:07:25 -> setHour(7); -> 04.May.1993 07:07:25
4091
+ *
4092
+ * @param string|integer|array|Zend_Date $hour Hour to set
4093
+ * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
4094
+ * @return Zend_Date new date
4095
+ * @throws Zend_Date_Exception
4096
+ */
4097
+ public function setHour($hour, $locale = null)
4098
+ {
4099
+ return $this->_calcvalue('set', $hour, 'hour', Zend_Date::HOUR_SHORT, $locale);
4100
+ }
4101
+
4102
+
4103
+ /**
4104
+ * Adds hours to the existing date object.
4105
+ * The hour is always a number.
4106
+ * Returned is the new date object
4107
+ * Example: 04.May.1993 13:07:25 -> addHour(12); -> 05.May.1993 01:07:25
4108
+ *
4109
+ * @param string|integer|array|Zend_Date $hour Hour to add
4110
+ * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
4111
+ * @return Zend_Date new date
4112
+ * @throws Zend_Date_Exception
4113
+ */
4114
+ public function addHour($hour, $locale = null)
4115
+ {
4116
+ return $this->_calcvalue('add', $hour, 'hour', Zend_Date::HOUR_SHORT, $locale);
4117
+ }
4118
+
4119
+
4120
+ /**
4121
+ * Subtracts hours from the existing date object.
4122
+ * The hour is always a number.
4123
+ * Returned is the new date object
4124
+ * Example: 04.May.1993 13:07:25 -> subHour(6); -> 05.May.1993 07:07:25
4125
+ *
4126
+ * @param string|integer|array|Zend_Date $hour Hour to sub
4127
+ * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
4128
+ * @return Zend_Date new date
4129
+ * @throws Zend_Date_Exception
4130
+ */
4131
+ public function subHour($hour, $locale = null)
4132
+ {
4133
+ return $this->_calcvalue('sub', $hour, 'hour', Zend_Date::HOUR_SHORT, $locale);
4134
+ }
4135
+
4136
+
4137
+ /**
4138
+ * Compares the hour with the existing date object.
4139
+ * For example: 10:30:25 -> compareHour(10) -> 0
4140
+ * Returns if equal, earlier or later
4141
+ *
4142
+ * @param string|integer|array|Zend_Date $hour Hour to compare
4143
+ * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
4144
+ * @return integer 0 = equal, 1 = later, -1 = earlier
4145
+ * @throws Zend_Date_Exception
4146
+ */
4147
+ public function compareHour($hour, $locale = null)
4148
+ {
4149
+ return $this->_calcvalue('cmp', $hour, 'hour', Zend_Date::HOUR_SHORT, $locale);
4150
+ }
4151
+
4152
+
4153
+ /**
4154
+ * Returns the minute as new date object
4155
+ * Example: 02.Feb.1986 10:30:25 -> 01.Jan.1970 00:30:00
4156
+ *
4157
+ * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
4158
+ * @return Zend_Date
4159
+ */
4160
+ public function getMinute($locale = null)
4161
+ {
4162
+ return $this->copyPart(Zend_Date::MINUTE, $locale);
4163
+ }
4164
+
4165
+
4166
+ /**
4167
+ * Sets a new minute
4168
+ * The minute is always a number.
4169
+ * Returned is the new date object
4170
+ * Example: 04.May.1993 13:07:25 -> setMinute(29); -> 04.May.1993 13:29:25
4171
+ *
4172
+ * @param string|integer|array|Zend_Date $minute Minute to set
4173
+ * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
4174
+ * @return Zend_Date new date
4175
+ * @throws Zend_Date_Exception
4176
+ */
4177
+ public function setMinute($minute, $locale = null)
4178
+ {
4179
+ return $this->_calcvalue('set', $minute, 'minute', Zend_Date::MINUTE_SHORT, $locale);
4180
+ }
4181
+
4182
+
4183
+ /**
4184
+ * Adds minutes to the existing date object.
4185
+ * The minute is always a number.
4186
+ * Returned is the new date object
4187
+ * Example: 04.May.1993 13:07:25 -> addMinute(65); -> 04.May.1993 13:12:25
4188
+ *
4189
+ * @param string|integer|array|Zend_Date $minute Minute to add
4190
+ * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
4191
+ * @return Zend_Date new date
4192
+ * @throws Zend_Date_Exception
4193
+ */
4194
+ public function addMinute($minute, $locale = null)
4195
+ {
4196
+ return $this->_calcvalue('add', $minute, 'minute', Zend_Date::MINUTE_SHORT, $locale);
4197
+ }
4198
+
4199
+
4200
+ /**
4201
+ * Subtracts minutes from the existing date object.
4202
+ * The minute is always a number.
4203
+ * Returned is the new date object
4204
+ * Example: 04.May.1993 13:07:25 -> subMinute(9); -> 04.May.1993 12:58:25
4205
+ *
4206
+ * @param string|integer|array|Zend_Date $minute Minute to sub
4207
+ * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
4208
+ * @return Zend_Date new date
4209
+ * @throws Zend_Date_Exception
4210
+ */
4211
+ public function subMinute($minute, $locale = null)
4212
+ {
4213
+ return $this->_calcvalue('sub', $minute, 'minute', Zend_Date::MINUTE_SHORT, $locale);
4214
+ }
4215
+
4216
+
4217
+ /**
4218
+ * Compares the minute with the existing date object.
4219
+ * For example: 10:30:25 -> compareMinute(30) -> 0
4220
+ * Returns if equal, earlier or later
4221
+ *
4222
+ * @param string|integer|array|Zend_Date $minute Hour to compare
4223
+ * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
4224
+ * @return integer 0 = equal, 1 = later, -1 = earlier
4225
+ * @throws Zend_Date_Exception
4226
+ */
4227
+ public function compareMinute($minute, $locale = null)
4228
+ {
4229
+ return $this->_calcvalue('cmp', $minute, 'minute', Zend_Date::MINUTE_SHORT, $locale);
4230
+ }
4231
+
4232
+
4233
+ /**
4234
+ * Returns the second as new date object
4235
+ * Example: 02.Feb.1986 10:30:25 -> 01.Jan.1970 00:00:25
4236
+ *
4237
+ * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
4238
+ * @return Zend_Date
4239
+ */
4240
+ public function getSecond($locale = null)
4241
+ {
4242
+ return $this->copyPart(Zend_Date::SECOND, $locale);
4243
+ }
4244
+
4245
+
4246
+ /**
4247
+ * Sets new seconds to the existing date object.
4248
+ * The second is always a number.
4249
+ * Returned is the new date object
4250
+ * Example: 04.May.1993 13:07:25 -> setSecond(100); -> 04.May.1993 13:08:40
4251
+ *
4252
+ * @param string|integer|array|Zend_Date $second Second to set
4253
+ * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
4254
+ * @return Zend_Date new date
4255
+ * @throws Zend_Date_Exception
4256
+ */
4257
+ public function setSecond($second, $locale = null)
4258
+ {
4259
+ return $this->_calcvalue('set', $second, 'second', Zend_Date::SECOND_SHORT, $locale);
4260
+ }
4261
+
4262
+
4263
+ /**
4264
+ * Adds seconds to the existing date object.
4265
+ * The second is always a number.
4266
+ * Returned is the new date object
4267
+ * Example: 04.May.1993 13:07:25 -> addSecond(65); -> 04.May.1993 13:08:30
4268
+ *
4269
+ * @param string|integer|array|Zend_Date $second Second to add
4270
+ * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
4271
+ * @return Zend_Date new date
4272
+ * @throws Zend_Date_Exception
4273
+ */
4274
+ public function addSecond($second, $locale = null)
4275
+ {
4276
+ return $this->_calcvalue('add', $second, 'second', Zend_Date::SECOND_SHORT, $locale);
4277
+ }
4278
+
4279
+
4280
+ /**
4281
+ * Subtracts seconds from the existing date object.
4282
+ * The second is always a number.
4283
+ * Returned is the new date object
4284
+ * Example: 04.May.1993 13:07:25 -> subSecond(10); -> 04.May.1993 13:07:15
4285
+ *
4286
+ * @param string|integer|array|Zend_Date $second Second to sub
4287
+ * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
4288
+ * @return Zend_Date new date
4289
+ * @throws Zend_Date_Exception
4290
+ */
4291
+ public function subSecond($second, $locale = null)
4292
+ {
4293
+ return $this->_calcvalue('sub', $second, 'second', Zend_Date::SECOND_SHORT, $locale);
4294
+ }
4295
+
4296
+
4297
+ /**
4298
+ * Compares the second with the existing date object.
4299
+ * For example: 10:30:25 -> compareSecond(25) -> 0
4300
+ * Returns if equal, earlier or later
4301
+ *
4302
+ * @param string|integer|array|Zend_Date $second Second to compare
4303
+ * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
4304
+ * @return integer 0 = equal, 1 = later, -1 = earlier
4305
+ * @throws Zend_Date_Exception
4306
+ */
4307
+ public function compareSecond($second, $locale = null)
4308
+ {
4309
+ return $this->_calcvalue('cmp', $second, 'second', Zend_Date::SECOND_SHORT, $locale);
4310
+ }
4311
+
4312
+
4313
+ /**
4314
+ * Returns the precision for fractional seconds
4315
+ *
4316
+ * @return integer
4317
+ */
4318
+ public function getFractionalPrecision()
4319
+ {
4320
+ return $this->_Precision;
4321
+ }
4322
+
4323
+
4324
+ /**
4325
+ * Sets a new precision for fractional seconds
4326
+ *
4327
+ * @param integer $precision Precision for the fractional datepart 3 = milliseconds
4328
+ * @throws Zend_Date_Exception
4329
+ */
4330
+ public function setFractionalPrecision($precision)
4331
+ {
4332
+ if (!intval($precision) or ($precision < 0) or ($precision > 9)) {
4333
+ require_once 'Zend/Date/Exception.php';
4334
+ throw new Zend_Date_Exception("precision ($precision) must be a positive integer less than 10", $precision);
4335
+ }
4336
+ $this->_Precision = (int) $precision;
4337
+ }
4338
+
4339
+
4340
+ /**
4341
+ * Returns the milliseconds of the date object
4342
+ *
4343
+ * @return integer
4344
+ */
4345
+ public function getMilliSecond()
4346
+ {
4347
+ return $this->_Fractional;
4348
+ }
4349
+
4350
+
4351
+ /**
4352
+ * Sets new milliseconds for the date object
4353
+ * Example: setMilliSecond(550, 2) -> equals +5 Sec +50 MilliSec
4354
+ *
4355
+ * @param integer|Zend_Date $milli OPTIONAL Millisecond to set, when null the actual millisecond is set
4356
+ * @param integer $precision OPTIONAL Fraction precision of the given milliseconds
4357
+ * @return integer|string
4358
+ */
4359
+ public function setMilliSecond($milli = null, $precision = null)
4360
+ {
4361
+ if ($milli === null) {
4362
+ list($milli, $time) = explode(" ", microtime());
4363
+ $milli = intval($milli);
4364
+ $precision = 6;
4365
+ } else if (!is_numeric($milli)) {
4366
+ require_once 'Zend/Date/Exception.php';
4367
+ throw new Zend_Date_Exception("invalid milli second ($milli) operand", $milli);
4368
+ }
4369
+
4370
+ if ($precision === null) {
4371
+ $precision = $this->_Precision;
4372
+ } else if (!is_int($precision) || $precision < 1 || $precision > 9) {
4373
+ require_once 'Zend/Date/Exception.php';
4374
+ throw new Zend_Date_Exception("precision ($precision) must be a positive integer less than 10", $precision);
4375
+ }
4376
+
4377
+ $this->_Fractional = 0;
4378
+ $this->addMilliSecond($milli, $precision);
4379
+ return $this->_Fractional;
4380
+ }
4381
+
4382
+
4383
+ /**
4384
+ * Adds milliseconds to the date object
4385
+ *
4386
+ * @param integer|Zend_Date $milli OPTIONAL Millisecond to add, when null the actual millisecond is added
4387
+ * @param integer $precision OPTIONAL Fractional precision for the given milliseconds
4388
+ * @return integer|string
4389
+ */
4390
+ public function addMilliSecond($milli = null, $precision = null)
4391
+ {
4392
+ if ($milli === null) {
4393
+ list($milli, $time) = explode(" ", microtime());
4394
+ $milli = intval($milli);
4395
+ } else if (!is_numeric($milli)) {
4396
+ require_once 'Zend/Date/Exception.php';
4397
+ throw new Zend_Date_Exception("invalid milli second ($milli) operand", $milli);
4398
+ }
4399
+
4400
+ if ($precision === null) {
4401
+ $precision = $this->_Precision;
4402
+ } else if (!is_int($precision) || $precision < 1 || $precision > 9) {
4403
+ require_once 'Zend/Date/Exception.php';
4404
+ throw new Zend_Date_Exception("precision ($precision) must be a positive integer less than 10", $precision);
4405
+ }
4406
+
4407
+ if ($precision != $this->_Precision) {
4408
+ if ($precision > $this->_Precision) {
4409
+ $diff = $precision - $this->_Precision;
4410
+ $milli = (int) ($milli / (10 * $diff));
4411
+ } else {
4412
+ $diff = $this->_Precision - $precision;
4413
+ $milli = (int) ($milli * (10 * $diff));
4414
+ }
4415
+ }
4416
+
4417
+ $this->_Fractional += $milli;
4418
+ // add/sub milliseconds + add/sub seconds
4419
+
4420
+ $max = pow(10, $this->_Precision);
4421
+ // milli includes seconds
4422
+ if ($this->_Fractional > $max) {
4423
+ while ($this->_Fractional > $max) {
4424
+ $this->addSecond(1);
4425
+ $this->_Fractional -= $max;
4426
+ }
4427
+ }
4428
+
4429
+ if ($this->_Fractional < 0) {
4430
+ while ($this->_Fractional < 0) {
4431
+ $this->subSecond(1);
4432
+ $this->_Fractional += $max;
4433
+ }
4434
+ }
4435
+ return $this->_Fractional;
4436
+ }
4437
+
4438
+
4439
+ /**
4440
+ * Subtracts a millisecond
4441
+ *
4442
+ * @param integer|Zend_Date $milli OPTIONAL Millisecond to sub, when null the actual millisecond is subtracted
4443
+ * @param integer $precision OPTIONAL Fractional precision for the given milliseconds
4444
+ * @return integer
4445
+ */
4446
+ public function subMilliSecond($milli = null, $precision = null)
4447
+ {
4448
+ return $this->addMilliSecond(0 - $milli);
4449
+ }
4450
+
4451
+
4452
+ /**
4453
+ * Compares only the millisecond part, returning the difference
4454
+ *
4455
+ * @param integer|Zend_Date $milli OPTIONAL Millisecond to compare, when null the actual millisecond is compared
4456
+ * @param integer $precision OPTIONAL Fractional precision for the given milliseconds
4457
+ * @return integer
4458
+ */
4459
+ public function compareMilliSecond($milli = null, $precision = null)
4460
+ {
4461
+ if ($milli === null) {
4462
+ list($milli, $time) = explode(" ", microtime());
4463
+ $milli = intval($milli);
4464
+ } else if (!is_numeric($milli)) {
4465
+ require_once 'Zend/Date/Exception.php';
4466
+ throw new Zend_Date_Exception("invalid milli second ($milli) operand", $milli);
4467
+ }
4468
+
4469
+ if ($precision === null) {
4470
+ $precision = $this->_Precision;
4471
+ } else if (!is_int($precision) || $precision < 1 || $precision > 9) {
4472
+ require_once 'Zend/Date/Exception.php';
4473
+ throw new Zend_Date_Exception("precision ($precision) must be a positive integer less than 10", $precision);
4474
+ }
4475
+
4476
+ if ($precision === 0) {
4477
+ require_once 'Zend/Date/Exception.php';
4478
+ throw new Zend_Date_Exception('precision is 0');
4479
+ }
4480
+
4481
+ if ($precision != $this->_Precision) {
4482
+ if ($precision > $this->_Precision) {
4483
+ $diff = $precision - $this->_Precision;
4484
+ $milli = (int) ($milli / (10 * $diff));
4485
+ } else {
4486
+ $diff = $this->_Precision - $precision;
4487
+ $milli = (int) ($milli * (10 * $diff));
4488
+ }
4489
+ }
4490
+
4491
+ $comp = $this->_Fractional - $milli;
4492
+ if ($comp < 0) {
4493
+ return -1;
4494
+ } else if ($comp > 0) {
4495
+ return 1;
4496
+ }
4497
+ return 0;
4498
+ }
4499
+
4500
+
4501
+ /**
4502
+ * Returns the week as new date object using monday as begining of the week
4503
+ * Example: 12.Jan.2007 -> 08.Jan.1970 00:00:00
4504
+ *
4505
+ * @param $locale string|Zend_Locale OPTIONAL Locale for parsing input
4506
+ * @return Zend_Date
4507
+ */
4508
+ public function getWeek($locale = null)
4509
+ {
4510
+ return $this->copyPart(Zend_Date::WEEK, $locale);
4511
+ }
4512
+
4513
+
4514
+ /**
4515
+ * Sets a new week. The week is always a number. The day of week is not changed.
4516
+ * Returned is the new date object
4517
+ * Example: 09.Jan.2007 13:07:25 -> setWeek(1); -> 02.Jan.2007 13:07:25
4518
+ *
4519
+ * @param string|integer|array|Zend_Date $week Week to set
4520
+ * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
4521
+ * @return Zend_Date
4522
+ * @throws Zend_Date_Exception
4523
+ */
4524
+ public function setWeek($week, $locale = null)
4525
+ {
4526
+ return $this->_calcvalue('set', $week, 'week', Zend_Date::WEEK, $locale);
4527
+ }
4528
+
4529
+
4530
+ /**
4531
+ * Adds a week. The week is always a number. The day of week is not changed.
4532
+ * Returned is the new date object
4533
+ * Example: 09.Jan.2007 13:07:25 -> addWeek(1); -> 16.Jan.2007 13:07:25
4534
+ *
4535
+ * @param string|integer|array|Zend_Date $week Week to add
4536
+ * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
4537
+ * @return Zend_Date
4538
+ * @throws Zend_Date_Exception
4539
+ */
4540
+ public function addWeek($week, $locale = null)
4541
+ {
4542
+ return $this->_calcvalue('add', $week, 'week', Zend_Date::WEEK, $locale);
4543
+ }
4544
+
4545
+
4546
+ /**
4547
+ * Subtracts a week. The week is always a number. The day of week is not changed.
4548
+ * Returned is the new date object
4549
+ * Example: 09.Jan.2007 13:07:25 -> subWeek(1); -> 02.Jan.2007 13:07:25
4550
+ *
4551
+ * @param string|integer|array|Zend_Date $week Week to sub
4552
+ * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
4553
+ * @return Zend_Date
4554
+ * @throws Zend_Date_Exception
4555
+ */
4556
+ public function subWeek($week, $locale = null)
4557
+ {
4558
+ return $this->_calcvalue('sub', $week, 'week', Zend_Date::WEEK, $locale);
4559
+ }
4560
+
4561
+
4562
+ /**
4563
+ * Compares only the week part, returning the difference
4564
+ * Returned is the new date object
4565
+ * Returns if equal, earlier or later
4566
+ * Example: 09.Jan.2007 13:07:25 -> compareWeek(2); -> 0
4567
+ *
4568
+ * @param string|integer|array|Zend_Date $week Week to compare
4569
+ * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
4570
+ * @return integer 0 = equal, 1 = later, -1 = earlier
4571
+ * @throws Zend_Date_Exception
4572
+ */
4573
+ public function compareWeek($week, $locale = null)
4574
+ {
4575
+ return $this->_calcvalue('cmp', $week, 'week', Zend_Date::WEEK, $locale);
4576
+ }
4577
+
4578
+
4579
+ /**
4580
+ * Sets a new standard locale for the date object.
4581
+ * This locale will be used for all functions
4582
+ * Returned is the really set locale.
4583
+ * Example: 'de_XX' will be set to 'de' because 'de_XX' does not exist
4584
+ * 'xx_YY' will be set to 'root' because 'xx' does not exist
4585
+ *
4586
+ * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
4587
+ * @return string
4588
+ */
4589
+ public function setLocale($locale = null)
4590
+ {
4591
+ if ($locale instanceof Zend_Locale) {
4592
+ $this->_Locale = $locale;
4593
+ } else if (!$locale = Zend_Locale::isLocale($locale, true)) {
4594
+ require_once 'Zend/Date/Exception.php';
4595
+ throw new Zend_Date_Exception("Given locale ($locale) does not exist", $locale);
4596
+ } else {
4597
+ $this->_Locale = new Zend_Locale($locale);
4598
+ }
4599
+ return $this->getLocale();
4600
+ }
4601
+
4602
+
4603
+ /**
4604
+ * Returns the actual set locale
4605
+ *
4606
+ * @return string
4607
+ */
4608
+ public function getLocale()
4609
+ {
4610
+ return $this->_Locale->toString();
4611
+ }
4612
+
4613
+
4614
+ /**
4615
+ * Checks if the given date is a real date or datepart.
4616
+ * Returns false if a expected datepart is missing or a datepart exceeds its possible border.
4617
+ * But the check will only be done for the expected dateparts which are given by format.
4618
+ * If no format is given the standard dateformat for the actual locale is used.
4619
+ * f.e. 30.February.2007 will return false if format is 'dd.MMMM.YYYY'
4620
+ *
4621
+ * @param string $date Date to parse for correctness
4622
+ * @param string $format OPTIONAL Format for parsing the date string
4623
+ * @param string|Zend_Locale $locale OPTIONAL Locale for parsing date parts
4624
+ * @return boolean True when all date parts are correct
4625
+ */
4626
+ public static function isDate($date, $format = null, $locale = null)
4627
+ {
4628
+ if (Zend_Locale::isLocale($format)) {
4629
+ $locale = $format;
4630
+ $format = null;
4631
+ }
4632
+
4633
+ if ($locale === null) {
4634
+ $locale = new Zend_Locale();
4635
+ $locale = $locale->toString();
4636
+ }
4637
+
4638
+ if ($format === null) {
4639
+ $format = Zend_Locale_Format::getDateFormat($locale);
4640
+ } else if (self::$_Options['format_type'] == 'php') {
4641
+ $format = Zend_Locale_Format::convertPhpToIsoFormat($format);
4642
+ }
4643
+
4644
+ try {
4645
+ $parsed = Zend_Locale_Format::getDate($date, array('locale' => $locale, 'date_format' => $format, 'format_type' => 'iso', 'fix_date' => false));
4646
+ if ((strpos(strtoupper($format), 'YY') !== false) and (strpos(strtoupper($format), 'YYYY') === false)) {
4647
+ $parsed['year'] = self::_century($parsed['year']);
4648
+ }
4649
+ } catch (Zend_Locale_Exception $e) {
4650
+ // date can not be parsed
4651
+ return false;
4652
+ }
4653
+
4654
+ if (((strpos($format, 'Y') !== false) or (strpos($format, 'y') !== false)) and (!isset($parsed['year']))) {
4655
+ // year expected but not found
4656
+ return false;
4657
+ }
4658
+ if ((strpos($format, 'M') !== false) and (!isset($parsed['month']))) {
4659
+ // month expected but not found
4660
+ return false;
4661
+ }
4662
+ if ((strpos($format, 'd') !== false) and (!isset($parsed['day']))) {
4663
+ // day expected but not found
4664
+ return false;
4665
+ }
4666
+ if (((strpos($format, 'H') !== false) or (strpos($format, 'h') !== false)) and (!isset($parsed['hour']))) {
4667
+ // hour expected but not found
4668
+ return false;
4669
+ }
4670
+ if ((strpos($format, 'm') !== false) and (!isset($parsed['minute']))) {
4671
+ // minute expected but not found
4672
+ return false;
4673
+ }
4674
+ if ((strpos($format, 's') !== false) and (!isset($parsed['second']))) {
4675
+ // second expected but not found
4676
+ return false;
4677
+ }
4678
+
4679
+ // set not given dateparts
4680
+ if (!isset($parsed['hour'])) {
4681
+ $parsed['hour'] = 0;
4682
+ }
4683
+ if (!isset($parsed['minute'])) {
4684
+ $parsed['minute'] = 0;
4685
+ }
4686
+ if (!isset($parsed['second'])) {
4687
+ $parsed['second'] = 0;
4688
+ }
4689
+ if (!isset($parsed['month'])) {
4690
+ $parsed['month'] = 1;
4691
+ }
4692
+ if (!isset($parsed['day'])) {
4693
+ $parsed['day'] = 1;
4694
+ }
4695
+ if (!isset($parsed['year'])) {
4696
+ $parsed['year'] = 1970;
4697
+ }
4698
+ $date = new self($locale);
4699
+ $timestamp = $date->mktime($parsed['hour'], $parsed['minute'], $parsed['second'],
4700
+ $parsed['month'], $parsed['day'], $parsed['year']);
4701
+ if ($parsed['year'] != $date->date('Y', $timestamp)) {
4702
+ // given year differs from parsed year
4703
+ return false;
4704
+ }
4705
+ if ($parsed['month'] != $date->date('n', $timestamp)) {
4706
+ // given month differs from parsed month
4707
+ return false;
4708
+ }
4709
+ if ($parsed['day'] != $date->date('j', $timestamp)) {
4710
+ // given day differs from parsed day
4711
+ return false;
4712
+ }
4713
+ if ($parsed['hour'] != $date->date('G', $timestamp)) {
4714
+ // given hour differs from parsed hour
4715
+ return false;
4716
+ }
4717
+ if ($parsed['minute'] != $date->date('i', $timestamp)) {
4718
+ // given minute differs from parsed minute
4719
+ return false;
4720
+ }
4721
+ if ($parsed['second'] != $date->date('s', $timestamp)) {
4722
+ // given second differs from parsed second
4723
+ return false;
4724
+ }
4725
+ return true;
4726
+ }
4727
+ }
lib/Zend/Date/Cities.php ADDED
@@ -0,0 +1,315 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Zend Framework
4
+ *
5
+ * LICENSE
6
+ *
7
+ * This source file is subject to the new BSD license that is bundled
8
+ * with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://framework.zend.com/license/new-bsd
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@zend.com so we can send you a copy immediately.
14
+ *
15
+ * @category Zend
16
+ * @package Zend_Date
17
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
18
+ * @version $Id: DateObject.php 2511 2006-12-26 22:54:37Z bkarwin $
19
+ * @license http://framework.zend.com/license/new-bsd New BSD License
20
+ */
21
+
22
+ /**
23
+ * Additional data for sunset/sunrise calculations
24
+ * Holds the geographical data for all capital cities and many others worldwide
25
+ * Original data from http://www.fallingrain.com/world/
26
+ *
27
+ * @category Zend
28
+ * @package Zend_Date
29
+ * @subpackage Zend_Date_Cities
30
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
31
+ * @license http://framework.zend.com/license/new-bsd New BSD License
32
+ */
33
+ class Zend_Date_Cities {
34
+
35
+ public static $Cities = array(
36
+ 'Abidjan' => array('latitude' => 5.3411111, 'longitude' => -4.0280556),
37
+ 'Abu Dhabi' => array('latitude' => 24.4666667, 'longitude' => 54.3666667),
38
+ 'Abuja' => array('latitude' => 9.1758333, 'longitude' => 7.1808333),
39
+ 'Accra' => array('latitude' => 5.55, 'longitude' => -0.2166667),
40
+ 'Adamstown' => array('latitude' => -25.0666667, 'longitude' => -130.0833333),
41
+ 'Addis Ababa' => array('latitude' => 9.0333333, 'longitude' => 38.7),
42
+ 'Adelaide' => array('latitude' => -34.9333333, 'longitude' => 138.6),
43
+ 'Algiers' => array('latitude' => 36.7630556, 'longitude' => 3.0505556),
44
+ 'Alofi' => array('latitude' => -19.0166667, 'longitude' => -169.9166667),
45
+ 'Amman' => array('latitude' => 31.95, 'longitude' => 35.9333333),
46
+ 'Amsterdam' => array('latitude' => 52.35, 'longitude' => 4.9166667),
47
+ 'Andorra la Vella' => array('latitude' => 42.5, 'longitude' => 1.5166667),
48
+ 'Ankara' => array('latitude' => 39.9272222, 'longitude' => 32.8644444),
49
+ 'Antananarivo' => array('latitude' => -18.9166667, 'longitude' => 47.5166667),
50
+ 'Apia' => array('latitude' => -13.8333333, 'longitude' => -171.7333333),
51
+ 'Ashgabat' => array('latitude' => 37.95, 'longitude' => 58.3833333),
52
+ 'Asmara' => array('latitude' => 15.3333333, 'longitude' => 38.9333333),
53
+ 'Astana' => array('latitude' => 51.1811111, 'longitude' => 71.4277778),
54
+ 'Asunción' => array('latitude' => -25.2666667, 'longitude' => -57.6666667),
55
+ 'Athens' => array('latitude' => 37.9833333, 'longitude' => 23.7333333),
56
+ 'Auckland' => array('latitude' => -36.8666667, 'longitude' => 174.7666667),
57
+ 'Avarua' => array('latitude' => -21.2, 'longitude' => -159.7666667),
58
+ 'Baghdad' => array('latitude' => 33.3386111, 'longitude' => 44.3938889),
59
+ 'Baku' => array('latitude' => 40.3952778, 'longitude' => 49.8822222),
60
+ 'Bamako' => array('latitude' => 12.65, 'longitude' => -8),
61
+ 'Bandar Seri Begawan' => array('latitude' => 4.8833333, 'longitude' => 114.9333333),
62
+ 'Bankok' => array('latitude' => 13.5833333, 'longitude' => 100.2166667),
63
+ 'Bangui' => array('latitude' => 4.3666667, 'longitude' => 18.5833333),
64
+ 'Banjul' => array('latitude' => 13.4530556, 'longitude' => -16.5775),
65
+ 'Basel' => array('latitude' => 47.5666667, 'longitude' => 7.6),
66
+ 'Basseterre' => array('latitude' => 17.3, 'longitude' => -62.7166667),
67
+ 'Beijing' => array('latitude' => 39.9288889, 'longitude' => 116.3883333),
68
+ 'Beirut' => array('latitude' => 33.8719444, 'longitude' => 35.5097222),
69
+ 'Belgrade' => array('latitude' => 44.8186111, 'longitude' => 20.4680556),
70
+ 'Belmopan' => array('latitude' => 17.25, 'longitude' => -88.7666667),
71
+ 'Berlin' => array('latitude' => 52.5166667, 'longitude' => 13.4),
72
+ 'Bern' => array('latitude' => 46.9166667, 'longitude' => 7.4666667),
73
+ 'Bishkek' => array('latitude' => 42.8730556, 'longitude' => 74.6002778),
74
+ 'Bissau' => array('latitude' => 11.85, 'longitude' => -15.5833333),
75
+ 'Bloemfontein' => array('latitude' => -29.1333333, 'longitude' => 26.2),
76
+ 'Bogotá' => array('latitude' => 4.6, 'longitude' => -74.0833333),
77
+ 'Brasilia' => array('latitude' => -15.7833333, 'longitude' => -47.9166667),
78
+ 'Bratislava' => array('latitude' => 48.15, 'longitude' => 17.1166667),
79
+ 'Brazzaville' => array('latitude' => -4.2591667, 'longitude' => 15.2847222),
80
+ 'Bridgetown' => array('latitude' => 13.1, 'longitude' => -59.6166667),
81
+ 'Brisbane' => array('latitude' => -27.5, 'longitude' => 153.0166667),
82
+ 'Brussels' => array('latitude' => 50.8333333, 'longitude' => 4.3333333),
83
+ 'Bucharest' => array('latitude' => 44.4333333, 'longitude' => 26.1),
84
+ 'Budapest' => array('latitude' => 47.5, 'longitude' => 19.0833333),
85
+ 'Buenos Aires' => array('latitude' => -34.5875, 'longitude' => -58.6725),
86
+ 'Bujumbura' => array('latitude' => -3.3761111, 'longitude' => 29.36),
87
+ 'Cairo' => array('latitude' => 30.05, 'longitude' => 31.25),
88
+ 'Calgary' => array('latitude' => 51.0833333, 'longitude' => -114.0833333),
89
+ 'Canberra' => array('latitude' => -35.2833333, 'longitude' => 149.2166667),
90
+ 'Cape Town' => array('latitude' => -33.9166667, 'longitude' => 18.4166667),
91
+ 'Caracas' => array('latitude' => 10.5, 'longitude' => -66.9166667),
92
+ 'Castries' => array('latitude' => 14, 'longitude' => -61),
93
+ 'Charlotte Amalie' => array('latitude' => 18.34389, 'longitude' => -64.93111),
94
+ 'Chicago' => array('latitude' => 41.85, 'longitude' => -87.65),
95
+ 'Chisinau' => array('latitude' => 47.055556, 'longitude' => 28.8575),
96
+ 'Cockburn Town' => array('latitude' => 21.4666667, 'longitude' => -71.1333333),
97
+ 'Colombo' => array('latitude' => 6.9319444, 'longitude' => 79.8477778),
98
+ 'Conakry' => array('latitude' => 9.5091667, 'longitude' => -13.7122222),
99
+ 'Copenhagen' => array('latitude' => 55.6666667, 'longitude' => 12.5833333),
100
+ 'Cotonou' => array('latitude' => 6.35, 'longitude' => 2.4333333),
101
+ 'Dakar' => array('latitude' => 14.6708333, 'longitude' => -17.4380556),
102
+ 'Damascus' => array('latitude' => 33.5, 'longitude' => 36.3),
103
+ 'Dar es Salaam' => array('latitude' => -6.8, 'longitude' => 39.2833333),
104
+ 'Dhaka' => array('latitude' => 23.7230556, 'longitude' => 90.4086111),
105
+ 'Dili' => array('latitude' => -8.5586111, 'longitude' => 125.5736111),
106
+ 'Djibouti' => array('latitude' => 11.595, 'longitude' => 43.1480556),
107
+ 'Dodoma' => array('latitude' => -6.1833333, 'longitude' => 35.75),
108
+ 'Doha' => array('latitude' => 25.2866667, 'longitude' => 51.5333333),
109
+ 'Dubai' => array('latitude' => 25.2522222, 'longitude' => 55.28),
110
+ 'Dublin' => array('latitude' => 53.3330556, 'longitude' => -6.2488889),
111
+ 'Dushanbe' => array('latitude' => 38.56, 'longitude' => 68.7738889 ),
112
+ 'Fagatogo' => array('latitude' => -14.2825, 'longitude' => -170.69),
113
+ 'Fongafale' => array('latitude' => -8.5166667, 'longitude' => 179.2166667),
114
+ 'Freetown' => array('latitude' => 8.49, 'longitude' => -13.2341667),
115
+ 'Gaborone' => array('latitude' => -24.6463889, 'longitude' => 25.9119444),
116
+ 'Geneva' => array('latitude' => 46.2, 'longitude' => 6.1666667),
117
+ 'George Town' => array('latitude' => 19.3, 'longitude' => -81.3833333),
118
+ 'Georgetown' => array('latitude' => 6.8, 'longitude' => -58.1666667),
119
+ 'Gibraltar' => array('latitude' => 36.1333333, 'longitude' => -5.35),
120
+ 'Glasgow' => array('latitude' => 55.8333333, 'longitude' => -4.25),
121
+ 'Guatemala la Nueva' => array('latitude' => 14.6211111, 'longitude' => -90.5269444),
122
+ 'Hagatna' => array('latitude' => 13.47417, 'longitude' => 144.74778),
123
+ 'The Hague' => array('latitude' => 52.0833333, 'longitude' => 4.3),
124
+ 'Hamilton' => array('latitude' => 32.2941667, 'longitude' => -64.7838889),
125
+ 'Hanoi' => array('latitude' => 21.0333333, 'longitude' => 105.85),
126
+ 'Harare' => array('latitude' => -17.8177778, 'longitude' => 31.0447222),
127
+ 'Havana' => array('latitude' => 23.1319444, 'longitude' => -82.3641667),
128
+ 'Helsinki' => array('latitude' => 60.1755556, 'longitude' => 24.9341667),
129
+ 'Honiara' => array('latitude' => -9.4333333, 'longitude' => 159.95),
130
+ 'Islamabad' => array('latitude' => 30.8486111, 'longitude' => 72.4944444),
131
+ 'Istanbul' => array('latitude' => 41.0186111, 'longitude' => 28.9647222),
132
+ 'Jakarta' => array('latitude' => -6.1744444, 'longitude' => 106.8294444),
133
+ 'Jamestown' => array('latitude' => -15.9333333, 'longitude' => -5.7166667),
134
+ 'Jerusalem' => array('latitude' => 31.7666667, 'longitude' => 35.2333333),
135
+ 'Johannesburg' => array('latitude' => -26.2, 'longitude' => 28.0833333),
136
+ 'Kabul' => array('latitude' => 34.5166667, 'longitude' => 69.1833333),
137
+ 'Kampala' => array('latitude' => 0.3155556, 'longitude' => 32.5655556),
138
+ 'Kathmandu' => array('latitude' => 27.7166667, 'longitude' => 85.3166667),
139
+ 'Khartoum' => array('latitude' => 15.5880556, 'longitude' => 32.5341667),
140
+ 'Kigali' => array('latitude' => -1.9536111, 'longitude' => 30.0605556),
141
+ 'Kingston' => array('latitude' => -29.05, 'longitude' => 167.95),
142
+ 'Kingstown' => array('latitude' => 13.1333333, 'longitude' => -61.2166667),
143
+ 'Kinshasa' => array('latitude' => -4.3, 'longitude' => 15.3),
144
+ 'Kolkata' => array('latitude' => 22.5697222, 'longitude' => 88.3697222),
145
+ 'Kuala Lumpur' => array('latitude' => 3.1666667, 'longitude' => 101.7),
146
+ 'Kuwait City' => array('latitude' => 29.3697222, 'longitude' => 47.9783333),
147
+ 'Kiev' => array('latitude' => 50.4333333, 'longitude' => 30.5166667),
148
+ 'La Paz' => array('latitude' => -16.5, 'longitude' => -68.15),
149
+ 'Libreville' => array('latitude' => 0.3833333, 'longitude' => 9.45),
150
+ 'Lilongwe' => array('latitude' => -13.9833333, 'longitude' => 33.7833333),
151
+ 'Lima' => array('latitude' => -12.05, 'longitude' => -77.05),
152
+ 'Lisbon' => array('latitude' => 38.7166667, 'longitude' => -9.1333333),
153
+ 'Ljubljana' => array('latitude' => 46.0552778, 'longitude' => 14.5144444),
154
+ 'Lobamba' => array('latitude' => -26.4666667, 'longitude' => 31.2),
155
+ 'Lomé' => array('latitude' => 9.7166667, 'longitude' => 38.3),
156
+ 'London' => array('latitude' => 51.5, 'longitude' => -0.1166667),
157
+ 'Los Angeles' => array('latitude' => 34.05222, 'longitude' => -118.24278),
158
+ 'Luanda' => array('latitude' => -8.8383333, 'longitude' => 13.2344444),
159
+ 'Lusaka' => array('latitude' => -15.4166667, 'longitude' => 28.2833333),
160
+ 'Luxembourg' => array('latitude' => 49.6116667, 'longitude' => 6.13),
161
+ 'Madrid' => array('latitude' => 40.4, 'longitude' => -3.6833333),
162
+ 'Majuro' => array('latitude' => 7.1, 'longitude' => 171.3833333),
163
+ 'Malabo' => array('latitude' => 3.75, 'longitude' => 8.7833333),
164
+ 'Managua' => array('latitude' => 12.1508333, 'longitude' => -86.2683333),
165
+ 'Manama' => array('latitude' => 26.2361111, 'longitude' => 50.5830556),
166
+ 'Manila' => array('latitude' => 14.6041667, 'longitude' => 120.9822222),
167
+ 'Maputo' => array('latitude' => -25.9652778, 'longitude' => 32.5891667),
168
+ 'Maseru' => array('latitude' => -29.3166667, 'longitude' => 27.4833333),
169
+ 'Mbabane' => array('latitude' => -26.3166667, 'longitude' => 31.1333333),
170
+ 'Melbourne' => array('latitude' => -37.8166667, 'longitude' => 144.9666667),
171
+ 'Melekeok' => array('latitude' => 7.4933333, 'longitude' => 134.6341667),
172
+ 'Mexiko City' => array('latitude' => 19.4341667, 'longitude' => -99.1386111),
173
+ 'Minsk' => array('latitude' => 53.9, 'longitude' => 27.5666667),
174
+ 'Mogadishu' => array('latitude' => 2.0666667, 'longitude' => 45.3666667),
175
+ 'Monaco' => array('latitude' => 43.7333333, 'longitude' => 7.4166667),
176
+ 'Monrovia' => array('latitude' => 6.3105556, 'longitude' => -10.8047222),
177
+ 'Montevideo' => array('latitude' => -34.8580556, 'longitude' => -56.1708333),
178
+ 'Montreal' => array('latitude' => 45.5, 'longitude' => -73.5833333),
179
+ 'Moroni' => array('latitude' => -11.7041667, 'longitude' => 43.2402778),
180
+ 'Moscow' => array('latitude' => 55.7522222, 'longitude' => 37.6155556),
181
+ 'Muscat' => array('latitude' => 23.6133333, 'longitude' => 58.5933333),
182
+ 'Nairobi' => array('latitude' => -1.3166667, 'longitude' => 36.8333333),
183
+ 'Nassau' => array('latitude' => 25.0833333, 'longitude' => -77.35),
184
+ 'N´Djamena' => array('latitude' => 12.1130556, 'longitude' => 15.0491667),
185
+ 'New Dehli' => array('latitude' => 28.6, 'longitude' => 77.2),
186
+ 'New York' => array('latitude' => 40.71417, 'longitude' => -74.00639),
187
+ 'Newcastle' => array('latitude' => -32.9166667, 'longitude' => 151.75),
188
+ 'Niamey' => array('latitude' => 13.6666667, 'longitude' => 1.7833333),
189
+ 'Nicosia' => array('latitude' => 35.1666667, 'longitude' => 33.3666667),
190
+ 'Nouakchott' => array('latitude' => 18.0863889, 'longitude' => -15.9752778),
191
+ 'Noumea' => array('latitude' => -22.2666667, 'longitude' => 166.45),
192
+ 'Nuku´alofa' => array('latitude' => -21.1333333, 'longitude' => -175.2),
193
+ 'Nuuk' => array('latitude' => 64.1833333, 'longitude' => -51.75),
194
+ 'Oranjestad' => array('latitude' => 12.5166667, 'longitude' => -70.0333333),
195
+ 'Oslo' => array('latitude' => 59.9166667, 'longitude' => 10.75),
196
+ 'Ouagadougou' => array('latitude' => 12.3702778, 'longitude' => -1.5247222),
197
+ 'Palikir' => array('latitude' => 6.9166667, 'longitude' => 158.15),
198
+ 'Panama City' => array('latitude' => 8.9666667, 'longitude' => -79.5333333),
199
+ 'Papeete' => array('latitude' => -17.5333333, 'longitude' => -149.5666667),
200
+ 'Paramaribo' => array('latitude' => 5.8333333, 'longitude' => -55.1666667),
201
+ 'Paris' => array('latitude' => 48.8666667, 'longitude' => 2.3333333),
202
+ 'Perth' => array('latitude' => -31.9333333, 'longitude' => 115.8333333),
203
+ 'Phnom Penh' => array('latitude' => 11.55, 'longitude' => 104.9166667),
204
+ 'Podgorica' => array('latitude' => 43.7752778, 'longitude' => 19.6827778),
205
+ 'Port Louis' => array('latitude' => -20.1666667, 'longitude' => 57.5),
206
+ 'Port Moresby' => array('latitude' => -9.4647222, 'longitude' => 147.1925),
207
+ 'Port-au-Prince' => array('latitude' => 18.5391667, 'longitude' => -72.335),
208
+ 'Port of Spain' => array('latitude' => 10.6666667, 'longitude' => -61.5),
209
+ 'Porto-Novo' => array('latitude' => 6.4833333, 'longitude' => 2.6166667),
210
+ 'Prague' => array('latitude' => 50.0833333, 'longitude' => 14.4666667),
211
+ 'Praia' => array('latitude' => 14.9166667, 'longitude' => -23.5166667),
212
+ 'Pretoria' => array('latitude' => -25.7069444, 'longitude' => 28.2294444),
213
+ 'Pyongyang' => array('latitude' => 39.0194444, 'longitude' => 125.7547222),
214
+ 'Quito' => array('latitude' => -0.2166667, 'longitude' => -78.5),
215
+ 'Rabat' => array('latitude' => 34.0252778, 'longitude' => -6.8361111),
216
+ 'Reykjavik' => array('latitude' => 64.15, 'longitude' => -21.95),
217
+ 'Riga' => array('latitude' => 56.95, 'longitude' => 24.1),
218
+ 'Rio de Janero' => array('latitude' => -22.9, 'longitude' => -43.2333333),
219
+ 'Road Town' => array('latitude' => 18.4166667, 'longitude' => -64.6166667),
220
+ 'Rome' => array('latitude' => 41.9, 'longitude' => 12.4833333),
221
+ 'Roseau' => array('latitude' => 15.3, 'longitude' => -61.4),
222
+ 'Rotterdam' => array('latitude' => 51.9166667, 'longitude' => 4.5),
223
+ 'Salvador' => array('latitude' => -12.9833333, 'longitude' => -38.5166667),
224
+ 'San José' => array('latitude' => 9.9333333, 'longitude' => -84.0833333),
225
+ 'San Juan' => array('latitude' => 18.46833, 'longitude' => -66.10611),
226
+ 'San Marino' => array('latitude' => 43.5333333, 'longitude' => 12.9666667),
227
+ 'San Salvador' => array('latitude' => 13.7086111, 'longitude' => -89.2030556),
228
+ 'Sanaá' => array('latitude' => 15.3547222, 'longitude' => 44.2066667),
229
+ 'Santa Cruz' => array('latitude' => -17.8, 'longitude' => -63.1666667),
230
+ 'Santiago' => array('latitude' => -33.45, 'longitude' => -70.6666667),
231
+ 'Santo Domingo' => array('latitude' => 18.4666667, 'longitude' => -69.9),
232
+ 'Sao Paulo' => array('latitude' => -23.5333333, 'longitude' => -46.6166667),
233
+ 'Sarajevo' => array('latitude' => 43.85, 'longitude' => 18.3833333),
234
+ 'Seoul' => array('latitude' => 37.5663889, 'longitude' => 126.9997222),
235
+ 'Shanghai' => array('latitude' => 31.2222222, 'longitude' => 121.4580556),
236
+ 'Sydney' => array('latitude' => -33.8833333, 'longitude' => 151.2166667),
237
+ 'Singapore' => array('latitude' => 1.2930556, 'longitude' => 103.8558333),
238
+ 'Skopje' => array('latitude' => 42, 'longitude' => 21.4333333),
239
+ 'Sofia' => array('latitude' => 42.6833333, 'longitude' => 23.3166667),
240
+ 'St. George´s' => array('latitude' => 12.05, 'longitude' => -61.75),
241
+ 'St. John´s' => array('latitude' => 17.1166667, 'longitude' => -61.85),
242
+ 'Stanley' => array('latitude' => -51.7, 'longitude' => -57.85),
243
+ 'Stockholm' => array('latitude' => 59.3333333, 'longitude' => 18.05),
244
+ 'Suva' => array('latitude' => -18.1333333, 'longitude' => 178.4166667),
245
+ 'Taipei' => array('latitude' => 25.0166667, 'longitude' => 121.45),
246
+ 'Tallinn' => array('latitude' => 59.4338889, 'longitude' => 24.7280556),
247
+ 'Tashkent' => array('latitude' => 41.3166667, 'longitude' => 69.25),
248
+ 'Tbilisi' => array('latitude' => 41.725, 'longitude' => 44.7908333),
249
+ 'Tegucigalpa' => array('latitude' => 14.1, 'longitude' => -87.2166667),
250
+ 'Tehran' => array('latitude' => 35.6719444, 'longitude' => 51.4244444),
251
+ 'The Hague' => array('latitude' => 52.0833333, 'longitude' => 4.3),
252
+ 'Thimphu' => array('latitude' => 27.4833333, 'longitude' => 89.6),
253
+ 'Tirana' => array('latitude' => 41.3275, 'longitude' => 19.8188889),
254
+ 'Tiraspol' => array('latitude' => 46.8402778, 'longitude' => 29.6433333),
255
+ 'Tokyo' => array('latitude' => 35.685, 'longitude' => 139.7513889),
256
+ 'Toronto' => array('latitude' => 43.6666667, 'longitude' => -79.4166667),
257
+ 'Tórshavn' => array('latitude' => 62.0166667, 'longitude' => -6.7666667),
258
+ 'Tripoli' => array('latitude' => 32.8925, 'longitude' => 13.18),
259
+ 'Tunis' => array('latitude' => 36.8027778, 'longitude' => 10.1797222),
260
+ 'Ulaanbaatar' => array('latitude' => 47.9166667, 'longitude' => 106.9166667),
261
+ 'Vaduz' => array('latitude' => 47.1333333, 'longitude' => 9.5166667),
262
+ 'Valletta' => array('latitude' => 35.8997222, 'longitude' => 14.5147222),
263
+ 'Valparaiso' => array('latitude' => -33.0477778, 'longitude' => -71.6011111),
264
+ 'Vancouver' => array('latitude' => 49.25, 'longitude' => -123.1333333),
265
+ 'Vatican City' => array('latitude' => 41.9, 'longitude' => 12.4833333),
266
+ 'Victoria' => array('latitude' => -4.6166667, 'longitude' => 55.45),
267
+ 'Vienna' => array('latitude' => 48.2, 'longitude' => 16.3666667),
268
+ 'Vientaine' => array('latitude' => 17.9666667, 'longitude' => 102.6),
269
+ 'Vilnius' => array('latitude' => 54.6833333, 'longitude' => 25.3166667),
270
+ 'Warsaw' => array('latitude' => 52.25, 'longitude' => 21),
271
+ 'Washington dc' => array('latitude' => 38.895, 'longitude' => -77.03667),
272
+ 'Wellington' => array('latitude' => -41.3, 'longitude' => 174.7833333),
273
+ 'Willemstad' => array('latitude' => 12.1, 'longitude' => -68.9166667),
274
+ 'Windhoek' => array('latitude' => -22.57, 'longitude' => 17.0836111),
275
+ 'Yamoussoukro' => array('latitude' => 6.8166667, 'longitude' => -5.2833333),
276
+ 'Yaoundé' => array('latitude' => 3.8666667, 'longitude' => 11.5166667),
277
+ 'Yerevan' => array('latitude' => 40.1811111, 'longitude' => 44.5136111),
278
+ 'Zürich' => array('latitude' => 47.3666667, 'longitude' => 8.55),
279
+ 'Zagreb' => array('latitude' => 45.8, 'longitude' => 16)
280
+ );
281
+
282
+ /**
283
+ * Returns the location from the selected city
284
+ *
285
+ * @param string $city - city to get location for
286
+ * @param string $horizon - horizon to use :
287
+ * default: effective
288
+ * others are civil, nautic, astronomic
289
+ * @return array
290
+ * @throws Zend_Date_Exception
291
+ */
292
+ public static function City($city, $horizon = false) {
293
+ foreach (self::$Cities as $key => $value) {
294
+ if (strtolower($key) == strtolower($city)) {
295
+ $return = $value;
296
+ $return['horizon'] = $horizon;
297
+ return $return;
298
+ }
299
+ }
300
+ /**
301
+ * @see Zend_Date_Exception
302
+ */
303
+ require_once 'Zend/Date/Exception.php';
304
+ throw new Zend_Date_Exception('unknown city');
305
+ }
306
+
307
+ /**
308
+ * Return a list with all known cities
309
+ *
310
+ * @return array
311
+ */
312
+ public static function getCityList() {
313
+ return array_keys(self::$Cities);
314
+ }
315
+ }
lib/Zend/Date/DateObject.php ADDED
@@ -0,0 +1,1060 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Zend Framework
4
+ *
5
+ * LICENSE
6
+ *
7
+ * This source file is subject to the new BSD license that is bundled
8
+ * with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://framework.zend.com/license/new-bsd
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@zend.com so we can send you a copy immediately.
14
+ *
15
+ * @category Zend
16
+ * @package Zend_Date
17
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
18
+ * @version $Id: DateObject.php 8064 2008-02-16 10:58:39Z thomas $
19
+ * @license http://framework.zend.com/license/new-bsd New BSD License
20
+ */
21
+
22
+
23
+ /**
24
+ * @category Zend
25
+ * @package Zend_Date
26
+ * @subpackage Zend_Date_DateObject
27
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
28
+ * @license http://framework.zend.com/license/new-bsd New BSD License
29
+ */
30
+ abstract class Zend_Date_DateObject {
31
+
32
+
33
+ /**
34
+ * UNIX Timestamp
35
+ */
36
+ private $_unixTimestamp;
37
+ protected static $_cache = null;
38
+ protected static $_defaultOffset = 0;
39
+
40
+
41
+ /**
42
+ * active timezone
43
+ */
44
+ private $_timezone = 'UTC';
45
+ private $_offset = 0;
46
+ private $_syncronised = 0;
47
+
48
+ // turn off DST correction if UTC or GMT
49
+ protected $_dst = true;
50
+
51
+ /**
52
+ * Table of Monthdays
53
+ */
54
+ private static $_monthTable = array(31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
55
+
56
+
57
+ /**
58
+ * Table of Years
59
+ */
60
+ private static $_yearTable = array(
61
+ 1970 => 0, 1960 => -315619200, 1950 => -631152000,
62
+ 1940 => -946771200, 1930 => -1262304000, 1920 => -1577923200,
63
+ 1910 => -1893456000, 1900 => -2208988800, 1890 => -2524521600,
64
+ 1880 => -2840140800, 1870 => -3155673600, 1860 => -3471292800,
65
+ 1850 => -3786825600, 1840 => -4102444800, 1830 => -4417977600,
66
+ 1820 => -4733596800, 1810 => -5049129600, 1800 => -5364662400,
67
+ 1790 => -5680195200, 1780 => -5995814400, 1770 => -6311347200,
68
+ 1760 => -6626966400, 1750 => -6942499200, 1740 => -7258118400,
69
+ 1730 => -7573651200, 1720 => -7889270400, 1710 => -8204803200,
70
+ 1700 => -8520336000, 1690 => -8835868800, 1680 => -9151488000,
71
+ 1670 => -9467020800, 1660 => -9782640000, 1650 => -10098172800,
72
+ 1640 => -10413792000, 1630 => -10729324800, 1620 => -11044944000,
73
+ 1610 => -11360476800, 1600 => -11676096000);
74
+
75
+
76
+ /**
77
+ * Set this object to have a new UNIX timestamp.
78
+ *
79
+ * @param string|integer $timestamp OPTIONAL timestamp; defaults to local time using time()
80
+ * @return string|integer old timestamp
81
+ * @throws Zend_Date_Exception
82
+ */
83
+ protected function setUnixTimestamp($timestamp = null)
84
+ {
85
+ $old = $this->_unixTimestamp;
86
+
87
+ if (is_numeric($timestamp)) {
88
+ $this->_unixTimestamp = $timestamp;
89
+ } else if ($timestamp === null) {
90
+ $this->_unixTimestamp = time();
91
+ } else {
92
+ require_once 'Zend/Date/Exception.php';
93
+ throw new Zend_Date_Exception('\'' . $timestamp . '\' is not a valid UNIX timestamp', $timestamp);
94
+ }
95
+
96
+ return $old;
97
+ }
98
+
99
+
100
+ /**
101
+ * Returns this object's UNIX timestamp
102
+ * A timestamp greater then the integer range will be returned as string
103
+ * This function does not return the timestamp as object. Use copy() instead.
104
+ *
105
+ * @return integer|string timestamp
106
+ */
107
+ protected function getUnixTimestamp()
108
+ {
109
+ if ($this->_unixTimestamp === intval($this->_unixTimestamp)) {
110
+ return (int) $this->_unixTimestamp;
111
+ } else {
112
+ return (string) $this->_unixTimestamp;
113
+ }
114
+ }
115
+
116
+ /**
117
+ * Internal function.
118
+ * Returns time(). This method exists to allow unit tests to work-around methods that might otherwise
119
+ * be hard-coded to use time(). For example, this makes it possible to test isYesterday() in Date.php.
120
+ *
121
+ * @param integer $sync OPTIONAL time syncronisation value
122
+ * @return integer timestamp
123
+ */
124
+ protected function _getTime($sync = null)
125
+ {
126
+ if ($sync !== null) {
127
+ $this->_syncronised = round($sync);
128
+ }
129
+ return (time() + $this->_syncronised);
130
+ }
131
+
132
+
133
+ /**
134
+ * Internal mktime function used by Zend_Date.
135
+ * The timestamp returned by mktime() can exceed the precision of traditional UNIX timestamps,
136
+ * by allowing PHP to auto-convert to using a float value.
137
+ *
138
+ * Returns a timestamp relative to 1970/01/01 00:00:00 GMT/UTC.
139
+ * DST (Summer/Winter) is depriciated since php 5.1.0.
140
+ * Year has to be 4 digits otherwise it would be recognised as
141
+ * year 70 AD instead of 1970 AD as expected !!
142
+ *
143
+ * @param integer $hour
144
+ * @param integer $minute
145
+ * @param integer $second
146
+ * @param integer $month
147
+ * @param integer $day
148
+ * @param integer $year
149
+ * @param boolean $gmt OPTIONAL true = other arguments are for UTC time, false = arguments are for local time/date
150
+ * @return integer|float timestamp (number of seconds elapsed relative to 1970/01/01 00:00:00 GMT/UTC)
151
+ */
152
+ protected function mktime($hour, $minute, $second, $month, $day, $year, $gmt = false)
153
+ {
154
+
155
+ // complete date but in 32bit timestamp - use PHP internal
156
+ if ((1901 < $year) and ($year < 2038)) {
157
+
158
+ $oldzone = @date_default_timezone_get();
159
+ // Timezone also includes DST settings, therefor substracting the GMT offset is not enough
160
+ // We have to set the correct timezone to get the right value
161
+ if (($this->_timezone != $oldzone) and ($gmt === false)) {
162
+ date_default_timezone_set($this->_timezone);
163
+ }
164
+ $result = ($gmt) ? @gmmktime($hour, $minute, $second, $month, $day, $year)
165
+ : @mktime($hour, $minute, $second, $month, $day, $year);
166
+ date_default_timezone_set($oldzone);
167
+
168
+ return $result;
169
+ }
170
+
171
+ if ($gmt !== true) {
172
+ $second += $this->_offset;
173
+ }
174
+
175
+ if (isset(self::$_cache)) {
176
+ $id = strtr('Zend_DateObject_mkTime_' . $this->_offset . '_' . $year.$month.$day.'_'.$hour.$minute.$second . '_'.(int)$gmt, '-','_');
177
+ if ($result = self::$_cache->load($id)) {
178
+ return unserialize($result);
179
+ }
180
+ }
181
+
182
+ // date to integer
183
+ $day = intval($day);
184
+ $month = intval($month);
185
+ $year = intval($year);
186
+
187
+ // correct months > 12 and months < 1
188
+ if ($month > 12) {
189
+ $overlap = floor($month / 12);
190
+ $year += $overlap;
191
+ $month -= $overlap * 12;
192
+ } else {
193
+ $overlap = ceil((1 - $month) / 12);
194
+ $year -= $overlap;
195
+ $month += $overlap * 12;
196
+ }
197
+
198
+ $date = 0;
199
+ if ($year >= 1970) {
200
+
201
+ // Date is after UNIX epoch
202
+ // go through leapyears
203
+ // add months from letest given year
204
+ for ($count = 1970; $count <= $year; $count++) {
205
+ $leapyear = self::isYearLeapYear($count);
206
+ if ($count < $year) {
207
+
208
+ $date += 365;
209
+ if ($leapyear === true) {
210
+ $date++;
211
+ }
212
+
213
+ } else {
214
+
215
+ for ($mcount = 0; $mcount < ($month - 1); $mcount++) {
216
+ $date += self::$_monthTable[$mcount];
217
+ if (($leapyear === true) and ($mcount == 1)) {
218
+ $date++;
219
+ }
220
+
221
+ }
222
+ }
223
+ }
224
+
225
+ $date += $day - 1;
226
+ $date = (($date * 86400) + ($hour * 3600) + ($minute * 60) + $second);
227
+ } else {
228
+
229
+ // Date is before UNIX epoch
230
+ // go through leapyears
231
+ // add months from latest given year
232
+ for ($count = 1969; $count >= $year; $count--) {
233
+
234
+ $leapyear = self::isYearLeapYear($count);
235
+ if ($count > $year)
236
+ {
237
+ $date += 365;
238
+ if ($leapyear === true)
239
+ $date++;
240
+ } else {
241
+
242
+ for ($mcount = 11; $mcount > ($month - 1); $mcount--) {
243
+ $date += self::$_monthTable[$mcount];
244
+ if (($leapyear === true) and ($mcount == 1)) {
245
+ $date++;
246
+ }
247
+
248
+ }
249
+ }
250
+ }
251
+
252
+ $date += (self::$_monthTable[$month - 1] - $day);
253
+ $date = -(($date * 86400) + (86400 - (($hour * 3600) + ($minute * 60) + $second)));
254
+
255
+ // gregorian correction for 5.Oct.1582
256
+ if ($date < -12220185600) {
257
+ $date += 864000;
258
+ } else if ($date < -12219321600) {
259
+ $date = -12219321600;
260
+ }
261
+ }
262
+
263
+ if (isset(self::$_cache)) {
264
+ self::$_cache->save( serialize($date), $id);
265
+ }
266
+
267
+ return $date;
268
+ }
269
+
270
+
271
+ /**
272
+ * Returns true, if given $year is a leap year.
273
+ *
274
+ * @param integer $year
275
+ * @return boolean true, if year is leap year
276
+ */
277
+ protected static function isYearLeapYear($year)
278
+ {
279
+ // all leapyears can be divided through 4
280
+ if (($year % 4) != 0) {
281
+ return false;
282
+ }
283
+
284
+ // all leapyears can be divided through 400
285
+ if ($year % 400 == 0) {
286
+ return true;
287
+ } else if (($year > 1582) and ($year % 100 == 0)) {
288
+ return false;
289
+ }
290
+
291
+ return true;
292
+ }
293
+
294
+
295
+ /**
296
+ * Internal mktime function used by Zend_Date for handling 64bit timestamps.
297
+ *
298
+ * Returns a formatted date for a given timestamp.
299
+ *
300
+ * @param string $format format for output
301
+ * @param mixed $timestamp
302
+ * @param boolean $gmt OPTIONAL true = other arguments are for UTC time, false = arguments are for local time/date
303
+ * @return string
304
+ */
305
+ protected function date($format, $timestamp = null, $gmt = false)
306
+ {
307
+ $oldzone = @date_default_timezone_get();
308
+ if ($this->_timezone != $oldzone) {
309
+ date_default_timezone_set($this->_timezone);
310
+ }
311
+ if ($timestamp === null) {
312
+ $result = ($gmt) ? @gmdate($format) : @date($format);
313
+ date_default_timezone_set($oldzone);
314
+ return $result;
315
+ }
316
+
317
+ if (abs($timestamp) <= 0x7FFFFFFF) {
318
+ $result = ($gmt) ? @gmdate($format, $timestamp) : @date($format, $timestamp);
319
+ date_default_timezone_set($oldzone);
320
+ return $result;
321
+ }
322
+
323
+ $jump = false;
324
+ if (isset(self::$_cache)) {
325
+ $idstamp = strtr('Zend_DateObject_date_' . $this->_offset . '_'. $timestamp . '_'.(int)$gmt, '-','_');
326
+ if ($result2 = self::$_cache->load($idstamp)) {
327
+ $timestamp = unserialize($result2);
328
+ $jump = true;
329
+ }
330
+ }
331
+
332
+ // check on false or null alone failes
333
+ if (empty($gmt) and empty($jump)) {
334
+ $tempstamp = $timestamp;
335
+ if ($tempstamp > 0) {
336
+ while (abs($tempstamp) > 0x7FFFFFFF) {
337
+ $tempstamp -= (86400 * 23376);
338
+ }
339
+ $dst = date("I", $tempstamp);
340
+ if ($dst === 1) {
341
+ $timestamp += 3600;
342
+ }
343
+ $temp = date('Z', $tempstamp);
344
+ $timestamp += $temp;
345
+ }
346
+
347
+ if (isset(self::$_cache)) {
348
+ self::$_cache->save( serialize($timestamp), $idstamp);
349
+ }
350
+ }
351
+
352
+
353
+ if (($timestamp < 0) and ($gmt !== true)) {
354
+ $timestamp -= $this->_offset;
355
+ }
356
+ date_default_timezone_set($oldzone);
357
+
358
+ $date = $this->getDateParts($timestamp, true);
359
+ $length = strlen($format);
360
+ $output = '';
361
+
362
+ for ($i = 0; $i < $length; $i++) {
363
+
364
+ switch($format[$i]) {
365
+
366
+ // day formats
367
+ case 'd': // day of month, 2 digits, with leading zero, 01 - 31
368
+ $output .= (($date['mday'] < 10) ? '0' . $date['mday'] : $date['mday']);
369
+ break;
370
+
371
+ case 'D': // day of week, 3 letters, Mon - Sun
372
+ $output .= date('D', 86400 * (3 + self::dayOfWeek($date['year'], $date['mon'], $date['mday'])));
373
+ break;
374
+
375
+ case 'j': // day of month, without leading zero, 1 - 31
376
+ $output .= $date['mday'];
377
+ break;
378
+
379
+ case 'l': // day of week, full string name, Sunday - Saturday
380
+ $output .= date('l', 86400 * (3 + self::dayOfWeek($date['year'], $date['mon'], $date['mday'])));
381
+ break;
382
+
383
+ case 'N': // ISO 8601 numeric day of week, 1 - 7
384
+ $day = self::dayOfWeek($date['year'], $date['mon'], $date['mday']);
385
+ if ($day == 0) {
386
+ $day = 7;
387
+ }
388
+ $output .= $day;
389
+ break;
390
+
391
+ case 'S': // english suffix for day of month, st nd rd th
392
+ if (($date['mday'] % 10) == 1) {
393
+ $output .= 'st';
394
+ } else if ((($date['mday'] % 10) == 2) and ($date['mday'] != 12)) {
395
+ $output .= 'nd';
396
+ } else if (($date['mday'] % 10) == 3) {
397
+ $output .= 'rd';
398
+ } else {
399
+ $output .= 'th';
400
+ }
401
+ break;
402
+
403
+ case 'w': // numeric day of week, 0 - 6
404
+ $output .= self::dayOfWeek($date['year'], $date['mon'], $date['mday']);
405
+ break;
406
+
407
+ case 'z': // day of year, 0 - 365
408
+ $output .= $date['yday'];
409
+ break;
410
+
411
+
412
+ // week formats
413
+ case 'W': // ISO 8601, week number of year
414
+ $output .= $this->weekNumber($date['year'], $date['mon'], $date['mday']);
415
+ break;
416
+
417
+
418
+ // month formats
419
+ case 'F': // string month name, january - december
420
+ $output .= date('F', mktime(0, 0, 0, $date['mon'], 2, 1971));
421
+ break;
422
+
423
+ case 'm': // number of month, with leading zeros, 01 - 12
424
+ $output .= (($date['mon'] < 10) ? '0' . $date['mon'] : $date['mon']);
425
+ break;
426
+
427
+ case 'M': // 3 letter month name, Jan - Dec
428
+ $output .= date('M',mktime(0, 0, 0, $date['mon'], 2, 1971));
429
+ break;
430
+
431
+ case 'n': // number of month, without leading zeros, 1 - 12
432
+ $output .= $date['mon'];
433
+ break;
434
+
435
+ case 't': // number of day in month
436
+ $output .= self::$_monthTable[$date['mon'] - 1];
437
+ break;
438
+
439
+
440
+ // year formats
441
+ case 'L': // is leap year ?
442
+ $output .= (self::isYearLeapYear($date['year'])) ? '1' : '0';
443
+ break;
444
+
445
+ case 'o': // ISO 8601 year number
446
+ $week = $this->weekNumber($date['year'], $date['mon'], $date['mday']);
447
+ if (($week > 50) and ($date['mon'] == 1)) {
448
+ $output .= ($date['year'] - 1);
449
+ } else {
450
+ $output .= $date['year'];
451
+ }
452
+ break;
453
+
454
+ case 'Y': // year number, 4 digits
455
+ $output .= $date['year'];
456
+ break;
457
+
458
+ case 'y': // year number, 2 digits
459
+ $output .= substr($date['year'], strlen($date['year']) - 2, 2);
460
+ break;
461
+
462
+
463
+ // time formats
464
+ case 'a': // lower case am/pm
465
+ $output .= (($date['hours'] >= 12) ? 'pm' : 'am');
466
+ break;
467
+
468
+ case 'A': // upper case am/pm
469
+ $output .= (($date['hours'] >= 12) ? 'PM' : 'AM');
470
+ break;
471
+
472
+ case 'B': // swatch internet time
473
+ $dayseconds = ($date['hours'] * 3600) + ($date['minutes'] * 60) + $date['seconds'];
474
+ if ($gmt === true) {
475
+ $dayseconds += 3600;
476
+ }
477
+ $output .= (int) (($dayseconds % 86400) / 86.4);
478
+ break;
479
+
480
+ case 'g': // hours without leading zeros, 12h format
481
+ if ($date['hours'] > 12) {
482
+ $hour = $date['hours'] - 12;
483
+ } else {
484
+ if ($date['hours'] == 0) {
485
+ $hour = '12';
486
+ } else {
487
+ $hour = $date['hours'];
488
+ }
489
+ }
490
+ $output .= $hour;
491
+ break;
492
+
493
+ case 'G': // hours without leading zeros, 24h format
494
+ $output .= $date['hours'];
495
+ break;
496
+
497
+ case 'h': // hours with leading zeros, 12h format
498
+ if ($date['hours'] > 12) {
499
+ $hour = $date['hours'] - 12;
500
+ } else {
501
+ if ($date['hours'] == 0) {
502
+ $hour = '12';
503
+ } else {
504
+ $hour = $date['hours'];
505
+ }
506
+ }
507
+ $output .= (($hour < 10) ? '0'.$hour : $hour);
508
+ break;
509
+
510
+ case 'H': // hours with leading zeros, 24h format
511
+ $output .= (($date['hours'] < 10) ? '0' . $date['hours'] : $date['hours']);
512
+ break;
513
+
514
+ case 'i': // minutes with leading zeros
515
+ $output .= (($date['minutes'] < 10) ? '0' . $date['minutes'] : $date['minutes']);
516
+ break;
517
+
518
+ case 's': // seconds with leading zeros
519
+ $output .= (($date['seconds'] < 10) ? '0' . $date['seconds'] : $date['seconds']);
520
+ break;
521
+
522
+
523
+ // timezone formats
524
+ case 'e': // timezone identifier
525
+ if ($gmt === true) {
526
+ $output .= gmdate('e', mktime($date['hours'], $date['minutes'], $date['seconds'],
527
+ $date['mon'], $date['mday'], 2000));
528
+ } else {
529
+ $output .= date('e', mktime($date['hours'], $date['minutes'], $date['seconds'],
530
+ $date['mon'], $date['mday'], 2000));
531
+ }
532
+ break;
533
+
534
+ case 'I': // daylight saving time or not
535
+ if ($gmt === true) {
536
+ $output .= gmdate('I', mktime($date['hours'], $date['minutes'], $date['seconds'],
537
+ $date['mon'], $date['mday'], 2000));
538
+ } else {
539
+ $output .= date('I', mktime($date['hours'], $date['minutes'], $date['seconds'],
540
+ $date['mon'], $date['mday'], 2000));
541
+ }
542
+ break;
543
+
544
+ case 'O': // difference to GMT in hours
545
+ $gmtstr = ($gmt === true) ? 0 : $this->_offset;
546
+ $output .= sprintf('%s%04d', ($gmtstr <= 0) ? '+' : '-', abs($gmtstr) / 36);
547
+ break;
548
+
549
+ case 'P': // difference to GMT with colon
550
+ $gmtstr = ($gmt === true) ? 0 : $this->_offset;
551
+ $gmtstr = sprintf('%s%04d', ($gmtstr <= 0) ? '+' : '-', abs($gmtstr) / 36);
552
+ $output = $output . substr($gmtstr, 0, 3) . ':' . substr($gmtstr, 3);
553
+ break;
554
+
555
+ case 'T': // timezone settings
556
+ if ($gmt === true) {
557
+ $output .= gmdate('T', mktime($date['hours'], $date['minutes'], $date['seconds'],
558
+ $date['mon'], $date['mday'], 2000));
559
+ } else {
560
+ $output .= date('T', mktime($date['hours'], $date['minutes'], $date['seconds'],
561
+ $date['mon'], $date['mday'], 2000));
562
+ }
563
+ break;
564
+
565
+ case 'Z': // timezone offset in seconds
566
+ $output .= ($gmt === true) ? 0 : -$this->_offset;
567
+ break;
568
+
569
+
570
+ // complete time formats
571
+ case 'c': // ISO 8601 date format
572
+ $difference = $this->_offset;
573
+ $difference = sprintf('%s%04d', ($difference <= 0) ? '+' : '-', abs($difference) / 36);
574
+ $output .= $date['year'] . '-'
575
+ . (($date['mon'] < 10) ? '0' . $date['mon'] : $date['mon']) . '-'
576
+ . (($date['mday'] < 10) ? '0' . $date['mday'] : $date['mday']) . 'T'
577
+ . (($date['hours'] < 10) ? '0' . $date['hours'] : $date['hours']) . ':'
578
+ . (($date['minutes'] < 10) ? '0' . $date['minutes'] : $date['minutes']) . ':'
579
+ . (($date['seconds'] < 10) ? '0' . $date['seconds'] : $date['seconds'])
580
+ . $difference;
581
+ break;
582
+
583
+ case 'r': // RFC 2822 date format
584
+ $difference = $this->_offset;
585
+ $difference = sprintf('%s%04d', ($difference <= 0) ? '+' : '-', abs($difference) / 36);
586
+ $output .= gmdate('D', 86400 * (3 + self::dayOfWeek($date['year'], $date['mon'], $date['mday']))) . ', '
587
+ . (($date['mday'] < 10) ? '0' . $date['mday'] : $date['mday']) . ' '
588
+ . date('M', mktime(0, 0, 0, $date['mon'], 2, 1971)) . ' '
589
+ . $date['year'] . ' '
590
+ . (($date['hours'] < 10) ? '0' . $date['hours'] : $date['hours']) . ':'
591
+ . (($date['minutes'] < 10) ? '0' . $date['minutes'] : $date['minutes']) . ':'
592
+ . (($date['seconds'] < 10) ? '0' . $date['seconds'] : $date['seconds']) . ' '
593
+ . $difference;
594
+ break;
595
+
596
+ case 'U': // Unix timestamp
597
+ $output .= $timestamp;
598
+ break;
599
+
600
+
601
+ // special formats
602
+ case "\\": // next letter to print with no format
603
+ $i++;
604
+ if ($i < $length) {
605
+ $output .= $format[$i];
606
+ }
607
+ break;
608
+
609
+ default: // letter is no format so add it direct
610
+ $output .= $format[$i];
611
+ break;
612
+ }
613
+ }
614
+
615
+ return (string) $output;
616
+ }
617
+
618
+
619
+ /**
620
+ * Returns the day of week for a Gregorian calendar date.
621
+ * 0 = sunday, 6 = saturday
622
+ *
623
+ * @param integer $year
624
+ * @param integer $month
625
+ * @param integer $day
626
+ * @return integer dayOfWeek
627
+ */
628
+ protected static function dayOfWeek($year, $month, $day)
629
+ {
630
+ if ((1901 < $year) and ($year < 2038)) {
631
+ return (int) date('w', mktime(0, 0, 0, $month, $day, $year));
632
+ }
633
+
634
+ // gregorian correction
635
+ $correction = 0;
636
+ if (($year < 1582) or (($year == 1582) and (($month < 10) or (($month == 10) && ($day < 15))))) {
637
+ $correction = 3;
638
+ }
639
+
640
+ if ($month > 2) {
641
+ $month -= 2;
642
+ } else {
643
+ $month += 10;
644
+ $year--;
645
+ }
646
+
647
+ $day = floor((13 * $month - 1) / 5) + $day + ($year % 100) + floor(($year % 100) / 4);
648
+ $day += floor(($year / 100) / 4) - 2 * floor($year / 100) + 77 + $correction;
649
+
650
+ return (int) ($day - 7 * floor($day / 7));
651
+ }
652
+
653
+
654
+ /**
655
+ * Internal getDateParts function for handling 64bit timestamps, similar to:
656
+ * http://www.php.net/getdate
657
+ *
658
+ * Returns an array of date parts for $timestamp, relative to 1970/01/01 00:00:00 GMT/UTC.
659
+ *
660
+ * $fast specifies ALL date parts should be returned (slower)
661
+ * Default is false, and excludes $dayofweek, weekday, month and timestamp from parts returned.
662
+ *
663
+ * @param mixed $timestamp
664
+ * @param boolean $fast OPTIONAL defaults to fast (false), resulting in fewer date parts
665
+ * @return array
666
+ */
667
+ protected function getDateParts($timestamp = null, $fast = null)
668
+ {
669
+
670
+ // actual timestamp
671
+ if ($timestamp === null) {
672
+ return getdate();
673
+ }
674
+
675
+ // 32bit timestamp
676
+ if (abs($timestamp) <= 0x7FFFFFFF) {
677
+ return @getdate($timestamp);
678
+ }
679
+
680
+ if (isset(self::$_cache)) {
681
+ $id = strtr('Zend_DateObject_getDateParts_' . $timestamp.'_'.(int)$fast, '-','_');
682
+ if ($result = self::$_cache->load($id)) {
683
+ return unserialize($result);
684
+ }
685
+ }
686
+
687
+ $otimestamp = $timestamp;
688
+ $numday = 0;
689
+ $month = 0;
690
+ // gregorian correction
691
+ if ($timestamp < -12219321600) {
692
+ $timestamp -= 864000;
693
+ }
694
+
695
+ // timestamp lower 0
696
+ if ($timestamp < 0) {
697
+ $sec = 0;
698
+ $act = 1970;
699
+
700
+ // iterate through 10 years table, increasing speed
701
+ foreach(self::$_yearTable as $year => $seconds) {
702
+ if ($timestamp >= $seconds) {
703
+ $i = $act;
704
+ break;
705
+ }
706
+ $sec = $seconds;
707
+ $act = $year;
708
+ }
709
+
710
+ $timestamp -= $sec;
711
+ if (!isset($i)) {
712
+ $i = $act;
713
+ }
714
+
715
+ // iterate the max last 10 years
716
+ do {
717
+ --$i;
718
+ $day = $timestamp;
719
+
720
+ $timestamp += 31536000;
721
+ $leapyear = self::isYearLeapYear($i);
722
+ if ($leapyear === true) {
723
+ $timestamp += 86400;
724
+ }
725
+
726
+ if ($timestamp >= 0) {
727
+ $year = $i;
728
+ break;
729
+ }
730
+ } while ($timestamp < 0);
731
+
732
+ $secondsPerYear = 86400 * ($leapyear ? 366 : 365) + $day;
733
+
734
+ $timestamp = $day;
735
+ // iterate through months
736
+ for ($i = 12; --$i >= 0;) {
737
+ $day = $timestamp;
738
+
739
+ $timestamp += self::$_monthTable[$i] * 86400;
740
+ if (($leapyear === true) and ($i == 1)) {
741
+ $timestamp += 86400;
742
+ }
743
+
744
+ if ($timestamp >= 0) {
745
+ $month = $i;
746
+ $numday = self::$_monthTable[$i];
747
+ if (($leapyear === true) and ($i == 1)) {
748
+ ++$numday;
749
+ }
750
+ break;
751
+ }
752
+ }
753
+
754
+ $timestamp = $day;
755
+ $numberdays = $numday + ceil(($timestamp + 1) / 86400);
756
+
757
+ $timestamp += ($numday - $numberdays + 1) * 86400;
758
+ $hours = floor($timestamp / 3600);
759
+ } else {
760
+
761
+ // iterate through years
762
+ for ($i = 1970;;$i++) {
763
+ $day = $timestamp;
764
+
765
+ $timestamp -= 31536000;
766
+ $leapyear = self::isYearLeapYear($i);
767
+ if ($leapyear === true) {
768
+ $timestamp -= 86400;
769
+ }
770
+
771
+ if ($timestamp < 0) {
772
+ $year = $i;
773
+ break;
774
+ }
775
+ }
776
+
777
+ $secondsPerYear = $day;
778
+
779
+ $timestamp = $day;
780
+ // iterate through months
781
+ for ($i = 0; $i <= 11; $i++) {
782
+ $day = $timestamp;
783
+ $timestamp -= self::$_monthTable[$i] * 86400;
784
+
785
+ if (($leapyear === true) and ($i == 1)) {
786
+ $timestamp -= 86400;
787
+ }
788
+
789
+ if ($timestamp < 0) {
790
+ $month = $i;
791
+ $numday = self::$_monthTable[$i];
792
+ if (($leapyear === true) and ($i == 1)) {
793
+ ++$numday;
794
+ }
795
+ break;
796
+ }
797
+ }
798
+
799
+ $timestamp = $day;
800
+ $numberdays = ceil(($timestamp + 1) / 86400);
801
+ $timestamp = $timestamp - ($numberdays - 1) * 86400;
802
+ $hours = floor($timestamp / 3600);
803
+ }
804
+
805
+ $timestamp -= $hours * 3600;
806
+
807
+ $month += 1;
808
+ $minutes = floor($timestamp / 60);
809
+ $seconds = $timestamp - $minutes * 60;
810
+
811
+ if ($fast === true) {
812
+ $array = array(
813
+ 'seconds' => $seconds,
814
+ 'minutes' => $minutes,
815
+ 'hours' => $hours,
816
+ 'mday' => $numberdays,
817
+ 'mon' => $month,
818
+ 'year' => $year,
819
+ 'yday' => floor($secondsPerYear / 86400),
820
+ );
821
+ } else {
822
+
823
+ $dayofweek = self::dayOfWeek($year, $month, $numberdays);
824
+ $array = array(
825
+ 'seconds' => $seconds,
826
+ 'minutes' => $minutes,
827
+ 'hours' => $hours,
828
+ 'mday' => $numberdays,
829
+ 'wday' => $dayofweek,
830
+ 'mon' => $month,
831
+ 'year' => $year,
832
+ 'yday' => floor($secondsPerYear / 86400),
833
+ 'weekday' => gmdate('l', 86400 * (3 + $dayofweek)),
834
+ 'month' => gmdate('F', mktime(0, 0, 0, $month, 1, 1971)),
835
+ 0 => $otimestamp
836
+ );
837
+ }
838
+
839
+ if (isset(self::$_cache)) {
840
+ self::$_cache->save( serialize($array), $id);
841
+ }
842
+
843
+ return $array;
844
+ }
845
+
846
+
847
+ /**
848
+ * Internal getWeekNumber function for handling 64bit timestamps
849
+ *
850
+ * Returns the ISO 8601 week number of a given date
851
+ *
852
+ * @param integer $year
853
+ * @param integer $month
854
+ * @param integer $day
855
+ * @return integer
856
+ */
857
+ protected function weekNumber($year, $month, $day)
858
+ {
859
+ if ((1901 < $year) and ($year < 2038)) {
860
+ return (int) date('W', mktime(0, 0, 0, $month, $day, $year));
861
+ }
862
+
863
+ $dayofweek = self::dayOfWeek($year, $month, $day);
864
+ $firstday = self::dayOfWeek($year, 1, 1);
865
+ if (($month == 1) and (($firstday < 1) or ($firstday > 4)) and ($day < 4)) {
866
+ $firstday = self::dayOfWeek($year - 1, 1, 1);
867
+ $month = 12;
868
+ $day = 31;
869
+
870
+ } else if (($month == 12) and ((self::dayOfWeek($year + 1, 1, 1) < 5) and
871
+ (self::dayOfWeek($year + 1, 1, 1) > 0))) {
872
+ return 1;
873
+ }
874
+
875
+ return intval (((self::dayOfWeek($year, 1, 1) < 5) and (self::dayOfWeek($year, 1, 1) > 0)) +
876
+ 4 * ($month - 1) + (2 * ($month - 1) + ($day - 1) + $firstday - $dayofweek + 6) * 36 / 256);
877
+ }
878
+
879
+
880
+ /**
881
+ * Internal _range function
882
+ * Sets the value $a to be in the range of [0, $b]
883
+ *
884
+ * @param float $a - value to correct
885
+ * @param float $b - maximum range to set
886
+ */
887
+ private function _range($a, $b) {
888
+ while ($a < 0) {
889
+ $a += $b;
890
+ }
891
+ while ($a >= $b) {
892
+ $a -= $b;
893
+ }
894
+ return $a;
895
+ }
896
+
897
+
898
+ /**
899
+ * Calculates the sunrise or sunset based on a location
900
+ *
901
+ * @param array $location Location for calculation MUST include 'latitude', 'longitude', 'horizon'
902
+ * @param bool $horizon true: sunrise; false: sunset
903
+ * @return mixed - false: midnight sun, integer:
904
+ */
905
+ protected function calcSun($location, $horizon, $rise = false)
906
+ {
907
+ // timestamp within 32bit
908
+ if (abs($this->_unixTimestamp) <= 0x7FFFFFFF) {
909
+ if ($rise === false) {
910
+ return date_sunset($this->_unixTimestamp, SUNFUNCS_RET_TIMESTAMP, $location['latitude'],
911
+ $location['longitude'], 90 + $horizon, $this->_offset / 3600);
912
+ }
913
+ return date_sunrise($this->_unixTimestamp, SUNFUNCS_RET_TIMESTAMP, $location['latitude'],
914
+ $location['longitude'], 90 + $horizon, $this->_offset / 3600);
915
+ }
916
+
917
+ // self calculation - timestamp bigger than 32bit
918
+ // fix circle values
919
+ $quarterCircle = 0.5 * M_PI;
920
+ $halfCircle = M_PI;
921
+ $threeQuarterCircle = 1.5 * M_PI;
922
+ $fullCircle = 2 * M_PI;
923
+
924
+ // radiant conversion for coordinates
925
+ $radLatitude = $location['latitude'] * $halfCircle / 180;
926
+ $radLongitude = $location['longitude'] * $halfCircle / 180;
927
+
928
+ // get solar coordinates
929
+ $tmpRise = $rise ? $quarterCircle : $threeQuarterCircle;
930
+ $radDay = $this->date('z',$this->_unixTimestamp) + ($tmpRise - $radLongitude) / $fullCircle;
931
+
932
+ // solar anomoly and longitude
933
+ $solAnomoly = $radDay * 0.017202 - 0.0574039;
934
+ $solLongitude = $solAnomoly + 0.0334405 * sin($solAnomoly);
935
+ $solLongitude += 4.93289 + 3.49066E-4 * sin(2 * $solAnomoly);
936
+
937
+ // get quadrant
938
+ $solLongitude = $this->_range($solLongitude, $fullCircle);
939
+
940
+ if (($solLongitude / $quarterCircle) - intval($solLongitude / $quarterCircle) == 0) {
941
+ $solLongitude += 4.84814E-6;
942
+ }
943
+
944
+ // solar ascension
945
+ $solAscension = sin($solLongitude) / cos($solLongitude);
946
+ $solAscension = atan2(0.91746 * $solAscension, 1);
947
+
948
+ // adjust quadrant
949
+ if ($solLongitude > $threeQuarterCircle) {
950
+ $solAscension += $fullCircle;
951
+ } else if ($solLongitude > $quarterCircle) {
952
+ $solAscension += $halfCircle;
953
+ }
954
+
955
+ // solar declination
956
+ $solDeclination = 0.39782 * sin($solLongitude);
957
+ $solDeclination /= sqrt(-$solDeclination * $solDeclination + 1);
958
+ $solDeclination = atan2($solDeclination, 1);
959
+
960
+ $solHorizon = $horizon - sin($solDeclination) * sin($radLatitude);
961
+ $solHorizon /= cos($solDeclination) * cos($radLatitude);
962
+
963
+ // midnight sun, always night
964
+ if (abs($solHorizon) > 1) {
965
+ return false;
966
+ }
967
+
968
+ $solHorizon /= sqrt(-$solHorizon * $solHorizon + 1);
969
+ $solHorizon = $quarterCircle - atan2($solHorizon, 1);
970
+
971
+ if ($rise) {
972
+ $solHorizon = $fullCircle - $solHorizon;
973
+ }
974
+
975
+ // time calculation
976
+ $localTime = $solHorizon + $solAscension - 0.0172028 * $radDay - 1.73364;
977
+ $universalTime = $localTime - $radLongitude;
978
+
979
+ // determinate quadrant
980
+ $universalTime = $this->_range($universalTime, $fullCircle);
981
+
982
+ // radiant to hours
983
+ $universalTime *= 24 / $fullCircle;
984
+
985
+ // convert to time
986
+ $hour = intval($universalTime);
987
+ $universalTime = ($universalTime - $hour) * 60;
988
+ $min = intval($universalTime);
989
+ $universalTime = ($universalTime - $min) * 60;
990
+ $sec = intval($universalTime);
991
+
992
+ return $this->mktime($hour, $min, $sec, $this->date('m', $this->_unixTimestamp),
993
+ $this->date('j', $this->_unixTimestamp), $this->date('Y', $this->_unixTimestamp),
994
+ -1, true);
995
+ }
996
+
997
+
998
+ /**
999
+ * Sets a new timezone for calculation of $this object's gmt offset.
1000
+ * For a list of supported timezones look here: http://php.net/timezones
1001
+ * If no timezone can be detected or the given timezone is wrong UTC will be set.
1002
+ *
1003
+ * @param string $zone OPTIONAL timezone for date calculation; defaults to date_default_timezone_get()
1004
+ * @return string actual set timezone string
1005
+ * @throws Zend_Date_Exception
1006
+ */
1007
+ public function setTimezone($zone = null)
1008
+ {
1009
+ $oldzone = @date_default_timezone_get();
1010
+ if ($zone === null) {
1011
+ $zone = $oldzone;
1012
+ }
1013
+
1014
+ // throw an error on false input, but only if the new date extension is available
1015
+ if (function_exists('timezone_open')) {
1016
+ if (!@timezone_open($zone)) {
1017
+ require_once 'Zend/Date/Exception.php';
1018
+ throw new Zend_Date_Exception("timezone ($zone) is not a known timezone", $zone);
1019
+ }
1020
+ }
1021
+ // this can generate an error if the date extension is not available and a false timezone is given
1022
+ $result = @date_default_timezone_set($zone);
1023
+ if ($result === true) {
1024
+ $this->_offset = mktime(0, 0, 0, 1, 2, 1970) - gmmktime(0, 0, 0, 1, 2, 1970);
1025
+ $this->_timezone = $zone;
1026
+ }
1027
+ date_default_timezone_set($oldzone);
1028
+
1029
+ if (($zone == 'UTC') or ($zone == 'GMT')) {
1030
+ $this->_dst = false;
1031
+ }
1032
+
1033
+ return $result;
1034
+ }
1035
+
1036
+
1037
+ /**
1038
+ * Return the timezone of $this object.
1039
+ * The timezone is initially set when the object is instantiated.
1040
+ *
1041
+ * @return string actual set timezone string
1042
+ */
1043
+ public function getTimezone()
1044
+ {
1045
+ return $this->_timezone;
1046
+ }
1047
+
1048
+
1049
+ /**
1050
+ * Return the offset to GMT of $this object's timezone.
1051
+ * The offset to GMT is initially set when the object is instantiated using the currently,
1052
+ * in effect, default timezone for PHP functions.
1053
+ *
1054
+ * @return integer seconds difference between GMT timezone and timezone when object was instantiated
1055
+ */
1056
+ public function getGmtOffset()
1057
+ {
1058
+ return $this->_offset;
1059
+ }
1060
+ }
lib/Zend/Date/Exception.php ADDED
@@ -0,0 +1,49 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Zend Framework
4
+ *
5
+ * LICENSE
6
+ *
7
+ * This source file is subject to the new BSD license that is bundled
8
+ * with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://framework.zend.com/license/new-bsd
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@zend.com so we can send you a copy immediately.
14
+ *
15
+ * @category Zend
16
+ * @package Zend_Date
17
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
18
+ * @version $Id: Exception.php 8064 2008-02-16 10:58:39Z thomas $
19
+ * @license http://framework.zend.com/license/new-bsd New BSD License
20
+ */
21
+
22
+
23
+ /**
24
+ * Zend_Exception
25
+ */
26
+ require_once 'Zend/Exception.php';
27
+
28
+
29
+ /**
30
+ * @category Zend
31
+ * @package Zend_Date
32
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
33
+ * @license http://framework.zend.com/license/new-bsd New BSD License
34
+ */
35
+ class Zend_Date_Exception extends Zend_Exception
36
+ {
37
+ protected $operand = null;
38
+
39
+ public function __construct($message, $op = null)
40
+ {
41
+ $this->operand = $op;
42
+ parent::__construct($message);
43
+ }
44
+
45
+ public function getOperand()
46
+ {
47
+ return $this->operand;
48
+ }
49
+ }
lib/Zend/Db.php ADDED
@@ -0,0 +1,263 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Zend Framework
5
+ *
6
+ * LICENSE
7
+ *
8
+ * This source file is subject to the new BSD license that is bundled
9
+ * with this package in the file LICENSE.txt.
10
+ * It is also available through the world-wide-web at this URL:
11
+ * http://framework.zend.com/license/new-bsd
12
+ * If you did not receive a copy of the license and are unable to
13
+ * obtain it through the world-wide-web, please send an email
14
+ * to license@zend.com so we can send you a copy immediately.
15
+ *
16
+ * @category Zend
17
+ * @package Zend_Db
18
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
19
+ * @license http://framework.zend.com/license/new-bsd New BSD License
20
+ * @version $Id: Db.php 8084 2008-02-17 01:41:23Z peptolab $
21
+ */
22
+
23
+
24
+ /**
25
+ * @see Zend_Loader
26
+ */
27
+ require_once 'Zend/Loader.php';
28
+
29
+
30
+ /**
31
+ * Class for connecting to SQL databases and performing common operations.
32
+ *
33
+ * @category Zend
34
+ * @package Zend_Db
35
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
36
+ * @license http://framework.zend.com/license/new-bsd New BSD License
37
+ */
38
+ class Zend_Db
39
+ {
40
+
41
+ /**
42
+ * Use the PROFILER constant in the config of a Zend_Db_Adapter.
43
+ */
44
+ const PROFILER = 'profiler';
45
+
46
+ /**
47
+ * Use the CASE_FOLDING constant in the config of a Zend_Db_Adapter.
48
+ */
49
+ const CASE_FOLDING = 'caseFolding';
50
+
51
+ /**
52
+ * Use the AUTO_QUOTE_IDENTIFIERS constant in the config of a Zend_Db_Adapter.
53
+ */
54
+ const AUTO_QUOTE_IDENTIFIERS = 'autoQuoteIdentifiers';
55
+
56
+ /**
57
+ * Use the INT_TYPE, BIGINT_TYPE, and FLOAT_TYPE with the quote() method.
58
+ */
59
+ const INT_TYPE = 0;
60
+ const BIGINT_TYPE = 1;
61
+ const FLOAT_TYPE = 2;
62
+
63
+ /**
64
+ * PDO constant values discovered by this script result:
65
+ *
66
+ * $list = array(
67
+ * 'PARAM_BOOL', 'PARAM_NULL', 'PARAM_INT', 'PARAM_STR', 'PARAM_LOB',
68
+ * 'PARAM_STMT', 'PARAM_INPUT_OUTPUT', 'FETCH_LAZY', 'FETCH_ASSOC',
69
+ * 'FETCH_NUM', 'FETCH_BOTH', 'FETCH_OBJ', 'FETCH_BOUND',
70
+ * 'FETCH_COLUMN', 'FETCH_CLASS', 'FETCH_INTO', 'FETCH_FUNC',
71
+ * 'FETCH_GROUP', 'FETCH_UNIQUE', 'FETCH_CLASSTYPE', 'FETCH_SERIALIZE',
72
+ * 'FETCH_NAMED', 'ATTR_AUTOCOMMIT', 'ATTR_PREFETCH', 'ATTR_TIMEOUT',
73
+ * 'ATTR_ERRMODE', 'ATTR_SERVER_VERSION', 'ATTR_CLIENT_VERSION',
74
+ * 'ATTR_SERVER_INFO', 'ATTR_CONNECTION_STATUS', 'ATTR_CASE',
75
+ * 'ATTR_CURSOR_NAME', 'ATTR_CURSOR', 'ATTR_ORACLE_NULLS',
76
+ * 'ATTR_PERSISTENT', 'ATTR_STATEMENT_CLASS', 'ATTR_FETCH_TABLE_NAMES',
77
+ * 'ATTR_FETCH_CATALOG_NAMES', 'ATTR_DRIVER_NAME',
78
+ * 'ATTR_STRINGIFY_FETCHES', 'ATTR_MAX_COLUMN_LEN', 'ERRMODE_SILENT',
79
+ * 'ERRMODE_WARNING', 'ERRMODE_EXCEPTION', 'CASE_NATURAL',
80
+ * 'CASE_LOWER', 'CASE_UPPER', 'NULL_NATURAL', 'NULL_EMPTY_STRING',
81
+ * 'NULL_TO_STRING', 'ERR_NONE', 'FETCH_ORI_NEXT',
82
+ * 'FETCH_ORI_PRIOR', 'FETCH_ORI_FIRST', 'FETCH_ORI_LAST',
83
+ * 'FETCH_ORI_ABS', 'FETCH_ORI_REL', 'CURSOR_FWDONLY', 'CURSOR_SCROLL',
84
+ * 'ERR_CANT_MAP', 'ERR_SYNTAX', 'ERR_CONSTRAINT', 'ERR_NOT_FOUND',
85
+ * 'ERR_ALREADY_EXISTS', 'ERR_NOT_IMPLEMENTED', 'ERR_MISMATCH',
86
+ * 'ERR_TRUNCATED', 'ERR_DISCONNECTED', 'ERR_NO_PERM',
87
+ * );
88
+ *
89
+ * $const = array();
90
+ * foreach ($list as $name) {
91
+ * $const[$name] = constant("PDO::$name");
92
+ * }
93
+ * var_export($const);
94
+ */
95
+ const ATTR_AUTOCOMMIT = 0;
96
+ const ATTR_CASE = 8;
97
+ const ATTR_CLIENT_VERSION = 5;
98
+ const ATTR_CONNECTION_STATUS = 7;
99
+ const ATTR_CURSOR = 10;
100
+ const ATTR_CURSOR_NAME = 9;
101
+ const ATTR_DRIVER_NAME = 16;
102
+ const ATTR_ERRMODE = 3;
103
+ const ATTR_FETCH_CATALOG_NAMES = 15;
104
+ const ATTR_FETCH_TABLE_NAMES = 14;
105
+ const ATTR_MAX_COLUMN_LEN = 18;
106
+ const ATTR_ORACLE_NULLS = 11;
107
+ const ATTR_PERSISTENT = 12;
108
+ const ATTR_PREFETCH = 1;
109
+ const ATTR_SERVER_INFO = 6;
110
+ const ATTR_SERVER_VERSION = 4;
111
+ const ATTR_STATEMENT_CLASS = 13;
112
+ const ATTR_STRINGIFY_FETCHES = 17;
113
+ const ATTR_TIMEOUT = 2;
114
+ const CASE_LOWER = 2;
115
+ const CASE_NATURAL = 0;
116
+ const CASE_UPPER = 1;
117
+ const CURSOR_FWDONLY = 0;
118
+ const CURSOR_SCROLL = 1;
119
+ const ERR_ALREADY_EXISTS = NULL;
120
+ const ERR_CANT_MAP = NULL;
121
+ const ERR_CONSTRAINT = NULL;
122
+ const ERR_DISCONNECTED = NULL;
123
+ const ERR_MISMATCH = NULL;
124
+ const ERR_NO_PERM = NULL;
125
+ const ERR_NONE = '00000';
126
+ const ERR_NOT_FOUND = NULL;
127
+ const ERR_NOT_IMPLEMENTED = NULL;
128
+ const ERR_SYNTAX = NULL;
129
+ const ERR_TRUNCATED = NULL;
130
+ const ERRMODE_EXCEPTION = 2;
131
+ const ERRMODE_SILENT = 0;
132
+ const ERRMODE_WARNING = 1;
133
+ const FETCH_ASSOC = 2;
134
+ const FETCH_BOTH = 4;
135
+ const FETCH_BOUND = 6;
136
+ const FETCH_CLASS = 8;
137
+ const FETCH_CLASSTYPE = 262144;
138
+ const FETCH_COLUMN = 7;
139
+ const FETCH_FUNC = 10;
140
+ const FETCH_GROUP = 65536;
141
+ const FETCH_INTO = 9;
142
+ const FETCH_LAZY = 1;
143
+ const FETCH_NAMED = 11;
144
+ const FETCH_NUM = 3;
145
+ const FETCH_OBJ = 5;
146
+ const FETCH_ORI_ABS = 4;
147
+ const FETCH_ORI_FIRST = 2;
148
+ const FETCH_ORI_LAST = 3;
149
+ const FETCH_ORI_NEXT = 0;
150
+ const FETCH_ORI_PRIOR = 1;
151
+ const FETCH_ORI_REL = 5;
152
+ const FETCH_SERIALIZE = 524288;
153
+ const FETCH_UNIQUE = 196608;
154
+ const NULL_EMPTY_STRING = 1;
155
+ const NULL_NATURAL = 0;
156
+ const NULL_TO_STRING = NULL;
157
+ const PARAM_BOOL = 5;
158
+ const PARAM_INPUT_OUTPUT = -2147483648;
159
+ const PARAM_INT = 1;
160
+ const PARAM_LOB = 3;
161
+ const PARAM_NULL = 0;
162
+ const PARAM_STMT = 4;
163
+ const PARAM_STR = 2;
164
+
165
+ /**
166
+ * Factory for Zend_Db_Adapter_Abstract classes.
167
+ *
168
+ * First argument may be a string containing the base of the adapter class
169
+ * name, e.g. 'Mysqli' corresponds to class Zend_Db_Adapter_Mysqli. This
170
+ * is case-insensitive.
171
+ *
172
+ * First argument may alternatively be an object of type Zend_Config.
173
+ * The adapter class base name is read from the 'adapter' property.
174
+ * The adapter config parameters are read from the 'params' property.
175
+ *
176
+ * Second argument is optional and may be an associative array of key-value
177
+ * pairs. This is used as the argument to the adapter constructor.
178
+ *
179
+ * If the first argument is of type Zend_Config, it is assumed to contain
180
+ * all parameters, and the second argument is ignored.
181
+ *
182
+ * @param mixed $adapter String name of base adapter class, or Zend_Config object.
183
+ * @param mixed $config OPTIONAL; an array or Zend_Config object with adapter parameters.
184
+ * @return Zend_Db_Adapter_Abstract
185
+ * @throws Zend_Db_Exception
186
+ */
187
+ public static function factory($adapter, $config = array())
188
+ {
189
+ /*
190
+ * Convert Zend_Config argument to plain string
191
+ * adapter name and separate config object.
192
+ */
193
+ if ($adapter instanceof Zend_Config) {
194
+ if (isset($adapter->params)) {
195
+ $config = $adapter->params->toArray();
196
+ }
197
+ if (isset($adapter->adapter)) {
198
+ $adapter = (string) $adapter->adapter;
199
+ } else {
200
+ $adapter = null;
201
+ }
202
+ }
203
+
204
+ /*
205
+ * Verify that adapter parameters are in an array.
206
+ */
207
+ if (!is_array($config)) {
208
+ /**
209
+ * @see Zend_Db_Exception
210
+ */
211
+ require_once 'Zend/Db/Exception.php';
212
+ throw new Zend_Db_Exception('Adapter parameters must be in an array or a Zend_Config object');
213
+ }
214
+
215
+ /*
216
+ * Verify that an adapter name has been specified.
217
+ */
218
+ if (!is_string($adapter) || empty($adapter)) {
219
+ /**
220
+ * @see Zend_Db_Exception
221
+ */
222
+ require_once 'Zend/Db/Exception.php';
223
+ throw new Zend_Db_Exception('Adapter name must be specified in a string');
224
+ }
225
+
226
+ /*
227
+ * Form full adapter class name
228
+ */
229
+ $adapterNamespace = 'Zend_Db_Adapter';
230
+ if (isset($config['adapterNamespace'])) {
231
+ $adapterNamespace = $config['adapterNamespace'];
232
+ unset($config['adapterNamespace']);
233
+ }
234
+ $adapterName = strtolower($adapterNamespace . '_' . $adapter);
235
+ $adapterName = str_replace(' ', '_', ucwords(str_replace('_', ' ', $adapterName)));
236
+
237
+ /*
238
+ * Load the adapter class. This throws an exception
239
+ * if the specified class cannot be loaded.
240
+ */
241
+ @Zend_Loader::loadClass($adapterName);
242
+
243
+ /*
244
+ * Create an instance of the adapter class.
245
+ * Pass the config to the adapter class constructor.
246
+ */
247
+ $dbAdapter = new $adapterName($config);
248
+
249
+ /*
250
+ * Verify that the object created is a descendent of the abstract adapter type.
251
+ */
252
+ if (! $dbAdapter instanceof Zend_Db_Adapter_Abstract) {
253
+ /**
254
+ * @see Zend_Db_Exception
255
+ */
256
+ require_once 'Zend/Db/Exception.php';
257
+ throw new Zend_Db_Exception("Adapter class '$adapterName' does not extend Zend_Db_Adapter_Abstract");
258
+ }
259
+
260
+ return $dbAdapter;
261
+ }
262
+
263
+ }
lib/Zend/Db/Adapter/Abstract.php ADDED
@@ -0,0 +1,1117 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Zend Framework
5
+ *
6
+ * LICENSE
7
+ *
8
+ * This source file is subject to the new BSD license that is bundled
9
+ * with this package in the file LICENSE.txt.
10
+ * It is also available through the world-wide-web at this URL:
11
+ * http://framework.zend.com/license/new-bsd
12
+ * If you did not receive a copy of the license and are unable to
13
+ * obtain it through the world-wide-web, please send an email
14
+ * to license@zend.com so we can send you a copy immediately.
15
+ *
16
+ * @category Zend
17
+ * @package Zend_Db
18
+ * @subpackage Adapter
19
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
20
+ * @license http://framework.zend.com/license/new-bsd New BSD License
21
+ * @version $Id: Abstract.php 8711 2008-03-09 18:08:32Z thomas $
22
+ */
23
+
24
+
25
+ /**
26
+ * @see Zend_Config
27
+ */
28
+ require_once 'Zend/Config.php';
29
+
30
+ /**
31
+ * @see Zend_Db
32
+ */
33
+ require_once 'Zend/Db.php';
34
+
35
+ /**
36
+ * @see Zend_Db_Select
37
+ */
38
+ require_once 'Zend/Db/Select.php';
39
+
40
+ /**
41
+ * @see Zend_Loader
42
+ */
43
+ require_once 'Zend/Loader.php';
44
+
45
+
46
+ /**
47
+ * Class for connecting to SQL databases and performing common operations.
48
+ *
49
+ * @category Zend
50
+ * @package Zend_Db
51
+ * @subpackage Adapter
52
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
53
+ * @license http://framework.zend.com/license/new-bsd New BSD License
54
+ */
55
+ abstract class Zend_Db_Adapter_Abstract
56
+ {
57
+
58
+ /**
59
+ * User-provided configuration
60
+ *
61
+ * @var array
62
+ */
63
+ protected $_config = array();
64
+
65
+ /**
66
+ * Fetch mode
67
+ *
68
+ * @var integer
69
+ */
70
+ protected $_fetchMode = Zend_Db::FETCH_ASSOC;
71
+
72
+ /**
73
+ * Query profiler object, of type Zend_Db_Profiler
74
+ * or a subclass of that.
75
+ *
76
+ * @var Zend_Db_Profiler
77
+ */
78
+ protected $_profiler;
79
+
80
+ /**
81
+ * Default class name for the profiler object.
82
+ *
83
+ * @var string
84
+ */
85
+ protected $_defaultProfilerClass = 'Zend_Db_Profiler';
86
+
87
+ /**
88
+ * Database connection
89
+ *
90
+ * @var object|resource|null
91
+ */
92
+ protected $_connection = null;
93
+
94
+ /**
95
+ * Specifies the case of column names retrieved in queries
96
+ * Options
97
+ * Zend_Db::CASE_NATURAL (default)
98
+ * Zend_Db::CASE_LOWER
99
+ * Zend_Db::CASE_UPPER
100
+ *
101
+ * @var integer
102
+ */
103
+ protected $_caseFolding = Zend_Db::CASE_NATURAL;
104
+
105
+ /**
106
+ * Specifies whether the adapter automatically quotes identifiers.
107
+ * If true, most SQL generated by Zend_Db classes applies
108
+ * identifier quoting automatically.
109
+ * If false, developer must quote identifiers themselves
110
+ * by calling quoteIdentifier().
111
+ *
112
+ * @var bool
113
+ */
114
+ protected $_autoQuoteIdentifiers = true;
115
+
116
+ /**
117
+ * Keys are UPPERCASE SQL datatypes or the constants
118
+ * Zend_Db::INT_TYPE, Zend_Db::BIGINT_TYPE, or Zend_Db::FLOAT_TYPE.
119
+ *
120
+ * Values are:
121
+ * 0 = 32-bit integer
122
+ * 1 = 64-bit integer
123
+ * 2 = float or decimal
124
+ *
125
+ * @var array Associative array of datatypes to values 0, 1, or 2.
126
+ */
127
+ protected $_numericDataTypes = array(
128
+ Zend_Db::INT_TYPE => Zend_Db::INT_TYPE,
129
+ Zend_Db::BIGINT_TYPE => Zend_Db::BIGINT_TYPE,
130
+ Zend_Db::FLOAT_TYPE => Zend_Db::FLOAT_TYPE
131
+ );
132
+
133
+ /**
134
+ * Constructor.
135
+ *
136
+ * $config is an array of key/value pairs or an instance of Zend_Config
137
+ * containing configuration options. These options are common to most adapters:
138
+ *
139
+ * dbname => (string) The name of the database to user
140
+ * username => (string) Connect to the database as this username.
141
+ * password => (string) Password associated with the username.
142
+ * host => (string) What host to connect to, defaults to localhost
143
+ *
144
+ * Some options are used on a case-by-case basis by adapters:
145
+ *
146
+ * port => (string) The port of the database
147
+ * persistent => (boolean) Whether to use a persistent connection or not, defaults to false
148
+ * protocol => (string) The network protocol, defaults to TCPIP
149
+ * caseFolding => (int) style of case-alteration used for identifiers
150
+ *
151
+ * @param array|Zend_Config $config An array or instance of Zend_Config having configuration data
152
+ * @throws Zend_Db_Adapter_Exception
153
+ */
154
+ public function __construct($config)
155
+ {
156
+ /*
157
+ * Verify that adapter parameters are in an array.
158
+ */
159
+ if (!is_array($config)) {
160
+ /*
161
+ * Convert Zend_Config argument to a plain array.
162
+ */
163
+ if ($config instanceof Zend_Config) {
164
+ $config = $config->toArray();
165
+ } else {
166
+ /**
167
+ * @see Zend_Db_Exception
168
+ */
169
+ require_once 'Zend/Db/Exception.php';
170
+ throw new Zend_Db_Exception('Adapter parameters must be in an array or a Zend_Config object');
171
+ }
172
+ }
173
+
174
+ $this->_checkRequiredOptions($config);
175
+
176
+ $options = array(
177
+ Zend_Db::CASE_FOLDING => $this->_caseFolding,
178
+ Zend_DB::AUTO_QUOTE_IDENTIFIERS => $this->_autoQuoteIdentifiers
179
+ );
180
+ $driverOptions = array();
181
+
182
+ /*
183
+ * normalize the config and merge it with the defaults
184
+ */
185
+ if (array_key_exists('options', $config)) {
186
+ // can't use array_merge() because keys might be integers
187
+ foreach ((array) $config['options'] as $key => $value) {
188
+ $options[$key] = $value;
189
+ }
190
+ }
191
+ if (array_key_exists('driver_options', $config)) {
192
+ // can't use array_merge() because keys might be integers
193
+ foreach ((array) $config['driver_options'] as $key => $value) {
194
+ $driverOptions[$key] = $value;
195
+ }
196
+ }
197
+ $this->_config = array_merge($this->_config, $config);
198
+ $this->_config['options'] = $options;
199
+ $this->_config['driver_options'] = $driverOptions;
200
+
201
+ // obtain the case setting, if there is one
202
+ if (array_key_exists(Zend_Db::CASE_FOLDING, $options)) {
203
+ $case = (int) $options[Zend_Db::CASE_FOLDING];
204
+ switch ($case) {
205
+ case Zend_Db::CASE_LOWER:
206
+ case Zend_Db::CASE_UPPER:
207
+ case Zend_Db::CASE_NATURAL:
208
+ $this->_caseFolding = $case;
209
+ break;
210
+ default:
211
+ require_once 'Zend/Db/Adapter/Exception.php';
212
+ throw new Zend_Db_Adapter_Exception('Case must be one of the following constants: '
213
+ . 'Zend_Db::CASE_NATURAL, Zend_Db::CASE_LOWER, Zend_Db::CASE_UPPER');
214
+ }
215
+ }
216
+
217
+ // obtain quoting property if there is one
218
+ if (array_key_exists(Zend_Db::AUTO_QUOTE_IDENTIFIERS, $options)) {
219
+ $this->_autoQuoteIdentifiers = (bool) $options[Zend_Db::AUTO_QUOTE_IDENTIFIERS];
220
+ }
221
+
222
+ // create a profiler object
223
+ $profiler = false;
224
+ if (array_key_exists(Zend_Db::PROFILER, $this->_config)) {
225
+ $profiler = $this->_config[Zend_Db::PROFILER];
226
+ unset($this->_config[Zend_Db::PROFILER]);
227
+ }
228
+ $this->setProfiler($profiler);
229
+ }
230
+
231
+ /**
232
+ * Check for config options that are mandatory.
233
+ * Throw exceptions if any are missing.
234
+ *
235
+ * @param array $config
236
+ * @throws Zend_Db_Adapter_Exception
237
+ */
238
+ protected function _checkRequiredOptions(array $config)
239
+ {
240
+ // we need at least a dbname
241
+ if (! array_key_exists('dbname', $config)) {
242
+ require_once 'Zend/Db/Adapter/Exception.php';
243
+ throw new Zend_Db_Adapter_Exception("Configuration array must have a key for 'dbname' that names the database instance");
244
+ }
245
+
246
+ if (! array_key_exists('password', $config)) {
247
+ /**
248
+ * @see Zend_Db_Adapter_Exception
249
+ */
250
+ require_once 'Zend/Db/Adapter/Exception.php';
251
+ throw new Zend_Db_Adapter_Exception("Configuration array must have a key for 'password' for login credentials");
252
+ }
253
+
254
+ if (! array_key_exists('username', $config)) {
255
+ /**
256
+ * @see Zend_Db_Adapter_Exception
257
+ */
258
+ require_once 'Zend/Db/Adapter/Exception.php';
259
+ throw new Zend_Db_Adapter_Exception("Configuration array must have a key for 'username' for login credentials");
260
+ }
261
+ }
262
+
263
+ /**
264
+ * Returns the underlying database connection object or resource.
265
+ * If not presently connected, this initiates the connection.
266
+ *
267
+ * @return object|resource|null
268
+ */
269
+ public function getConnection()
270
+ {
271
+ $this->_connect();
272
+ return $this->_connection;
273
+ }
274
+
275
+ /**
276
+ * Returns the configuration variables in this adapter.
277
+ *
278
+ * @return array
279
+ */
280
+ public function getConfig()
281
+ {
282
+ return $this->_config;
283
+ }
284
+
285
+ /**
286
+ * Set the adapter's profiler object.
287
+ *
288
+ * The argument may be a boolean, an associative array, an instance of
289
+ * Zend_Db_Profiler, or an instance of Zend_Config.
290
+ *
291
+ * A boolean argument sets the profiler to enabled if true, or disabled if
292
+ * false. The profiler class is the adapter's default profiler class,
293
+ * Zend_Db_Profiler.
294
+ *
295
+ * An instance of Zend_Db_Profiler sets the adapter's instance to that
296
+ * object. The profiler is enabled and disabled separately.
297
+ *
298
+ * An associative array argument may contain any of the keys 'enabled',
299
+ * 'class', and 'instance'. The 'enabled' and 'instance' keys correspond to the
300
+ * boolean and object types documented above. The 'class' key is used to name a
301
+ * class to use for a custom profiler. The class must be Zend_Db_Profiler or a
302
+ * subclass. The class is instantiated with no constructor arguments. The 'class'
303
+ * option is ignored when the 'instance' option is supplied.
304
+ *
305
+ * An object of type Zend_Config may contain the properties 'enabled', 'class', and
306
+ * 'instance', just as if an associative array had been passed instead.
307
+ *
308
+ * @param Zend_Db_Profiler|Zend_Config|array|boolean $profiler
309
+ * @return Zend_Db_Adapter_Abstract Provides a fluent interface
310
+ * @throws Zend_Db_Profiler_Exception if the object instance or class specified
311
+ * is not Zend_Db_Profiler or an extension of that class.
312
+ */
313
+ public function setProfiler($profiler)
314
+ {
315
+ $enabled = null;
316
+ $profilerClass = $this->_defaultProfilerClass;
317
+ $profilerInstance = null;
318
+
319
+ if ($profilerIsObject = is_object($profiler)) {
320
+ if ($profiler instanceof Zend_Db_Profiler) {
321
+ $profilerInstance = $profiler;
322
+ } else if ($profiler instanceof Zend_Config) {
323
+ $profiler = $profiler->toArray();
324
+ } else {
325
+ /**
326
+ * @see Zend_Db_Profiler_Exception
327
+ */
328
+ require_once 'Zend/Db/Profiler/Exception.php';
329
+ throw new Zend_Db_Profiler_Exception('Profiler argument must be an instance of either Zend_Db_Profiler'
330
+ . ' or Zend_Config when provided as an object');
331
+ }
332
+ }
333
+
334
+ if (is_array($profiler)) {
335
+ if (isset($profiler['enabled'])) {
336
+ $enabled = (bool) $profiler['enabled'];
337
+ }
338
+ if (isset($profiler['class'])) {
339
+ $profilerClass = $profiler['class'];
340
+ }
341
+ if (isset($profiler['instance'])) {
342
+ $profilerInstance = $profiler['instance'];
343
+ }
344
+ } else if (!$profilerIsObject) {
345
+ $enabled = (bool) $profiler;
346
+ }
347
+
348
+ if ($profilerInstance === null) {
349
+ @Zend_Loader::loadClass($profilerClass);
350
+ $profilerInstance = new $profilerClass();
351
+ }
352
+
353
+ if (!$profilerInstance instanceof Zend_Db_Profiler) {
354
+ require_once 'Zend/Db/Profiler/Exception.php';
355
+ throw new Zend_Db_Profiler_Exception('Class ' . get_class($profilerInstance) . ' does not extend '
356
+ . 'Zend_Db_Profiler');
357
+ }
358
+
359
+ if (null !== $enabled) {
360
+ $profilerInstance->setEnabled($enabled);
361
+ }
362
+
363
+ $this->_profiler = $profilerInstance;
364
+
365
+ return $this;
366
+ }
367
+
368
+
369
+ /**
370
+ * Returns the profiler for this adapter.
371
+ *
372
+ * @return Zend_Db_Profiler
373
+ */
374
+ public function getProfiler()
375
+ {
376
+ return $this->_profiler;
377
+ }
378
+
379
+ /**
380
+ * Prepares and executes an SQL statement with bound data.
381
+ *
382
+ * @param mixed $sql The SQL statement with placeholders.
383
+ * May be a string or Zend_Db_Select.
384
+ * @param mixed $bind An array of data to bind to the placeholders.
385
+ * @return Zend_Db_Statement_Interface
386
+ */
387
+ public function query($sql, $bind = array())
388
+ {
389
+ // connect to the database if needed
390
+ $this->_connect();
391
+
392
+ // is the $sql a Zend_Db_Select object?
393
+ if ($sql instanceof Zend_Db_Select) {
394
+ $sql = $sql->__toString();
395
+ }
396
+
397
+ // make sure $bind to an array;
398
+ // don't use (array) typecasting because
399
+ // because $bind may be a Zend_Db_Expr object
400
+ if (!is_array($bind)) {
401
+ $bind = array($bind);
402
+ }
403
+
404
+ // prepare and execute the statement with profiling
405
+ $stmt = $this->prepare($sql);
406
+ $stmt->execute($bind);
407
+
408
+ // return the results embedded in the prepared statement object
409
+ $stmt->setFetchMode($this->_fetchMode);
410
+ return $stmt;
411
+ }
412
+
413
+ /**
414
+ * Leave autocommit mode and begin a transaction.
415
+ *
416
+ * @return bool True
417
+ */
418
+ public function beginTransaction()
419
+ {
420
+ $this->_connect();
421
+ $q = $this->_profiler->queryStart('begin', Zend_Db_Profiler::TRANSACTION);
422
+ $this->_beginTransaction();
423
+ $this->_profiler->queryEnd($q);
424
+ return true;
425
+ }
426
+
427
+ /**
428
+ * Commit a transaction and return to autocommit mode.
429
+ *
430
+ * @return bool True
431
+ */
432
+ public function commit()
433
+ {
434
+ $this->_connect();
435
+ $q = $this->_profiler->queryStart('commit', Zend_Db_Profiler::TRANSACTION);
436
+ $this->_commit();
437
+ $this->_profiler->queryEnd($q);
438
+ return true;
439
+ }
440
+
441
+ /**
442
+ * Roll back a transaction and return to autocommit mode.
443
+ *
444
+ * @return bool True
445
+ */
446
+ public function rollBack()
447
+ {
448
+ $this->_connect();
449
+ $q = $this->_profiler->queryStart('rollback', Zend_Db_Profiler::TRANSACTION);
450
+ $this->_rollBack();
451
+ $this->_profiler->queryEnd($q);
452
+ return true;
453
+ }
454
+
455
+ /**
456
+ * Inserts a table row with specified data.
457
+ *
458
+ * @param mixed $table The table to insert data into.
459
+ * @param array $bind Column-value pairs.
460
+ * @return int The number of affected rows.
461
+ */
462
+ public function insert($table, array $bind)
463
+ {
464
+ // extract and quote col names from the array keys
465
+ $cols = array();
466
+ $vals = array();
467
+ foreach ($bind as $col => $val) {
468
+ $cols[] = $this->quoteIdentifier($col, true);
469
+ if ($val instanceof Zend_Db_Expr) {
470
+ $vals[] = $val->__toString();
471
+ unset($bind[$col]);
472
+ } else {
473
+ $vals[] = '?';
474
+ }
475
+ }
476
+
477
+ // build the statement
478
+ $sql = "INSERT INTO "
479
+ . $this->quoteIdentifier($table, true)
480
+ . ' (' . implode(', ', $cols) . ') '
481
+ . 'VALUES (' . implode(', ', $vals) . ')';
482
+
483
+ // execute the statement and return the number of affected rows
484
+ $stmt = $this->query($sql, array_values($bind));
485
+ $result = $stmt->rowCount();
486
+ return $result;
487
+ }
488
+
489
+ /**
490
+ * Updates table rows with specified data based on a WHERE clause.
491
+ *
492
+ * @param mixed $table The table to update.
493
+ * @param array $bind Column-value pairs.
494
+ * @param mixed $where UPDATE WHERE clause(s).
495
+ * @return int The number of affected rows.
496
+ */
497
+ public function update($table, array $bind, $where = '')
498
+ {
499
+ /**
500
+ * Build "col = ?" pairs for the statement,
501
+ * except for Zend_Db_Expr which is treated literally.
502
+ */
503
+ $set = array();
504
+ foreach ($bind as $col => $val) {
505
+ if ($val instanceof Zend_Db_Expr) {
506
+ $val = $val->__toString();
507
+ unset($bind[$col]);
508
+ } else {
509
+ $val = '?';
510
+ }
511
+ $set[] = $this->quoteIdentifier($col, true) . ' = ' . $val;
512
+ }
513
+
514
+ $where = $this->_whereExpr($where);
515
+
516
+ /**
517
+ * Build the UPDATE statement
518
+ */
519
+ $sql = "UPDATE "
520
+ . $this->quoteIdentifier($table, true)
521
+ . ' SET ' . implode(', ', $set)
522
+ . (($where) ? " WHERE $where" : '');
523
+
524
+ /**
525
+ * Execute the statement and return the number of affected rows
526
+ */
527
+ $stmt = $this->query($sql, array_values($bind));
528
+ $result = $stmt->rowCount();
529
+ return $result;
530
+ }
531
+
532
+ /**
533
+ * Deletes table rows based on a WHERE clause.
534
+ *
535
+ * @param mixed $table The table to update.
536
+ * @param mixed $where DELETE WHERE clause(s).
537
+ * @return int The number of affected rows.
538
+ */
539
+ public function delete($table, $where = '')
540
+ {
541
+ $where = $this->_whereExpr($where);
542
+
543
+ /**
544
+ * Build the DELETE statement
545
+ */
546
+ $sql = "DELETE FROM "
547
+ . $this->quoteIdentifier($table, true)
548
+ . (($where) ? " WHERE $where" : '');
549
+
550
+ /**
551
+ * Execute the statement and return the number of affected rows
552
+ */
553
+ $stmt = $this->query($sql);
554
+ $result = $stmt->rowCount();
555
+ return $result;
556
+ }
557
+
558
+ /**
559
+ * Convert an array, string, or Zend_Db_Expr object
560
+ * into a string to put in a WHERE clause.
561
+ *
562
+ * @param mixed $where
563
+ * @return string
564
+ */
565
+ protected function _whereExpr($where)
566
+ {
567
+ if (empty($where)) {
568
+ return $where;
569
+ }
570
+ if (!is_array($where)) {
571
+ $where = array($where);
572
+ }
573
+ foreach ($where as &$term) {
574
+ if ($term instanceof Zend_Db_Expr) {
575
+ $term = $term->__toString();
576
+ }
577
+ $term = '(' . $term . ')';
578
+ }
579
+ $where = implode(' AND ', $where);
580
+ return $where;
581
+ }
582
+
583
+ /**
584
+ * Creates and returns a new Zend_Db_Select object for this adapter.
585
+ *
586
+ * @return Zend_Db_Select
587
+ */
588
+ public function select()
589
+ {
590
+ return new Zend_Db_Select($this);
591
+ }
592
+
593
+ /**
594
+ * Get the fetch mode.
595
+ *
596
+ * @return int
597
+ */
598
+ public function getFetchMode()
599
+ {
600
+ return $this->_fetchMode;
601
+ }
602
+
603
+ /**
604
+ * Fetches all SQL result rows as a sequential array.
605
+ * Uses the current fetchMode for the adapter.
606
+ *
607
+ * @param string|Zend_Db_Select $sql An SQL SELECT statement.
608
+ * @param mixed $bind Data to bind into SELECT placeholders.
609
+ * @param mixed $fetchMode Override current fetch mode.
610
+ * @return array
611
+ */
612
+ public function fetchAll($sql, $bind = array(), $fetchMode = null)
613
+ {
614
+ if ($fetchMode === null) {
615
+ $fetchMode = $this->_fetchMode;
616
+ }
617
+ $stmt = $this->query($sql, $bind);
618
+ $result = $stmt->fetchAll($fetchMode);
619
+ return $result;
620
+ }
621
+
622
+ /**
623
+ * Fetches the first row of the SQL result.
624
+ * Uses the current fetchMode for the adapter.
625
+ *
626
+ * @param string|Zend_Db_Select $sql An SQL SELECT statement.
627
+ * @param mixed $bind Data to bind into SELECT placeholders.
628
+ * @param mixed $fetchMode Override current fetch mode.
629
+ * @return array
630
+ */
631
+ public function fetchRow($sql, $bind = array(), $fetchMode = null)
632
+ {
633
+ if ($fetchMode === null) {
634
+ $fetchMode = $this->_fetchMode;
635
+ }
636
+ $stmt = $this->query($sql, $bind);
637
+ $result = $stmt->fetch($fetchMode);
638
+ $stmt->closeCursor();
639
+ return $result;
640
+ }
641
+
642
+ /**
643
+ * Fetches all SQL result rows as an associative array.
644
+ *
645
+ * The first column is the key, the entire row array is the
646
+ * value. You should construct the query to be sure that
647
+ * the first column contains unique values, or else
648
+ * rows with duplicate values in the first column will
649
+ * overwrite previous data.
650
+ *
651
+ * @param string|Zend_Db_Select $sql An SQL SELECT statement.
652
+ * @param mixed $bind Data to bind into SELECT placeholders.
653
+ * @return string
654
+ */
655
+ public function fetchAssoc($sql, $bind = array())
656
+ {
657
+ $stmt = $this->query($sql, $bind);
658
+ $data = array();
659
+ while ($row = $stmt->fetch(Zend_Db::FETCH_ASSOC)) {
660
+ $tmp = array_values(array_slice($row, 0, 1));
661
+ $data[$tmp[0]] = $row;
662
+ }
663
+ return $data;
664
+ }
665
+
666
+ /**
667
+ * Fetches the first column of all SQL result rows as an array.
668
+ *
669
+ * The first column in each row is used as the array key.
670
+ *
671
+ * @param string|Zend_Db_Select $sql An SQL SELECT statement.
672
+ * @param mixed $bind Data to bind into SELECT placeholders.
673
+ * @return array
674
+ */
675
+ public function fetchCol($sql, $bind = array())
676
+ {
677
+ $stmt = $this->query($sql, $bind);
678
+ $result = $stmt->fetchAll(Zend_Db::FETCH_COLUMN, 0);
679
+ return $result;
680
+ }
681
+
682
+ /**
683
+ * Fetches all SQL result rows as an array of key-value pairs.
684
+ *
685
+ * The first column is the key, the second column is the
686
+ * value.
687
+ *
688
+ * @param string|Zend_Db_Select $sql An SQL SELECT statement.
689
+ * @param mixed $bind Data to bind into SELECT placeholders.
690
+ * @return string
691
+ */
692
+ public function fetchPairs($sql, $bind = array())
693
+ {
694
+ $stmt = $this->query($sql, $bind);
695
+ $data = array();
696
+ while ($row = $stmt->fetch(Zend_Db::FETCH_NUM)) {
697
+ $data[$row[0]] = $row[1];
698
+ }
699
+ return $data;
700
+ }
701
+
702
+ /**
703
+ * Fetches the first column of the first row of the SQL result.
704
+ *
705
+ * @param string|Zend_Db_Select $sql An SQL SELECT statement.
706
+ * @param mixed $bind Data to bind into SELECT placeholders.
707
+ * @return string
708
+ */
709
+ public function fetchOne($sql, $bind = array())
710
+ {
711
+ $stmt = $this->query($sql, $bind);
712
+ $result = $stmt->fetchColumn(0);
713
+ $stmt->closeCursor();
714
+ return $result;
715
+ }
716
+
717
+ /**
718
+ * Quote a raw string.
719
+ *
720
+ * @param string $value Raw string
721
+ * @return string Quoted string
722
+ */
723
+ protected function _quote($value)
724
+ {
725
+ if (is_int($value) || is_float($value)) {
726
+ return $value;
727
+ }
728
+ return "'" . addcslashes($value, "\000\n\r\\'\"\032") . "'";
729
+ }
730
+
731
+ /**
732
+ * Safely quotes a value for an SQL statement.
733
+ *
734
+ * If an array is passed as the value, the array values are quoted
735
+ * and then returned as a comma-separated string.
736
+ *
737
+ * @param mixed $value The value to quote.
738
+ * @param mixed $type OPTIONAL the SQL datatype name, or constant, or null.
739
+ * @return mixed An SQL-safe quoted value (or string of separated values).
740
+ */
741
+ public function quote($value, $type = null)
742
+ {
743
+ $this->_connect();
744
+
745
+ if ($value instanceof Zend_Db_Select) {
746
+ return '(' . $value->__toString() . ')';
747
+ }
748
+
749
+ if ($value instanceof Zend_Db_Expr) {
750
+ return $value->__toString();
751
+ }
752
+
753
+ if (is_array($value)) {
754
+ foreach ($value as &$val) {
755
+ $val = $this->quote($val, $type);
756
+ }
757
+ return implode(', ', $value);
758
+ }
759
+
760
+ if ($type !== null && array_key_exists($type = strtoupper($type), $this->_numericDataTypes)) {
761
+ switch ($this->_numericDataTypes[$type]) {
762
+ case Zend_Db::INT_TYPE: // 32-bit integer
763
+ return (string) intval($value);
764
+ break;
765
+ case Zend_Db::BIGINT_TYPE: // 64-bit integer
766
+ // ANSI SQL-style hex literals (e.g. x'[\dA-F]+')
767
+ // are not supported here, because these are string
768
+ // literals, not numeric literals.
769
+ if (preg_match('/^(
770
+ [+-]? # optional sign
771
+ (?:
772
+ 0[Xx][\da-fA-F]+ # ODBC-style hexadecimal
773
+ |\d+ # decimal or octal, or MySQL ZEROFILL decimal
774
+ (?:[eE][+-]?\d+)? # optional exponent on decimals or octals
775
+ )
776
+ )/x',
777
+ (string) $value, $matches)) {
778
+ return $matches[1];
779
+ }
780
+ break;
781
+ case Zend_Db::FLOAT_TYPE: // float or decimal
782
+ return (string) floatval($value);
783
+ break;
784
+ }
785
+ return '0';
786
+ }
787
+
788
+ return $this->_quote($value);
789
+ }
790
+
791
+ /**
792
+ * Quotes a value and places into a piece of text at a placeholder.
793
+ *
794
+ * The placeholder is a question-mark; all placeholders will be replaced
795
+ * with the quoted value. For example:
796
+ *
797
+ * <code>
798
+ * $text = "WHERE date < ?";
799
+ * $date = "2005-01-02";
800
+ * $safe = $sql->quoteInto($text, $date);
801
+ * // $safe = "WHERE date < '2005-01-02'"
802
+ * </code>
803
+ *
804
+ * @param string $text The text with a placeholder.
805
+ * @param mixed $value The value to quote.
806
+ * @param string $type OPTIONAL SQL datatype
807
+ * @param integer $count OPTIONAL count of placeholders to replace
808
+ * @return string An SQL-safe quoted value placed into the orignal text.
809
+ */
810
+ public function quoteInto($text, $value, $type = null, $count = null)
811
+ {
812
+ if ($count === null) {
813
+ return str_replace('?', $this->quote($value, $type), $text);
814
+ } else {
815
+ while ($count > 0) {
816
+ if (strpos($text, '?') != false) {
817
+ $text = substr_replace($text, $this->quote($value, $type), strpos($text, '?'), 1);
818
+ }
819
+ --$count;
820
+ }
821
+ return $text;
822
+ }
823
+