From 8ca6cc32b2c789a3149861159ad258f2cb9491e3 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 28 Apr 2024 14:39:39 +0200 Subject: Adding upstream version 2.11.4. Signed-off-by: Daniel Baumann --- library/vendor/Zend/Cache.php | 245 + library/vendor/Zend/Cache/Backend.php | 285 ++ library/vendor/Zend/Cache/Backend/Apc.php | 353 ++ library/vendor/Zend/Cache/Backend/BlackHole.php | 248 + .../Zend/Cache/Backend/ExtendedInterface.php | 125 + library/vendor/Zend/Cache/Backend/File.php | 1035 +++++ library/vendor/Zend/Cache/Backend/Interface.php | 99 + library/vendor/Zend/Cache/Backend/Libmemcached.php | 482 ++ library/vendor/Zend/Cache/Backend/Memcached.php | 507 ++ library/vendor/Zend/Cache/Backend/Sqlite.php | 676 +++ library/vendor/Zend/Cache/Backend/Static.php | 577 +++ library/vendor/Zend/Cache/Backend/Test.php | 414 ++ library/vendor/Zend/Cache/Backend/TwoLevels.php | 546 +++ library/vendor/Zend/Cache/Backend/WinCache.php | 347 ++ library/vendor/Zend/Cache/Backend/Xcache.php | 219 + library/vendor/Zend/Cache/Backend/ZendPlatform.php | 315 ++ library/vendor/Zend/Cache/Backend/ZendServer.php | 205 + .../vendor/Zend/Cache/Backend/ZendServer/Disk.php | 99 + .../vendor/Zend/Cache/Backend/ZendServer/ShMem.php | 99 + library/vendor/Zend/Cache/Core.php | 762 +++ library/vendor/Zend/Cache/Exception.php | 31 + library/vendor/Zend/Cache/Frontend/Capture.php | 87 + library/vendor/Zend/Cache/Frontend/Class.php | 274 ++ library/vendor/Zend/Cache/Frontend/File.php | 221 + library/vendor/Zend/Cache/Frontend/Function.php | 178 + library/vendor/Zend/Cache/Frontend/Output.php | 104 + library/vendor/Zend/Cache/Frontend/Page.php | 403 ++ library/vendor/Zend/Cache/Manager.php | 304 ++ library/vendor/Zend/Config.php | 481 ++ library/vendor/Zend/Config/Exception.php | 32 + library/vendor/Zend/Config/Ini.php | 301 ++ library/vendor/Zend/Config/Writer.php | 101 + library/vendor/Zend/Config/Writer/Array.php | 54 + library/vendor/Zend/Config/Writer/FileAbstract.php | 130 + library/vendor/Zend/Config/Writer/Ini.php | 191 + library/vendor/Zend/Controller/Action.php | 789 ++++ .../vendor/Zend/Controller/Action/Exception.php | 37 + .../Zend/Controller/Action/Helper/Abstract.php | 155 + .../Zend/Controller/Action/Helper/ActionStack.php | 133 + .../Zend/Controller/Action/Helper/AjaxContext.php | 79 + .../Action/Helper/AutoComplete/Abstract.php | 146 + .../vendor/Zend/Controller/Action/Helper/Cache.php | 286 ++ .../Controller/Action/Helper/ContextSwitch.php | 1377 ++++++ .../vendor/Zend/Controller/Action/Helper/Json.php | 130 + .../Zend/Controller/Action/Helper/Redirector.php | 531 +++ .../vendor/Zend/Controller/Action/Helper/Url.php | 116 + .../Zend/Controller/Action/Helper/ViewRenderer.php | 996 ++++ .../vendor/Zend/Controller/Action/HelperBroker.php | 373 ++ .../Action/HelperBroker/PriorityStack.php | 272 ++ .../vendor/Zend/Controller/Action/Interface.php | 69 + .../vendor/Zend/Controller/Dispatcher/Abstract.php | 435 ++ .../Zend/Controller/Dispatcher/Exception.php | 36 + .../Zend/Controller/Dispatcher/Interface.php | 204 + .../vendor/Zend/Controller/Dispatcher/Standard.php | 504 ++ library/vendor/Zend/Controller/Exception.php | 34 + library/vendor/Zend/Controller/Front.php | 977 ++++ library/vendor/Zend/Controller/Plugin/Abstract.php | 151 + .../vendor/Zend/Controller/Plugin/ActionStack.php | 277 ++ library/vendor/Zend/Controller/Plugin/Broker.php | 361 ++ .../vendor/Zend/Controller/Plugin/ErrorHandler.php | 299 ++ .../vendor/Zend/Controller/Plugin/PutHandler.php | 58 + .../vendor/Zend/Controller/Request/Abstract.php | 356 ++ .../vendor/Zend/Controller/Request/Apache404.php | 80 + .../vendor/Zend/Controller/Request/Exception.php | 36 + library/vendor/Zend/Controller/Request/Http.php | 1087 +++++ .../Zend/Controller/Request/HttpTestCase.php | 275 ++ library/vendor/Zend/Controller/Request/Simple.php | 54 + .../vendor/Zend/Controller/Response/Abstract.php | 790 ++++ library/vendor/Zend/Controller/Response/Cli.php | 67 + .../vendor/Zend/Controller/Response/Exception.php | 35 + library/vendor/Zend/Controller/Response/Http.php | 37 + .../Zend/Controller/Response/HttpTestCase.php | 129 + library/vendor/Zend/Controller/Router/Abstract.php | 176 + .../vendor/Zend/Controller/Router/Exception.php | 34 + .../vendor/Zend/Controller/Router/Interface.php | 123 + library/vendor/Zend/Controller/Router/Rewrite.php | 542 +++ library/vendor/Zend/Controller/Router/Route.php | 603 +++ .../Zend/Controller/Router/Route/Abstract.php | 119 + .../vendor/Zend/Controller/Router/Route/Chain.php | 228 + .../Zend/Controller/Router/Route/Hostname.php | 377 ++ .../Zend/Controller/Router/Route/Interface.php | 38 + .../vendor/Zend/Controller/Router/Route/Module.php | 322 ++ .../vendor/Zend/Controller/Router/Route/Regex.php | 316 ++ .../vendor/Zend/Controller/Router/Route/Static.php | 148 + library/vendor/Zend/Crypt.php | 167 + library/vendor/Zend/Crypt/DiffieHellman.php | 378 ++ .../vendor/Zend/Crypt/DiffieHellman/Exception.php | 35 + library/vendor/Zend/Crypt/Exception.php | 34 + library/vendor/Zend/Crypt/Hmac.php | 178 + library/vendor/Zend/Crypt/Hmac/Exception.php | 35 + library/vendor/Zend/Crypt/Math.php | 186 + library/vendor/Zend/Crypt/Math/BigInteger.php | 113 + .../vendor/Zend/Crypt/Math/BigInteger/Bcmath.php | 226 + .../Zend/Crypt/Math/BigInteger/Exception.php | 35 + library/vendor/Zend/Crypt/Math/BigInteger/Gmp.php | 219 + .../Zend/Crypt/Math/BigInteger/Interface.php | 51 + library/vendor/Zend/Crypt/Math/Exception.php | 35 + library/vendor/Zend/Crypt/Rsa.php | 334 ++ library/vendor/Zend/Crypt/Rsa/Exception.php | 35 + library/vendor/Zend/Crypt/Rsa/Key.php | 94 + library/vendor/Zend/Crypt/Rsa/Key/Private.php | 72 + library/vendor/Zend/Crypt/Rsa/Key/Public.php | 72 + library/vendor/Zend/Date.php | 4872 ++++++++++++++++++++ library/vendor/Zend/Date/Cities.php | 321 ++ library/vendor/Zend/Date/DateObject.php | 1094 +++++ library/vendor/Zend/Date/Exception.php | 48 + library/vendor/Zend/Db.php | 282 ++ library/vendor/Zend/Db/Adapter/Abstract.php | 1267 +++++ library/vendor/Zend/Db/Adapter/Db2.php | 827 ++++ library/vendor/Zend/Db/Adapter/Db2/Exception.php | 44 + library/vendor/Zend/Db/Adapter/Exception.php | 56 + library/vendor/Zend/Db/Adapter/Mysqli.php | 543 +++ .../vendor/Zend/Db/Adapter/Mysqli/Exception.php | 39 + library/vendor/Zend/Db/Adapter/Oracle.php | 631 +++ .../vendor/Zend/Db/Adapter/Oracle/Exception.php | 59 + library/vendor/Zend/Db/Adapter/Pdo/Abstract.php | 397 ++ library/vendor/Zend/Db/Adapter/Pdo/Ibm.php | 354 ++ library/vendor/Zend/Db/Adapter/Pdo/Ibm/Db2.php | 224 + library/vendor/Zend/Db/Adapter/Pdo/Ibm/Ids.php | 297 ++ library/vendor/Zend/Db/Adapter/Pdo/Mssql.php | 435 ++ library/vendor/Zend/Db/Adapter/Pdo/Mysql.php | 269 ++ library/vendor/Zend/Db/Adapter/Pdo/Oci.php | 375 ++ library/vendor/Zend/Db/Adapter/Pdo/Pgsql.php | 333 ++ library/vendor/Zend/Db/Adapter/Pdo/Sqlite.php | 305 ++ library/vendor/Zend/Db/Adapter/Sqlsrv.php | 662 +++ .../vendor/Zend/Db/Adapter/Sqlsrv/Exception.php | 62 + library/vendor/Zend/Db/Exception.php | 34 + library/vendor/Zend/Db/Expr.php | 77 + library/vendor/Zend/Db/Profiler.php | 469 ++ library/vendor/Zend/Db/Profiler/Exception.php | 39 + library/vendor/Zend/Db/Profiler/Query.php | 213 + library/vendor/Zend/Db/Select.php | 1368 ++++++ library/vendor/Zend/Db/Select/Exception.php | 38 + library/vendor/Zend/Db/Statement.php | 488 ++ library/vendor/Zend/Db/Statement/Db2.php | 354 ++ library/vendor/Zend/Db/Statement/Db2/Exception.php | 57 + library/vendor/Zend/Db/Statement/Exception.php | 55 + library/vendor/Zend/Db/Statement/Interface.php | 203 + library/vendor/Zend/Db/Statement/Mysqli.php | 356 ++ .../vendor/Zend/Db/Statement/Mysqli/Exception.php | 37 + library/vendor/Zend/Db/Statement/Oracle.php | 561 +++ .../vendor/Zend/Db/Statement/Oracle/Exception.php | 58 + library/vendor/Zend/Db/Statement/Pdo.php | 426 ++ library/vendor/Zend/Db/Statement/Pdo/Ibm.php | 92 + library/vendor/Zend/Db/Statement/Pdo/Oci.php | 90 + library/vendor/Zend/Db/Statement/Sqlsrv.php | 430 ++ .../vendor/Zend/Db/Statement/Sqlsrv/Exception.php | 60 + library/vendor/Zend/Db/Table.php | 77 + library/vendor/Zend/Db/Table/Abstract.php | 1599 +++++++ library/vendor/Zend/Db/Table/Definition.php | 131 + library/vendor/Zend/Db/Table/Exception.php | 37 + library/vendor/Zend/Db/Table/Row.php | 41 + library/vendor/Zend/Db/Table/Row/Abstract.php | 1160 +++++ library/vendor/Zend/Db/Table/Row/Exception.php | 37 + library/vendor/Zend/Db/Table/Rowset.php | 42 + library/vendor/Zend/Db/Table/Rowset/Abstract.php | 443 ++ library/vendor/Zend/Db/Table/Rowset/Exception.php | 36 + library/vendor/Zend/Db/Table/Select.php | 221 + library/vendor/Zend/Db/Table/Select/Exception.php | 38 + library/vendor/Zend/Exception.php | 96 + library/vendor/Zend/File/ClassFileLocator.php | 177 + library/vendor/Zend/File/PhpClassFile.php | 56 + library/vendor/Zend/File/Transfer.php | 122 + .../vendor/Zend/File/Transfer/Adapter/Abstract.php | 1548 +++++++ library/vendor/Zend/File/Transfer/Adapter/Http.php | 480 ++ library/vendor/Zend/File/Transfer/Exception.php | 54 + library/vendor/Zend/Filter.php | 236 + library/vendor/Zend/Filter/Alnum.php | 144 + library/vendor/Zend/Filter/Alpha.php | 144 + library/vendor/Zend/Filter/BaseName.php | 49 + library/vendor/Zend/Filter/Boolean.php | 369 ++ library/vendor/Zend/Filter/Callback.php | 149 + library/vendor/Zend/Filter/Compress.php | 192 + library/vendor/Zend/Filter/Compress/Bz2.php | 181 + .../Zend/Filter/Compress/CompressAbstract.php | 88 + .../Zend/Filter/Compress/CompressInterface.php | 54 + library/vendor/Zend/Filter/Compress/Gz.php | 220 + library/vendor/Zend/Filter/Compress/Lzf.php | 87 + library/vendor/Zend/Filter/Compress/Rar.php | 243 + library/vendor/Zend/Filter/Compress/Tar.php | 234 + library/vendor/Zend/Filter/Compress/Zip.php | 343 ++ library/vendor/Zend/Filter/Decompress.php | 48 + library/vendor/Zend/Filter/Decrypt.php | 48 + library/vendor/Zend/Filter/Digits.php | 81 + library/vendor/Zend/Filter/Dir.php | 49 + library/vendor/Zend/Filter/Encrypt.php | 134 + library/vendor/Zend/Filter/Encrypt/Interface.php | 47 + library/vendor/Zend/Filter/Encrypt/Mcrypt.php | 352 ++ library/vendor/Zend/Filter/Encrypt/Openssl.php | 480 ++ library/vendor/Zend/Filter/Exception.php | 36 + library/vendor/Zend/Filter/File/Decrypt.php | 101 + library/vendor/Zend/Filter/File/Encrypt.php | 101 + library/vendor/Zend/Filter/File/LowerCase.php | 79 + library/vendor/Zend/Filter/File/Rename.php | 304 ++ library/vendor/Zend/Filter/File/UpperCase.php | 79 + library/vendor/Zend/Filter/HtmlEntities.php | 213 + library/vendor/Zend/Filter/Inflector.php | 523 +++ library/vendor/Zend/Filter/Input.php | 1196 +++++ library/vendor/Zend/Filter/Int.php | 49 + library/vendor/Zend/Filter/Interface.php | 40 + .../vendor/Zend/Filter/LocalizedToNormalized.php | 110 + .../vendor/Zend/Filter/NormalizedToLocalized.php | 108 + library/vendor/Zend/Filter/Null.php | 181 + library/vendor/Zend/Filter/PregReplace.php | 172 + library/vendor/Zend/Filter/RealPath.php | 133 + library/vendor/Zend/Filter/StringToLower.php | 118 + library/vendor/Zend/Filter/StringToUpper.php | 118 + library/vendor/Zend/Filter/StringTrim.php | 123 + library/vendor/Zend/Filter/StripNewlines.php | 47 + library/vendor/Zend/Filter/StripTags.php | 351 ++ .../vendor/Zend/Filter/Word/CamelCaseToDash.php | 43 + .../Zend/Filter/Word/CamelCaseToSeparator.php | 48 + .../Zend/Filter/Word/CamelCaseToUnderscore.php | 43 + .../vendor/Zend/Filter/Word/DashToCamelCase.php | 43 + .../vendor/Zend/Filter/Word/DashToSeparator.php | 41 + .../vendor/Zend/Filter/Word/DashToUnderscore.php | 44 + .../vendor/Zend/Filter/Word/Separator/Abstract.php | 74 + .../Zend/Filter/Word/SeparatorToCamelCase.php | 63 + .../vendor/Zend/Filter/Word/SeparatorToDash.php | 45 + .../Zend/Filter/Word/SeparatorToSeparator.php | 127 + .../Zend/Filter/Word/UnderscoreToCamelCase.php | 43 + .../vendor/Zend/Filter/Word/UnderscoreToDash.php | 44 + .../Zend/Filter/Word/UnderscoreToSeparator.php | 44 + library/vendor/Zend/Form.php | 3472 ++++++++++++++ library/vendor/Zend/Form/Decorator/Abstract.php | 251 + library/vendor/Zend/Form/Decorator/Callback.php | 126 + library/vendor/Zend/Form/Decorator/Captcha.php | 71 + library/vendor/Zend/Form/Decorator/Description.php | 197 + library/vendor/Zend/Form/Decorator/DtDdWrapper.php | 69 + library/vendor/Zend/Form/Decorator/Errors.php | 76 + library/vendor/Zend/Form/Decorator/Exception.php | 36 + library/vendor/Zend/Form/Decorator/Fieldset.php | 156 + library/vendor/Zend/Form/Decorator/File.php | 140 + library/vendor/Zend/Form/Decorator/Form.php | 133 + .../vendor/Zend/Form/Decorator/FormElements.php | 140 + library/vendor/Zend/Form/Decorator/FormErrors.php | 514 +++ library/vendor/Zend/Form/Decorator/HtmlTag.php | 253 + library/vendor/Zend/Form/Decorator/Image.php | 152 + library/vendor/Zend/Form/Decorator/Interface.php | 123 + library/vendor/Zend/Form/Decorator/Label.php | 461 ++ .../Zend/Form/Decorator/Marker/File/Interface.php | 33 + .../vendor/Zend/Form/Decorator/PrepareElements.php | 89 + library/vendor/Zend/Form/Decorator/Tooltip.php | 57 + library/vendor/Zend/Form/Decorator/ViewHelper.php | 266 ++ library/vendor/Zend/Form/Decorator/ViewScript.php | 190 + library/vendor/Zend/Form/DisplayGroup.php | 1172 +++++ library/vendor/Zend/Form/Element.php | 2280 +++++++++ library/vendor/Zend/Form/Element/Button.php | 55 + library/vendor/Zend/Form/Element/Checkbox.php | 202 + library/vendor/Zend/Form/Element/Exception.php | 36 + library/vendor/Zend/Form/Element/File.php | 910 ++++ library/vendor/Zend/Form/Element/Hidden.php | 41 + library/vendor/Zend/Form/Element/Image.php | 131 + library/vendor/Zend/Form/Element/Multi.php | 316 ++ library/vendor/Zend/Form/Element/MultiCheckbox.php | 72 + library/vendor/Zend/Form/Element/Multiselect.php | 53 + library/vendor/Zend/Form/Element/Note.php | 63 + library/vendor/Zend/Form/Element/Password.php | 87 + library/vendor/Zend/Form/Element/Radio.php | 65 + library/vendor/Zend/Form/Element/Reset.php | 41 + library/vendor/Zend/Form/Element/Select.php | 47 + library/vendor/Zend/Form/Element/Submit.php | 126 + library/vendor/Zend/Form/Element/Text.php | 41 + library/vendor/Zend/Form/Element/Textarea.php | 41 + library/vendor/Zend/Form/Element/Xhtml.php | 36 + library/vendor/Zend/Form/Exception.php | 34 + library/vendor/Zend/Form/SubForm.php | 60 + library/vendor/Zend/Json.php | 433 ++ library/vendor/Zend/Json/Decoder.php | 570 +++ library/vendor/Zend/Json/Encoder.php | 576 +++ library/vendor/Zend/Json/Exception.php | 36 + library/vendor/Zend/Json/Expr.php | 80 + library/vendor/Zend/LICENSE.txt | 27 + library/vendor/Zend/Layout.php | 788 ++++ .../Layout/Controller/Action/Helper/Layout.php | 181 + .../Zend/Layout/Controller/Plugin/Layout.php | 155 + library/vendor/Zend/Layout/Exception.php | 34 + library/vendor/Zend/Loader.php | 338 ++ library/vendor/Zend/Loader/Autoloader.php | 589 +++ .../vendor/Zend/Loader/Autoloader/Interface.php | 43 + library/vendor/Zend/Loader/Exception.php | 34 + .../Loader/Exception/InvalidArgumentException.php | 33 + library/vendor/Zend/Loader/PluginLoader.php | 497 ++ .../vendor/Zend/Loader/PluginLoader/Exception.php | 38 + .../vendor/Zend/Loader/PluginLoader/Interface.php | 75 + library/vendor/Zend/Locale.php | 1996 ++++++++ library/vendor/Zend/Locale/Data.php | 1609 +++++++ library/vendor/Zend/Locale/Data/Translation.php | 285 ++ library/vendor/Zend/Locale/Exception.php | 36 + library/vendor/Zend/Locale/Format.php | 1321 ++++++ library/vendor/Zend/Locale/Math.php | 354 ++ library/vendor/Zend/Locale/Math/Exception.php | 52 + library/vendor/Zend/Locale/Math/PhpMath.php | 239 + library/vendor/Zend/Log.php | 645 +++ library/vendor/Zend/Log/Exception.php | 32 + library/vendor/Zend/Log/FactoryInterface.php | 38 + library/vendor/Zend/Log/Filter/Abstract.php | 57 + library/vendor/Zend/Log/Filter/Interface.php | 40 + library/vendor/Zend/Log/Filter/Message.php | 83 + library/vendor/Zend/Log/Filter/Priority.php | 99 + library/vendor/Zend/Log/Filter/Suppress.php | 76 + library/vendor/Zend/Log/Formatter/Abstract.php | 38 + library/vendor/Zend/Log/Formatter/Interface.php | 41 + library/vendor/Zend/Log/Formatter/Simple.php | 106 + library/vendor/Zend/Log/Formatter/Xml.php | 164 + library/vendor/Zend/Log/Writer/Abstract.php | 138 + library/vendor/Zend/Log/Writer/Db.php | 144 + library/vendor/Zend/Log/Writer/Mail.php | 426 ++ library/vendor/Zend/Log/Writer/Mock.php | 80 + library/vendor/Zend/Log/Writer/Null.php | 55 + library/vendor/Zend/Log/Writer/Stream.php | 132 + library/vendor/Zend/Log/Writer/Syslog.php | 263 ++ library/vendor/Zend/Log/Writer/ZendMonitor.php | 130 + library/vendor/Zend/Mail.php | 1265 +++++ library/vendor/Zend/Mail/Exception.php | 36 + library/vendor/Zend/Mail/Header/HeaderName.php | 91 + library/vendor/Zend/Mail/Header/HeaderValue.php | 135 + library/vendor/Zend/Mail/Message.php | 110 + library/vendor/Zend/Mail/Message/File.php | 94 + library/vendor/Zend/Mail/Message/Interface.php | 55 + library/vendor/Zend/Mail/Part.php | 590 +++ library/vendor/Zend/Mail/Part/File.php | 191 + library/vendor/Zend/Mail/Part/Interface.php | 136 + library/vendor/Zend/Mail/Protocol/Abstract.php | 436 ++ library/vendor/Zend/Mail/Protocol/Exception.php | 38 + library/vendor/Zend/Mail/Protocol/Imap.php | 830 ++++ library/vendor/Zend/Mail/Protocol/Pop3.php | 466 ++ library/vendor/Zend/Mail/Protocol/Smtp.php | 433 ++ .../Zend/Mail/Protocol/Smtp/Auth/Crammd5.php | 107 + .../vendor/Zend/Mail/Protocol/Smtp/Auth/Login.php | 97 + .../vendor/Zend/Mail/Protocol/Smtp/Auth/Plain.php | 95 + library/vendor/Zend/Mail/Storage.php | 40 + library/vendor/Zend/Mail/Storage/Abstract.php | 364 ++ library/vendor/Zend/Mail/Storage/Exception.php | 38 + library/vendor/Zend/Mail/Storage/Folder.php | 235 + .../vendor/Zend/Mail/Storage/Folder/Interface.php | 60 + .../vendor/Zend/Mail/Storage/Folder/Maildir.php | 255 + library/vendor/Zend/Mail/Storage/Folder/Mbox.php | 255 + library/vendor/Zend/Mail/Storage/Imap.php | 620 +++ library/vendor/Zend/Mail/Storage/Maildir.php | 462 ++ library/vendor/Zend/Mail/Storage/Mbox.php | 437 ++ library/vendor/Zend/Mail/Storage/Pop3.php | 321 ++ .../Zend/Mail/Storage/Writable/Interface.php | 108 + .../vendor/Zend/Mail/Storage/Writable/Maildir.php | 1014 ++++ library/vendor/Zend/Mail/Transport/Abstract.php | 345 ++ library/vendor/Zend/Mail/Transport/Exception.php | 38 + library/vendor/Zend/Mail/Transport/File.php | 131 + library/vendor/Zend/Mail/Transport/Sendmail.php | 214 + library/vendor/Zend/Mail/Transport/Smtp.php | 238 + library/vendor/Zend/Mime.php | 670 +++ library/vendor/Zend/Mime/Decode.php | 275 ++ library/vendor/Zend/Mime/Exception.php | 35 + library/vendor/Zend/Mime/Message.php | 302 ++ library/vendor/Zend/Mime/Part.php | 329 ++ library/vendor/Zend/Paginator.php | 1164 +++++ library/vendor/Zend/Paginator/Adapter/Array.php | 80 + library/vendor/Zend/Paginator/Adapter/DbSelect.php | 285 ++ .../Zend/Paginator/Adapter/DbTableSelect.php | 47 + .../vendor/Zend/Paginator/Adapter/Interface.php | 40 + library/vendor/Zend/Paginator/Adapter/Iterator.php | 99 + library/vendor/Zend/Paginator/Adapter/Null.php | 79 + library/vendor/Zend/Paginator/AdapterAggregate.php | 40 + library/vendor/Zend/Paginator/Exception.php | 34 + .../vendor/Zend/Paginator/ScrollingStyle/All.php | 49 + .../Zend/Paginator/ScrollingStyle/Elastic.php | 62 + .../Zend/Paginator/ScrollingStyle/Interface.php | 38 + .../Zend/Paginator/ScrollingStyle/Jumping.php | 62 + .../Zend/Paginator/ScrollingStyle/Sliding.php | 77 + .../Zend/Paginator/SerializableLimitIterator.php | 159 + library/vendor/Zend/ProgressBar.php | 207 + library/vendor/Zend/ProgressBar/Adapter.php | 113 + .../vendor/Zend/ProgressBar/Adapter/Exception.php | 37 + library/vendor/Zend/ProgressBar/Adapter/JsPull.php | 115 + library/vendor/Zend/ProgressBar/Adapter/JsPush.php | 146 + library/vendor/Zend/ProgressBar/Exception.php | 37 + library/vendor/Zend/README.md | 8 + library/vendor/Zend/Registry.php | 192 + library/vendor/Zend/Server/Abstract.php | 235 + library/vendor/Zend/Server/Cache.php | 147 + library/vendor/Zend/Server/Definition.php | 263 ++ library/vendor/Zend/Server/Exception.php | 34 + library/vendor/Zend/Server/Interface.php | 118 + library/vendor/Zend/Server/Method/Callback.php | 204 + library/vendor/Zend/Server/Method/Definition.php | 288 ++ library/vendor/Zend/Server/Method/Parameter.php | 214 + library/vendor/Zend/Server/Method/Prototype.php | 207 + library/vendor/Zend/Server/Reflection.php | 105 + library/vendor/Zend/Server/Reflection/Class.php | 195 + .../vendor/Zend/Server/Reflection/Exception.php | 37 + library/vendor/Zend/Server/Reflection/Function.php | 38 + .../Zend/Server/Reflection/Function/Abstract.php | 506 ++ library/vendor/Zend/Server/Reflection/Method.php | 109 + library/vendor/Zend/Server/Reflection/Node.php | 201 + .../vendor/Zend/Server/Reflection/Parameter.php | 158 + .../vendor/Zend/Server/Reflection/Prototype.php | 99 + .../vendor/Zend/Server/Reflection/ReturnValue.php | 108 + library/vendor/Zend/Session.php | 895 ++++ library/vendor/Zend/Session/Abstract.php | 182 + library/vendor/Zend/Session/Exception.php | 73 + library/vendor/Zend/Session/Namespace.php | 511 ++ .../vendor/Zend/Session/SaveHandler/DbTable.php | 579 +++ .../vendor/Zend/Session/SaveHandler/Exception.php | 36 + .../vendor/Zend/Session/SaveHandler/Interface.php | 81 + library/vendor/Zend/Session/Validator/Abstract.php | 70 + .../vendor/Zend/Session/Validator/Exception.php | 42 + .../Zend/Session/Validator/HttpUserAgent.php | 65 + .../vendor/Zend/Session/Validator/Interface.php | 52 + library/vendor/Zend/Soap/AutoDiscover.php | 597 +++ .../vendor/Zend/Soap/AutoDiscover/Exception.php | 33 + library/vendor/Zend/Soap/Client.php | 1223 +++++ library/vendor/Zend/Soap/Client/Common.php | 76 + library/vendor/Zend/Soap/Client/DotNet.php | 93 + library/vendor/Zend/Soap/Client/Exception.php | 34 + library/vendor/Zend/Soap/Client/Local.php | 97 + library/vendor/Zend/Soap/Server.php | 999 ++++ library/vendor/Zend/Soap/Server/Exception.php | 36 + library/vendor/Zend/Soap/Server/Proxy.php | 75 + library/vendor/Zend/Soap/Wsdl.php | 661 +++ library/vendor/Zend/Soap/Wsdl/Exception.php | 36 + .../vendor/Zend/Soap/Wsdl/Strategy/Abstract.php | 65 + library/vendor/Zend/Soap/Wsdl/Strategy/AnyType.php | 58 + .../Zend/Soap/Wsdl/Strategy/ArrayOfTypeComplex.php | 142 + .../Soap/Wsdl/Strategy/ArrayOfTypeSequence.php | 154 + .../vendor/Zend/Soap/Wsdl/Strategy/Composite.php | 183 + .../Zend/Soap/Wsdl/Strategy/DefaultComplexType.php | 89 + .../vendor/Zend/Soap/Wsdl/Strategy/Interface.php | 48 + library/vendor/Zend/TimeSync.php | 296 ++ library/vendor/Zend/TimeSync/Exception.php | 63 + library/vendor/Zend/TimeSync/Ntp.php | 430 ++ library/vendor/Zend/TimeSync/Protocol.php | 148 + library/vendor/Zend/TimeSync/Sntp.php | 118 + library/vendor/Zend/Translate.php | 220 + library/vendor/Zend/Translate/Adapter.php | 988 ++++ library/vendor/Zend/Translate/Exception.php | 36 + library/vendor/Zend/Translate/Plural.php | 223 + library/vendor/Zend/Uri.php | 201 + library/vendor/Zend/Uri/Exception.php | 36 + library/vendor/Zend/Uri/Http.php | 745 +++ library/vendor/Zend/VERSION | 1 + library/vendor/Zend/Validate.php | 283 ++ library/vendor/Zend/Validate/Abstract.php | 477 ++ library/vendor/Zend/Validate/Alnum.php | 147 + library/vendor/Zend/Validate/Alpha.php | 147 + library/vendor/Zend/Validate/Barcode.php | 222 + .../Zend/Validate/Barcode/AdapterAbstract.php | 314 ++ .../Zend/Validate/Barcode/AdapterInterface.php | 68 + library/vendor/Zend/Validate/Barcode/Code25.php | 61 + .../Zend/Validate/Barcode/Code25interleaved.php | 61 + library/vendor/Zend/Validate/Barcode/Code39.php | 97 + library/vendor/Zend/Validate/Barcode/Code39ext.php | 55 + library/vendor/Zend/Validate/Barcode/Code93.php | 117 + library/vendor/Zend/Validate/Barcode/Code93ext.php | 55 + library/vendor/Zend/Validate/Barcode/Ean12.php | 51 + library/vendor/Zend/Validate/Barcode/Ean13.php | 51 + library/vendor/Zend/Validate/Barcode/Ean14.php | 51 + library/vendor/Zend/Validate/Barcode/Ean18.php | 51 + library/vendor/Zend/Validate/Barcode/Ean2.php | 55 + library/vendor/Zend/Validate/Barcode/Ean5.php | 55 + library/vendor/Zend/Validate/Barcode/Ean8.php | 68 + library/vendor/Zend/Validate/Barcode/Gtin12.php | 51 + library/vendor/Zend/Validate/Barcode/Gtin13.php | 51 + library/vendor/Zend/Validate/Barcode/Gtin14.php | 51 + library/vendor/Zend/Validate/Barcode/Identcode.php | 51 + .../Zend/Validate/Barcode/Intelligentmail.php | 55 + library/vendor/Zend/Validate/Barcode/Issn.php | 118 + library/vendor/Zend/Validate/Barcode/Itf14.php | 51 + library/vendor/Zend/Validate/Barcode/Leitcode.php | 51 + library/vendor/Zend/Validate/Barcode/Planet.php | 51 + library/vendor/Zend/Validate/Barcode/Postnet.php | 51 + library/vendor/Zend/Validate/Barcode/Royalmail.php | 120 + library/vendor/Zend/Validate/Barcode/Sscc.php | 51 + library/vendor/Zend/Validate/Barcode/Upca.php | 51 + library/vendor/Zend/Validate/Barcode/Upce.php | 68 + library/vendor/Zend/Validate/Between.php | 222 + library/vendor/Zend/Validate/Callback.php | 170 + library/vendor/Zend/Validate/Ccnum.php | 110 + library/vendor/Zend/Validate/CreditCard.php | 316 ++ library/vendor/Zend/Validate/Date.php | 253 + library/vendor/Zend/Validate/Db/Abstract.php | 350 ++ library/vendor/Zend/Validate/Db/NoRecordExists.php | 50 + library/vendor/Zend/Validate/Db/RecordExists.php | 50 + library/vendor/Zend/Validate/Digits.php | 89 + library/vendor/Zend/Validate/EmailAddress.php | 571 +++ library/vendor/Zend/Validate/Exception.php | 33 + library/vendor/Zend/Validate/File/Count.php | 279 ++ library/vendor/Zend/Validate/File/Crc32.php | 177 + .../vendor/Zend/Validate/File/ExcludeExtension.php | 92 + .../vendor/Zend/Validate/File/ExcludeMimeType.php | 99 + library/vendor/Zend/Validate/File/Exists.php | 201 + library/vendor/Zend/Validate/File/Extension.php | 235 + library/vendor/Zend/Validate/File/FilesSize.php | 161 + library/vendor/Zend/Validate/File/Hash.php | 190 + library/vendor/Zend/Validate/File/ImageSize.php | 357 ++ library/vendor/Zend/Validate/File/IsCompressed.php | 148 + library/vendor/Zend/Validate/File/IsImage.php | 171 + library/vendor/Zend/Validate/File/Md5.php | 179 + library/vendor/Zend/Validate/File/MimeType.php | 468 ++ library/vendor/Zend/Validate/File/NotExists.php | 83 + library/vendor/Zend/Validate/File/Sha1.php | 179 + library/vendor/Zend/Validate/File/Size.php | 398 ++ library/vendor/Zend/Validate/File/Upload.php | 249 + library/vendor/Zend/Validate/File/WordCount.php | 99 + library/vendor/Zend/Validate/Float.php | 131 + library/vendor/Zend/Validate/GreaterThan.php | 122 + library/vendor/Zend/Validate/Hex.php | 71 + library/vendor/Zend/Validate/Hostname.php | 1987 ++++++++ library/vendor/Zend/Validate/Hostname/Biz.php | 2917 ++++++++++++ library/vendor/Zend/Validate/Hostname/Cn.php | 2199 +++++++++ library/vendor/Zend/Validate/Hostname/Com.php | 196 + library/vendor/Zend/Validate/Hostname/Jp.php | 739 +++ library/vendor/Zend/Validate/Iban.php | 246 + library/vendor/Zend/Validate/Identical.php | 163 + library/vendor/Zend/Validate/InArray.php | 202 + library/vendor/Zend/Validate/Int.php | 145 + library/vendor/Zend/Validate/Interface.php | 54 + library/vendor/Zend/Validate/Ip.php | 190 + library/vendor/Zend/Validate/Isbn.php | 274 ++ library/vendor/Zend/Validate/LessThan.php | 120 + library/vendor/Zend/Validate/NotEmpty.php | 277 ++ library/vendor/Zend/Validate/PostCode.php | 202 + library/vendor/Zend/Validate/Regex.php | 143 + .../vendor/Zend/Validate/Sitemap/Changefreq.php | 94 + library/vendor/Zend/Validate/Sitemap/Lastmod.php | 87 + library/vendor/Zend/Validate/Sitemap/Loc.php | 85 + library/vendor/Zend/Validate/Sitemap/Priority.php | 81 + library/vendor/Zend/Validate/StringLength.php | 263 ++ library/vendor/Zend/View.php | 158 + library/vendor/Zend/View/Abstract.php | 1186 +++++ library/vendor/Zend/View/Exception.php | 50 + library/vendor/Zend/View/Helper/Abstract.php | 63 + library/vendor/Zend/View/Helper/Action.php | 161 + library/vendor/Zend/View/Helper/BaseUrl.php | 114 + library/vendor/Zend/View/Helper/Cycle.php | 225 + library/vendor/Zend/View/Helper/DeclareVars.php | 94 + library/vendor/Zend/View/Helper/Doctype.php | 239 + library/vendor/Zend/View/Helper/Fieldset.php | 78 + library/vendor/Zend/View/Helper/Form.php | 85 + library/vendor/Zend/View/Helper/FormButton.php | 104 + library/vendor/Zend/View/Helper/FormCheckbox.php | 163 + library/vendor/Zend/View/Helper/FormElement.php | 202 + library/vendor/Zend/View/Helper/FormErrors.php | 166 + library/vendor/Zend/View/Helper/FormFile.php | 74 + library/vendor/Zend/View/Helper/FormHidden.php | 65 + library/vendor/Zend/View/Helper/FormImage.php | 94 + library/vendor/Zend/View/Helper/FormLabel.php | 71 + .../vendor/Zend/View/Helper/FormMultiCheckbox.php | 73 + library/vendor/Zend/View/Helper/FormNote.php | 60 + library/vendor/Zend/View/Helper/FormPassword.php | 88 + library/vendor/Zend/View/Helper/FormRadio.php | 185 + library/vendor/Zend/View/Helper/FormReset.php | 81 + library/vendor/Zend/View/Helper/FormSelect.php | 199 + library/vendor/Zend/View/Helper/FormSubmit.php | 80 + library/vendor/Zend/View/Helper/FormText.php | 77 + library/vendor/Zend/View/Helper/FormTextarea.php | 103 + library/vendor/Zend/View/Helper/Gravatar.php | 361 ++ library/vendor/Zend/View/Helper/HeadLink.php | 471 ++ library/vendor/Zend/View/Helper/HeadMeta.php | 440 ++ library/vendor/Zend/View/Helper/HeadScript.php | 512 ++ library/vendor/Zend/View/Helper/HeadStyle.php | 426 ++ library/vendor/Zend/View/Helper/HeadTitle.php | 218 + library/vendor/Zend/View/Helper/HtmlElement.php | 165 + library/vendor/Zend/View/Helper/HtmlFlash.php | 59 + library/vendor/Zend/View/Helper/HtmlList.php | 88 + library/vendor/Zend/View/Helper/HtmlObject.php | 79 + library/vendor/Zend/View/Helper/HtmlPage.php | 74 + library/vendor/Zend/View/Helper/HtmlQuicktime.php | 81 + library/vendor/Zend/View/Helper/InlineScript.php | 60 + library/vendor/Zend/View/Helper/Interface.php | 46 + library/vendor/Zend/View/Helper/Json.php | 86 + library/vendor/Zend/View/Helper/Layout.php | 79 + .../vendor/Zend/View/Helper/PaginationControl.php | 142 + library/vendor/Zend/View/Helper/Partial.php | 150 + .../vendor/Zend/View/Helper/Partial/Exception.php | 38 + library/vendor/Zend/View/Helper/PartialLoop.php | 98 + library/vendor/Zend/View/Helper/Placeholder.php | 85 + .../Zend/View/Helper/Placeholder/Container.php | 35 + .../View/Helper/Placeholder/Container/Abstract.php | 384 ++ .../Helper/Placeholder/Container/Exception.php | 38 + .../Helper/Placeholder/Container/Standalone.php | 322 ++ .../Zend/View/Helper/Placeholder/Registry.php | 183 + .../View/Helper/Placeholder/Registry/Exception.php | 38 + .../Zend/View/Helper/RenderToPlaceholder.php | 52 + library/vendor/Zend/View/Helper/ServerUrl.php | 148 + library/vendor/Zend/View/Helper/Translate.php | 174 + library/vendor/Zend/View/Helper/Url.php | 50 + library/vendor/Zend/View/Interface.php | 137 + library/vendor/Zend/View/Stream.php | 183 + library/vendor/Zend/Xml/Exception.php | 35 + library/vendor/Zend/Xml/Security.php | 486 ++ 589 files changed, 148200 insertions(+) create mode 100644 library/vendor/Zend/Cache.php create mode 100644 library/vendor/Zend/Cache/Backend.php create mode 100644 library/vendor/Zend/Cache/Backend/Apc.php create mode 100644 library/vendor/Zend/Cache/Backend/BlackHole.php create mode 100644 library/vendor/Zend/Cache/Backend/ExtendedInterface.php create mode 100644 library/vendor/Zend/Cache/Backend/File.php create mode 100644 library/vendor/Zend/Cache/Backend/Interface.php create mode 100644 library/vendor/Zend/Cache/Backend/Libmemcached.php create mode 100644 library/vendor/Zend/Cache/Backend/Memcached.php create mode 100644 library/vendor/Zend/Cache/Backend/Sqlite.php create mode 100644 library/vendor/Zend/Cache/Backend/Static.php create mode 100644 library/vendor/Zend/Cache/Backend/Test.php create mode 100644 library/vendor/Zend/Cache/Backend/TwoLevels.php create mode 100644 library/vendor/Zend/Cache/Backend/WinCache.php create mode 100644 library/vendor/Zend/Cache/Backend/Xcache.php create mode 100644 library/vendor/Zend/Cache/Backend/ZendPlatform.php create mode 100644 library/vendor/Zend/Cache/Backend/ZendServer.php create mode 100644 library/vendor/Zend/Cache/Backend/ZendServer/Disk.php create mode 100644 library/vendor/Zend/Cache/Backend/ZendServer/ShMem.php create mode 100644 library/vendor/Zend/Cache/Core.php create mode 100644 library/vendor/Zend/Cache/Exception.php create mode 100644 library/vendor/Zend/Cache/Frontend/Capture.php create mode 100644 library/vendor/Zend/Cache/Frontend/Class.php create mode 100644 library/vendor/Zend/Cache/Frontend/File.php create mode 100644 library/vendor/Zend/Cache/Frontend/Function.php create mode 100644 library/vendor/Zend/Cache/Frontend/Output.php create mode 100644 library/vendor/Zend/Cache/Frontend/Page.php create mode 100644 library/vendor/Zend/Cache/Manager.php create mode 100644 library/vendor/Zend/Config.php create mode 100644 library/vendor/Zend/Config/Exception.php create mode 100644 library/vendor/Zend/Config/Ini.php create mode 100644 library/vendor/Zend/Config/Writer.php create mode 100644 library/vendor/Zend/Config/Writer/Array.php create mode 100644 library/vendor/Zend/Config/Writer/FileAbstract.php create mode 100644 library/vendor/Zend/Config/Writer/Ini.php create mode 100644 library/vendor/Zend/Controller/Action.php create mode 100644 library/vendor/Zend/Controller/Action/Exception.php create mode 100644 library/vendor/Zend/Controller/Action/Helper/Abstract.php create mode 100644 library/vendor/Zend/Controller/Action/Helper/ActionStack.php create mode 100644 library/vendor/Zend/Controller/Action/Helper/AjaxContext.php create mode 100644 library/vendor/Zend/Controller/Action/Helper/AutoComplete/Abstract.php create mode 100644 library/vendor/Zend/Controller/Action/Helper/Cache.php create mode 100644 library/vendor/Zend/Controller/Action/Helper/ContextSwitch.php create mode 100644 library/vendor/Zend/Controller/Action/Helper/Json.php create mode 100644 library/vendor/Zend/Controller/Action/Helper/Redirector.php create mode 100644 library/vendor/Zend/Controller/Action/Helper/Url.php create mode 100644 library/vendor/Zend/Controller/Action/Helper/ViewRenderer.php create mode 100644 library/vendor/Zend/Controller/Action/HelperBroker.php create mode 100644 library/vendor/Zend/Controller/Action/HelperBroker/PriorityStack.php create mode 100644 library/vendor/Zend/Controller/Action/Interface.php create mode 100644 library/vendor/Zend/Controller/Dispatcher/Abstract.php create mode 100644 library/vendor/Zend/Controller/Dispatcher/Exception.php create mode 100644 library/vendor/Zend/Controller/Dispatcher/Interface.php create mode 100644 library/vendor/Zend/Controller/Dispatcher/Standard.php create mode 100644 library/vendor/Zend/Controller/Exception.php create mode 100644 library/vendor/Zend/Controller/Front.php create mode 100644 library/vendor/Zend/Controller/Plugin/Abstract.php create mode 100644 library/vendor/Zend/Controller/Plugin/ActionStack.php create mode 100644 library/vendor/Zend/Controller/Plugin/Broker.php create mode 100644 library/vendor/Zend/Controller/Plugin/ErrorHandler.php create mode 100644 library/vendor/Zend/Controller/Plugin/PutHandler.php create mode 100644 library/vendor/Zend/Controller/Request/Abstract.php create mode 100644 library/vendor/Zend/Controller/Request/Apache404.php create mode 100644 library/vendor/Zend/Controller/Request/Exception.php create mode 100644 library/vendor/Zend/Controller/Request/Http.php create mode 100644 library/vendor/Zend/Controller/Request/HttpTestCase.php create mode 100644 library/vendor/Zend/Controller/Request/Simple.php create mode 100644 library/vendor/Zend/Controller/Response/Abstract.php create mode 100644 library/vendor/Zend/Controller/Response/Cli.php create mode 100644 library/vendor/Zend/Controller/Response/Exception.php create mode 100644 library/vendor/Zend/Controller/Response/Http.php create mode 100644 library/vendor/Zend/Controller/Response/HttpTestCase.php create mode 100644 library/vendor/Zend/Controller/Router/Abstract.php create mode 100644 library/vendor/Zend/Controller/Router/Exception.php create mode 100644 library/vendor/Zend/Controller/Router/Interface.php create mode 100644 library/vendor/Zend/Controller/Router/Rewrite.php create mode 100644 library/vendor/Zend/Controller/Router/Route.php create mode 100644 library/vendor/Zend/Controller/Router/Route/Abstract.php create mode 100644 library/vendor/Zend/Controller/Router/Route/Chain.php create mode 100644 library/vendor/Zend/Controller/Router/Route/Hostname.php create mode 100644 library/vendor/Zend/Controller/Router/Route/Interface.php create mode 100644 library/vendor/Zend/Controller/Router/Route/Module.php create mode 100644 library/vendor/Zend/Controller/Router/Route/Regex.php create mode 100644 library/vendor/Zend/Controller/Router/Route/Static.php create mode 100644 library/vendor/Zend/Crypt.php create mode 100644 library/vendor/Zend/Crypt/DiffieHellman.php create mode 100644 library/vendor/Zend/Crypt/DiffieHellman/Exception.php create mode 100644 library/vendor/Zend/Crypt/Exception.php create mode 100644 library/vendor/Zend/Crypt/Hmac.php create mode 100644 library/vendor/Zend/Crypt/Hmac/Exception.php create mode 100644 library/vendor/Zend/Crypt/Math.php create mode 100644 library/vendor/Zend/Crypt/Math/BigInteger.php create mode 100644 library/vendor/Zend/Crypt/Math/BigInteger/Bcmath.php create mode 100644 library/vendor/Zend/Crypt/Math/BigInteger/Exception.php create mode 100644 library/vendor/Zend/Crypt/Math/BigInteger/Gmp.php create mode 100644 library/vendor/Zend/Crypt/Math/BigInteger/Interface.php create mode 100644 library/vendor/Zend/Crypt/Math/Exception.php create mode 100644 library/vendor/Zend/Crypt/Rsa.php create mode 100644 library/vendor/Zend/Crypt/Rsa/Exception.php create mode 100644 library/vendor/Zend/Crypt/Rsa/Key.php create mode 100644 library/vendor/Zend/Crypt/Rsa/Key/Private.php create mode 100644 library/vendor/Zend/Crypt/Rsa/Key/Public.php create mode 100644 library/vendor/Zend/Date.php create mode 100644 library/vendor/Zend/Date/Cities.php create mode 100644 library/vendor/Zend/Date/DateObject.php create mode 100644 library/vendor/Zend/Date/Exception.php create mode 100644 library/vendor/Zend/Db.php create mode 100644 library/vendor/Zend/Db/Adapter/Abstract.php create mode 100644 library/vendor/Zend/Db/Adapter/Db2.php create mode 100644 library/vendor/Zend/Db/Adapter/Db2/Exception.php create mode 100644 library/vendor/Zend/Db/Adapter/Exception.php create mode 100644 library/vendor/Zend/Db/Adapter/Mysqli.php create mode 100644 library/vendor/Zend/Db/Adapter/Mysqli/Exception.php create mode 100644 library/vendor/Zend/Db/Adapter/Oracle.php create mode 100644 library/vendor/Zend/Db/Adapter/Oracle/Exception.php create mode 100644 library/vendor/Zend/Db/Adapter/Pdo/Abstract.php create mode 100644 library/vendor/Zend/Db/Adapter/Pdo/Ibm.php create mode 100644 library/vendor/Zend/Db/Adapter/Pdo/Ibm/Db2.php create mode 100644 library/vendor/Zend/Db/Adapter/Pdo/Ibm/Ids.php create mode 100644 library/vendor/Zend/Db/Adapter/Pdo/Mssql.php create mode 100644 library/vendor/Zend/Db/Adapter/Pdo/Mysql.php create mode 100644 library/vendor/Zend/Db/Adapter/Pdo/Oci.php create mode 100644 library/vendor/Zend/Db/Adapter/Pdo/Pgsql.php create mode 100644 library/vendor/Zend/Db/Adapter/Pdo/Sqlite.php create mode 100644 library/vendor/Zend/Db/Adapter/Sqlsrv.php create mode 100644 library/vendor/Zend/Db/Adapter/Sqlsrv/Exception.php create mode 100644 library/vendor/Zend/Db/Exception.php create mode 100644 library/vendor/Zend/Db/Expr.php create mode 100644 library/vendor/Zend/Db/Profiler.php create mode 100644 library/vendor/Zend/Db/Profiler/Exception.php create mode 100644 library/vendor/Zend/Db/Profiler/Query.php create mode 100644 library/vendor/Zend/Db/Select.php create mode 100644 library/vendor/Zend/Db/Select/Exception.php create mode 100644 library/vendor/Zend/Db/Statement.php create mode 100644 library/vendor/Zend/Db/Statement/Db2.php create mode 100644 library/vendor/Zend/Db/Statement/Db2/Exception.php create mode 100644 library/vendor/Zend/Db/Statement/Exception.php create mode 100644 library/vendor/Zend/Db/Statement/Interface.php create mode 100644 library/vendor/Zend/Db/Statement/Mysqli.php create mode 100644 library/vendor/Zend/Db/Statement/Mysqli/Exception.php create mode 100644 library/vendor/Zend/Db/Statement/Oracle.php create mode 100644 library/vendor/Zend/Db/Statement/Oracle/Exception.php create mode 100644 library/vendor/Zend/Db/Statement/Pdo.php create mode 100644 library/vendor/Zend/Db/Statement/Pdo/Ibm.php create mode 100644 library/vendor/Zend/Db/Statement/Pdo/Oci.php create mode 100644 library/vendor/Zend/Db/Statement/Sqlsrv.php create mode 100644 library/vendor/Zend/Db/Statement/Sqlsrv/Exception.php create mode 100644 library/vendor/Zend/Db/Table.php create mode 100644 library/vendor/Zend/Db/Table/Abstract.php create mode 100644 library/vendor/Zend/Db/Table/Definition.php create mode 100644 library/vendor/Zend/Db/Table/Exception.php create mode 100644 library/vendor/Zend/Db/Table/Row.php create mode 100644 library/vendor/Zend/Db/Table/Row/Abstract.php create mode 100644 library/vendor/Zend/Db/Table/Row/Exception.php create mode 100644 library/vendor/Zend/Db/Table/Rowset.php create mode 100644 library/vendor/Zend/Db/Table/Rowset/Abstract.php create mode 100644 library/vendor/Zend/Db/Table/Rowset/Exception.php create mode 100644 library/vendor/Zend/Db/Table/Select.php create mode 100644 library/vendor/Zend/Db/Table/Select/Exception.php create mode 100644 library/vendor/Zend/Exception.php create mode 100644 library/vendor/Zend/File/ClassFileLocator.php create mode 100644 library/vendor/Zend/File/PhpClassFile.php create mode 100644 library/vendor/Zend/File/Transfer.php create mode 100644 library/vendor/Zend/File/Transfer/Adapter/Abstract.php create mode 100644 library/vendor/Zend/File/Transfer/Adapter/Http.php create mode 100644 library/vendor/Zend/File/Transfer/Exception.php create mode 100644 library/vendor/Zend/Filter.php create mode 100644 library/vendor/Zend/Filter/Alnum.php create mode 100644 library/vendor/Zend/Filter/Alpha.php create mode 100644 library/vendor/Zend/Filter/BaseName.php create mode 100644 library/vendor/Zend/Filter/Boolean.php create mode 100644 library/vendor/Zend/Filter/Callback.php create mode 100644 library/vendor/Zend/Filter/Compress.php create mode 100644 library/vendor/Zend/Filter/Compress/Bz2.php create mode 100644 library/vendor/Zend/Filter/Compress/CompressAbstract.php create mode 100644 library/vendor/Zend/Filter/Compress/CompressInterface.php create mode 100644 library/vendor/Zend/Filter/Compress/Gz.php create mode 100644 library/vendor/Zend/Filter/Compress/Lzf.php create mode 100644 library/vendor/Zend/Filter/Compress/Rar.php create mode 100644 library/vendor/Zend/Filter/Compress/Tar.php create mode 100644 library/vendor/Zend/Filter/Compress/Zip.php create mode 100644 library/vendor/Zend/Filter/Decompress.php create mode 100644 library/vendor/Zend/Filter/Decrypt.php create mode 100644 library/vendor/Zend/Filter/Digits.php create mode 100644 library/vendor/Zend/Filter/Dir.php create mode 100644 library/vendor/Zend/Filter/Encrypt.php create mode 100644 library/vendor/Zend/Filter/Encrypt/Interface.php create mode 100644 library/vendor/Zend/Filter/Encrypt/Mcrypt.php create mode 100644 library/vendor/Zend/Filter/Encrypt/Openssl.php create mode 100644 library/vendor/Zend/Filter/Exception.php create mode 100644 library/vendor/Zend/Filter/File/Decrypt.php create mode 100644 library/vendor/Zend/Filter/File/Encrypt.php create mode 100644 library/vendor/Zend/Filter/File/LowerCase.php create mode 100644 library/vendor/Zend/Filter/File/Rename.php create mode 100644 library/vendor/Zend/Filter/File/UpperCase.php create mode 100644 library/vendor/Zend/Filter/HtmlEntities.php create mode 100644 library/vendor/Zend/Filter/Inflector.php create mode 100644 library/vendor/Zend/Filter/Input.php create mode 100644 library/vendor/Zend/Filter/Int.php create mode 100644 library/vendor/Zend/Filter/Interface.php create mode 100644 library/vendor/Zend/Filter/LocalizedToNormalized.php create mode 100644 library/vendor/Zend/Filter/NormalizedToLocalized.php create mode 100644 library/vendor/Zend/Filter/Null.php create mode 100644 library/vendor/Zend/Filter/PregReplace.php create mode 100644 library/vendor/Zend/Filter/RealPath.php create mode 100644 library/vendor/Zend/Filter/StringToLower.php create mode 100644 library/vendor/Zend/Filter/StringToUpper.php create mode 100644 library/vendor/Zend/Filter/StringTrim.php create mode 100644 library/vendor/Zend/Filter/StripNewlines.php create mode 100644 library/vendor/Zend/Filter/StripTags.php create mode 100644 library/vendor/Zend/Filter/Word/CamelCaseToDash.php create mode 100644 library/vendor/Zend/Filter/Word/CamelCaseToSeparator.php create mode 100644 library/vendor/Zend/Filter/Word/CamelCaseToUnderscore.php create mode 100644 library/vendor/Zend/Filter/Word/DashToCamelCase.php create mode 100644 library/vendor/Zend/Filter/Word/DashToSeparator.php create mode 100644 library/vendor/Zend/Filter/Word/DashToUnderscore.php create mode 100644 library/vendor/Zend/Filter/Word/Separator/Abstract.php create mode 100644 library/vendor/Zend/Filter/Word/SeparatorToCamelCase.php create mode 100644 library/vendor/Zend/Filter/Word/SeparatorToDash.php create mode 100644 library/vendor/Zend/Filter/Word/SeparatorToSeparator.php create mode 100644 library/vendor/Zend/Filter/Word/UnderscoreToCamelCase.php create mode 100644 library/vendor/Zend/Filter/Word/UnderscoreToDash.php create mode 100644 library/vendor/Zend/Filter/Word/UnderscoreToSeparator.php create mode 100644 library/vendor/Zend/Form.php create mode 100644 library/vendor/Zend/Form/Decorator/Abstract.php create mode 100644 library/vendor/Zend/Form/Decorator/Callback.php create mode 100644 library/vendor/Zend/Form/Decorator/Captcha.php create mode 100644 library/vendor/Zend/Form/Decorator/Description.php create mode 100644 library/vendor/Zend/Form/Decorator/DtDdWrapper.php create mode 100644 library/vendor/Zend/Form/Decorator/Errors.php create mode 100644 library/vendor/Zend/Form/Decorator/Exception.php create mode 100644 library/vendor/Zend/Form/Decorator/Fieldset.php create mode 100644 library/vendor/Zend/Form/Decorator/File.php create mode 100644 library/vendor/Zend/Form/Decorator/Form.php create mode 100644 library/vendor/Zend/Form/Decorator/FormElements.php create mode 100644 library/vendor/Zend/Form/Decorator/FormErrors.php create mode 100644 library/vendor/Zend/Form/Decorator/HtmlTag.php create mode 100644 library/vendor/Zend/Form/Decorator/Image.php create mode 100644 library/vendor/Zend/Form/Decorator/Interface.php create mode 100644 library/vendor/Zend/Form/Decorator/Label.php create mode 100644 library/vendor/Zend/Form/Decorator/Marker/File/Interface.php create mode 100644 library/vendor/Zend/Form/Decorator/PrepareElements.php create mode 100644 library/vendor/Zend/Form/Decorator/Tooltip.php create mode 100644 library/vendor/Zend/Form/Decorator/ViewHelper.php create mode 100644 library/vendor/Zend/Form/Decorator/ViewScript.php create mode 100644 library/vendor/Zend/Form/DisplayGroup.php create mode 100644 library/vendor/Zend/Form/Element.php create mode 100644 library/vendor/Zend/Form/Element/Button.php create mode 100644 library/vendor/Zend/Form/Element/Checkbox.php create mode 100644 library/vendor/Zend/Form/Element/Exception.php create mode 100644 library/vendor/Zend/Form/Element/File.php create mode 100644 library/vendor/Zend/Form/Element/Hidden.php create mode 100644 library/vendor/Zend/Form/Element/Image.php create mode 100644 library/vendor/Zend/Form/Element/Multi.php create mode 100644 library/vendor/Zend/Form/Element/MultiCheckbox.php create mode 100644 library/vendor/Zend/Form/Element/Multiselect.php create mode 100644 library/vendor/Zend/Form/Element/Note.php create mode 100644 library/vendor/Zend/Form/Element/Password.php create mode 100644 library/vendor/Zend/Form/Element/Radio.php create mode 100644 library/vendor/Zend/Form/Element/Reset.php create mode 100644 library/vendor/Zend/Form/Element/Select.php create mode 100644 library/vendor/Zend/Form/Element/Submit.php create mode 100644 library/vendor/Zend/Form/Element/Text.php create mode 100644 library/vendor/Zend/Form/Element/Textarea.php create mode 100644 library/vendor/Zend/Form/Element/Xhtml.php create mode 100644 library/vendor/Zend/Form/Exception.php create mode 100644 library/vendor/Zend/Form/SubForm.php create mode 100644 library/vendor/Zend/Json.php create mode 100644 library/vendor/Zend/Json/Decoder.php create mode 100644 library/vendor/Zend/Json/Encoder.php create mode 100644 library/vendor/Zend/Json/Exception.php create mode 100644 library/vendor/Zend/Json/Expr.php create mode 100644 library/vendor/Zend/LICENSE.txt create mode 100644 library/vendor/Zend/Layout.php create mode 100644 library/vendor/Zend/Layout/Controller/Action/Helper/Layout.php create mode 100644 library/vendor/Zend/Layout/Controller/Plugin/Layout.php create mode 100644 library/vendor/Zend/Layout/Exception.php create mode 100644 library/vendor/Zend/Loader.php create mode 100644 library/vendor/Zend/Loader/Autoloader.php create mode 100644 library/vendor/Zend/Loader/Autoloader/Interface.php create mode 100644 library/vendor/Zend/Loader/Exception.php create mode 100644 library/vendor/Zend/Loader/Exception/InvalidArgumentException.php create mode 100644 library/vendor/Zend/Loader/PluginLoader.php create mode 100644 library/vendor/Zend/Loader/PluginLoader/Exception.php create mode 100644 library/vendor/Zend/Loader/PluginLoader/Interface.php create mode 100644 library/vendor/Zend/Locale.php create mode 100644 library/vendor/Zend/Locale/Data.php create mode 100644 library/vendor/Zend/Locale/Data/Translation.php create mode 100644 library/vendor/Zend/Locale/Exception.php create mode 100644 library/vendor/Zend/Locale/Format.php create mode 100644 library/vendor/Zend/Locale/Math.php create mode 100644 library/vendor/Zend/Locale/Math/Exception.php create mode 100644 library/vendor/Zend/Locale/Math/PhpMath.php create mode 100644 library/vendor/Zend/Log.php create mode 100644 library/vendor/Zend/Log/Exception.php create mode 100644 library/vendor/Zend/Log/FactoryInterface.php create mode 100644 library/vendor/Zend/Log/Filter/Abstract.php create mode 100644 library/vendor/Zend/Log/Filter/Interface.php create mode 100644 library/vendor/Zend/Log/Filter/Message.php create mode 100644 library/vendor/Zend/Log/Filter/Priority.php create mode 100644 library/vendor/Zend/Log/Filter/Suppress.php create mode 100644 library/vendor/Zend/Log/Formatter/Abstract.php create mode 100644 library/vendor/Zend/Log/Formatter/Interface.php create mode 100644 library/vendor/Zend/Log/Formatter/Simple.php create mode 100644 library/vendor/Zend/Log/Formatter/Xml.php create mode 100644 library/vendor/Zend/Log/Writer/Abstract.php create mode 100644 library/vendor/Zend/Log/Writer/Db.php create mode 100644 library/vendor/Zend/Log/Writer/Mail.php create mode 100644 library/vendor/Zend/Log/Writer/Mock.php create mode 100644 library/vendor/Zend/Log/Writer/Null.php create mode 100644 library/vendor/Zend/Log/Writer/Stream.php create mode 100644 library/vendor/Zend/Log/Writer/Syslog.php create mode 100644 library/vendor/Zend/Log/Writer/ZendMonitor.php create mode 100644 library/vendor/Zend/Mail.php create mode 100644 library/vendor/Zend/Mail/Exception.php create mode 100644 library/vendor/Zend/Mail/Header/HeaderName.php create mode 100644 library/vendor/Zend/Mail/Header/HeaderValue.php create mode 100644 library/vendor/Zend/Mail/Message.php create mode 100644 library/vendor/Zend/Mail/Message/File.php create mode 100644 library/vendor/Zend/Mail/Message/Interface.php create mode 100644 library/vendor/Zend/Mail/Part.php create mode 100644 library/vendor/Zend/Mail/Part/File.php create mode 100644 library/vendor/Zend/Mail/Part/Interface.php create mode 100644 library/vendor/Zend/Mail/Protocol/Abstract.php create mode 100644 library/vendor/Zend/Mail/Protocol/Exception.php create mode 100644 library/vendor/Zend/Mail/Protocol/Imap.php create mode 100644 library/vendor/Zend/Mail/Protocol/Pop3.php create mode 100644 library/vendor/Zend/Mail/Protocol/Smtp.php create mode 100644 library/vendor/Zend/Mail/Protocol/Smtp/Auth/Crammd5.php create mode 100644 library/vendor/Zend/Mail/Protocol/Smtp/Auth/Login.php create mode 100644 library/vendor/Zend/Mail/Protocol/Smtp/Auth/Plain.php create mode 100644 library/vendor/Zend/Mail/Storage.php create mode 100644 library/vendor/Zend/Mail/Storage/Abstract.php create mode 100644 library/vendor/Zend/Mail/Storage/Exception.php create mode 100644 library/vendor/Zend/Mail/Storage/Folder.php create mode 100644 library/vendor/Zend/Mail/Storage/Folder/Interface.php create mode 100644 library/vendor/Zend/Mail/Storage/Folder/Maildir.php create mode 100644 library/vendor/Zend/Mail/Storage/Folder/Mbox.php create mode 100644 library/vendor/Zend/Mail/Storage/Imap.php create mode 100644 library/vendor/Zend/Mail/Storage/Maildir.php create mode 100644 library/vendor/Zend/Mail/Storage/Mbox.php create mode 100644 library/vendor/Zend/Mail/Storage/Pop3.php create mode 100644 library/vendor/Zend/Mail/Storage/Writable/Interface.php create mode 100644 library/vendor/Zend/Mail/Storage/Writable/Maildir.php create mode 100644 library/vendor/Zend/Mail/Transport/Abstract.php create mode 100644 library/vendor/Zend/Mail/Transport/Exception.php create mode 100644 library/vendor/Zend/Mail/Transport/File.php create mode 100644 library/vendor/Zend/Mail/Transport/Sendmail.php create mode 100644 library/vendor/Zend/Mail/Transport/Smtp.php create mode 100644 library/vendor/Zend/Mime.php create mode 100644 library/vendor/Zend/Mime/Decode.php create mode 100644 library/vendor/Zend/Mime/Exception.php create mode 100644 library/vendor/Zend/Mime/Message.php create mode 100644 library/vendor/Zend/Mime/Part.php create mode 100644 library/vendor/Zend/Paginator.php create mode 100644 library/vendor/Zend/Paginator/Adapter/Array.php create mode 100644 library/vendor/Zend/Paginator/Adapter/DbSelect.php create mode 100644 library/vendor/Zend/Paginator/Adapter/DbTableSelect.php create mode 100644 library/vendor/Zend/Paginator/Adapter/Interface.php create mode 100644 library/vendor/Zend/Paginator/Adapter/Iterator.php create mode 100644 library/vendor/Zend/Paginator/Adapter/Null.php create mode 100644 library/vendor/Zend/Paginator/AdapterAggregate.php create mode 100644 library/vendor/Zend/Paginator/Exception.php create mode 100644 library/vendor/Zend/Paginator/ScrollingStyle/All.php create mode 100644 library/vendor/Zend/Paginator/ScrollingStyle/Elastic.php create mode 100644 library/vendor/Zend/Paginator/ScrollingStyle/Interface.php create mode 100644 library/vendor/Zend/Paginator/ScrollingStyle/Jumping.php create mode 100644 library/vendor/Zend/Paginator/ScrollingStyle/Sliding.php create mode 100644 library/vendor/Zend/Paginator/SerializableLimitIterator.php create mode 100644 library/vendor/Zend/ProgressBar.php create mode 100644 library/vendor/Zend/ProgressBar/Adapter.php create mode 100644 library/vendor/Zend/ProgressBar/Adapter/Exception.php create mode 100644 library/vendor/Zend/ProgressBar/Adapter/JsPull.php create mode 100644 library/vendor/Zend/ProgressBar/Adapter/JsPush.php create mode 100644 library/vendor/Zend/ProgressBar/Exception.php create mode 100644 library/vendor/Zend/README.md create mode 100644 library/vendor/Zend/Registry.php create mode 100644 library/vendor/Zend/Server/Abstract.php create mode 100644 library/vendor/Zend/Server/Cache.php create mode 100644 library/vendor/Zend/Server/Definition.php create mode 100644 library/vendor/Zend/Server/Exception.php create mode 100644 library/vendor/Zend/Server/Interface.php create mode 100644 library/vendor/Zend/Server/Method/Callback.php create mode 100644 library/vendor/Zend/Server/Method/Definition.php create mode 100644 library/vendor/Zend/Server/Method/Parameter.php create mode 100644 library/vendor/Zend/Server/Method/Prototype.php create mode 100644 library/vendor/Zend/Server/Reflection.php create mode 100644 library/vendor/Zend/Server/Reflection/Class.php create mode 100644 library/vendor/Zend/Server/Reflection/Exception.php create mode 100644 library/vendor/Zend/Server/Reflection/Function.php create mode 100644 library/vendor/Zend/Server/Reflection/Function/Abstract.php create mode 100644 library/vendor/Zend/Server/Reflection/Method.php create mode 100644 library/vendor/Zend/Server/Reflection/Node.php create mode 100644 library/vendor/Zend/Server/Reflection/Parameter.php create mode 100644 library/vendor/Zend/Server/Reflection/Prototype.php create mode 100644 library/vendor/Zend/Server/Reflection/ReturnValue.php create mode 100644 library/vendor/Zend/Session.php create mode 100644 library/vendor/Zend/Session/Abstract.php create mode 100644 library/vendor/Zend/Session/Exception.php create mode 100644 library/vendor/Zend/Session/Namespace.php create mode 100644 library/vendor/Zend/Session/SaveHandler/DbTable.php create mode 100644 library/vendor/Zend/Session/SaveHandler/Exception.php create mode 100644 library/vendor/Zend/Session/SaveHandler/Interface.php create mode 100644 library/vendor/Zend/Session/Validator/Abstract.php create mode 100644 library/vendor/Zend/Session/Validator/Exception.php create mode 100644 library/vendor/Zend/Session/Validator/HttpUserAgent.php create mode 100644 library/vendor/Zend/Session/Validator/Interface.php create mode 100644 library/vendor/Zend/Soap/AutoDiscover.php create mode 100644 library/vendor/Zend/Soap/AutoDiscover/Exception.php create mode 100644 library/vendor/Zend/Soap/Client.php create mode 100644 library/vendor/Zend/Soap/Client/Common.php create mode 100644 library/vendor/Zend/Soap/Client/DotNet.php create mode 100644 library/vendor/Zend/Soap/Client/Exception.php create mode 100644 library/vendor/Zend/Soap/Client/Local.php create mode 100644 library/vendor/Zend/Soap/Server.php create mode 100644 library/vendor/Zend/Soap/Server/Exception.php create mode 100644 library/vendor/Zend/Soap/Server/Proxy.php create mode 100644 library/vendor/Zend/Soap/Wsdl.php create mode 100644 library/vendor/Zend/Soap/Wsdl/Exception.php create mode 100644 library/vendor/Zend/Soap/Wsdl/Strategy/Abstract.php create mode 100644 library/vendor/Zend/Soap/Wsdl/Strategy/AnyType.php create mode 100644 library/vendor/Zend/Soap/Wsdl/Strategy/ArrayOfTypeComplex.php create mode 100644 library/vendor/Zend/Soap/Wsdl/Strategy/ArrayOfTypeSequence.php create mode 100644 library/vendor/Zend/Soap/Wsdl/Strategy/Composite.php create mode 100644 library/vendor/Zend/Soap/Wsdl/Strategy/DefaultComplexType.php create mode 100644 library/vendor/Zend/Soap/Wsdl/Strategy/Interface.php create mode 100644 library/vendor/Zend/TimeSync.php create mode 100644 library/vendor/Zend/TimeSync/Exception.php create mode 100644 library/vendor/Zend/TimeSync/Ntp.php create mode 100644 library/vendor/Zend/TimeSync/Protocol.php create mode 100644 library/vendor/Zend/TimeSync/Sntp.php create mode 100644 library/vendor/Zend/Translate.php create mode 100644 library/vendor/Zend/Translate/Adapter.php create mode 100644 library/vendor/Zend/Translate/Exception.php create mode 100644 library/vendor/Zend/Translate/Plural.php create mode 100644 library/vendor/Zend/Uri.php create mode 100644 library/vendor/Zend/Uri/Exception.php create mode 100644 library/vendor/Zend/Uri/Http.php create mode 100644 library/vendor/Zend/VERSION create mode 100644 library/vendor/Zend/Validate.php create mode 100644 library/vendor/Zend/Validate/Abstract.php create mode 100644 library/vendor/Zend/Validate/Alnum.php create mode 100644 library/vendor/Zend/Validate/Alpha.php create mode 100644 library/vendor/Zend/Validate/Barcode.php create mode 100644 library/vendor/Zend/Validate/Barcode/AdapterAbstract.php create mode 100644 library/vendor/Zend/Validate/Barcode/AdapterInterface.php create mode 100644 library/vendor/Zend/Validate/Barcode/Code25.php create mode 100644 library/vendor/Zend/Validate/Barcode/Code25interleaved.php create mode 100644 library/vendor/Zend/Validate/Barcode/Code39.php create mode 100644 library/vendor/Zend/Validate/Barcode/Code39ext.php create mode 100644 library/vendor/Zend/Validate/Barcode/Code93.php create mode 100644 library/vendor/Zend/Validate/Barcode/Code93ext.php create mode 100644 library/vendor/Zend/Validate/Barcode/Ean12.php create mode 100644 library/vendor/Zend/Validate/Barcode/Ean13.php create mode 100644 library/vendor/Zend/Validate/Barcode/Ean14.php create mode 100644 library/vendor/Zend/Validate/Barcode/Ean18.php create mode 100644 library/vendor/Zend/Validate/Barcode/Ean2.php create mode 100644 library/vendor/Zend/Validate/Barcode/Ean5.php create mode 100644 library/vendor/Zend/Validate/Barcode/Ean8.php create mode 100644 library/vendor/Zend/Validate/Barcode/Gtin12.php create mode 100644 library/vendor/Zend/Validate/Barcode/Gtin13.php create mode 100644 library/vendor/Zend/Validate/Barcode/Gtin14.php create mode 100644 library/vendor/Zend/Validate/Barcode/Identcode.php create mode 100644 library/vendor/Zend/Validate/Barcode/Intelligentmail.php create mode 100644 library/vendor/Zend/Validate/Barcode/Issn.php create mode 100644 library/vendor/Zend/Validate/Barcode/Itf14.php create mode 100644 library/vendor/Zend/Validate/Barcode/Leitcode.php create mode 100644 library/vendor/Zend/Validate/Barcode/Planet.php create mode 100644 library/vendor/Zend/Validate/Barcode/Postnet.php create mode 100644 library/vendor/Zend/Validate/Barcode/Royalmail.php create mode 100644 library/vendor/Zend/Validate/Barcode/Sscc.php create mode 100644 library/vendor/Zend/Validate/Barcode/Upca.php create mode 100644 library/vendor/Zend/Validate/Barcode/Upce.php create mode 100644 library/vendor/Zend/Validate/Between.php create mode 100644 library/vendor/Zend/Validate/Callback.php create mode 100644 library/vendor/Zend/Validate/Ccnum.php create mode 100644 library/vendor/Zend/Validate/CreditCard.php create mode 100644 library/vendor/Zend/Validate/Date.php create mode 100644 library/vendor/Zend/Validate/Db/Abstract.php create mode 100644 library/vendor/Zend/Validate/Db/NoRecordExists.php create mode 100644 library/vendor/Zend/Validate/Db/RecordExists.php create mode 100644 library/vendor/Zend/Validate/Digits.php create mode 100644 library/vendor/Zend/Validate/EmailAddress.php create mode 100644 library/vendor/Zend/Validate/Exception.php create mode 100644 library/vendor/Zend/Validate/File/Count.php create mode 100644 library/vendor/Zend/Validate/File/Crc32.php create mode 100644 library/vendor/Zend/Validate/File/ExcludeExtension.php create mode 100644 library/vendor/Zend/Validate/File/ExcludeMimeType.php create mode 100644 library/vendor/Zend/Validate/File/Exists.php create mode 100644 library/vendor/Zend/Validate/File/Extension.php create mode 100644 library/vendor/Zend/Validate/File/FilesSize.php create mode 100644 library/vendor/Zend/Validate/File/Hash.php create mode 100644 library/vendor/Zend/Validate/File/ImageSize.php create mode 100644 library/vendor/Zend/Validate/File/IsCompressed.php create mode 100644 library/vendor/Zend/Validate/File/IsImage.php create mode 100644 library/vendor/Zend/Validate/File/Md5.php create mode 100644 library/vendor/Zend/Validate/File/MimeType.php create mode 100644 library/vendor/Zend/Validate/File/NotExists.php create mode 100644 library/vendor/Zend/Validate/File/Sha1.php create mode 100644 library/vendor/Zend/Validate/File/Size.php create mode 100644 library/vendor/Zend/Validate/File/Upload.php create mode 100644 library/vendor/Zend/Validate/File/WordCount.php create mode 100644 library/vendor/Zend/Validate/Float.php create mode 100644 library/vendor/Zend/Validate/GreaterThan.php create mode 100644 library/vendor/Zend/Validate/Hex.php create mode 100644 library/vendor/Zend/Validate/Hostname.php create mode 100644 library/vendor/Zend/Validate/Hostname/Biz.php create mode 100644 library/vendor/Zend/Validate/Hostname/Cn.php create mode 100644 library/vendor/Zend/Validate/Hostname/Com.php create mode 100644 library/vendor/Zend/Validate/Hostname/Jp.php create mode 100644 library/vendor/Zend/Validate/Iban.php create mode 100644 library/vendor/Zend/Validate/Identical.php create mode 100644 library/vendor/Zend/Validate/InArray.php create mode 100644 library/vendor/Zend/Validate/Int.php create mode 100644 library/vendor/Zend/Validate/Interface.php create mode 100644 library/vendor/Zend/Validate/Ip.php create mode 100644 library/vendor/Zend/Validate/Isbn.php create mode 100644 library/vendor/Zend/Validate/LessThan.php create mode 100644 library/vendor/Zend/Validate/NotEmpty.php create mode 100644 library/vendor/Zend/Validate/PostCode.php create mode 100644 library/vendor/Zend/Validate/Regex.php create mode 100644 library/vendor/Zend/Validate/Sitemap/Changefreq.php create mode 100644 library/vendor/Zend/Validate/Sitemap/Lastmod.php create mode 100644 library/vendor/Zend/Validate/Sitemap/Loc.php create mode 100644 library/vendor/Zend/Validate/Sitemap/Priority.php create mode 100644 library/vendor/Zend/Validate/StringLength.php create mode 100644 library/vendor/Zend/View.php create mode 100644 library/vendor/Zend/View/Abstract.php create mode 100644 library/vendor/Zend/View/Exception.php create mode 100644 library/vendor/Zend/View/Helper/Abstract.php create mode 100644 library/vendor/Zend/View/Helper/Action.php create mode 100644 library/vendor/Zend/View/Helper/BaseUrl.php create mode 100644 library/vendor/Zend/View/Helper/Cycle.php create mode 100644 library/vendor/Zend/View/Helper/DeclareVars.php create mode 100644 library/vendor/Zend/View/Helper/Doctype.php create mode 100644 library/vendor/Zend/View/Helper/Fieldset.php create mode 100644 library/vendor/Zend/View/Helper/Form.php create mode 100644 library/vendor/Zend/View/Helper/FormButton.php create mode 100644 library/vendor/Zend/View/Helper/FormCheckbox.php create mode 100644 library/vendor/Zend/View/Helper/FormElement.php create mode 100644 library/vendor/Zend/View/Helper/FormErrors.php create mode 100644 library/vendor/Zend/View/Helper/FormFile.php create mode 100644 library/vendor/Zend/View/Helper/FormHidden.php create mode 100644 library/vendor/Zend/View/Helper/FormImage.php create mode 100644 library/vendor/Zend/View/Helper/FormLabel.php create mode 100644 library/vendor/Zend/View/Helper/FormMultiCheckbox.php create mode 100644 library/vendor/Zend/View/Helper/FormNote.php create mode 100644 library/vendor/Zend/View/Helper/FormPassword.php create mode 100644 library/vendor/Zend/View/Helper/FormRadio.php create mode 100644 library/vendor/Zend/View/Helper/FormReset.php create mode 100644 library/vendor/Zend/View/Helper/FormSelect.php create mode 100644 library/vendor/Zend/View/Helper/FormSubmit.php create mode 100644 library/vendor/Zend/View/Helper/FormText.php create mode 100644 library/vendor/Zend/View/Helper/FormTextarea.php create mode 100644 library/vendor/Zend/View/Helper/Gravatar.php create mode 100644 library/vendor/Zend/View/Helper/HeadLink.php create mode 100644 library/vendor/Zend/View/Helper/HeadMeta.php create mode 100644 library/vendor/Zend/View/Helper/HeadScript.php create mode 100644 library/vendor/Zend/View/Helper/HeadStyle.php create mode 100644 library/vendor/Zend/View/Helper/HeadTitle.php create mode 100644 library/vendor/Zend/View/Helper/HtmlElement.php create mode 100644 library/vendor/Zend/View/Helper/HtmlFlash.php create mode 100644 library/vendor/Zend/View/Helper/HtmlList.php create mode 100644 library/vendor/Zend/View/Helper/HtmlObject.php create mode 100644 library/vendor/Zend/View/Helper/HtmlPage.php create mode 100644 library/vendor/Zend/View/Helper/HtmlQuicktime.php create mode 100644 library/vendor/Zend/View/Helper/InlineScript.php create mode 100644 library/vendor/Zend/View/Helper/Interface.php create mode 100644 library/vendor/Zend/View/Helper/Json.php create mode 100644 library/vendor/Zend/View/Helper/Layout.php create mode 100644 library/vendor/Zend/View/Helper/PaginationControl.php create mode 100644 library/vendor/Zend/View/Helper/Partial.php create mode 100644 library/vendor/Zend/View/Helper/Partial/Exception.php create mode 100644 library/vendor/Zend/View/Helper/PartialLoop.php create mode 100644 library/vendor/Zend/View/Helper/Placeholder.php create mode 100644 library/vendor/Zend/View/Helper/Placeholder/Container.php create mode 100644 library/vendor/Zend/View/Helper/Placeholder/Container/Abstract.php create mode 100644 library/vendor/Zend/View/Helper/Placeholder/Container/Exception.php create mode 100644 library/vendor/Zend/View/Helper/Placeholder/Container/Standalone.php create mode 100644 library/vendor/Zend/View/Helper/Placeholder/Registry.php create mode 100644 library/vendor/Zend/View/Helper/Placeholder/Registry/Exception.php create mode 100644 library/vendor/Zend/View/Helper/RenderToPlaceholder.php create mode 100644 library/vendor/Zend/View/Helper/ServerUrl.php create mode 100644 library/vendor/Zend/View/Helper/Translate.php create mode 100644 library/vendor/Zend/View/Helper/Url.php create mode 100644 library/vendor/Zend/View/Interface.php create mode 100644 library/vendor/Zend/View/Stream.php create mode 100644 library/vendor/Zend/Xml/Exception.php create mode 100644 library/vendor/Zend/Xml/Security.php (limited to 'library/vendor/Zend') diff --git a/library/vendor/Zend/Cache.php b/library/vendor/Zend/Cache.php new file mode 100644 index 0000000..272cd0b --- /dev/null +++ b/library/vendor/Zend/Cache.php @@ -0,0 +1,245 @@ +setBackend($backendObject); + return $frontendObject; + } + + /** + * Backend Constructor + * + * @param string $backend + * @param array $backendOptions + * @param boolean $customBackendNaming + * @param boolean $autoload + * @return Zend_Cache_Backend + */ + public static function _makeBackend($backend, $backendOptions, $customBackendNaming = false, $autoload = false) + { + if (!$customBackendNaming) { + $backend = self::_normalizeName($backend); + } + if (in_array($backend, Zend_Cache::$standardBackends)) { + // we use a standard backend + $backendClass = 'Zend_Cache_Backend_' . $backend; + // security controls are explicit + } else { + // we use a custom backend + if (!preg_match('~^[\w\\\\]+$~D', $backend)) { + Zend_Cache::throwException("Invalid backend name [$backend]"); + } + if (!$customBackendNaming) { + // we use this boolean to avoid an API break + $backendClass = 'Zend_Cache_Backend_' . $backend; + } else { + $backendClass = $backend; + } + if (!$autoload) { + $file = str_replace('_', DIRECTORY_SEPARATOR, $backendClass) . '.php'; + if (!(self::_isReadable($file))) { + self::throwException("file $file not found in include_path"); + } + } + } + return new $backendClass($backendOptions); + } + + /** + * Frontend Constructor + * + * @param string $frontend + * @param array $frontendOptions + * @param boolean $customFrontendNaming + * @param boolean $autoload + * @return Zend_Cache_Core|Zend_Cache_Frontend + */ + public static function _makeFrontend($frontend, $frontendOptions = array(), $customFrontendNaming = false, $autoload = false) + { + if (!$customFrontendNaming) { + $frontend = self::_normalizeName($frontend); + } + if (in_array($frontend, self::$standardFrontends)) { + // we use a standard frontend + // For perfs reasons, with frontend == 'Core', we can interact with the Core itself + $frontendClass = 'Zend_Cache_' . ($frontend != 'Core' ? 'Frontend_' : '') . $frontend; + // security controls are explicit + } else { + // we use a custom frontend + if (!preg_match('~^[\w\\\\]+$~D', $frontend)) { + Zend_Cache::throwException("Invalid frontend name [$frontend]"); + } + if (!$customFrontendNaming) { + // we use this boolean to avoid an API break + $frontendClass = 'Zend_Cache_Frontend_' . $frontend; + } else { + $frontendClass = $frontend; + } + if (!$autoload) { + $file = str_replace('_', DIRECTORY_SEPARATOR, $frontendClass) . '.php'; + if (!(self::_isReadable($file))) { + self::throwException("file $file not found in include_path"); + } + } + } + return new $frontendClass($frontendOptions); + } + + /** + * Throw an exception + * + * Note : for perf reasons, the "load" of Zend/Cache/Exception is dynamic + * @param string $msg Message for the exception + * @throws Zend_Cache_Exception + */ + public static function throwException($msg, Exception $e = null) + { + // For perfs reasons, we use this dynamic inclusion + throw new Zend_Cache_Exception($msg, 0, $e); + } + + /** + * Normalize frontend and backend names to allow multiple words TitleCased + * + * @param string $name Name to normalize + * @return string + */ + protected static function _normalizeName($name) + { + $name = ucfirst(strtolower($name)); + $name = str_replace(array('-', '_', '.'), ' ', $name); + $name = ucwords($name); + $name = str_replace(' ', '', $name); + if (stripos($name, 'ZendServer') === 0) { + $name = 'ZendServer_' . substr($name, strlen('ZendServer')); + } + + return $name; + } + + /** + * Returns TRUE if the $filename is readable, or FALSE otherwise. + * This function uses the PHP include_path, where PHP's is_readable() + * does not. + * + * Note : this method comes from Zend_Loader (see #ZF-2891 for details) + * + * @param string $filename + * @return boolean + */ + private static function _isReadable($filename) + { + if (!$fh = @fopen($filename, 'r', true)) { + return false; + } + @fclose($fh); + return true; + } + +} diff --git a/library/vendor/Zend/Cache/Backend.php b/library/vendor/Zend/Cache/Backend.php new file mode 100644 index 0000000..6e1efde --- /dev/null +++ b/library/vendor/Zend/Cache/Backend.php @@ -0,0 +1,285 @@ + (int) lifetime : + * - Cache lifetime (in seconds) + * - If null, the cache is valid forever + * + * =====> (int) logging : + * - if set to true, a logging is activated throw Zend_Log + * + * @var array directives + */ + protected $_directives = array( + 'lifetime' => 3600, + 'logging' => false, + 'logger' => null + ); + + /** + * Available options + * + * @var array available options + */ + protected $_options = array(); + + /** + * Constructor + * + * @param array $options Associative array of options + */ + public function __construct(array $options = array()) + { + foreach ($options as $name => $value) { + $this->setOption($name, $value); + } + } + + /** + * Set the frontend directives + * + * @param array $directives Assoc of directives + * @throws Zend_Cache_Exception + * @return void + */ + public function setDirectives($directives) + { + if (!is_array($directives)) Zend_Cache::throwException('Directives parameter must be an array'); + while (list($name, $value) = each($directives)) { + if (!is_string($name)) { + Zend_Cache::throwException("Incorrect option name : $name"); + } + $name = strtolower($name); + if (array_key_exists($name, $this->_directives)) { + $this->_directives[$name] = $value; + } + + } + + $this->_loggerSanity(); + } + + /** + * Set an option + * + * @param string $name + * @param mixed $value + * @throws Zend_Cache_Exception + * @return void + */ + public function setOption($name, $value) + { + if (!is_string($name)) { + Zend_Cache::throwException("Incorrect option name : $name"); + } + $name = strtolower($name); + if (array_key_exists($name, $this->_options)) { + $this->_options[$name] = $value; + } + } + + /** + * Returns an option + * + * @param string $name Optional, the options name to return + * @throws Zend_Cache_Exceptions + * @return mixed + */ + public function getOption($name) + { + $name = strtolower($name); + + if (array_key_exists($name, $this->_options)) { + return $this->_options[$name]; + } + + if (array_key_exists($name, $this->_directives)) { + return $this->_directives[$name]; + } + + Zend_Cache::throwException("Incorrect option name : {$name}"); + } + + /** + * Get the life time + * + * if $specificLifetime is not false, the given specific life time is used + * else, the global lifetime is used + * + * @param int $specificLifetime + * @return int Cache life time + */ + public function getLifetime($specificLifetime) + { + if ($specificLifetime === false) { + return $this->_directives['lifetime']; + } + return $specificLifetime; + } + + /** + * Return true if the automatic cleaning is available for the backend + * + * DEPRECATED : use getCapabilities() instead + * + * @deprecated + * @return boolean + */ + public function isAutomaticCleaningAvailable() + { + return true; + } + + /** + * Determine system TMP directory and detect if we have read access + * + * inspired from Zend_File_Transfer_Adapter_Abstract + * + * @return string + * @throws Zend_Cache_Exception if unable to determine directory + */ + public function getTmpDir() + { + $tmpdir = array(); + foreach (array($_ENV, $_SERVER) as $tab) { + foreach (array('TMPDIR', 'TEMP', 'TMP', 'windir', 'SystemRoot') as $key) { + if (isset($tab[$key]) && is_string($tab[$key])) { + if (($key == 'windir') or ($key == 'SystemRoot')) { + $dir = realpath($tab[$key] . '\\temp'); + } else { + $dir = realpath($tab[$key]); + } + if ($this->_isGoodTmpDir($dir)) { + return $dir; + } + } + } + } + $upload = ini_get('upload_tmp_dir'); + if ($upload) { + $dir = realpath($upload); + if ($this->_isGoodTmpDir($dir)) { + return $dir; + } + } + if (function_exists('sys_get_temp_dir')) { + $dir = sys_get_temp_dir(); + if ($this->_isGoodTmpDir($dir)) { + return $dir; + } + } + // Attemp to detect by creating a temporary file + $tempFile = tempnam(md5(uniqid(rand(), TRUE)), ''); + if ($tempFile) { + $dir = realpath(dirname($tempFile)); + unlink($tempFile); + if ($this->_isGoodTmpDir($dir)) { + return $dir; + } + } + if ($this->_isGoodTmpDir('/tmp')) { + return '/tmp'; + } + if ($this->_isGoodTmpDir('\\temp')) { + return '\\temp'; + } + Zend_Cache::throwException('Could not determine temp directory, please specify a cache_dir manually'); + } + + /** + * Verify if the given temporary directory is readable and writable + * + * @param string $dir temporary directory + * @return boolean true if the directory is ok + */ + protected function _isGoodTmpDir($dir) + { + if (is_readable($dir)) { + if (is_writable($dir)) { + return true; + } + } + return false; + } + + /** + * Make sure if we enable logging that the Zend_Log class + * is available. + * Create a default log object if none is set. + * + * @throws Zend_Cache_Exception + * @return void + */ + protected function _loggerSanity() + { + if (!isset($this->_directives['logging']) || !$this->_directives['logging']) { + return; + } + + if (isset($this->_directives['logger'])) { + if ($this->_directives['logger'] instanceof Zend_Log) { + return; + } + Zend_Cache::throwException('Logger object is not an instance of Zend_Log class.'); + } + + // Create a default logger to the standard output stream + $logger = new Zend_Log(new Zend_Log_Writer_Stream('php://output')); + $logger->addFilter(new Zend_Log_Filter_Priority(Zend_Log::WARN, '<=')); + $this->_directives['logger'] = $logger; + } + + /** + * Log a message at the WARN (4) priority. + * + * @param string $message + * @param int $priority + * @return void + */ + protected function _log($message, $priority = 4) + { + if (!$this->_directives['logging']) { + return; + } + + if (!isset($this->_directives['logger'])) { + Zend_Cache::throwException('Logging is enabled but logger is not set.'); + } + $logger = $this->_directives['logger']; + if (!$logger instanceof Zend_Log) { + Zend_Cache::throwException('Logger object is not an instance of Zend_Log class.'); + } + $logger->log($message, $priority); + } +} diff --git a/library/vendor/Zend/Cache/Backend/Apc.php b/library/vendor/Zend/Cache/Backend/Apc.php new file mode 100644 index 0000000..9605323 --- /dev/null +++ b/library/vendor/Zend/Cache/Backend/Apc.php @@ -0,0 +1,353 @@ + infinite lifetime) + * @return boolean true if no problem + */ + public function save($data, $id, $tags = array(), $specificLifetime = false) + { + $lifetime = $this->getLifetime($specificLifetime); + $result = apc_store($id, array($data, time(), $lifetime), $lifetime); + if (count($tags) > 0) { + $this->_log(self::TAGS_UNSUPPORTED_BY_SAVE_OF_APC_BACKEND); + } + return $result; + } + + /** + * Remove a cache record + * + * @param string $id cache id + * @return boolean true if no problem + */ + public function remove($id) + { + return apc_delete($id); + } + + /** + * Clean some cache records + * + * Available modes are : + * 'all' (default) => remove all cache entries ($tags is not used) + * 'old' => unsupported + * 'matchingTag' => unsupported + * 'notMatchingTag' => unsupported + * 'matchingAnyTag' => unsupported + * + * @param string $mode clean mode + * @param array $tags array of tags + * @throws Zend_Cache_Exception + * @return boolean true if no problem + */ + public function clean($mode = Zend_Cache::CLEANING_MODE_ALL, $tags = array()) + { + switch ($mode) { + case Zend_Cache::CLEANING_MODE_ALL: + return apc_clear_cache('user'); + break; + case Zend_Cache::CLEANING_MODE_OLD: + $this->_log("Zend_Cache_Backend_Apc::clean() : CLEANING_MODE_OLD is unsupported by the Apc backend"); + break; + case Zend_Cache::CLEANING_MODE_MATCHING_TAG: + case Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG: + case Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG: + $this->_log(self::TAGS_UNSUPPORTED_BY_CLEAN_OF_APC_BACKEND); + break; + default: + Zend_Cache::throwException('Invalid mode for clean() method'); + break; + } + } + + /** + * Return true if the automatic cleaning is available for the backend + * + * DEPRECATED : use getCapabilities() instead + * + * @deprecated + * @return boolean + */ + public function isAutomaticCleaningAvailable() + { + return false; + } + + /** + * Return the filling percentage of the backend storage + * + * @throws Zend_Cache_Exception + * @return int integer between 0 and 100 + */ + public function getFillingPercentage() + { + $mem = apc_sma_info(true); + $memSize = $mem['num_seg'] * $mem['seg_size']; + $memAvailable= $mem['avail_mem']; + $memUsed = $memSize - $memAvailable; + if ($memSize == 0) { + Zend_Cache::throwException('can\'t get apc memory size'); + } + if ($memUsed > $memSize) { + return 100; + } + return ((int) (100. * ($memUsed / $memSize))); + } + + /** + * Return an array of stored tags + * + * @return array array of stored tags (string) + */ + public function getTags() + { + $this->_log(self::TAGS_UNSUPPORTED_BY_SAVE_OF_APC_BACKEND); + return array(); + } + + /** + * Return an array of stored cache ids which match given tags + * + * In case of multiple tags, a logical AND is made between tags + * + * @param array $tags array of tags + * @return array array of matching cache ids (string) + */ + public function getIdsMatchingTags($tags = array()) + { + $this->_log(self::TAGS_UNSUPPORTED_BY_SAVE_OF_APC_BACKEND); + return array(); + } + + /** + * Return an array of stored cache ids which don't match given tags + * + * In case of multiple tags, a logical OR is made between tags + * + * @param array $tags array of tags + * @return array array of not matching cache ids (string) + */ + public function getIdsNotMatchingTags($tags = array()) + { + $this->_log(self::TAGS_UNSUPPORTED_BY_SAVE_OF_APC_BACKEND); + return array(); + } + + /** + * Return an array of stored cache ids which match any given tags + * + * In case of multiple tags, a logical AND is made between tags + * + * @param array $tags array of tags + * @return array array of any matching cache ids (string) + */ + public function getIdsMatchingAnyTags($tags = array()) + { + $this->_log(self::TAGS_UNSUPPORTED_BY_SAVE_OF_APC_BACKEND); + return array(); + } + + /** + * Return an array of stored cache ids + * + * @return array array of stored cache ids (string) + */ + public function getIds() + { + $ids = array(); + $iterator = new APCIterator('user', null, APC_ITER_KEY); + foreach ($iterator as $item) { + $ids[] = $item['key']; + } + + return $ids; + } + + /** + * Return an array of metadatas for the given cache id + * + * The array must include these keys : + * - expire : the expire timestamp + * - tags : a string array of tags + * - mtime : timestamp of last modification time + * + * @param string $id cache id + * @return array array of metadatas (false if the cache id is not found) + */ + public function getMetadatas($id) + { + $tmp = apc_fetch($id); + if (is_array($tmp)) { + $data = $tmp[0]; + $mtime = $tmp[1]; + if (!isset($tmp[2])) { + // because this record is only with 1.7 release + // if old cache records are still there... + return false; + } + $lifetime = $tmp[2]; + return array( + 'expire' => $mtime + $lifetime, + 'tags' => array(), + 'mtime' => $mtime + ); + } + return false; + } + + /** + * Give (if possible) an extra lifetime to the given cache id + * + * @param string $id cache id + * @param int $extraLifetime + * @return boolean true if ok + */ + public function touch($id, $extraLifetime) + { + $tmp = apc_fetch($id); + if (is_array($tmp)) { + $data = $tmp[0]; + $mtime = $tmp[1]; + if (!isset($tmp[2])) { + // because this record is only with 1.7 release + // if old cache records are still there... + return false; + } + $lifetime = $tmp[2]; + $newLifetime = $lifetime - (time() - $mtime) + $extraLifetime; + if ($newLifetime <=0) { + return false; + } + apc_store($id, array($data, time(), $newLifetime), $newLifetime); + return true; + } + return false; + } + + /** + * Return an associative array of capabilities (booleans) of the backend + * + * The array must include these keys : + * - automatic_cleaning (is automating cleaning necessary) + * - tags (are tags supported) + * - expired_read (is it possible to read expired cache records + * (for doNotTestCacheValidity option for example)) + * - priority does the backend deal with priority when saving + * - infinite_lifetime (is infinite lifetime can work with this backend) + * - get_list (is it possible to get the list of cache ids and the complete list of tags) + * + * @return array associative of with capabilities + */ + public function getCapabilities() + { + return array( + 'automatic_cleaning' => false, + 'tags' => false, + 'expired_read' => false, + 'priority' => false, + 'infinite_lifetime' => false, + 'get_list' => true + ); + } + +} diff --git a/library/vendor/Zend/Cache/Backend/BlackHole.php b/library/vendor/Zend/Cache/Backend/BlackHole.php new file mode 100644 index 0000000..8732c19 --- /dev/null +++ b/library/vendor/Zend/Cache/Backend/BlackHole.php @@ -0,0 +1,248 @@ + infinite lifetime) + * @return boolean true if no problem + */ + public function save($data, $id, $tags = array(), $specificLifetime = false) + { + return true; + } + + /** + * Remove a cache record + * + * @param string $id cache id + * @return boolean true if no problem + */ + public function remove($id) + { + return true; + } + + /** + * Clean some cache records + * + * Available modes are : + * 'all' (default) => remove all cache entries ($tags is not used) + * 'old' => remove too old cache entries ($tags is not used) + * 'matchingTag' => remove cache entries matching all given tags + * ($tags can be an array of strings or a single string) + * 'notMatchingTag' => remove cache entries not matching one of the given tags + * ($tags can be an array of strings or a single string) + * 'matchingAnyTag' => remove cache entries matching any given tags + * ($tags can be an array of strings or a single string) + * + * @param string $mode clean mode + * @param tags array $tags array of tags + * @return boolean true if no problem + */ + public function clean($mode = Zend_Cache::CLEANING_MODE_ALL, $tags = array()) + { + return true; + } + + /** + * Return an array of stored cache ids + * + * @return array array of stored cache ids (string) + */ + public function getIds() + { + return array(); + } + + /** + * Return an array of stored tags + * + * @return array array of stored tags (string) + */ + public function getTags() + { + return array(); + } + + /** + * Return an array of stored cache ids which match given tags + * + * In case of multiple tags, a logical AND is made between tags + * + * @param array $tags array of tags + * @return array array of matching cache ids (string) + */ + public function getIdsMatchingTags($tags = array()) + { + return array(); + } + + /** + * Return an array of stored cache ids which don't match given tags + * + * In case of multiple tags, a logical OR is made between tags + * + * @param array $tags array of tags + * @return array array of not matching cache ids (string) + */ + public function getIdsNotMatchingTags($tags = array()) + { + return array(); + } + + /** + * Return an array of stored cache ids which match any given tags + * + * In case of multiple tags, a logical AND is made between tags + * + * @param array $tags array of tags + * @return array array of any matching cache ids (string) + */ + public function getIdsMatchingAnyTags($tags = array()) + { + return array(); + } + + /** + * Return the filling percentage of the backend storage + * + * @return int integer between 0 and 100 + * @throws Zend_Cache_Exception + */ + public function getFillingPercentage() + { + return 0; + } + + /** + * Return an array of metadatas for the given cache id + * + * The array must include these keys : + * - expire : the expire timestamp + * - tags : a string array of tags + * - mtime : timestamp of last modification time + * + * @param string $id cache id + * @return array array of metadatas (false if the cache id is not found) + */ + public function getMetadatas($id) + { + return false; + } + + /** + * Give (if possible) an extra lifetime to the given cache id + * + * @param string $id cache id + * @param int $extraLifetime + * @return boolean true if ok + */ + public function touch($id, $extraLifetime) + { + return false; + } + + /** + * Return an associative array of capabilities (booleans) of the backend + * + * The array must include these keys : + * - automatic_cleaning (is automating cleaning necessary) + * - tags (are tags supported) + * - expired_read (is it possible to read expired cache records + * (for doNotTestCacheValidity option for example)) + * - priority does the backend deal with priority when saving + * - infinite_lifetime (is infinite lifetime can work with this backend) + * - get_list (is it possible to get the list of cache ids and the complete list of tags) + * + * @return array associative of with capabilities + */ + public function getCapabilities() + { + return array( + 'automatic_cleaning' => true, + 'tags' => true, + 'expired_read' => true, + 'priority' => true, + 'infinite_lifetime' => true, + 'get_list' => true, + ); + } + + /** + * PUBLIC METHOD FOR UNIT TESTING ONLY ! + * + * Force a cache record to expire + * + * @param string $id cache id + */ + public function ___expire($id) + { + } +} diff --git a/library/vendor/Zend/Cache/Backend/ExtendedInterface.php b/library/vendor/Zend/Cache/Backend/ExtendedInterface.php new file mode 100644 index 0000000..2f0f526 --- /dev/null +++ b/library/vendor/Zend/Cache/Backend/ExtendedInterface.php @@ -0,0 +1,125 @@ + (string) cache_dir : + * - Directory where to put the cache files + * + * =====> (boolean) file_locking : + * - Enable / disable file_locking + * - Can avoid cache corruption under bad circumstances but it doesn't work on multithread + * webservers and on NFS filesystems for example + * + * =====> (boolean) read_control : + * - Enable / disable read control + * - If enabled, a control key is embeded in cache file and this key is compared with the one + * calculated after the reading. + * + * =====> (string) read_control_type : + * - Type of read control (only if read control is enabled). Available values are : + * 'md5' for a md5 hash control (best but slowest) + * 'crc32' for a crc32 hash control (lightly less safe but faster, better choice) + * 'adler32' for an adler32 hash control (excellent choice too, faster than crc32) + * 'strlen' for a length only test (fastest) + * + * =====> (int) hashed_directory_level : + * - Hashed directory level + * - Set the hashed directory structure level. 0 means "no hashed directory + * structure", 1 means "one level of directory", 2 means "two levels"... + * This option can speed up the cache only when you have many thousands of + * cache file. Only specific benchs can help you to choose the perfect value + * for you. Maybe, 1 or 2 is a good start. + * + * =====> (int) hashed_directory_umask : + * - deprecated + * - Permissions for hashed directory structure + * + * =====> (int) hashed_directory_perm : + * - Permissions for hashed directory structure + * + * =====> (string) file_name_prefix : + * - prefix for cache files + * - be really carefull with this option because a too generic value in a system cache dir + * (like /tmp) can cause disasters when cleaning the cache + * + * =====> (int) cache_file_umask : + * - deprecated + * - Permissions for cache files + * + * =====> (int) cache_file_perm : + * - Permissions for cache files + * + * =====> (int) metatadatas_array_max_size : + * - max size for the metadatas array (don't change this value unless you + * know what you are doing) + * + * @var array available options + */ + protected $_options = array( + 'cache_dir' => null, + 'file_locking' => true, + 'read_control' => true, + 'read_control_type' => 'crc32', + 'hashed_directory_level' => 0, + 'hashed_directory_perm' => 0700, + 'file_name_prefix' => 'zend_cache', + 'cache_file_perm' => 0600, + 'metadatas_array_max_size' => 100 + ); + + /** + * Array of metadatas (each item is an associative array) + * + * @var array + */ + protected $_metadatasArray = array(); + + + /** + * Constructor + * + * @param array $options associative array of options + * @throws Zend_Cache_Exception + */ + public function __construct(array $options = array()) + { + parent::__construct($options); + if ($this->_options['cache_dir'] !== null) { // particular case for this option + $this->setCacheDir($this->_options['cache_dir']); + } else { + $this->setCacheDir(self::getTmpDir() . DIRECTORY_SEPARATOR, false); + } + if (isset($this->_options['file_name_prefix'])) { // particular case for this option + if (!preg_match('~^[a-zA-Z0-9_]+$~D', $this->_options['file_name_prefix'])) { + Zend_Cache::throwException('Invalid file_name_prefix : must use only [a-zA-Z0-9_]'); + } + } + if ($this->_options['metadatas_array_max_size'] < 10) { + Zend_Cache::throwException('Invalid metadatas_array_max_size, must be > 10'); + } + + if (isset($options['hashed_directory_umask'])) { + // See #ZF-12047 + trigger_error("'hashed_directory_umask' is deprecated -> please use 'hashed_directory_perm' instead", E_USER_NOTICE); + if (!isset($options['hashed_directory_perm'])) { + $options['hashed_directory_perm'] = $options['hashed_directory_umask']; + } + } + if (isset($options['hashed_directory_perm']) && is_string($options['hashed_directory_perm'])) { + // See #ZF-4422 + $this->_options['hashed_directory_perm'] = octdec($this->_options['hashed_directory_perm']); + } + + if (isset($options['cache_file_umask'])) { + // See #ZF-12047 + trigger_error("'cache_file_umask' is deprecated -> please use 'cache_file_perm' instead", E_USER_NOTICE); + if (!isset($options['cache_file_perm'])) { + $options['cache_file_perm'] = $options['cache_file_umask']; + } + } + if (isset($options['cache_file_perm']) && is_string($options['cache_file_perm'])) { + // See #ZF-4422 + $this->_options['cache_file_perm'] = octdec($this->_options['cache_file_perm']); + } + } + + /** + * Set the cache_dir (particular case of setOption() method) + * + * @param string $value + * @param boolean $trailingSeparator If true, add a trailing separator is necessary + * @throws Zend_Cache_Exception + * @return void + */ + public function setCacheDir($value, $trailingSeparator = true) + { + if (!is_dir($value)) { + Zend_Cache::throwException(sprintf('cache_dir "%s" must be a directory', $value)); + } + if (!is_writable($value)) { + Zend_Cache::throwException(sprintf('cache_dir "%s" is not writable', $value)); + } + if ($trailingSeparator) { + // add a trailing DIRECTORY_SEPARATOR if necessary + $value = rtrim(realpath($value), '\\/') . DIRECTORY_SEPARATOR; + } + $this->_options['cache_dir'] = $value; + } + + /** + * Test if a cache is available for the given id and (if yes) return it (false else) + * + * @param string $id cache id + * @param boolean $doNotTestCacheValidity if set to true, the cache validity won't be tested + * @return string|false cached datas + */ + public function load($id, $doNotTestCacheValidity = false) + { + if (!($this->_test($id, $doNotTestCacheValidity))) { + // The cache is not hit ! + return false; + } + $metadatas = $this->_getMetadatas($id); + $file = $this->_file($id); + $data = $this->_fileGetContents($file); + if ($this->_options['read_control']) { + $hashData = $this->_hash($data, $this->_options['read_control_type']); + $hashControl = $metadatas['hash']; + if ($hashData != $hashControl) { + // Problem detected by the read control ! + $this->_log('Zend_Cache_Backend_File::load() / read_control : stored hash and computed hash do not match'); + $this->remove($id); + return false; + } + } + return $data; + } + + /** + * Test if a cache is available or not (for the given id) + * + * @param string $id cache id + * @return mixed false (a cache is not available) or "last modified" timestamp (int) of the available cache record + */ + public function test($id) + { + clearstatcache(); + return $this->_test($id, false); + } + + /** + * Save some string datas into a cache record + * + * Note : $data is always "string" (serialization is done by the + * core not by the backend) + * + * @param string $data Datas to cache + * @param string $id Cache id + * @param array $tags Array of strings, the cache record will be tagged by each string entry + * @param boolean|int $specificLifetime If != false, set a specific lifetime for this cache record (null => infinite lifetime) + * @return boolean true if no problem + */ + public function save($data, $id, $tags = array(), $specificLifetime = false) + { + clearstatcache(); + $file = $this->_file($id); + $path = $this->_path($id); + if ($this->_options['hashed_directory_level'] > 0) { + if (!is_writable($path)) { + // maybe, we just have to build the directory structure + $this->_recursiveMkdirAndChmod($id); + } + if (!is_writable($path)) { + return false; + } + } + if ($this->_options['read_control']) { + $hash = $this->_hash($data, $this->_options['read_control_type']); + } else { + $hash = ''; + } + $metadatas = array( + 'hash' => $hash, + 'mtime' => time(), + 'expire' => $this->_expireTime($this->getLifetime($specificLifetime)), + 'tags' => $tags + ); + $res = $this->_setMetadatas($id, $metadatas); + if (!$res) { + $this->_log('Zend_Cache_Backend_File::save() / error on saving metadata'); + return false; + } + $res = $this->_filePutContents($file, $data); + return $res; + } + + /** + * Remove a cache record + * + * @param string $id cache id + * @return boolean true if no problem + */ + public function remove($id) + { + $file = $this->_file($id); + $boolRemove = $this->_remove($file); + $boolMetadata = $this->_delMetadatas($id); + return $boolMetadata && $boolRemove; + } + + /** + * Clean some cache records + * + * Available modes are : + * + * Zend_Cache::CLEANING_MODE_ALL (default) => remove all cache entries ($tags is not used) + * Zend_Cache::CLEANING_MODE_OLD => remove too old cache entries ($tags is not used) + * Zend_Cache::CLEANING_MODE_MATCHING_TAG => remove cache entries matching all given tags + * ($tags can be an array of strings or a single string) + * Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG => remove cache entries not {matching one of the given tags} + * ($tags can be an array of strings or a single string) + * Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG => remove cache entries matching any given tags + * ($tags can be an array of strings or a single string) + * + * @param string $mode clean mode + * @param array $tags array of tags + * @return boolean true if no problem + */ + public function clean($mode = Zend_Cache::CLEANING_MODE_ALL, $tags = array()) + { + // We use this protected method to hide the recursive stuff + clearstatcache(); + return $this->_clean($this->_options['cache_dir'], $mode, $tags); + } + + /** + * Return an array of stored cache ids + * + * @return array array of stored cache ids (string) + */ + public function getIds() + { + return $this->_get($this->_options['cache_dir'], 'ids', array()); + } + + /** + * Return an array of stored tags + * + * @return array array of stored tags (string) + */ + public function getTags() + { + return $this->_get($this->_options['cache_dir'], 'tags', array()); + } + + /** + * Return an array of stored cache ids which match given tags + * + * In case of multiple tags, a logical AND is made between tags + * + * @param array $tags array of tags + * @return array array of matching cache ids (string) + */ + public function getIdsMatchingTags($tags = array()) + { + return $this->_get($this->_options['cache_dir'], 'matching', $tags); + } + + /** + * Return an array of stored cache ids which don't match given tags + * + * In case of multiple tags, a logical OR is made between tags + * + * @param array $tags array of tags + * @return array array of not matching cache ids (string) + */ + public function getIdsNotMatchingTags($tags = array()) + { + return $this->_get($this->_options['cache_dir'], 'notMatching', $tags); + } + + /** + * Return an array of stored cache ids which match any given tags + * + * In case of multiple tags, a logical AND is made between tags + * + * @param array $tags array of tags + * @return array array of any matching cache ids (string) + */ + public function getIdsMatchingAnyTags($tags = array()) + { + return $this->_get($this->_options['cache_dir'], 'matchingAny', $tags); + } + + /** + * Return the filling percentage of the backend storage + * + * @throws Zend_Cache_Exception + * @return int integer between 0 and 100 + */ + public function getFillingPercentage() + { + $free = disk_free_space($this->_options['cache_dir']); + $total = disk_total_space($this->_options['cache_dir']); + if ($total == 0) { + Zend_Cache::throwException('can\'t get disk_total_space'); + } else { + if ($free >= $total) { + return 100; + } + return ((int) (100. * ($total - $free) / $total)); + } + } + + /** + * Return an array of metadatas for the given cache id + * + * The array must include these keys : + * - expire : the expire timestamp + * - tags : a string array of tags + * - mtime : timestamp of last modification time + * + * @param string $id cache id + * @return array array of metadatas (false if the cache id is not found) + */ + public function getMetadatas($id) + { + $metadatas = $this->_getMetadatas($id); + if (!$metadatas) { + return false; + } + if (time() > $metadatas['expire']) { + return false; + } + return array( + 'expire' => $metadatas['expire'], + 'tags' => $metadatas['tags'], + 'mtime' => $metadatas['mtime'] + ); + } + + /** + * Give (if possible) an extra lifetime to the given cache id + * + * @param string $id cache id + * @param int $extraLifetime + * @return boolean true if ok + */ + public function touch($id, $extraLifetime) + { + $metadatas = $this->_getMetadatas($id); + if (!$metadatas) { + return false; + } + if (time() > $metadatas['expire']) { + return false; + } + $newMetadatas = array( + 'hash' => $metadatas['hash'], + 'mtime' => time(), + 'expire' => $metadatas['expire'] + $extraLifetime, + 'tags' => $metadatas['tags'] + ); + $res = $this->_setMetadatas($id, $newMetadatas); + if (!$res) { + return false; + } + return true; + } + + /** + * Return an associative array of capabilities (booleans) of the backend + * + * The array must include these keys : + * - automatic_cleaning (is automating cleaning necessary) + * - tags (are tags supported) + * - expired_read (is it possible to read expired cache records + * (for doNotTestCacheValidity option for example)) + * - priority does the backend deal with priority when saving + * - infinite_lifetime (is infinite lifetime can work with this backend) + * - get_list (is it possible to get the list of cache ids and the complete list of tags) + * + * @return array associative of with capabilities + */ + public function getCapabilities() + { + return array( + 'automatic_cleaning' => true, + 'tags' => true, + 'expired_read' => true, + 'priority' => false, + 'infinite_lifetime' => true, + 'get_list' => true + ); + } + + /** + * PUBLIC METHOD FOR UNIT TESTING ONLY ! + * + * Force a cache record to expire + * + * @param string $id cache id + */ + public function ___expire($id) + { + $metadatas = $this->_getMetadatas($id); + if ($metadatas) { + $metadatas['expire'] = 1; + $this->_setMetadatas($id, $metadatas); + } + } + + /** + * Get a metadatas record + * + * @param string $id Cache id + * @return array|false Associative array of metadatas + */ + protected function _getMetadatas($id) + { + if (isset($this->_metadatasArray[$id])) { + return $this->_metadatasArray[$id]; + } else { + $metadatas = $this->_loadMetadatas($id); + if (!$metadatas) { + return false; + } + $this->_setMetadatas($id, $metadatas, false); + return $metadatas; + } + } + + /** + * Set a metadatas record + * + * @param string $id Cache id + * @param array $metadatas Associative array of metadatas + * @param boolean $save optional pass false to disable saving to file + * @return boolean True if no problem + */ + protected function _setMetadatas($id, $metadatas, $save = true) + { + if (count($this->_metadatasArray) >= $this->_options['metadatas_array_max_size']) { + $n = (int) ($this->_options['metadatas_array_max_size'] / 10); + $this->_metadatasArray = array_slice($this->_metadatasArray, $n); + } + if ($save) { + $result = $this->_saveMetadatas($id, $metadatas); + if (!$result) { + return false; + } + } + $this->_metadatasArray[$id] = $metadatas; + return true; + } + + /** + * Drop a metadata record + * + * @param string $id Cache id + * @return boolean True if no problem + */ + protected function _delMetadatas($id) + { + if (isset($this->_metadatasArray[$id])) { + unset($this->_metadatasArray[$id]); + } + $file = $this->_metadatasFile($id); + return $this->_remove($file); + } + + /** + * Clear the metadatas array + * + * @return void + */ + protected function _cleanMetadatas() + { + $this->_metadatasArray = array(); + } + + /** + * Load metadatas from disk + * + * @param string $id Cache id + * @return array|false Metadatas associative array + */ + protected function _loadMetadatas($id) + { + $file = $this->_metadatasFile($id); + $result = $this->_fileGetContents($file); + if (!$result) { + return false; + } + $tmp = @unserialize($result); + return $tmp; + } + + /** + * Save metadatas to disk + * + * @param string $id Cache id + * @param array $metadatas Associative array + * @return boolean True if no problem + */ + protected function _saveMetadatas($id, $metadatas) + { + $file = $this->_metadatasFile($id); + $result = $this->_filePutContents($file, serialize($metadatas)); + if (!$result) { + return false; + } + return true; + } + + /** + * Make and return a file name (with path) for metadatas + * + * @param string $id Cache id + * @return string Metadatas file name (with path) + */ + protected function _metadatasFile($id) + { + $path = $this->_path($id); + $fileName = $this->_idToFileName('internal-metadatas---' . $id); + return $path . $fileName; + } + + /** + * Check if the given filename is a metadatas one + * + * @param string $fileName File name + * @return boolean True if it's a metadatas one + */ + protected function _isMetadatasFile($fileName) + { + $id = $this->_fileNameToId($fileName); + if (substr($id, 0, 21) == 'internal-metadatas---') { + return true; + } else { + return false; + } + } + + /** + * Remove a file + * + * If we can't remove the file (because of locks or any problem), we will touch + * the file to invalidate it + * + * @param string $file Complete file path + * @return boolean True if ok + */ + protected function _remove($file) + { + if (!is_file($file)) { + return false; + } + if (!@unlink($file)) { + # we can't remove the file (because of locks or any problem) + $this->_log("Zend_Cache_Backend_File::_remove() : we can't remove $file"); + return false; + } + return true; + } + + /** + * Clean some cache records (protected method used for recursive stuff) + * + * Available modes are : + * Zend_Cache::CLEANING_MODE_ALL (default) => remove all cache entries ($tags is not used) + * Zend_Cache::CLEANING_MODE_OLD => remove too old cache entries ($tags is not used) + * Zend_Cache::CLEANING_MODE_MATCHING_TAG => remove cache entries matching all given tags + * ($tags can be an array of strings or a single string) + * Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG => remove cache entries not {matching one of the given tags} + * ($tags can be an array of strings or a single string) + * Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG => remove cache entries matching any given tags + * ($tags can be an array of strings or a single string) + * + * @param string $dir Directory to clean + * @param string $mode Clean mode + * @param array $tags Array of tags + * @throws Zend_Cache_Exception + * @return boolean True if no problem + */ + protected function _clean($dir, $mode = Zend_Cache::CLEANING_MODE_ALL, $tags = array()) + { + if (!is_dir($dir)) { + return false; + } + $result = true; + $prefix = $this->_options['file_name_prefix']; + $glob = @glob($dir . $prefix . '--*'); + if ($glob === false) { + // On some systems it is impossible to distinguish between empty match and an error. + return true; + } + $metadataFiles = array(); + foreach ($glob as $file) { + if (is_file($file)) { + $fileName = basename($file); + if ($this->_isMetadatasFile($fileName)) { + // In CLEANING_MODE_ALL, we drop anything, even remainings old metadatas files. + // To do that, we need to save the list of the metadata files first. + if ($mode == Zend_Cache::CLEANING_MODE_ALL) { + $metadataFiles[] = $file; + } + continue; + } + $id = $this->_fileNameToId($fileName); + $metadatas = $this->_getMetadatas($id); + if ($metadatas === FALSE) { + $metadatas = array('expire' => 1, 'tags' => array()); + } + switch ($mode) { + case Zend_Cache::CLEANING_MODE_ALL: + $result = $result && $this->remove($id); + break; + case Zend_Cache::CLEANING_MODE_OLD: + if (time() > $metadatas['expire']) { + $result = $this->remove($id) && $result; + } + break; + case Zend_Cache::CLEANING_MODE_MATCHING_TAG: + $matching = true; + foreach ($tags as $tag) { + if (!in_array($tag, $metadatas['tags'])) { + $matching = false; + break; + } + } + if ($matching) { + $result = $this->remove($id) && $result; + } + break; + case Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG: + $matching = false; + foreach ($tags as $tag) { + if (in_array($tag, $metadatas['tags'])) { + $matching = true; + break; + } + } + if (!$matching) { + $result = $this->remove($id) && $result; + } + break; + case Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG: + $matching = false; + foreach ($tags as $tag) { + if (in_array($tag, $metadatas['tags'])) { + $matching = true; + break; + } + } + if ($matching) { + $result = $this->remove($id) && $result; + } + break; + default: + Zend_Cache::throwException('Invalid mode for clean() method'); + break; + } + } + if ((is_dir($file)) and ($this->_options['hashed_directory_level']>0)) { + // Recursive call + $result = $this->_clean($file . DIRECTORY_SEPARATOR, $mode, $tags) && $result; + if ($mode == Zend_Cache::CLEANING_MODE_ALL) { + // we try to drop the structure too + @rmdir($file); + } + } + } + + // cycle through metadataFiles and delete orphaned ones + foreach ($metadataFiles as $file) { + if (file_exists($file)) { + $result = $this->_remove($file) && $result; + } + } + + return $result; + } + + protected function _get($dir, $mode, $tags = array()) + { + if (!is_dir($dir)) { + return false; + } + $result = array(); + $prefix = $this->_options['file_name_prefix']; + $glob = @glob($dir . $prefix . '--*'); + if ($glob === false) { + // On some systems it is impossible to distinguish between empty match and an error. + return array(); + } + foreach ($glob as $file) { + if (is_file($file)) { + $fileName = basename($file); + $id = $this->_fileNameToId($fileName); + $metadatas = $this->_getMetadatas($id); + if ($metadatas === FALSE) { + continue; + } + if (time() > $metadatas['expire']) { + continue; + } + switch ($mode) { + case 'ids': + $result[] = $id; + break; + case 'tags': + $result = array_unique(array_merge($result, $metadatas['tags'])); + break; + case 'matching': + $matching = true; + foreach ($tags as $tag) { + if (!in_array($tag, $metadatas['tags'])) { + $matching = false; + break; + } + } + if ($matching) { + $result[] = $id; + } + break; + case 'notMatching': + $matching = false; + foreach ($tags as $tag) { + if (in_array($tag, $metadatas['tags'])) { + $matching = true; + break; + } + } + if (!$matching) { + $result[] = $id; + } + break; + case 'matchingAny': + $matching = false; + foreach ($tags as $tag) { + if (in_array($tag, $metadatas['tags'])) { + $matching = true; + break; + } + } + if ($matching) { + $result[] = $id; + } + break; + default: + Zend_Cache::throwException('Invalid mode for _get() method'); + break; + } + } + if ((is_dir($file)) and ($this->_options['hashed_directory_level']>0)) { + // Recursive call + $recursiveRs = $this->_get($file . DIRECTORY_SEPARATOR, $mode, $tags); + if ($recursiveRs === false) { + $this->_log('Zend_Cache_Backend_File::_get() / recursive call : can\'t list entries of "'.$file.'"'); + } else { + $result = array_unique(array_merge($result, $recursiveRs)); + } + } + } + return array_unique($result); + } + + /** + * Compute & return the expire time + * + * @param int $lifetime + * @return int expire time (unix timestamp) + */ + protected function _expireTime($lifetime) + { + if ($lifetime === null) { + return 9999999999; + } + return time() + $lifetime; + } + + /** + * Make a control key with the string containing datas + * + * @param string $data Data + * @param string $controlType Type of control 'md5', 'crc32' or 'strlen' + * @throws Zend_Cache_Exception + * @return string Control key + */ + protected function _hash($data, $controlType) + { + switch ($controlType) { + case 'md5': + return md5($data); + case 'crc32': + return crc32($data); + case 'strlen': + return strlen($data); + case 'adler32': + return hash('adler32', $data); + default: + Zend_Cache::throwException("Incorrect hash function : $controlType"); + } + } + + /** + * Transform a cache id into a file name and return it + * + * @param string $id Cache id + * @return string File name + */ + protected function _idToFileName($id) + { + $prefix = $this->_options['file_name_prefix']; + $result = $prefix . '---' . $id; + return $result; + } + + /** + * Make and return a file name (with path) + * + * @param string $id Cache id + * @return string File name (with path) + */ + protected function _file($id) + { + $path = $this->_path($id); + $fileName = $this->_idToFileName($id); + return $path . $fileName; + } + + /** + * Return the complete directory path of a filename (including hashedDirectoryStructure) + * + * @param string $id Cache id + * @param boolean $parts if true, returns array of directory parts instead of single string + * @return string Complete directory path + */ + protected function _path($id, $parts = false) + { + $partsArray = array(); + $root = $this->_options['cache_dir']; + $prefix = $this->_options['file_name_prefix']; + if ($this->_options['hashed_directory_level']>0) { + $hash = hash('adler32', $id); + for ($i=0 ; $i < $this->_options['hashed_directory_level'] ; $i++) { + $root = $root . $prefix . '--' . substr($hash, 0, $i + 1) . DIRECTORY_SEPARATOR; + $partsArray[] = $root; + } + } + if ($parts) { + return $partsArray; + } else { + return $root; + } + } + + /** + * Make the directory strucuture for the given id + * + * @param string $id cache id + * @return boolean true + */ + protected function _recursiveMkdirAndChmod($id) + { + if ($this->_options['hashed_directory_level'] <=0) { + return true; + } + $partsArray = $this->_path($id, true); + foreach ($partsArray as $part) { + if (!is_dir($part)) { + @mkdir($part, $this->_options['hashed_directory_perm']); + @chmod($part, $this->_options['hashed_directory_perm']); // see #ZF-320 (this line is required in some configurations) + } + } + return true; + } + + /** + * Test if the given cache id is available (and still valid as a cache record) + * + * @param string $id Cache id + * @param boolean $doNotTestCacheValidity If set to true, the cache validity won't be tested + * @return boolean|mixed false (a cache is not available) or "last modified" timestamp (int) of the available cache record + */ + protected function _test($id, $doNotTestCacheValidity) + { + $metadatas = $this->_getMetadatas($id); + if (!$metadatas) { + return false; + } + if ($doNotTestCacheValidity || (time() <= $metadatas['expire'])) { + return $metadatas['mtime']; + } + return false; + } + + /** + * Return the file content of the given file + * + * @param string $file File complete path + * @return string File content (or false if problem) + */ + protected function _fileGetContents($file) + { + $result = false; + if (!is_file($file)) { + return false; + } + $f = @fopen($file, 'rb'); + if ($f) { + if ($this->_options['file_locking']) @flock($f, LOCK_SH); + $result = stream_get_contents($f); + if ($this->_options['file_locking']) @flock($f, LOCK_UN); + @fclose($f); + } + return $result; + } + + /** + * Put the given string into the given file + * + * @param string $file File complete path + * @param string $string String to put in file + * @return boolean true if no problem + */ + protected function _filePutContents($file, $string) + { + $result = false; + $f = @fopen($file, 'ab+'); + if ($f) { + if ($this->_options['file_locking']) @flock($f, LOCK_EX); + fseek($f, 0); + ftruncate($f, 0); + $tmp = @fwrite($f, $string); + if (!($tmp === FALSE)) { + $result = true; + } + @fclose($f); + } + @chmod($file, $this->_options['cache_file_perm']); + return $result; + } + + /** + * Transform a file name into cache id and return it + * + * @param string $fileName File name + * @return string Cache id + */ + protected function _fileNameToId($fileName) + { + $prefix = $this->_options['file_name_prefix']; + return preg_replace('~^' . $prefix . '---(.*)$~', '$1', $fileName); + } + +} diff --git a/library/vendor/Zend/Cache/Backend/Interface.php b/library/vendor/Zend/Cache/Backend/Interface.php new file mode 100644 index 0000000..1bd72d8 --- /dev/null +++ b/library/vendor/Zend/Cache/Backend/Interface.php @@ -0,0 +1,99 @@ + infinite lifetime) + * @return boolean true if no problem + */ + public function save($data, $id, $tags = array(), $specificLifetime = false); + + /** + * Remove a cache record + * + * @param string $id Cache id + * @return boolean True if no problem + */ + public function remove($id); + + /** + * Clean some cache records + * + * Available modes are : + * Zend_Cache::CLEANING_MODE_ALL (default) => remove all cache entries ($tags is not used) + * Zend_Cache::CLEANING_MODE_OLD => remove too old cache entries ($tags is not used) + * Zend_Cache::CLEANING_MODE_MATCHING_TAG => remove cache entries matching all given tags + * ($tags can be an array of strings or a single string) + * Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG => remove cache entries not {matching one of the given tags} + * ($tags can be an array of strings or a single string) + * Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG => remove cache entries matching any given tags + * ($tags can be an array of strings or a single string) + * + * @param string $mode Clean mode + * @param array $tags Array of tags + * @return boolean true if no problem + */ + public function clean($mode = Zend_Cache::CLEANING_MODE_ALL, $tags = array()); + +} diff --git a/library/vendor/Zend/Cache/Backend/Libmemcached.php b/library/vendor/Zend/Cache/Backend/Libmemcached.php new file mode 100644 index 0000000..ca1f695 --- /dev/null +++ b/library/vendor/Zend/Cache/Backend/Libmemcached.php @@ -0,0 +1,482 @@ + (array) servers : + * an array of memcached server ; each memcached server is described by an associative array : + * 'host' => (string) : the name of the memcached server + * 'port' => (int) : the port of the memcached server + * 'weight' => (int) : number of buckets to create for this server which in turn control its + * probability of it being selected. The probability is relative to the total + * weight of all servers. + * =====> (array) client : + * an array of memcached client options ; the memcached client is described by an associative array : + * @see http://php.net/manual/memcached.constants.php + * - The option name can be the name of the constant without the prefix 'OPT_' + * or the integer value of this option constant + * + * @var array available options + */ + protected $_options = array( + 'servers' => array(array( + 'host' => self::DEFAULT_HOST, + 'port' => self::DEFAULT_PORT, + 'weight' => self::DEFAULT_WEIGHT, + )), + 'client' => array() + ); + + /** + * Memcached object + * + * @var mixed memcached object + */ + protected $_memcache = null; + + /** + * Constructor + * + * @param array $options associative array of options + * @throws Zend_Cache_Exception + * @return void + */ + public function __construct(array $options = array()) + { + if (!extension_loaded('memcached')) { + Zend_Cache::throwException('The memcached extension must be loaded for using this backend !'); + } + + // override default client options + $this->_options['client'] = array( + Memcached::OPT_DISTRIBUTION => Memcached::DISTRIBUTION_CONSISTENT, + Memcached::OPT_HASH => Memcached::HASH_MD5, + Memcached::OPT_LIBKETAMA_COMPATIBLE => true, + ); + + parent::__construct($options); + + if (isset($this->_options['servers'])) { + $value = $this->_options['servers']; + if (isset($value['host'])) { + // in this case, $value seems to be a simple associative array (one server only) + $value = array(0 => $value); // let's transform it into a classical array of associative arrays + } + $this->setOption('servers', $value); + } + $this->_memcache = new Memcached; + + // setup memcached client options + foreach ($this->_options['client'] as $name => $value) { + $optId = null; + if (is_int($name)) { + $optId = $name; + } else { + $optConst = 'Memcached::OPT_' . strtoupper($name); + if (defined($optConst)) { + $optId = constant($optConst); + } else { + $this->_log("Unknown memcached client option '{$name}' ({$optConst})"); + } + } + if (null !== $optId) { + if (!$this->_memcache->setOption($optId, $value)) { + $this->_log("Setting memcached client option '{$optId}' failed"); + } + } + } + + // setup memcached servers + $servers = array(); + foreach ($this->_options['servers'] as $server) { + if (!array_key_exists('port', $server)) { + $server['port'] = self::DEFAULT_PORT; + } + if (!array_key_exists('weight', $server)) { + $server['weight'] = self::DEFAULT_WEIGHT; + } + + $servers[] = array($server['host'], $server['port'], $server['weight']); + } + $this->_memcache->addServers($servers); + } + + /** + * Test if a cache is available for the given id and (if yes) return it (false else) + * + * @param string $id Cache id + * @param boolean $doNotTestCacheValidity If set to true, the cache validity won't be tested + * @return string|false cached datas + */ + public function load($id, $doNotTestCacheValidity = false) + { + $tmp = $this->_memcache->get($id); + if (isset($tmp[0])) { + return $tmp[0]; + } + return false; + } + + /** + * Test if a cache is available or not (for the given id) + * + * @param string $id Cache id + * @return int|false (a cache is not available) or "last modified" timestamp (int) of the available cache record + */ + public function test($id) + { + $tmp = $this->_memcache->get($id); + if (isset($tmp[0], $tmp[1])) { + return (int)$tmp[1]; + } + return false; + } + + /** + * Save some string datas into a cache record + * + * Note : $data is always "string" (serialization is done by the + * core not by the backend) + * + * @param string $data Datas to cache + * @param string $id Cache id + * @param array $tags Array of strings, the cache record will be tagged by each string entry + * @param int $specificLifetime If != false, set a specific lifetime for this cache record (null => infinite lifetime) + * @return boolean True if no problem + */ + public function save($data, $id, $tags = array(), $specificLifetime = false) + { + $lifetime = $this->getLifetime($specificLifetime); + + // ZF-8856: using set because add needs a second request if item already exists + $result = @$this->_memcache->set($id, array($data, time(), $lifetime), $lifetime); + if ($result === false) { + $rsCode = $this->_memcache->getResultCode(); + $rsMsg = $this->_memcache->getResultMessage(); + $this->_log("Memcached::set() failed: [{$rsCode}] {$rsMsg}"); + } + + if (count($tags) > 0) { + $this->_log(self::TAGS_UNSUPPORTED_BY_SAVE_OF_LIBMEMCACHED_BACKEND); + } + + return $result; + } + + /** + * Remove a cache record + * + * @param string $id Cache id + * @return boolean True if no problem + */ + public function remove($id) + { + return $this->_memcache->delete($id); + } + + /** + * Clean some cache records + * + * Available modes are : + * 'all' (default) => remove all cache entries ($tags is not used) + * 'old' => unsupported + * 'matchingTag' => unsupported + * 'notMatchingTag' => unsupported + * 'matchingAnyTag' => unsupported + * + * @param string $mode Clean mode + * @param array $tags Array of tags + * @throws Zend_Cache_Exception + * @return boolean True if no problem + */ + public function clean($mode = Zend_Cache::CLEANING_MODE_ALL, $tags = array()) + { + switch ($mode) { + case Zend_Cache::CLEANING_MODE_ALL: + return $this->_memcache->flush(); + break; + case Zend_Cache::CLEANING_MODE_OLD: + $this->_log("Zend_Cache_Backend_Libmemcached::clean() : CLEANING_MODE_OLD is unsupported by the Libmemcached backend"); + break; + case Zend_Cache::CLEANING_MODE_MATCHING_TAG: + case Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG: + case Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG: + $this->_log(self::TAGS_UNSUPPORTED_BY_CLEAN_OF_LIBMEMCACHED_BACKEND); + break; + default: + Zend_Cache::throwException('Invalid mode for clean() method'); + break; + } + } + + /** + * Return true if the automatic cleaning is available for the backend + * + * @return boolean + */ + public function isAutomaticCleaningAvailable() + { + return false; + } + + /** + * Set the frontend directives + * + * @param array $directives Assoc of directives + * @throws Zend_Cache_Exception + * @return void + */ + public function setDirectives($directives) + { + parent::setDirectives($directives); + $lifetime = $this->getLifetime(false); + if ($lifetime > 2592000) { + // #ZF-3490 : For the memcached backend, there is a lifetime limit of 30 days (2592000 seconds) + $this->_log('memcached backend has a limit of 30 days (2592000 seconds) for the lifetime'); + } + if ($lifetime === null) { + // #ZF-4614 : we tranform null to zero to get the maximal lifetime + parent::setDirectives(array('lifetime' => 0)); + } + } + + /** + * Return an array of stored cache ids + * + * @return array array of stored cache ids (string) + */ + public function getIds() + { + $this->_log("Zend_Cache_Backend_Libmemcached::save() : getting the list of cache ids is unsupported by the Libmemcached backend"); + return array(); + } + + /** + * Return an array of stored tags + * + * @return array array of stored tags (string) + */ + public function getTags() + { + $this->_log(self::TAGS_UNSUPPORTED_BY_SAVE_OF_LIBMEMCACHED_BACKEND); + return array(); + } + + /** + * Return an array of stored cache ids which match given tags + * + * In case of multiple tags, a logical AND is made between tags + * + * @param array $tags array of tags + * @return array array of matching cache ids (string) + */ + public function getIdsMatchingTags($tags = array()) + { + $this->_log(self::TAGS_UNSUPPORTED_BY_SAVE_OF_LIBMEMCACHED_BACKEND); + return array(); + } + + /** + * Return an array of stored cache ids which don't match given tags + * + * In case of multiple tags, a logical OR is made between tags + * + * @param array $tags array of tags + * @return array array of not matching cache ids (string) + */ + public function getIdsNotMatchingTags($tags = array()) + { + $this->_log(self::TAGS_UNSUPPORTED_BY_SAVE_OF_LIBMEMCACHED_BACKEND); + return array(); + } + + /** + * Return an array of stored cache ids which match any given tags + * + * In case of multiple tags, a logical AND is made between tags + * + * @param array $tags array of tags + * @return array array of any matching cache ids (string) + */ + public function getIdsMatchingAnyTags($tags = array()) + { + $this->_log(self::TAGS_UNSUPPORTED_BY_SAVE_OF_LIBMEMCACHED_BACKEND); + return array(); + } + + /** + * Return the filling percentage of the backend storage + * + * @throws Zend_Cache_Exception + * @return int integer between 0 and 100 + */ + public function getFillingPercentage() + { + $mems = $this->_memcache->getStats(); + if ($mems === false) { + return 0; + } + + $memSize = null; + $memUsed = null; + foreach ($mems as $key => $mem) { + if ($mem === false) { + $this->_log('can\'t get stat from ' . $key); + continue; + } + + $eachSize = $mem['limit_maxbytes']; + $eachUsed = $mem['bytes']; + if ($eachUsed > $eachSize) { + $eachUsed = $eachSize; + } + + $memSize += $eachSize; + $memUsed += $eachUsed; + } + + if ($memSize === null || $memUsed === null) { + Zend_Cache::throwException('Can\'t get filling percentage'); + } + + return ((int) (100. * ($memUsed / $memSize))); + } + + /** + * Return an array of metadatas for the given cache id + * + * The array must include these keys : + * - expire : the expire timestamp + * - tags : a string array of tags + * - mtime : timestamp of last modification time + * + * @param string $id cache id + * @return array array of metadatas (false if the cache id is not found) + */ + public function getMetadatas($id) + { + $tmp = $this->_memcache->get($id); + if (isset($tmp[0], $tmp[1], $tmp[2])) { + $data = $tmp[0]; + $mtime = $tmp[1]; + $lifetime = $tmp[2]; + return array( + 'expire' => $mtime + $lifetime, + 'tags' => array(), + 'mtime' => $mtime + ); + } + + return false; + } + + /** + * Give (if possible) an extra lifetime to the given cache id + * + * @param string $id cache id + * @param int $extraLifetime + * @return boolean true if ok + */ + public function touch($id, $extraLifetime) + { + $tmp = $this->_memcache->get($id); + if (isset($tmp[0], $tmp[1], $tmp[2])) { + $data = $tmp[0]; + $mtime = $tmp[1]; + $lifetime = $tmp[2]; + $newLifetime = $lifetime - (time() - $mtime) + $extraLifetime; + if ($newLifetime <=0) { + return false; + } + // #ZF-5702 : we try replace() first becase set() seems to be slower + if (!($result = $this->_memcache->replace($id, array($data, time(), $newLifetime), $newLifetime))) { + $result = $this->_memcache->set($id, array($data, time(), $newLifetime), $newLifetime); + if ($result === false) { + $rsCode = $this->_memcache->getResultCode(); + $rsMsg = $this->_memcache->getResultMessage(); + $this->_log("Memcached::set() failed: [{$rsCode}] {$rsMsg}"); + } + } + return $result; + } + return false; + } + + /** + * Return an associative array of capabilities (booleans) of the backend + * + * The array must include these keys : + * - automatic_cleaning (is automating cleaning necessary) + * - tags (are tags supported) + * - expired_read (is it possible to read expired cache records + * (for doNotTestCacheValidity option for example)) + * - priority does the backend deal with priority when saving + * - infinite_lifetime (is infinite lifetime can work with this backend) + * - get_list (is it possible to get the list of cache ids and the complete list of tags) + * + * @return array associative of with capabilities + */ + public function getCapabilities() + { + return array( + 'automatic_cleaning' => false, + 'tags' => false, + 'expired_read' => false, + 'priority' => false, + 'infinite_lifetime' => false, + 'get_list' => false + ); + } + +} diff --git a/library/vendor/Zend/Cache/Backend/Memcached.php b/library/vendor/Zend/Cache/Backend/Memcached.php new file mode 100644 index 0000000..61ddfdc --- /dev/null +++ b/library/vendor/Zend/Cache/Backend/Memcached.php @@ -0,0 +1,507 @@ + (array) servers : + * an array of memcached server ; each memcached server is described by an associative array : + * 'host' => (string) : the name of the memcached server + * 'port' => (int) : the port of the memcached server + * 'persistent' => (bool) : use or not persistent connections to this memcached server + * 'weight' => (int) : number of buckets to create for this server which in turn control its + * probability of it being selected. The probability is relative to the total + * weight of all servers. + * 'timeout' => (int) : value in seconds which will be used for connecting to the daemon. Think twice + * before changing the default value of 1 second - you can lose all the + * advantages of caching if your connection is too slow. + * 'retry_interval' => (int) : controls how often a failed server will be retried, the default value + * is 15 seconds. Setting this parameter to -1 disables automatic retry. + * 'status' => (bool) : controls if the server should be flagged as online. + * 'failure_callback' => (callback) : Allows the user to specify a callback function to run upon + * encountering an error. The callback is run before failover + * is attempted. The function takes two parameters, the hostname + * and port of the failed server. + * + * =====> (boolean) compression : + * true if you want to use on-the-fly compression + * + * =====> (boolean) compatibility : + * true if you use old memcache server or extension + * + * @var array available options + */ + protected $_options = array( + 'servers' => array(array( + 'host' => self::DEFAULT_HOST, + 'port' => self::DEFAULT_PORT, + 'persistent' => self::DEFAULT_PERSISTENT, + 'weight' => self::DEFAULT_WEIGHT, + 'timeout' => self::DEFAULT_TIMEOUT, + 'retry_interval' => self::DEFAULT_RETRY_INTERVAL, + 'status' => self::DEFAULT_STATUS, + 'failure_callback' => self::DEFAULT_FAILURE_CALLBACK + )), + 'compression' => false, + 'compatibility' => false, + ); + + /** + * Memcache object + * + * @var mixed memcache object + */ + protected $_memcache = null; + + /** + * Constructor + * + * @param array $options associative array of options + * @throws Zend_Cache_Exception + * @return void + */ + public function __construct(array $options = array()) + { + if (!extension_loaded('memcache')) { + Zend_Cache::throwException('The memcache extension must be loaded for using this backend !'); + } + parent::__construct($options); + if (isset($this->_options['servers'])) { + $value= $this->_options['servers']; + if (isset($value['host'])) { + // in this case, $value seems to be a simple associative array (one server only) + $value = array(0 => $value); // let's transform it into a classical array of associative arrays + } + $this->setOption('servers', $value); + } + $this->_memcache = new Memcache; + foreach ($this->_options['servers'] as $server) { + if (!array_key_exists('port', $server)) { + $server['port'] = self::DEFAULT_PORT; + } + if (!array_key_exists('persistent', $server)) { + $server['persistent'] = self::DEFAULT_PERSISTENT; + } + if (!array_key_exists('weight', $server)) { + $server['weight'] = self::DEFAULT_WEIGHT; + } + if (!array_key_exists('timeout', $server)) { + $server['timeout'] = self::DEFAULT_TIMEOUT; + } + if (!array_key_exists('retry_interval', $server)) { + $server['retry_interval'] = self::DEFAULT_RETRY_INTERVAL; + } + if (!array_key_exists('status', $server)) { + $server['status'] = self::DEFAULT_STATUS; + } + if (!array_key_exists('failure_callback', $server)) { + $server['failure_callback'] = self::DEFAULT_FAILURE_CALLBACK; + } + if ($this->_options['compatibility']) { + // No status for compatibility mode (#ZF-5887) + $this->_memcache->addServer($server['host'], $server['port'], $server['persistent'], + $server['weight'], $server['timeout'], + $server['retry_interval']); + } else { + $this->_memcache->addServer($server['host'], $server['port'], $server['persistent'], + $server['weight'], $server['timeout'], + $server['retry_interval'], + $server['status'], $server['failure_callback']); + } + } + } + + /** + * Test if a cache is available for the given id and (if yes) return it (false else) + * + * @param string $id Cache id + * @param boolean $doNotTestCacheValidity If set to true, the cache validity won't be tested + * @return string|false cached datas + */ + public function load($id, $doNotTestCacheValidity = false) + { + $tmp = $this->_memcache->get($id); + if (is_array($tmp) && isset($tmp[0])) { + return $tmp[0]; + } + return false; + } + + /** + * Test if a cache is available or not (for the given id) + * + * @param string $id Cache id + * @return mixed|false (a cache is not available) or "last modified" timestamp (int) of the available cache record + */ + public function test($id) + { + $tmp = $this->_memcache->get($id); + if (is_array($tmp)) { + return $tmp[1]; + } + return false; + } + + /** + * Save some string datas into a cache record + * + * Note : $data is always "string" (serialization is done by the + * core not by the backend) + * + * @param string $data Datas to cache + * @param string $id Cache id + * @param array $tags Array of strings, the cache record will be tagged by each string entry + * @param int $specificLifetime If != false, set a specific lifetime for this cache record (null => infinite lifetime) + * @return boolean True if no problem + */ + public function save($data, $id, $tags = array(), $specificLifetime = false) + { + $lifetime = $this->getLifetime($specificLifetime); + if ($this->_options['compression']) { + $flag = MEMCACHE_COMPRESSED; + } else { + $flag = 0; + } + + // ZF-8856: using set because add needs a second request if item already exists + $result = @$this->_memcache->set($id, array($data, time(), $lifetime), $flag, $lifetime); + + if (count($tags) > 0) { + $this->_log(self::TAGS_UNSUPPORTED_BY_SAVE_OF_MEMCACHED_BACKEND); + } + + return $result; + } + + /** + * Remove a cache record + * + * @param string $id Cache id + * @return boolean True if no problem + */ + public function remove($id) + { + return $this->_memcache->delete($id, 0); + } + + /** + * Clean some cache records + * + * Available modes are : + * 'all' (default) => remove all cache entries ($tags is not used) + * 'old' => unsupported + * 'matchingTag' => unsupported + * 'notMatchingTag' => unsupported + * 'matchingAnyTag' => unsupported + * + * @param string $mode Clean mode + * @param array $tags Array of tags + * @throws Zend_Cache_Exception + * @return boolean True if no problem + */ + public function clean($mode = Zend_Cache::CLEANING_MODE_ALL, $tags = array()) + { + switch ($mode) { + case Zend_Cache::CLEANING_MODE_ALL: + return $this->_memcache->flush(); + break; + case Zend_Cache::CLEANING_MODE_OLD: + $this->_log("Zend_Cache_Backend_Memcached::clean() : CLEANING_MODE_OLD is unsupported by the Memcached backend"); + break; + case Zend_Cache::CLEANING_MODE_MATCHING_TAG: + case Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG: + case Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG: + $this->_log(self::TAGS_UNSUPPORTED_BY_CLEAN_OF_MEMCACHED_BACKEND); + break; + default: + Zend_Cache::throwException('Invalid mode for clean() method'); + break; + } + } + + /** + * Return true if the automatic cleaning is available for the backend + * + * @return boolean + */ + public function isAutomaticCleaningAvailable() + { + return false; + } + + /** + * Set the frontend directives + * + * @param array $directives Assoc of directives + * @throws Zend_Cache_Exception + * @return void + */ + public function setDirectives($directives) + { + parent::setDirectives($directives); + $lifetime = $this->getLifetime(false); + if ($lifetime > 2592000) { + // #ZF-3490 : For the memcached backend, there is a lifetime limit of 30 days (2592000 seconds) + $this->_log('memcached backend has a limit of 30 days (2592000 seconds) for the lifetime'); + } + if ($lifetime === null) { + // #ZF-4614 : we tranform null to zero to get the maximal lifetime + parent::setDirectives(array('lifetime' => 0)); + } + } + + /** + * Return an array of stored cache ids + * + * @return array array of stored cache ids (string) + */ + public function getIds() + { + $this->_log("Zend_Cache_Backend_Memcached::save() : getting the list of cache ids is unsupported by the Memcache backend"); + return array(); + } + + /** + * Return an array of stored tags + * + * @return array array of stored tags (string) + */ + public function getTags() + { + $this->_log(self::TAGS_UNSUPPORTED_BY_SAVE_OF_MEMCACHED_BACKEND); + return array(); + } + + /** + * Return an array of stored cache ids which match given tags + * + * In case of multiple tags, a logical AND is made between tags + * + * @param array $tags array of tags + * @return array array of matching cache ids (string) + */ + public function getIdsMatchingTags($tags = array()) + { + $this->_log(self::TAGS_UNSUPPORTED_BY_SAVE_OF_MEMCACHED_BACKEND); + return array(); + } + + /** + * Return an array of stored cache ids which don't match given tags + * + * In case of multiple tags, a logical OR is made between tags + * + * @param array $tags array of tags + * @return array array of not matching cache ids (string) + */ + public function getIdsNotMatchingTags($tags = array()) + { + $this->_log(self::TAGS_UNSUPPORTED_BY_SAVE_OF_MEMCACHED_BACKEND); + return array(); + } + + /** + * Return an array of stored cache ids which match any given tags + * + * In case of multiple tags, a logical AND is made between tags + * + * @param array $tags array of tags + * @return array array of any matching cache ids (string) + */ + public function getIdsMatchingAnyTags($tags = array()) + { + $this->_log(self::TAGS_UNSUPPORTED_BY_SAVE_OF_MEMCACHED_BACKEND); + return array(); + } + + /** + * Return the filling percentage of the backend storage + * + * @throws Zend_Cache_Exception + * @return int integer between 0 and 100 + */ + public function getFillingPercentage() + { + $mems = $this->_memcache->getExtendedStats(); + + $memSize = null; + $memUsed = null; + foreach ($mems as $key => $mem) { + if ($mem === false) { + $this->_log('can\'t get stat from ' . $key); + continue; + } + + $eachSize = $mem['limit_maxbytes']; + + /** + * Couchbase 1.x uses 'mem_used' instead of 'bytes' + * @see https://www.couchbase.com/issues/browse/MB-3466 + */ + $eachUsed = isset($mem['bytes']) ? $mem['bytes'] : $mem['mem_used']; + if ($eachUsed > $eachSize) { + $eachUsed = $eachSize; + } + + $memSize += $eachSize; + $memUsed += $eachUsed; + } + + if ($memSize === null || $memUsed === null) { + Zend_Cache::throwException('Can\'t get filling percentage'); + } + + return ((int) (100. * ($memUsed / $memSize))); + } + + /** + * Return an array of metadatas for the given cache id + * + * The array must include these keys : + * - expire : the expire timestamp + * - tags : a string array of tags + * - mtime : timestamp of last modification time + * + * @param string $id cache id + * @return array array of metadatas (false if the cache id is not found) + */ + public function getMetadatas($id) + { + $tmp = $this->_memcache->get($id); + if (is_array($tmp)) { + $data = $tmp[0]; + $mtime = $tmp[1]; + if (!isset($tmp[2])) { + // because this record is only with 1.7 release + // if old cache records are still there... + return false; + } + $lifetime = $tmp[2]; + return array( + 'expire' => $mtime + $lifetime, + 'tags' => array(), + 'mtime' => $mtime + ); + } + return false; + } + + /** + * Give (if possible) an extra lifetime to the given cache id + * + * @param string $id cache id + * @param int $extraLifetime + * @return boolean true if ok + */ + public function touch($id, $extraLifetime) + { + if ($this->_options['compression']) { + $flag = MEMCACHE_COMPRESSED; + } else { + $flag = 0; + } + $tmp = $this->_memcache->get($id); + if (is_array($tmp)) { + $data = $tmp[0]; + $mtime = $tmp[1]; + if (!isset($tmp[2])) { + // because this record is only with 1.7 release + // if old cache records are still there... + return false; + } + $lifetime = $tmp[2]; + $newLifetime = $lifetime - (time() - $mtime) + $extraLifetime; + if ($newLifetime <=0) { + return false; + } + // #ZF-5702 : we try replace() first becase set() seems to be slower + if (!($result = $this->_memcache->replace($id, array($data, time(), $newLifetime), $flag, $newLifetime))) { + $result = $this->_memcache->set($id, array($data, time(), $newLifetime), $flag, $newLifetime); + } + return $result; + } + return false; + } + + /** + * Return an associative array of capabilities (booleans) of the backend + * + * The array must include these keys : + * - automatic_cleaning (is automating cleaning necessary) + * - tags (are tags supported) + * - expired_read (is it possible to read expired cache records + * (for doNotTestCacheValidity option for example)) + * - priority does the backend deal with priority when saving + * - infinite_lifetime (is infinite lifetime can work with this backend) + * - get_list (is it possible to get the list of cache ids and the complete list of tags) + * + * @return array associative of with capabilities + */ + public function getCapabilities() + { + return array( + 'automatic_cleaning' => false, + 'tags' => false, + 'expired_read' => false, + 'priority' => false, + 'infinite_lifetime' => false, + 'get_list' => false + ); + } + +} diff --git a/library/vendor/Zend/Cache/Backend/Sqlite.php b/library/vendor/Zend/Cache/Backend/Sqlite.php new file mode 100644 index 0000000..fa6be7d --- /dev/null +++ b/library/vendor/Zend/Cache/Backend/Sqlite.php @@ -0,0 +1,676 @@ + (string) cache_db_complete_path : + * - the complete path (filename included) of the SQLITE database + * + * ====> (int) automatic_vacuum_factor : + * - Disable / Tune the automatic vacuum process + * - The automatic vacuum process defragment the database file (and make it smaller) + * when a clean() or delete() is called + * 0 => no automatic vacuum + * 1 => systematic vacuum (when delete() or clean() methods are called) + * x (integer) > 1 => automatic vacuum randomly 1 times on x clean() or delete() + * + * @var array Available options + */ + protected $_options = array( + 'cache_db_complete_path' => null, + 'automatic_vacuum_factor' => 10 + ); + + /** + * DB ressource + * + * @var mixed $_db + */ + private $_db = null; + + /** + * Boolean to store if the structure has benn checked or not + * + * @var boolean $_structureChecked + */ + private $_structureChecked = false; + + /** + * Constructor + * + * @param array $options Associative array of options + * @throws Zend_cache_Exception + * @return void + */ + public function __construct(array $options = array()) + { + parent::__construct($options); + if ($this->_options['cache_db_complete_path'] === null) { + Zend_Cache::throwException('cache_db_complete_path option has to set'); + } + if (!extension_loaded('sqlite')) { + Zend_Cache::throwException("Cannot use SQLite storage because the 'sqlite' extension is not loaded in the current PHP environment"); + } + $this->_getConnection(); + } + + /** + * Destructor + * + * @return void + */ + public function __destruct() + { + @sqlite_close($this->_getConnection()); + } + + /** + * Test if a cache is available for the given id and (if yes) return it (false else) + * + * @param string $id Cache id + * @param boolean $doNotTestCacheValidity If set to true, the cache validity won't be tested + * @return string|false Cached datas + */ + public function load($id, $doNotTestCacheValidity = false) + { + $this->_checkAndBuildStructure(); + $sql = "SELECT content FROM cache WHERE id='$id'"; + if (!$doNotTestCacheValidity) { + $sql = $sql . " AND (expire=0 OR expire>" . time() . ')'; + } + $result = $this->_query($sql); + $row = @sqlite_fetch_array($result); + if ($row) { + return $row['content']; + } + return false; + } + + /** + * Test if a cache is available or not (for the given id) + * + * @param string $id Cache id + * @return mixed|false (a cache is not available) or "last modified" timestamp (int) of the available cache record + */ + public function test($id) + { + $this->_checkAndBuildStructure(); + $sql = "SELECT lastModified FROM cache WHERE id='$id' AND (expire=0 OR expire>" . time() . ')'; + $result = $this->_query($sql); + $row = @sqlite_fetch_array($result); + if ($row) { + return ((int) $row['lastModified']); + } + return false; + } + + /** + * Save some string datas into a cache record + * + * Note : $data is always "string" (serialization is done by the + * core not by the backend) + * + * @param string $data Datas to cache + * @param string $id Cache id + * @param array $tags Array of strings, the cache record will be tagged by each string entry + * @param int $specificLifetime If != false, set a specific lifetime for this cache record (null => infinite lifetime) + * @throws Zend_Cache_Exception + * @return boolean True if no problem + */ + public function save($data, $id, $tags = array(), $specificLifetime = false) + { + $this->_checkAndBuildStructure(); + $lifetime = $this->getLifetime($specificLifetime); + $data = @sqlite_escape_string($data); + $mktime = time(); + if ($lifetime === null) { + $expire = 0; + } else { + $expire = $mktime + $lifetime; + } + $this->_query("DELETE FROM cache WHERE id='$id'"); + $sql = "INSERT INTO cache (id, content, lastModified, expire) VALUES ('$id', '$data', $mktime, $expire)"; + $res = $this->_query($sql); + if (!$res) { + $this->_log("Zend_Cache_Backend_Sqlite::save() : impossible to store the cache id=$id"); + return false; + } + $res = true; + foreach ($tags as $tag) { + $res = $this->_registerTag($id, $tag) && $res; + } + return $res; + } + + /** + * Remove a cache record + * + * @param string $id Cache id + * @return boolean True if no problem + */ + public function remove($id) + { + $this->_checkAndBuildStructure(); + $res = $this->_query("SELECT COUNT(*) AS nbr FROM cache WHERE id='$id'"); + $result1 = @sqlite_fetch_single($res); + $result2 = $this->_query("DELETE FROM cache WHERE id='$id'"); + $result3 = $this->_query("DELETE FROM tag WHERE id='$id'"); + $this->_automaticVacuum(); + return ($result1 && $result2 && $result3); + } + + /** + * Clean some cache records + * + * Available modes are : + * Zend_Cache::CLEANING_MODE_ALL (default) => remove all cache entries ($tags is not used) + * Zend_Cache::CLEANING_MODE_OLD => remove too old cache entries ($tags is not used) + * Zend_Cache::CLEANING_MODE_MATCHING_TAG => remove cache entries matching all given tags + * ($tags can be an array of strings or a single string) + * Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG => remove cache entries not {matching one of the given tags} + * ($tags can be an array of strings or a single string) + * Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG => remove cache entries matching any given tags + * ($tags can be an array of strings or a single string) + * + * @param string $mode Clean mode + * @param array $tags Array of tags + * @return boolean True if no problem + */ + public function clean($mode = Zend_Cache::CLEANING_MODE_ALL, $tags = array()) + { + $this->_checkAndBuildStructure(); + $return = $this->_clean($mode, $tags); + $this->_automaticVacuum(); + return $return; + } + + /** + * Return an array of stored cache ids + * + * @return array array of stored cache ids (string) + */ + public function getIds() + { + $this->_checkAndBuildStructure(); + $res = $this->_query("SELECT id FROM cache WHERE (expire=0 OR expire>" . time() . ")"); + $result = array(); + while ($id = @sqlite_fetch_single($res)) { + $result[] = $id; + } + return $result; + } + + /** + * Return an array of stored tags + * + * @return array array of stored tags (string) + */ + public function getTags() + { + $this->_checkAndBuildStructure(); + $res = $this->_query("SELECT DISTINCT(name) AS name FROM tag"); + $result = array(); + while ($id = @sqlite_fetch_single($res)) { + $result[] = $id; + } + return $result; + } + + /** + * Return an array of stored cache ids which match given tags + * + * In case of multiple tags, a logical AND is made between tags + * + * @param array $tags array of tags + * @return array array of matching cache ids (string) + */ + public function getIdsMatchingTags($tags = array()) + { + $first = true; + $ids = array(); + foreach ($tags as $tag) { + $res = $this->_query("SELECT DISTINCT(id) AS id FROM tag WHERE name='$tag'"); + if (!$res) { + return array(); + } + $rows = @sqlite_fetch_all($res, SQLITE_ASSOC); + $ids2 = array(); + foreach ($rows as $row) { + $ids2[] = $row['id']; + } + if ($first) { + $ids = $ids2; + $first = false; + } else { + $ids = array_intersect($ids, $ids2); + } + } + $result = array(); + foreach ($ids as $id) { + $result[] = $id; + } + return $result; + } + + /** + * Return an array of stored cache ids which don't match given tags + * + * In case of multiple tags, a logical OR is made between tags + * + * @param array $tags array of tags + * @return array array of not matching cache ids (string) + */ + public function getIdsNotMatchingTags($tags = array()) + { + $res = $this->_query("SELECT id FROM cache"); + $rows = @sqlite_fetch_all($res, SQLITE_ASSOC); + $result = array(); + foreach ($rows as $row) { + $id = $row['id']; + $matching = false; + foreach ($tags as $tag) { + $res = $this->_query("SELECT COUNT(*) AS nbr FROM tag WHERE name='$tag' AND id='$id'"); + if (!$res) { + return array(); + } + $nbr = (int) @sqlite_fetch_single($res); + if ($nbr > 0) { + $matching = true; + } + } + if (!$matching) { + $result[] = $id; + } + } + return $result; + } + + /** + * Return an array of stored cache ids which match any given tags + * + * In case of multiple tags, a logical AND is made between tags + * + * @param array $tags array of tags + * @return array array of any matching cache ids (string) + */ + public function getIdsMatchingAnyTags($tags = array()) + { + $first = true; + $ids = array(); + foreach ($tags as $tag) { + $res = $this->_query("SELECT DISTINCT(id) AS id FROM tag WHERE name='$tag'"); + if (!$res) { + return array(); + } + $rows = @sqlite_fetch_all($res, SQLITE_ASSOC); + $ids2 = array(); + foreach ($rows as $row) { + $ids2[] = $row['id']; + } + if ($first) { + $ids = $ids2; + $first = false; + } else { + $ids = array_merge($ids, $ids2); + } + } + $result = array(); + foreach ($ids as $id) { + $result[] = $id; + } + return $result; + } + + /** + * Return the filling percentage of the backend storage + * + * @throws Zend_Cache_Exception + * @return int integer between 0 and 100 + */ + public function getFillingPercentage() + { + $dir = dirname($this->_options['cache_db_complete_path']); + $free = disk_free_space($dir); + $total = disk_total_space($dir); + if ($total == 0) { + Zend_Cache::throwException('can\'t get disk_total_space'); + } else { + if ($free >= $total) { + return 100; + } + return ((int) (100. * ($total - $free) / $total)); + } + } + + /** + * Return an array of metadatas for the given cache id + * + * The array must include these keys : + * - expire : the expire timestamp + * - tags : a string array of tags + * - mtime : timestamp of last modification time + * + * @param string $id cache id + * @return array array of metadatas (false if the cache id is not found) + */ + public function getMetadatas($id) + { + $tags = array(); + $res = $this->_query("SELECT name FROM tag WHERE id='$id'"); + if ($res) { + $rows = @sqlite_fetch_all($res, SQLITE_ASSOC); + foreach ($rows as $row) { + $tags[] = $row['name']; + } + } + $this->_query('CREATE TABLE cache (id TEXT PRIMARY KEY, content BLOB, lastModified INTEGER, expire INTEGER)'); + $res = $this->_query("SELECT lastModified,expire FROM cache WHERE id='$id'"); + if (!$res) { + return false; + } + $row = @sqlite_fetch_array($res, SQLITE_ASSOC); + return array( + 'tags' => $tags, + 'mtime' => $row['lastModified'], + 'expire' => $row['expire'] + ); + } + + /** + * Give (if possible) an extra lifetime to the given cache id + * + * @param string $id cache id + * @param int $extraLifetime + * @return boolean true if ok + */ + public function touch($id, $extraLifetime) + { + $sql = "SELECT expire FROM cache WHERE id='$id' AND (expire=0 OR expire>" . time() . ')'; + $res = $this->_query($sql); + if (!$res) { + return false; + } + $expire = @sqlite_fetch_single($res); + $newExpire = $expire + $extraLifetime; + $res = $this->_query("UPDATE cache SET lastModified=" . time() . ", expire=$newExpire WHERE id='$id'"); + if ($res) { + return true; + } else { + return false; + } + } + + /** + * Return an associative array of capabilities (booleans) of the backend + * + * The array must include these keys : + * - automatic_cleaning (is automating cleaning necessary) + * - tags (are tags supported) + * - expired_read (is it possible to read expired cache records + * (for doNotTestCacheValidity option for example)) + * - priority does the backend deal with priority when saving + * - infinite_lifetime (is infinite lifetime can work with this backend) + * - get_list (is it possible to get the list of cache ids and the complete list of tags) + * + * @return array associative of with capabilities + */ + public function getCapabilities() + { + return array( + 'automatic_cleaning' => true, + 'tags' => true, + 'expired_read' => true, + 'priority' => false, + 'infinite_lifetime' => true, + 'get_list' => true + ); + } + + /** + * PUBLIC METHOD FOR UNIT TESTING ONLY ! + * + * Force a cache record to expire + * + * @param string $id Cache id + */ + public function ___expire($id) + { + $time = time() - 1; + $this->_query("UPDATE cache SET lastModified=$time, expire=$time WHERE id='$id'"); + } + + /** + * Return the connection resource + * + * If we are not connected, the connection is made + * + * @throws Zend_Cache_Exception + * @return resource Connection resource + */ + private function _getConnection() + { + if (is_resource($this->_db)) { + return $this->_db; + } else { + $this->_db = @sqlite_open($this->_options['cache_db_complete_path']); + if (!(is_resource($this->_db))) { + Zend_Cache::throwException("Impossible to open " . $this->_options['cache_db_complete_path'] . " cache DB file"); + } + return $this->_db; + } + } + + /** + * Execute an SQL query silently + * + * @param string $query SQL query + * @return mixed|false query results + */ + private function _query($query) + { + $db = $this->_getConnection(); + if (is_resource($db)) { + $res = @sqlite_query($db, $query); + if ($res === false) { + return false; + } else { + return $res; + } + } + return false; + } + + /** + * Deal with the automatic vacuum process + * + * @return void + */ + private function _automaticVacuum() + { + if ($this->_options['automatic_vacuum_factor'] > 0) { + $rand = rand(1, $this->_options['automatic_vacuum_factor']); + if ($rand == 1) { + $this->_query('VACUUM'); + } + } + } + + /** + * Register a cache id with the given tag + * + * @param string $id Cache id + * @param string $tag Tag + * @return boolean True if no problem + */ + private function _registerTag($id, $tag) { + $res = $this->_query("DELETE FROM TAG WHERE name='$tag' AND id='$id'"); + $res = $this->_query("INSERT INTO tag (name, id) VALUES ('$tag', '$id')"); + if (!$res) { + $this->_log("Zend_Cache_Backend_Sqlite::_registerTag() : impossible to register tag=$tag on id=$id"); + return false; + } + return true; + } + + /** + * Build the database structure + * + * @return false + */ + private function _buildStructure() + { + $this->_query('DROP INDEX tag_id_index'); + $this->_query('DROP INDEX tag_name_index'); + $this->_query('DROP INDEX cache_id_expire_index'); + $this->_query('DROP TABLE version'); + $this->_query('DROP TABLE cache'); + $this->_query('DROP TABLE tag'); + $this->_query('CREATE TABLE version (num INTEGER PRIMARY KEY)'); + $this->_query('CREATE TABLE cache (id TEXT PRIMARY KEY, content BLOB, lastModified INTEGER, expire INTEGER)'); + $this->_query('CREATE TABLE tag (name TEXT, id TEXT)'); + $this->_query('CREATE INDEX tag_id_index ON tag(id)'); + $this->_query('CREATE INDEX tag_name_index ON tag(name)'); + $this->_query('CREATE INDEX cache_id_expire_index ON cache(id, expire)'); + $this->_query('INSERT INTO version (num) VALUES (1)'); + } + + /** + * Check if the database structure is ok (with the good version) + * + * @return boolean True if ok + */ + private function _checkStructureVersion() + { + $result = $this->_query("SELECT num FROM version"); + if (!$result) return false; + $row = @sqlite_fetch_array($result); + if (!$row) { + return false; + } + if (((int) $row['num']) != 1) { + // old cache structure + $this->_log('Zend_Cache_Backend_Sqlite::_checkStructureVersion() : old cache structure version detected => the cache is going to be dropped'); + return false; + } + return true; + } + + /** + * Clean some cache records + * + * Available modes are : + * Zend_Cache::CLEANING_MODE_ALL (default) => remove all cache entries ($tags is not used) + * Zend_Cache::CLEANING_MODE_OLD => remove too old cache entries ($tags is not used) + * Zend_Cache::CLEANING_MODE_MATCHING_TAG => remove cache entries matching all given tags + * ($tags can be an array of strings or a single string) + * Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG => remove cache entries not {matching one of the given tags} + * ($tags can be an array of strings or a single string) + * Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG => remove cache entries matching any given tags + * ($tags can be an array of strings or a single string) + * + * @param string $mode Clean mode + * @param array $tags Array of tags + * @return boolean True if no problem + */ + private function _clean($mode = Zend_Cache::CLEANING_MODE_ALL, $tags = array()) + { + switch ($mode) { + case Zend_Cache::CLEANING_MODE_ALL: + $res1 = $this->_query('DELETE FROM cache'); + $res2 = $this->_query('DELETE FROM tag'); + return $res1 && $res2; + break; + case Zend_Cache::CLEANING_MODE_OLD: + $mktime = time(); + $res1 = $this->_query("DELETE FROM tag WHERE id IN (SELECT id FROM cache WHERE expire>0 AND expire<=$mktime)"); + $res2 = $this->_query("DELETE FROM cache WHERE expire>0 AND expire<=$mktime"); + return $res1 && $res2; + break; + case Zend_Cache::CLEANING_MODE_MATCHING_TAG: + $ids = $this->getIdsMatchingTags($tags); + $result = true; + foreach ($ids as $id) { + $result = $this->remove($id) && $result; + } + return $result; + break; + case Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG: + $ids = $this->getIdsNotMatchingTags($tags); + $result = true; + foreach ($ids as $id) { + $result = $this->remove($id) && $result; + } + return $result; + break; + case Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG: + $ids = $this->getIdsMatchingAnyTags($tags); + $result = true; + foreach ($ids as $id) { + $result = $this->remove($id) && $result; + } + return $result; + break; + default: + break; + } + return false; + } + + /** + * Check if the database structure is ok (with the good version), if no : build it + * + * @throws Zend_Cache_Exception + * @return boolean True if ok + */ + private function _checkAndBuildStructure() + { + if (!($this->_structureChecked)) { + if (!$this->_checkStructureVersion()) { + $this->_buildStructure(); + if (!$this->_checkStructureVersion()) { + Zend_Cache::throwException("Impossible to build cache structure in " . $this->_options['cache_db_complete_path']); + } + } + $this->_structureChecked = true; + } + return true; + } + +} diff --git a/library/vendor/Zend/Cache/Backend/Static.php b/library/vendor/Zend/Cache/Backend/Static.php new file mode 100644 index 0000000..9203020 --- /dev/null +++ b/library/vendor/Zend/Cache/Backend/Static.php @@ -0,0 +1,577 @@ + null, + 'sub_dir' => 'html', + 'file_extension' => '.html', + 'index_filename' => 'index', + 'file_locking' => true, + 'cache_file_perm' => 0600, + 'cache_directory_perm' => 0700, + 'debug_header' => false, + 'tag_cache' => null, + 'disable_caching' => false + ); + + /** + * Cache for handling tags + * @var Zend_Cache_Core + */ + protected $_tagCache = null; + + /** + * Tagged items + * @var array + */ + protected $_tagged = null; + + /** + * Interceptor child method to handle the case where an Inner + * Cache object is being set since it's not supported by the + * standard backend interface + * + * @param string $name + * @param mixed $value + * @return Zend_Cache_Backend_Static + */ + public function setOption($name, $value) + { + if ($name == 'tag_cache') { + $this->setInnerCache($value); + } else { + // See #ZF-12047 and #GH-91 + if ($name == 'cache_file_umask') { + trigger_error( + "'cache_file_umask' is deprecated -> please use 'cache_file_perm' instead", + E_USER_NOTICE + ); + + $name = 'cache_file_perm'; + } + if ($name == 'cache_directory_umask') { + trigger_error( + "'cache_directory_umask' is deprecated -> please use 'cache_directory_perm' instead", + E_USER_NOTICE + ); + + $name = 'cache_directory_perm'; + } + + parent::setOption($name, $value); + } + return $this; + } + + /** + * Retrieve any option via interception of the parent's statically held + * options including the local option for a tag cache. + * + * @param string $name + * @return mixed + */ + public function getOption($name) + { + $name = strtolower($name); + + if ($name == 'tag_cache') { + return $this->getInnerCache(); + } + + return parent::getOption($name); + } + + /** + * Test if a cache is available for the given id and (if yes) return it (false else) + * + * Note : return value is always "string" (unserialization is done by the core not by the backend) + * + * @param string $id Cache id + * @param boolean $doNotTestCacheValidity If set to true, the cache validity won't be tested + * @return string|false cached datas + */ + public function load($id, $doNotTestCacheValidity = false) + { + if (($id = (string)$id) === '') { + $id = $this->_detectId(); + } else { + $id = $this->_decodeId($id); + } + if (!$this->_verifyPath($id)) { + Zend_Cache::throwException('Invalid cache id: does not match expected public_dir path'); + } + if ($doNotTestCacheValidity) { + $this->_log("Zend_Cache_Backend_Static::load() : \$doNotTestCacheValidity=true is unsupported by the Static backend"); + } + + $fileName = basename($id); + if ($fileName === '') { + $fileName = $this->_options['index_filename']; + } + $pathName = $this->_options['public_dir'] . dirname($id); + $file = rtrim($pathName, '/') . '/' . $fileName . $this->_options['file_extension']; + if (file_exists($file)) { + $content = file_get_contents($file); + return $content; + } + + return false; + } + + /** + * Test if a cache is available or not (for the given id) + * + * @param string $id cache id + * @return bool + */ + public function test($id) + { + $id = $this->_decodeId($id); + if (!$this->_verifyPath($id)) { + Zend_Cache::throwException('Invalid cache id: does not match expected public_dir path'); + } + + $fileName = basename($id); + if ($fileName === '') { + $fileName = $this->_options['index_filename']; + } + if ($this->_tagged === null && $tagged = $this->getInnerCache()->load(self::INNER_CACHE_NAME)) { + $this->_tagged = $tagged; + } elseif (!$this->_tagged) { + return false; + } + $pathName = $this->_options['public_dir'] . dirname($id); + + // Switch extension if needed + if (isset($this->_tagged[$id])) { + $extension = $this->_tagged[$id]['extension']; + } else { + $extension = $this->_options['file_extension']; + } + $file = $pathName . '/' . $fileName . $extension; + if (file_exists($file)) { + return true; + } + return false; + } + + /** + * Save some string datas into a cache record + * + * Note : $data is always "string" (serialization is done by the + * core not by the backend) + * + * @param string $data Datas to cache + * @param string $id Cache id + * @param array $tags Array of strings, the cache record will be tagged by each string entry + * @param int $specificLifetime If != false, set a specific lifetime for this cache record (null => infinite lifetime) + * @return boolean true if no problem + */ + public function save($data, $id, $tags = array(), $specificLifetime = false) + { + if ($this->_options['disable_caching']) { + return true; + } + $extension = null; + if ($this->_isSerialized($data)) { + $data = unserialize($data); + $extension = '.' . ltrim($data[1], '.'); + $data = $data[0]; + } + + clearstatcache(); + if (($id = (string)$id) === '') { + $id = $this->_detectId(); + } else { + $id = $this->_decodeId($id); + } + + $fileName = basename($id); + if ($fileName === '') { + $fileName = $this->_options['index_filename']; + } + + $pathName = realpath($this->_options['public_dir']) . dirname($id); + $this->_createDirectoriesFor($pathName); + + if ($id === null || strlen($id) == 0) { + $dataUnserialized = unserialize($data); + $data = $dataUnserialized['data']; + } + $ext = $this->_options['file_extension']; + if ($extension) $ext = $extension; + $file = rtrim($pathName, '/') . '/' . $fileName . $ext; + if ($this->_options['file_locking']) { + $result = file_put_contents($file, $data, LOCK_EX); + } else { + $result = file_put_contents($file, $data); + } + @chmod($file, $this->_octdec($this->_options['cache_file_perm'])); + + if ($this->_tagged === null && $tagged = $this->getInnerCache()->load(self::INNER_CACHE_NAME)) { + $this->_tagged = $tagged; + } elseif ($this->_tagged === null) { + $this->_tagged = array(); + } + if (!isset($this->_tagged[$id])) { + $this->_tagged[$id] = array(); + } + if (!isset($this->_tagged[$id]['tags'])) { + $this->_tagged[$id]['tags'] = array(); + } + $this->_tagged[$id]['tags'] = array_unique(array_merge($this->_tagged[$id]['tags'], $tags)); + $this->_tagged[$id]['extension'] = $ext; + $this->getInnerCache()->save($this->_tagged, self::INNER_CACHE_NAME); + return (bool) $result; + } + + /** + * Recursively create the directories needed to write the static file + */ + protected function _createDirectoriesFor($path) + { + if (!is_dir($path)) { + $oldUmask = umask(0); + if ( !@mkdir($path, $this->_octdec($this->_options['cache_directory_perm']), true)) { + $lastErr = error_get_last(); + umask($oldUmask); + Zend_Cache::throwException("Can't create directory: {$lastErr['message']}"); + } + umask($oldUmask); + } + } + + /** + * Detect serialization of data (cannot predict since this is the only way + * to obey the interface yet pass in another parameter). + * + * In future, ZF 2.0, check if we can just avoid the interface restraints. + * + * This format is the only valid one possible for the class, so it's simple + * to just run a regular expression for the starting serialized format. + */ + protected function _isSerialized($data) + { + return preg_match("/a:2:\{i:0;s:\d+:\"/", $data); + } + + /** + * Remove a cache record + * + * @param string $id Cache id + * @return boolean True if no problem + */ + public function remove($id) + { + if (!$this->_verifyPath($id)) { + Zend_Cache::throwException('Invalid cache id: does not match expected public_dir path'); + } + $fileName = basename($id); + if ($this->_tagged === null && $tagged = $this->getInnerCache()->load(self::INNER_CACHE_NAME)) { + $this->_tagged = $tagged; + } elseif (!$this->_tagged) { + return false; + } + if (isset($this->_tagged[$id])) { + $extension = $this->_tagged[$id]['extension']; + } else { + $extension = $this->_options['file_extension']; + } + if ($fileName === '') { + $fileName = $this->_options['index_filename']; + } + $pathName = $this->_options['public_dir'] . dirname($id); + $file = realpath($pathName) . '/' . $fileName . $extension; + if (!file_exists($file)) { + return false; + } + return unlink($file); + } + + /** + * Remove a cache record recursively for the given directory matching a + * REQUEST_URI based relative path (deletes the actual file matching this + * in addition to the matching directory) + * + * @param string $id Cache id + * @return boolean True if no problem + */ + public function removeRecursively($id) + { + if (!$this->_verifyPath($id)) { + Zend_Cache::throwException('Invalid cache id: does not match expected public_dir path'); + } + $fileName = basename($id); + if ($fileName === '') { + $fileName = $this->_options['index_filename']; + } + $pathName = $this->_options['public_dir'] . dirname($id); + $file = $pathName . '/' . $fileName . $this->_options['file_extension']; + $directory = $pathName . '/' . $fileName; + if (file_exists($directory)) { + if (!is_writable($directory)) { + return false; + } + if (is_dir($directory)) { + foreach (new DirectoryIterator($directory) as $file) { + if (true === $file->isFile()) { + if (false === unlink($file->getPathName())) { + return false; + } + } + } + } + rmdir($directory); + } + if (file_exists($file)) { + if (!is_writable($file)) { + return false; + } + return unlink($file); + } + return true; + } + + /** + * Clean some cache records + * + * Available modes are : + * Zend_Cache::CLEANING_MODE_ALL (default) => remove all cache entries ($tags is not used) + * Zend_Cache::CLEANING_MODE_OLD => remove too old cache entries ($tags is not used) + * Zend_Cache::CLEANING_MODE_MATCHING_TAG => remove cache entries matching all given tags + * ($tags can be an array of strings or a single string) + * Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG => remove cache entries not {matching one of the given tags} + * ($tags can be an array of strings or a single string) + * Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG => remove cache entries matching any given tags + * ($tags can be an array of strings or a single string) + * + * @param string $mode Clean mode + * @param array $tags Array of tags + * @return boolean true if no problem + * @throws Zend_Exception + */ + public function clean($mode = Zend_Cache::CLEANING_MODE_ALL, $tags = array()) + { + $result = false; + switch ($mode) { + case Zend_Cache::CLEANING_MODE_MATCHING_TAG: + case Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG: + if (empty($tags)) { + throw new Zend_Exception('Cannot use tag matching modes as no tags were defined'); + } + if ($this->_tagged === null && $tagged = $this->getInnerCache()->load(self::INNER_CACHE_NAME)) { + $this->_tagged = $tagged; + } elseif (!$this->_tagged) { + return true; + } + foreach ($tags as $tag) { + $urls = array_keys($this->_tagged); + foreach ($urls as $url) { + if (isset($this->_tagged[$url]['tags']) && in_array($tag, $this->_tagged[$url]['tags'])) { + $this->remove($url); + unset($this->_tagged[$url]); + } + } + } + $this->getInnerCache()->save($this->_tagged, self::INNER_CACHE_NAME); + $result = true; + break; + case Zend_Cache::CLEANING_MODE_ALL: + if ($this->_tagged === null) { + $tagged = $this->getInnerCache()->load(self::INNER_CACHE_NAME); + $this->_tagged = $tagged; + } + if ($this->_tagged === null || empty($this->_tagged)) { + return true; + } + $urls = array_keys($this->_tagged); + foreach ($urls as $url) { + $this->remove($url); + unset($this->_tagged[$url]); + } + $this->getInnerCache()->save($this->_tagged, self::INNER_CACHE_NAME); + $result = true; + break; + case Zend_Cache::CLEANING_MODE_OLD: + $this->_log("Zend_Cache_Backend_Static : Selected Cleaning Mode Currently Unsupported By This Backend"); + break; + case Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG: + if (empty($tags)) { + throw new Zend_Exception('Cannot use tag matching modes as no tags were defined'); + } + if ($this->_tagged === null) { + $tagged = $this->getInnerCache()->load(self::INNER_CACHE_NAME); + $this->_tagged = $tagged; + } + if ($this->_tagged === null || empty($this->_tagged)) { + return true; + } + $urls = array_keys($this->_tagged); + foreach ($urls as $url) { + $difference = array_diff($tags, $this->_tagged[$url]['tags']); + if (count($tags) == count($difference)) { + $this->remove($url); + unset($this->_tagged[$url]); + } + } + $this->getInnerCache()->save($this->_tagged, self::INNER_CACHE_NAME); + $result = true; + break; + default: + Zend_Cache::throwException('Invalid mode for clean() method'); + break; + } + return $result; + } + + /** + * Set an Inner Cache, used here primarily to store Tags associated + * with caches created by this backend. Note: If Tags are lost, the cache + * should be completely cleaned as the mapping of tags to caches will + * have been irrevocably lost. + * + * @param Zend_Cache_Core + * @return void + */ + public function setInnerCache(Zend_Cache_Core $cache) + { + $this->_tagCache = $cache; + $this->_options['tag_cache'] = $cache; + } + + /** + * Get the Inner Cache if set + * + * @return Zend_Cache_Core + */ + public function getInnerCache() + { + if ($this->_tagCache === null) { + Zend_Cache::throwException('An Inner Cache has not been set; use setInnerCache()'); + } + return $this->_tagCache; + } + + /** + * Verify path exists and is non-empty + * + * @param string $path + * @return bool + */ + protected function _verifyPath($path) + { + $path = realpath($path); + $base = realpath($this->_options['public_dir']); + return strncmp($path, $base, strlen($base)) !== 0; + } + + /** + * Determine the page to save from the request + * + * @return string + */ + protected function _detectId() + { + return $_SERVER['REQUEST_URI']; + } + + /** + * Validate a cache id or a tag (security, reliable filenames, reserved prefixes...) + * + * Throw an exception if a problem is found + * + * @param string $string Cache id or tag + * @throws Zend_Cache_Exception + * @return void + * @deprecated Not usable until perhaps ZF 2.0 + */ + protected static function _validateIdOrTag($string) + { + if (!is_string($string)) { + Zend_Cache::throwException('Invalid id or tag : must be a string'); + } + + // Internal only checked in Frontend - not here! + if (substr($string, 0, 9) == 'internal-') { + return; + } + + // Validation assumes no query string, fragments or scheme included - only the path + if (!preg_match( + '/^(?:\/(?:(?:%[[:xdigit:]]{2}|[A-Za-z0-9-_.!~*\'()\[\]:@&=+$,;])*)?)+$/', + $string + ) + ) { + Zend_Cache::throwException("Invalid id or tag '$string' : must be a valid URL path"); + } + } + + /** + * Detect an octal string and return its octal value for file permission ops + * otherwise return the non-string (assumed octal or decimal int already) + * + * @param string $val The potential octal in need of conversion + * @return int + */ + protected function _octdec($val) + { + if (is_string($val) && decoct(octdec($val)) == $val) { + return octdec($val); + } + return $val; + } + + /** + * Decode a request URI from the provided ID + * + * @param string $id + * @return string + */ + protected function _decodeId($id) + { + return pack('H*', $id); + } +} diff --git a/library/vendor/Zend/Cache/Backend/Test.php b/library/vendor/Zend/Cache/Backend/Test.php new file mode 100644 index 0000000..c06f959 --- /dev/null +++ b/library/vendor/Zend/Cache/Backend/Test.php @@ -0,0 +1,414 @@ +_addLog('construct', array($options)); + } + + /** + * Set the frontend directives + * + * @param array $directives assoc of directives + * @return void + */ + public function setDirectives($directives) + { + $this->_addLog('setDirectives', array($directives)); + } + + /** + * Test if a cache is available for the given id and (if yes) return it (false else) + * + * For this test backend only, if $id == 'false', then the method will return false + * if $id == 'serialized', the method will return a serialized array + * ('foo' else) + * + * @param string $id Cache id + * @param boolean $doNotTestCacheValidity If set to true, the cache validity won't be tested + * @return string Cached datas (or false) + */ + public function load($id, $doNotTestCacheValidity = false) + { + $this->_addLog('get', array($id, $doNotTestCacheValidity)); + + if ( $id == 'false' + || $id == 'd8523b3ee441006261eeffa5c3d3a0a7' + || $id == 'e83249ea22178277d5befc2c5e2e9ace' + || $id == '40f649b94977c0a6e76902e2a0b43587' + || $id == '88161989b73a4cbfd0b701c446115a99' + || $id == '205fc79cba24f0f0018eb92c7c8b3ba4' + || $id == '170720e35f38150b811f68a937fb042d') + { + return false; + } + if ($id=='serialized') { + return serialize(array('foo')); + } + if ($id=='serialized2') { + return serialize(array('headers' => array(), 'data' => 'foo')); + } + if ( $id == '71769f39054f75894288e397df04e445' || $id == '615d222619fb20b527168340cebd0578' + || $id == '8a02d218a5165c467e7a5747cc6bd4b6' || $id == '648aca1366211d17cbf48e65dc570bee' + || $id == '4a923ef02d7f997ca14d56dfeae25ea7') { + return serialize(array('foo', 'bar')); + } + if ( $id == 'f53c7d912cc523d9a65834c8286eceb9') { + return serialize(array('foobar')); + } + return 'foo'; + } + + /** + * Test if a cache is available or not (for the given id) + * + * For this test backend only, if $id == 'false', then the method will return false + * (123456 else) + * + * @param string $id Cache id + * @return mixed|false false (a cache is not available) or "last modified" timestamp (int) of the available cache record + */ + public function test($id) + { + $this->_addLog('test', array($id)); + if ($id=='false') { + return false; + } + if (($id=='3c439c922209e2cb0b54d6deffccd75a')) { + return false; + } + return 123456; + } + + /** + * Save some string datas into a cache record + * + * For this test backend only, if $id == 'false', then the method will return false + * (true else) + * + * @param string $data Datas to cache + * @param string $id Cache id + * @param array $tags Array of strings, the cache record will be tagged by each string entry + * @param int $specificLifetime If != false, set a specific lifetime for this cache record (null => infinite lifetime) + * @return boolean True if no problem + */ + public function save($data, $id, $tags = array(), $specificLifetime = false) + { + $this->_addLog('save', array($data, $id, $tags)); + if (substr($id,-5)=='false') { + return false; + } + return true; + } + + /** + * Remove a cache record + * + * For this test backend only, if $id == 'false', then the method will return false + * (true else) + * + * @param string $id Cache id + * @return boolean True if no problem + */ + public function remove($id) + { + $this->_addLog('remove', array($id)); + if (substr($id,-5)=='false') { + return false; + } + return true; + } + + /** + * Clean some cache records + * + * For this test backend only, if $mode == 'false', then the method will return false + * (true else) + * + * Available modes are : + * Zend_Cache::CLEANING_MODE_ALL (default) => remove all cache entries ($tags is not used) + * Zend_Cache::CLEANING_MODE_OLD => remove too old cache entries ($tags is not used) + * Zend_Cache::CLEANING_MODE_MATCHING_TAG => remove cache entries matching all given tags + * ($tags can be an array of strings or a single string) + * Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG => remove cache entries not {matching one of the given tags} + * ($tags can be an array of strings or a single string) + * + * @param string $mode Clean mode + * @param array $tags Array of tags + * @return boolean True if no problem + */ + public function clean($mode = Zend_Cache::CLEANING_MODE_ALL, $tags = array()) + { + $this->_addLog('clean', array($mode, $tags)); + if ($mode=='false') { + return false; + } + return true; + } + + /** + * Get the last log + * + * @return string The last log + */ + public function getLastLog() + { + return $this->_log[$this->_index - 1]; + } + + /** + * Get the log index + * + * @return int Log index + */ + public function getLogIndex() + { + return $this->_index; + } + + /** + * Get the complete log array + * + * @return array Complete log array + */ + public function getAllLogs() + { + return $this->_log; + } + + /** + * Return true if the automatic cleaning is available for the backend + * + * @return boolean + */ + public function isAutomaticCleaningAvailable() + { + return true; + } + + /** + * Return an array of stored cache ids + * + * @return array array of stored cache ids (string) + */ + public function getIds() + { + return array( + 'prefix_id1', 'prefix_id2' + ); + } + + /** + * Return an array of stored tags + * + * @return array array of stored tags (string) + */ + public function getTags() + { + return array( + 'tag1', 'tag2' + ); + } + + /** + * Return an array of stored cache ids which match given tags + * + * In case of multiple tags, a logical AND is made between tags + * + * @param array $tags array of tags + * @return array array of matching cache ids (string) + */ + public function getIdsMatchingTags($tags = array()) + { + if ($tags == array('tag1', 'tag2')) { + return array('prefix_id1', 'prefix_id2'); + } + + return array(); + } + + /** + * Return an array of stored cache ids which don't match given tags + * + * In case of multiple tags, a logical OR is made between tags + * + * @param array $tags array of tags + * @return array array of not matching cache ids (string) + */ + public function getIdsNotMatchingTags($tags = array()) + { + if ($tags == array('tag3', 'tag4')) { + return array('prefix_id3', 'prefix_id4'); + } + + return array(); + } + + /** + * Return an array of stored cache ids which match any given tags + * + * In case of multiple tags, a logical AND is made between tags + * + * @param array $tags array of tags + * @return array array of any matching cache ids (string) + */ + public function getIdsMatchingAnyTags($tags = array()) + { + if ($tags == array('tag5', 'tag6')) { + return array('prefix_id5', 'prefix_id6'); + } + + return array(); + } + + /** + * Return the filling percentage of the backend storage + * + * @return int integer between 0 and 100 + */ + public function getFillingPercentage() + { + return 50; + } + + /** + * Return an array of metadatas for the given cache id + * + * The array must include these keys : + * - expire : the expire timestamp + * - tags : a string array of tags + * - mtime : timestamp of last modification time + * + * @param string $id cache id + * @return array array of metadatas (false if the cache id is not found) + */ + public function getMetadatas($id) + { + return false; + } + + /** + * Give (if possible) an extra lifetime to the given cache id + * + * @param string $id cache id + * @param int $extraLifetime + * @return boolean true if ok + */ + public function touch($id, $extraLifetime) + { + return true; + } + + /** + * Return an associative array of capabilities (booleans) of the backend + * + * The array must include these keys : + * - automatic_cleaning (is automating cleaning necessary) + * - tags (are tags supported) + * - expired_read (is it possible to read expired cache records + * (for doNotTestCacheValidity option for example)) + * - priority does the backend deal with priority when saving + * - infinite_lifetime (is infinite lifetime can work with this backend) + * - get_list (is it possible to get the list of cache ids and the complete list of tags) + * + * @return array associative of with capabilities + */ + public function getCapabilities() + { + return array( + 'automatic_cleaning' => true, + 'tags' => true, + 'expired_read' => false, + 'priority' => true, + 'infinite_lifetime' => true, + 'get_list' => true + ); + } + + /** + * Add an event to the log array + * + * @param string $methodName MethodName + * @param array $args Arguments + * @return void + */ + private function _addLog($methodName, $args) + { + $this->_log[$this->_index] = array( + 'methodName' => $methodName, + 'args' => $args + ); + $this->_index = $this->_index + 1; + } + +} diff --git a/library/vendor/Zend/Cache/Backend/TwoLevels.php b/library/vendor/Zend/Cache/Backend/TwoLevels.php new file mode 100644 index 0000000..1e6792b --- /dev/null +++ b/library/vendor/Zend/Cache/Backend/TwoLevels.php @@ -0,0 +1,546 @@ + (string) slow_backend : + * - Slow backend name + * - Must implement the Zend_Cache_Backend_ExtendedInterface + * - Should provide a big storage + * + * =====> (string) fast_backend : + * - Flow backend name + * - Must implement the Zend_Cache_Backend_ExtendedInterface + * - Must be much faster than slow_backend + * + * =====> (array) slow_backend_options : + * - Slow backend options (see corresponding backend) + * + * =====> (array) fast_backend_options : + * - Fast backend options (see corresponding backend) + * + * =====> (int) stats_update_factor : + * - Disable / Tune the computation of the fast backend filling percentage + * - When saving a record into cache : + * 1 => systematic computation of the fast backend filling percentage + * x (integer) > 1 => computation of the fast backend filling percentage randomly 1 times on x cache write + * + * =====> (boolean) slow_backend_custom_naming : + * =====> (boolean) fast_backend_custom_naming : + * =====> (boolean) slow_backend_autoload : + * =====> (boolean) fast_backend_autoload : + * - See Zend_Cache::factory() method + * + * =====> (boolean) auto_fill_fast_cache + * - If true, automatically fill the fast cache when a cache record was not found in fast cache, but did + * exist in slow cache. This can be usefull when a non-persistent cache like APC or Memcached got + * purged for whatever reason. + * + * =====> (boolean) auto_refresh_fast_cache + * - If true, auto refresh the fast cache when a cache record is hit + * + * @var array available options + */ + protected $_options = array( + 'slow_backend' => 'File', + 'fast_backend' => 'Apc', + 'slow_backend_options' => array(), + 'fast_backend_options' => array(), + 'stats_update_factor' => 10, + 'slow_backend_custom_naming' => false, + 'fast_backend_custom_naming' => false, + 'slow_backend_autoload' => false, + 'fast_backend_autoload' => false, + 'auto_fill_fast_cache' => true, + 'auto_refresh_fast_cache' => true + ); + + /** + * Slow Backend + * + * @var Zend_Cache_Backend_ExtendedInterface + */ + protected $_slowBackend; + + /** + * Fast Backend + * + * @var Zend_Cache_Backend_ExtendedInterface + */ + protected $_fastBackend; + + /** + * Cache for the fast backend filling percentage + * + * @var int + */ + protected $_fastBackendFillingPercentage = null; + + /** + * Constructor + * + * @param array $options Associative array of options + * @throws Zend_Cache_Exception + * @return void + */ + public function __construct(array $options = array()) + { + parent::__construct($options); + + if ($this->_options['slow_backend'] === null) { + Zend_Cache::throwException('slow_backend option has to set'); + } elseif ($this->_options['slow_backend'] instanceof Zend_Cache_Backend_ExtendedInterface) { + $this->_slowBackend = $this->_options['slow_backend']; + } else { + $this->_slowBackend = Zend_Cache::_makeBackend( + $this->_options['slow_backend'], + $this->_options['slow_backend_options'], + $this->_options['slow_backend_custom_naming'], + $this->_options['slow_backend_autoload'] + ); + if (!in_array('Zend_Cache_Backend_ExtendedInterface', class_implements($this->_slowBackend))) { + Zend_Cache::throwException('slow_backend must implement the Zend_Cache_Backend_ExtendedInterface interface'); + } + } + + if ($this->_options['fast_backend'] === null) { + Zend_Cache::throwException('fast_backend option has to set'); + } elseif ($this->_options['fast_backend'] instanceof Zend_Cache_Backend_ExtendedInterface) { + $this->_fastBackend = $this->_options['fast_backend']; + } else { + $this->_fastBackend = Zend_Cache::_makeBackend( + $this->_options['fast_backend'], + $this->_options['fast_backend_options'], + $this->_options['fast_backend_custom_naming'], + $this->_options['fast_backend_autoload'] + ); + if (!in_array('Zend_Cache_Backend_ExtendedInterface', class_implements($this->_fastBackend))) { + Zend_Cache::throwException('fast_backend must implement the Zend_Cache_Backend_ExtendedInterface interface'); + } + } + + $this->_slowBackend->setDirectives($this->_directives); + $this->_fastBackend->setDirectives($this->_directives); + } + + /** + * Test if a cache is available or not (for the given id) + * + * @param string $id cache id + * @return mixed|false (a cache is not available) or "last modified" timestamp (int) of the available cache record + */ + public function test($id) + { + $fastTest = $this->_fastBackend->test($id); + if ($fastTest) { + return $fastTest; + } else { + return $this->_slowBackend->test($id); + } + } + + /** + * Save some string datas into a cache record + * + * Note : $data is always "string" (serialization is done by the + * core not by the backend) + * + * @param string $data Datas to cache + * @param string $id Cache id + * @param array $tags Array of strings, the cache record will be tagged by each string entry + * @param int $specificLifetime If != false, set a specific lifetime for this cache record (null => infinite lifetime) + * @param int $priority integer between 0 (very low priority) and 10 (maximum priority) used by some particular backends + * @return boolean true if no problem + */ + public function save($data, $id, $tags = array(), $specificLifetime = false, $priority = 8) + { + $usage = $this->_getFastFillingPercentage('saving'); + $boolFast = true; + $lifetime = $this->getLifetime($specificLifetime); + $preparedData = $this->_prepareData($data, $lifetime, $priority); + if (($priority > 0) && (10 * $priority >= $usage)) { + $fastLifetime = $this->_getFastLifetime($lifetime, $priority); + $boolFast = $this->_fastBackend->save($preparedData, $id, array(), $fastLifetime); + $boolSlow = $this->_slowBackend->save($preparedData, $id, $tags, $lifetime); + } else { + $boolSlow = $this->_slowBackend->save($preparedData, $id, $tags, $lifetime); + if ($boolSlow === true) { + $boolFast = $this->_fastBackend->remove($id); + if (!$boolFast && !$this->_fastBackend->test($id)) { + // some backends return false on remove() even if the key never existed. (and it won't if fast is full) + // all we care about is that the key doesn't exist now + $boolFast = true; + } + } + } + + return ($boolFast && $boolSlow); + } + + /** + * Test if a cache is available for the given id and (if yes) return it (false else) + * + * Note : return value is always "string" (unserialization is done by the core not by the backend) + * + * @param string $id Cache id + * @param boolean $doNotTestCacheValidity If set to true, the cache validity won't be tested + * @return string|false cached datas + */ + public function load($id, $doNotTestCacheValidity = false) + { + $resultFast = $this->_fastBackend->load($id, $doNotTestCacheValidity); + if ($resultFast === false) { + $resultSlow = $this->_slowBackend->load($id, $doNotTestCacheValidity); + if ($resultSlow === false) { + // there is no cache at all for this id + return false; + } + } + $array = $resultFast !== false ? unserialize($resultFast) : unserialize($resultSlow); + + //In case no cache entry was found in the FastCache and auto-filling is enabled, copy data to FastCache + if ($resultFast === false && $this->_options['auto_fill_fast_cache']) { + $preparedData = $this->_prepareData($array['data'], $array['lifetime'], $array['priority']); + $this->_fastBackend->save($preparedData, $id, array(), $array['lifetime']); + } + // maybe, we have to refresh the fast cache ? + elseif ($this->_options['auto_refresh_fast_cache']) { + if ($array['priority'] == 10) { + // no need to refresh the fast cache with priority = 10 + return $array['data']; + } + $newFastLifetime = $this->_getFastLifetime($array['lifetime'], $array['priority'], time() - $array['expire']); + // we have the time to refresh the fast cache + $usage = $this->_getFastFillingPercentage('loading'); + if (($array['priority'] > 0) && (10 * $array['priority'] >= $usage)) { + // we can refresh the fast cache + $preparedData = $this->_prepareData($array['data'], $array['lifetime'], $array['priority']); + $this->_fastBackend->save($preparedData, $id, array(), $newFastLifetime); + } + } + return $array['data']; + } + + /** + * Remove a cache record + * + * @param string $id Cache id + * @return boolean True if no problem + */ + public function remove($id) + { + $boolFast = $this->_fastBackend->remove($id); + $boolSlow = $this->_slowBackend->remove($id); + return $boolFast && $boolSlow; + } + + /** + * Clean some cache records + * + * Available modes are : + * Zend_Cache::CLEANING_MODE_ALL (default) => remove all cache entries ($tags is not used) + * Zend_Cache::CLEANING_MODE_OLD => remove too old cache entries ($tags is not used) + * Zend_Cache::CLEANING_MODE_MATCHING_TAG => remove cache entries matching all given tags + * ($tags can be an array of strings or a single string) + * Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG => remove cache entries not {matching one of the given tags} + * ($tags can be an array of strings or a single string) + * Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG => remove cache entries matching any given tags + * ($tags can be an array of strings or a single string) + * + * @param string $mode Clean mode + * @param array $tags Array of tags + * @throws Zend_Cache_Exception + * @return boolean true if no problem + */ + public function clean($mode = Zend_Cache::CLEANING_MODE_ALL, $tags = array()) + { + switch($mode) { + case Zend_Cache::CLEANING_MODE_ALL: + $boolFast = $this->_fastBackend->clean(Zend_Cache::CLEANING_MODE_ALL); + $boolSlow = $this->_slowBackend->clean(Zend_Cache::CLEANING_MODE_ALL); + return $boolFast && $boolSlow; + break; + case Zend_Cache::CLEANING_MODE_OLD: + return $this->_slowBackend->clean(Zend_Cache::CLEANING_MODE_OLD); + case Zend_Cache::CLEANING_MODE_MATCHING_TAG: + $ids = $this->_slowBackend->getIdsMatchingTags($tags); + $res = true; + foreach ($ids as $id) { + $bool = $this->remove($id); + $res = $res && $bool; + } + return $res; + break; + case Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG: + $ids = $this->_slowBackend->getIdsNotMatchingTags($tags); + $res = true; + foreach ($ids as $id) { + $bool = $this->remove($id); + $res = $res && $bool; + } + return $res; + break; + case Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG: + $ids = $this->_slowBackend->getIdsMatchingAnyTags($tags); + $res = true; + foreach ($ids as $id) { + $bool = $this->remove($id); + $res = $res && $bool; + } + return $res; + break; + default: + Zend_Cache::throwException('Invalid mode for clean() method'); + break; + } + } + + /** + * Return an array of stored cache ids + * + * @return array array of stored cache ids (string) + */ + public function getIds() + { + return $this->_slowBackend->getIds(); + } + + /** + * Return an array of stored tags + * + * @return array array of stored tags (string) + */ + public function getTags() + { + return $this->_slowBackend->getTags(); + } + + /** + * Return an array of stored cache ids which match given tags + * + * In case of multiple tags, a logical AND is made between tags + * + * @param array $tags array of tags + * @return array array of matching cache ids (string) + */ + public function getIdsMatchingTags($tags = array()) + { + return $this->_slowBackend->getIdsMatchingTags($tags); + } + + /** + * Return an array of stored cache ids which don't match given tags + * + * In case of multiple tags, a logical OR is made between tags + * + * @param array $tags array of tags + * @return array array of not matching cache ids (string) + */ + public function getIdsNotMatchingTags($tags = array()) + { + return $this->_slowBackend->getIdsNotMatchingTags($tags); + } + + /** + * Return an array of stored cache ids which match any given tags + * + * In case of multiple tags, a logical AND is made between tags + * + * @param array $tags array of tags + * @return array array of any matching cache ids (string) + */ + public function getIdsMatchingAnyTags($tags = array()) + { + return $this->_slowBackend->getIdsMatchingAnyTags($tags); + } + + /** + * Return the filling percentage of the backend storage + * + * @return int integer between 0 and 100 + */ + public function getFillingPercentage() + { + return $this->_slowBackend->getFillingPercentage(); + } + + /** + * Return an array of metadatas for the given cache id + * + * The array must include these keys : + * - expire : the expire timestamp + * - tags : a string array of tags + * - mtime : timestamp of last modification time + * + * @param string $id cache id + * @return array array of metadatas (false if the cache id is not found) + */ + public function getMetadatas($id) + { + return $this->_slowBackend->getMetadatas($id); + } + + /** + * Give (if possible) an extra lifetime to the given cache id + * + * @param string $id cache id + * @param int $extraLifetime + * @return boolean true if ok + */ + public function touch($id, $extraLifetime) + { + return $this->_slowBackend->touch($id, $extraLifetime); + } + + /** + * Return an associative array of capabilities (booleans) of the backend + * + * The array must include these keys : + * - automatic_cleaning (is automating cleaning necessary) + * - tags (are tags supported) + * - expired_read (is it possible to read expired cache records + * (for doNotTestCacheValidity option for example)) + * - priority does the backend deal with priority when saving + * - infinite_lifetime (is infinite lifetime can work with this backend) + * - get_list (is it possible to get the list of cache ids and the complete list of tags) + * + * @return array associative of with capabilities + */ + public function getCapabilities() + { + $slowBackendCapabilities = $this->_slowBackend->getCapabilities(); + return array( + 'automatic_cleaning' => $slowBackendCapabilities['automatic_cleaning'], + 'tags' => $slowBackendCapabilities['tags'], + 'expired_read' => $slowBackendCapabilities['expired_read'], + 'priority' => $slowBackendCapabilities['priority'], + 'infinite_lifetime' => $slowBackendCapabilities['infinite_lifetime'], + 'get_list' => $slowBackendCapabilities['get_list'] + ); + } + + /** + * Prepare a serialized array to store datas and metadatas informations + * + * @param string $data data to store + * @param int $lifetime original lifetime + * @param int $priority priority + * @return string serialize array to store into cache + */ + private function _prepareData($data, $lifetime, $priority) + { + $lt = $lifetime; + if ($lt === null) { + $lt = 9999999999; + } + return serialize(array( + 'data' => $data, + 'lifetime' => $lifetime, + 'expire' => time() + $lt, + 'priority' => $priority + )); + } + + /** + * Compute and return the lifetime for the fast backend + * + * @param int $lifetime original lifetime + * @param int $priority priority + * @param int $maxLifetime maximum lifetime + * @return int lifetime for the fast backend + */ + private function _getFastLifetime($lifetime, $priority, $maxLifetime = null) + { + if ($lifetime <= 0) { + // if no lifetime, we have an infinite lifetime + // we need to use arbitrary lifetimes + $fastLifetime = (int) (2592000 / (11 - $priority)); + } else { + // prevent computed infinite lifetime (0) by ceil + $fastLifetime = (int) ceil($lifetime / (11 - $priority)); + } + + if ($maxLifetime >= 0 && $fastLifetime > $maxLifetime) { + return $maxLifetime; + } + + return $fastLifetime; + } + + /** + * PUBLIC METHOD FOR UNIT TESTING ONLY ! + * + * Force a cache record to expire + * + * @param string $id cache id + */ + public function ___expire($id) + { + $this->_fastBackend->remove($id); + $this->_slowBackend->___expire($id); + } + + private function _getFastFillingPercentage($mode) + { + + if ($mode == 'saving') { + // mode saving + if ($this->_fastBackendFillingPercentage === null) { + $this->_fastBackendFillingPercentage = $this->_fastBackend->getFillingPercentage(); + } else { + $rand = rand(1, $this->_options['stats_update_factor']); + if ($rand == 1) { + // we force a refresh + $this->_fastBackendFillingPercentage = $this->_fastBackend->getFillingPercentage(); + } + } + } else { + // mode loading + // we compute the percentage only if it's not available in cache + if ($this->_fastBackendFillingPercentage === null) { + $this->_fastBackendFillingPercentage = $this->_fastBackend->getFillingPercentage(); + } + } + return $this->_fastBackendFillingPercentage; + } + +} diff --git a/library/vendor/Zend/Cache/Backend/WinCache.php b/library/vendor/Zend/Cache/Backend/WinCache.php new file mode 100644 index 0000000..c922280 --- /dev/null +++ b/library/vendor/Zend/Cache/Backend/WinCache.php @@ -0,0 +1,347 @@ + infinite lifetime) + * @return boolean true if no problem + */ + public function save($data, $id, $tags = array(), $specificLifetime = false) + { + $lifetime = $this->getLifetime($specificLifetime); + $result = wincache_ucache_set($id, array($data, time(), $lifetime), $lifetime); + if (count($tags) > 0) { + $this->_log(self::TAGS_UNSUPPORTED_BY_SAVE_OF_WINCACHE_BACKEND); + } + return $result; + } + + /** + * Remove a cache record + * + * @param string $id cache id + * @return boolean true if no problem + */ + public function remove($id) + { + return wincache_ucache_delete($id); + } + + /** + * Clean some cache records + * + * Available modes are : + * 'all' (default) => remove all cache entries ($tags is not used) + * 'old' => unsupported + * 'matchingTag' => unsupported + * 'notMatchingTag' => unsupported + * 'matchingAnyTag' => unsupported + * + * @param string $mode clean mode + * @param array $tags array of tags + * @throws Zend_Cache_Exception + * @return boolean true if no problem + */ + public function clean($mode = Zend_Cache::CLEANING_MODE_ALL, $tags = array()) + { + switch ($mode) { + case Zend_Cache::CLEANING_MODE_ALL: + return wincache_ucache_clear(); + break; + case Zend_Cache::CLEANING_MODE_OLD: + $this->_log("Zend_Cache_Backend_WinCache::clean() : CLEANING_MODE_OLD is unsupported by the WinCache backend"); + break; + case Zend_Cache::CLEANING_MODE_MATCHING_TAG: + case Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG: + case Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG: + $this->_log(self::TAGS_UNSUPPORTED_BY_CLEAN_OF_WINCACHE_BACKEND); + break; + default: + Zend_Cache::throwException('Invalid mode for clean() method'); + break; + } + } + + /** + * Return true if the automatic cleaning is available for the backend + * + * DEPRECATED : use getCapabilities() instead + * + * @deprecated + * @return boolean + */ + public function isAutomaticCleaningAvailable() + { + return false; + } + + /** + * Return the filling percentage of the backend storage + * + * @throws Zend_Cache_Exception + * @return int integer between 0 and 100 + */ + public function getFillingPercentage() + { + $mem = wincache_ucache_meminfo(); + $memSize = $mem['memory_total']; + $memUsed = $memSize - $mem['memory_free']; + if ($memSize == 0) { + Zend_Cache::throwException('can\'t get WinCache memory size'); + } + if ($memUsed > $memSize) { + return 100; + } + return ((int) (100. * ($memUsed / $memSize))); + } + + /** + * Return an array of stored tags + * + * @return array array of stored tags (string) + */ + public function getTags() + { + $this->_log(self::TAGS_UNSUPPORTED_BY_SAVE_OF_WINCACHE_BACKEND); + return array(); + } + + /** + * Return an array of stored cache ids which match given tags + * + * In case of multiple tags, a logical AND is made between tags + * + * @param array $tags array of tags + * @return array array of matching cache ids (string) + */ + public function getIdsMatchingTags($tags = array()) + { + $this->_log(self::TAGS_UNSUPPORTED_BY_SAVE_OF_WINCACHE_BACKEND); + return array(); + } + + /** + * Return an array of stored cache ids which don't match given tags + * + * In case of multiple tags, a logical OR is made between tags + * + * @param array $tags array of tags + * @return array array of not matching cache ids (string) + */ + public function getIdsNotMatchingTags($tags = array()) + { + $this->_log(self::TAGS_UNSUPPORTED_BY_SAVE_OF_WINCACHE_BACKEND); + return array(); + } + + /** + * Return an array of stored cache ids which match any given tags + * + * In case of multiple tags, a logical AND is made between tags + * + * @param array $tags array of tags + * @return array array of any matching cache ids (string) + */ + public function getIdsMatchingAnyTags($tags = array()) + { + $this->_log(self::TAGS_UNSUPPORTED_BY_SAVE_OF_WINCACHE_BACKEND); + return array(); + } + + /** + * Return an array of stored cache ids + * + * @return array array of stored cache ids (string) + */ + public function getIds() + { + $res = array(); + $array = wincache_ucache_info(); + $records = $array['ucache_entries']; + foreach ($records as $record) { + $res[] = $record['key_name']; + } + return $res; + } + + /** + * Return an array of metadatas for the given cache id + * + * The array must include these keys : + * - expire : the expire timestamp + * - tags : a string array of tags + * - mtime : timestamp of last modification time + * + * @param string $id cache id + * @return array array of metadatas (false if the cache id is not found) + */ + public function getMetadatas($id) + { + $tmp = wincache_ucache_get($id); + if (is_array($tmp)) { + $data = $tmp[0]; + $mtime = $tmp[1]; + if (!isset($tmp[2])) { + return false; + } + $lifetime = $tmp[2]; + return array( + 'expire' => $mtime + $lifetime, + 'tags' => array(), + 'mtime' => $mtime + ); + } + return false; + } + + /** + * Give (if possible) an extra lifetime to the given cache id + * + * @param string $id cache id + * @param int $extraLifetime + * @return boolean true if ok + */ + public function touch($id, $extraLifetime) + { + $tmp = wincache_ucache_get($id); + if (is_array($tmp)) { + $data = $tmp[0]; + $mtime = $tmp[1]; + if (!isset($tmp[2])) { + return false; + } + $lifetime = $tmp[2]; + $newLifetime = $lifetime - (time() - $mtime) + $extraLifetime; + if ($newLifetime <=0) { + return false; + } + return wincache_ucache_set($id, array($data, time(), $newLifetime), $newLifetime); + } + return false; + } + + /** + * Return an associative array of capabilities (booleans) of the backend + * + * The array must include these keys : + * - automatic_cleaning (is automating cleaning necessary) + * - tags (are tags supported) + * - expired_read (is it possible to read expired cache records + * (for doNotTestCacheValidity option for example)) + * - priority does the backend deal with priority when saving + * - infinite_lifetime (is infinite lifetime can work with this backend) + * - get_list (is it possible to get the list of cache ids and the complete list of tags) + * + * @return array associative of with capabilities + */ + public function getCapabilities() + { + return array( + 'automatic_cleaning' => false, + 'tags' => false, + 'expired_read' => false, + 'priority' => false, + 'infinite_lifetime' => false, + 'get_list' => true + ); + } + +} diff --git a/library/vendor/Zend/Cache/Backend/Xcache.php b/library/vendor/Zend/Cache/Backend/Xcache.php new file mode 100644 index 0000000..d78d52d --- /dev/null +++ b/library/vendor/Zend/Cache/Backend/Xcache.php @@ -0,0 +1,219 @@ + (string) user : + * xcache.admin.user (necessary for the clean() method) + * + * =====> (string) password : + * xcache.admin.pass (clear, not MD5) (necessary for the clean() method) + * + * @var array available options + */ + protected $_options = array( + 'user' => null, + 'password' => null + ); + + /** + * Constructor + * + * @param array $options associative array of options + * @throws Zend_Cache_Exception + * @return void + */ + public function __construct(array $options = array()) + { + if (!extension_loaded('xcache')) { + Zend_Cache::throwException('The xcache extension must be loaded for using this backend !'); + } + parent::__construct($options); + } + + /** + * Test if a cache is available for the given id and (if yes) return it (false else) + * + * WARNING $doNotTestCacheValidity=true is unsupported by the Xcache backend + * + * @param string $id cache id + * @param boolean $doNotTestCacheValidity if set to true, the cache validity won't be tested + * @return string cached datas (or false) + */ + public function load($id, $doNotTestCacheValidity = false) + { + if ($doNotTestCacheValidity) { + $this->_log("Zend_Cache_Backend_Xcache::load() : \$doNotTestCacheValidity=true is unsupported by the Xcache backend"); + } + $tmp = xcache_get($id); + if (is_array($tmp)) { + return $tmp[0]; + } + return false; + } + + /** + * Test if a cache is available or not (for the given id) + * + * @param string $id cache id + * @return mixed false (a cache is not available) or "last modified" timestamp (int) of the available cache record + */ + public function test($id) + { + if (xcache_isset($id)) { + $tmp = xcache_get($id); + if (is_array($tmp)) { + return $tmp[1]; + } + } + return false; + } + + /** + * Save some string datas into a cache record + * + * Note : $data is always "string" (serialization is done by the + * core not by the backend) + * + * @param string $data datas to cache + * @param string $id cache id + * @param array $tags array of strings, the cache record will be tagged by each string entry + * @param int $specificLifetime if != false, set a specific lifetime for this cache record (null => infinite lifetime) + * @return boolean true if no problem + */ + public function save($data, $id, $tags = array(), $specificLifetime = false) + { + $lifetime = $this->getLifetime($specificLifetime); + $result = xcache_set($id, array($data, time()), $lifetime); + if (count($tags) > 0) { + $this->_log(self::TAGS_UNSUPPORTED_BY_SAVE_OF_XCACHE_BACKEND); + } + return $result; + } + + /** + * Remove a cache record + * + * @param string $id cache id + * @return boolean true if no problem + */ + public function remove($id) + { + return xcache_unset($id); + } + + /** + * Clean some cache records + * + * Available modes are : + * 'all' (default) => remove all cache entries ($tags is not used) + * 'old' => unsupported + * 'matchingTag' => unsupported + * 'notMatchingTag' => unsupported + * 'matchingAnyTag' => unsupported + * + * @param string $mode clean mode + * @param array $tags array of tags + * @throws Zend_Cache_Exception + * @return boolean true if no problem + */ + public function clean($mode = Zend_Cache::CLEANING_MODE_ALL, $tags = array()) + { + switch ($mode) { + case Zend_Cache::CLEANING_MODE_ALL: + // Necessary because xcache_clear_cache() need basic authentification + $backup = array(); + if (isset($_SERVER['PHP_AUTH_USER'])) { + $backup['PHP_AUTH_USER'] = $_SERVER['PHP_AUTH_USER']; + } + if (isset($_SERVER['PHP_AUTH_PW'])) { + $backup['PHP_AUTH_PW'] = $_SERVER['PHP_AUTH_PW']; + } + if ($this->_options['user']) { + $_SERVER['PHP_AUTH_USER'] = $this->_options['user']; + } + if ($this->_options['password']) { + $_SERVER['PHP_AUTH_PW'] = $this->_options['password']; + } + + $cnt = xcache_count(XC_TYPE_VAR); + for ($i=0; $i < $cnt; $i++) { + xcache_clear_cache(XC_TYPE_VAR, $i); + } + + if (isset($backup['PHP_AUTH_USER'])) { + $_SERVER['PHP_AUTH_USER'] = $backup['PHP_AUTH_USER']; + $_SERVER['PHP_AUTH_PW'] = $backup['PHP_AUTH_PW']; + } + return true; + break; + case Zend_Cache::CLEANING_MODE_OLD: + $this->_log("Zend_Cache_Backend_Xcache::clean() : CLEANING_MODE_OLD is unsupported by the Xcache backend"); + break; + case Zend_Cache::CLEANING_MODE_MATCHING_TAG: + case Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG: + case Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG: + $this->_log(self::TAGS_UNSUPPORTED_BY_CLEAN_OF_XCACHE_BACKEND); + break; + default: + Zend_Cache::throwException('Invalid mode for clean() method'); + break; + } + } + + /** + * Return true if the automatic cleaning is available for the backend + * + * @return boolean + */ + public function isAutomaticCleaningAvailable() + { + return false; + } + +} diff --git a/library/vendor/Zend/Cache/Backend/ZendPlatform.php b/library/vendor/Zend/Cache/Backend/ZendPlatform.php new file mode 100644 index 0000000..8e6f460 --- /dev/null +++ b/library/vendor/Zend/Cache/Backend/ZendPlatform.php @@ -0,0 +1,315 @@ +_directives['lifetime']; + } + $res = output_cache_get($id, $lifetime); + if($res) { + return $res[0]; + } else { + return false; + } + } + + + /** + * Test if a cache is available or not (for the given id) + * + * @param string $id Cache id + * @return mixed|false false (a cache is not available) or "last modified" timestamp (int) of the available cache record + */ + public function test($id) + { + $result = output_cache_get($id, $this->_directives['lifetime']); + if ($result) { + return $result[1]; + } + return false; + } + + /** + * Save some string datas into a cache record + * + * Note : $data is always "string" (serialization is done by the + * core not by the backend) + * + * @param string $data Data to cache + * @param string $id Cache id + * @param array $tags Array of strings, the cache record will be tagged by each string entry + * @param int $specificLifetime If != false, set a specific lifetime for this cache record (null => infinite lifetime) + * @return boolean true if no problem + */ + public function save($data, $id, $tags = array(), $specificLifetime = false) + { + if (!($specificLifetime === false)) { + $this->_log("Zend_Cache_Backend_ZendPlatform::save() : non false specifc lifetime is unsuported for this backend"); + } + + $lifetime = $this->_directives['lifetime']; + $result1 = output_cache_put($id, array($data, time())); + $result2 = (count($tags) == 0); + + foreach ($tags as $tag) { + $tagid = self::TAGS_PREFIX.$tag; + $old_tags = output_cache_get($tagid, $lifetime); + if ($old_tags === false) { + $old_tags = array(); + } + $old_tags[$id] = $id; + output_cache_remove_key($tagid); + $result2 = output_cache_put($tagid, $old_tags); + } + + return $result1 && $result2; + } + + + /** + * Remove a cache record + * + * @param string $id Cache id + * @return boolean True if no problem + */ + public function remove($id) + { + return output_cache_remove_key($id); + } + + + /** + * Clean some cache records + * + * Available modes are : + * Zend_Cache::CLEANING_MODE_ALL (default) => remove all cache entries ($tags is not used) + * Zend_Cache::CLEANING_MODE_OLD => remove too old cache entries ($tags is not used) + * This mode is not supported in this backend + * Zend_Cache::CLEANING_MODE_MATCHING_TAG => remove cache entries matching all given tags + * ($tags can be an array of strings or a single string) + * Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG => unsupported + * Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG => remove cache entries matching any given tags + * ($tags can be an array of strings or a single string) + * + * @param string $mode Clean mode + * @param array $tags Array of tags + * @throws Zend_Cache_Exception + * @return boolean True if no problem + */ + public function clean($mode = Zend_Cache::CLEANING_MODE_ALL, $tags = array()) + { + switch ($mode) { + case Zend_Cache::CLEANING_MODE_ALL: + case Zend_Cache::CLEANING_MODE_OLD: + $cache_dir = ini_get('zend_accelerator.output_cache_dir'); + if (!$cache_dir) { + return false; + } + $cache_dir .= '/.php_cache_api/'; + return $this->_clean($cache_dir, $mode); + break; + case Zend_Cache::CLEANING_MODE_MATCHING_TAG: + $idlist = null; + foreach ($tags as $tag) { + $next_idlist = output_cache_get(self::TAGS_PREFIX.$tag, $this->_directives['lifetime']); + if ($idlist) { + $idlist = array_intersect_assoc($idlist, $next_idlist); + } else { + $idlist = $next_idlist; + } + if (count($idlist) == 0) { + // if ID list is already empty - we may skip checking other IDs + $idlist = null; + break; + } + } + if ($idlist) { + foreach ($idlist as $id) { + output_cache_remove_key($id); + } + } + return true; + break; + case Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG: + $this->_log("Zend_Cache_Backend_ZendPlatform::clean() : CLEANING_MODE_NOT_MATCHING_TAG is not supported by the Zend Platform backend"); + return false; + break; + case Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG: + $idlist = null; + foreach ($tags as $tag) { + $next_idlist = output_cache_get(self::TAGS_PREFIX.$tag, $this->_directives['lifetime']); + if ($idlist) { + $idlist = array_merge_recursive($idlist, $next_idlist); + } else { + $idlist = $next_idlist; + } + if (count($idlist) == 0) { + // if ID list is already empty - we may skip checking other IDs + $idlist = null; + break; + } + } + if ($idlist) { + foreach ($idlist as $id) { + output_cache_remove_key($id); + } + } + return true; + break; + default: + Zend_Cache::throwException('Invalid mode for clean() method'); + break; + } + } + + /** + * Clean a directory and recursivly go over it's subdirectories + * + * Remove all the cached files that need to be cleaned (according to mode and files mtime) + * + * @param string $dir Path of directory ot clean + * @param string $mode The same parameter as in Zend_Cache_Backend_ZendPlatform::clean() + * @return boolean True if ok + */ + private function _clean($dir, $mode) + { + $d = @dir($dir); + if (!$d) { + return false; + } + $result = true; + while (false !== ($file = $d->read())) { + if ($file == '.' || $file == '..') { + continue; + } + $file = $d->path . $file; + if (is_dir($file)) { + $result = ($this->_clean($file .'/', $mode)) && ($result); + } else { + if ($mode == Zend_Cache::CLEANING_MODE_ALL) { + $result = ($this->_remove($file)) && ($result); + } else if ($mode == Zend_Cache::CLEANING_MODE_OLD) { + // Files older than lifetime get deleted from cache + if ($this->_directives['lifetime'] !== null) { + if ((time() - @filemtime($file)) > $this->_directives['lifetime']) { + $result = ($this->_remove($file)) && ($result); + } + } + } + } + } + $d->close(); + return $result; + } + + /** + * Remove a file + * + * If we can't remove the file (because of locks or any problem), we will touch + * the file to invalidate it + * + * @param string $file Complete file path + * @return boolean True if ok + */ + private function _remove($file) + { + if (!@unlink($file)) { + # If we can't remove the file (because of locks or any problem), we will touch + # the file to invalidate it + $this->_log("Zend_Cache_Backend_ZendPlatform::_remove() : we can't remove $file => we are going to try to invalidate it"); + if ($this->_directives['lifetime'] === null) { + return false; + } + if (!file_exists($file)) { + return false; + } + return @touch($file, time() - 2*abs($this->_directives['lifetime'])); + } + return true; + } + +} diff --git a/library/vendor/Zend/Cache/Backend/ZendServer.php b/library/vendor/Zend/Cache/Backend/ZendServer.php new file mode 100644 index 0000000..6243d86 --- /dev/null +++ b/library/vendor/Zend/Cache/Backend/ZendServer.php @@ -0,0 +1,205 @@ + (string) namespace : + * Namespace to be used for chaching operations + * + * @var array available options + */ + protected $_options = array( + 'namespace' => 'zendframework' + ); + + /** + * Store data + * + * @param mixed $data Object to store + * @param string $id Cache id + * @param int $timeToLive Time to live in seconds + * @throws Zend_Cache_Exception + */ + abstract protected function _store($data, $id, $timeToLive); + + /** + * Fetch data + * + * @param string $id Cache id + * @throws Zend_Cache_Exception + */ + abstract protected function _fetch($id); + + /** + * Unset data + * + * @param string $id Cache id + */ + abstract protected function _unset($id); + + /** + * Clear cache + */ + abstract protected function _clear(); + + /** + * Test if a cache is available for the given id and (if yes) return it (false else) + * + * @param string $id cache id + * @param boolean $doNotTestCacheValidity if set to true, the cache validity won't be tested + * @return string cached datas (or false) + */ + public function load($id, $doNotTestCacheValidity = false) + { + $tmp = $this->_fetch($id); + if ($tmp !== null) { + return $tmp; + } + return false; + } + + /** + * Test if a cache is available or not (for the given id) + * + * @param string $id cache id + * @return mixed false (a cache is not available) or "last modified" timestamp (int) of the available cache record + * @throws Zend_Cache_Exception + */ + public function test($id) + { + $tmp = $this->_fetch('internal-metadatas---' . $id); + if ($tmp !== false) { + if (!is_array($tmp) || !isset($tmp['mtime'])) { + Zend_Cache::throwException('Cache metadata for \'' . $id . '\' id is corrupted' ); + } + return $tmp['mtime']; + } + return false; + } + + /** + * Compute & return the expire time + * + * @return int expire time (unix timestamp) + */ + private function _expireTime($lifetime) + { + if ($lifetime === null) { + return 9999999999; + } + return time() + $lifetime; + } + + /** + * Save some string datas into a cache record + * + * Note : $data is always "string" (serialization is done by the + * core not by the backend) + * + * @param string $data datas to cache + * @param string $id cache id + * @param array $tags array of strings, the cache record will be tagged by each string entry + * @param int $specificLifetime if != false, set a specific lifetime for this cache record (null => infinite lifetime) + * @return boolean true if no problem + */ + public function save($data, $id, $tags = array(), $specificLifetime = false) + { + $lifetime = $this->getLifetime($specificLifetime); + $metadatas = array( + 'mtime' => time(), + 'expire' => $this->_expireTime($lifetime), + ); + + if (count($tags) > 0) { + $this->_log('Zend_Cache_Backend_ZendServer::save() : tags are unsupported by the ZendServer backends'); + } + + return $this->_store($data, $id, $lifetime) && + $this->_store($metadatas, 'internal-metadatas---' . $id, $lifetime); + } + + /** + * Remove a cache record + * + * @param string $id cache id + * @return boolean true if no problem + */ + public function remove($id) + { + $result1 = $this->_unset($id); + $result2 = $this->_unset('internal-metadatas---' . $id); + + return $result1 && $result2; + } + + /** + * Clean some cache records + * + * Available modes are : + * 'all' (default) => remove all cache entries ($tags is not used) + * 'old' => unsupported + * 'matchingTag' => unsupported + * 'notMatchingTag' => unsupported + * 'matchingAnyTag' => unsupported + * + * @param string $mode clean mode + * @param array $tags array of tags + * @throws Zend_Cache_Exception + * @return boolean true if no problem + */ + public function clean($mode = Zend_Cache::CLEANING_MODE_ALL, $tags = array()) + { + switch ($mode) { + case Zend_Cache::CLEANING_MODE_ALL: + $this->_clear(); + return true; + break; + case Zend_Cache::CLEANING_MODE_OLD: + $this->_log("Zend_Cache_Backend_ZendServer::clean() : CLEANING_MODE_OLD is unsupported by the Zend Server backends."); + break; + case Zend_Cache::CLEANING_MODE_MATCHING_TAG: + case Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG: + case Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG: + $this->_clear(); + $this->_log('Zend_Cache_Backend_ZendServer::clean() : tags are unsupported by the Zend Server backends.'); + break; + default: + Zend_Cache::throwException('Invalid mode for clean() method'); + break; + } + } +} diff --git a/library/vendor/Zend/Cache/Backend/ZendServer/Disk.php b/library/vendor/Zend/Cache/Backend/ZendServer/Disk.php new file mode 100644 index 0000000..09cd126 --- /dev/null +++ b/library/vendor/Zend/Cache/Backend/ZendServer/Disk.php @@ -0,0 +1,99 @@ +_options['namespace'] . '::' . $id, + $data, + $timeToLive) === false) { + $this->_log('Store operation failed.'); + return false; + } + return true; + } + + /** + * Fetch data + * + * @param string $id Cache id + * @return mixed|null + */ + protected function _fetch($id) + { + return zend_disk_cache_fetch($this->_options['namespace'] . '::' . $id); + } + + /** + * Unset data + * + * @param string $id Cache id + * @return boolean true if no problem + */ + protected function _unset($id) + { + return zend_disk_cache_delete($this->_options['namespace'] . '::' . $id); + } + + /** + * Clear cache + */ + protected function _clear() + { + zend_disk_cache_clear($this->_options['namespace']); + } +} diff --git a/library/vendor/Zend/Cache/Backend/ZendServer/ShMem.php b/library/vendor/Zend/Cache/Backend/ZendServer/ShMem.php new file mode 100644 index 0000000..5fe1894 --- /dev/null +++ b/library/vendor/Zend/Cache/Backend/ZendServer/ShMem.php @@ -0,0 +1,99 @@ +_options['namespace'] . '::' . $id, + $data, + $timeToLive) === false) { + $this->_log('Store operation failed.'); + return false; + } + return true; + } + + /** + * Fetch data + * + * @param string $id Cache id + * @return mixed|null + */ + protected function _fetch($id) + { + return zend_shm_cache_fetch($this->_options['namespace'] . '::' . $id); + } + + /** + * Unset data + * + * @param string $id Cache id + * @return boolean true if no problem + */ + protected function _unset($id) + { + return zend_shm_cache_delete($this->_options['namespace'] . '::' . $id); + } + + /** + * Clear cache + */ + protected function _clear() + { + zend_shm_cache_clear($this->_options['namespace']); + } +} diff --git a/library/vendor/Zend/Cache/Core.php b/library/vendor/Zend/Cache/Core.php new file mode 100644 index 0000000..833f247 --- /dev/null +++ b/library/vendor/Zend/Cache/Core.php @@ -0,0 +1,762 @@ + (boolean) write_control : + * - Enable / disable write control (the cache is read just after writing to detect corrupt entries) + * - Enable write control will lightly slow the cache writing but not the cache reading + * Write control can detect some corrupt cache files but maybe it's not a perfect control + * + * ====> (boolean) caching : + * - Enable / disable caching + * (can be very useful for the debug of cached scripts) + * + * =====> (string) cache_id_prefix : + * - prefix for cache ids (namespace) + * + * ====> (boolean) automatic_serialization : + * - Enable / disable automatic serialization + * - It can be used to save directly datas which aren't strings (but it's slower) + * + * ====> (int) automatic_cleaning_factor : + * - Disable / Tune the automatic cleaning process + * - The automatic cleaning process destroy too old (for the given life time) + * cache files when a new cache file is written : + * 0 => no automatic cache cleaning + * 1 => systematic cache cleaning + * x (integer) > 1 => automatic cleaning randomly 1 times on x cache write + * + * ====> (int) lifetime : + * - Cache lifetime (in seconds) + * - If null, the cache is valid forever. + * + * ====> (boolean) logging : + * - If set to true, logging is activated (but the system is slower) + * + * ====> (boolean) ignore_user_abort + * - If set to true, the core will set the ignore_user_abort PHP flag inside the + * save() method to avoid cache corruptions in some cases (default false) + * + * @var array $_options available options + */ + protected $_options = array( + 'write_control' => true, + 'caching' => true, + 'cache_id_prefix' => null, + 'automatic_serialization' => false, + 'automatic_cleaning_factor' => 10, + 'lifetime' => 3600, + 'logging' => false, + 'logger' => null, + 'ignore_user_abort' => false + ); + + /** + * Array of options which have to be transfered to backend + * + * @var array $_directivesList + */ + protected static $_directivesList = array('lifetime', 'logging', 'logger'); + + /** + * Not used for the core, just a sort a hint to get a common setOption() method (for the core and for frontends) + * + * @var array $_specificOptions + */ + protected $_specificOptions = array(); + + /** + * Last used cache id + * + * @var string $_lastId + */ + private $_lastId = null; + + /** + * True if the backend implements Zend_Cache_Backend_ExtendedInterface + * + * @var boolean $_extendedBackend + */ + protected $_extendedBackend = false; + + /** + * Array of capabilities of the backend (only if it implements Zend_Cache_Backend_ExtendedInterface) + * + * @var array + */ + protected $_backendCapabilities = array(); + + /** + * Constructor + * + * @param array|Zend_Config $options Associative array of options or Zend_Config instance + * @throws Zend_Cache_Exception + * @return void + */ + public function __construct($options = array()) + { + if ($options instanceof Zend_Config) { + $options = $options->toArray(); + } + if (!is_array($options)) { + Zend_Cache::throwException("Options passed were not an array" + . " or Zend_Config instance."); + } + foreach ($options as $name => $value) { + $this->setOption($name, $value); + } + $this->_loggerSanity(); + } + + /** + * Set options using an instance of type Zend_Config + * + * @param Zend_Config $config + * @return Zend_Cache_Core + */ + public function setConfig(Zend_Config $config) + { + $options = $config->toArray(); + foreach ($options as $name => $value) { + $this->setOption($name, $value); + } + return $this; + } + + /** + * Set the backend + * + * @param Zend_Cache_Backend $backendObject + * @throws Zend_Cache_Exception + * @return void + */ + public function setBackend(Zend_Cache_Backend $backendObject) + { + $this->_backend= $backendObject; + // some options (listed in $_directivesList) have to be given + // to the backend too (even if they are not "backend specific") + $directives = array(); + foreach (Zend_Cache_Core::$_directivesList as $directive) { + $directives[$directive] = $this->_options[$directive]; + } + $this->_backend->setDirectives($directives); + if (in_array('Zend_Cache_Backend_ExtendedInterface', class_implements($this->_backend))) { + $this->_extendedBackend = true; + $this->_backendCapabilities = $this->_backend->getCapabilities(); + } + + } + + /** + * Returns the backend + * + * @return Zend_Cache_Backend backend object + */ + public function getBackend() + { + return $this->_backend; + } + + /** + * Public frontend to set an option + * + * There is an additional validation (relatively to the protected _setOption method) + * + * @param string $name Name of the option + * @param mixed $value Value of the option + * @throws Zend_Cache_Exception + * @return void + */ + public function setOption($name, $value) + { + if (!is_string($name)) { + Zend_Cache::throwException("Incorrect option name!"); + } + $name = strtolower($name); + if (array_key_exists($name, $this->_options)) { + // This is a Core option + $this->_setOption($name, $value); + return; + } + if (array_key_exists($name, $this->_specificOptions)) { + // This a specic option of this frontend + $this->_specificOptions[$name] = $value; + return; + } + } + + /** + * Public frontend to get an option value + * + * @param string $name Name of the option + * @throws Zend_Cache_Exception + * @return mixed option value + */ + public function getOption($name) + { + $name = strtolower($name); + + if (array_key_exists($name, $this->_options)) { + // This is a Core option + return $this->_options[$name]; + } + + if (array_key_exists($name, $this->_specificOptions)) { + // This a specic option of this frontend + return $this->_specificOptions[$name]; + } + + Zend_Cache::throwException("Incorrect option name : $name"); + } + + /** + * Set an option + * + * @param string $name Name of the option + * @param mixed $value Value of the option + * @throws Zend_Cache_Exception + * @return void + */ + private function _setOption($name, $value) + { + if (!is_string($name) || !array_key_exists($name, $this->_options)) { + Zend_Cache::throwException("Incorrect option name : $name"); + } + if ($name == 'lifetime' && empty($value)) { + $value = null; + } + $this->_options[$name] = $value; + } + + /** + * Force a new lifetime + * + * The new value is set for the core/frontend but for the backend too (directive) + * + * @param int $newLifetime New lifetime (in seconds) + * @return void + */ + public function setLifetime($newLifetime) + { + $this->_options['lifetime'] = $newLifetime; + $this->_backend->setDirectives(array( + 'lifetime' => $newLifetime + )); + } + + /** + * Test if a cache is available for the given id and (if yes) return it (false else) + * + * @param string $id Cache id + * @param boolean $doNotTestCacheValidity If set to true, the cache validity won't be tested + * @param boolean $doNotUnserialize Do not serialize (even if automatic_serialization is true) => for internal use + * @return mixed|false Cached datas + */ + public function load($id, $doNotTestCacheValidity = false, $doNotUnserialize = false) + { + if (!$this->_options['caching']) { + return false; + } + $id = $this->_id($id); // cache id may need prefix + $this->_lastId = $id; + $this->_validateIdOrTag($id); + + $this->_log("Zend_Cache_Core: load item '{$id}'", 7); + $data = $this->_backend->load($id, $doNotTestCacheValidity); + if ($data===false) { + // no cache available + return false; + } + if ((!$doNotUnserialize) && $this->_options['automatic_serialization']) { + // we need to unserialize before sending the result + return unserialize($data); + } + return $data; + } + + /** + * Test if a cache is available for the given id + * + * @param string $id Cache id + * @return int|false Last modified time of cache entry if it is available, false otherwise + */ + public function test($id) + { + if (!$this->_options['caching']) { + return false; + } + $id = $this->_id($id); // cache id may need prefix + $this->_validateIdOrTag($id); + $this->_lastId = $id; + + $this->_log("Zend_Cache_Core: test item '{$id}'", 7); + return $this->_backend->test($id); + } + + /** + * Save some data in a cache + * + * @param mixed $data Data to put in cache (can be another type than string if automatic_serialization is on) + * @param string $id Cache id (if not set, the last cache id will be used) + * @param array $tags Cache tags + * @param int $specificLifetime If != false, set a specific lifetime for this cache record (null => infinite lifetime) + * @param int $priority integer between 0 (very low priority) and 10 (maximum priority) used by some particular backends + * @throws Zend_Cache_Exception + * @return boolean True if no problem + */ + public function save($data, $id = null, $tags = array(), $specificLifetime = false, $priority = 8) + { + if (!$this->_options['caching']) { + return true; + } + if ($id === null) { + $id = $this->_lastId; + } else { + $id = $this->_id($id); + } + $this->_validateIdOrTag($id); + $this->_validateTagsArray($tags); + if ($this->_options['automatic_serialization']) { + // we need to serialize datas before storing them + $data = serialize($data); + } else { + if (!is_string($data)) { + Zend_Cache::throwException("Datas must be string or set automatic_serialization = true"); + } + } + + // automatic cleaning + if ($this->_options['automatic_cleaning_factor'] > 0) { + $rand = rand(1, $this->_options['automatic_cleaning_factor']); + if ($rand==1) { + // new way || deprecated way + if ($this->_extendedBackend || method_exists($this->_backend, 'isAutomaticCleaningAvailable')) { + $this->_log("Zend_Cache_Core::save(): automatic cleaning running", 7); + $this->clean(Zend_Cache::CLEANING_MODE_OLD); + } else { + $this->_log("Zend_Cache_Core::save(): automatic cleaning is not available/necessary with current backend", 4); + } + } + } + + $this->_log("Zend_Cache_Core: save item '{$id}'", 7); + if ($this->_options['ignore_user_abort']) { + $abort = ignore_user_abort(true); + } + if (($this->_extendedBackend) && ($this->_backendCapabilities['priority'])) { + $result = $this->_backend->save($data, $id, $tags, $specificLifetime, $priority); + } else { + $result = $this->_backend->save($data, $id, $tags, $specificLifetime); + } + if ($this->_options['ignore_user_abort']) { + ignore_user_abort($abort); + } + + if (!$result) { + // maybe the cache is corrupted, so we remove it ! + $this->_log("Zend_Cache_Core::save(): failed to save item '{$id}' -> removing it", 4); + $this->_backend->remove($id); + return false; + } + + if ($this->_options['write_control']) { + $data2 = $this->_backend->load($id, true); + if ($data!=$data2) { + $this->_log("Zend_Cache_Core::save(): write control of item '{$id}' failed -> removing it", 4); + $this->_backend->remove($id); + return false; + } + } + + return true; + } + + /** + * Remove a cache + * + * @param string $id Cache id to remove + * @return boolean True if ok + */ + public function remove($id) + { + if (!$this->_options['caching']) { + return true; + } + $id = $this->_id($id); // cache id may need prefix + $this->_validateIdOrTag($id); + + $this->_log("Zend_Cache_Core: remove item '{$id}'", 7); + return $this->_backend->remove($id); + } + + /** + * Clean cache entries + * + * Available modes are : + * 'all' (default) => remove all cache entries ($tags is not used) + * 'old' => remove too old cache entries ($tags is not used) + * 'matchingTag' => remove cache entries matching all given tags + * ($tags can be an array of strings or a single string) + * 'notMatchingTag' => remove cache entries not matching one of the given tags + * ($tags can be an array of strings or a single string) + * 'matchingAnyTag' => remove cache entries matching any given tags + * ($tags can be an array of strings or a single string) + * + * @param string $mode + * @param array|string $tags + * @throws Zend_Cache_Exception + * @return boolean True if ok + */ + public function clean($mode = 'all', $tags = array()) + { + if (!$this->_options['caching']) { + return true; + } + if (!in_array($mode, array(Zend_Cache::CLEANING_MODE_ALL, + Zend_Cache::CLEANING_MODE_OLD, + Zend_Cache::CLEANING_MODE_MATCHING_TAG, + Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG, + Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG))) { + Zend_Cache::throwException('Invalid cleaning mode'); + } + $this->_validateTagsArray($tags); + + return $this->_backend->clean($mode, $tags); + } + + /** + * Return an array of stored cache ids which match given tags + * + * In case of multiple tags, a logical AND is made between tags + * + * @param array $tags array of tags + * @return array array of matching cache ids (string) + */ + public function getIdsMatchingTags($tags = array()) + { + if (!$this->_extendedBackend) { + Zend_Cache::throwException(self::BACKEND_NOT_IMPLEMENTS_EXTENDED_IF); + } + if (!($this->_backendCapabilities['tags'])) { + Zend_Cache::throwException(self::BACKEND_NOT_SUPPORTS_TAG); + } + + $ids = $this->_backend->getIdsMatchingTags($tags); + + // we need to remove cache_id_prefix from ids (see #ZF-6178, #ZF-7600) + if (isset($this->_options['cache_id_prefix']) && $this->_options['cache_id_prefix'] !== '') { + $prefix = & $this->_options['cache_id_prefix']; + $prefixLen = strlen($prefix); + foreach ($ids as &$id) { + if (strpos($id, $prefix) === 0) { + $id = substr($id, $prefixLen); + } + } + } + + return $ids; + } + + /** + * Return an array of stored cache ids which don't match given tags + * + * In case of multiple tags, a logical OR is made between tags + * + * @param array $tags array of tags + * @return array array of not matching cache ids (string) + */ + public function getIdsNotMatchingTags($tags = array()) + { + if (!$this->_extendedBackend) { + Zend_Cache::throwException(self::BACKEND_NOT_IMPLEMENTS_EXTENDED_IF); + } + if (!($this->_backendCapabilities['tags'])) { + Zend_Cache::throwException(self::BACKEND_NOT_SUPPORTS_TAG); + } + + $ids = $this->_backend->getIdsNotMatchingTags($tags); + + // we need to remove cache_id_prefix from ids (see #ZF-6178, #ZF-7600) + if (isset($this->_options['cache_id_prefix']) && $this->_options['cache_id_prefix'] !== '') { + $prefix = & $this->_options['cache_id_prefix']; + $prefixLen = strlen($prefix); + foreach ($ids as &$id) { + if (strpos($id, $prefix) === 0) { + $id = substr($id, $prefixLen); + } + } + } + + return $ids; + } + + /** + * Return an array of stored cache ids which match any given tags + * + * In case of multiple tags, a logical OR is made between tags + * + * @param array $tags array of tags + * @return array array of matching any cache ids (string) + */ + public function getIdsMatchingAnyTags($tags = array()) + { + if (!$this->_extendedBackend) { + Zend_Cache::throwException(self::BACKEND_NOT_IMPLEMENTS_EXTENDED_IF); + } + if (!($this->_backendCapabilities['tags'])) { + Zend_Cache::throwException(self::BACKEND_NOT_SUPPORTS_TAG); + } + + $ids = $this->_backend->getIdsMatchingAnyTags($tags); + + // we need to remove cache_id_prefix from ids (see #ZF-6178, #ZF-7600) + if (isset($this->_options['cache_id_prefix']) && $this->_options['cache_id_prefix'] !== '') { + $prefix = & $this->_options['cache_id_prefix']; + $prefixLen = strlen($prefix); + foreach ($ids as &$id) { + if (strpos($id, $prefix) === 0) { + $id = substr($id, $prefixLen); + } + } + } + + return $ids; + } + + /** + * Return an array of stored cache ids + * + * @return array array of stored cache ids (string) + */ + public function getIds() + { + if (!$this->_extendedBackend) { + Zend_Cache::throwException(self::BACKEND_NOT_IMPLEMENTS_EXTENDED_IF); + } + + $ids = $this->_backend->getIds(); + + // we need to remove cache_id_prefix from ids (see #ZF-6178, #ZF-7600) + if (isset($this->_options['cache_id_prefix']) && $this->_options['cache_id_prefix'] !== '') { + $prefix = & $this->_options['cache_id_prefix']; + $prefixLen = strlen($prefix); + foreach ($ids as &$id) { + if (strpos($id, $prefix) === 0) { + $id = substr($id, $prefixLen); + } + } + } + + return $ids; + } + + /** + * Return an array of stored tags + * + * @return array array of stored tags (string) + */ + public function getTags() + { + if (!$this->_extendedBackend) { + Zend_Cache::throwException(self::BACKEND_NOT_IMPLEMENTS_EXTENDED_IF); + } + if (!($this->_backendCapabilities['tags'])) { + Zend_Cache::throwException(self::BACKEND_NOT_SUPPORTS_TAG); + } + return $this->_backend->getTags(); + } + + /** + * Return the filling percentage of the backend storage + * + * @return int integer between 0 and 100 + */ + public function getFillingPercentage() + { + if (!$this->_extendedBackend) { + Zend_Cache::throwException(self::BACKEND_NOT_IMPLEMENTS_EXTENDED_IF); + } + return $this->_backend->getFillingPercentage(); + } + + /** + * Return an array of metadatas for the given cache id + * + * The array will include these keys : + * - expire : the expire timestamp + * - tags : a string array of tags + * - mtime : timestamp of last modification time + * + * @param string $id cache id + * @return array array of metadatas (false if the cache id is not found) + */ + public function getMetadatas($id) + { + if (!$this->_extendedBackend) { + Zend_Cache::throwException(self::BACKEND_NOT_IMPLEMENTS_EXTENDED_IF); + } + $id = $this->_id($id); // cache id may need prefix + return $this->_backend->getMetadatas($id); + } + + /** + * Give (if possible) an extra lifetime to the given cache id + * + * @param string $id cache id + * @param int $extraLifetime + * @return boolean true if ok + */ + public function touch($id, $extraLifetime) + { + if (!$this->_extendedBackend) { + Zend_Cache::throwException(self::BACKEND_NOT_IMPLEMENTS_EXTENDED_IF); + } + $id = $this->_id($id); // cache id may need prefix + + $this->_log("Zend_Cache_Core: touch item '{$id}'", 7); + return $this->_backend->touch($id, $extraLifetime); + } + + /** + * Validate a cache id or a tag (security, reliable filenames, reserved prefixes...) + * + * Throw an exception if a problem is found + * + * @param string $string Cache id or tag + * @throws Zend_Cache_Exception + * @return void + */ + protected function _validateIdOrTag($string) + { + if (!is_string($string)) { + Zend_Cache::throwException('Invalid id or tag : must be a string'); + } + if (substr($string, 0, 9) == 'internal-') { + Zend_Cache::throwException('"internal-*" ids or tags are reserved'); + } + if (!preg_match('~^[a-zA-Z0-9_]+$~D', $string)) { + Zend_Cache::throwException("Invalid id or tag '$string' : must use only [a-zA-Z0-9_]"); + } + } + + /** + * Validate a tags array (security, reliable filenames, reserved prefixes...) + * + * Throw an exception if a problem is found + * + * @param array $tags Array of tags + * @throws Zend_Cache_Exception + * @return void + */ + protected function _validateTagsArray($tags) + { + if (!is_array($tags)) { + Zend_Cache::throwException('Invalid tags array : must be an array'); + } + foreach($tags as $tag) { + $this->_validateIdOrTag($tag); + } + reset($tags); + } + + /** + * Make sure if we enable logging that the Zend_Log class + * is available. + * Create a default log object if none is set. + * + * @throws Zend_Cache_Exception + * @return void + */ + protected function _loggerSanity() + { + if (!isset($this->_options['logging']) || !$this->_options['logging']) { + return; + } + + if (isset($this->_options['logger']) && $this->_options['logger'] instanceof Zend_Log) { + return; + } + + // Create a default logger to the standard output stream + $logger = new Zend_Log(new Zend_Log_Writer_Stream('php://output')); + $logger->addFilter(new Zend_Log_Filter_Priority(Zend_Log::WARN, '<=')); + $this->_options['logger'] = $logger; + } + + /** + * Log a message at the WARN (4) priority. + * + * @param string $message + * @throws Zend_Cache_Exception + * @return void + */ + protected function _log($message, $priority = 4) + { + if (!$this->_options['logging']) { + return; + } + if (!(isset($this->_options['logger']) || $this->_options['logger'] instanceof Zend_Log)) { + Zend_Cache::throwException('Logging is enabled but logger is not set'); + } + $logger = $this->_options['logger']; + $logger->log($message, $priority); + } + + /** + * Make and return a cache id + * + * Checks 'cache_id_prefix' and returns new id with prefix or simply the id if null + * + * @param string $id Cache id + * @return string Cache id (with or without prefix) + */ + protected function _id($id) + { + if (($id !== null) && isset($this->_options['cache_id_prefix'])) { + return $this->_options['cache_id_prefix'] . $id; // return with prefix + } + return $id; // no prefix, just return the $id passed + } + +} diff --git a/library/vendor/Zend/Cache/Exception.php b/library/vendor/Zend/Cache/Exception.php new file mode 100644 index 0000000..bc3c815 --- /dev/null +++ b/library/vendor/Zend/Cache/Exception.php @@ -0,0 +1,31 @@ +_tags = $tags; + $this->_extension = $extension; + ob_start(array($this, '_flush')); + ob_implicit_flush(false); + $this->_idStack[] = $id; + return false; + } + + /** + * callback for output buffering + * (shouldn't really be called manually) + * + * @param string $data Buffered output + * @return string Data to send to browser + */ + public function _flush($data) + { + $id = array_pop($this->_idStack); + if ($id === null) { + Zend_Cache::throwException('use of _flush() without a start()'); + } + if ($this->_extension) { + $this->save(serialize(array($data, $this->_extension)), $id, $this->_tags); + } else { + $this->save($data, $id, $this->_tags); + } + return $data; + } +} diff --git a/library/vendor/Zend/Cache/Frontend/Class.php b/library/vendor/Zend/Cache/Frontend/Class.php new file mode 100644 index 0000000..c7208a1 --- /dev/null +++ b/library/vendor/Zend/Cache/Frontend/Class.php @@ -0,0 +1,274 @@ + (mixed) cached_entity : + * - if set to a class name, we will cache an abstract class and will use only static calls + * - if set to an object, we will cache this object methods + * + * ====> (boolean) cache_by_default : + * - if true, method calls will be cached by default + * + * ====> (array) cached_methods : + * - an array of method names which will be cached (even if cache_by_default = false) + * + * ====> (array) non_cached_methods : + * - an array of method names which won't be cached (even if cache_by_default = true) + * + * @var array available options + */ + protected $_specificOptions = array( + 'cached_entity' => null, + 'cache_by_default' => true, + 'cached_methods' => array(), + 'non_cached_methods' => array() + ); + + /** + * Tags array + * + * @var array + */ + protected $_tags = array(); + + /** + * SpecificLifetime value + * + * false => no specific life time + * + * @var bool|int + */ + protected $_specificLifetime = false; + + /** + * The cached object or the name of the cached abstract class + * + * @var mixed + */ + protected $_cachedEntity = null; + + /** + * The class name of the cached object or cached abstract class + * + * Used to differentiate between different classes with the same method calls. + * + * @var string + */ + protected $_cachedEntityLabel = ''; + + /** + * Priority (used by some particular backends) + * + * @var int + */ + protected $_priority = 8; + + /** + * Constructor + * + * @param array $options Associative array of options + * @throws Zend_Cache_Exception + */ + public function __construct(array $options = array()) + { + foreach ($options as $name => $value) { + $this->setOption($name, $value); + } + if ($this->_specificOptions['cached_entity'] === null) { + Zend_Cache::throwException('cached_entity must be set !'); + } + $this->setCachedEntity($this->_specificOptions['cached_entity']); + $this->setOption('automatic_serialization', true); + } + + /** + * Set a specific life time + * + * @param bool|int $specificLifetime + * @return void + */ + public function setSpecificLifetime($specificLifetime = false) + { + $this->_specificLifetime = $specificLifetime; + } + + /** + * Set the priority (used by some particular backends) + * + * @param int $priority integer between 0 (very low priority) and 10 (maximum priority) + */ + public function setPriority($priority) + { + $this->_priority = $priority; + } + + /** + * Public frontend to set an option + * + * Just a wrapper to get a specific behaviour for cached_entity + * + * @param string $name Name of the option + * @param mixed $value Value of the option + * @throws Zend_Cache_Exception + * @return void + */ + public function setOption($name, $value) + { + if ($name == 'cached_entity') { + $this->setCachedEntity($value); + } else { + parent::setOption($name, $value); + } + } + + /** + * Specific method to set the cachedEntity + * + * if set to a class name, we will cache an abstract class and will use only static calls + * if set to an object, we will cache this object methods + * + * @param mixed $cachedEntity + */ + public function setCachedEntity($cachedEntity) + { + if (!is_string($cachedEntity) && !is_object($cachedEntity)) { + Zend_Cache::throwException( + 'cached_entity must be an object or a class name' + ); + } + + $this->_cachedEntity = $cachedEntity; + $this->_specificOptions['cached_entity'] = $cachedEntity; + + if (is_string($this->_cachedEntity)) { + $this->_cachedEntityLabel = $this->_cachedEntity; + } else { + $ro = new ReflectionObject($this->_cachedEntity); + $this->_cachedEntityLabel = $ro->getName(); + } + } + + /** + * Set the cache array + * + * @param array $tags + * @return void + */ + public function setTagsArray($tags = array()) + { + $this->_tags = $tags; + } + + /** + * Main method : call the specified method or get the result from cache + * + * @param string $name Method name + * @param array $parameters Method parameters + * @return mixed Result + * @throws Exception + */ + public function __call($name, $parameters) + { + $callback = array($this->_cachedEntity, $name); + + if (!is_callable($callback, false)) { + Zend_Cache::throwException('Invalid callback'); + } + + $cacheBool1 = $this->_specificOptions['cache_by_default']; + $cacheBool2 = in_array($name, $this->_specificOptions['cached_methods']); + $cacheBool3 = in_array($name, $this->_specificOptions['non_cached_methods']); + $cache = (($cacheBool1 || $cacheBool2) && (!$cacheBool3)); + + if (!$cache) { + // We do not have not cache + return call_user_func_array($callback, $parameters); + } + + $id = $this->makeId($name, $parameters); + if (($rs = $this->load($id)) && (array_key_exists(0, $rs)) + && (array_key_exists(1, $rs)) + ) { + // A cache is available + $output = $rs[0]; + $return = $rs[1]; + } else { + // A cache is not available (or not valid for this frontend) + ob_start(); + ob_implicit_flush(false); + + try { + $return = call_user_func_array($callback, $parameters); + $output = ob_get_clean(); + $data = array($output, $return); + + $this->save( + $data, $id, $this->_tags, $this->_specificLifetime, + $this->_priority + ); + } catch (Exception $e) { + ob_end_clean(); + throw $e; + } + } + + echo $output; + return $return; + } + + /** + * ZF-9970 + * + * @deprecated + */ + private function _makeId($name, $args) + { + return $this->makeId($name, $args); + } + + /** + * Make a cache id from the method name and parameters + * + * @param string $name Method name + * @param array $args Method parameters + * @return string Cache id + */ + public function makeId($name, array $args = array()) + { + return md5($this->_cachedEntityLabel . '__' . $name . '__' . serialize($args)); + } +} diff --git a/library/vendor/Zend/Cache/Frontend/File.php b/library/vendor/Zend/Cache/Frontend/File.php new file mode 100644 index 0000000..98cd5a3 --- /dev/null +++ b/library/vendor/Zend/Cache/Frontend/File.php @@ -0,0 +1,221 @@ + (string) master_file : + * - a complete path of the master file + * - deprecated (see master_files) + * + * ====> (array) master_files : + * - an array of complete path of master files + * - this option has to be set ! + * + * ====> (string) master_files_mode : + * - Zend_Cache_Frontend_File::MODE_AND or Zend_Cache_Frontend_File::MODE_OR + * - if MODE_AND, then all master files have to be touched to get a cache invalidation + * - if MODE_OR (default), then a single touched master file is enough to get a cache invalidation + * + * ====> (boolean) ignore_missing_master_files + * - if set to true, missing master files are ignored silently + * - if set to false (default), an exception is thrown if there is a missing master file + * @var array available options + */ + protected $_specificOptions = array( + 'master_file' => null, + 'master_files' => null, + 'master_files_mode' => 'OR', + 'ignore_missing_master_files' => false + ); + + /** + * Master file mtimes + * + * Array of int + * + * @var array + */ + private $_masterFile_mtimes = null; + + /** + * Constructor + * + * @param array $options Associative array of options + * @throws Zend_Cache_Exception + * @return void + */ + public function __construct(array $options = array()) + { + foreach ($options as $name => $value) { + $this->setOption($name, $value); + } + if (!isset($this->_specificOptions['master_files'])) { + Zend_Cache::throwException('master_files option must be set'); + } + } + + /** + * Change the master_files option + * + * @param array $masterFiles the complete paths and name of the master files + */ + public function setMasterFiles(array $masterFiles) + { + $this->_specificOptions['master_file'] = null; // to keep a compatibility + $this->_specificOptions['master_files'] = null; + $this->_masterFile_mtimes = array(); + + clearstatcache(); + $i = 0; + foreach ($masterFiles as $masterFile) { + if (file_exists($masterFile)) { + $mtime = filemtime($masterFile); + } else { + $mtime = false; + } + + if (!$this->_specificOptions['ignore_missing_master_files'] && !$mtime) { + Zend_Cache::throwException('Unable to read master_file : ' . $masterFile); + } + + $this->_masterFile_mtimes[$i] = $mtime; + $this->_specificOptions['master_files'][$i] = $masterFile; + if ($i === 0) { // to keep a compatibility + $this->_specificOptions['master_file'] = $masterFile; + } + + $i++; + } + } + + /** + * Change the master_file option + * + * To keep the compatibility + * + * @deprecated + * @param string $masterFile the complete path and name of the master file + */ + public function setMasterFile($masterFile) + { + $this->setMasterFiles(array($masterFile)); + } + + /** + * Public frontend to set an option + * + * Just a wrapper to get a specific behaviour for master_file + * + * @param string $name Name of the option + * @param mixed $value Value of the option + * @throws Zend_Cache_Exception + * @return void + */ + public function setOption($name, $value) + { + if ($name == 'master_file') { + $this->setMasterFile($value); + } else if ($name == 'master_files') { + $this->setMasterFiles($value); + } else { + parent::setOption($name, $value); + } + } + + /** + * Test if a cache is available for the given id and (if yes) return it (false else) + * + * @param string $id Cache id + * @param boolean $doNotTestCacheValidity If set to true, the cache validity won't be tested + * @param boolean $doNotUnserialize Do not serialize (even if automatic_serialization is true) => for internal use + * @return mixed|false Cached datas + */ + public function load($id, $doNotTestCacheValidity = false, $doNotUnserialize = false) + { + if (!$doNotTestCacheValidity) { + if ($this->test($id)) { + return parent::load($id, true, $doNotUnserialize); + } + return false; + } + return parent::load($id, true, $doNotUnserialize); + } + + /** + * Test if a cache is available for the given id + * + * @param string $id Cache id + * @return int|false Last modified time of cache entry if it is available, false otherwise + */ + public function test($id) + { + $lastModified = parent::test($id); + if ($lastModified) { + if ($this->_specificOptions['master_files_mode'] == self::MODE_AND) { + // MODE_AND + foreach($this->_masterFile_mtimes as $masterFileMTime) { + if ($masterFileMTime) { + if ($lastModified > $masterFileMTime) { + return $lastModified; + } + } + } + } else { + // MODE_OR + $res = true; + foreach($this->_masterFile_mtimes as $masterFileMTime) { + if ($masterFileMTime) { + if ($lastModified <= $masterFileMTime) { + return false; + } + } + } + return $lastModified; + } + } + return false; + } + +} + diff --git a/library/vendor/Zend/Cache/Frontend/Function.php b/library/vendor/Zend/Cache/Frontend/Function.php new file mode 100644 index 0000000..3dc7fd8 --- /dev/null +++ b/library/vendor/Zend/Cache/Frontend/Function.php @@ -0,0 +1,178 @@ + (boolean) cache_by_default : + * - if true, function calls will be cached by default + * + * ====> (array) cached_functions : + * - an array of function names which will be cached (even if cache_by_default = false) + * + * ====> (array) non_cached_functions : + * - an array of function names which won't be cached (even if cache_by_default = true) + * + * @var array options + */ + protected $_specificOptions = array( + 'cache_by_default' => true, + 'cached_functions' => array(), + 'non_cached_functions' => array() + ); + + /** + * Constructor + * + * @param array $options Associative array of options + * @return void + */ + public function __construct(array $options = array()) + { + foreach ($options as $name => $value) { + $this->setOption($name, $value); + } + $this->setOption('automatic_serialization', true); + } + + /** + * Main method : call the specified function or get the result from cache + * + * @param callback $callback A valid callback + * @param array $parameters Function parameters + * @param array $tags Cache tags + * @param int $specificLifetime If != false, set a specific lifetime for this cache record (null => infinite lifetime) + * @param int $priority integer between 0 (very low priority) and 10 (maximum priority) used by some particular backends + * @return mixed Result + */ + public function call($callback, array $parameters = array(), $tags = array(), $specificLifetime = false, $priority = 8) + { + if (!is_callable($callback, true, $name)) { + Zend_Cache::throwException('Invalid callback'); + } + + $cacheBool1 = $this->_specificOptions['cache_by_default']; + $cacheBool2 = in_array($name, $this->_specificOptions['cached_functions']); + $cacheBool3 = in_array($name, $this->_specificOptions['non_cached_functions']); + $cache = (($cacheBool1 || $cacheBool2) && (!$cacheBool3)); + if (!$cache) { + // Caching of this callback is disabled + return call_user_func_array($callback, $parameters); + } + + $id = $this->_makeId($callback, $parameters); + if ( ($rs = $this->load($id)) && isset($rs[0], $rs[1])) { + // A cache is available + $output = $rs[0]; + $return = $rs[1]; + } else { + // A cache is not available (or not valid for this frontend) + ob_start(); + ob_implicit_flush(false); + $return = call_user_func_array($callback, $parameters); + $output = ob_get_clean(); + $data = array($output, $return); + $this->save($data, $id, $tags, $specificLifetime, $priority); + } + + echo $output; + return $return; + } + + /** + * ZF-9970 + * + * @deprecated + */ + private function _makeId($callback, array $args) + { + return $this->makeId($callback, $args); + } + + /** + * Make a cache id from the function name and parameters + * + * @param callback $callback A valid callback + * @param array $args Function parameters + * @throws Zend_Cache_Exception + * @return string Cache id + */ + public function makeId($callback, array $args = array()) + { + if (!is_callable($callback, true, $name)) { + Zend_Cache::throwException('Invalid callback'); + } + + // functions, methods and classnames are case-insensitive + $name = strtolower($name); + + // generate a unique id for object callbacks + if (is_object($callback)) { // Closures & __invoke + $object = $callback; + } elseif (isset($callback[0])) { // array($object, 'method') + $object = $callback[0]; + } + if (isset($object)) { + try { + $tmp = @serialize($callback); + } catch (Exception $e) { + Zend_Cache::throwException($e->getMessage()); + } + if (!$tmp) { + $lastErr = error_get_last(); + Zend_Cache::throwException("Can't serialize callback object to generate id: {$lastErr['message']}"); + } + $name.= '__' . $tmp; + } + + // generate a unique id for arguments + $argsStr = ''; + if ($args) { + try { + $argsStr = @serialize(array_values($args)); + } catch (Exception $e) { + Zend_Cache::throwException($e->getMessage()); + } + if (!$argsStr) { + $lastErr = error_get_last(); + throw Zend_Cache::throwException("Can't serialize arguments to generate id: {$lastErr['message']}"); + } + } + + return md5($name . $argsStr); + } + +} diff --git a/library/vendor/Zend/Cache/Frontend/Output.php b/library/vendor/Zend/Cache/Frontend/Output.php new file mode 100644 index 0000000..dd8fe8d --- /dev/null +++ b/library/vendor/Zend/Cache/Frontend/Output.php @@ -0,0 +1,104 @@ +_idStack = array(); + } + + /** + * Start the cache + * + * @param string $id Cache id + * @param boolean $doNotTestCacheValidity If set to true, the cache validity won't be tested + * @param boolean $echoData If set to true, datas are sent to the browser if the cache is hit (simply returned else) + * @return mixed True if the cache is hit (false else) with $echoData=true (default) ; string else (datas) + */ + public function start($id, $doNotTestCacheValidity = false, $echoData = true) + { + $data = $this->load($id, $doNotTestCacheValidity); + if ($data !== false) { + if ( $echoData ) { + echo($data); + return true; + } else { + return $data; + } + } + ob_start(); + ob_implicit_flush(false); + $this->_idStack[] = $id; + return false; + } + + /** + * Stop the cache + * + * @param array $tags Tags array + * @param int $specificLifetime If != false, set a specific lifetime for this cache record (null => infinite lifetime) + * @param string $forcedDatas If not null, force written datas with this + * @param boolean $echoData If set to true, datas are sent to the browser + * @param int $priority integer between 0 (very low priority) and 10 (maximum priority) used by some particular backends + * @return void + */ + public function end($tags = array(), $specificLifetime = false, $forcedDatas = null, $echoData = true, $priority = 8) + { + if ($forcedDatas === null) { + $data = ob_get_clean(); + } else { + $data =& $forcedDatas; + } + $id = array_pop($this->_idStack); + if ($id === null) { + Zend_Cache::throwException('use of end() without a start()'); + } + $this->save($data, $id, $tags, $specificLifetime, $priority); + if ($echoData) { + echo($data); + } + } + +} diff --git a/library/vendor/Zend/Cache/Frontend/Page.php b/library/vendor/Zend/Cache/Frontend/Page.php new file mode 100644 index 0000000..8326281 --- /dev/null +++ b/library/vendor/Zend/Cache/Frontend/Page.php @@ -0,0 +1,403 @@ + (boolean) http_conditional : + * - if true, http conditional mode is on + * WARNING : http_conditional OPTION IS NOT IMPLEMENTED FOR THE MOMENT (TODO) + * + * ====> (boolean) debug_header : + * - if true, a debug text is added before each cached pages + * + * ====> (boolean) content_type_memorization : + * - deprecated => use memorize_headers instead + * - if the Content-Type header is sent after the cache was started, the + * corresponding value can be memorized and replayed when the cache is hit + * (if false (default), the frontend doesn't take care of Content-Type header) + * + * ====> (array) memorize_headers : + * - an array of strings corresponding to some HTTP headers name. Listed headers + * will be stored with cache datas and "replayed" when the cache is hit + * + * ====> (array) default_options : + * - an associative array of default options : + * - (boolean) cache : cache is on by default if true + * - (boolean) cacheWithXXXVariables (XXXX = 'Get', 'Post', 'Session', 'Files' or 'Cookie') : + * if true, cache is still on even if there are some variables in this superglobal array + * if false, cache is off if there are some variables in this superglobal array + * - (boolean) makeIdWithXXXVariables (XXXX = 'Get', 'Post', 'Session', 'Files' or 'Cookie') : + * if true, we have to use the content of this superglobal array to make a cache id + * if false, the cache id won't be dependent of the content of this superglobal array + * - (int) specific_lifetime : cache specific lifetime + * (false => global lifetime is used, null => infinite lifetime, + * integer => this lifetime is used), this "lifetime" is probably only + * usefull when used with "regexps" array + * - (array) tags : array of tags (strings) + * - (int) priority : integer between 0 (very low priority) and 10 (maximum priority) used by + * some particular backends + * + * ====> (array) regexps : + * - an associative array to set options only for some REQUEST_URI + * - keys are (pcre) regexps + * - values are associative array with specific options to set if the regexp matchs on $_SERVER['REQUEST_URI'] + * (see default_options for the list of available options) + * - if several regexps match the $_SERVER['REQUEST_URI'], only the last one will be used + * + * @var array options + */ + protected $_specificOptions = array( + 'http_conditional' => false, + 'debug_header' => false, + 'content_type_memorization' => false, + 'memorize_headers' => array(), + 'default_options' => array( + 'cache_with_get_variables' => false, + 'cache_with_post_variables' => false, + 'cache_with_session_variables' => false, + 'cache_with_files_variables' => false, + 'cache_with_cookie_variables' => false, + 'make_id_with_get_variables' => true, + 'make_id_with_post_variables' => true, + 'make_id_with_session_variables' => true, + 'make_id_with_files_variables' => true, + 'make_id_with_cookie_variables' => true, + 'cache' => true, + 'specific_lifetime' => false, + 'tags' => array(), + 'priority' => null + ), + 'regexps' => array() + ); + + /** + * Internal array to store some options + * + * @var array associative array of options + */ + protected $_activeOptions = array(); + + /** + * If true, the page won't be cached + * + * @var boolean + */ + protected $_cancel = false; + + /** + * Constructor + * + * @param array $options Associative array of options + * @param boolean $doNotTestCacheValidity If set to true, the cache validity won't be tested + * @throws Zend_Cache_Exception + * @return void + */ + public function __construct(array $options = array()) + { + foreach ($options as $name => $value) { + $name = strtolower($name); + switch ($name) { + case 'regexps': + $this->_setRegexps($value); + break; + case 'default_options': + $this->_setDefaultOptions($value); + break; + case 'content_type_memorization': + $this->_setContentTypeMemorization($value); + break; + default: + $this->setOption($name, $value); + } + } + if (isset($this->_specificOptions['http_conditional'])) { + if ($this->_specificOptions['http_conditional']) { + Zend_Cache::throwException('http_conditional is not implemented for the moment !'); + } + } + $this->setOption('automatic_serialization', true); + } + + /** + * Specific setter for the 'default_options' option (with some additional tests) + * + * @param array $options Associative array + * @throws Zend_Cache_Exception + * @return void + */ + protected function _setDefaultOptions($options) + { + if (!is_array($options)) { + Zend_Cache::throwException('default_options must be an array !'); + } + foreach ($options as $key=>$value) { + if (!is_string($key)) { + Zend_Cache::throwException("invalid option [$key] !"); + } + $key = strtolower($key); + if (isset($this->_specificOptions['default_options'][$key])) { + $this->_specificOptions['default_options'][$key] = $value; + } + } + } + + /** + * Set the deprecated contentTypeMemorization option + * + * @param boolean $value value + * @return void + * @deprecated + */ + protected function _setContentTypeMemorization($value) + { + $found = null; + foreach ($this->_specificOptions['memorize_headers'] as $key => $value) { + if (strtolower($value) == 'content-type') { + $found = $key; + } + } + if ($value) { + if (!$found) { + $this->_specificOptions['memorize_headers'][] = 'Content-Type'; + } + } else { + if ($found) { + unset($this->_specificOptions['memorize_headers'][$found]); + } + } + } + + /** + * Specific setter for the 'regexps' option (with some additional tests) + * + * @param array $options Associative array + * @throws Zend_Cache_Exception + * @return void + */ + protected function _setRegexps($regexps) + { + if (!is_array($regexps)) { + Zend_Cache::throwException('regexps option must be an array !'); + } + foreach ($regexps as $regexp=>$conf) { + if (!is_array($conf)) { + Zend_Cache::throwException('regexps option must be an array of arrays !'); + } + $validKeys = array_keys($this->_specificOptions['default_options']); + foreach ($conf as $key=>$value) { + if (!is_string($key)) { + Zend_Cache::throwException("unknown option [$key] !"); + } + $key = strtolower($key); + if (!in_array($key, $validKeys)) { + unset($regexps[$regexp][$key]); + } + } + } + $this->setOption('regexps', $regexps); + } + + /** + * Start the cache + * + * @param string $id (optional) A cache id (if you set a value here, maybe you have to use Output frontend instead) + * @param boolean $doNotDie For unit testing only ! + * @return boolean True if the cache is hit (false else) + */ + public function start($id = false, $doNotDie = false) + { + $this->_cancel = false; + $lastMatchingRegexp = null; + if (isset($_SERVER['REQUEST_URI'])) { + foreach ($this->_specificOptions['regexps'] as $regexp => $conf) { + if (preg_match("`$regexp`", $_SERVER['REQUEST_URI'])) { + $lastMatchingRegexp = $regexp; + } + } + } + $this->_activeOptions = $this->_specificOptions['default_options']; + if ($lastMatchingRegexp !== null) { + $conf = $this->_specificOptions['regexps'][$lastMatchingRegexp]; + foreach ($conf as $key=>$value) { + $this->_activeOptions[$key] = $value; + } + } + if (!($this->_activeOptions['cache'])) { + return false; + } + if (!$id) { + $id = $this->_makeId(); + if (!$id) { + return false; + } + } + $array = $this->load($id); + if ($array !== false) { + $data = $array['data']; + $headers = $array['headers']; + if (!headers_sent()) { + foreach ($headers as $key=>$headerCouple) { + $name = $headerCouple[0]; + $value = $headerCouple[1]; + header("$name: $value"); + } + } + if ($this->_specificOptions['debug_header']) { + echo 'DEBUG HEADER : This is a cached page !'; + } + echo $data; + if ($doNotDie) { + return true; + } + die(); + } + ob_start(array($this, '_flush')); + ob_implicit_flush(false); + return false; + } + + /** + * Cancel the current caching process + */ + public function cancel() + { + $this->_cancel = true; + } + + /** + * callback for output buffering + * (shouldn't really be called manually) + * + * @param string $data Buffered output + * @return string Data to send to browser + */ + public function _flush($data) + { + if ($this->_cancel) { + return $data; + } + $contentType = null; + $storedHeaders = array(); + $headersList = headers_list(); + foreach($this->_specificOptions['memorize_headers'] as $key=>$headerName) { + foreach ($headersList as $headerSent) { + $tmp = explode(':', $headerSent); + $headerSentName = trim(array_shift($tmp)); + if (strtolower($headerName) == strtolower($headerSentName)) { + $headerSentValue = trim(implode(':', $tmp)); + $storedHeaders[] = array($headerSentName, $headerSentValue); + } + } + } + $array = array( + 'data' => $data, + 'headers' => $storedHeaders + ); + $this->save($array, null, $this->_activeOptions['tags'], $this->_activeOptions['specific_lifetime'], $this->_activeOptions['priority']); + return $data; + } + + /** + * Make an id depending on REQUEST_URI and superglobal arrays (depending on options) + * + * @return mixed|false a cache id (string), false if the cache should have not to be used + */ + protected function _makeId() + { + $tmp = $_SERVER['REQUEST_URI']; + $array = explode('?', $tmp, 2); + $tmp = $array[0]; + foreach (array('Get', 'Post', 'Session', 'Files', 'Cookie') as $arrayName) { + $tmp2 = $this->_makePartialId($arrayName, $this->_activeOptions['cache_with_' . strtolower($arrayName) . '_variables'], $this->_activeOptions['make_id_with_' . strtolower($arrayName) . '_variables']); + if ($tmp2===false) { + return false; + } + $tmp = $tmp . $tmp2; + } + return md5($tmp); + } + + /** + * Make a partial id depending on options + * + * @param string $arrayName Superglobal array name + * @param bool $bool1 If true, cache is still on even if there are some variables in the superglobal array + * @param bool $bool2 If true, we have to use the content of the superglobal array to make a partial id + * @return mixed|false Partial id (string) or false if the cache should have not to be used + */ + protected function _makePartialId($arrayName, $bool1, $bool2) + { + switch ($arrayName) { + case 'Get': + $var = $_GET; + break; + case 'Post': + $var = $_POST; + break; + case 'Session': + if (isset($_SESSION)) { + $var = $_SESSION; + } else { + $var = null; + } + break; + case 'Cookie': + if (isset($_COOKIE)) { + $var = $_COOKIE; + } else { + $var = null; + } + break; + case 'Files': + $var = $_FILES; + break; + default: + return false; + } + if ($bool1) { + if ($bool2) { + return serialize($var); + } + return ''; + } + if (count($var) > 0) { + return false; + } + return ''; + } + +} diff --git a/library/vendor/Zend/Cache/Manager.php b/library/vendor/Zend/Cache/Manager.php new file mode 100644 index 0000000..5196c19 --- /dev/null +++ b/library/vendor/Zend/Cache/Manager.php @@ -0,0 +1,304 @@ + array( + 'frontend' => array( + 'name' => 'Core', + 'options' => array( + 'automatic_serialization' => true, + ), + ), + 'backend' => array( + 'name' => 'File', + 'options' => array( + // use system temp dir by default of file backend + // 'cache_dir' => '../cache', + ), + ), + ), + + // Static Page HTML Cache + 'page' => array( + 'frontend' => array( + 'name' => 'Capture', + 'options' => array( + 'ignore_user_abort' => true, + ), + ), + 'backend' => array( + 'name' => 'Static', + 'options' => array( + 'public_dir' => '../public', + ), + ), + ), + + // Tag Cache + 'pagetag' => array( + 'frontend' => array( + 'name' => 'Core', + 'options' => array( + 'automatic_serialization' => true, + 'lifetime' => null + ), + ), + 'backend' => array( + 'name' => 'File', + 'options' => array( + // use system temp dir by default of file backend + // 'cache_dir' => '../cache', + // use default umask of file backend + // 'cache_file_umask' => 0644 + ), + ), + ), + ); + + /** + * Set a new cache for the Cache Manager to contain + * + * @param string $name + * @param Zend_Cache_Core $cache + * @return Zend_Cache_Manager + */ + public function setCache($name, Zend_Cache_Core $cache) + { + $this->_caches[$name] = $cache; + return $this; + } + + /** + * Check if the Cache Manager contains the named cache object, or a named + * configuration template to lazy load the cache object + * + * @param string $name + * @return bool + */ + public function hasCache($name) + { + if (isset($this->_caches[$name]) + || $this->hasCacheTemplate($name) + ) { + return true; + } + return false; + } + + /** + * Fetch the named cache object, or instantiate and return a cache object + * using a named configuration template + * + * @param string $name + * @return Zend_Cache_Core + */ + public function getCache($name) + { + if (isset($this->_caches[$name])) { + return $this->_caches[$name]; + } + if (isset($this->_optionTemplates[$name])) { + if ($name == self::PAGECACHE + && (!isset($this->_optionTemplates[$name]['backend']['options']['tag_cache']) + || !$this->_optionTemplates[$name]['backend']['options']['tag_cache'] instanceof Zend_Cache_Core) + ) { + $this->_optionTemplates[$name]['backend']['options']['tag_cache'] + = $this->getCache(self::PAGETAGCACHE); + } + + $this->_caches[$name] = Zend_Cache::factory( + $this->_optionTemplates[$name]['frontend']['name'], + $this->_optionTemplates[$name]['backend']['name'], + isset($this->_optionTemplates[$name]['frontend']['options']) ? $this->_optionTemplates[$name]['frontend']['options'] : array(), + isset($this->_optionTemplates[$name]['backend']['options']) ? $this->_optionTemplates[$name]['backend']['options'] : array(), + isset($this->_optionTemplates[$name]['frontend']['customFrontendNaming']) ? $this->_optionTemplates[$name]['frontend']['customFrontendNaming'] : false, + isset($this->_optionTemplates[$name]['backend']['customBackendNaming']) ? $this->_optionTemplates[$name]['backend']['customBackendNaming'] : false, + isset($this->_optionTemplates[$name]['frontendBackendAutoload']) ? $this->_optionTemplates[$name]['frontendBackendAutoload'] : false + ); + + return $this->_caches[$name]; + } + } + + /** + * Fetch all available caches + * + * @return array An array of all available caches with it's names as key + */ + public function getCaches() + { + $caches = $this->_caches; + foreach ($this->_optionTemplates as $name => $tmp) { + if (!isset($caches[$name])) { + $caches[$name] = $this->getCache($name); + } + } + return $caches; + } + + /** + * Set a named configuration template from which a cache object can later + * be lazy loaded + * + * @param string $name + * @param array $options + * @return Zend_Cache_Manager + * @throws Zend_Cache_Exception + */ + public function setCacheTemplate($name, $options) + { + if ($options instanceof Zend_Config) { + $options = $options->toArray(); + } elseif (!is_array($options)) { + throw new Zend_Cache_Exception('Options passed must be in' + . ' an associative array or instance of Zend_Config'); + } + $this->_optionTemplates[$name] = $options; + return $this; + } + + /** + * Check if the named configuration template + * + * @param string $name + * @return bool + */ + public function hasCacheTemplate($name) + { + if (isset($this->_optionTemplates[$name])) { + return true; + } + return false; + } + + /** + * Get the named configuration template + * + * @param string $name + * @return array + */ + public function getCacheTemplate($name) + { + if (isset($this->_optionTemplates[$name])) { + return $this->_optionTemplates[$name]; + } + } + + /** + * Pass an array containing changes to be applied to a named + * configuration + * template + * + * @param string $name + * @param array $options + * @return Zend_Cache_Manager + * @throws Zend_Cache_Exception for invalid options format or if option templates do not have $name + */ + public function setTemplateOptions($name, $options) + { + if ($options instanceof Zend_Config) { + $options = $options->toArray(); + } elseif (!is_array($options)) { + throw new Zend_Cache_Exception('Options passed must be in' + . ' an associative array or instance of Zend_Config'); + } + if (!isset($this->_optionTemplates[$name])) { + throw new Zend_Cache_Exception('A cache configuration template' + . 'does not exist with the name "' . $name . '"'); + } + $this->_optionTemplates[$name] + = $this->_mergeOptions($this->_optionTemplates[$name], $options); + return $this; + } + + /** + * Simple method to merge two configuration arrays + * + * @param array $current + * @param array $options + * @return array + */ + protected function _mergeOptions(array $current, array $options) + { + if (isset($options['frontend']['name'])) { + $current['frontend']['name'] = $options['frontend']['name']; + } + if (isset($options['backend']['name'])) { + $current['backend']['name'] = $options['backend']['name']; + } + if (isset($options['frontend']['options'])) { + foreach ($options['frontend']['options'] as $key => $value) { + $current['frontend']['options'][$key] = $value; + } + } + if (isset($options['backend']['options'])) { + foreach ($options['backend']['options'] as $key => $value) { + $current['backend']['options'][$key] = $value; + } + } + if (isset($options['frontend']['customFrontendNaming'])) { + $current['frontend']['customFrontendNaming'] = $options['frontend']['customFrontendNaming']; + } + if (isset($options['backend']['customBackendNaming'])) { + $current['backend']['customBackendNaming'] = $options['backend']['customBackendNaming']; + } + if (isset($options['frontendBackendAutoload'])) { + $current['frontendBackendAutoload'] = $options['frontendBackendAutoload']; + } + return $current; + } +} diff --git a/library/vendor/Zend/Config.php b/library/vendor/Zend/Config.php new file mode 100644 index 0000000..59c3265 --- /dev/null +++ b/library/vendor/Zend/Config.php @@ -0,0 +1,481 @@ +_allowModifications = (boolean) $allowModifications; + $this->_loadedSection = null; + $this->_index = 0; + $this->_data = array(); + foreach ($array as $key => $value) { + if (is_array($value)) { + $this->_data[$key] = new self($value, $this->_allowModifications); + } else { + $this->_data[$key] = $value; + } + } + $this->_count = count($this->_data); + } + + /** + * Retrieve a value and return $default if there is no element set. + * + * @param string $name + * @param mixed $default + * @return mixed + */ + public function get($name, $default = null) + { + $result = $default; + if (array_key_exists($name, $this->_data)) { + $result = $this->_data[$name]; + } + return $result; + } + + /** + * Magic function so that $obj->value will work. + * + * @param string $name + * @return mixed + */ + public function __get($name) + { + return $this->get($name); + } + + /** + * Only allow setting of a property if $allowModifications + * was set to true on construction. Otherwise, throw an exception. + * + * @param string $name + * @param mixed $value + * @throws Zend_Config_Exception + * @return void + */ + public function __set($name, $value) + { + if ($this->_allowModifications) { + if (is_array($value)) { + $this->_data[$name] = new self($value, true); + } else { + $this->_data[$name] = $value; + } + $this->_count = count($this->_data); + } else { + /** @see Zend_Config_Exception */ + throw new Zend_Config_Exception('Zend_Config is read only'); + } + } + + /** + * Deep clone of this instance to ensure that nested Zend_Configs + * are also cloned. + * + * @return void + */ + public function __clone() + { + $array = array(); + foreach ($this->_data as $key => $value) { + if ($value instanceof Zend_Config) { + $array[$key] = clone $value; + } else { + $array[$key] = $value; + } + } + $this->_data = $array; + } + + /** + * Return an associative array of the stored data. + * + * @return array + */ + public function toArray() + { + $array = array(); + $data = $this->_data; + foreach ($data as $key => $value) { + if ($value instanceof Zend_Config) { + $array[$key] = $value->toArray(); + } else { + $array[$key] = $value; + } + } + return $array; + } + + /** + * Support isset() overloading on PHP 5.1 + * + * @param string $name + * @return boolean + */ + public function __isset($name) + { + return isset($this->_data[$name]); + } + + /** + * Support unset() overloading on PHP 5.1 + * + * @param string $name + * @throws Zend_Config_Exception + * @return void + */ + public function __unset($name) + { + if ($this->_allowModifications) { + unset($this->_data[$name]); + $this->_count = count($this->_data); + $this->_skipNextIteration = true; + } else { + /** @see Zend_Config_Exception */ + throw new Zend_Config_Exception('Zend_Config is read only'); + } + + } + + /** + * Defined by Countable interface + * + * @return int + */ + public function count() + { + return $this->_count; + } + + /** + * Defined by Iterator interface + * + * @return mixed + */ + public function current() + { + $this->_skipNextIteration = false; + return current($this->_data); + } + + /** + * Defined by Iterator interface + * + * @return mixed + */ + public function key() + { + return key($this->_data); + } + + /** + * Defined by Iterator interface + * + */ + public function next() + { + if ($this->_skipNextIteration) { + $this->_skipNextIteration = false; + return; + } + next($this->_data); + $this->_index++; + } + + /** + * Defined by Iterator interface + * + */ + public function rewind() + { + $this->_skipNextIteration = false; + reset($this->_data); + $this->_index = 0; + } + + /** + * Defined by Iterator interface + * + * @return boolean + */ + public function valid() + { + return $this->_index < $this->_count; + } + + /** + * Returns the section name(s) loaded. + * + * @return mixed + */ + public function getSectionName() + { + if(is_array($this->_loadedSection) && count($this->_loadedSection) == 1) { + $this->_loadedSection = $this->_loadedSection[0]; + } + return $this->_loadedSection; + } + + /** + * Returns true if all sections were loaded + * + * @return boolean + */ + public function areAllSectionsLoaded() + { + return $this->_loadedSection === null; + } + + + /** + * Merge another Zend_Config with this one. The items + * in $merge will override the same named items in + * the current config. + * + * @param Zend_Config $merge + * @return Zend_Config + */ + public function merge(Zend_Config $merge) + { + foreach($merge as $key => $item) { + if(array_key_exists($key, $this->_data)) { + if($item instanceof Zend_Config && $this->$key instanceof Zend_Config) { + $this->$key = $this->$key->merge(new Zend_Config($item->toArray(), !$this->readOnly())); + } else { + $this->$key = $item; + } + } else { + if($item instanceof Zend_Config) { + $this->$key = new Zend_Config($item->toArray(), !$this->readOnly()); + } else { + $this->$key = $item; + } + } + } + + return $this; + } + + /** + * Prevent any more modifications being made to this instance. Useful + * after merge() has been used to merge multiple Zend_Config objects + * into one object which should then not be modified again. + * + */ + public function setReadOnly() + { + $this->_allowModifications = false; + foreach ($this->_data as $key => $value) { + if ($value instanceof Zend_Config) { + $value->setReadOnly(); + } + } + } + + /** + * Returns if this Zend_Config object is read only or not. + * + * @return boolean + */ + public function readOnly() + { + return !$this->_allowModifications; + } + + /** + * Get the current extends + * + * @return array + */ + public function getExtends() + { + return $this->_extends; + } + + /** + * Set an extend for Zend_Config_Writer + * + * @param string $extendingSection + * @param string $extendedSection + * @return void + */ + public function setExtend($extendingSection, $extendedSection = null) + { + if ($extendedSection === null && isset($this->_extends[$extendingSection])) { + unset($this->_extends[$extendingSection]); + } else if ($extendedSection !== null) { + $this->_extends[$extendingSection] = $extendedSection; + } + } + + /** + * Throws an exception if $extendingSection may not extend $extendedSection, + * and tracks the section extension if it is valid. + * + * @param string $extendingSection + * @param string $extendedSection + * @throws Zend_Config_Exception + * @return void + */ + protected function _assertValidExtend($extendingSection, $extendedSection) + { + // detect circular section inheritance + $extendedSectionCurrent = $extendedSection; + while (array_key_exists($extendedSectionCurrent, $this->_extends)) { + if ($this->_extends[$extendedSectionCurrent] == $extendingSection) { + /** @see Zend_Config_Exception */ + throw new Zend_Config_Exception('Illegal circular inheritance detected'); + } + $extendedSectionCurrent = $this->_extends[$extendedSectionCurrent]; + } + // remember that this section extends another section + $this->_extends[$extendingSection] = $extendedSection; + } + + /** + * Handle any errors from simplexml_load_file or parse_ini_file + * + * @param integer $errno + * @param string $errstr + * @param string $errfile + * @param integer $errline + */ + public function _loadFileErrorHandler($errno, $errstr, $errfile, $errline) + { + if ($this->_loadFileErrorStr === null) { + $this->_loadFileErrorStr = $errstr; + } else { + $this->_loadFileErrorStr .= (PHP_EOL . $errstr); + } + } + + /** + * Merge two arrays recursively, overwriting keys of the same name + * in $firstArray with the value in $secondArray. + * + * @param mixed $firstArray First array + * @param mixed $secondArray Second array to merge into first array + * @return array + */ + protected function _arrayMergeRecursive($firstArray, $secondArray) + { + if (is_array($firstArray) && is_array($secondArray)) { + foreach ($secondArray as $key => $value) { + if (isset($firstArray[$key])) { + $firstArray[$key] = $this->_arrayMergeRecursive($firstArray[$key], $value); + } else { + if($key === 0) { + $firstArray= array(0=>$this->_arrayMergeRecursive($firstArray, $value)); + } else { + $firstArray[$key] = $value; + } + } + } + } else { + $firstArray = $secondArray; + } + + return $firstArray; + } +} diff --git a/library/vendor/Zend/Config/Exception.php b/library/vendor/Zend/Config/Exception.php new file mode 100644 index 0000000..abffe5b --- /dev/null +++ b/library/vendor/Zend/Config/Exception.php @@ -0,0 +1,32 @@ +hostname === "staging" + * $data->db->connection === "database" + * + * The $options parameter may be provided as either a boolean or an array. + * If provided as a boolean, this sets the $allowModifications option of + * Zend_Config. If provided as an array, there are three configuration + * directives that may be set. For example: + * + * $options = array( + * 'allowModifications' => false, + * 'nestSeparator' => ':', + * 'skipExtends' => false, + * ); + * + * @param string $filename + * @param mixed $section + * @param boolean|array $options + * @throws Zend_Config_Exception + * @return void + */ + public function __construct($filename, $section = null, $options = false) + { + if (empty($filename)) { + /** + * @see Zend_Config_Exception + */ + throw new Zend_Config_Exception('Filename is not set'); + } + + $allowModifications = false; + if (is_bool($options)) { + $allowModifications = $options; + } elseif (is_array($options)) { + if (isset($options['allowModifications'])) { + $allowModifications = (bool) $options['allowModifications']; + } + if (isset($options['nestSeparator'])) { + $this->_nestSeparator = (string) $options['nestSeparator']; + } + if (isset($options['skipExtends'])) { + $this->_skipExtends = (bool) $options['skipExtends']; + } + } + + $iniArray = $this->_loadIniFile($filename); + + if (null === $section) { + // Load entire file + $dataArray = array(); + foreach ($iniArray as $sectionName => $sectionData) { + if(!is_array($sectionData)) { + $dataArray = $this->_arrayMergeRecursive($dataArray, $this->_processKey(array(), $sectionName, $sectionData)); + } else { + $dataArray[$sectionName] = $this->_processSection($iniArray, $sectionName); + } + } + parent::__construct($dataArray, $allowModifications); + } else { + // Load one or more sections + if (!is_array($section)) { + $section = array($section); + } + $dataArray = array(); + foreach ($section as $sectionName) { + if (!isset($iniArray[$sectionName])) { + /** + * @see Zend_Config_Exception + */ + throw new Zend_Config_Exception("Section '$sectionName' cannot be found in $filename"); + } + $dataArray = $this->_arrayMergeRecursive($this->_processSection($iniArray, $sectionName), $dataArray); + + } + parent::__construct($dataArray, $allowModifications); + } + + $this->_loadedSection = $section; + } + + /** + * Load the INI file from disk using parse_ini_file(). Use a private error + * handler to convert any loading errors into a Zend_Config_Exception + * + * @param string $filename + * @throws Zend_Config_Exception + * @return array + */ + protected function _parseIniFile($filename) + { + set_error_handler(array($this, '_loadFileErrorHandler')); + $iniArray = parse_ini_file($filename, true); // Warnings and errors are suppressed + restore_error_handler(); + + // Check if there was a error while loading file + if ($this->_loadFileErrorStr !== null) { + /** + * @see Zend_Config_Exception + */ + throw new Zend_Config_Exception($this->_loadFileErrorStr); + } + + return $iniArray; + } + + /** + * Load the ini file and preprocess the section separator (':' in the + * section name (that is used for section extension) so that the resultant + * array has the correct section names and the extension information is + * stored in a sub-key called ';extends'. We use ';extends' as this can + * never be a valid key name in an INI file that has been loaded using + * parse_ini_file(). + * + * @param string $filename + * @throws Zend_Config_Exception + * @return array + */ + protected function _loadIniFile($filename) + { + $loaded = $this->_parseIniFile($filename); + $iniArray = array(); + foreach ($loaded as $key => $data) + { + $pieces = explode($this->_sectionSeparator, $key); + $thisSection = trim($pieces[0]); + switch (count($pieces)) { + case 1: + $iniArray[$thisSection] = $data; + break; + + case 2: + $extendedSection = trim($pieces[1]); + $iniArray[$thisSection] = array_merge(array(';extends'=>$extendedSection), $data); + break; + + default: + /** + * @see Zend_Config_Exception + */ + throw new Zend_Config_Exception("Section '$thisSection' may not extend multiple sections in $filename"); + } + } + + return $iniArray; + } + + /** + * Process each element in the section and handle the ";extends" inheritance + * key. Passes control to _processKey() to handle the nest separator + * sub-property syntax that may be used within the key name. + * + * @param array $iniArray + * @param string $section + * @param array $config + * @throws Zend_Config_Exception + * @return array + */ + protected function _processSection($iniArray, $section, $config = array()) + { + $thisSection = $iniArray[$section]; + + foreach ($thisSection as $key => $value) { + if (strtolower($key) == ';extends') { + if (isset($iniArray[$value])) { + $this->_assertValidExtend($section, $value); + + if (!$this->_skipExtends) { + $config = $this->_processSection($iniArray, $value, $config); + } + } else { + /** + * @see Zend_Config_Exception + */ + throw new Zend_Config_Exception("Parent section '$section' cannot be found"); + } + } else { + $config = $this->_processKey($config, $key, $value); + } + } + return $config; + } + + /** + * Assign the key's value to the property list. Handles the + * nest separator for sub-properties. + * + * @param array $config + * @param string $key + * @param string $value + * @throws Zend_Config_Exception + * @return array + */ + protected function _processKey($config, $key, $value) + { + if (strpos($key, $this->_nestSeparator) !== false) { + $pieces = explode($this->_nestSeparator, $key, 2); + if (strlen($pieces[0]) && strlen($pieces[1])) { + if (!isset($config[$pieces[0]])) { + if ($pieces[0] === '0' && !empty($config)) { + // convert the current values in $config into an array + $config = array($pieces[0] => $config); + } else { + $config[$pieces[0]] = array(); + } + } elseif (!is_array($config[$pieces[0]])) { + /** + * @see Zend_Config_Exception + */ + throw new Zend_Config_Exception("Cannot create sub-key for '{$pieces[0]}' as key already exists"); + } + $config[$pieces[0]] = $this->_processKey($config[$pieces[0]], $pieces[1], $value); + } else { + /** + * @see Zend_Config_Exception + */ + throw new Zend_Config_Exception("Invalid key '$key'"); + } + } else { + $config[$key] = $value; + } + return $config; + } +} diff --git a/library/vendor/Zend/Config/Writer.php b/library/vendor/Zend/Config/Writer.php new file mode 100644 index 0000000..8c255b3 --- /dev/null +++ b/library/vendor/Zend/Config/Writer.php @@ -0,0 +1,101 @@ +setOptions($options); + } + } + + /** + * Set options via a Zend_Config instance + * + * @param Zend_Config $config + * @return Zend_Config_Writer + */ + public function setConfig(Zend_Config $config) + { + $this->_config = $config; + + return $this; + } + + /** + * Set options via an array + * + * @param array $options + * @return Zend_Config_Writer + */ + public function setOptions(array $options) + { + foreach ($options as $key => $value) { + if (in_array(strtolower($key), $this->_skipOptions)) { + continue; + } + + $method = 'set' . ucfirst($key); + if (method_exists($this, $method)) { + $this->$method($value); + } + } + + return $this; + } + + /** + * Write a Zend_Config object to it's target + * + * @return void + */ + abstract public function write(); +} diff --git a/library/vendor/Zend/Config/Writer/Array.php b/library/vendor/Zend/Config/Writer/Array.php new file mode 100644 index 0000000..f7cd502 --- /dev/null +++ b/library/vendor/Zend/Config/Writer/Array.php @@ -0,0 +1,54 @@ +_config->toArray(); + $sectionName = $this->_config->getSectionName(); + + if (is_string($sectionName)) { + $data = array($sectionName => $data); + } + + $arrayString = "_filename = $filename; + + return $this; + } + + /** + * Set wether to exclusively lock the file or not + * + * @param boolean $exclusiveLock + * @return Zend_Config_Writer_Array + */ + public function setExclusiveLock($exclusiveLock) + { + $this->_exclusiveLock = $exclusiveLock; + + return $this; + } + + /** + * Write configuration to file. + * + * @param string $filename + * @param Zend_Config $config + * @param bool $exclusiveLock + * @return void + */ + public function write($filename = null, Zend_Config $config = null, $exclusiveLock = null) + { + if ($filename !== null) { + $this->setFilename($filename); + } + + if ($config !== null) { + $this->setConfig($config); + } + + if ($exclusiveLock !== null) { + $this->setExclusiveLock($exclusiveLock); + } + + if ($this->_filename === null) { + throw new Zend_Config_Exception('No filename was set'); + } + + if ($this->_config === null) { + throw new Zend_Config_Exception('No config was set'); + } + + $configString = $this->render(); + + $flags = 0; + + if ($this->_exclusiveLock) { + $flags |= LOCK_EX; + } + + $result = @file_put_contents($this->_filename, $configString, $flags); + + if ($result === false) { + throw new Zend_Config_Exception('Could not write to file "' . $this->_filename . '"'); + } + } + + /** + * Render a Zend_Config into a config file string. + * + * @since 1.10 + * @todo For 2.0 this should be redone into an abstract method. + * @return string + */ + public function render() + { + return ""; + } +} diff --git a/library/vendor/Zend/Config/Writer/Ini.php b/library/vendor/Zend/Config/Writer/Ini.php new file mode 100644 index 0000000..67aaf89 --- /dev/null +++ b/library/vendor/Zend/Config/Writer/Ini.php @@ -0,0 +1,191 @@ +_nestSeparator = $separator; + + return $this; + } + + /** + * Set if rendering should occour without sections or not. + * + * If set to true, the INI file is rendered without sections completely + * into the global namespace of the INI file. + * + * @param bool $withoutSections + * @return Zend_Config_Writer_Ini + */ + public function setRenderWithoutSections($withoutSections=true) + { + $this->_renderWithoutSections = (bool)$withoutSections; + return $this; + } + + /** + * Render a Zend_Config into a INI config string. + * + * @since 1.10 + * @return string + */ + public function render() + { + $iniString = ''; + $extends = $this->_config->getExtends(); + $sectionName = $this->_config->getSectionName(); + + if($this->_renderWithoutSections == true) { + $iniString .= $this->_addBranch($this->_config); + } else if (is_string($sectionName)) { + $iniString .= '[' . $sectionName . ']' . "\n" + . $this->_addBranch($this->_config) + . "\n"; + } else { + $config = $this->_sortRootElements($this->_config); + foreach ($config as $sectionName => $data) { + if (!($data instanceof Zend_Config)) { + $iniString .= $sectionName + . ' = ' + . $this->_prepareValue($data) + . "\n"; + } else { + if (isset($extends[$sectionName])) { + $sectionName .= ' : ' . $extends[$sectionName]; + } + + $iniString .= '[' . $sectionName . ']' . "\n" + . $this->_addBranch($data) + . "\n"; + } + } + } + + return $iniString; + } + + /** + * Add a branch to an INI string recursively + * + * @param Zend_Config $config + * @return void + */ + protected function _addBranch(Zend_Config $config, $parents = array()) + { + $iniString = ''; + + foreach ($config as $key => $value) { + $group = array_merge($parents, array($key)); + + if ($value instanceof Zend_Config) { + $iniString .= $this->_addBranch($value, $group); + } else { + $iniString .= implode($this->_nestSeparator, $group) + . ' = ' + . $this->_prepareValue($value) + . "\n"; + } + } + + return $iniString; + } + + /** + * Prepare a value for INI + * + * @param mixed $value + * @return string + */ + protected function _prepareValue($value) + { + if (is_integer($value) || is_float($value)) { + return $value; + } elseif (is_bool($value)) { + return ($value ? 'true' : 'false'); + } elseif (strpos($value, '"') === false) { + return '"' . $value . '"'; + } else { + /** @see Zend_Config_Exception */ + throw new Zend_Config_Exception('Value can not contain double quotes "'); + } + } + + /** + * Root elements that are not assigned to any section needs to be + * on the top of config. + * + * @see http://framework.zend.com/issues/browse/ZF-6289 + * @param Zend_Config + * @return Zend_Config + */ + protected function _sortRootElements(Zend_Config $config) + { + $configArray = $config->toArray(); + $sections = array(); + + // remove sections from config array + foreach ($configArray as $key => $value) { + if (is_array($value)) { + $sections[$key] = $value; + unset($configArray[$key]); + } + } + + // readd sections to the end + foreach ($sections as $key => $value) { + $configArray[$key] = $value; + } + + return new Zend_Config($configArray); + } +} diff --git a/library/vendor/Zend/Controller/Action.php b/library/vendor/Zend/Controller/Action.php new file mode 100644 index 0000000..35c450a --- /dev/null +++ b/library/vendor/Zend/Controller/Action.php @@ -0,0 +1,789 @@ +setRequest($request) + ->setResponse($response) + ->_setInvokeArgs($invokeArgs); + $this->_helper = new Zend_Controller_Action_HelperBroker($this); + $this->init(); + } + + /** + * Initialize object + * + * Called from {@link __construct()} as final step of object instantiation. + * + * @return void + */ + public function init() + { + } + + /** + * Initialize View object + * + * Initializes {@link $view} if not otherwise a Zend_View_Interface. + * + * If {@link $view} is not otherwise set, instantiates a new Zend_View + * object, using the 'views' subdirectory at the same level as the + * controller directory for the current module as the base directory. + * It uses this to set the following: + * - script path = views/scripts/ + * - helper path = views/helpers/ + * - filter path = views/filters/ + * + * @return Zend_View_Interface + * @throws Zend_Controller_Exception if base view directory does not exist + */ + public function initView() + { + if (!$this->getInvokeArg('noViewRenderer') && $this->_helper->hasHelper('viewRenderer')) { + return $this->view; + } + + if (isset($this->view) && ($this->view instanceof Zend_View_Interface)) { + return $this->view; + } + + $request = $this->getRequest(); + $module = $request->getModuleName(); + $dirs = $this->getFrontController()->getControllerDirectory(); + if (empty($module) || !isset($dirs[$module])) { + $module = $this->getFrontController()->getDispatcher()->getDefaultModule(); + } + $baseDir = dirname($dirs[$module]) . DIRECTORY_SEPARATOR . 'views'; + if (!file_exists($baseDir) || !is_dir($baseDir)) { + throw new Zend_Controller_Exception('Missing base view directory ("' . $baseDir . '")'); + } + + $this->view = new Zend_View(array('basePath' => $baseDir)); + + return $this->view; + } + + /** + * Render a view + * + * Renders a view. By default, views are found in the view script path as + * /.phtml. You may change the script suffix by + * resetting {@link $viewSuffix}. You may omit the controller directory + * prefix by specifying boolean true for $noController. + * + * By default, the rendered contents are appended to the response. You may + * specify the named body content segment to set by specifying a $name. + * + * @see Zend_Controller_Response_Abstract::appendBody() + * @param string|null $action Defaults to action registered in request object + * @param string|null $name Response object named path segment to use; defaults to null + * @param bool $noController Defaults to false; i.e. use controller name as subdir in which to search for view script + * @return void + */ + public function render($action = null, $name = null, $noController = false) + { + if (!$this->getInvokeArg('noViewRenderer') && $this->_helper->hasHelper('viewRenderer')) { + return $this->_helper->viewRenderer->render($action, $name, $noController); + } + + $view = $this->initView(); + $script = $this->getViewScript($action, $noController); + + $this->getResponse()->appendBody( + $view->render($script), + $name + ); + } + + /** + * Render a given view script + * + * Similar to {@link render()}, this method renders a view script. Unlike render(), + * however, it does not autodetermine the view script via {@link getViewScript()}, + * but instead renders the script passed to it. Use this if you know the + * exact view script name and path you wish to use, or if using paths that do not + * conform to the spec defined with getViewScript(). + * + * By default, the rendered contents are appended to the response. You may + * specify the named body content segment to set by specifying a $name. + * + * @param string $script + * @param string $name + * @return void + */ + public function renderScript($script, $name = null) + { + if (!$this->getInvokeArg('noViewRenderer') && $this->_helper->hasHelper('viewRenderer')) { + return $this->_helper->viewRenderer->renderScript($script, $name); + } + + $view = $this->initView(); + $this->getResponse()->appendBody( + $view->render($script), + $name + ); + } + + /** + * Construct view script path + * + * Used by render() to determine the path to the view script. + * + * @param string $action Defaults to action registered in request object + * @param bool $noController Defaults to false; i.e. use controller name as subdir in which to search for view script + * @return string + * @throws Zend_Controller_Exception with bad $action + */ + public function getViewScript($action = null, $noController = null) + { + if (!$this->getInvokeArg('noViewRenderer') && $this->_helper->hasHelper('viewRenderer')) { + $viewRenderer = $this->_helper->getHelper('viewRenderer'); + if (null !== $noController) { + $viewRenderer->setNoController($noController); + } + return $viewRenderer->getViewScript($action); + } + + $request = $this->getRequest(); + if (null === $action) { + $action = $request->getActionName(); + } elseif (!is_string($action)) { + throw new Zend_Controller_Exception('Invalid action specifier for view render'); + } + + if (null === $this->_delimiters) { + $dispatcher = Zend_Controller_Front::getInstance()->getDispatcher(); + $wordDelimiters = $dispatcher->getWordDelimiter(); + $pathDelimiters = $dispatcher->getPathDelimiter(); + $this->_delimiters = array_unique(array_merge($wordDelimiters, (array) $pathDelimiters)); + } + + $action = str_replace($this->_delimiters, '-', $action); + $script = $action . '.' . $this->viewSuffix; + + if (!$noController) { + $controller = $request->getControllerName(); + $controller = str_replace($this->_delimiters, '-', $controller); + $script = $controller . DIRECTORY_SEPARATOR . $script; + } + + return $script; + } + + /** + * Return the Request object + * + * @return Zend_Controller_Request_Abstract + */ + public function getRequest() + { + return $this->_request; + } + + /** + * Set the Request object + * + * @param Zend_Controller_Request_Abstract $request + * @return Zend_Controller_Action + */ + public function setRequest(Zend_Controller_Request_Abstract $request) + { + $this->_request = $request; + return $this; + } + + /** + * Return the Response object + * + * @return Zend_Controller_Response_Abstract + */ + public function getResponse() + { + return $this->_response; + } + + /** + * Set the Response object + * + * @param Zend_Controller_Response_Abstract $response + * @return Zend_Controller_Action + */ + public function setResponse(Zend_Controller_Response_Abstract $response) + { + $this->_response = $response; + return $this; + } + + /** + * Set invocation arguments + * + * @param array $args + * @return Zend_Controller_Action + */ + protected function _setInvokeArgs(array $args = array()) + { + $this->_invokeArgs = $args; + return $this; + } + + /** + * Return the array of constructor arguments (minus the Request object) + * + * @return array + */ + public function getInvokeArgs() + { + return $this->_invokeArgs; + } + + /** + * Return a single invocation argument + * + * @param string $key + * @return mixed + */ + public function getInvokeArg($key) + { + if (isset($this->_invokeArgs[$key])) { + return $this->_invokeArgs[$key]; + } + + return null; + } + + /** + * Get a helper by name + * + * @param string $helperName + * @return Zend_Controller_Action_Helper_Abstract + */ + public function getHelper($helperName) + { + return $this->_helper->{$helperName}; + } + + /** + * Get a clone of a helper by name + * + * @param string $helperName + * @return Zend_Controller_Action_Helper_Abstract + */ + public function getHelperCopy($helperName) + { + return clone $this->_helper->{$helperName}; + } + + /** + * Set the front controller instance + * + * @param Zend_Controller_Front $front + * @return Zend_Controller_Action + */ + public function setFrontController(Zend_Controller_Front $front) + { + $this->_frontController = $front; + return $this; + } + + /** + * Retrieve Front Controller + * + * @return Zend_Controller_Front + */ + public function getFrontController() + { + // Used cache version if found + if (null !== $this->_frontController) { + return $this->_frontController; + } + + // Grab singleton instance, if class has been loaded + if (class_exists('Zend_Controller_Front')) { + $this->_frontController = Zend_Controller_Front::getInstance(); + return $this->_frontController; + } + + // Throw exception in all other cases + throw new Zend_Controller_Exception('Front controller class has not been loaded'); + } + + /** + * Pre-dispatch routines + * + * Called before action method. If using class with + * {@link Zend_Controller_Front}, it may modify the + * {@link $_request Request object} and reset its dispatched flag in order + * to skip processing the current action. + * + * @return void + */ + public function preDispatch() + { + } + + /** + * Post-dispatch routines + * + * Called after action method execution. If using class with + * {@link Zend_Controller_Front}, it may modify the + * {@link $_request Request object} and reset its dispatched flag in order + * to process an additional action. + * + * Common usages for postDispatch() include rendering content in a sitewide + * template, link url correction, setting headers, etc. + * + * @return void + */ + public function postDispatch() + { + } + + /** + * Proxy for undefined methods. Default behavior is to throw an + * exception on undefined methods, however this function can be + * overridden to implement magic (dynamic) actions, or provide run-time + * dispatching. + * + * @param string $methodName + * @param array $args + * @return void + * @throws Zend_Controller_Action_Exception + */ + public function __call($methodName, $args) + { + if ('Action' == substr($methodName, -6)) { + $action = substr($methodName, 0, strlen($methodName) - 6); + throw new Zend_Controller_Action_Exception(sprintf('Action "%s" does not exist and was not trapped in __call()', $action), 404); + } + + throw new Zend_Controller_Action_Exception(sprintf('Method "%s" does not exist and was not trapped in __call()', $methodName), 500); + } + + /** + * Dispatch the requested action + * + * @param string $action Method name of action + * @return void + */ + public function dispatch($action) + { + // Notify helpers of action preDispatch state + $this->_helper->notifyPreDispatch(); + + $this->preDispatch(); + if ($this->getRequest()->isDispatched()) { + if (null === $this->_classMethods) { + $this->_classMethods = get_class_methods($this); + } + + // If pre-dispatch hooks introduced a redirect then stop dispatch + // @see ZF-7496 + if (!($this->getResponse()->isRedirect())) { + // preDispatch() didn't change the action, so we can continue + if ($this->getInvokeArg('useCaseSensitiveActions') || in_array($action, $this->_classMethods)) { + if ($this->getInvokeArg('useCaseSensitiveActions')) { + trigger_error('Using case sensitive actions without word separators is deprecated; please do not rely on this "feature"'); + } + $this->$action(); + } else { + $this->__call($action, array()); + } + } + $this->postDispatch(); + } + + // whats actually important here is that this action controller is + // shutting down, regardless of dispatching; notify the helpers of this + // state + $this->_helper->notifyPostDispatch(); + } + + /** + * Call the action specified in the request object, and return a response + * + * Not used in the Action Controller implementation, but left for usage in + * Page Controller implementations. Dispatches a method based on the + * request. + * + * Returns a Zend_Controller_Response_Abstract object, instantiating one + * prior to execution if none exists in the controller. + * + * {@link preDispatch()} is called prior to the action, + * {@link postDispatch()} is called following it. + * + * @param null|Zend_Controller_Request_Abstract $request Optional request + * object to use + * @param null|Zend_Controller_Response_Abstract $response Optional response + * object to use + * @return Zend_Controller_Response_Abstract + */ + public function run(Zend_Controller_Request_Abstract $request = null, Zend_Controller_Response_Abstract $response = null) + { + if (null !== $request) { + $this->setRequest($request); + } else { + $request = $this->getRequest(); + } + + if (null !== $response) { + $this->setResponse($response); + } + + $action = $request->getActionName(); + if (empty($action)) { + $action = 'index'; + } + $action = $action . 'Action'; + + $request->setDispatched(true); + $this->dispatch($action); + + return $this->getResponse(); + } + + /** + * Gets a parameter from the {@link $_request Request object}. If the + * parameter does not exist, NULL will be returned. + * + * If the parameter does not exist and $default is set, then + * $default will be returned instead of NULL. + * + * @param string $paramName + * @param mixed $default + * @return mixed + */ + protected function _getParam($paramName, $default = null) + { + return $this->getParam($paramName, $default); + } + + /** + * Gets a parameter from the {@link $_request Request object}. If the + * parameter does not exist, NULL will be returned. + * + * If the parameter does not exist and $default is set, then + * $default will be returned instead of NULL. + * + * @param string $paramName + * @param mixed $default + * @return mixed + */ + public function getParam($paramName, $default = null) + { + $value = $this->getRequest()->getParam($paramName); + if ((null === $value || '' === $value) && (null !== $default)) { + $value = $default; + } + + return $value; + } + + /** + * Set a parameter in the {@link $_request Request object}. + * + * @param string $paramName + * @param mixed $value + * @return Zend_Controller_Action + * @deprecated Deprecated as of Zend Framework 1.7. Use + * setParam() instead. + */ + protected function _setParam($paramName, $value) + { + return $this->setParam($paramName, $value); + } + + /** + * Set a parameter in the {@link $_request Request object}. + * + * @param string $paramName + * @param mixed $value + * @return Zend_Controller_Action + */ + public function setParam($paramName, $value) + { + $this->getRequest()->setParam($paramName, $value); + + return $this; + } + + /** + * Determine whether a given parameter exists in the + * {@link $_request Request object}. + * + * @param string $paramName + * @return boolean + * @deprecated Deprecated as of Zend Framework 1.7. Use + * hasParam() instead. + */ + protected function _hasParam($paramName) + { + return $this->hasParam($paramName); + } + + /** + * Determine whether a given parameter exists in the + * {@link $_request Request object}. + * + * @param string $paramName + * @return boolean + */ + public function hasParam($paramName) + { + return null !== $this->getRequest()->getParam($paramName); + } + + /** + * Return all parameters in the {@link $_request Request object} + * as an associative array. + * + * @return array + * @deprecated Deprecated as of Zend Framework 1.7. Use + * getAllParams() instead. + */ + protected function _getAllParams() + { + return $this->getAllParams(); + } + + /** + * Return all parameters in the {@link $_request Request object} + * as an associative array. + * + * @return array + */ + public function getAllParams() + { + return $this->getRequest()->getParams(); + } + + + /** + * Forward to another controller/action. + * + * It is important to supply the unformatted names, i.e. "article" + * rather than "ArticleController". The dispatcher will do the + * appropriate formatting when the request is received. + * + * If only an action name is provided, forwards to that action in this + * controller. + * + * If an action and controller are specified, forwards to that action and + * controller in this module. + * + * Specifying an action, controller, and module is the most specific way to + * forward. + * + * A fourth argument, $params, will be used to set the request parameters. + * If either the controller or module are unnecessary for forwarding, + * simply pass null values for them before specifying the parameters. + * + * @param string $action + * @param string $controller + * @param string $module + * @param array $params + * @return void + * @deprecated Deprecated as of Zend Framework 1.7. Use + * forward() instead. + */ + final protected function _forward($action, $controller = null, $module = null, array $params = null) + { + $this->forward($action, $controller, $module, $params); + } + + /** + * Forward to another controller/action. + * + * It is important to supply the unformatted names, i.e. "article" + * rather than "ArticleController". The dispatcher will do the + * appropriate formatting when the request is received. + * + * If only an action name is provided, forwards to that action in this + * controller. + * + * If an action and controller are specified, forwards to that action and + * controller in this module. + * + * Specifying an action, controller, and module is the most specific way to + * forward. + * + * A fourth argument, $params, will be used to set the request parameters. + * If either the controller or module are unnecessary for forwarding, + * simply pass null values for them before specifying the parameters. + * + * @param string $action + * @param string $controller + * @param string $module + * @param array $params + * @return void + */ + final public function forward($action, $controller = null, $module = null, array $params = null) + { + $request = $this->getRequest(); + + if (null !== $params) { + $request->setParams($params); + } + + if (null !== $controller) { + $request->setControllerName($controller); + + // Module should only be reset if controller has been specified + if (null !== $module) { + $request->setModuleName($module); + } + } + + $request->setActionName($action) + ->setDispatched(false); + } + + /** + * Redirect to another URL + * + * Proxies to {@link Zend_Controller_Action_Helper_Redirector::gotoUrl()}. + * + * @param string $url + * @param array $options Options to be used when redirecting + * @return void + * @deprecated Deprecated as of Zend Framework 1.7. Use + * redirect() instead. + */ + protected function _redirect($url, array $options = array()) + { + $this->redirect($url, $options); + } + + /** + * Redirect to another URL + * + * Proxies to {@link Zend_Controller_Action_Helper_Redirector::gotoUrl()}. + * + * @param string $url + * @param array $options Options to be used when redirecting + * @return void + */ + public function redirect($url, array $options = array()) + { + $this->_helper->redirector->gotoUrl($url, $options); + } +} diff --git a/library/vendor/Zend/Controller/Action/Exception.php b/library/vendor/Zend/Controller/Action/Exception.php new file mode 100644 index 0000000..1c3438d --- /dev/null +++ b/library/vendor/Zend/Controller/Action/Exception.php @@ -0,0 +1,37 @@ +_actionController = $actionController; + return $this; + } + + /** + * Retrieve current action controller + * + * @return Zend_Controller_Action + */ + public function getActionController() + { + return $this->_actionController; + } + + /** + * Retrieve front controller instance + * + * @return Zend_Controller_Front + */ + public function getFrontController() + { + return Zend_Controller_Front::getInstance(); + } + + /** + * Hook into action controller initialization + * + * @return void + */ + public function init() + { + } + + /** + * Hook into action controller preDispatch() workflow + * + * @return void + */ + public function preDispatch() + { + } + + /** + * Hook into action controller postDispatch() workflow + * + * @return void + */ + public function postDispatch() + { + } + + /** + * getRequest() - + * + * @return Zend_Controller_Request_Abstract $request + */ + public function getRequest() + { + $controller = $this->getActionController(); + if (null === $controller) { + $controller = $this->getFrontController(); + } + + return $controller->getRequest(); + } + + /** + * getResponse() - + * + * @return Zend_Controller_Response_Abstract $response + */ + public function getResponse() + { + $controller = $this->getActionController(); + if (null === $controller) { + $controller = $this->getFrontController(); + } + + return $controller->getResponse(); + } + + /** + * getName() + * + * @return string + */ + public function getName() + { + $fullClassName = get_class($this); + if (strpos($fullClassName, '_') !== false) { + $helperName = strrchr($fullClassName, '_'); + return ltrim($helperName, '_'); + } elseif (strpos($fullClassName, '\\') !== false) { + $helperName = strrchr($fullClassName, '\\'); + return ltrim($helperName, '\\'); + } else { + return $fullClassName; + } + } +} diff --git a/library/vendor/Zend/Controller/Action/Helper/ActionStack.php b/library/vendor/Zend/Controller/Action/Helper/ActionStack.php new file mode 100644 index 0000000..30fb633 --- /dev/null +++ b/library/vendor/Zend/Controller/Action/Helper/ActionStack.php @@ -0,0 +1,133 @@ +hasPlugin('Zend_Controller_Plugin_ActionStack')) { + /** + * @see Zend_Controller_Plugin_ActionStack + */ + $this->_actionStack = new Zend_Controller_Plugin_ActionStack(); + $front->registerPlugin($this->_actionStack, 97); + } else { + $this->_actionStack = $front->getPlugin('Zend_Controller_Plugin_ActionStack'); + } + } + + /** + * Push onto the stack + * + * @param Zend_Controller_Request_Abstract $next + * @return Zend_Controller_Action_Helper_ActionStack Provides a fluent interface + */ + public function pushStack(Zend_Controller_Request_Abstract $next) + { + $this->_actionStack->pushStack($next); + return $this; + } + + /** + * Push a new action onto the stack + * + * @param string $action + * @param string $controller + * @param string $module + * @param array $params + * @throws Zend_Controller_Action_Exception + * @return Zend_Controller_Action_Helper_ActionStack + */ + public function actionToStack($action, $controller = null, $module = null, array $params = array()) + { + if ($action instanceof Zend_Controller_Request_Abstract) { + return $this->pushStack($action); + } elseif (!is_string($action)) { + /** + * @see Zend_Controller_Action_Exception + */ + throw new Zend_Controller_Action_Exception('ActionStack requires either a request object or minimally a string action'); + } + + $request = $this->getRequest(); + + if ($request instanceof Zend_Controller_Request_Abstract === false){ + /** + * @see Zend_Controller_Action_Exception + */ + throw new Zend_Controller_Action_Exception('Request object not set yet'); + } + + $controller = (null === $controller) ? $request->getControllerName() : $controller; + $module = (null === $module) ? $request->getModuleName() : $module; + + /** + * @see Zend_Controller_Request_Simple + */ + $newRequest = new Zend_Controller_Request_Simple($action, $controller, $module, $params); + + return $this->pushStack($newRequest); + } + + /** + * Perform helper when called as $this->_helper->actionStack() from an action controller + * + * Proxies to {@link simple()} + * + * @param string $action + * @param string $controller + * @param string $module + * @param array $params + * @return boolean + */ + public function direct($action, $controller = null, $module = null, array $params = array()) + { + return $this->actionToStack($action, $controller, $module, $params); + } +} diff --git a/library/vendor/Zend/Controller/Action/Helper/AjaxContext.php b/library/vendor/Zend/Controller/Action/Helper/AjaxContext.php new file mode 100644 index 0000000..3074a40 --- /dev/null +++ b/library/vendor/Zend/Controller/Action/Helper/AjaxContext.php @@ -0,0 +1,79 @@ +addContext('html', array('suffix' => 'ajax')); + } + + /** + * Initialize AJAX context switching + * + * Checks for XHR requests; if detected, attempts to perform context switch. + * + * @param string $format + * @return void + */ + public function initContext($format = null) + { + $this->_currentContext = null; + + $request = $this->getRequest(); + if (!method_exists($request, 'isXmlHttpRequest') || + !$this->getRequest()->isXmlHttpRequest()) + { + return; + } + + return parent::initContext($format); + } +} diff --git a/library/vendor/Zend/Controller/Action/Helper/AutoComplete/Abstract.php b/library/vendor/Zend/Controller/Action/Helper/AutoComplete/Abstract.php new file mode 100644 index 0000000..7cd4ad0 --- /dev/null +++ b/library/vendor/Zend/Controller/Action/Helper/AutoComplete/Abstract.php @@ -0,0 +1,146 @@ +disableLayout(); + } + + Zend_Controller_Action_HelperBroker::getStaticHelper('viewRenderer')->setNoRender(true); + + return $this; + } + + /** + * Encode data to JSON + * + * @param mixed $data + * @param bool $keepLayouts + * @throws Zend_Controller_Action_Exception + * @return string + */ + public function encodeJson($data, $keepLayouts = false) + { + if ($this->validateData($data)) { + return Zend_Controller_Action_HelperBroker::getStaticHelper('Json')->encodeJson($data, $keepLayouts); + } + + /** + * @see Zend_Controller_Action_Exception + */ + throw new Zend_Controller_Action_Exception('Invalid data passed for autocompletion'); + } + + /** + * Send autocompletion data + * + * Calls prepareAutoCompletion, populates response body with this + * information, and sends response. + * + * @param mixed $data + * @param bool $keepLayouts + * @return string|void + */ + public function sendAutoCompletion($data, $keepLayouts = false) + { + $data = $this->prepareAutoCompletion($data, $keepLayouts); + + $response = $this->getResponse(); + $response->setBody($data); + + if (!$this->suppressExit) { + $response->sendResponse(); + exit; + } + + return $data; + } + + /** + * Strategy pattern: allow calling helper as broker method + * + * Prepares autocompletion data and, if $sendNow is true, immediately sends + * response. + * + * @param mixed $data + * @param bool $sendNow + * @param bool $keepLayouts + * @return string|void + */ + public function direct($data, $sendNow = true, $keepLayouts = false) + { + if ($sendNow) { + return $this->sendAutoCompletion($data, $keepLayouts); + } + + return $this->prepareAutoCompletion($data, $keepLayouts); + } +} diff --git a/library/vendor/Zend/Controller/Action/Helper/Cache.php b/library/vendor/Zend/Controller/Action/Helper/Cache.php new file mode 100644 index 0000000..32afc77 --- /dev/null +++ b/library/vendor/Zend/Controller/Action/Helper/Cache.php @@ -0,0 +1,286 @@ +getRequest()->getControllerName(); + $actions = array_unique($actions); + if (!isset($this->_caching[$controller])) { + $this->_caching[$controller] = array(); + } + if (!empty($tags)) { + $tags = array_unique($tags); + if (!isset($this->_tags[$controller])) { + $this->_tags[$controller] = array(); + } + } + foreach ($actions as $action) { + $this->_caching[$controller][] = $action; + if (!empty($tags)) { + $this->_tags[$controller][$action] = array(); + foreach ($tags as $tag) { + $this->_tags[$controller][$action][] = $tag; + } + } + } + if ($extension) { + if (!isset($this->_extensions[$controller])) { + $this->_extensions[$controller] = array(); + } + foreach ($actions as $action) { + $this->_extensions[$controller][$action] = $extension; + } + } + } + + /** + * Remove a specific page cache static file based on its + * relative URL from the application's public directory. + * The file extension is not required here; usually matches + * the original REQUEST_URI that was cached. + * + * @param string $relativeUrl + * @param bool $recursive + * @return mixed + */ + public function removePage($relativeUrl, $recursive = false) + { + $cache = $this->getCache(Zend_Cache_Manager::PAGECACHE); + $encodedCacheId = $this->_encodeCacheId($relativeUrl); + + if ($recursive) { + $backend = $cache->getBackend(); + if (($backend instanceof Zend_Cache_Backend) + && method_exists($backend, 'removeRecursively') + ) { + $result = $backend->removeRecursively($encodedCacheId); + if (is_null($result) ) { + $result = $backend->removeRecursively($relativeUrl); + } + return $result; + } + } + + $result = $cache->remove($encodedCacheId); + if (is_null($result) ) { + $result = $cache->remove($relativeUrl); + } + return $result; + } + + /** + * Remove a specific page cache static file based on its + * relative URL from the application's public directory. + * The file extension is not required here; usually matches + * the original REQUEST_URI that was cached. + * + * @param array $tags + * @return mixed + */ + public function removePagesTagged(array $tags) + { + return $this->getCache(Zend_Cache_Manager::PAGECACHE) + ->clean(Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG, $tags); + } + + /** + * Commence page caching for any cacheable actions + * + * @return void + */ + public function preDispatch() + { + $controller = $this->getRequest()->getControllerName(); + $action = $this->getRequest()->getActionName(); + $stats = ob_get_status(true); + foreach ($stats as $status) { + if ($status['name'] == 'Zend_Cache_Frontend_Page::_flush' + || $status['name'] == 'Zend_Cache_Frontend_Capture::_flush') { + $obStarted = true; + } + } + if (!isset($obStarted) && isset($this->_caching[$controller]) && + in_array($action, $this->_caching[$controller])) { + $reqUri = $this->getRequest()->getRequestUri(); + $tags = array(); + if (isset($this->_tags[$controller][$action]) + && !empty($this->_tags[$controller][$action])) { + $tags = array_unique($this->_tags[$controller][$action]); + } + $extension = null; + if (isset($this->_extensions[$controller][$action])) { + $extension = $this->_extensions[$controller][$action]; + } + $this->getCache(Zend_Cache_Manager::PAGECACHE) + ->start($this->_encodeCacheId($reqUri), $tags, $extension); + } + } + + /** + * Encode a Cache ID as hexadecimal. This is a workaround because Backend ID validation + * is trapped in the Frontend classes. Will try to get this reversed for ZF 2.0 + * because it's a major annoyance to have IDs so restricted! + * + * @return string + * @param string $requestUri + */ + protected function _encodeCacheId($requestUri) + { + return bin2hex($requestUri); + } + + /** + * Set an instance of the Cache Manager for this helper + * + * @param Zend_Cache_Manager $manager + * @return void + */ + public function setManager(Zend_Cache_Manager $manager) + { + $this->_manager = $manager; + return $this; + } + + /** + * Get the Cache Manager instance or instantiate the object if not + * exists. Attempts to load from bootstrap if available. + * + * @return Zend_Cache_Manager + */ + public function getManager() + { + if ($this->_manager !== null) { + return $this->_manager; + } + $front = Zend_Controller_Front::getInstance(); + if ($front->getParam('bootstrap') + && $front->getParam('bootstrap')->getResource('CacheManager')) { + return $front->getParam('bootstrap') + ->getResource('CacheManager'); + } + $this->_manager = new Zend_Cache_Manager; + return $this->_manager; + } + + /** + * Return a list of actions for the current Controller marked for + * caching + * + * @return array + */ + public function getCacheableActions() + { + return $this->_caching; + } + + /** + * Return a list of tags set for all cacheable actions + * + * @return array + */ + public function getCacheableTags() + { + return $this->_tags; + } + + /** + * Proxy non-matched methods back to Zend_Cache_Manager where + * appropriate + * + * @param string $method + * @param array $args + * @return mixed + */ + public function __call($method, $args) + { + if (method_exists($this->getManager(), $method)) { + return call_user_func_array( + array($this->getManager(), $method), $args + ); + } + throw new Zend_Controller_Action_Exception('Method does not exist:' + . $method); + } + +} diff --git a/library/vendor/Zend/Controller/Action/Helper/ContextSwitch.php b/library/vendor/Zend/Controller/Action/Helper/ContextSwitch.php new file mode 100644 index 0000000..6caeec9 --- /dev/null +++ b/library/vendor/Zend/Controller/Action/Helper/ContextSwitch.php @@ -0,0 +1,1377 @@ +setConfig($options); + } elseif (is_array($options)) { + $this->setOptions($options); + } + + if (empty($this->_contexts)) { + $this->addContexts(array( + 'json' => array( + 'suffix' => 'json', + 'headers' => array('Content-Type' => 'application/json'), + 'callbacks' => array( + 'init' => 'initJsonContext', + 'post' => 'postJsonContext' + ) + ), + 'xml' => array( + 'suffix' => 'xml', + 'headers' => array('Content-Type' => 'application/xml'), + ) + )); + } + + $this->init(); + } + + /** + * Initialize at start of action controller + * + * Reset the view script suffix to the original state, or store the + * original state. + * + * @return void + */ + public function init() + { + if (null === $this->_viewSuffixOrig) { + $this->_viewSuffixOrig = $this->_getViewRenderer()->getViewSuffix(); + } else { + $this->_getViewRenderer()->setViewSuffix($this->_viewSuffixOrig); + } + } + + /** + * Configure object from array of options + * + * @param array $options + * @return Zend_Controller_Action_Helper_ContextSwitch Provides a fluent interface + */ + public function setOptions(array $options) + { + if (isset($options['contexts'])) { + $this->setContexts($options['contexts']); + unset($options['contexts']); + } + + foreach ($options as $key => $value) { + $method = 'set' . ucfirst($key); + if (in_array($method, $this->_unconfigurable)) { + continue; + } + + if (in_array($method, $this->_specialConfig)) { + $method = '_' . $method; + } + + if (method_exists($this, $method)) { + $this->$method($value); + } + } + return $this; + } + + /** + * Set object state from config object + * + * @param Zend_Config $config + * @return Zend_Controller_Action_Helper_ContextSwitch Provides a fluent interface + */ + public function setConfig(Zend_Config $config) + { + return $this->setOptions($config->toArray()); + } + + /** + * Strategy pattern: return object + * + * @return Zend_Controller_Action_Helper_ContextSwitch Provides a fluent interface + */ + public function direct() + { + return $this; + } + + /** + * Initialize context detection and switching + * + * @param mixed $format + * @throws Zend_Controller_Action_Exception + * @return void + */ + public function initContext($format = null) + { + $this->_currentContext = null; + + $controller = $this->getActionController(); + $request = $this->getRequest(); + $action = $request->getActionName(); + + // Return if no context switching enabled, or no context switching + // enabled for this action + $contexts = $this->getActionContexts($action); + if (empty($contexts)) { + return; + } + + // Return if no context parameter provided + if (!$context = $request->getParam($this->getContextParam())) { + if ($format === null) { + return; + } + $context = $format; + $format = null; + } + + // Check if context allowed by action controller + if (!$this->hasActionContext($action, $context)) { + return; + } + + // Return if invalid context parameter provided and no format or invalid + // format provided + if (!$this->hasContext($context)) { + if (empty($format) || !$this->hasContext($format)) { + + return; + } + } + + // Use provided format if passed + if (!empty($format) && $this->hasContext($format)) { + $context = $format; + } + + $suffix = $this->getSuffix($context); + + $this->_getViewRenderer()->setViewSuffix($suffix); + + $headers = $this->getHeaders($context); + if (!empty($headers)) { + $response = $this->getResponse(); + foreach ($headers as $header => $content) { + $response->setHeader($header, $content); + } + } + + if ($this->getAutoDisableLayout()) { + /** + * @see Zend_Layout + */ + $layout = Zend_Layout::getMvcInstance(); + if (null !== $layout) { + $layout->disableLayout(); + } + } + + if (null !== ($callback = $this->getCallback($context, self::TRIGGER_INIT))) { + if (is_string($callback) && method_exists($this, $callback)) { + $this->$callback(); + } elseif (is_string($callback) && function_exists($callback)) { + $callback(); + } elseif (is_array($callback)) { + call_user_func($callback); + } else { + /** + * @see Zend_Controller_Action_Exception + */ + throw new Zend_Controller_Action_Exception(sprintf('Invalid context callback registered for context "%s"', $context)); + } + } + + $this->_currentContext = $context; + } + + /** + * JSON context extra initialization + * + * Turns off viewRenderer auto-rendering + * + * @return void + */ + public function initJsonContext() + { + if (!$this->getAutoJsonSerialization()) { + return; + } + + $viewRenderer = Zend_Controller_Action_HelperBroker::getStaticHelper('viewRenderer'); + $view = $viewRenderer->view; + if ($view instanceof Zend_View_Interface) { + $viewRenderer->setNoRender(true); + } + } + + /** + * Should JSON contexts auto-serialize? + * + * @param boolean $flag + * @return Zend_Controller_Action_Helper_ContextSwitch Provides a fluent interface + */ + public function setAutoJsonSerialization($flag) + { + $this->_autoJsonSerialization = (bool) $flag; + return $this; + } + + /** + * Get JSON context auto-serialization flag + * + * @return boolean + */ + public function getAutoJsonSerialization() + { + return $this->_autoJsonSerialization; + } + + /** + * Set suffix from array + * + * @param array $spec + * @return Zend_Controller_Action_Helper_ContextSwitch Provides a fluent interface + */ + protected function _setSuffix(array $spec) + { + foreach ($spec as $context => $suffixInfo) { + if (!is_string($context)) { + $context = null; + } + + if (is_string($suffixInfo)) { + $this->setSuffix($context, $suffixInfo); + continue; + } elseif (is_array($suffixInfo)) { + if (isset($suffixInfo['suffix'])) { + $suffix = $suffixInfo['suffix']; + $prependViewRendererSuffix = true; + + if ((null === $context) && isset($suffixInfo['context'])) { + $context = $suffixInfo['context']; + } + + if (isset($suffixInfo['prependViewRendererSuffix'])) { + $prependViewRendererSuffix = $suffixInfo['prependViewRendererSuffix']; + } + + $this->setSuffix($context, $suffix, $prependViewRendererSuffix); + continue; + } + + $count = count($suffixInfo); + switch (true) { + case (($count < 2) && (null === $context)): + /** + * @see Zend_Controller_Action_Exception + */ + throw new Zend_Controller_Action_Exception('Invalid suffix information provided in config'); + case ($count < 2): + $suffix = array_shift($suffixInfo); + $this->setSuffix($context, $suffix); + break; + case (($count < 3) && (null === $context)): + $context = array_shift($suffixInfo); + $suffix = array_shift($suffixInfo); + $this->setSuffix($context, $suffix); + break; + case (($count == 3) && (null === $context)): + $context = array_shift($suffixInfo); + $suffix = array_shift($suffixInfo); + $prependViewRendererSuffix = array_shift($suffixInfo); + $this->setSuffix($context, $suffix, $prependViewRendererSuffix); + break; + case ($count >= 2): + $suffix = array_shift($suffixInfo); + $prependViewRendererSuffix = array_shift($suffixInfo); + $this->setSuffix($context, $suffix, $prependViewRendererSuffix); + break; + } + } + } + return $this; + } + + /** + * Customize view script suffix to use when switching context. + * + * Passing an empty suffix value to the setters disables the view script + * suffix change. + * + * @param string $context Context type for which to set suffix + * @param string $suffix Suffix to use + * @param boolean $prependViewRendererSuffix Whether or not to prepend the new suffix to the viewrenderer suffix + * @throws Zend_Controller_Action_Exception + * @return Zend_Controller_Action_Helper_ContextSwitch Provides a fluent interface + */ + public function setSuffix($context, $suffix, $prependViewRendererSuffix = true) + { + if (!isset($this->_contexts[$context])) { + /** + * @see Zend_Controller_Action_Exception + */ + throw new Zend_Controller_Action_Exception(sprintf('Cannot set suffix; invalid context type "%s"', $context)); + } + + if (empty($suffix)) { + $suffix = ''; + } + + if (is_array($suffix)) { + if (isset($suffix['prependViewRendererSuffix'])) { + $prependViewRendererSuffix = $suffix['prependViewRendererSuffix']; + } + if (isset($suffix['suffix'])) { + $suffix = $suffix['suffix']; + } else { + $suffix = ''; + } + } + + $suffix = (string) $suffix; + + if ($prependViewRendererSuffix) { + if (empty($suffix)) { + $suffix = $this->_getViewRenderer()->getViewSuffix(); + } else { + $suffix .= '.' . $this->_getViewRenderer()->getViewSuffix(); + } + } + + $this->_contexts[$context]['suffix'] = $suffix; + return $this; + } + + /** + * Retrieve suffix for given context type + * + * @param string $type Context type + * @throws Zend_Controller_Action_Exception + * @return string + */ + public function getSuffix($type) + { + if (!isset($this->_contexts[$type])) { + /** + * @see Zend_Controller_Action_Exception + */ + throw new Zend_Controller_Action_Exception(sprintf('Cannot retrieve suffix; invalid context type "%s"', $type)); + } + + return $this->_contexts[$type]['suffix']; + } + + /** + * Does the given context exist? + * + * @param string $context + * @param boolean $throwException + * @throws Zend_Controller_Action_Exception if context does not exist and throwException is true + * @return bool + */ + public function hasContext($context, $throwException = false) + { + if (is_string($context)) { + if (isset($this->_contexts[$context])) { + return true; + } + } elseif (is_array($context)) { + $error = false; + foreach ($context as $test) { + if (!isset($this->_contexts[$test])) { + $error = (string) $test; + break; + } + } + if (false === $error) { + return true; + } + $context = $error; + } elseif (true === $context) { + return true; + } + + if ($throwException) { + /** + * @see Zend_Controller_Action_Exception + */ + throw new Zend_Controller_Action_Exception(sprintf('Context "%s" does not exist', $context)); + } + + return false; + } + + /** + * Add header to context + * + * @param string $context + * @param string $header + * @param string $content + * @throws Zend_Controller_Action_Exception + * @return Zend_Controller_Action_Helper_ContextSwitch Provides a fluent interface + */ + public function addHeader($context, $header, $content) + { + $context = (string) $context; + $this->hasContext($context, true); + + $header = (string) $header; + $content = (string) $content; + + if (isset($this->_contexts[$context]['headers'][$header])) { + /** + * @see Zend_Controller_Action_Exception + */ + throw new Zend_Controller_Action_Exception(sprintf('Cannot add "%s" header to context "%s": already exists', $header, $context)); + } + + $this->_contexts[$context]['headers'][$header] = $content; + return $this; + } + + /** + * Customize response header to use when switching context + * + * Passing an empty header value to the setters disables the response + * header. + * + * @param string $type Context type for which to set suffix + * @param string $header Header to set + * @param string $content Header content + * @return Zend_Controller_Action_Helper_ContextSwitch Provides a fluent interface + */ + public function setHeader($context, $header, $content) + { + $this->hasContext($context, true); + $context = (string) $context; + $header = (string) $header; + $content = (string) $content; + + $this->_contexts[$context]['headers'][$header] = $content; + return $this; + } + + /** + * Add multiple headers at once for a given context + * + * @param string $context + * @param array $headers + * @return Zend_Controller_Action_Helper_ContextSwitch Provides a fluent interface + */ + public function addHeaders($context, array $headers) + { + foreach ($headers as $header => $content) { + $this->addHeader($context, $header, $content); + } + + return $this; + } + + /** + * Set headers from context => headers pairs + * + * @param array $options + * @return Zend_Controller_Action_Helper_ContextSwitch Provides a fluent interface + */ + protected function _setHeaders(array $options) + { + foreach ($options as $context => $headers) { + if (!is_array($headers)) { + continue; + } + $this->setHeaders($context, $headers); + } + + return $this; + } + + /** + * Set multiple headers at once for a given context + * + * @param string $context + * @param array $headers + * @return Zend_Controller_Action_Helper_ContextSwitch Provides a fluent interface + */ + public function setHeaders($context, array $headers) + { + $this->clearHeaders($context); + foreach ($headers as $header => $content) { + $this->setHeader($context, $header, $content); + } + + return $this; + } + + /** + * Retrieve context header + * + * Returns the value of a given header for a given context type + * + * @param string $context + * @param string $header + * @return string|null + */ + public function getHeader($context, $header) + { + $this->hasContext($context, true); + $context = (string) $context; + $header = (string) $header; + if (isset($this->_contexts[$context]['headers'][$header])) { + return $this->_contexts[$context]['headers'][$header]; + } + + return null; + } + + /** + * Retrieve context headers + * + * Returns all headers for a context as key/value pairs + * + * @param string $context + * @return array + */ + public function getHeaders($context) + { + $this->hasContext($context, true); + $context = (string) $context; + return $this->_contexts[$context]['headers']; + } + + /** + * Remove a single header from a context + * + * @param string $context + * @param string $header + * @return boolean + */ + public function removeHeader($context, $header) + { + $this->hasContext($context, true); + $context = (string) $context; + $header = (string) $header; + if (isset($this->_contexts[$context]['headers'][$header])) { + unset($this->_contexts[$context]['headers'][$header]); + return true; + } + + return false; + } + + /** + * Clear all headers for a given context + * + * @param string $context + * @return Zend_Controller_Action_Helper_ContextSwitch Provides a fluent interface + */ + public function clearHeaders($context) + { + $this->hasContext($context, true); + $context = (string) $context; + $this->_contexts[$context]['headers'] = array(); + return $this; + } + + /** + * Validate trigger and return in normalized form + * + * @param string $trigger + * @throws Zend_Controller_Action_Exception + * @return string + */ + protected function _validateTrigger($trigger) + { + $trigger = strtoupper($trigger); + if ('TRIGGER_' !== substr($trigger, 0, 8)) { + $trigger = 'TRIGGER_' . $trigger; + } + + if (!in_array($trigger, array(self::TRIGGER_INIT, self::TRIGGER_POST))) { + /** + * @see Zend_Controller_Action_Exception + */ + throw new Zend_Controller_Action_Exception(sprintf('Invalid trigger "%s"', $trigger)); + } + + return $trigger; + } + + /** + * Set a callback for a given context and trigger + * + * @param string $context + * @param string $trigger + * @param string|array $callback + * @throws Zend_Controller_Action_Exception + * @return Zend_Controller_Action_Helper_ContextSwitch Provides a fluent interface + */ + public function setCallback($context, $trigger, $callback) + { + $this->hasContext($context, true); + $trigger = $this->_validateTrigger($trigger); + + if (!is_string($callback)) { + if (!is_array($callback) || (2 != count($callback))) { + /** + * @see Zend_Controller_Action_Exception + */ + throw new Zend_Controller_Action_Exception('Invalid callback specified'); + } + } + + $this->_contexts[$context]['callbacks'][$trigger] = $callback; + return $this; + } + + /** + * Set callbacks from array of context => callbacks pairs + * + * @param array $options + * @return Zend_Controller_Action_Helper_ContextSwitch Provides a fluent interface + */ + protected function _setCallbacks(array $options) + { + foreach ($options as $context => $callbacks) { + if (!is_array($callbacks)) { + continue; + } + + $this->setCallbacks($context, $callbacks); + } + return $this; + } + + /** + * Set callbacks for a given context + * + * Callbacks should be in trigger/callback pairs. + * + * @param string $context + * @param array $callbacks + * @return Zend_Controller_Action_Helper_ContextSwitch Provides a fluent interface + */ + public function setCallbacks($context, array $callbacks) + { + $this->hasContext($context, true); + $context = (string) $context; + if (!isset($this->_contexts[$context]['callbacks'])) { + $this->_contexts[$context]['callbacks'] = array(); + } + + foreach ($callbacks as $trigger => $callback) { + $this->setCallback($context, $trigger, $callback); + } + return $this; + } + + /** + * Get a single callback for a given context and trigger + * + * @param string $context + * @param string $trigger + * @return string|array|null + */ + public function getCallback($context, $trigger) + { + $this->hasContext($context, true); + $trigger = $this->_validateTrigger($trigger); + if (isset($this->_contexts[$context]['callbacks'][$trigger])) { + return $this->_contexts[$context]['callbacks'][$trigger]; + } + + return null; + } + + /** + * Get all callbacks for a given context + * + * @param string $context + * @return array + */ + public function getCallbacks($context) + { + $this->hasContext($context, true); + return $this->_contexts[$context]['callbacks']; + } + + /** + * Clear a callback for a given context and trigger + * + * @param string $context + * @param string $trigger + * @return boolean + */ + public function removeCallback($context, $trigger) + { + $this->hasContext($context, true); + $trigger = $this->_validateTrigger($trigger); + if (isset($this->_contexts[$context]['callbacks'][$trigger])) { + unset($this->_contexts[$context]['callbacks'][$trigger]); + return true; + } + + return false; + } + + /** + * Clear all callbacks for a given context + * + * @param string $context + * @return Zend_Controller_Action_Helper_ContextSwitch Provides a fluent interface + */ + public function clearCallbacks($context) + { + $this->hasContext($context, true); + $this->_contexts[$context]['callbacks'] = array(); + return $this; + } + + /** + * Set name of parameter to use when determining context format + * + * @param string $name + * @return Zend_Controller_Action_Helper_ContextSwitch Provides a fluent interface + */ + public function setContextParam($name) + { + $this->_contextParam = (string) $name; + return $this; + } + + /** + * Return context format request parameter name + * + * @return string + */ + public function getContextParam() + { + return $this->_contextParam; + } + + /** + * Indicate default context to use when no context format provided + * + * @param string $type + * @throws Zend_Controller_Action_Exception + * @return Zend_Controller_Action_Helper_ContextSwitch Provides a fluent interface + */ + public function setDefaultContext($type) + { + if (!isset($this->_contexts[$type])) { + /** + * @see Zend_Controller_Action_Exception + */ + throw new Zend_Controller_Action_Exception(sprintf('Cannot set default context; invalid context type "%s"', $type)); + } + + $this->_defaultContext = $type; + return $this; + } + + /** + * Return default context + * + * @return string + */ + public function getDefaultContext() + { + return $this->_defaultContext; + } + + /** + * Set flag indicating if layout should be disabled + * + * @param boolean $flag + * @return Zend_Controller_Action_Helper_ContextSwitch Provides a fluent interface + */ + public function setAutoDisableLayout($flag) + { + $this->_disableLayout = ($flag) ? true : false; + return $this; + } + + /** + * Retrieve auto layout disable flag + * + * @return boolean + */ + public function getAutoDisableLayout() + { + return $this->_disableLayout; + } + + /** + * Add new context + * + * @param string $context Context type + * @param array $spec Context specification + * @throws Zend_Controller_Action_Exception + * @return Zend_Controller_Action_Helper_ContextSwitch Provides a fluent interface + */ + public function addContext($context, array $spec) + { + if ($this->hasContext($context)) { + /** + * @see Zend_Controller_Action_Exception + */ + throw new Zend_Controller_Action_Exception(sprintf('Cannot add context "%s"; already exists', $context)); + } + $context = (string) $context; + + $this->_contexts[$context] = array(); + + $this->setSuffix($context, (isset($spec['suffix']) ? $spec['suffix'] : '')) + ->setHeaders($context, (isset($spec['headers']) ? $spec['headers'] : array())) + ->setCallbacks($context, (isset($spec['callbacks']) ? $spec['callbacks'] : array())); + return $this; + } + + /** + * Overwrite existing context + * + * @param string $context Context type + * @param array $spec Context specification + * @return Zend_Controller_Action_Helper_ContextSwitch Provides a fluent interface + */ + public function setContext($context, array $spec) + { + $this->removeContext($context); + return $this->addContext($context, $spec); + } + + /** + * Add multiple contexts + * + * @param array $contexts + * @return Zend_Controller_Action_Helper_ContextSwitch Provides a fluent interface + */ + public function addContexts(array $contexts) + { + foreach ($contexts as $context => $spec) { + $this->addContext($context, $spec); + } + return $this; + } + + /** + * Set multiple contexts, after first removing all + * + * @param array $contexts + * @return Zend_Controller_Action_Helper_ContextSwitch Provides a fluent interface + */ + public function setContexts(array $contexts) + { + $this->clearContexts(); + foreach ($contexts as $context => $spec) { + $this->addContext($context, $spec); + } + return $this; + } + + /** + * Retrieve context specification + * + * @param string $context + * @return array|null + */ + public function getContext($context) + { + if ($this->hasContext($context)) { + return $this->_contexts[(string) $context]; + } + return null; + } + + /** + * Retrieve context definitions + * + * @return array + */ + public function getContexts() + { + return $this->_contexts; + } + + /** + * Remove a context + * + * @param string $context + * @return boolean + */ + public function removeContext($context) + { + if ($this->hasContext($context)) { + unset($this->_contexts[(string) $context]); + return true; + } + return false; + } + + /** + * Remove all contexts + * + * @return Zend_Controller_Action_Helper_ContextSwitch Provides a fluent interface + */ + public function clearContexts() + { + $this->_contexts = array(); + return $this; + } + + /** + * Return current context, if any + * + * @return null|string + */ + public function getCurrentContext() + { + return $this->_currentContext; + } + + /** + * Post dispatch processing + * + * Execute postDispatch callback for current context, if available + * + * @throws Zend_Controller_Action_Exception + * @return void + */ + public function postDispatch() + { + $context = $this->getCurrentContext(); + if (null !== $context) { + if (null !== ($callback = $this->getCallback($context, self::TRIGGER_POST))) { + if (is_string($callback) && method_exists($this, $callback)) { + $this->$callback(); + } elseif (is_string($callback) && function_exists($callback)) { + $callback(); + } elseif (is_array($callback)) { + call_user_func($callback); + } else { + /** + * @see Zend_Controller_Action_Exception + */ + throw new Zend_Controller_Action_Exception(sprintf('Invalid postDispatch context callback registered for context "%s"', $context)); + } + } + } + } + + /** + * JSON post processing + * + * JSON serialize view variables to response body + * + * @return void + */ + public function postJsonContext() + { + if (!$this->getAutoJsonSerialization()) { + return; + } + + $viewRenderer = Zend_Controller_Action_HelperBroker::getStaticHelper('viewRenderer'); + $view = $viewRenderer->view; + if ($view instanceof Zend_View_Interface) { + /** + * @see Zend_Json + */ + if(method_exists($view, 'getVars')) { + $vars = Zend_Json::encode($view->getVars()); + $this->getResponse()->setBody($vars); + } else { + throw new Zend_Controller_Action_Exception('View does not implement the getVars() method needed to encode the view into JSON'); + } + } + } + + /** + * Add one or more contexts to an action + * + * @param string $action + * @param string|array $context + * @return Zend_Controller_Action_Helper_ContextSwitch|void Provides a fluent interface + */ + public function addActionContext($action, $context) + { + $this->hasContext($context, true); + $controller = $this->getActionController(); + if (null === $controller) { + return; + } + $action = (string) $action; + $contextKey = $this->_contextKey; + + if (!isset($controller->$contextKey)) { + $controller->$contextKey = array(); + } + + if (true === $context) { + $contexts = $this->getContexts(); + $controller->{$contextKey}[$action] = array_keys($contexts); + return $this; + } + + $context = (array) $context; + if (!isset($controller->{$contextKey}[$action])) { + $controller->{$contextKey}[$action] = $context; + } else { + $controller->{$contextKey}[$action] = array_merge( + $controller->{$contextKey}[$action], + $context + ); + } + + return $this; + } + + /** + * Set a context as available for a given controller action + * + * @param string $action + * @param string|array $context + * @return Zend_Controller_Action_Helper_ContextSwitch|void Provides a fluent interface + */ + public function setActionContext($action, $context) + { + $this->hasContext($context, true); + $controller = $this->getActionController(); + if (null === $controller) { + return; + } + $action = (string) $action; + $contextKey = $this->_contextKey; + + if (!isset($controller->$contextKey)) { + $controller->$contextKey = array(); + } + + if (true === $context) { + $contexts = $this->getContexts(); + $controller->{$contextKey}[$action] = array_keys($contexts); + } else { + $controller->{$contextKey}[$action] = (array) $context; + } + + return $this; + } + + /** + * Add multiple action/context pairs at once + * + * @param array $contexts + * @return Zend_Controller_Action_Helper_ContextSwitch Provides a fluent interface + */ + public function addActionContexts(array $contexts) + { + foreach ($contexts as $action => $context) { + $this->addActionContext($action, $context); + } + return $this; + } + + /** + * Overwrite and set multiple action contexts at once + * + * @param array $contexts + * @return Zend_Controller_Action_Helper_ContextSwitch Provides a fluent interface + */ + public function setActionContexts(array $contexts) + { + foreach ($contexts as $action => $context) { + $this->setActionContext($action, $context); + } + return $this; + } + + /** + * Does a particular controller action have the given context(s)? + * + * @param string $action + * @param string|array $context + * @throws Zend_Controller_Action_Exception + * @return boolean + */ + public function hasActionContext($action, $context) + { + $this->hasContext($context, true); + $controller = $this->getActionController(); + if (null === $controller) { + return false; + } + $action = (string) $action; + $contextKey = $this->_contextKey; + + if (!isset($controller->{$contextKey})) { + return false; + } + + $allContexts = $controller->{$contextKey}; + + if (!is_array($allContexts)) { + /** + * @see Zend_Controller_Action_Exception + */ + throw new Zend_Controller_Action_Exception("Invalid contexts found for controller"); + } + + if (!isset($allContexts[$action])) { + return false; + } + + if (true === $allContexts[$action]) { + return true; + } + + $contexts = $allContexts[$action]; + + if (!is_array($contexts)) { + /** + * @see Zend_Controller_Action_Exception + */ + throw new Zend_Controller_Action_Exception(sprintf("Invalid contexts found for action '%s'", $action)); + } + + if (is_string($context) && in_array($context, $contexts)) { + return true; + } elseif (is_array($context)) { + $found = true; + foreach ($context as $test) { + if (!in_array($test, $contexts)) { + $found = false; + break; + } + } + return $found; + } + + return false; + } + + /** + * Get contexts for a given action or all actions in the controller + * + * @param string $action + * @return array + */ + public function getActionContexts($action = null) + { + $controller = $this->getActionController(); + if (null === $controller) { + return array(); + } + $contextKey = $this->_contextKey; + + if (!isset($controller->$contextKey)) { + return array(); + } + + if (null !== $action) { + $action = (string) $action; + if (isset($controller->{$contextKey}[$action])) { + return $controller->{$contextKey}[$action]; + } else { + return array(); + } + } + + return $controller->$contextKey; + } + + /** + * Remove one or more contexts for a given controller action + * + * @param string $action + * @param string|array $context + * @return boolean + */ + public function removeActionContext($action, $context) + { + if ($this->hasActionContext($action, $context)) { + $controller = $this->getActionController(); + $contextKey = $this->_contextKey; + $action = (string) $action; + $contexts = $controller->$contextKey; + $actionContexts = $contexts[$action]; + $contexts = (array) $context; + foreach ($contexts as $context) { + $index = array_search($context, $actionContexts); + if (false !== $index) { + unset($controller->{$contextKey}[$action][$index]); + } + } + return true; + } + return false; + } + + /** + * Clear all contexts for a given controller action or all actions + * + * @param string $action + * @return Zend_Controller_Action_Helper_ContextSwitch Provides a fluent interface + */ + public function clearActionContexts($action = null) + { + $controller = $this->getActionController(); + $contextKey = $this->_contextKey; + + if (!isset($controller->$contextKey) || empty($controller->$contextKey)) { + return $this; + } + + if (null === $action) { + $controller->$contextKey = array(); + return $this; + } + + $action = (string) $action; + if (isset($controller->{$contextKey}[$action])) { + unset($controller->{$contextKey}[$action]); + } + + return $this; + } + + /** + * Retrieve ViewRenderer + * + * @return Zend_Controller_Action_Helper_ViewRenderer Provides a fluent interface + */ + protected function _getViewRenderer() + { + if (null === $this->_viewRenderer) { + $this->_viewRenderer = Zend_Controller_Action_HelperBroker::getStaticHelper('viewRenderer'); + } + + return $this->_viewRenderer; + } +} + diff --git a/library/vendor/Zend/Controller/Action/Helper/Json.php b/library/vendor/Zend/Controller/Action/Helper/Json.php new file mode 100644 index 0000000..5b77f12 --- /dev/null +++ b/library/vendor/Zend/Controller/Action/Helper/Json.php @@ -0,0 +1,130 @@ +true|false + * if $keepLayouts and parmas for Zend_Json::encode are required + * then, the array can contains a 'keepLayout'=>true|false and/or 'encodeData'=>true|false + * that will not be passed to Zend_Json::encode method but will be passed + * to Zend_View_Helper_Json + * @throws Zend_Controller_Action_Helper_Json + * @return string + */ + public function encodeJson($data, $keepLayouts = false, $encodeData = true) + { + /** + * @see Zend_View_Helper_Json + */ + $jsonHelper = new Zend_View_Helper_Json(); + $data = $jsonHelper->json($data, $keepLayouts, $encodeData); + + if (!$keepLayouts) { + /** + * @see Zend_Controller_Action_HelperBroker + */ + Zend_Controller_Action_HelperBroker::getStaticHelper('viewRenderer')->setNoRender(true); + } + + return $data; + } + + /** + * Encode JSON response and immediately send + * + * @param mixed $data + * @param boolean|array $keepLayouts + * @param $encodeData Encode $data as JSON? + * NOTE: if boolean, establish $keepLayouts to true|false + * if array, admit params for Zend_Json::encode as enableJsonExprFinder=>true|false + * if $keepLayouts and parmas for Zend_Json::encode are required + * then, the array can contains a 'keepLayout'=>true|false and/or 'encodeData'=>true|false + * that will not be passed to Zend_Json::encode method but will be passed + * to Zend_View_Helper_Json + * @return string|void + */ + public function sendJson($data, $keepLayouts = false, $encodeData = true) + { + $data = $this->encodeJson($data, $keepLayouts, $encodeData); + $response = $this->getResponse(); + $response->setBody($data); + + if (!$this->suppressExit) { + $response->sendResponse(); + exit; + } + + return $data; + } + + /** + * Strategy pattern: call helper as helper broker method + * + * Allows encoding JSON. If $sendNow is true, immediately sends JSON + * response. + * + * @param mixed $data + * @param boolean $sendNow + * @param boolean $keepLayouts + * @param boolean $encodeData Encode $data as JSON? + * @return string|void + */ + public function direct($data, $sendNow = true, $keepLayouts = false, $encodeData = true) + { + if ($sendNow) { + return $this->sendJson($data, $keepLayouts, $encodeData); + } + return $this->encodeJson($data, $keepLayouts, $encodeData); + } +} diff --git a/library/vendor/Zend/Controller/Action/Helper/Redirector.php b/library/vendor/Zend/Controller/Action/Helper/Redirector.php new file mode 100644 index 0000000..8ff7c3e --- /dev/null +++ b/library/vendor/Zend/Controller/Action/Helper/Redirector.php @@ -0,0 +1,531 @@ +_code; + } + + /** + * Validate HTTP status redirect code + * + * @param int $code + * @throws Zend_Controller_Action_Exception on invalid HTTP status code + * @return true + */ + protected function _checkCode($code) + { + $code = (int)$code; + if ((300 > $code) || (307 < $code) || (304 == $code) || (306 == $code)) { + throw new Zend_Controller_Action_Exception('Invalid redirect HTTP status code (' . $code . ')'); + } + + return true; + } + + /** + * Set HTTP status code for {@link _redirect()} behaviour + * + * @param int $code + * @return Zend_Controller_Action_Helper_Redirector Provides a fluent interface + */ + public function setCode($code) + { + $this->_checkCode($code); + $this->_code = $code; + return $this; + } + + /** + * Retrieve flag for whether or not {@link _redirect()} will exit when finished. + * + * @return boolean + */ + public function getExit() + { + return $this->_exit; + } + + /** + * Set exit flag for {@link _redirect()} behaviour + * + * @param boolean $flag + * @return Zend_Controller_Action_Helper_Redirector Provides a fluent interface + */ + public function setExit($flag) + { + $this->_exit = ($flag) ? true : false; + return $this; + } + + /** + * Retrieve flag for whether or not {@link _redirect()} will prepend the + * base URL on relative URLs + * + * @return boolean + */ + public function getPrependBase() + { + return $this->_prependBase; + } + + /** + * Set 'prepend base' flag for {@link _redirect()} behaviour + * + * @param boolean $flag + * @return Zend_Controller_Action_Helper_Redirector Provides a fluent interface + */ + public function setPrependBase($flag) + { + $this->_prependBase = ($flag) ? true : false; + return $this; + } + + /** + * Retrieve flag for whether or not {@link redirectAndExit()} shall close the session before + * exiting. + * + * @return boolean + */ + public function getCloseSessionOnExit() + { + return $this->_closeSessionOnExit; + } + + /** + * Set flag for whether or not {@link redirectAndExit()} shall close the session before exiting. + * + * @param boolean $flag + * @return Zend_Controller_Action_Helper_Redirector Provides a fluent interface + */ + public function setCloseSessionOnExit($flag) + { + $this->_closeSessionOnExit = ($flag) ? true : false; + return $this; + } + + /** + * Return use absolute URI flag + * + * @return boolean + */ + public function getUseAbsoluteUri() + { + return $this->_useAbsoluteUri; + } + + /** + * Set use absolute URI flag + * + * @param boolean $flag + * @return Zend_Controller_Action_Helper_Redirector Provides a fluent interface + */ + public function setUseAbsoluteUri($flag = true) + { + $this->_useAbsoluteUri = ($flag) ? true : false; + return $this; + } + + /** + * Set redirect in response object + * + * @return void + */ + protected function _redirect($url) + { + if ($this->getUseAbsoluteUri() && !preg_match('#^(https?|ftp)://#', $url)) { + $host = (isset($_SERVER['HTTP_HOST'])?$_SERVER['HTTP_HOST']:''); + $proto = (isset($_SERVER['HTTPS'])&&$_SERVER['HTTPS']!=="off") ? 'https' : 'http'; + $port = (isset($_SERVER['SERVER_PORT'])?$_SERVER['SERVER_PORT']:80); + $uri = $proto . '://' . $host; + if ((('http' == $proto) && (80 != $port)) || (('https' == $proto) && (443 != $port))) { + // do not append if HTTP_HOST already contains port + if (strrchr($host, ':') === false) { + $uri .= ':' . $port; + } + } + $url = $uri . '/' . ltrim($url, '/'); + } + $this->_redirectUrl = $url; + $this->getResponse()->setRedirect($url, $this->getCode()); + } + + /** + * Retrieve currently set URL for redirect + * + * @return string + */ + public function getRedirectUrl() + { + return $this->_redirectUrl; + } + + /** + * Determine if the baseUrl should be prepended, and prepend if necessary + * + * @param string $url + * @return string + */ + protected function _prependBase($url) + { + if ($this->getPrependBase()) { + $request = $this->getRequest(); + if ($request instanceof Zend_Controller_Request_Http) { + $base = rtrim($request->getBaseUrl(), '/'); + if (!empty($base) && ('/' != $base)) { + $url = $base . '/' . ltrim($url, '/'); + } else { + $url = '/' . ltrim($url, '/'); + } + } + } + + return $url; + } + + /** + * Set a redirect URL of the form /module/controller/action/params + * + * @param string $action + * @param string $controller + * @param string $module + * @param array $params + * @return void + */ + public function setGotoSimple($action, $controller = null, $module = null, array $params = array()) + { + $dispatcher = $this->getFrontController()->getDispatcher(); + $request = $this->getRequest(); + $curModule = $request->getModuleName(); + $useDefaultController = false; + + if (null === $controller && null !== $module) { + $useDefaultController = true; + } + + if (null === $module) { + $module = $curModule; + } + + if ($module == $dispatcher->getDefaultModule()) { + $module = ''; + } + + if (null === $controller && !$useDefaultController) { + $controller = $request->getControllerName(); + if (empty($controller)) { + $controller = $dispatcher->getDefaultControllerName(); + } + } + + $params[$request->getModuleKey()] = $module; + $params[$request->getControllerKey()] = $controller; + $params[$request->getActionKey()] = $action; + + $router = $this->getFrontController()->getRouter(); + $url = $router->assemble($params, 'default', true); + + $this->_redirect($url); + } + + /** + * Build a URL based on a route + * + * @param array $urlOptions + * @param string $name Route name + * @param boolean $reset + * @param boolean $encode + * @return void + */ + public function setGotoRoute(array $urlOptions = array(), $name = null, $reset = false, $encode = true) + { + $router = $this->getFrontController()->getRouter(); + $url = $router->assemble($urlOptions, $name, $reset, $encode); + + $this->_redirect($url); + } + + /** + * Set a redirect URL string + * + * By default, emits a 302 HTTP status header, prepends base URL as defined + * in request object if url is relative, and halts script execution by + * calling exit(). + * + * $options is an optional associative array that can be used to control + * redirect behaviour. The available option keys are: + * - exit: boolean flag indicating whether or not to halt script execution when done + * - prependBase: boolean flag indicating whether or not to prepend the base URL when a relative URL is provided + * - code: integer HTTP status code to use with redirect. Should be between 300 and 307. + * + * _redirect() sets the Location header in the response object. If you set + * the exit flag to false, you can override this header later in code + * execution. + * + * If the exit flag is true (true by default), _redirect() will write and + * close the current session, if any. + * + * @param string $url + * @param array $options + * @return void + */ + public function setGotoUrl($url, array $options = array()) + { + // prevent header injections + $url = str_replace(array("\n", "\r"), '', $url); + + if (null !== $options) { + if (isset($options['exit'])) { + $this->setExit(($options['exit']) ? true : false); + } + if (isset($options['prependBase'])) { + $this->setPrependBase(($options['prependBase']) ? true : false); + } + if (isset($options['code'])) { + $this->setCode($options['code']); + } + } + + // If relative URL, decide if we should prepend base URL + if (!preg_match('|^[a-z]+://|', $url)) { + $url = $this->_prependBase($url); + } + + $this->_redirect($url); + } + + /** + * Perform a redirect to an action/controller/module with params + * + * @param string $action + * @param string $controller + * @param string $module + * @param array $params + * @return void + */ + public function gotoSimple($action, $controller = null, $module = null, array $params = array()) + { + $this->setGotoSimple($action, $controller, $module, $params); + + if ($this->getExit()) { + $this->redirectAndExit(); + } + } + + /** + * Perform a redirect to an action/controller/module with params, forcing an immdiate exit + * + * @param mixed $action + * @param mixed $controller + * @param mixed $module + * @param array $params + * @return void + */ + public function gotoSimpleAndExit($action, $controller = null, $module = null, array $params = array()) + { + $this->setGotoSimple($action, $controller, $module, $params); + $this->redirectAndExit(); + } + + /** + * Redirect to a route-based URL + * + * Uses route's assemble method to build the URL; route is specified by $name; + * default route is used if none provided. + * + * @param array $urlOptions Array of key/value pairs used to assemble URL + * @param string $name + * @param boolean $reset + * @param boolean $encode + * @return void + */ + public function gotoRoute(array $urlOptions = array(), $name = null, $reset = false, $encode = true) + { + $this->setGotoRoute($urlOptions, $name, $reset, $encode); + + if ($this->getExit()) { + $this->redirectAndExit(); + } + } + + /** + * Redirect to a route-based URL, and immediately exit + * + * Uses route's assemble method to build the URL; route is specified by $name; + * default route is used if none provided. + * + * @param array $urlOptions Array of key/value pairs used to assemble URL + * @param string $name + * @param boolean $reset + * @return void + */ + public function gotoRouteAndExit(array $urlOptions = array(), $name = null, $reset = false) + { + $this->setGotoRoute($urlOptions, $name, $reset); + $this->redirectAndExit(); + } + + /** + * Perform a redirect to a url + * + * @param string $url + * @param array $options + * @return void + */ + public function gotoUrl($url, array $options = array()) + { + $this->setGotoUrl($url, $options); + + if ($this->getExit()) { + $this->redirectAndExit(); + } + } + + /** + * Set a URL string for a redirect, perform redirect, and immediately exit + * + * @param string $url + * @param array $options + * @return void + */ + public function gotoUrlAndExit($url, array $options = array()) + { + $this->setGotoUrl($url, $options); + $this->redirectAndExit(); + } + + /** + * exit(): Perform exit for redirector + * + * @return void + */ + public function redirectAndExit() + { + if ($this->getCloseSessionOnExit()) { + // Close session, if started + if (class_exists('Zend_Session', false) && Zend_Session::isStarted()) { + Zend_Session::writeClose(); + } elseif (isset($_SESSION)) { + session_write_close(); + } + } + + $this->getResponse()->sendHeaders(); + exit(); + } + + /** + * direct(): Perform helper when called as + * $this->_helper->redirector($action, $controller, $module, $params) + * + * @param string $action + * @param string $controller + * @param string $module + * @param array $params + * @return void + */ + public function direct($action, $controller = null, $module = null, array $params = array()) + { + $this->gotoSimple($action, $controller, $module, $params); + } + + /** + * Overloading + * + * Overloading for old 'goto', 'setGoto', and 'gotoAndExit' methods + * + * @param string $method + * @param array $args + * @return mixed + * @throws Zend_Controller_Action_Exception for invalid methods + */ + public function __call($method, $args) + { + $method = strtolower($method); + if ('goto' == $method) { + return call_user_func_array(array($this, 'gotoSimple'), $args); + } + if ('setgoto' == $method) { + return call_user_func_array(array($this, 'setGotoSimple'), $args); + } + if ('gotoandexit' == $method) { + return call_user_func_array(array($this, 'gotoSimpleAndExit'), $args); + } + + throw new Zend_Controller_Action_Exception(sprintf('Invalid method "%s" called on redirector', $method)); + } +} diff --git a/library/vendor/Zend/Controller/Action/Helper/Url.php b/library/vendor/Zend/Controller/Action/Helper/Url.php new file mode 100644 index 0000000..f98bfa5 --- /dev/null +++ b/library/vendor/Zend/Controller/Action/Helper/Url.php @@ -0,0 +1,116 @@ +getRequest(); + + if (null === $controller) { + $controller = $request->getControllerName(); + } + + if (null === $module) { + $module = $request->getModuleName(); + } + + $url = $controller . '/' . $action; + if ($module != $this->getFrontController()->getDispatcher()->getDefaultModule()) { + $url = $module . '/' . $url; + } + + if ('' !== ($baseUrl = $this->getFrontController()->getBaseUrl())) { + $url = $baseUrl . '/' . $url; + } + + if (null !== $params) { + $paramPairs = array(); + foreach ($params as $key => $value) { + $paramPairs[] = urlencode($key) . '/' . urlencode($value); + } + $paramString = implode('/', $paramPairs); + $url .= '/' . $paramString; + } + + $url = '/' . ltrim($url, '/'); + + return $url; + } + + /** + * Assembles a URL based on a given route + * + * This method will typically be used for more complex operations, as it + * ties into the route objects registered with the router. + * + * @param array $urlOptions Options passed to the assemble method of the Route object. + * @param mixed $name The name of a Route to use. If null it will use the current Route + * @param boolean $reset + * @param boolean $encode + * @return string Url for the link href attribute. + */ + public function url($urlOptions = array(), $name = null, $reset = false, $encode = true) + { + $router = $this->getFrontController()->getRouter(); + return $router->assemble($urlOptions, $name, $reset, $encode); + } + + /** + * Perform helper when called as $this->_helper->url() from an action controller + * + * Proxies to {@link simple()} + * + * @param string $action + * @param string $controller + * @param string $module + * @param array $params + * @return string + */ + public function direct($action, $controller = null, $module = null, array $params = null) + { + return $this->simple($action, $controller, $module, $params); + } +} diff --git a/library/vendor/Zend/Controller/Action/Helper/ViewRenderer.php b/library/vendor/Zend/Controller/Action/Helper/ViewRenderer.php new file mode 100644 index 0000000..948ecc4 --- /dev/null +++ b/library/vendor/Zend/Controller/Action/Helper/ViewRenderer.php @@ -0,0 +1,996 @@ + + * // In your bootstrap: + * Zend_Controller_Action_HelperBroker::addHelper(new Zend_Controller_Action_Helper_ViewRenderer()); + * + * // In your action controller methods: + * $viewHelper = $this->_helper->getHelper('view'); + * + * // Don't use controller subdirectories + * $viewHelper->setNoController(true); + * + * // Specify a different script to render: + * $this->_helper->viewRenderer('form'); + * + * + * + * @uses Zend_Controller_Action_Helper_Abstract + * @package Zend_Controller + * @subpackage Zend_Controller_Action_Helper + * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +class Zend_Controller_Action_Helper_ViewRenderer extends Zend_Controller_Action_Helper_Abstract +{ + /** + * @var Zend_View_Interface + */ + public $view; + + /** + * Word delimiters + * @var array + */ + protected $_delimiters; + + /** + * @var Zend_Filter_Inflector + */ + protected $_inflector; + + /** + * Inflector target + * @var string + */ + protected $_inflectorTarget = ''; + + /** + * Current module directory + * @var string + */ + protected $_moduleDir = ''; + + /** + * Whether or not to autorender using controller name as subdirectory; + * global setting (not reset at next invocation) + * @var boolean + */ + protected $_neverController = false; + + /** + * Whether or not to autorender postDispatch; global setting (not reset at + * next invocation) + * @var boolean + */ + protected $_neverRender = false; + + /** + * Whether or not to use a controller name as a subdirectory when rendering + * @var boolean + */ + protected $_noController = false; + + /** + * Whether or not to autorender postDispatch; per controller/action setting (reset + * at next invocation) + * @var boolean + */ + protected $_noRender = false; + + /** + * Characters representing path delimiters in the controller + * @var string|array + */ + protected $_pathDelimiters; + + /** + * Which named segment of the response to utilize + * @var string + */ + protected $_responseSegment = null; + + /** + * Which action view script to render + * @var string + */ + protected $_scriptAction = null; + + /** + * View object basePath + * @var string + */ + protected $_viewBasePathSpec = ':moduleDir/views'; + + /** + * View script path specification string + * @var string + */ + protected $_viewScriptPathSpec = ':controller/:action.:suffix'; + + /** + * View script path specification string, minus controller segment + * @var string + */ + protected $_viewScriptPathNoControllerSpec = ':action.:suffix'; + + /** + * View script suffix + * @var string + */ + protected $_viewSuffix = 'phtml'; + + /** + * Constructor + * + * Optionally set view object and options. + * + * @param Zend_View_Interface $view + * @param array $options + * @return void + */ + public function __construct(Zend_View_Interface $view = null, array $options = array()) + { + if (null !== $view) { + $this->setView($view); + } + + if (!empty($options)) { + $this->_setOptions($options); + } + } + + /** + * Clone - also make sure the view is cloned. + * + * @return void + */ + public function __clone() + { + if (isset($this->view) && $this->view instanceof Zend_View_Interface) { + $this->view = clone $this->view; + + } + } + + /** + * Set the view object + * + * @param Zend_View_Interface $view + * @return Zend_Controller_Action_Helper_ViewRenderer Provides a fluent interface + */ + public function setView(Zend_View_Interface $view) + { + $this->view = $view; + return $this; + } + + /** + * Get current module name + * + * @return string + */ + public function getModule() + { + $request = $this->getRequest(); + $module = $request->getModuleName(); + if (null === $module) { + $module = $this->getFrontController()->getDispatcher()->getDefaultModule(); + } + + return $module; + } + + /** + * Get module directory + * + * @throws Zend_Controller_Action_Exception + * @return string + */ + public function getModuleDirectory() + { + $module = $this->getModule(); + $moduleDir = $this->getFrontController()->getControllerDirectory($module); + if ((null === $moduleDir) || is_array($moduleDir)) { + /** + * @see Zend_Controller_Action_Exception + */ + throw new Zend_Controller_Action_Exception('ViewRenderer cannot locate module directory for module "' . $module . '"'); + } + $this->_moduleDir = dirname($moduleDir); + return $this->_moduleDir; + } + + /** + * Get inflector + * + * @return Zend_Filter_Inflector + */ + public function getInflector() + { + if (null === $this->_inflector) { + /** + * @see Zend_Filter_Inflector + */ + /** + * @see Zend_Filter_PregReplace + */ + /** + * @see Zend_Filter_Word_UnderscoreToSeparator + */ + $this->_inflector = new Zend_Filter_Inflector(); + $this->_inflector->setStaticRuleReference('moduleDir', $this->_moduleDir) // moduleDir must be specified before the less specific 'module' + ->addRules(array( + ':module' => array('Word_CamelCaseToDash', 'StringToLower'), + ':controller' => array('Word_CamelCaseToDash', new Zend_Filter_Word_UnderscoreToSeparator('/'), 'StringToLower', new Zend_Filter_PregReplace('/\./', '-')), + ':action' => array('Word_CamelCaseToDash', new Zend_Filter_PregReplace('#[^a-z0-9' . preg_quote('/', '#') . ']+#i', '-'), 'StringToLower'), + )) + ->setStaticRuleReference('suffix', $this->_viewSuffix) + ->setTargetReference($this->_inflectorTarget); + } + + // Ensure that module directory is current + $this->getModuleDirectory(); + + return $this->_inflector; + } + + /** + * Set inflector + * + * @param Zend_Filter_Inflector $inflector + * @param boolean $reference Whether the moduleDir, target, and suffix should be set as references to ViewRenderer properties + * @return Zend_Controller_Action_Helper_ViewRenderer Provides a fluent interface + */ + public function setInflector(Zend_Filter_Inflector $inflector, $reference = false) + { + $this->_inflector = $inflector; + if ($reference) { + $this->_inflector->setStaticRuleReference('suffix', $this->_viewSuffix) + ->setStaticRuleReference('moduleDir', $this->_moduleDir) + ->setTargetReference($this->_inflectorTarget); + } + return $this; + } + + /** + * Set inflector target + * + * @param string $target + * @return void + */ + protected function _setInflectorTarget($target) + { + $this->_inflectorTarget = (string) $target; + } + + /** + * Set internal module directory representation + * + * @param string $dir + * @return void + */ + protected function _setModuleDir($dir) + { + $this->_moduleDir = (string) $dir; + } + + /** + * Get internal module directory representation + * + * @return string + */ + protected function _getModuleDir() + { + return $this->_moduleDir; + } + + /** + * Generate a class prefix for helper and filter classes + * + * @return string + */ + protected function _generateDefaultPrefix() + { + $default = 'Zend_View'; + if (null === $this->_actionController) { + return $default; + } + + $class = get_class($this->_actionController); + + if (!strstr($class, '_')) { + return $default; + } + + $module = $this->getModule(); + if ('default' == $module) { + return $default; + } + + $prefix = substr($class, 0, strpos($class, '_')) . '_View'; + + return $prefix; + } + + /** + * Retrieve base path based on location of current action controller + * + * @return string + */ + protected function _getBasePath() + { + if (null === $this->_actionController) { + return './views'; + } + + $inflector = $this->getInflector(); + $this->_setInflectorTarget($this->getViewBasePathSpec()); + + $dispatcher = $this->getFrontController()->getDispatcher(); + $request = $this->getRequest(); + + $parts = array( + 'module' => (($moduleName = $request->getModuleName()) != '') ? $dispatcher->formatModuleName($moduleName) : $moduleName, + 'controller' => $request->getControllerName(), + 'action' => $dispatcher->formatActionName($request->getActionName()) + ); + + $path = $inflector->filter($parts); + return $path; + } + + /** + * Set options + * + * @param array $options + * @return Zend_Controller_Action_Helper_ViewRenderer Provides a fluent interface + */ + protected function _setOptions(array $options) + { + foreach ($options as $key => $value) + { + switch ($key) { + case 'neverRender': + case 'neverController': + case 'noController': + case 'noRender': + $property = '_' . $key; + $this->{$property} = ($value) ? true : false; + break; + case 'responseSegment': + case 'scriptAction': + case 'viewBasePathSpec': + case 'viewScriptPathSpec': + case 'viewScriptPathNoControllerSpec': + case 'viewSuffix': + $property = '_' . $key; + $this->{$property} = (string) $value; + break; + default: + break; + } + } + + return $this; + } + + /** + * Initialize the view object + * + * $options may contain the following keys: + * - neverRender - flag dis/enabling postDispatch() autorender (affects all subsequent calls) + * - noController - flag indicating whether or not to look for view scripts in subdirectories named after the controller + * - noRender - flag indicating whether or not to autorender postDispatch() + * - responseSegment - which named response segment to render a view script to + * - scriptAction - what action script to render + * - viewBasePathSpec - specification to use for determining view base path + * - viewScriptPathSpec - specification to use for determining view script paths + * - viewScriptPathNoControllerSpec - specification to use for determining view script paths when noController flag is set + * - viewSuffix - what view script filename suffix to use + * + * @param string $path + * @param string $prefix + * @param array $options + * @throws Zend_Controller_Action_Exception + * @return void + */ + public function initView($path = null, $prefix = null, array $options = array()) + { + if (null === $this->view) { + $this->setView(new Zend_View()); + } + + // Reset some flags every time + $options['noController'] = (isset($options['noController'])) ? $options['noController'] : false; + $options['noRender'] = (isset($options['noRender'])) ? $options['noRender'] : false; + $this->_scriptAction = null; + $this->_responseSegment = null; + + // Set options first; may be used to determine other initializations + $this->_setOptions($options); + + // Get base view path + if (empty($path)) { + $path = $this->_getBasePath(); + if (empty($path)) { + /** + * @see Zend_Controller_Action_Exception + */ + throw new Zend_Controller_Action_Exception('ViewRenderer initialization failed: retrieved view base path is empty'); + } + } + + if (null === $prefix) { + $prefix = $this->_generateDefaultPrefix(); + } + + // Determine if this path has already been registered + $currentPaths = $this->view->getScriptPaths(); + $path = str_replace(array('/', '\\'), '/', $path); + $pathExists = false; + foreach ($currentPaths as $tmpPath) { + $tmpPath = str_replace(array('/', '\\'), '/', $tmpPath); + if (strstr($tmpPath, $path)) { + $pathExists = true; + break; + } + } + if (!$pathExists) { + $this->view->addBasePath($path, $prefix); + } + + // Register view with action controller (unless already registered) + if ((null !== $this->_actionController) && (null === $this->_actionController->view)) { + $this->_actionController->view = $this->view; + $this->_actionController->viewSuffix = $this->_viewSuffix; + } + } + + /** + * init - initialize view + * + * @return void + */ + public function init() + { + if ($this->getFrontController()->getParam('noViewRenderer')) { + return; + } + + $this->initView(); + } + + /** + * Set view basePath specification + * + * Specification can contain one or more of the following: + * - :moduleDir - current module directory + * - :controller - name of current controller in the request + * - :action - name of current action in the request + * - :module - name of current module in the request + * + * @param string $path + * @return Zend_Controller_Action_Helper_ViewRenderer Provides a fluent interface + */ + public function setViewBasePathSpec($path) + { + $this->_viewBasePathSpec = (string) $path; + return $this; + } + + /** + * Retrieve the current view basePath specification string + * + * @return string + */ + public function getViewBasePathSpec() + { + return $this->_viewBasePathSpec; + } + + /** + * Set view script path specification + * + * Specification can contain one or more of the following: + * - :moduleDir - current module directory + * - :controller - name of current controller in the request + * - :action - name of current action in the request + * - :module - name of current module in the request + * + * @param string $path + * @return Zend_Controller_Action_Helper_ViewRenderer Provides a fluent interface + */ + public function setViewScriptPathSpec($path) + { + $this->_viewScriptPathSpec = (string) $path; + return $this; + } + + /** + * Retrieve the current view script path specification string + * + * @return string + */ + public function getViewScriptPathSpec() + { + return $this->_viewScriptPathSpec; + } + + /** + * Set view script path specification (no controller variant) + * + * Specification can contain one or more of the following: + * - :moduleDir - current module directory + * - :controller - name of current controller in the request + * - :action - name of current action in the request + * - :module - name of current module in the request + * + * :controller will likely be ignored in this variant. + * + * @param string $path + * @return Zend_Controller_Action_Helper_ViewRenderer Provides a fluent interface + */ + public function setViewScriptPathNoControllerSpec($path) + { + $this->_viewScriptPathNoControllerSpec = (string) $path; + return $this; + } + + /** + * Retrieve the current view script path specification string (no controller variant) + * + * @return string + */ + public function getViewScriptPathNoControllerSpec() + { + return $this->_viewScriptPathNoControllerSpec; + } + + /** + * Get a view script based on an action and/or other variables + * + * Uses values found in current request if no values passed in $vars. + * + * If {@link $_noController} is set, uses {@link $_viewScriptPathNoControllerSpec}; + * otherwise, uses {@link $_viewScriptPathSpec}. + * + * @param string $action + * @param array $vars + * @return string + */ + public function getViewScript($action = null, array $vars = array()) + { + $request = $this->getRequest(); + if ((null === $action) && (!isset($vars['action']))) { + $action = $this->getScriptAction(); + if (null === $action) { + $action = $request->getActionName(); + } + $vars['action'] = $action; + } elseif (null !== $action) { + $vars['action'] = $action; + } + + $replacePattern = array('/[^a-z0-9]+$/i', '/^[^a-z0-9]+/i'); + $vars['action'] = preg_replace($replacePattern, '', $vars['action']); + + $inflector = $this->getInflector(); + if ($this->getNoController() || $this->getNeverController()) { + $this->_setInflectorTarget($this->getViewScriptPathNoControllerSpec()); + } else { + $this->_setInflectorTarget($this->getViewScriptPathSpec()); + } + return $this->_translateSpec($vars); + } + + /** + * Set the neverRender flag (i.e., globally dis/enable autorendering) + * + * @param boolean $flag + * @return Zend_Controller_Action_Helper_ViewRenderer Provides a fluent interface + */ + public function setNeverRender($flag = true) + { + $this->_neverRender = ($flag) ? true : false; + return $this; + } + + /** + * Retrieve neverRender flag value + * + * @return boolean + */ + public function getNeverRender() + { + return $this->_neverRender; + } + + /** + * Set the noRender flag (i.e., whether or not to autorender) + * + * @param boolean $flag + * @return Zend_Controller_Action_Helper_ViewRenderer Provides a fluent interface + */ + public function setNoRender($flag = true) + { + $this->_noRender = ($flag) ? true : false; + return $this; + } + + /** + * Retrieve noRender flag value + * + * @return boolean + */ + public function getNoRender() + { + return $this->_noRender; + } + + /** + * Set the view script to use + * + * @param string $name + * @return Zend_Controller_Action_Helper_ViewRenderer Provides a fluent interface + */ + public function setScriptAction($name) + { + $this->_scriptAction = (string) $name; + return $this; + } + + /** + * Retrieve view script name + * + * @return string + */ + public function getScriptAction() + { + return $this->_scriptAction; + } + + /** + * Set the response segment name + * + * @param string $name + * @return Zend_Controller_Action_Helper_ViewRenderer Provides a fluent interface + */ + public function setResponseSegment($name) + { + if (null === $name) { + $this->_responseSegment = null; + } else { + $this->_responseSegment = (string) $name; + } + + return $this; + } + + /** + * Retrieve named response segment name + * + * @return string + */ + public function getResponseSegment() + { + return $this->_responseSegment; + } + + /** + * Set the noController flag (i.e., whether or not to render into controller subdirectories) + * + * @param boolean $flag + * @return Zend_Controller_Action_Helper_ViewRenderer Provides a fluent interface + */ + public function setNoController($flag = true) + { + $this->_noController = ($flag) ? true : false; + return $this; + } + + /** + * Retrieve noController flag value + * + * @return boolean + */ + public function getNoController() + { + return $this->_noController; + } + + /** + * Set the neverController flag (i.e., whether or not to render into controller subdirectories) + * + * @param boolean $flag + * @return Zend_Controller_Action_Helper_ViewRenderer Provides a fluent interface + */ + public function setNeverController($flag = true) + { + $this->_neverController = ($flag) ? true : false; + return $this; + } + + /** + * Retrieve neverController flag value + * + * @return boolean + */ + public function getNeverController() + { + return $this->_neverController; + } + + /** + * Set view script suffix + * + * @param string $suffix + * @return Zend_Controller_Action_Helper_ViewRenderer Provides a fluent interface + */ + public function setViewSuffix($suffix) + { + $this->_viewSuffix = (string) $suffix; + return $this; + } + + /** + * Get view script suffix + * + * @return string + */ + public function getViewSuffix() + { + return $this->_viewSuffix; + } + + /** + * Set options for rendering a view script + * + * @param string $action View script to render + * @param string $name Response named segment to render to + * @param boolean $noController Whether or not to render within a subdirectory named after the controller + * @return Zend_Controller_Action_Helper_ViewRenderer Provides a fluent interface + */ + public function setRender($action = null, $name = null, $noController = null) + { + if (null !== $action) { + $this->setScriptAction($action); + } + + if (null !== $name) { + $this->setResponseSegment($name); + } + + if (null !== $noController) { + $this->setNoController($noController); + } + + return $this; + } + + /** + * Inflect based on provided vars + * + * Allowed variables are: + * - :moduleDir - current module directory + * - :module - current module name + * - :controller - current controller name + * - :action - current action name + * - :suffix - view script file suffix + * + * @param array $vars + * @return string + */ + protected function _translateSpec(array $vars = array()) + { + $inflector = $this->getInflector(); + $request = $this->getRequest(); + $dispatcher = $this->getFrontController()->getDispatcher(); + + // Format module name + $module = $dispatcher->formatModuleName($request->getModuleName()); + + // Format controller name + $filter = new Zend_Filter_Word_CamelCaseToDash(); + $controller = $filter->filter($request->getControllerName()); + $controller = $dispatcher->formatControllerName($controller); + if ('Controller' == substr($controller, -10)) { + $controller = substr($controller, 0, -10); + } + + // Format action name + $action = $dispatcher->formatActionName($request->getActionName()); + + $params = compact('module', 'controller', 'action'); + foreach ($vars as $key => $value) { + switch ($key) { + case 'module': + case 'controller': + case 'action': + case 'moduleDir': + case 'suffix': + $params[$key] = (string) $value; + break; + default: + break; + } + } + + if (isset($params['suffix'])) { + $origSuffix = $this->getViewSuffix(); + $this->setViewSuffix($params['suffix']); + } + if (isset($params['moduleDir'])) { + $origModuleDir = $this->_getModuleDir(); + $this->_setModuleDir($params['moduleDir']); + } + + $filtered = $inflector->filter($params); + + if (isset($params['suffix'])) { + $this->setViewSuffix($origSuffix); + } + if (isset($params['moduleDir'])) { + $this->_setModuleDir($origModuleDir); + } + + return $filtered; + } + + /** + * Render a view script (optionally to a named response segment) + * + * Sets the noRender flag to true when called. + * + * @param string $script + * @param string $name + * @return void + */ + public function renderScript($script, $name = null) + { + if (null === $name) { + $name = $this->getResponseSegment(); + } + + $this->getResponse()->appendBody( + $this->view->render($script), + $name + ); + + $this->setNoRender(); + } + + /** + * Render a view based on path specifications + * + * Renders a view based on the view script path specifications. + * + * @param string $action + * @param string $name + * @param boolean $noController + * @return void + */ + public function render($action = null, $name = null, $noController = null) + { + $this->setRender($action, $name, $noController); + $path = $this->getViewScript(); + $this->renderScript($path, $name); + } + + /** + * Render a script based on specification variables + * + * Pass an action, and one or more specification variables (view script suffix) + * to determine the view script path, and render that script. + * + * @param string $action + * @param array $vars + * @param string $name + * @return void + */ + public function renderBySpec($action = null, array $vars = array(), $name = null) + { + if (null !== $name) { + $this->setResponseSegment($name); + } + + $path = $this->getViewScript($action, $vars); + + $this->renderScript($path); + } + + /** + * postDispatch - auto render a view + * + * Only autorenders if: + * - _noRender is false + * - action controller is present + * - request has not been re-dispatched (i.e., _forward() has not been called) + * - response is not a redirect + * + * @return void + */ + public function postDispatch() + { + if ($this->_shouldRender()) { + $this->render(); + } + } + + /** + * Should the ViewRenderer render a view script? + * + * @return boolean + */ + protected function _shouldRender() + { + return (!$this->getFrontController()->getParam('noViewRenderer') + && !$this->_neverRender + && !$this->_noRender + && (null !== $this->_actionController) + && $this->getRequest()->isDispatched() + && !$this->getResponse()->isRedirect() + ); + } + + /** + * Use this helper as a method; proxies to setRender() + * + * @param string $action + * @param string $name + * @param boolean $noController + * @return void + */ + public function direct($action = null, $name = null, $noController = null) + { + $this->setRender($action, $name, $noController); + } +} diff --git a/library/vendor/Zend/Controller/Action/HelperBroker.php b/library/vendor/Zend/Controller/Action/HelperBroker.php new file mode 100644 index 0000000..ff94dca --- /dev/null +++ b/library/vendor/Zend/Controller/Action/HelperBroker.php @@ -0,0 +1,373 @@ + 'Zend/Controller/Action/Helper/', + )); + } + return self::$_pluginLoader; + } + + /** + * addPrefix() - Add repository of helpers by prefix + * + * @param string $prefix + */ + static public function addPrefix($prefix) + { + $prefix = rtrim($prefix, '_'); + $path = str_replace('_', DIRECTORY_SEPARATOR, $prefix); + self::getPluginLoader()->addPrefixPath($prefix, $path); + } + + /** + * addPath() - Add path to repositories where Action_Helpers could be found. + * + * @param string $path + * @param string $prefix Optional; defaults to 'Zend_Controller_Action_Helper' + * @return void + */ + static public function addPath($path, $prefix = 'Zend_Controller_Action_Helper') + { + self::getPluginLoader()->addPrefixPath($prefix, $path); + } + + /** + * addHelper() - Add helper objects + * + * @param Zend_Controller_Action_Helper_Abstract $helper + * @return void + */ + static public function addHelper(Zend_Controller_Action_Helper_Abstract $helper) + { + self::getStack()->push($helper); + return; + } + + /** + * resetHelpers() + * + * @return void + */ + static public function resetHelpers() + { + self::$_stack = null; + return; + } + + /** + * Retrieve or initialize a helper statically + * + * Retrieves a helper object statically, loading on-demand if the helper + * does not already exist in the stack. Always returns a helper, unless + * the helper class cannot be found. + * + * @param string $name + * @return Zend_Controller_Action_Helper_Abstract + */ + public static function getStaticHelper($name) + { + $name = self::_normalizeHelperName($name); + $stack = self::getStack(); + + if (!isset($stack->{$name})) { + self::_loadHelper($name); + } + + return $stack->{$name}; + } + + /** + * getExistingHelper() - get helper by name + * + * Static method to retrieve helper object. Only retrieves helpers already + * initialized with the broker (either via addHelper() or on-demand loading + * via getHelper()). + * + * Throws an exception if the referenced helper does not exist in the + * stack; use {@link hasHelper()} to check if the helper is registered + * prior to retrieving it. + * + * @param string $name + * @return Zend_Controller_Action_Helper_Abstract + * @throws Zend_Controller_Action_Exception + */ + public static function getExistingHelper($name) + { + $name = self::_normalizeHelperName($name); + $stack = self::getStack(); + + if (!isset($stack->{$name})) { + throw new Zend_Controller_Action_Exception('Action helper "' . $name . '" has not been registered with the helper broker'); + } + + return $stack->{$name}; + } + + /** + * Return all registered helpers as helper => object pairs + * + * @return array + */ + public static function getExistingHelpers() + { + return self::getStack()->getHelpersByName(); + } + + /** + * Is a particular helper loaded in the broker? + * + * @param string $name + * @return boolean + */ + public static function hasHelper($name) + { + $name = self::_normalizeHelperName($name); + return isset(self::getStack()->{$name}); + } + + /** + * Remove a particular helper from the broker + * + * @param string $name + * @return boolean + */ + public static function removeHelper($name) + { + $name = self::_normalizeHelperName($name); + $stack = self::getStack(); + if (isset($stack->{$name})) { + unset($stack->{$name}); + } + + return false; + } + + /** + * Lazy load the priority stack and return it + * + * @return Zend_Controller_Action_HelperBroker_PriorityStack + */ + public static function getStack() + { + if (self::$_stack == null) { + self::$_stack = new Zend_Controller_Action_HelperBroker_PriorityStack(); + } + + return self::$_stack; + } + + /** + * Constructor + * + * @param Zend_Controller_Action $actionController + * @return void + */ + public function __construct(Zend_Controller_Action $actionController) + { + $this->_actionController = $actionController; + foreach (self::getStack() as $helper) { + $helper->setActionController($actionController); + $helper->init(); + } + } + + /** + * notifyPreDispatch() - called by action controller dispatch method + * + * @return void + */ + public function notifyPreDispatch() + { + foreach (self::getStack() as $helper) { + $helper->preDispatch(); + } + } + + /** + * notifyPostDispatch() - called by action controller dispatch method + * + * @return void + */ + public function notifyPostDispatch() + { + foreach (self::getStack() as $helper) { + $helper->postDispatch(); + } + } + + /** + * getHelper() - get helper by name + * + * @param string $name + * @return Zend_Controller_Action_Helper_Abstract + */ + public function getHelper($name) + { + $name = self::_normalizeHelperName($name); + $stack = self::getStack(); + + if (!isset($stack->{$name})) { + self::_loadHelper($name); + } + + $helper = $stack->{$name}; + + $initialize = false; + if (null === ($actionController = $helper->getActionController())) { + $initialize = true; + } elseif ($actionController !== $this->_actionController) { + $initialize = true; + } + + if ($initialize) { + $helper->setActionController($this->_actionController) + ->init(); + } + + return $helper; + } + + /** + * Method overloading + * + * @param string $method + * @param array $args + * @return mixed + * @throws Zend_Controller_Action_Exception if helper does not have a direct() method + */ + public function __call($method, $args) + { + $helper = $this->getHelper($method); + if (!method_exists($helper, 'direct')) { + throw new Zend_Controller_Action_Exception('Helper "' . $method . '" does not support overloading via direct()'); + } + return call_user_func_array(array($helper, 'direct'), $args); + } + + /** + * Retrieve helper by name as object property + * + * @param string $name + * @return Zend_Controller_Action_Helper_Abstract + */ + public function __get($name) + { + return $this->getHelper($name); + } + + /** + * Normalize helper name for lookups + * + * @param string $name + * @return string + */ + protected static function _normalizeHelperName($name) + { + if (strpos($name, '_') !== false) { + $name = str_replace(' ', '', ucwords(str_replace('_', ' ', $name))); + } + + return ucfirst($name); + } + + /** + * Load a helper + * + * @param string $name + * @return void + */ + protected static function _loadHelper($name) + { + try { + $class = self::getPluginLoader()->load($name); + } catch (Zend_Loader_PluginLoader_Exception $e) { + throw new Zend_Controller_Action_Exception('Action Helper by name ' . $name . ' not found', 0, $e); + } + + $helper = new $class(); + + if (!$helper instanceof Zend_Controller_Action_Helper_Abstract) { + throw new Zend_Controller_Action_Exception('Helper name ' . $name . ' -> class ' . $class . ' is not of type Zend_Controller_Action_Helper_Abstract'); + } + + self::getStack()->push($helper); + } +} diff --git a/library/vendor/Zend/Controller/Action/HelperBroker/PriorityStack.php b/library/vendor/Zend/Controller/Action/HelperBroker/PriorityStack.php new file mode 100644 index 0000000..c957b10 --- /dev/null +++ b/library/vendor/Zend/Controller/Action/HelperBroker/PriorityStack.php @@ -0,0 +1,272 @@ +_helpersByNameRef)) { + return false; + } + + return $this->_helpersByNameRef[$helperName]; + } + + /** + * Magic property overloading for returning if helper is set by name + * + * @param string $helperName The helper name + * @return Zend_Controller_Action_Helper_Abstract + */ + public function __isset($helperName) + { + return array_key_exists($helperName, $this->_helpersByNameRef); + } + + /** + * Magic property overloading for unsetting if helper is exists by name + * + * @param string $helperName The helper name + */ + public function __unset($helperName) + { + $this->offsetUnset($helperName); + } + + /** + * push helper onto the stack + * + * @param Zend_Controller_Action_Helper_Abstract $helper + * @return Zend_Controller_Action_HelperBroker_PriorityStack + */ + public function push(Zend_Controller_Action_Helper_Abstract $helper) + { + $this->offsetSet($this->getNextFreeHigherPriority(), $helper); + return $this; + } + + /** + * Return something iterable + * + * @return Traversable + */ + public function getIterator(): Traversable + { + return new ArrayObject($this->_helpersByPriority); + } + + /** + * offsetExists() + * + * @param int|string $priorityOrHelperName + * @return bool + */ + public function offsetExists($priorityOrHelperName): bool + { + if (is_string($priorityOrHelperName)) { + return array_key_exists($priorityOrHelperName, $this->_helpersByNameRef); + } else { + return array_key_exists($priorityOrHelperName, $this->_helpersByPriority); + } + } + + /** + * offsetGet() + * + * @param int|string $priorityOrHelperName + * @return Zend_Controller_Action_Helper_Abstract + */ + public function offsetGet($priorityOrHelperName): Zend_Controller_Action_Helper_Abstract + { + if (!$this->offsetExists($priorityOrHelperName)) { + throw new Zend_Controller_Action_Exception('A helper with priority ' . $priorityOrHelperName . ' does not exist.'); + } + + if (is_string($priorityOrHelperName)) { + return $this->_helpersByNameRef[$priorityOrHelperName]; + } else { + return $this->_helpersByPriority[$priorityOrHelperName]; + } + } + + /** + * offsetSet() + * + * @param int $priority + * @param Zend_Controller_Action_Helper_Abstract $helper + */ + public function offsetSet($priority, $helper): void + { + $priority = (int) $priority; + + if (!$helper instanceof Zend_Controller_Action_Helper_Abstract) { + throw new Zend_Controller_Action_Exception('$helper must extend Zend_Controller_Action_Helper_Abstract.'); + } + + if (array_key_exists($helper->getName(), $this->_helpersByNameRef)) { + // remove any object with the same name to retain BC compailitbility + // @todo At ZF 2.0 time throw an exception here. + $this->offsetUnset($helper->getName()); + } + + if (array_key_exists($priority, $this->_helpersByPriority)) { + $priority = $this->getNextFreeHigherPriority($priority); // ensures LIFO + trigger_error("A helper with the same priority already exists, reassigning to $priority", E_USER_WARNING); + } + + $this->_helpersByPriority[$priority] = $helper; + $this->_helpersByNameRef[$helper->getName()] = $helper; + + if ($priority == ($nextFreeDefault = $this->getNextFreeHigherPriority($this->_nextDefaultPriority))) { + $this->_nextDefaultPriority = $nextFreeDefault; + } + + krsort($this->_helpersByPriority); // always make sure priority and LIFO are both enforced + } + + /** + * offsetUnset() + * + * @param int|string $priorityOrHelperName Priority integer or the helper name + */ + public function offsetUnset($priorityOrHelperName): void + { + if (!$this->offsetExists($priorityOrHelperName)) { + throw new Zend_Controller_Action_Exception('A helper with priority or name ' . $priorityOrHelperName . ' does not exist.'); + } + + if (is_string($priorityOrHelperName)) { + $helperName = $priorityOrHelperName; + $helper = $this->_helpersByNameRef[$helperName]; + $priority = array_search($helper, $this->_helpersByPriority, true); + } else { + $priority = $priorityOrHelperName; + $helperName = $this->_helpersByPriority[$priorityOrHelperName]->getName(); + } + + unset($this->_helpersByNameRef[$helperName]); + unset($this->_helpersByPriority[$priority]); + } + + /** + * return the count of helpers + * + * @return int + */ + public function count(): int + { + return count($this->_helpersByPriority); + } + + /** + * Find the next free higher priority. If an index is given, it will + * find the next free highest priority after it. + * + * @param int $indexPriority OPTIONAL + * @return int + */ + public function getNextFreeHigherPriority($indexPriority = null) + { + if ($indexPriority == null) { + $indexPriority = $this->_nextDefaultPriority; + } + + $priorities = array_keys($this->_helpersByPriority); + + while (in_array($indexPriority, $priorities)) { + $indexPriority++; + } + + return $indexPriority; + } + + /** + * Find the next free lower priority. If an index is given, it will + * find the next free lower priority before it. + * + * @param int $indexPriority + * @return int + */ + public function getNextFreeLowerPriority($indexPriority = null) + { + if ($indexPriority == null) { + $indexPriority = $this->_nextDefaultPriority; + } + + $priorities = array_keys($this->_helpersByPriority); + + while (in_array($indexPriority, $priorities)) { + $indexPriority--; + } + + return $indexPriority; + } + + /** + * return the highest priority + * + * @return int + */ + public function getHighestPriority() + { + return max(array_keys($this->_helpersByPriority)); + } + + /** + * return the lowest priority + * + * @return int + */ + public function getLowestPriority() + { + return min(array_keys($this->_helpersByPriority)); + } + + /** + * return the helpers referenced by name + * + * @return array + */ + public function getHelpersByName() + { + return $this->_helpersByNameRef; + } + +} diff --git a/library/vendor/Zend/Controller/Action/Interface.php b/library/vendor/Zend/Controller/Action/Interface.php new file mode 100644 index 0000000..db35463 --- /dev/null +++ b/library/vendor/Zend/Controller/Action/Interface.php @@ -0,0 +1,69 @@ +setParams($params); + } + + /** + * Formats a string into a controller name. This is used to take a raw + * controller name, such as one stored inside a Zend_Controller_Request_Abstract + * object, and reformat it to a proper class name that a class extending + * Zend_Controller_Action would use. + * + * @param string $unformatted + * @return string + */ + public function formatControllerName($unformatted) + { + return ucfirst($this->_formatName($unformatted)) . 'Controller'; + } + + /** + * Formats a string into an action name. This is used to take a raw + * action name, such as one that would be stored inside a Zend_Controller_Request_Abstract + * object, and reformat into a proper method name that would be found + * inside a class extending Zend_Controller_Action. + * + * @param string $unformatted + * @return string + */ + public function formatActionName($unformatted) + { + $formatted = $this->_formatName($unformatted, true); + return strtolower(substr($formatted, 0, 1)) . substr($formatted, 1) . 'Action'; + } + + /** + * Verify delimiter + * + * Verify a delimiter to use in controllers or actions. May be a single + * string or an array of strings. + * + * @param string|array $spec + * @return array + * @throws Zend_Controller_Dispatcher_Exception with invalid delimiters + */ + public function _verifyDelimiter($spec) + { + if (is_string($spec)) { + return (array) $spec; + } elseif (is_array($spec)) { + $allStrings = true; + foreach ($spec as $delim) { + if (!is_string($delim)) { + $allStrings = false; + break; + } + } + + if (!$allStrings) { + throw new Zend_Controller_Dispatcher_Exception('Word delimiter array must contain only strings'); + } + + return $spec; + } + + throw new Zend_Controller_Dispatcher_Exception('Invalid word delimiter'); + } + + /** + * Retrieve the word delimiter character(s) used in + * controller or action names + * + * @return array + */ + public function getWordDelimiter() + { + return $this->_wordDelimiter; + } + + /** + * Set word delimiter + * + * Set the word delimiter to use in controllers and actions. May be a + * single string or an array of strings. + * + * @param string|array $spec + * @return Zend_Controller_Dispatcher_Abstract + */ + public function setWordDelimiter($spec) + { + $spec = $this->_verifyDelimiter($spec); + $this->_wordDelimiter = $spec; + + return $this; + } + + /** + * Retrieve the path delimiter character(s) used in + * controller names + * + * @return array + */ + public function getPathDelimiter() + { + return $this->_pathDelimiter; + } + + /** + * Set path delimiter + * + * Set the path delimiter to use in controllers. May be a single string or + * an array of strings. + * + * @param string $spec + * @return Zend_Controller_Dispatcher_Abstract + */ + public function setPathDelimiter($spec) + { + if (!is_string($spec)) { + throw new Zend_Controller_Dispatcher_Exception('Invalid path delimiter'); + } + $this->_pathDelimiter = $spec; + + return $this; + } + + /** + * Formats a string from a URI into a PHP-friendly name. + * + * By default, replaces words separated by the word separator character(s) + * with camelCaps. If $isAction is false, it also preserves replaces words + * separated by the path separation character with an underscore, making + * the following word Title cased. All non-alphanumeric characters are + * removed. + * + * @param string $unformatted + * @param boolean $isAction Defaults to false + * @return string + */ + protected function _formatName($unformatted, $isAction = false) + { + // preserve directories + if (!$isAction) { + $segments = explode($this->getPathDelimiter(), $unformatted); + } else { + $segments = (array) $unformatted; + } + + foreach ($segments as $key => $segment) { + $segment = str_replace($this->getWordDelimiter(), ' ', strtolower($segment)); + $segment = preg_replace('/[^a-z0-9 ]/', '', $segment); + $segments[$key] = str_replace(' ', '', ucwords($segment)); + } + + return implode('_', $segments); + } + + /** + * Retrieve front controller instance + * + * @return Zend_Controller_Front + */ + public function getFrontController() + { + if (null === $this->_frontController) { + $this->_frontController = Zend_Controller_Front::getInstance(); + } + + return $this->_frontController; + } + + /** + * Set front controller instance + * + * @param Zend_Controller_Front $controller + * @return Zend_Controller_Dispatcher_Abstract + */ + public function setFrontController(Zend_Controller_Front $controller) + { + $this->_frontController = $controller; + return $this; + } + + /** + * Add or modify a parameter to use when instantiating an action controller + * + * @param string $name + * @param mixed $value + * @return Zend_Controller_Dispatcher_Abstract + */ + public function setParam($name, $value) + { + $name = (string) $name; + $this->_invokeParams[$name] = $value; + return $this; + } + + /** + * Set parameters to pass to action controller constructors + * + * @param array $params + * @return Zend_Controller_Dispatcher_Abstract + */ + public function setParams(array $params) + { + $this->_invokeParams = array_merge($this->_invokeParams, $params); + return $this; + } + + /** + * Retrieve a single parameter from the controller parameter stack + * + * @param string $name + * @return mixed + */ + public function getParam($name) + { + if(isset($this->_invokeParams[$name])) { + return $this->_invokeParams[$name]; + } + + return null; + } + + /** + * Retrieve action controller instantiation parameters + * + * @return array + */ + public function getParams() + { + return $this->_invokeParams; + } + + /** + * Clear the controller parameter stack + * + * By default, clears all parameters. If a parameter name is given, clears + * only that parameter; if an array of parameter names is provided, clears + * each. + * + * @param null|string|array single key or array of keys for params to clear + * @return Zend_Controller_Dispatcher_Abstract + */ + public function clearParams($name = null) + { + if (null === $name) { + $this->_invokeParams = array(); + } elseif (is_string($name) && isset($this->_invokeParams[$name])) { + unset($this->_invokeParams[$name]); + } elseif (is_array($name)) { + foreach ($name as $key) { + if (is_string($key) && isset($this->_invokeParams[$key])) { + unset($this->_invokeParams[$key]); + } + } + } + + return $this; + } + + /** + * Set response object to pass to action controllers + * + * @param Zend_Controller_Response_Abstract|null $response + * @return Zend_Controller_Dispatcher_Abstract + */ + public function setResponse(Zend_Controller_Response_Abstract $response = null) + { + $this->_response = $response; + return $this; + } + + /** + * Return the registered response object + * + * @return Zend_Controller_Response_Abstract|null + */ + public function getResponse() + { + return $this->_response; + } + + /** + * Set the default controller (minus any formatting) + * + * @param string $controller + * @return Zend_Controller_Dispatcher_Abstract + */ + public function setDefaultControllerName($controller) + { + $this->_defaultController = (string) $controller; + return $this; + } + + /** + * Retrieve the default controller name (minus formatting) + * + * @return string + */ + public function getDefaultControllerName() + { + return $this->_defaultController; + } + + /** + * Set the default action (minus any formatting) + * + * @param string $action + * @return Zend_Controller_Dispatcher_Abstract + */ + public function setDefaultAction($action) + { + $this->_defaultAction = (string) $action; + return $this; + } + + /** + * Retrieve the default action name (minus formatting) + * + * @return string + */ + public function getDefaultAction() + { + return $this->_defaultAction; + } + + /** + * Set the default module + * + * @param string $module + * @return Zend_Controller_Dispatcher_Abstract + */ + public function setDefaultModule($module) + { + $this->_defaultModule = (string) $module; + return $this; + } + + /** + * Retrieve the default module + * + * @return string + */ + public function getDefaultModule() + { + return $this->_defaultModule; + } +} diff --git a/library/vendor/Zend/Controller/Dispatcher/Exception.php b/library/vendor/Zend/Controller/Dispatcher/Exception.php new file mode 100644 index 0000000..298dfdb --- /dev/null +++ b/library/vendor/Zend/Controller/Dispatcher/Exception.php @@ -0,0 +1,36 @@ +_curModule = $this->getDefaultModule(); + } + + /** + * Add a single path to the controller directory stack + * + * @param string $path + * @param string $module + * @return Zend_Controller_Dispatcher_Standard + */ + public function addControllerDirectory($path, $module = null) + { + if (null === $module) { + $module = $this->_defaultModule; + } + + $module = (string) $module; + $path = rtrim((string) $path, '/\\'); + + $this->_controllerDirectory[$module] = $path; + return $this; + } + + /** + * Set controller directory + * + * @param array|string $directory + * @return Zend_Controller_Dispatcher_Standard + */ + public function setControllerDirectory($directory, $module = null) + { + $this->_controllerDirectory = array(); + + if (is_string($directory)) { + $this->addControllerDirectory($directory, $module); + } elseif (is_array($directory)) { + foreach ((array) $directory as $module => $path) { + $this->addControllerDirectory($path, $module); + } + } else { + throw new Zend_Controller_Exception('Controller directory spec must be either a string or an array'); + } + + return $this; + } + + /** + * Return the currently set directories for Zend_Controller_Action class + * lookup + * + * If a module is specified, returns just that directory. + * + * @param string $module Module name + * @return array|string Returns array of all directories by default, single + * module directory if module argument provided + */ + public function getControllerDirectory($module = null) + { + if (null === $module) { + return $this->_controllerDirectory; + } + + $module = (string) $module; + if (array_key_exists($module, $this->_controllerDirectory)) { + return $this->_controllerDirectory[$module]; + } + + return null; + } + + /** + * Remove a controller directory by module name + * + * @param string $module + * @return bool + */ + public function removeControllerDirectory($module) + { + $module = (string) $module; + if (array_key_exists($module, $this->_controllerDirectory)) { + unset($this->_controllerDirectory[$module]); + return true; + } + return false; + } + + /** + * Format the module name. + * + * @param string $unformatted + * @return string + */ + public function formatModuleName($unformatted) + { + if (($this->_defaultModule == $unformatted) && !$this->getParam('prefixDefaultModule')) { + return $unformatted; + } + + return ucfirst($this->_formatName($unformatted)); + } + + /** + * Format action class name + * + * @param string $moduleName Name of the current module + * @param string $className Name of the action class + * @return string Formatted class name + */ + public function formatClassName($moduleName, $className) + { + return $this->formatModuleName($moduleName) . '_' . $className; + } + + /** + * Convert a class name to a filename + * + * @param string $class + * @return string + */ + public function classToFilename($class) + { + return str_replace('_', DIRECTORY_SEPARATOR, $class) . '.php'; + } + + /** + * Returns TRUE if the Zend_Controller_Request_Abstract object can be + * dispatched to a controller. + * + * Use this method wisely. By default, the dispatcher will fall back to the + * default controller (either in the module specified or the global default) + * if a given controller does not exist. This method returning false does + * not necessarily indicate the dispatcher will not still dispatch the call. + * + * @param Zend_Controller_Request_Abstract $action + * @return boolean + */ + public function isDispatchable(Zend_Controller_Request_Abstract $request) + { + $className = $this->getControllerClass($request); + if (!$className) { + return false; + } + + $finalClass = $className; + if (($this->_defaultModule != $this->_curModule) + || $this->getParam('prefixDefaultModule')) + { + $finalClass = $this->formatClassName($this->_curModule, $className); + } + if (class_exists($finalClass, false)) { + return true; + } + + $fileSpec = $this->classToFilename($className); + $dispatchDir = $this->getDispatchDirectory(); + $test = $dispatchDir . DIRECTORY_SEPARATOR . $fileSpec; + return Zend_Loader::isReadable($test); + } + + /** + * Dispatch to a controller/action + * + * By default, if a controller is not dispatchable, dispatch() will throw + * an exception. If you wish to use the default controller instead, set the + * param 'useDefaultControllerAlways' via {@link setParam()}. + * + * @param Zend_Controller_Request_Abstract $request + * @param Zend_Controller_Response_Abstract $response + * @return void + * @throws Zend_Controller_Dispatcher_Exception + */ + public function dispatch(Zend_Controller_Request_Abstract $request, Zend_Controller_Response_Abstract $response) + { + $this->setResponse($response); + + /** + * Get controller class + */ + if (!$this->isDispatchable($request)) { + $controller = $request->getControllerName(); + if (!$this->getParam('useDefaultControllerAlways') && !empty($controller)) { + throw new Zend_Controller_Dispatcher_Exception('Invalid controller specified (' . $request->getControllerName() . ')'); + } + + $className = $this->getDefaultControllerClass($request); + } else { + $className = $this->getControllerClass($request); + if (!$className) { + $className = $this->getDefaultControllerClass($request); + } + } + + /** + * If we're in a module or prefixDefaultModule is on, we must add the module name + * prefix to the contents of $className, as getControllerClass does not do that automatically. + * We must keep a separate variable because modules are not strictly PSR-0: We need the no-module-prefix + * class name to do the class->file mapping, but the full class name to insantiate the controller + */ + $moduleClassName = $className; + if (($this->_defaultModule != $this->_curModule) + || $this->getParam('prefixDefaultModule')) + { + $moduleClassName = $this->formatClassName($this->_curModule, $className); + } + + /** + * Load the controller class file + */ + $className = $this->loadClass($className); + + /** + * Instantiate controller with request, response, and invocation + * arguments; throw exception if it's not an action controller + */ + $controller = new $moduleClassName($request, $this->getResponse(), $this->getParams()); + if (!($controller instanceof Zend_Controller_Action_Interface) && + !($controller instanceof Zend_Controller_Action)) { + throw new Zend_Controller_Dispatcher_Exception( + 'Controller "' . $moduleClassName . '" is not an instance of Zend_Controller_Action_Interface' + ); + } + + /** + * Retrieve the action name + */ + $action = $this->getActionMethod($request); + + /** + * Dispatch the method call + */ + $request->setDispatched(true); + + // by default, buffer output + $disableOb = $this->getParam('disableOutputBuffering'); + $obLevel = ob_get_level(); + if (empty($disableOb)) { + ob_start(); + } + + try { + $controller->dispatch($action); + } catch (Exception $e) { + // Clean output buffer on error + $curObLevel = ob_get_level(); + if ($curObLevel > $obLevel) { + do { + ob_get_clean(); + $curObLevel = ob_get_level(); + } while ($curObLevel > $obLevel); + } + throw $e; + } + + if (empty($disableOb)) { + $content = ob_get_clean(); + $response->appendBody($content); + } + + // Destroy the page controller instance and reflection objects + $controller = null; + } + + /** + * Load a controller class + * + * Attempts to load the controller class file from + * {@link getControllerDirectory()}. If the controller belongs to a + * module, looks for the module prefix to the controller class. + * + * @param string $className + * @return string Class name loaded + * @throws Zend_Controller_Dispatcher_Exception if class not loaded + */ + public function loadClass($className) + { + $finalClass = $className; + if (($this->_defaultModule != $this->_curModule) + || $this->getParam('prefixDefaultModule')) + { + $finalClass = $this->formatClassName($this->_curModule, $className); + } + if (class_exists($finalClass, false)) { + return $finalClass; + } + + $dispatchDir = $this->getDispatchDirectory(); + $loadFile = $dispatchDir . DIRECTORY_SEPARATOR . $this->classToFilename($className); + + if (Zend_Loader::isReadable($loadFile)) { + include_once $loadFile; + } else { + throw new Zend_Controller_Dispatcher_Exception('Cannot load controller class "' . $className . '" from file "' . $loadFile . "'"); + } + + if (!class_exists($finalClass, false)) { + throw new Zend_Controller_Dispatcher_Exception('Invalid controller class ("' . $finalClass . '")'); + } + + return $finalClass; + } + + /** + * Get controller class name + * + * Try request first; if not found, try pulling from request parameter; + * if still not found, fallback to default + * + * @param Zend_Controller_Request_Abstract $request + * @return string|false Returns class name on success + */ + public function getControllerClass(Zend_Controller_Request_Abstract $request) + { + $controllerName = $request->getControllerName(); + if (empty($controllerName)) { + if (!$this->getParam('useDefaultControllerAlways')) { + return false; + } + $controllerName = $this->getDefaultControllerName(); + $request->setControllerName($controllerName); + } + + $className = $this->formatControllerName($controllerName); + + $controllerDirs = $this->getControllerDirectory(); + $module = $request->getModuleName(); + if ($this->isValidModule($module)) { + $this->_curModule = $module; + $this->_curDirectory = $controllerDirs[$module]; + } elseif ($this->isValidModule($this->_defaultModule)) { + $request->setModuleName($this->_defaultModule); + $this->_curModule = $this->_defaultModule; + $this->_curDirectory = $controllerDirs[$this->_defaultModule]; + } else { + throw new Zend_Controller_Exception('No default module defined for this application'); + } + + return $className; + } + + /** + * Determine if a given module is valid + * + * @param string $module + * @return bool + */ + public function isValidModule($module) + { + if (!is_string($module)) { + return false; + } + + $module = strtolower($module); + $controllerDir = $this->getControllerDirectory(); + foreach (array_keys($controllerDir) as $moduleName) { + if ($module == strtolower($moduleName)) { + return true; + } + } + + return false; + } + + /** + * Retrieve default controller class + * + * Determines whether the default controller to use lies within the + * requested module, or if the global default should be used. + * + * By default, will only use the module default unless that controller does + * not exist; if this is the case, it falls back to the default controller + * in the default module. + * + * @param Zend_Controller_Request_Abstract $request + * @return string + */ + public function getDefaultControllerClass(Zend_Controller_Request_Abstract $request) + { + $controller = $this->getDefaultControllerName(); + $default = $this->formatControllerName($controller); + $request->setControllerName($controller) + ->setActionName(null); + + $module = $request->getModuleName(); + $controllerDirs = $this->getControllerDirectory(); + $this->_curModule = $this->_defaultModule; + $this->_curDirectory = $controllerDirs[$this->_defaultModule]; + if ($this->isValidModule($module)) { + $found = false; + if (class_exists($default, false)) { + $found = true; + } else { + $moduleDir = $controllerDirs[$module]; + $fileSpec = $moduleDir . DIRECTORY_SEPARATOR . $this->classToFilename($default); + if (Zend_Loader::isReadable($fileSpec)) { + $found = true; + $this->_curDirectory = $moduleDir; + } + } + if ($found) { + $request->setModuleName($module); + $this->_curModule = $this->formatModuleName($module); + } + } else { + $request->setModuleName($this->_defaultModule); + } + + return $default; + } + + /** + * Return the value of the currently selected dispatch directory (as set by + * {@link getController()}) + * + * @return string + */ + public function getDispatchDirectory() + { + return $this->_curDirectory; + } + + /** + * Determine the action name + * + * First attempt to retrieve from request; then from request params + * using action key; default to default action + * + * Returns formatted action name + * + * @param Zend_Controller_Request_Abstract $request + * @return string + */ + public function getActionMethod(Zend_Controller_Request_Abstract $request) + { + $action = $request->getActionName(); + if (empty($action)) { + $action = $this->getDefaultAction(); + $request->setActionName($action); + } + + return $this->formatActionName($action); + } +} diff --git a/library/vendor/Zend/Controller/Exception.php b/library/vendor/Zend/Controller/Exception.php new file mode 100644 index 0000000..861289f --- /dev/null +++ b/library/vendor/Zend/Controller/Exception.php @@ -0,0 +1,34 @@ +_plugins = new Zend_Controller_Plugin_Broker(); + } + + /** + * Enforce singleton; disallow cloning + * + * @return void + */ + private function __clone() + { + } + + /** + * Singleton instance + * + * @return Zend_Controller_Front + */ + public static function getInstance() + { + if (null === self::$_instance) { + self::$_instance = new self(); + } + + return self::$_instance; + } + + /** + * Resets all object properties of the singleton instance + * + * Primarily used for testing; could be used to chain front controllers. + * + * Also resets action helper broker, clearing all registered helpers. + * + * @return void + */ + public function resetInstance() + { + $reflection = new ReflectionObject($this); + foreach ($reflection->getProperties() as $property) { + $name = $property->getName(); + switch ($name) { + case '_instance': + break; + case '_controllerDir': + case '_invokeParams': + $this->{$name} = array(); + break; + case '_plugins': + $this->{$name} = new Zend_Controller_Plugin_Broker(); + break; + case '_throwExceptions': + case '_returnResponse': + $this->{$name} = false; + break; + case '_moduleControllerDirectoryName': + $this->{$name} = 'controllers'; + break; + default: + $this->{$name} = null; + break; + } + } + Zend_Controller_Action_HelperBroker::resetHelpers(); + } + + /** + * Convenience feature, calls setControllerDirectory()->setRouter()->dispatch() + * + * In PHP 5.1.x, a call to a static method never populates $this -- so run() + * may actually be called after setting up your front controller. + * + * @param string|array $controllerDirectory Path to Zend_Controller_Action + * controller classes or array of such paths + * @return void + * @throws Zend_Controller_Exception if called from an object instance + */ + public static function run($controllerDirectory) + { + self::getInstance() + ->setControllerDirectory($controllerDirectory) + ->dispatch(); + } + + /** + * Add a controller directory to the controller directory stack + * + * If $args is presented and is a string, uses it for the array key mapping + * to the directory specified. + * + * @param string $directory + * @param string $module Optional argument; module with which to associate directory. If none provided, assumes 'default' + * @return Zend_Controller_Front + * @throws Zend_Controller_Exception if directory not found or readable + */ + public function addControllerDirectory($directory, $module = null) + { + $this->getDispatcher()->addControllerDirectory($directory, $module); + return $this; + } + + /** + * Set controller directory + * + * Stores controller directory(ies) in dispatcher. May be an array of + * directories or a string containing a single directory. + * + * @param string|array $directory Path to Zend_Controller_Action controller + * classes or array of such paths + * @param string $module Optional module name to use with string $directory + * @return Zend_Controller_Front + */ + public function setControllerDirectory($directory, $module = null) + { + $this->getDispatcher()->setControllerDirectory($directory, $module); + return $this; + } + + /** + * Retrieve controller directory + * + * Retrieves: + * - Array of all controller directories if no $name passed + * - String path if $name passed and exists as a key in controller directory array + * - null if $name passed but does not exist in controller directory keys + * + * @param string $name Default null + * @return array|string|null + */ + public function getControllerDirectory($name = null) + { + return $this->getDispatcher()->getControllerDirectory($name); + } + + /** + * Remove a controller directory by module name + * + * @param string $module + * @return bool + */ + public function removeControllerDirectory($module) + { + return $this->getDispatcher()->removeControllerDirectory($module); + } + + /** + * Specify a directory as containing modules + * + * Iterates through the directory, adding any subdirectories as modules; + * the subdirectory within each module named after {@link $_moduleControllerDirectoryName} + * will be used as the controller directory path. + * + * @param string $path + * @return Zend_Controller_Front + */ + public function addModuleDirectory($path) + { + try{ + $dir = new DirectoryIterator($path); + } catch(Exception $e) { + throw new Zend_Controller_Exception("Directory $path not readable", 0, $e); + } + foreach ($dir as $file) { + if ($file->isDot() || !$file->isDir()) { + continue; + } + + $module = $file->getFilename(); + + // Don't use SCCS directories as modules + if (preg_match('/^[^a-z]/i', $module) || ('CVS' == $module)) { + continue; + } + + $moduleDir = $file->getPathname() . DIRECTORY_SEPARATOR . $this->getModuleControllerDirectoryName(); + $this->addControllerDirectory($moduleDir, $module); + } + + return $this; + } + + /** + * Return the path to a module directory (but not the controllers directory within) + * + * @param string $module + * @return string|null + */ + public function getModuleDirectory($module = null) + { + if (null === $module) { + $request = $this->getRequest(); + if (null !== $request) { + $module = $this->getRequest()->getModuleName(); + } + if (empty($module)) { + $module = $this->getDispatcher()->getDefaultModule(); + } + } + + $controllerDir = $this->getControllerDirectory($module); + + if ((null === $controllerDir) || !is_string($controllerDir)) { + return null; + } + + return dirname($controllerDir); + } + + /** + * Set the directory name within a module containing controllers + * + * @param string $name + * @return Zend_Controller_Front + */ + public function setModuleControllerDirectoryName($name = 'controllers') + { + $this->_moduleControllerDirectoryName = (string) $name; + + return $this; + } + + /** + * Return the directory name within a module containing controllers + * + * @return string + */ + public function getModuleControllerDirectoryName() + { + return $this->_moduleControllerDirectoryName; + } + + /** + * Set the default controller (unformatted string) + * + * @param string $controller + * @return Zend_Controller_Front + */ + public function setDefaultControllerName($controller) + { + $dispatcher = $this->getDispatcher(); + $dispatcher->setDefaultControllerName($controller); + return $this; + } + + /** + * Retrieve the default controller (unformatted string) + * + * @return string + */ + public function getDefaultControllerName() + { + return $this->getDispatcher()->getDefaultControllerName(); + } + + /** + * Set the default action (unformatted string) + * + * @param string $action + * @return Zend_Controller_Front + */ + public function setDefaultAction($action) + { + $dispatcher = $this->getDispatcher(); + $dispatcher->setDefaultAction($action); + return $this; + } + + /** + * Retrieve the default action (unformatted string) + * + * @return string + */ + public function getDefaultAction() + { + return $this->getDispatcher()->getDefaultAction(); + } + + /** + * Set the default module name + * + * @param string $module + * @return Zend_Controller_Front + */ + public function setDefaultModule($module) + { + $dispatcher = $this->getDispatcher(); + $dispatcher->setDefaultModule($module); + return $this; + } + + /** + * Retrieve the default module + * + * @return string + */ + public function getDefaultModule() + { + return $this->getDispatcher()->getDefaultModule(); + } + + /** + * Set request class/object + * + * Set the request object. The request holds the request environment. + * + * If a class name is provided, it will instantiate it + * + * @param string|Zend_Controller_Request_Abstract $request + * @throws Zend_Controller_Exception if invalid request class + * @return Zend_Controller_Front + */ + public function setRequest($request) + { + if (is_string($request)) { + if (!class_exists($request)) { + Zend_Loader::loadClass($request); + } + $request = new $request(); + } + if (!$request instanceof Zend_Controller_Request_Abstract) { + throw new Zend_Controller_Exception('Invalid request class'); + } + + $this->_request = $request; + + return $this; + } + + /** + * Return the request object. + * + * @return null|Zend_Controller_Request_Abstract + */ + public function getRequest() + { + return $this->_request; + } + + /** + * Set router class/object + * + * Set the router object. The router is responsible for mapping + * the request to a controller and action. + * + * If a class name is provided, instantiates router with any parameters + * registered via {@link setParam()} or {@link setParams()}. + * + * @param string|Zend_Controller_Router_Interface $router + * @throws Zend_Controller_Exception if invalid router class + * @return Zend_Controller_Front + */ + public function setRouter($router) + { + if (is_string($router)) { + if (!class_exists($router)) { + Zend_Loader::loadClass($router); + } + $router = new $router(); + } + + if (!$router instanceof Zend_Controller_Router_Interface) { + throw new Zend_Controller_Exception('Invalid router class'); + } + + $router->setFrontController($this); + $this->_router = $router; + + return $this; + } + + /** + * Return the router object. + * + * Instantiates a Zend_Controller_Router_Rewrite object if no router currently set. + * + * @return Zend_Controller_Router_Interface + */ + public function getRouter() + { + if (null == $this->_router) { + $this->setRouter(new Zend_Controller_Router_Rewrite()); + } + + return $this->_router; + } + + /** + * Set the base URL used for requests + * + * Use to set the base URL segment of the REQUEST_URI to use when + * determining PATH_INFO, etc. Examples: + * - /admin + * - /myapp + * - /subdir/index.php + * + * Note that the URL should not include the full URI. Do not use: + * - http://example.com/admin + * - http://example.com/myapp + * - http://example.com/subdir/index.php + * + * If a null value is passed, this can be used as well for autodiscovery (default). + * + * @param string $base + * @return Zend_Controller_Front + * @throws Zend_Controller_Exception for non-string $base + */ + public function setBaseUrl($base = null) + { + if (!is_string($base) && (null !== $base)) { + throw new Zend_Controller_Exception('Rewrite base must be a string'); + } + + $this->_baseUrl = $base; + + if ((null !== ($request = $this->getRequest())) && (method_exists($request, 'setBaseUrl'))) { + $request->setBaseUrl($base); + } + + return $this; + } + + /** + * Retrieve the currently set base URL + * + * @return string + */ + public function getBaseUrl() + { + $request = $this->getRequest(); + if ((null !== $request) && method_exists($request, 'getBaseUrl')) { + return $request->getBaseUrl(); + } + + return $this->_baseUrl; + } + + /** + * Set the dispatcher object. The dispatcher is responsible for + * taking a Zend_Controller_Dispatcher_Token object, instantiating the controller, and + * call the action method of the controller. + * + * @param Zend_Controller_Dispatcher_Interface $dispatcher + * @return Zend_Controller_Front + */ + public function setDispatcher(Zend_Controller_Dispatcher_Interface $dispatcher) + { + $this->_dispatcher = $dispatcher; + return $this; + } + + /** + * Return the dispatcher object. + * + * @return Zend_Controller_Dispatcher_Interface + */ + public function getDispatcher() + { + /** + * Instantiate the default dispatcher if one was not set. + */ + if (!$this->_dispatcher instanceof Zend_Controller_Dispatcher_Interface) { + $this->_dispatcher = new Zend_Controller_Dispatcher_Standard(); + } + return $this->_dispatcher; + } + + /** + * Set response class/object + * + * Set the response object. The response is a container for action + * responses and headers. Usage is optional. + * + * If a class name is provided, instantiates a response object. + * + * @param string|Zend_Controller_Response_Abstract $response + * @throws Zend_Controller_Exception if invalid response class + * @return Zend_Controller_Front + */ + public function setResponse($response) + { + if (is_string($response)) { + if (!class_exists($response)) { + Zend_Loader::loadClass($response); + } + $response = new $response(); + } + if (!$response instanceof Zend_Controller_Response_Abstract) { + throw new Zend_Controller_Exception('Invalid response class'); + } + + $this->_response = $response; + + return $this; + } + + /** + * Return the response object. + * + * @return null|Zend_Controller_Response_Abstract + */ + public function getResponse() + { + return $this->_response; + } + + /** + * Add or modify a parameter to use when instantiating an action controller + * + * @param string $name + * @param mixed $value + * @return Zend_Controller_Front + */ + public function setParam($name, $value) + { + $name = (string) $name; + $this->_invokeParams[$name] = $value; + return $this; + } + + /** + * Set parameters to pass to action controller constructors + * + * @param array $params + * @return Zend_Controller_Front + */ + public function setParams(array $params) + { + $this->_invokeParams = array_merge($this->_invokeParams, $params); + return $this; + } + + /** + * Retrieve a single parameter from the controller parameter stack + * + * @param string $name + * @return mixed + */ + public function getParam($name) + { + if(isset($this->_invokeParams[$name])) { + return $this->_invokeParams[$name]; + } + + return null; + } + + /** + * Retrieve action controller instantiation parameters + * + * @return array + */ + public function getParams() + { + return $this->_invokeParams; + } + + /** + * Clear the controller parameter stack + * + * By default, clears all parameters. If a parameter name is given, clears + * only that parameter; if an array of parameter names is provided, clears + * each. + * + * @param null|string|array single key or array of keys for params to clear + * @return Zend_Controller_Front + */ + public function clearParams($name = null) + { + if (null === $name) { + $this->_invokeParams = array(); + } elseif (is_string($name) && isset($this->_invokeParams[$name])) { + unset($this->_invokeParams[$name]); + } elseif (is_array($name)) { + foreach ($name as $key) { + if (is_string($key) && isset($this->_invokeParams[$key])) { + unset($this->_invokeParams[$key]); + } + } + } + + return $this; + } + + /** + * Register a plugin. + * + * @param Zend_Controller_Plugin_Abstract $plugin + * @param int $stackIndex Optional; stack index for plugin + * @return Zend_Controller_Front + */ + public function registerPlugin(Zend_Controller_Plugin_Abstract $plugin, $stackIndex = null) + { + $this->_plugins->registerPlugin($plugin, $stackIndex); + return $this; + } + + /** + * Unregister a plugin. + * + * @param string|Zend_Controller_Plugin_Abstract $plugin Plugin class or object to unregister + * @return Zend_Controller_Front + */ + public function unregisterPlugin($plugin) + { + $this->_plugins->unregisterPlugin($plugin); + return $this; + } + + /** + * Is a particular plugin registered? + * + * @param string $class + * @return bool + */ + public function hasPlugin($class) + { + return $this->_plugins->hasPlugin($class); + } + + /** + * Retrieve a plugin or plugins by class + * + * @param string $class + * @return false|Zend_Controller_Plugin_Abstract|array + */ + public function getPlugin($class) + { + return $this->_plugins->getPlugin($class); + } + + /** + * Retrieve all plugins + * + * @return array + */ + public function getPlugins() + { + return $this->_plugins->getPlugins(); + } + + /** + * Set the throwExceptions flag and retrieve current status + * + * Set whether exceptions encounted in the dispatch loop should be thrown + * or caught and trapped in the response object. + * + * Default behaviour is to trap them in the response object; call this + * method to have them thrown. + * + * Passing no value will return the current value of the flag; passing a + * boolean true or false value will set the flag and return the current + * object instance. + * + * @param boolean $flag Defaults to null (return flag state) + * @return boolean|Zend_Controller_Front Used as a setter, returns object; as a getter, returns boolean + */ + public function throwExceptions($flag = null) + { + if ($flag !== null) { + $this->_throwExceptions = (bool) $flag; + return $this; + } + + return $this->_throwExceptions; + } + + /** + * Set whether {@link dispatch()} should return the response without first + * rendering output. By default, output is rendered and dispatch() returns + * nothing. + * + * @param boolean $flag + * @return boolean|Zend_Controller_Front Used as a setter, returns object; as a getter, returns boolean + */ + public function returnResponse($flag = null) + { + if (true === $flag) { + $this->_returnResponse = true; + return $this; + } elseif (false === $flag) { + $this->_returnResponse = false; + return $this; + } + + return $this->_returnResponse; + } + + /** + * Dispatch an HTTP request to a controller/action. + * + * @param Zend_Controller_Request_Abstract|null $request + * @param Zend_Controller_Response_Abstract|null $response + * @return void|Zend_Controller_Response_Abstract Returns response object if returnResponse() is true + */ + public function dispatch(Zend_Controller_Request_Abstract $request = null, Zend_Controller_Response_Abstract $response = null) + { + if (!$this->getParam('noErrorHandler') && !$this->_plugins->hasPlugin('Zend_Controller_Plugin_ErrorHandler')) { + // Register with stack index of 100 + $this->_plugins->registerPlugin(new Zend_Controller_Plugin_ErrorHandler(), 100); + } + + if (!$this->getParam('noViewRenderer') && !Zend_Controller_Action_HelperBroker::hasHelper('viewRenderer')) { + Zend_Controller_Action_HelperBroker::getStack()->offsetSet(-80, new Zend_Controller_Action_Helper_ViewRenderer()); + } + + /** + * Instantiate default request object (HTTP version) if none provided + */ + if (null !== $request) { + $this->setRequest($request); + } elseif ((null === $request) && (null === ($request = $this->getRequest()))) { + $request = new Zend_Controller_Request_Http(); + $this->setRequest($request); + } + + /** + * Set base URL of request object, if available + */ + if (is_callable(array($this->_request, 'setBaseUrl'))) { + if (null !== $this->_baseUrl) { + $this->_request->setBaseUrl($this->_baseUrl); + } + } + + /** + * Instantiate default response object (HTTP version) if none provided + */ + if (null !== $response) { + $this->setResponse($response); + } elseif ((null === $this->_response) && (null === ($this->_response = $this->getResponse()))) { + $response = new Zend_Controller_Response_Http(); + $this->setResponse($response); + } + + /** + * Register request and response objects with plugin broker + */ + $this->_plugins + ->setRequest($this->_request) + ->setResponse($this->_response); + + /** + * Initialize router + */ + $router = $this->getRouter(); + $router->setParams($this->getParams()); + + /** + * Initialize dispatcher + */ + $dispatcher = $this->getDispatcher(); + $dispatcher->setParams($this->getParams()) + ->setResponse($this->_response); + + // Begin dispatch + try { + /** + * Route request to controller/action, if a router is provided + */ + + /** + * Notify plugins of router startup + */ + $this->_plugins->routeStartup($this->_request); + + try { + $router->route($this->_request); + } catch (Exception $e) { + if ($this->throwExceptions()) { + throw $e; + } + + $this->_response->setException($e); + } + + /** + * Notify plugins of router completion + */ + $this->_plugins->routeShutdown($this->_request); + + /** + * Notify plugins of dispatch loop startup + */ + $this->_plugins->dispatchLoopStartup($this->_request); + + /** + * Attempt to dispatch the controller/action. If the $this->_request + * indicates that it needs to be dispatched, move to the next + * action in the request. + */ + do { + $this->_request->setDispatched(true); + + /** + * Notify plugins of dispatch startup + */ + $this->_plugins->preDispatch($this->_request); + + /** + * Skip requested action if preDispatch() has reset it + */ + if (!$this->_request->isDispatched()) { + continue; + } + + /** + * Dispatch request + */ + try { + $dispatcher->dispatch($this->_request, $this->_response); + } catch (Exception $e) { + if ($this->throwExceptions()) { + throw $e; + } + $this->_response->setException($e); + } + + /** + * Notify plugins of dispatch completion + */ + $this->_plugins->postDispatch($this->_request); + } while (!$this->_request->isDispatched()); + } catch (Exception $e) { + if ($this->throwExceptions()) { + throw $e; + } + + $this->_response->setException($e); + } + + /** + * Notify plugins of dispatch loop completion + */ + try { + $this->_plugins->dispatchLoopShutdown(); + } catch (Exception $e) { + if ($this->throwExceptions()) { + throw $e; + } + + $this->_response->setException($e); + } + + if ($this->returnResponse()) { + return $this->_response; + } + + $this->_response->sendResponse(); + } +} diff --git a/library/vendor/Zend/Controller/Plugin/Abstract.php b/library/vendor/Zend/Controller/Plugin/Abstract.php new file mode 100644 index 0000000..7e590b7 --- /dev/null +++ b/library/vendor/Zend/Controller/Plugin/Abstract.php @@ -0,0 +1,151 @@ +_request = $request; + return $this; + } + + /** + * Get request object + * + * @return Zend_Controller_Request_Abstract $request + */ + public function getRequest() + { + return $this->_request; + } + + /** + * Set response object + * + * @param Zend_Controller_Response_Abstract $response + * @return Zend_Controller_Plugin_Abstract + */ + public function setResponse(Zend_Controller_Response_Abstract $response) + { + $this->_response = $response; + return $this; + } + + /** + * Get response object + * + * @return Zend_Controller_Response_Abstract $response + */ + public function getResponse() + { + return $this->_response; + } + + /** + * Called before Zend_Controller_Front begins evaluating the + * request against its routes. + * + * @param Zend_Controller_Request_Abstract $request + * @return void + */ + public function routeStartup(Zend_Controller_Request_Abstract $request) + {} + + /** + * Called after Zend_Controller_Router exits. + * + * Called after Zend_Controller_Front exits from the router. + * + * @param Zend_Controller_Request_Abstract $request + * @return void + */ + public function routeShutdown(Zend_Controller_Request_Abstract $request) + {} + + /** + * Called before Zend_Controller_Front enters its dispatch loop. + * + * @param Zend_Controller_Request_Abstract $request + * @return void + */ + public function dispatchLoopStartup(Zend_Controller_Request_Abstract $request) + {} + + /** + * Called before an action is dispatched by Zend_Controller_Dispatcher. + * + * This callback allows for proxy or filter behavior. By altering the + * request and resetting its dispatched flag (via + * {@link Zend_Controller_Request_Abstract::setDispatched() setDispatched(false)}), + * the current action may be skipped. + * + * @param Zend_Controller_Request_Abstract $request + * @return void + */ + public function preDispatch(Zend_Controller_Request_Abstract $request) + {} + + /** + * Called after an action is dispatched by Zend_Controller_Dispatcher. + * + * This callback allows for proxy or filter behavior. By altering the + * request and resetting its dispatched flag (via + * {@link Zend_Controller_Request_Abstract::setDispatched() setDispatched(false)}), + * a new action may be specified for dispatching. + * + * @param Zend_Controller_Request_Abstract $request + * @return void + */ + public function postDispatch(Zend_Controller_Request_Abstract $request) + {} + + /** + * Called before Zend_Controller_Front exits its dispatch loop. + * + * @return void + */ + public function dispatchLoopShutdown() + {} +} diff --git a/library/vendor/Zend/Controller/Plugin/ActionStack.php b/library/vendor/Zend/Controller/Plugin/ActionStack.php new file mode 100644 index 0000000..c654a6c --- /dev/null +++ b/library/vendor/Zend/Controller/Plugin/ActionStack.php @@ -0,0 +1,277 @@ +setRegistry($registry); + + if (null !== $key) { + $this->setRegistryKey($key); + } else { + $key = $this->getRegistryKey(); + } + + $registry[$key] = array(); + } + + /** + * Set registry object + * + * @param Zend_Registry $registry + * @return Zend_Controller_Plugin_ActionStack + */ + public function setRegistry(Zend_Registry $registry) + { + $this->_registry = $registry; + return $this; + } + + /** + * Retrieve registry object + * + * @return Zend_Registry + */ + public function getRegistry() + { + return $this->_registry; + } + + /** + * Retrieve registry key + * + * @return string + */ + public function getRegistryKey() + { + return $this->_registryKey; + } + + /** + * Set registry key + * + * @param string $key + * @return Zend_Controller_Plugin_ActionStack + */ + public function setRegistryKey($key) + { + $this->_registryKey = (string) $key; + return $this; + } + + /** + * Set clearRequestParams flag + * + * @param bool $clearRequestParams + * @return Zend_Controller_Plugin_ActionStack + */ + public function setClearRequestParams($clearRequestParams) + { + $this->_clearRequestParams = (bool) $clearRequestParams; + return $this; + } + + /** + * Retrieve clearRequestParams flag + * + * @return bool + */ + public function getClearRequestParams() + { + return $this->_clearRequestParams; + } + + /** + * Retrieve action stack + * + * @return array + */ + public function getStack() + { + $registry = $this->getRegistry(); + $stack = $registry[$this->getRegistryKey()]; + return $stack; + } + + /** + * Save stack to registry + * + * @param array $stack + * @return Zend_Controller_Plugin_ActionStack + */ + protected function _saveStack(array $stack) + { + $registry = $this->getRegistry(); + $registry[$this->getRegistryKey()] = $stack; + return $this; + } + + /** + * Push an item onto the stack + * + * @param Zend_Controller_Request_Abstract $next + * @return Zend_Controller_Plugin_ActionStack + */ + public function pushStack(Zend_Controller_Request_Abstract $next) + { + $stack = $this->getStack(); + array_push($stack, $next); + return $this->_saveStack($stack); + } + + /** + * Pop an item off the action stack + * + * @return false|Zend_Controller_Request_Abstract + */ + public function popStack() + { + $stack = $this->getStack(); + if (0 == count($stack)) { + return false; + } + + $next = array_pop($stack); + $this->_saveStack($stack); + + if (!$next instanceof Zend_Controller_Request_Abstract) { + throw new Zend_Controller_Exception('ArrayStack should only contain request objects'); + } + $action = $next->getActionName(); + if (empty($action)) { + return $this->popStack($stack); + } + + $request = $this->getRequest(); + $controller = $next->getControllerName(); + if (empty($controller)) { + $next->setControllerName($request->getControllerName()); + } + + $module = $next->getModuleName(); + if (empty($module)) { + $next->setModuleName($request->getModuleName()); + } + + return $next; + } + + /** + * postDispatch() plugin hook -- check for actions in stack, and dispatch if any found + * + * @param Zend_Controller_Request_Abstract $request + * @return void + */ + public function postDispatch(Zend_Controller_Request_Abstract $request) + { + // Don't move on to next request if this is already an attempt to + // forward + if (!$request->isDispatched()) { + return; + } + + $this->setRequest($request); + $stack = $this->getStack(); + if (empty($stack)) { + return; + } + $next = $this->popStack(); + if (!$next) { + return; + } + + $this->forward($next); + } + + /** + * Forward request with next action + * + * @param array $next + * @return void + */ + public function forward(Zend_Controller_Request_Abstract $next) + { + $request = $this->getRequest(); + if ($this->getClearRequestParams()) { + $request->clearParams(); + } + + $request->setModuleName($next->getModuleName()) + ->setControllerName($next->getControllerName()) + ->setActionName($next->getActionName()) + ->setParams($next->getParams()) + ->setDispatched(false); + } +} diff --git a/library/vendor/Zend/Controller/Plugin/Broker.php b/library/vendor/Zend/Controller/Plugin/Broker.php new file mode 100644 index 0000000..eec9809 --- /dev/null +++ b/library/vendor/Zend/Controller/Plugin/Broker.php @@ -0,0 +1,361 @@ +_plugins, true)) { + throw new Zend_Controller_Exception('Plugin already registered'); + } + + $stackIndex = (int) $stackIndex; + + if ($stackIndex) { + if (isset($this->_plugins[$stackIndex])) { + throw new Zend_Controller_Exception('Plugin with stackIndex "' . $stackIndex . '" already registered'); + } + $this->_plugins[$stackIndex] = $plugin; + } else { + $stackIndex = count($this->_plugins); + while (isset($this->_plugins[$stackIndex])) { + ++$stackIndex; + } + $this->_plugins[$stackIndex] = $plugin; + } + + $request = $this->getRequest(); + if ($request) { + $this->_plugins[$stackIndex]->setRequest($request); + } + $response = $this->getResponse(); + if ($response) { + $this->_plugins[$stackIndex]->setResponse($response); + } + + ksort($this->_plugins); + + return $this; + } + + /** + * Unregister a plugin. + * + * @param string|Zend_Controller_Plugin_Abstract $plugin Plugin object or class name + * @return Zend_Controller_Plugin_Broker + */ + public function unregisterPlugin($plugin) + { + if ($plugin instanceof Zend_Controller_Plugin_Abstract) { + // Given a plugin object, find it in the array + $key = array_search($plugin, $this->_plugins, true); + if (false === $key) { + throw new Zend_Controller_Exception('Plugin never registered.'); + } + unset($this->_plugins[$key]); + } elseif (is_string($plugin)) { + // Given a plugin class, find all plugins of that class and unset them + foreach ($this->_plugins as $key => $_plugin) { + $type = get_class($_plugin); + if ($plugin == $type) { + unset($this->_plugins[$key]); + } + } + } + return $this; + } + + /** + * Is a plugin of a particular class registered? + * + * @param string $class + * @return bool + */ + public function hasPlugin($class) + { + foreach ($this->_plugins as $plugin) { + $type = get_class($plugin); + if ($class == $type) { + return true; + } + } + + return false; + } + + /** + * Retrieve a plugin or plugins by class + * + * @param string $class Class name of plugin(s) desired + * @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 + */ + public function getPlugin($class) + { + $found = array(); + foreach ($this->_plugins as $plugin) { + $type = get_class($plugin); + if ($class == $type) { + $found[] = $plugin; + } + } + + switch (count($found)) { + case 0: + return false; + case 1: + return $found[0]; + default: + return $found; + } + } + + /** + * Retrieve all plugins + * + * @return array + */ + public function getPlugins() + { + return $this->_plugins; + } + + /** + * Set request object, and register with each plugin + * + * @param Zend_Controller_Request_Abstract $request + * @return Zend_Controller_Plugin_Broker + */ + public function setRequest(Zend_Controller_Request_Abstract $request) + { + $this->_request = $request; + + foreach ($this->_plugins as $plugin) { + $plugin->setRequest($request); + } + + return $this; + } + + /** + * Get request object + * + * @return Zend_Controller_Request_Abstract $request + */ + public function getRequest() + { + return $this->_request; + } + + /** + * Set response object + * + * @param Zend_Controller_Response_Abstract $response + * @return Zend_Controller_Plugin_Broker + */ + public function setResponse(Zend_Controller_Response_Abstract $response) + { + $this->_response = $response; + + foreach ($this->_plugins as $plugin) { + $plugin->setResponse($response); + } + + + return $this; + } + + /** + * Get response object + * + * @return Zend_Controller_Response_Abstract $response + */ + public function getResponse() + { + return $this->_response; + } + + + /** + * Called before Zend_Controller_Front begins evaluating the + * request against its routes. + * + * @param Zend_Controller_Request_Abstract $request + * @return void + */ + public function routeStartup(Zend_Controller_Request_Abstract $request) + { + foreach ($this->_plugins as $plugin) { + try { + $plugin->routeStartup($request); + } catch (Exception $e) { + if (Zend_Controller_Front::getInstance()->throwExceptions()) { + throw new Zend_Controller_Exception($e->getMessage() . $e->getTraceAsString(), $e->getCode(), $e); + } else { + $this->getResponse()->setException($e); + } + } + } + } + + + /** + * Called before Zend_Controller_Front exits its iterations over + * the route set. + * + * @param Zend_Controller_Request_Abstract $request + * @return void + */ + public function routeShutdown(Zend_Controller_Request_Abstract $request) + { + foreach ($this->_plugins as $plugin) { + try { + $plugin->routeShutdown($request); + } catch (Exception $e) { + if (Zend_Controller_Front::getInstance()->throwExceptions()) { + throw new Zend_Controller_Exception($e->getMessage() . $e->getTraceAsString(), $e->getCode(), $e); + } else { + $this->getResponse()->setException($e); + } + } + } + } + + + /** + * Called before Zend_Controller_Front enters its dispatch loop. + * + * During the dispatch loop, Zend_Controller_Front keeps a + * Zend_Controller_Request_Abstract object, and uses + * Zend_Controller_Dispatcher to dispatch the + * Zend_Controller_Request_Abstract object to controllers/actions. + * + * @param Zend_Controller_Request_Abstract $request + * @return void + */ + public function dispatchLoopStartup(Zend_Controller_Request_Abstract $request) + { + foreach ($this->_plugins as $plugin) { + try { + $plugin->dispatchLoopStartup($request); + } catch (Exception $e) { + if (Zend_Controller_Front::getInstance()->throwExceptions()) { + throw new Zend_Controller_Exception($e->getMessage() . $e->getTraceAsString(), $e->getCode(), $e); + } else { + $this->getResponse()->setException($e); + } + } + } + } + + + /** + * Called before an action is dispatched by Zend_Controller_Dispatcher. + * + * @param Zend_Controller_Request_Abstract $request + * @return void + */ + public function preDispatch(Zend_Controller_Request_Abstract $request) + { + foreach ($this->_plugins as $plugin) { + try { + $plugin->preDispatch($request); + } catch (Exception $e) { + if (Zend_Controller_Front::getInstance()->throwExceptions()) { + throw new Zend_Controller_Exception($e->getMessage() . $e->getTraceAsString(), $e->getCode(), $e); + } else { + $this->getResponse()->setException($e); + // skip rendering of normal dispatch give the error handler a try + $this->getRequest()->setDispatched(false); + } + } + } + } + + + /** + * Called after an action is dispatched by Zend_Controller_Dispatcher. + * + * @param Zend_Controller_Request_Abstract $request + * @return void + */ + public function postDispatch(Zend_Controller_Request_Abstract $request) + { + foreach ($this->_plugins as $plugin) { + try { + $plugin->postDispatch($request); + } catch (Exception $e) { + if (Zend_Controller_Front::getInstance()->throwExceptions()) { + throw new Zend_Controller_Exception($e->getMessage() . $e->getTraceAsString(), $e->getCode(), $e); + } else { + $this->getResponse()->setException($e); + } + } + } + } + + + /** + * Called before Zend_Controller_Front exits its dispatch loop. + * + * @param Zend_Controller_Request_Abstract $request + * @return void + */ + public function dispatchLoopShutdown() + { + foreach ($this->_plugins as $plugin) { + try { + $plugin->dispatchLoopShutdown(); + } catch (Exception $e) { + if (Zend_Controller_Front::getInstance()->throwExceptions()) { + throw new Zend_Controller_Exception($e->getMessage() . $e->getTraceAsString(), $e->getCode(), $e); + } else { + $this->getResponse()->setException($e); + } + } + } + } +} diff --git a/library/vendor/Zend/Controller/Plugin/ErrorHandler.php b/library/vendor/Zend/Controller/Plugin/ErrorHandler.php new file mode 100644 index 0000000..cd0e4f7 --- /dev/null +++ b/library/vendor/Zend/Controller/Plugin/ErrorHandler.php @@ -0,0 +1,299 @@ +setErrorHandler($options); + } + + /** + * setErrorHandler() - setup the error handling options + * + * @param array $options + * @return Zend_Controller_Plugin_ErrorHandler + */ + public function setErrorHandler(Array $options = array()) + { + if (isset($options['module'])) { + $this->setErrorHandlerModule($options['module']); + } + if (isset($options['controller'])) { + $this->setErrorHandlerController($options['controller']); + } + if (isset($options['action'])) { + $this->setErrorHandlerAction($options['action']); + } + return $this; + } + + /** + * Set the module name for the error handler + * + * @param string $module + * @return Zend_Controller_Plugin_ErrorHandler + */ + public function setErrorHandlerModule($module) + { + $this->_errorModule = (string) $module; + return $this; + } + + /** + * Retrieve the current error handler module + * + * @return string + */ + public function getErrorHandlerModule() + { + if (null === $this->_errorModule) { + $this->_errorModule = Zend_Controller_Front::getInstance()->getDispatcher()->getDefaultModule(); + } + return $this->_errorModule; + } + + /** + * Set the controller name for the error handler + * + * @param string $controller + * @return Zend_Controller_Plugin_ErrorHandler + */ + public function setErrorHandlerController($controller) + { + $this->_errorController = (string) $controller; + return $this; + } + + /** + * Retrieve the current error handler controller + * + * @return string + */ + public function getErrorHandlerController() + { + return $this->_errorController; + } + + /** + * Set the action name for the error handler + * + * @param string $action + * @return Zend_Controller_Plugin_ErrorHandler + */ + public function setErrorHandlerAction($action) + { + $this->_errorAction = (string) $action; + return $this; + } + + /** + * Retrieve the current error handler action + * + * @return string + */ + public function getErrorHandlerAction() + { + return $this->_errorAction; + } + + /** + * Route shutdown hook -- Ccheck for router exceptions + * + * @param Zend_Controller_Request_Abstract $request + */ + public function routeShutdown(Zend_Controller_Request_Abstract $request) + { + $this->_handleError($request); + } + + /** + * Pre dispatch hook -- check for exceptions and dispatch error handler if + * necessary + * + * @param Zend_Controller_Request_Abstract $request + */ + public function preDispatch(Zend_Controller_Request_Abstract $request) + { + $this->_handleError($request); + } + + /** + * Post dispatch hook -- check for exceptions and dispatch error handler if + * necessary + * + * @param Zend_Controller_Request_Abstract $request + */ + public function postDispatch(Zend_Controller_Request_Abstract $request) + { + $this->_handleError($request); + } + + /** + * Handle errors and exceptions + * + * If the 'noErrorHandler' front controller flag has been set, + * returns early. + * + * @param Zend_Controller_Request_Abstract $request + * @return void + */ + protected function _handleError(Zend_Controller_Request_Abstract $request) + { + $frontController = Zend_Controller_Front::getInstance(); + if ($frontController->getParam('noErrorHandler')) { + return; + } + + $response = $this->getResponse(); + + if ($this->_isInsideErrorHandlerLoop) { + $exceptions = $response->getException(); + if (count($exceptions) > $this->_exceptionCountAtFirstEncounter) { + // Exception thrown by error handler; tell the front controller to throw it + $frontController->throwExceptions(true); + throw array_pop($exceptions); + } + } + + // check for an exception AND allow the error handler controller the option to forward + if (($response->isException()) && (!$this->_isInsideErrorHandlerLoop)) { + $this->_isInsideErrorHandlerLoop = true; + + // Get exception information + $error = new ArrayObject(array(), ArrayObject::ARRAY_AS_PROPS); + $exceptions = $response->getException(); + $exception = $exceptions[0]; + $exceptionType = get_class($exception); + $error->exception = $exception; + switch ($exceptionType) { + case 'Zend_Controller_Router_Exception': + if (404 == $exception->getCode()) { + $error->type = self::EXCEPTION_NO_ROUTE; + } else { + $error->type = self::EXCEPTION_OTHER; + } + break; + case 'Zend_Controller_Dispatcher_Exception': + $error->type = self::EXCEPTION_NO_CONTROLLER; + break; + case 'Zend_Controller_Action_Exception': + if (404 == $exception->getCode()) { + $error->type = self::EXCEPTION_NO_ACTION; + } else { + $error->type = self::EXCEPTION_OTHER; + } + break; + default: + $error->type = self::EXCEPTION_OTHER; + break; + } + + // Keep a copy of the original request + $error->request = clone $request; + + // get a count of the number of exceptions encountered + $this->_exceptionCountAtFirstEncounter = count($exceptions); + + // Forward to the error handler + $request->setParam('error_handler', $error) + ->setModuleName($this->getErrorHandlerModule()) + ->setControllerName($this->getErrorHandlerController()) + ->setActionName($this->getErrorHandlerAction()) + ->setDispatched(false); + } + } +} diff --git a/library/vendor/Zend/Controller/Plugin/PutHandler.php b/library/vendor/Zend/Controller/Plugin/PutHandler.php new file mode 100644 index 0000000..3bf7a67 --- /dev/null +++ b/library/vendor/Zend/Controller/Plugin/PutHandler.php @@ -0,0 +1,58 @@ +_request->isPut()) { + $putParams = array(); + parse_str($this->_request->getRawBody(), $putParams); + $request->setParams($putParams); + } + } +} diff --git a/library/vendor/Zend/Controller/Request/Abstract.php b/library/vendor/Zend/Controller/Request/Abstract.php new file mode 100644 index 0000000..d57238f --- /dev/null +++ b/library/vendor/Zend/Controller/Request/Abstract.php @@ -0,0 +1,356 @@ +_module) { + $this->_module = $this->getParam($this->getModuleKey()); + } + + return $this->_module; + } + + /** + * Set the module name to use + * + * @param string $value + * @return Zend_Controller_Request_Abstract + */ + public function setModuleName($value) + { + $this->_module = $value; + return $this; + } + + /** + * Retrieve the controller name + * + * @return string + */ + public function getControllerName() + { + if (null === $this->_controller) { + $this->_controller = $this->getParam($this->getControllerKey()); + } + + return $this->_controller; + } + + /** + * Set the controller name to use + * + * @param string $value + * @return Zend_Controller_Request_Abstract + */ + public function setControllerName($value) + { + $this->_controller = $value; + return $this; + } + + /** + * Retrieve the action name + * + * @return string + */ + public function getActionName() + { + if (null === $this->_action) { + $this->_action = $this->getParam($this->getActionKey()); + } + + return $this->_action; + } + + /** + * Set the action name + * + * @param string $value + * @return Zend_Controller_Request_Abstract + */ + public function setActionName($value) + { + $this->_action = $value; + /** + * @see ZF-3465 + */ + if (null === $value) { + $this->setParam($this->getActionKey(), $value); + } + return $this; + } + + /** + * Retrieve the module key + * + * @return string + */ + public function getModuleKey() + { + return $this->_moduleKey; + } + + /** + * Set the module key + * + * @param string $key + * @return Zend_Controller_Request_Abstract + */ + public function setModuleKey($key) + { + $this->_moduleKey = (string) $key; + return $this; + } + + /** + * Retrieve the controller key + * + * @return string + */ + public function getControllerKey() + { + return $this->_controllerKey; + } + + /** + * Set the controller key + * + * @param string $key + * @return Zend_Controller_Request_Abstract + */ + public function setControllerKey($key) + { + $this->_controllerKey = (string) $key; + return $this; + } + + /** + * Retrieve the action key + * + * @return string + */ + public function getActionKey() + { + return $this->_actionKey; + } + + /** + * Set the action key + * + * @param string $key + * @return Zend_Controller_Request_Abstract + */ + public function setActionKey($key) + { + $this->_actionKey = (string) $key; + return $this; + } + + /** + * Get an action parameter + * + * @param string $key + * @param mixed $default Default value to use if key not found + * @return mixed + */ + public function getParam($key, $default = null) + { + $key = (string) $key; + if (isset($this->_params[$key])) { + return $this->_params[$key]; + } + + return $default; + } + + /** + * Retrieve only user params (i.e, any param specific to the object and not the environment) + * + * @return array + */ + public function getUserParams() + { + return $this->_params; + } + + /** + * Retrieve a single user param (i.e, a param specific to the object and not the environment) + * + * @param string $key + * @param string $default Default value to use if key not found + * @return mixed + */ + public function getUserParam($key, $default = null) + { + if (isset($this->_params[$key])) { + return $this->_params[$key]; + } + + return $default; + } + + /** + * Set an action parameter + * + * A $value of null will unset the $key if it exists + * + * @param string $key + * @param mixed $value + * @return Zend_Controller_Request_Abstract + */ + public function setParam($key, $value) + { + $key = (string) $key; + + if ((null === $value) && isset($this->_params[$key])) { + unset($this->_params[$key]); + } elseif (null !== $value) { + $this->_params[$key] = $value; + } + + return $this; + } + + /** + * Get all action parameters + * + * @return array + */ + public function getParams() + { + return $this->_params; + } + + /** + * Set action parameters en masse; does not overwrite + * + * Null values will unset the associated key. + * + * @param array $array + * @return Zend_Controller_Request_Abstract + */ + public function setParams(array $array) + { + $this->_params = $this->_params + (array) $array; + + foreach ($array as $key => $value) { + if (null === $value) { + unset($this->_params[$key]); + } + } + + return $this; + } + + /** + * Unset all user parameters + * + * @return Zend_Controller_Request_Abstract + */ + public function clearParams() + { + $this->_params = array(); + return $this; + } + + /** + * Set flag indicating whether or not request has been dispatched + * + * @param boolean $flag + * @return Zend_Controller_Request_Abstract + */ + public function setDispatched($flag = true) + { + $this->_dispatched = $flag ? true : false; + return $this; + } + + /** + * Determine if the request has been dispatched + * + * @return boolean + */ + public function isDispatched() + { + return $this->_dispatched; + } +} diff --git a/library/vendor/Zend/Controller/Request/Apache404.php b/library/vendor/Zend/Controller/Request/Apache404.php new file mode 100644 index 0000000..87d1d83 --- /dev/null +++ b/library/vendor/Zend/Controller/Request/Apache404.php @@ -0,0 +1,80 @@ +_requestUri = $requestUri; + return $this; + } +} diff --git a/library/vendor/Zend/Controller/Request/Exception.php b/library/vendor/Zend/Controller/Request/Exception.php new file mode 100644 index 0000000..89e8856 --- /dev/null +++ b/library/vendor/Zend/Controller/Request/Exception.php @@ -0,0 +1,36 @@ +valid()) { + $path = $uri->getPath(); + $query = $uri->getQuery(); + if (!empty($query)) { + $path .= '?' . $query; + } + + $this->setRequestUri($path); + } else { + throw new Zend_Controller_Request_Exception('Invalid URI provided to constructor'); + } + } else { + $this->setRequestUri(); + } + } + + /** + * Access values contained in the superglobals as public members + * Order of precedence: 1. GET, 2. POST, 3. COOKIE, 4. SERVER, 5. ENV + * + * @see http://msdn.microsoft.com/en-us/library/system.web.httprequest.item.aspx + * @param string $key + * @return mixed + */ + public function __get($key) + { + switch (true) { + case isset($this->_params[$key]): + return $this->_params[$key]; + case isset($_GET[$key]): + return $_GET[$key]; + case isset($_POST[$key]): + return $_POST[$key]; + case isset($_COOKIE[$key]): + return $_COOKIE[$key]; + case ($key == 'REQUEST_URI'): + return $this->getRequestUri(); + case ($key == 'PATH_INFO'): + return $this->getPathInfo(); + case isset($_SERVER[$key]): + return $_SERVER[$key]; + case isset($_ENV[$key]): + return $_ENV[$key]; + default: + return null; + } + } + + /** + * Alias to __get + * + * @param string $key + * @return mixed + */ + public function get($key) + { + return $this->__get($key); + } + + /** + * Set values + * + * In order to follow {@link __get()}, which operates on a number of + * superglobals, setting values through overloading is not allowed and will + * raise an exception. Use setParam() instead. + * + * @param string $key + * @param mixed $value + * @return void + * @throws Zend_Controller_Request_Exception + */ + public function __set($key, $value) + { + throw new Zend_Controller_Request_Exception('Setting values in superglobals not allowed; please use setParam()'); + } + + /** + * Alias to __set() + * + * @param string $key + * @param mixed $value + * @return void + */ + public function set($key, $value) + { + return $this->__set($key, $value); + } + + /** + * Check to see if a property is set + * + * @param string $key + * @return boolean + */ + public function __isset($key) + { + switch (true) { + case isset($this->_params[$key]): + return true; + case isset($_GET[$key]): + return true; + case isset($_POST[$key]): + return true; + case isset($_COOKIE[$key]): + return true; + case isset($_SERVER[$key]): + return true; + case isset($_ENV[$key]): + return true; + default: + return false; + } + } + + /** + * Alias to __isset() + * + * @param string $key + * @return boolean + */ + public function has($key) + { + return $this->__isset($key); + } + + /** + * Set GET values + * + * @param string|array $spec + * @param null|mixed $value + * @return Zend_Controller_Request_Http + */ + public function setQuery($spec, $value = null) + { + if ((null === $value) && !is_array($spec)) { + throw new Zend_Controller_Exception('Invalid value passed to setQuery(); must be either array of values or key/value pair'); + } + if ((null === $value) && is_array($spec)) { + foreach ($spec as $key => $value) { + $this->setQuery($key, $value); + } + return $this; + } + $_GET[(string) $spec] = $value; + return $this; + } + + /** + * Retrieve a member of the $_GET superglobal + * + * If no $key is passed, returns the entire $_GET array. + * + * @todo How to retrieve from nested arrays + * @param string $key + * @param mixed $default Default value to use if key not found + * @return mixed Returns null if key does not exist + */ + public function getQuery($key = null, $default = null) + { + if (null === $key) { + return $_GET; + } + + return (isset($_GET[$key])) ? $_GET[$key] : $default; + } + + /** + * Set POST values + * + * @param string|array $spec + * @param null|mixed $value + * @return Zend_Controller_Request_Http + */ + public function setPost($spec, $value = null) + { + if ((null === $value) && !is_array($spec)) { + throw new Zend_Controller_Exception('Invalid value passed to setPost(); must be either array of values or key/value pair'); + } + if ((null === $value) && is_array($spec)) { + foreach ($spec as $key => $value) { + $this->setPost($key, $value); + } + return $this; + } + $_POST[(string) $spec] = $value; + return $this; + } + + /** + * Retrieve a member of the $_POST superglobal + * + * If no $key is passed, returns the entire $_POST array. + * + * @todo How to retrieve from nested arrays + * @param string $key + * @param mixed $default Default value to use if key not found + * @return mixed Returns null if key does not exist + */ + public function getPost($key = null, $default = null) + { + if (null === $key) { + return $_POST; + } + + return (isset($_POST[$key])) ? $_POST[$key] : $default; + } + + /** + * Retrieve a member of the $_COOKIE superglobal + * + * If no $key is passed, returns the entire $_COOKIE array. + * + * @todo How to retrieve from nested arrays + * @param string $key + * @param mixed $default Default value to use if key not found + * @return mixed Returns null if key does not exist + */ + public function getCookie($key = null, $default = null) + { + if (null === $key) { + return $_COOKIE; + } + + return (isset($_COOKIE[$key])) ? $_COOKIE[$key] : $default; + } + + /** + * Retrieve a member of the $_SERVER superglobal + * + * If no $key is passed, returns the entire $_SERVER array. + * + * @param string $key + * @param mixed $default Default value to use if key not found + * @return mixed Returns null if key does not exist + */ + public function getServer($key = null, $default = null) + { + if (null === $key) { + return $_SERVER; + } + + return (isset($_SERVER[$key])) ? $_SERVER[$key] : $default; + } + + /** + * Retrieve a member of the $_ENV superglobal + * + * If no $key is passed, returns the entire $_ENV array. + * + * @param string $key + * @param mixed $default Default value to use if key not found + * @return mixed Returns null if key does not exist + */ + public function getEnv($key = null, $default = null) + { + if (null === $key) { + return $_ENV; + } + + return (isset($_ENV[$key])) ? $_ENV[$key] : $default; + } + + /** + * Set the REQUEST_URI on which the instance operates + * + * If no request URI is passed, uses the value in $_SERVER['REQUEST_URI'], + * $_SERVER['HTTP_X_REWRITE_URL'], or $_SERVER['ORIG_PATH_INFO'] + $_SERVER['QUERY_STRING']. + * + * @param string $requestUri + * @return Zend_Controller_Request_Http + */ + public function setRequestUri($requestUri = null) + { + if ($requestUri === null) { + if (isset($_SERVER['HTTP_X_ORIGINAL_URL'])) { + // IIS with Microsoft Rewrite Module + $requestUri = $_SERVER['HTTP_X_ORIGINAL_URL']; + } elseif (isset($_SERVER['HTTP_X_REWRITE_URL'])) { + // IIS with ISAPI_Rewrite + $requestUri = $_SERVER['HTTP_X_REWRITE_URL']; + } elseif ( + // IIS7 with URL Rewrite: make sure we get the unencoded url (double slash problem) + isset($_SERVER['IIS_WasUrlRewritten']) + && $_SERVER['IIS_WasUrlRewritten'] == '1' + && isset($_SERVER['UNENCODED_URL']) + && $_SERVER['UNENCODED_URL'] != '' + ) { + $requestUri = $_SERVER['UNENCODED_URL']; + } elseif (isset($_SERVER['REQUEST_URI'])) { + $requestUri = $_SERVER['REQUEST_URI']; + // Http proxy reqs setup request uri with scheme and host [and port] + the url path, only use url path + $schemeAndHttpHost = $this->getScheme() . '://' . $this->getHttpHost(); + if (strpos($requestUri, $schemeAndHttpHost) === 0) { + $requestUri = substr($requestUri, strlen($schemeAndHttpHost)); + } + } elseif (isset($_SERVER['ORIG_PATH_INFO'])) { // IIS 5.0, PHP as CGI + $requestUri = $_SERVER['ORIG_PATH_INFO']; + if (!empty($_SERVER['QUERY_STRING'])) { + $requestUri .= '?' . $_SERVER['QUERY_STRING']; + } + } else { + return $this; + } + } elseif (!is_string($requestUri)) { + return $this; + } else { + // Set GET items, if available + if (false !== ($pos = strpos($requestUri, '?'))) { + // Get key => value pairs and set $_GET + $query = substr($requestUri, $pos + 1); + parse_str($query, $vars); + $this->setQuery($vars); + } + } + + $this->_requestUri = $requestUri; + return $this; + } + + /** + * Returns the REQUEST_URI taking into account + * platform differences between Apache and IIS + * + * @return string + */ + public function getRequestUri() + { + if (empty($this->_requestUri)) { + $this->setRequestUri(); + } + + return $this->_requestUri; + } + + /** + * Set the base URL of the request; i.e., the segment leading to the script name + * + * E.g.: + * - /admin + * - /myapp + * - /subdir/index.php + * + * Do not use the full URI when providing the base. The following are + * examples of what not to use: + * - http://example.com/admin (should be just /admin) + * - http://example.com/subdir/index.php (should be just /subdir/index.php) + * + * If no $baseUrl is provided, attempts to determine the base URL from the + * environment, using SCRIPT_FILENAME, SCRIPT_NAME, PHP_SELF, and + * ORIG_SCRIPT_NAME in its determination. + * + * @param mixed $baseUrl + * @return Zend_Controller_Request_Http + */ + public function setBaseUrl($baseUrl = null) + { + if ((null !== $baseUrl) && !is_string($baseUrl)) { + return $this; + } + + if ($baseUrl === null) { + $filename = (isset($_SERVER['SCRIPT_FILENAME'])) ? basename($_SERVER['SCRIPT_FILENAME']) : ''; + + if (isset($_SERVER['SCRIPT_NAME']) && basename($_SERVER['SCRIPT_NAME']) === $filename) { + $baseUrl = $_SERVER['SCRIPT_NAME']; + } elseif (isset($_SERVER['PHP_SELF']) && basename($_SERVER['PHP_SELF']) === $filename) { + $baseUrl = $_SERVER['PHP_SELF']; + } elseif (isset($_SERVER['ORIG_SCRIPT_NAME']) && basename($_SERVER['ORIG_SCRIPT_NAME']) === $filename) { + $baseUrl = $_SERVER['ORIG_SCRIPT_NAME']; // 1and1 shared hosting compatibility + } else { + // Backtrack up the script_filename to find the portion matching + // php_self + $path = isset($_SERVER['PHP_SELF']) ? $_SERVER['PHP_SELF'] : ''; + $file = isset($_SERVER['SCRIPT_FILENAME']) ? $_SERVER['SCRIPT_FILENAME'] : ''; + $segs = explode('/', trim($file, '/')); + $segs = array_reverse($segs); + $index = 0; + $last = count($segs); + $baseUrl = ''; + do { + $seg = $segs[$index]; + $baseUrl = '/' . $seg . $baseUrl; + ++$index; + } while (($last > $index) && (false !== ($pos = strpos($path, $baseUrl))) && (0 != $pos)); + } + + // Does the baseUrl have anything in common with the request_uri? + $requestUri = $this->getRequestUri(); + + if (0 === strpos($requestUri, $baseUrl)) { + // full $baseUrl matches + $this->_baseUrl = $baseUrl; + return $this; + } + + if (0 === strpos($requestUri, dirname($baseUrl))) { + // directory portion of $baseUrl matches + $this->_baseUrl = rtrim(dirname($baseUrl), '/'); + return $this; + } + + $truncatedRequestUri = $requestUri; + if (($pos = strpos($requestUri, '?')) !== false) { + $truncatedRequestUri = substr($requestUri, 0, $pos); + } + + $basename = basename($baseUrl); + if (empty($basename) || !strpos($truncatedRequestUri, $basename)) { + // no match whatsoever; set it blank + $this->_baseUrl = ''; + return $this; + } + + // If using mod_rewrite or ISAPI_Rewrite strip the script filename + // out of baseUrl. $pos !== 0 makes sure it is not matching a value + // from PATH_INFO or QUERY_STRING + if ((strlen($requestUri) >= strlen($baseUrl)) + && ((false !== ($pos = strpos($requestUri, $baseUrl))) && ($pos !== 0))) + { + $baseUrl = substr($requestUri, 0, $pos + strlen($baseUrl)); + } + } + + $this->_baseUrl = rtrim($baseUrl, '/'); + return $this; + } + + /** + * Everything in REQUEST_URI before PATH_INFO + *
+ * + * @return string + */ + public function getBaseUrl($raw = false) + { + if (null === $this->_baseUrl) { + $this->setBaseUrl(); + } + + return (($raw == false) ? urldecode($this->_baseUrl) : $this->_baseUrl); + } + + /** + * Set the base path for the URL + * + * @param string|null $basePath + * @return Zend_Controller_Request_Http + */ + public function setBasePath($basePath = null) + { + if ($basePath === null) { + $filename = (isset($_SERVER['SCRIPT_FILENAME'])) + ? basename($_SERVER['SCRIPT_FILENAME']) + : ''; + + $baseUrl = $this->getBaseUrl(); + if (empty($baseUrl)) { + $this->_basePath = ''; + return $this; + } + + if (basename($baseUrl) === $filename) { + $basePath = dirname($baseUrl); + } else { + $basePath = $baseUrl; + } + } + + if (substr(PHP_OS, 0, 3) === 'WIN') { + $basePath = str_replace('\\', '/', $basePath); + } + + $this->_basePath = rtrim($basePath, '/'); + return $this; + } + + /** + * Everything in REQUEST_URI before PATH_INFO not including the filename + * + * + * @return string + */ + public function getBasePath() + { + if (null === $this->_basePath) { + $this->setBasePath(); + } + + return $this->_basePath; + } + + /** + * Set the PATH_INFO string + * + * @param string|null $pathInfo + * @return Zend_Controller_Request_Http + */ + public function setPathInfo($pathInfo = null) + { + if ($pathInfo === null) { + $baseUrl = $this->getBaseUrl(); // this actually calls setBaseUrl() & setRequestUri() + $baseUrlRaw = $this->getBaseUrl(false); + $baseUrlEncoded = urlencode($baseUrlRaw); + + if (null === ($requestUri = $this->getRequestUri())) { + return $this; + } + + // Remove the query string from REQUEST_URI + if ($pos = strpos($requestUri, '?')) { + $requestUri = substr($requestUri, 0, $pos); + } + + if (!empty($baseUrl) || !empty($baseUrlRaw)) { + if (strpos($requestUri, $baseUrl) === 0) { + $pathInfo = substr($requestUri, strlen($baseUrl)); + } elseif (strpos($requestUri, $baseUrlRaw) === 0) { + $pathInfo = substr($requestUri, strlen($baseUrlRaw)); + } elseif (strpos($requestUri, $baseUrlEncoded) === 0) { + $pathInfo = substr($requestUri, strlen($baseUrlEncoded)); + } else { + $pathInfo = $requestUri; + } + } else { + $pathInfo = $requestUri; + } + + } + + $this->_pathInfo = (string) $pathInfo; + return $this; + } + + /** + * Returns everything between the BaseUrl and QueryString. + * This value is calculated instead of reading PATH_INFO + * directly from $_SERVER due to cross-platform differences. + * + * @return string + */ + public function getPathInfo() + { + if (empty($this->_pathInfo)) { + $this->setPathInfo(); + } + + return $this->_pathInfo; + } + + /** + * Set allowed parameter sources + * + * Can be empty array, or contain one or more of '_GET' or '_POST'. + * + * @param array $paramSoures + * @return Zend_Controller_Request_Http + */ + public function setParamSources(array $paramSources = array()) + { + $this->_paramSources = $paramSources; + return $this; + } + + /** + * Get list of allowed parameter sources + * + * @return array + */ + public function getParamSources() + { + return $this->_paramSources; + } + + /** + * Set a userland parameter + * + * Uses $key to set a userland parameter. If $key is an alias, the actual + * key will be retrieved and used to set the parameter. + * + * @param mixed $key + * @param mixed $value + * @return Zend_Controller_Request_Http + */ + public function setParam($key, $value) + { + $key = (null !== ($alias = $this->getAlias($key))) ? $alias : $key; + parent::setParam($key, $value); + return $this; + } + + /** + * Retrieve a parameter + * + * Retrieves a parameter from the instance. Priority is in the order of + * userland parameters (see {@link setParam()}), $_GET, $_POST. If a + * parameter matching the $key is not found, null is returned. + * + * If the $key is an alias, the actual key aliased will be used. + * + * @param mixed $key + * @param mixed $default Default value to use if key not found + * @return mixed + */ + public function getParam($key, $default = null) + { + $keyName = (null !== ($alias = $this->getAlias($key))) ? $alias : $key; + + $paramSources = $this->getParamSources(); + if (isset($this->_params[$keyName])) { + return $this->_params[$keyName]; + } elseif (in_array('_GET', $paramSources) && (isset($_GET[$keyName]))) { + return $_GET[$keyName]; + } elseif (in_array('_POST', $paramSources) && (isset($_POST[$keyName]))) { + return $_POST[$keyName]; + } + + return $default; + } + + /** + * Retrieve an array of parameters + * + * Retrieves a merged array of parameters, with precedence of userland + * params (see {@link setParam()}), $_GET, $_POST (i.e., values in the + * userland params will take precedence over all others). + * + * @return array + */ + public function getParams() + { + $return = $this->_params; + $paramSources = $this->getParamSources(); + if (in_array('_GET', $paramSources) + && isset($_GET) + && is_array($_GET) + ) { + $return += $_GET; + } + if (in_array('_POST', $paramSources) + && isset($_POST) + && is_array($_POST) + ) { + $return += $_POST; + } + return $return; + } + + /** + * Set parameters + * + * Set one or more parameters. Parameters are set as userland parameters, + * using the keys specified in the array. + * + * @param array $params + * @return Zend_Controller_Request_Http + */ + public function setParams(array $params) + { + foreach ($params as $key => $value) { + $this->setParam($key, $value); + } + return $this; + } + + /** + * Set a key alias + * + * Set an alias used for key lookups. $name specifies the alias, $target + * specifies the actual key to use. + * + * @param string $name + * @param string $target + * @return Zend_Controller_Request_Http + */ + public function setAlias($name, $target) + { + $this->_aliases[$name] = $target; + return $this; + } + + /** + * Retrieve an alias + * + * Retrieve the actual key represented by the alias $name. + * + * @param string $name + * @return string|null Returns null when no alias exists + */ + public function getAlias($name) + { + if (isset($this->_aliases[$name])) { + return $this->_aliases[$name]; + } + + return null; + } + + /** + * Retrieve the list of all aliases + * + * @return array + */ + public function getAliases() + { + return $this->_aliases; + } + + /** + * Return the method by which the request was made + * + * @return string + */ + public function getMethod() + { + return $this->getServer('REQUEST_METHOD'); + } + + /** + * Was the request made by POST? + * + * @return boolean + */ + public function isPost() + { + if ('POST' == $this->getMethod()) { + return true; + } + + return false; + } + + /** + * Was the request made by GET? + * + * @return boolean + */ + public function isGet() + { + if ('GET' == $this->getMethod()) { + return true; + } + + return false; + } + + /** + * Was the request made by PUT? + * + * @return boolean + */ + public function isPut() + { + if ('PUT' == $this->getMethod()) { + return true; + } + + return false; + } + + /** + * Was the request made by DELETE? + * + * @return boolean + */ + public function isDelete() + { + if ('DELETE' == $this->getMethod()) { + return true; + } + + return false; + } + + /** + * Was the request made by HEAD? + * + * @return boolean + */ + public function isHead() + { + if ('HEAD' == $this->getMethod()) { + return true; + } + + return false; + } + + /** + * Was the request made by OPTIONS? + * + * @return boolean + */ + public function isOptions() + { + if ('OPTIONS' == $this->getMethod()) { + return true; + } + + return false; + } + + /** + * Was the request made by PATCH? + * + * @return boolean + */ + public function isPatch() + { + if ('PATCH' == $this->getMethod()) { + return true; + } + + return false; + } + + /** + * Is the request a Javascript XMLHttpRequest? + * + * Should work with Prototype/Script.aculo.us, possibly others. + * + * @return boolean + */ + public function isXmlHttpRequest() + { + return ($this->getHeader('X_REQUESTED_WITH') == 'XMLHttpRequest'); + } + + /** + * Is this a Flash request? + * + * @return boolean + */ + public function isFlashRequest() + { + $header = strtolower($this->getHeader('USER_AGENT')); + return (strstr($header, ' flash')) ? true : false; + } + + /** + * Is https secure request + * + * @return boolean + */ + public function isSecure() + { + return ($this->getScheme() === self::SCHEME_HTTPS); + } + + /** + * Return the raw body of the request, if present + * + * @return string|false Raw body, or false if not present + */ + public function getRawBody() + { + if (null === $this->_rawBody) { + $body = file_get_contents('php://input'); + + if (strlen(trim($body)) > 0) { + $this->_rawBody = $body; + } else { + $this->_rawBody = false; + } + } + return $this->_rawBody; + } + + /** + * Return the value of the given HTTP header. Pass the header name as the + * plain, HTTP-specified header name. Ex.: Ask for 'Accept' to get the + * Accept header, 'Accept-Encoding' to get the Accept-Encoding header. + * + * @param string $header HTTP header name + * @return string|false HTTP header value, or false if not found + * @throws Zend_Controller_Request_Exception + */ + public function getHeader($header) + { + if (empty($header)) { + throw new Zend_Controller_Request_Exception('An HTTP header name is required'); + } + + // Try to get it from the $_SERVER array first + $temp = strtoupper(str_replace('-', '_', $header)); + if (isset($_SERVER['HTTP_' . $temp])) { + return $_SERVER['HTTP_' . $temp]; + } + + /* + * Try to get it from the $_SERVER array on POST request or CGI environment + * @see https://www.ietf.org/rfc/rfc3875 (4.1.2. and 4.1.3.) + */ + if (isset($_SERVER[$temp]) + && in_array($temp, array('CONTENT_TYPE', 'CONTENT_LENGTH')) + ) { + return $_SERVER[$temp]; + } + + // This seems to be the only way to get the Authorization header on + // Apache + if (function_exists('apache_request_headers')) { + $headers = apache_request_headers(); + if (isset($headers[$header])) { + return $headers[$header]; + } + $header = strtolower($header); + foreach ($headers as $key => $value) { + if (strtolower($key) == $header) { + return $value; + } + } + } + + return false; + } + + /** + * Get the request URI scheme + * + * @return string + */ + public function getScheme() + { + return ($this->getServer('HTTPS') == 'on') ? self::SCHEME_HTTPS : self::SCHEME_HTTP; + } + + /** + * Get the HTTP host. + * + * "Host" ":" host [ ":" port ] ; Section 3.2.2 + * Note the HTTP Host header is not the same as the URI host. + * It includes the port while the URI host doesn't. + * + * @return string + */ + public function getHttpHost() + { + $host = $this->getServer('HTTP_HOST'); + if (!empty($host)) { + return $host; + } + + $scheme = $this->getScheme(); + $name = $this->getServer('SERVER_NAME'); + $port = $this->getServer('SERVER_PORT'); + + if(null === $name) { + return ''; + } + elseif (($scheme == self::SCHEME_HTTP && $port == 80) || ($scheme == self::SCHEME_HTTPS && $port == 443)) { + return $name; + } else { + return $name . ':' . $port; + } + } + + /** + * Get the client's IP addres + * + * @param boolean $checkProxy + * @return string + */ + public function getClientIp($checkProxy = true) + { + if ($checkProxy && $this->getServer('HTTP_CLIENT_IP') != null) { + $ip = $this->getServer('HTTP_CLIENT_IP'); + } else if ($checkProxy && $this->getServer('HTTP_X_FORWARDED_FOR') != null) { + $ip = $this->getServer('HTTP_X_FORWARDED_FOR'); + } else { + $ip = $this->getServer('REMOTE_ADDR'); + } + + return $ip; + } +} diff --git a/library/vendor/Zend/Controller/Request/HttpTestCase.php b/library/vendor/Zend/Controller/Request/HttpTestCase.php new file mode 100644 index 0000000..414c95e --- /dev/null +++ b/library/vendor/Zend/Controller/Request/HttpTestCase.php @@ -0,0 +1,275 @@ +_rawBody = (string) $content; + return $this; + } + + /** + * Get RAW POST body + * + * @return string|null + */ + public function getRawBody() + { + return $this->_rawBody; + } + + /** + * Clear raw POST body + * + * @return Zend_Controller_Request_HttpTestCase + */ + public function clearRawBody() + { + $this->_rawBody = null; + return $this; + } + + /** + * Set a cookie + * + * @param string $key + * @param mixed $value + * @return Zend_Controller_Request_HttpTestCase + */ + public function setCookie($key, $value) + { + $_COOKIE[(string) $key] = $value; + return $this; + } + + /** + * Set multiple cookies at once + * + * @param array $cookies + * @return void + */ + public function setCookies(array $cookies) + { + foreach ($cookies as $key => $value) { + $_COOKIE[$key] = $value; + } + return $this; + } + + /** + * Clear all cookies + * + * @return Zend_Controller_Request_HttpTestCase + */ + public function clearCookies() + { + $_COOKIE = array(); + return $this; + } + + /** + * Set request method + * + * @param string $type + * @return Zend_Controller_Request_HttpTestCase + */ + public function setMethod($type) + { + $type = strtoupper(trim((string) $type)); + if (!in_array($type, $this->_validMethodTypes)) { + throw new Zend_Controller_Exception('Invalid request method specified'); + } + $this->_method = $type; + return $this; + } + + /** + * Get request method + * + * @return string|null + */ + public function getMethod() + { + return $this->_method; + } + + /** + * Set a request header + * + * @param string $key + * @param string $value + * @return Zend_Controller_Request_HttpTestCase + */ + public function setHeader($key, $value) + { + $key = $this->_normalizeHeaderName($key); + $this->_headers[$key] = (string) $value; + return $this; + } + + /** + * Set request headers + * + * @param array $headers + * @return Zend_Controller_Request_HttpTestCase + */ + public function setHeaders(array $headers) + { + foreach ($headers as $key => $value) { + $this->setHeader($key, $value); + } + return $this; + } + + /** + * Get request header + * + * @param string $header + * @param mixed $default + * @return string|null + */ + public function getHeader($header, $default = null) + { + $header = $this->_normalizeHeaderName($header); + if (array_key_exists($header, $this->_headers)) { + return $this->_headers[$header]; + } + return $default; + } + + /** + * Get all request headers + * + * @return array + */ + public function getHeaders() + { + return $this->_headers; + } + + /** + * Clear request headers + * + * @return Zend_Controller_Request_HttpTestCase + */ + public function clearHeaders() + { + $this->_headers = array(); + return $this; + } + + /** + * Get REQUEST_URI + * + * @return null|string + */ + public function getRequestUri() + { + return $this->_requestUri; + } + + /** + * Normalize a header name for setting and retrieval + * + * @param string $name + * @return string + */ + protected function _normalizeHeaderName($name) + { + $name = strtoupper((string) $name); + $name = str_replace('-', '_', $name); + return $name; + } +} diff --git a/library/vendor/Zend/Controller/Request/Simple.php b/library/vendor/Zend/Controller/Request/Simple.php new file mode 100644 index 0000000..f804107 --- /dev/null +++ b/library/vendor/Zend/Controller/Request/Simple.php @@ -0,0 +1,54 @@ +setActionName($action); + } + + if ($controller) { + $this->setControllerName($controller); + } + + if ($module) { + $this->setModuleName($module); + } + + if ($params) { + $this->setParams($params); + } + } + +} diff --git a/library/vendor/Zend/Controller/Response/Abstract.php b/library/vendor/Zend/Controller/Response/Abstract.php new file mode 100644 index 0000000..0649694 --- /dev/null +++ b/library/vendor/Zend/Controller/Response/Abstract.php @@ -0,0 +1,790 @@ +canSendHeaders(true); + $name = $this->_normalizeHeader($name); + $value = (string) $value; + + if ($replace) { + foreach ($this->_headers as $key => $header) { + if ($name == $header['name']) { + unset($this->_headers[$key]); + } + } + } + + $this->_headers[] = array( + 'name' => $name, + 'value' => $value, + 'replace' => $replace + ); + + return $this; + } + + /** + * Set redirect URL + * + * Sets Location header and response code. Forces replacement of any prior + * redirects. + * + * @param string $url + * @param int $code + * @return Zend_Controller_Response_Abstract + */ + public function setRedirect($url, $code = 302) + { + $this->canSendHeaders(true); + $this->setHeader('Location', $url, true) + ->setHttpResponseCode($code); + + return $this; + } + + /** + * Is this a redirect? + * + * @return boolean + */ + public function isRedirect() + { + return $this->_isRedirect; + } + + /** + * Return array of headers; see {@link $_headers} for format + * + * @return array + */ + public function getHeaders() + { + return $this->_headers; + } + + /** + * Clear headers + * + * @return Zend_Controller_Response_Abstract + */ + public function clearHeaders() + { + $this->_headers = array(); + + return $this; + } + + /** + * Clears the specified HTTP header + * + * @param string $name + * @return Zend_Controller_Response_Abstract + */ + public function clearHeader($name) + { + if (! count($this->_headers)) { + return $this; + } + + foreach ($this->_headers as $index => $header) { + if ($name == $header['name']) { + unset($this->_headers[$index]); + } + } + + return $this; + } + + /** + * Set raw HTTP header + * + * Allows setting non key => value headers, such as status codes + * + * @param string $value + * @return Zend_Controller_Response_Abstract + */ + public function setRawHeader($value) + { + $this->canSendHeaders(true); + if ('Location' == substr($value, 0, 8)) { + $this->_isRedirect = true; + } + $this->_headersRaw[] = (string) $value; + return $this; + } + + /** + * Retrieve all {@link setRawHeader() raw HTTP headers} + * + * @return array + */ + public function getRawHeaders() + { + return $this->_headersRaw; + } + + /** + * Clear all {@link setRawHeader() raw HTTP headers} + * + * @return Zend_Controller_Response_Abstract + */ + public function clearRawHeaders() + { + $this->_headersRaw = array(); + return $this; + } + + /** + * Clears the specified raw HTTP header + * + * @param string $headerRaw + * @return Zend_Controller_Response_Abstract + */ + public function clearRawHeader($headerRaw) + { + if (! count($this->_headersRaw)) { + return $this; + } + + $key = array_search($headerRaw, $this->_headersRaw); + if ($key !== false) { + unset($this->_headersRaw[$key]); + } + + return $this; + } + + /** + * Clear all headers, normal and raw + * + * @return Zend_Controller_Response_Abstract + */ + public function clearAllHeaders() + { + return $this->clearHeaders() + ->clearRawHeaders(); + } + + /** + * Set HTTP response code to use with headers + * + * @param int $code + * @return Zend_Controller_Response_Abstract + */ + public function setHttpResponseCode($code) + { + if (!is_int($code) || (100 > $code) || (599 < $code)) { + throw new Zend_Controller_Response_Exception('Invalid HTTP response code'); + } + + if ((300 <= $code) && (307 >= $code)) { + $this->_isRedirect = true; + } else { + $this->_isRedirect = false; + } + + $this->_httpResponseCode = $code; + return $this; + } + + /** + * Retrieve HTTP response code + * + * @return int + */ + public function getHttpResponseCode() + { + return $this->_httpResponseCode; + } + + /** + * Can we send headers? + * + * @param boolean $throw Whether or not to throw an exception if headers have been sent; defaults to false + * @return boolean + * @throws Zend_Controller_Response_Exception + */ + public function canSendHeaders($throw = false) + { + $ok = headers_sent($file, $line); + if ($ok && $throw && $this->headersSentThrowsException) { + throw new Zend_Controller_Response_Exception('Cannot send headers; headers already sent in ' . $file . ', line ' . $line); + } + + return !$ok; + } + + /** + * Send all headers + * + * Sends any headers specified. If an {@link setHttpResponseCode() HTTP response code} + * has been specified, it is sent with the first header. + * + * @return Zend_Controller_Response_Abstract + */ + public function sendHeaders() + { + // Only check if we can send headers if we have headers to send + if (count($this->_headersRaw) || count($this->_headers) || (200 != $this->_httpResponseCode)) { + $this->canSendHeaders(true); + } elseif (200 == $this->_httpResponseCode) { + // Haven't changed the response code, and we have no headers + return $this; + } + + $httpCodeSent = false; + + foreach ($this->_headersRaw as $header) { + if (!$httpCodeSent && $this->_httpResponseCode) { + header($header, true, $this->_httpResponseCode); + $httpCodeSent = true; + } else { + header($header); + } + } + + foreach ($this->_headers as $header) { + if (!$httpCodeSent && $this->_httpResponseCode) { + header($header['name'] . ': ' . $header['value'], $header['replace'], $this->_httpResponseCode); + $httpCodeSent = true; + } else { + header($header['name'] . ': ' . $header['value'], $header['replace']); + } + } + + if (!$httpCodeSent) { + header('HTTP/1.1 ' . $this->_httpResponseCode); + $httpCodeSent = true; + } + + return $this; + } + + /** + * Set body content + * + * If $name is not passed, or is not a string, resets the entire body and + * sets the 'default' key to $content. + * + * If $name is a string, sets the named segment in the body array to + * $content. + * + * @param string $content + * @param null|string $name + * @return Zend_Controller_Response_Abstract + */ + public function setBody($content, $name = null) + { + if ((null === $name) || !is_string($name)) { + $this->_body = array('default' => (string) $content); + } else { + $this->_body[$name] = (string) $content; + } + + return $this; + } + + /** + * Append content to the body content + * + * @param string $content + * @param null|string $name + * @return Zend_Controller_Response_Abstract + */ + public function appendBody($content, $name = null) + { + if ((null === $name) || !is_string($name)) { + if (isset($this->_body['default'])) { + $this->_body['default'] .= (string) $content; + } else { + return $this->append('default', $content); + } + } elseif (isset($this->_body[$name])) { + $this->_body[$name] .= (string) $content; + } else { + return $this->append($name, $content); + } + + return $this; + } + + /** + * Clear body array + * + * With no arguments, clears the entire body array. Given a $name, clears + * just that named segment; if no segment matching $name exists, returns + * false to indicate an error. + * + * @param string $name Named segment to clear + * @return boolean + */ + public function clearBody($name = null) + { + if (null !== $name) { + $name = (string) $name; + if (isset($this->_body[$name])) { + unset($this->_body[$name]); + return true; + } + + return false; + } + + $this->_body = array(); + return true; + } + + /** + * Return the body content + * + * If $spec is false, returns the concatenated values of the body content + * array. If $spec is boolean true, returns the body content array. If + * $spec is a string and matches a named segment, returns the contents of + * that segment; otherwise, returns null. + * + * @param boolean $spec + * @return string|array|null + */ + public function getBody($spec = false) + { + if (false === $spec) { + ob_start(); + $this->outputBody(); + return ob_get_clean(); + } elseif (true === $spec) { + return $this->_body; + } elseif (is_string($spec) && isset($this->_body[$spec])) { + return $this->_body[$spec]; + } + + return null; + } + + /** + * Append a named body segment to the body content array + * + * If segment already exists, replaces with $content and places at end of + * array. + * + * @param string $name + * @param string $content + * @return Zend_Controller_Response_Abstract + */ + public function append($name, $content) + { + if (!is_string($name)) { + throw new Zend_Controller_Response_Exception('Invalid body segment key ("' . gettype($name) . '")'); + } + + if (isset($this->_body[$name])) { + unset($this->_body[$name]); + } + $this->_body[$name] = (string) $content; + return $this; + } + + /** + * Prepend a named body segment to the body content array + * + * If segment already exists, replaces with $content and places at top of + * array. + * + * @param string $name + * @param string $content + * @return void + */ + public function prepend($name, $content) + { + if (!is_string($name)) { + throw new Zend_Controller_Response_Exception('Invalid body segment key ("' . gettype($name) . '")'); + } + + if (isset($this->_body[$name])) { + unset($this->_body[$name]); + } + + $new = array($name => (string) $content); + $this->_body = $new + $this->_body; + + return $this; + } + + /** + * Insert a named segment into the body content array + * + * @param string $name + * @param string $content + * @param string $parent + * @param boolean $before Whether to insert the new segment before or + * after the parent. Defaults to false (after) + * @return Zend_Controller_Response_Abstract + */ + public function insert($name, $content, $parent = null, $before = false) + { + if (!is_string($name)) { + throw new Zend_Controller_Response_Exception('Invalid body segment key ("' . gettype($name) . '")'); + } + + if ((null !== $parent) && !is_string($parent)) { + throw new Zend_Controller_Response_Exception('Invalid body segment parent key ("' . gettype($parent) . '")'); + } + + if (isset($this->_body[$name])) { + unset($this->_body[$name]); + } + + if ((null === $parent) || !isset($this->_body[$parent])) { + return $this->append($name, $content); + } + + $ins = array($name => (string) $content); + $keys = array_keys($this->_body); + $loc = array_search($parent, $keys); + if (!$before) { + // Increment location if not inserting before + ++$loc; + } + + if (0 === $loc) { + // If location of key is 0, we're prepending + $this->_body = $ins + $this->_body; + } elseif ($loc >= (count($this->_body))) { + // If location of key is maximal, we're appending + $this->_body = $this->_body + $ins; + } else { + // Otherwise, insert at location specified + $pre = array_slice($this->_body, 0, $loc); + $post = array_slice($this->_body, $loc); + $this->_body = $pre + $ins + $post; + } + + return $this; + } + + /** + * Echo the body segments + * + * @return void + */ + public function outputBody() + { + $body = implode('', $this->_body); + echo $body; + } + + /** + * Register an exception with the response + * + * @param Exception $e + * @return Zend_Controller_Response_Abstract + */ + public function setException(Exception $e) + { + $this->_exceptions[] = $e; + return $this; + } + + /** + * Retrieve the exception stack + * + * @return array + */ + public function getException() + { + return $this->_exceptions; + } + + /** + * Has an exception been registered with the response? + * + * @return boolean + */ + public function isException() + { + return !empty($this->_exceptions); + } + + /** + * Does the response object contain an exception of a given type? + * + * @param string $type + * @return boolean + */ + public function hasExceptionOfType($type) + { + foreach ($this->_exceptions as $e) { + if ($e instanceof $type) { + return true; + } + } + + return false; + } + + /** + * Does the response object contain an exception with a given message? + * + * @param string $message + * @return boolean + */ + public function hasExceptionOfMessage($message) + { + foreach ($this->_exceptions as $e) { + if ($message == $e->getMessage()) { + return true; + } + } + + return false; + } + + /** + * Does the response object contain an exception with a given code? + * + * @param int $code + * @return boolean + */ + public function hasExceptionOfCode($code) + { + $code = (int) $code; + foreach ($this->_exceptions as $e) { + if ($code == $e->getCode()) { + return true; + } + } + + return false; + } + + /** + * Retrieve all exceptions of a given type + * + * @param string $type + * @return false|array + */ + public function getExceptionByType($type) + { + $exceptions = array(); + foreach ($this->_exceptions as $e) { + if ($e instanceof $type) { + $exceptions[] = $e; + } + } + + if (empty($exceptions)) { + $exceptions = false; + } + + return $exceptions; + } + + /** + * Retrieve all exceptions of a given message + * + * @param string $message + * @return false|array + */ + public function getExceptionByMessage($message) + { + $exceptions = array(); + foreach ($this->_exceptions as $e) { + if ($message == $e->getMessage()) { + $exceptions[] = $e; + } + } + + if (empty($exceptions)) { + $exceptions = false; + } + + return $exceptions; + } + + /** + * Retrieve all exceptions of a given code + * + * @param mixed $code + * @return void + */ + public function getExceptionByCode($code) + { + $code = (int) $code; + $exceptions = array(); + foreach ($this->_exceptions as $e) { + if ($code == $e->getCode()) { + $exceptions[] = $e; + } + } + + if (empty($exceptions)) { + $exceptions = false; + } + + return $exceptions; + } + + /** + * Whether or not to render exceptions (off by default) + * + * If called with no arguments or a null argument, returns the value of the + * flag; otherwise, sets it and returns the current value. + * + * @param boolean $flag Optional + * @return boolean + */ + public function renderExceptions($flag = null) + { + if (null !== $flag) { + $this->_renderExceptions = $flag ? true : false; + } + + return $this->_renderExceptions; + } + + /** + * Send the response, including all headers, rendering exceptions if so + * requested. + * + * @return void + */ + public function sendResponse() + { + $this->sendHeaders(); + + if ($this->isException() && $this->renderExceptions()) { + $exceptions = ''; + foreach ($this->getException() as $e) { + $exceptions .= $e->__toString() . "\n"; + } + echo $exceptions; + return; + } + + $this->outputBody(); + } + + /** + * Magic __toString functionality + * + * Proxies to {@link sendResponse()} and returns response value as string + * using output buffering. + * + * @return string + */ + public function __toString() + { + ob_start(); + $this->sendResponse(); + return ob_get_clean(); + } +} diff --git a/library/vendor/Zend/Controller/Response/Cli.php b/library/vendor/Zend/Controller/Response/Cli.php new file mode 100644 index 0000000..5177d56 --- /dev/null +++ b/library/vendor/Zend/Controller/Response/Cli.php @@ -0,0 +1,67 @@ +isException() && $this->renderExceptions()) { + $exceptions = ''; + foreach ($this->getException() as $e) { + $exceptions .= $e->__toString() . "\n"; + } + return $exceptions; + } + + return $this->_body; + } +} diff --git a/library/vendor/Zend/Controller/Response/Exception.php b/library/vendor/Zend/Controller/Response/Exception.php new file mode 100644 index 0000000..8750ef3 --- /dev/null +++ b/library/vendor/Zend/Controller/Response/Exception.php @@ -0,0 +1,35 @@ +_headersRaw as $header) { + $headers[] = $header; + } + foreach ($this->_headers as $header) { + $name = $header['name']; + $key = strtolower($name); + if (array_key_exists($name, $headers)) { + if ($header['replace']) { + $headers[$key] = $header['name'] . ': ' . $header['value']; + } + } else { + $headers[$key] = $header['name'] . ': ' . $header['value']; + } + } + return $headers; + } + + /** + * Can we send headers? + * + * @param bool $throw + * @return void + */ + public function canSendHeaders($throw = false) + { + return true; + } + + /** + * Return the concatenated body segments + * + * @return string + */ + public function outputBody() + { + $fullContent = ''; + foreach ($this->_body as $content) { + $fullContent .= $content; + } + return $fullContent; + } + + /** + * Get body and/or body segments + * + * @param bool|string $spec + * @return string|array|null + */ + public function getBody($spec = false) + { + if (false === $spec) { + return $this->outputBody(); + } elseif (true === $spec) { + return $this->_body; + } elseif (is_string($spec) && isset($this->_body[$spec])) { + return $this->_body[$spec]; + } + + return null; + } + + /** + * "send" Response + * + * Concats all response headers, and then final body (separated by two + * newlines) + * + * @return string + */ + public function sendResponse() + { + $headers = $this->sendHeaders(); + $content = implode("\n", $headers) . "\n\n"; + + if ($this->isException() && $this->renderExceptions()) { + $exceptions = ''; + foreach ($this->getException() as $e) { + $exceptions .= $e->__toString() . "\n"; + } + $content .= $exceptions; + } else { + $content .= $this->outputBody(); + } + + return $content; + } +} diff --git a/library/vendor/Zend/Controller/Router/Abstract.php b/library/vendor/Zend/Controller/Router/Abstract.php new file mode 100644 index 0000000..7709caf --- /dev/null +++ b/library/vendor/Zend/Controller/Router/Abstract.php @@ -0,0 +1,176 @@ +setParams($params); + } + + /** + * Add or modify a parameter to use when instantiating an action controller + * + * @param string $name + * @param mixed $value + * @return Zend_Controller_Router_Abstract + */ + public function setParam($name, $value) + { + $name = (string)$name; + $this->_invokeParams[$name] = $value; + + return $this; + } + + /** + * Set parameters to pass to action controller constructors + * + * @param array $params + * @return Zend_Controller_Router_Abstract + */ + public function setParams(array $params) + { + $this->_invokeParams = array_merge($this->_invokeParams, $params); + + return $this; + } + + /** + * Retrieve a single parameter from the controller parameter stack + * + * @param string $name + * @return mixed + */ + public function getParam($name) + { + if (isset($this->_invokeParams[$name])) { + return $this->_invokeParams[$name]; + } + + return null; + } + + /** + * Retrieve action controller instantiation parameters + * + * @return array + */ + public function getParams() + { + return $this->_invokeParams; + } + + /** + * Clear the controller parameter stack + * + * By default, clears all parameters. If a parameter name is given, clears + * only that parameter; if an array of parameter names is provided, clears + * each. + * + * @param null|string|array single key or array of keys for params to clear + * @return Zend_Controller_Router_Abstract + */ + public function clearParams($name = null) + { + if (null === $name) { + $this->_invokeParams = array(); + } elseif (is_string($name) && isset($this->_invokeParams[$name])) { + unset($this->_invokeParams[$name]); + } elseif (is_array($name)) { + foreach ($name as $key) { + if (is_string($key) && isset($this->_invokeParams[$key])) { + unset($this->_invokeParams[$key]); + } + } + } + + return $this; + } + + /** + * Retrieve Front Controller + * + * @return Zend_Controller_Front + */ + public function getFrontController() + { + // Used cache version if found + if (null !== $this->_frontController) { + return $this->_frontController; + } + + $this->_frontController = Zend_Controller_Front::getInstance(); + + return $this->_frontController; + } + + /** + * Set Front Controller + * + * @param Zend_Controller_Front $controller + * @return Zend_Controller_Router_Interface + */ + public function setFrontController(Zend_Controller_Front $controller) + { + $this->_frontController = $controller; + + return $this; + } +} diff --git a/library/vendor/Zend/Controller/Router/Exception.php b/library/vendor/Zend/Controller/Router/Exception.php new file mode 100644 index 0000000..8bdb7ff --- /dev/null +++ b/library/vendor/Zend/Controller/Router/Exception.php @@ -0,0 +1,34 @@ +hasRoute('default')) { + $dispatcher = $this->getFrontController()->getDispatcher(); + $request = $this->getFrontController()->getRequest(); + + $compat = new Zend_Controller_Router_Route_Module(array(), $dispatcher, $request); + + $this->_routes = array('default' => $compat) + $this->_routes; + } + + return $this; + } + + /** + * Add route to the route chain + * + * If route contains method setRequest(), it is initialized with a request object + * + * @param string $name Name of the route + * @param Zend_Controller_Router_Route_Interface $route Instance of the route + * @return Zend_Controller_Router_Rewrite + */ + public function addRoute($name, Zend_Controller_Router_Route_Interface $route) + { + if (method_exists($route, 'setRequest')) { + $route->setRequest($this->getFrontController()->getRequest()); + } + + $this->_routes[$name] = $route; + + return $this; + } + + /** + * Add routes to the route chain + * + * @param array $routes Array of routes with names as keys and routes as values + * @return Zend_Controller_Router_Rewrite + */ + public function addRoutes($routes) + { + foreach ($routes as $name => $route) { + $this->addRoute($name, $route); + } + + return $this; + } + + /** + * Create routes out of Zend_Config configuration + * + * Example INI: + * routes.archive.route = "archive/:year/*" + * routes.archive.defaults.controller = archive + * routes.archive.defaults.action = show + * routes.archive.defaults.year = 2000 + * routes.archive.reqs.year = "\d+" + * + * routes.news.type = "Zend_Controller_Router_Route_Static" + * routes.news.route = "news" + * routes.news.defaults.controller = "news" + * routes.news.defaults.action = "list" + * + * And finally after you have created a Zend_Config with above ini: + * $router = new Zend_Controller_Router_Rewrite(); + * $router->addConfig($config, 'routes'); + * + * @param Zend_Config $config Configuration object + * @param string $section Name of the config section containing route's definitions + * @throws Zend_Controller_Router_Exception + * @return Zend_Controller_Router_Rewrite + */ + public function addConfig(Zend_Config $config, $section = null) + { + if ($section !== null) { + if ($config->{$section} === null) { + throw new Zend_Controller_Router_Exception("No route configuration in section '{$section}'"); + } + + $config = $config->{$section}; + } + + foreach ($config as $name => $info) { + $route = $this->_getRouteFromConfig($info); + + if ($route instanceof Zend_Controller_Router_Route_Chain) { + if (!isset($info->chain)) { + throw new Zend_Controller_Router_Exception("No chain defined"); + } + + if ($info->chain instanceof Zend_Config) { + $childRouteNames = $info->chain; + } else { + $childRouteNames = explode(',', $info->chain); + } + + foreach ($childRouteNames as $childRouteName) { + $childRoute = $this->getRoute(trim($childRouteName)); + $route->chain($childRoute); + } + + $this->addRoute($name, $route); + } elseif (isset($info->chains) && $info->chains instanceof Zend_Config) { + $this->_addChainRoutesFromConfig($name, $route, $info->chains); + } else { + $this->addRoute($name, $route); + } + } + + return $this; + } + + /** + * Get a route frm a config instance + * + * @param Zend_Config $info + * @return Zend_Controller_Router_Route_Interface + */ + protected function _getRouteFromConfig(Zend_Config $info) + { + $class = (isset($info->type)) ? $info->type : 'Zend_Controller_Router_Route'; + if (!class_exists($class)) { + Zend_Loader::loadClass($class); + } + + $route = call_user_func( + array( + $class, + 'getInstance' + ), $info + ); + + if (isset($info->abstract) && $info->abstract && method_exists($route, 'isAbstract')) { + $route->isAbstract(true); + } + + return $route; + } + + /** + * Add chain routes from a config route + * + * @param string $name + * @param Zend_Controller_Router_Route_Interface $route + * @param Zend_Config $childRoutesInfo + * @return void + */ + protected function _addChainRoutesFromConfig( + $name, + Zend_Controller_Router_Route_Interface $route, + Zend_Config $childRoutesInfo + ) + { + foreach ($childRoutesInfo as $childRouteName => $childRouteInfo) { + if (is_string($childRouteInfo)) { + $childRouteName = $childRouteInfo; + $childRoute = $this->getRoute($childRouteName); + } else { + $childRoute = $this->_getRouteFromConfig($childRouteInfo); + } + + if ($route instanceof Zend_Controller_Router_Route_Chain) { + $chainRoute = clone $route; + $chainRoute->chain($childRoute); + } else { + $chainRoute = $route->chain($childRoute); + } + + $chainName = $name . $this->_chainNameSeparator . $childRouteName; + + if (isset($childRouteInfo->chains)) { + $this->_addChainRoutesFromConfig($chainName, $chainRoute, $childRouteInfo->chains); + } else { + $this->addRoute($chainName, $chainRoute); + } + } + } + + /** + * Remove a route from the route chain + * + * @param string $name Name of the route + * @throws Zend_Controller_Router_Exception + * @return Zend_Controller_Router_Rewrite + */ + public function removeRoute($name) + { + if (!isset($this->_routes[$name])) { + throw new Zend_Controller_Router_Exception("Route $name is not defined"); + } + + unset($this->_routes[$name]); + + return $this; + } + + /** + * Remove all standard default routes + * + * @return Zend_Controller_Router_Rewrite + */ + public function removeDefaultRoutes() + { + $this->_useDefaultRoutes = false; + + return $this; + } + + /** + * Check if named route exists + * + * @param string $name Name of the route + * @return boolean + */ + public function hasRoute($name) + { + return isset($this->_routes[$name]); + } + + /** + * Retrieve a named route + * + * @param string $name Name of the route + * @throws Zend_Controller_Router_Exception + * @return Zend_Controller_Router_Route_Interface Route object + */ + public function getRoute($name) + { + if (!isset($this->_routes[$name])) { + throw new Zend_Controller_Router_Exception("Route $name is not defined"); + } + + return $this->_routes[$name]; + } + + /** + * Retrieve a currently matched route + * + * @throws Zend_Controller_Router_Exception + * @return Zend_Controller_Router_Route_Interface Route object + */ + public function getCurrentRoute() + { + if (!isset($this->_currentRoute)) { + throw new Zend_Controller_Router_Exception("Current route is not defined"); + } + + return $this->getRoute($this->_currentRoute); + } + + /** + * Retrieve a name of currently matched route + * + * @throws Zend_Controller_Router_Exception + * @return string Route name + */ + public function getCurrentRouteName() + { + if (!isset($this->_currentRoute)) { + throw new Zend_Controller_Router_Exception("Current route is not defined"); + } + + return $this->_currentRoute; + } + + /** + * Retrieve an array of routes added to the route chain + * + * @return array All of the defined routes + */ + public function getRoutes() + { + return $this->_routes; + } + + /** + * Find a matching route to the current PATH_INFO and inject + * returning values to the Request object. + * + * @param Zend_Controller_Request_Abstract $request + * @throws Zend_Controller_Router_Exception + * @return Zend_Controller_Request_Abstract Request object + */ + public function route(Zend_Controller_Request_Abstract $request) + { + if (!$request instanceof Zend_Controller_Request_Http) { + throw new Zend_Controller_Router_Exception( + 'Zend_Controller_Router_Rewrite requires a Zend_Controller_Request_Http-based request object' + ); + } + + if ($this->_useDefaultRoutes) { + $this->addDefaultRoutes(); + } + + // Find the matching route + $routeMatched = false; + + foreach (array_reverse($this->_routes, true) as $name => $route) { + // TODO: Should be an interface method. Hack for 1.0 BC + if (method_exists($route, 'isAbstract') && $route->isAbstract()) { + continue; + } + + // TODO: Should be an interface method. Hack for 1.0 BC + if (!method_exists($route, 'getVersion') || $route->getVersion() == 1) { + $match = $request->getPathInfo(); + } else { + $match = $request; + } + + if ($params = $route->match($match)) { + $this->_setRequestParams($request, $params); + $this->_currentRoute = $name; + $routeMatched = true; + break; + } + } + + if (!$routeMatched) { + throw new Zend_Controller_Router_Exception('No route matched the request', 404); + } + + if ($this->_useCurrentParamsAsGlobal) { + $params = $request->getParams(); + foreach ($params as $param => $value) { + $this->setGlobalParam($param, $value); + } + } + + return $request; + } + + /** + * Sets parameters for request object + * + * Module name, controller name and action name + * + * @param Zend_Controller_Request_Abstract $request + * @param array $params + */ + protected function _setRequestParams($request, $params) + { + foreach ($params as $param => $value) { + + $request->setParam($param, $value); + + if ($param === $request->getModuleKey()) { + $request->setModuleName($value); + } + if ($param === $request->getControllerKey()) { + $request->setControllerName($value); + } + if ($param === $request->getActionKey()) { + $request->setActionName($value); + } + } + } + + /** + * Generates a URL path that can be used in URL creation, redirection, etc. + * + * @param array $userParams Options passed by a user used to override parameters + * @param mixed $name The name of a Route to use + * @param bool $reset Whether to reset to the route defaults ignoring URL params + * @param bool $encode Tells to encode URL parts on output + * @throws Zend_Controller_Router_Exception + * @return string Resulting absolute URL path + */ + public function assemble($userParams, $name = null, $reset = false, $encode = true) + { + if (!is_array($userParams)) { + throw new Zend_Controller_Router_Exception('userParams must be an array'); + } + + if ($name == null) { + try { + $name = $this->getCurrentRouteName(); + } catch (Zend_Controller_Router_Exception $e) { + $name = 'default'; + } + } + + // Use UNION (+) in order to preserve numeric keys + $params = $userParams + $this->_globalParams; + + $route = $this->getRoute($name); + $url = $route->assemble($params, $reset, $encode); + + if (!preg_match('|^[a-z]+://|', $url)) { + $url = rtrim($this->getFrontController()->getBaseUrl(), self::URI_DELIMITER) . self::URI_DELIMITER . $url; + } + + return $url; + } + + /** + * Set a global parameter + * + * @param string $name + * @param mixed $value + * @return Zend_Controller_Router_Rewrite + */ + public function setGlobalParam($name, $value) + { + $this->_globalParams[$name] = $value; + + return $this; + } + + /** + * Set the separator to use with chain names + * + * @param string $separator The separator to use + * @return Zend_Controller_Router_Rewrite + */ + public function setChainNameSeparator($separator) + { + $this->_chainNameSeparator = $separator; + + return $this; + } + + /** + * Get the separator to use for chain names + * + * @return string + */ + public function getChainNameSeparator() + { + return $this->_chainNameSeparator; + } + + /** + * Determines/returns whether to use the request parameters as global parameters. + * + * @param boolean|null $use + * Null/unset when you want to retrieve the current state. + * True when request parameters should be global, false otherwise + * @return boolean|Zend_Controller_Router_Rewrite + * Returns a boolean if first param isn't set, returns an + * instance of Zend_Controller_Router_Rewrite otherwise. + * + */ + public function useRequestParametersAsGlobal($use = null) + { + if ($use === null) { + return $this->_useCurrentParamsAsGlobal; + } + + $this->_useCurrentParamsAsGlobal = (bool)$use; + + return $this; + } +} diff --git a/library/vendor/Zend/Controller/Router/Route.php b/library/vendor/Zend/Controller/Router/Route.php new file mode 100644 index 0000000..e001a49 --- /dev/null +++ b/library/vendor/Zend/Controller/Router/Route.php @@ -0,0 +1,603 @@ +reqs instanceof Zend_Config) ? $config->reqs->toArray() : array(); + $defs = ($config->defaults instanceof Zend_Config) ? $config->defaults->toArray() : array(); + + return new self($config->route, $defs, $reqs); + } + + /** + * Prepares the route for mapping by splitting (exploding) it + * to a corresponding atomic parts. These parts are assigned + * a position which is later used for matching and preparing values. + * + * @param string $route Map used to match with later submitted URL path + * @param array $defaults Defaults for map variables with keys as variable names + * @param array $reqs Regular expression requirements for variables (keys as variable names) + * @param Zend_Translate $translator Translator to use for this instance + * @param mixed|null $locale + */ + public function __construct( + $route, $defaults = array(), $reqs = array(), Zend_Translate $translator = null, $locale = null + ) + { + $route = trim($route, $this->_urlDelimiter); + $this->_defaults = (array)$defaults; + $this->_requirements = (array)$reqs; + $this->_translator = $translator; + $this->_locale = $locale; + + if ($route !== '') { + foreach (explode($this->_urlDelimiter, $route) as $pos => $part) { + if (substr($part, 0, 1) == $this->_urlVariable && substr($part, 1, 1) != $this->_urlVariable) { + $name = substr($part, 1); + + if (substr($name, 0, 1) === '@' && substr($name, 1, 1) !== '@') { + $name = substr($name, 1); + $this->_translatable[] = $name; + $this->_isTranslated = true; + } + + $this->_parts[$pos] = (isset($reqs[$name]) ? $reqs[$name] : $this->_defaultRegex); + $this->_variables[$pos] = $name; + } else { + if (substr($part, 0, 1) == $this->_urlVariable) { + $part = substr($part, 1); + } + + if (substr($part, 0, 1) === '@' && substr($part, 1, 1) !== '@') { + $this->_isTranslated = true; + } + + $this->_parts[$pos] = $part; + + if ($part !== '*') { + $this->_staticCount++; + } + } + } + } + } + + /** + * Matches a user submitted path with parts defined by a map. Assigns and + * returns an array of variables on a successful match. + * + * @param string $path Path used to match against this routing map + * @param boolean $partial + * @throws Zend_Controller_Router_Exception + * @return array|false An array of assigned values or a false on a mismatch + */ + public function match($path, $partial = false) + { + if ($this->_isTranslated) { + $translateMessages = $this->getTranslator()->getMessages(); + } + + $pathStaticCount = 0; + $values = array(); + $matchedPath = ''; + + if (!$partial) { + $path = trim($path, $this->_urlDelimiter); + } + + if ($path !== '') { + $path = explode($this->_urlDelimiter, $path); + + foreach ($path as $pos => $pathPart) { + // Path is longer than a route, it's not a match + if (!array_key_exists($pos, $this->_parts)) { + if ($partial) { + break; + } else { + return false; + } + } + + $matchedPath .= $pathPart . $this->_urlDelimiter; + + // If it's a wildcard, get the rest of URL as wildcard data and stop matching + if ($this->_parts[$pos] == '*') { + $count = count($path); + for ($i = $pos; $i < $count; $i += 2) { + $var = urldecode($path[$i]); + if (!isset($this->_wildcardData[$var]) && !isset($this->_defaults[$var]) + && !isset($values[$var]) + ) { + $this->_wildcardData[$var] = (isset($path[$i + 1])) ? urldecode($path[$i + 1]) : null; + } + } + + $matchedPath = implode($this->_urlDelimiter, $path); + break; + } + + $name = isset($this->_variables[$pos]) ? $this->_variables[$pos] : null; + $pathPart = urldecode($pathPart); + + // Translate value if required + $part = $this->_parts[$pos]; + if ($this->_isTranslated + && $part !== null + && (substr($part, 0, 1) === '@' && substr($part, 1, 1) !== '@' + && $name === null) + || $name !== null && in_array($name, $this->_translatable) + ) { + if ($part && substr($part, 0, 1) === '@') { + $part = substr($part, 1); + } + + if (($originalPathPart = array_search($pathPart, $translateMessages)) !== false) { + $pathPart = $originalPathPart; + } + } + + if ($part && substr($part, 0, 2) === '@@') { + $part = substr($part, 1); + } + + // If it's a static part, match directly + if ($name === null && $part != $pathPart) { + return false; + } + + // If it's a variable with requirement, match a regex. If not - everything matches + if ($part !== null + && !preg_match( + $this->_regexDelimiter . '^' . $part . '$' . $this->_regexDelimiter . 'iu', $pathPart + ) + ) { + return false; + } + + // If it's a variable store it's value for later + if ($name !== null) { + $values[$name] = $pathPart; + } else { + $pathStaticCount++; + } + } + } + + // Check if all static mappings have been matched + if ($this->_staticCount != $pathStaticCount) { + return false; + } + + $return = $values + $this->_wildcardData + $this->_defaults; + + // Check if all map variables have been initialized + foreach ($this->_variables as $var) { + if (!array_key_exists($var, $return)) { + return false; + } elseif ($return[$var] == '' || $return[$var] === null) { + // Empty variable? Replace with the default value. + $return[$var] = $this->_defaults[$var]; + } + } + + $this->setMatchedPath(rtrim($matchedPath, $this->_urlDelimiter)); + + $this->_values = $values; + + return $return; + } + + /** + * Assembles user submitted parameters forming a URL path defined by this route + * + * @param array $data An array of variable and value pairs used as parameters + * @param boolean $reset Whether or not to set route defaults with those provided in $data + * @param boolean $encode + * @param boolean $partial + * @throws Zend_Controller_Router_Exception + * @return string Route path with user submitted parameters + */ + public function assemble($data = array(), $reset = false, $encode = false, $partial = false) + { + if ($this->_isTranslated) { + $translator = $this->getTranslator(); + + if (isset($data['@locale'])) { + $locale = $data['@locale']; + unset($data['@locale']); + } else { + $locale = $this->getLocale(); + } + } + + $url = array(); + $flag = false; + + foreach ($this->_parts as $key => $part) { + $name = isset($this->_variables[$key]) ? $this->_variables[$key] : null; + + $useDefault = false; + if (isset($name) && array_key_exists($name, $data) && $data[$name] === null) { + $useDefault = true; + } + + if (isset($name)) { + if (isset($data[$name]) && !$useDefault) { + $value = $data[$name]; + unset($data[$name]); + } elseif (!$reset && !$useDefault && isset($this->_values[$name])) { + $value = $this->_values[$name]; + } elseif (!$reset && !$useDefault && isset($this->_wildcardData[$name])) { + $value = $this->_wildcardData[$name]; + } elseif (array_key_exists($name, $this->_defaults)) { + $value = $this->_defaults[$name]; + } else { + throw new Zend_Controller_Router_Exception($name . ' is not specified'); + } + + if ($this->_isTranslated && in_array($name, $this->_translatable)) { + $url[$key] = $translator->translate($value, $locale); + } else { + $url[$key] = $value; + } + } elseif ($part != '*') { + if ($this->_isTranslated && substr($part, 0, 1) === '@') { + if (substr($part, 1, 1) !== '@') { + $url[$key] = $translator->translate(substr($part, 1), $locale); + } else { + $url[$key] = substr($part, 1); + } + } else { + if (substr($part, 0, 2) === '@@') { + $part = substr($part, 1); + } + + $url[$key] = $part; + } + } else { + if (!$reset) { + $data += $this->_wildcardData; + } + $defaults = $this->getDefaults(); + foreach ($data as $var => $value) { + if ($value !== null && (!isset($defaults[$var]) || $value != $defaults[$var])) { + $url[$key++] = $var; + $url[$key++] = $value; + $flag = true; + } + } + } + } + + $return = ''; + + foreach (array_reverse($url, true) as $key => $value) { + $defaultValue = null; + + if (isset($this->_variables[$key])) { + $defaultValue = $this->getDefault($this->_variables[$key]); + + if ($this->_isTranslated && $defaultValue !== null + && isset($this->_translatable[$this->_variables[$key]]) + ) { + $defaultValue = $translator->translate($defaultValue, $locale); + } + } + + if ($flag || $value !== $defaultValue || $partial) { + if ($encode) { + $value = urlencode($value); + } + $return = $this->_urlDelimiter . $value . $return; + $flag = true; + } + } + + return trim($return, $this->_urlDelimiter); + } + + /** + * Return a single parameter of route's defaults + * + * @param string $name Array key of the parameter + * @return string Previously set default + */ + public function getDefault($name) + { + if (isset($this->_defaults[$name])) { + return $this->_defaults[$name]; + } + + return null; + } + + /** + * Return an array of defaults + * + * @return array Route defaults + */ + public function getDefaults() + { + return $this->_defaults; + } + + /** + * Get all variables which are used by the route + * + * @return array + */ + public function getVariables() + { + return $this->_variables; + } + + /** + * Set a default translator + * + * @param Zend_Translate $translator + * @return void + */ + public static function setDefaultTranslator(Zend_Translate $translator = null) + { + self::$_defaultTranslator = $translator; + } + + /** + * Get the default translator + * + * @return Zend_Translate + */ + public static function getDefaultTranslator() + { + return self::$_defaultTranslator; + } + + /** + * Set a translator + * + * @param Zend_Translate $translator + * @return void + */ + public function setTranslator(Zend_Translate $translator) + { + $this->_translator = $translator; + } + + /** + * Get the translator + * + * @throws Zend_Controller_Router_Exception When no translator can be found + * @return Zend_Translate + */ + public function getTranslator() + { + if ($this->_translator !== null) { + return $this->_translator; + } else { + if (($translator = self::getDefaultTranslator()) !== null) { + return $translator; + } else { + try { + $translator = Zend_Registry::get('Zend_Translate'); + } catch (Zend_Exception $e) { + $translator = null; + } + + if ($translator instanceof Zend_Translate) { + return $translator; + } + } + } + + throw new Zend_Controller_Router_Exception('Could not find a translator'); + } + + /** + * Set a default locale + * + * @param mixed $locale + * @return void + */ + public static function setDefaultLocale($locale = null) + { + self::$_defaultLocale = $locale; + } + + /** + * Get the default locale + * + * @return mixed + */ + public static function getDefaultLocale() + { + return self::$_defaultLocale; + } + + /** + * Set a locale + * + * @param mixed $locale + * @return void + */ + public function setLocale($locale) + { + $this->_locale = $locale; + } + + /** + * Get the locale + * + * @return mixed + */ + public function getLocale() + { + if ($this->_locale !== null) { + return $this->_locale; + } else { + if (($locale = self::getDefaultLocale()) !== null) { + return $locale; + } else { + try { + $locale = Zend_Registry::get('Zend_Locale'); + } catch (Zend_Exception $e) { + $locale = null; + } + + if ($locale !== null) { + return $locale; + } + } + } + + return null; + } +} diff --git a/library/vendor/Zend/Controller/Router/Route/Abstract.php b/library/vendor/Zend/Controller/Router/Route/Abstract.php new file mode 100644 index 0000000..7ec1e30 --- /dev/null +++ b/library/vendor/Zend/Controller/Router/Route/Abstract.php @@ -0,0 +1,119 @@ +_matchedPath = $path; + } + + /** + * Get partially matched path + * + * @return string + */ + public function getMatchedPath() + { + return $this->_matchedPath; + } + + /** + * Check or set wether this is an abstract route or not + * + * @param boolean $flag + * @return boolean + */ + public function isAbstract($flag = null) + { + if ($flag !== null) { + $this->_isAbstract = $flag; + } + + return $this->_isAbstract; + } + + /** + * Create a new chain + * + * @param Zend_Controller_Router_Route_Abstract $route + * @param string $separator + * @return Zend_Controller_Router_Route_Chain + */ + public function chain(Zend_Controller_Router_Route_Abstract $route, $separator = '/') + { + + $chain = new Zend_Controller_Router_Route_Chain(); + $chain->chain($this)->chain($route, $separator); + + return $chain; + } +} diff --git a/library/vendor/Zend/Controller/Router/Route/Chain.php b/library/vendor/Zend/Controller/Router/Route/Chain.php new file mode 100644 index 0000000..a4414bd --- /dev/null +++ b/library/vendor/Zend/Controller/Router/Route/Chain.php @@ -0,0 +1,228 @@ +defaults instanceof Zend_Config) ? $config->defaults->toArray() : array(); + + return new self($config->route, $defs); + } + + /** + * Add a route to this chain + * + * @param Zend_Controller_Router_Route_Abstract $route + * @param string $separator + * @return Zend_Controller_Router_Route_Chain + */ + public function chain(Zend_Controller_Router_Route_Abstract $route, $separator = self::URI_DELIMITER) + { + $this->_routes[] = $route; + $this->_separators[] = $separator; + + return $this; + } + + /** + * Matches a user submitted path with a previously defined route. + * Assigns and returns an array of defaults on a successful match. + * + * @param Zend_Controller_Request_Http $request Request to get the path info from + * @param null $partial + * @return array|false An array of assigned values or a false on a mismatch + */ + public function match($request, $partial = null) + { + $rawPath = $request->getPathInfo(); + $path = trim($request->getPathInfo(), self::URI_DELIMITER); + $subPath = $path; + $values = array(); + $matchedPath = null; + + foreach ($this->_routes as $key => $route) { + if ($key > 0 + && $matchedPath !== null + && $subPath !== '' + && $subPath !== false + ) { + $separator = substr($subPath, 0, strlen($this->_separators[$key])); + + if ($separator !== $this->_separators[$key]) { + $request->setPathInfo($rawPath); + return false; + } + + $subPath = substr($subPath, strlen($separator)); + } + // TODO: Should be an interface method. Hack for 1.0 BC + if (!method_exists($route, 'getVersion') || $route->getVersion() == 1) { + $match = $subPath; + } else { + $request->setPathInfo($subPath); + $match = $request; + } + + $res = $route->match($match, true); + + if ($res === false) { + $request->setPathInfo($rawPath); + return false; + } + + $matchedPath = $route->getMatchedPath(); + + if ($matchedPath !== null) { + $subPath = substr($subPath, strlen($matchedPath)); + } + + $values = $res + $values; + } + + $request->setPathInfo($path); + + if ($subPath !== '' && $subPath !== false) { + return false; + } + + return $values; + } + + /** + * Assembles a URL path defined by this route + * + * @param array $data An array of variable and value pairs used as parameters + * @param bool $reset + * @param bool $encode + * @return string Route path with user submitted parameters + */ + public function assemble($data = array(), $reset = false, $encode = false) + { + $value = ''; + $numRoutes = count($this->_routes); + + foreach ($this->_routes as $key => $route) { + if ($key > 0) { + $value .= $this->_separators[$key]; + } + + $value .= $route->assemble($data, $reset, $encode, (($numRoutes - 1) > $key)); + + if (method_exists($route, 'getVariables')) { + $variables = $route->getVariables(); + + foreach ($variables as $variable) { + $data[$variable] = null; + } + } + } + + return $value; + } + + /** + * Set the request object for this and the child routes + * + * @param Zend_Controller_Request_Abstract|null $request + * @return void + */ + public function setRequest(Zend_Controller_Request_Abstract $request = null) + { + $this->_request = $request; + + foreach ($this->_routes as $route) { + if (method_exists($route, 'setRequest')) { + $route->setRequest($request); + } + } + } + + /** + * Return a single parameter of route's defaults + * + * @param string $name Array key of the parameter + * @return string Previously set default + */ + public function getDefault($name) + { + $default = null; + foreach ($this->_routes as $route) { + if (method_exists($route, 'getDefault')) { + $current = $route->getDefault($name); + if (null !== $current) { + $default = $current; + } + } + } + + return $default; + } + + /** + * Return an array of defaults + * + * @return array Route defaults + */ + public function getDefaults() + { + $defaults = array(); + foreach ($this->_routes as $route) { + if (method_exists($route, 'getDefaults')) { + $defaults = array_merge($defaults, $route->getDefaults()); + } + } + + return $defaults; + } +} diff --git a/library/vendor/Zend/Controller/Router/Route/Hostname.php b/library/vendor/Zend/Controller/Router/Route/Hostname.php new file mode 100644 index 0000000..b2be1c1 --- /dev/null +++ b/library/vendor/Zend/Controller/Router/Route/Hostname.php @@ -0,0 +1,377 @@ +_request = $request; + } + + /** + * Get the request object + * + * @return Zend_Controller_Request_Abstract $request + */ + public function getRequest() + { + if ($this->_request === null) { + $this->_request = Zend_Controller_Front::getInstance()->getRequest(); + } + + return $this->_request; + } + + /** + * Instantiates route based on passed Zend_Config structure + * + * @param Zend_Config $config Configuration object + * @return Zend_Controller_Router_Route_Hostname + */ + public static function getInstance(Zend_Config $config) + { + $reqs = ($config->reqs instanceof Zend_Config) ? $config->reqs->toArray() : array(); + $defs = ($config->defaults instanceof Zend_Config) ? $config->defaults->toArray() : array(); + $scheme = (isset($config->scheme)) ? $config->scheme : null; + + return new self($config->route, $defs, $reqs, $scheme); + } + + /** + * Prepares the route for mapping by splitting (exploding) it + * to a corresponding atomic parts. These parts are assigned + * a position which is later used for matching and preparing values. + * + * @param string $route Map used to match with later submitted hostname + * @param array $defaults Defaults for map variables with keys as variable names + * @param array $reqs Regular expression requirements for variables (keys as variable names) + * @param string $scheme + */ + public function __construct($route, $defaults = array(), $reqs = array(), $scheme = null) + { + $route = trim($route, '.'); + $this->_defaults = (array) $defaults; + $this->_requirements = (array) $reqs; + $this->_scheme = $scheme; + + if ($route != '') { + foreach (explode('.', $route) as $pos => $part) { + if (substr($part, 0, 1) == $this->_hostVariable) { + $name = substr($part, 1); + $this->_parts[$pos] = (isset($reqs[$name]) ? $reqs[$name] : $this->_defaultRegex); + $this->_variables[$pos] = $name; + } else { + $this->_parts[$pos] = $part; + $this->_staticCount++; + } + } + } + } + + /** + * Matches a user submitted path with parts defined by a map. Assigns and + * returns an array of variables on a successful match. + * + * @param Zend_Controller_Request_Http $request Request to get the host from + * @return array|false An array of assigned values or a false on a mismatch + */ + public function match($request) + { + // Check the scheme if required + if ($this->_scheme !== null) { + $scheme = $request->getScheme(); + + if ($scheme !== $this->_scheme) { + return false; + } + } + + // Get the host and remove unnecessary port information + $host = $request->getHttpHost(); + if (preg_match('#:\d+$#', $host, $result) === 1) { + $host = substr($host, 0, -strlen($result[0])); + } + + $hostStaticCount = 0; + $values = array(); + + $host = trim($host, '.'); + + if ($host != '') { + $host = explode('.', $host); + + foreach ($host as $pos => $hostPart) { + // Host is longer than a route, it's not a match + if (!array_key_exists($pos, $this->_parts)) { + return false; + } + + $name = isset($this->_variables[$pos]) ? $this->_variables[$pos] : null; + $hostPart = urldecode($hostPart); + + // If it's a static part, match directly + if ($name === null && $this->_parts[$pos] != $hostPart) { + return false; + } + + // If it's a variable with requirement, match a regex. If not - everything matches + if ($this->_parts[$pos] !== null + && !preg_match( + $this->_regexDelimiter . '^' . $this->_parts[$pos] . '$' . $this->_regexDelimiter . 'iu', + $hostPart + ) + ) { + return false; + } + + // If it's a variable store it's value for later + if ($name !== null) { + $values[$name] = $hostPart; + } else { + $hostStaticCount++; + } + } + } + + // Check if all static mappings have been matched + if ($this->_staticCount != $hostStaticCount) { + return false; + } + + $return = $values + $this->_defaults; + + // Check if all map variables have been initialized + foreach ($this->_variables as $var) { + if (!array_key_exists($var, $return)) { + return false; + } + } + + $this->_values = $values; + + return $return; + } + + /** + * Assembles user submitted parameters forming a hostname defined by this route + * + * @param array $data An array of variable and value pairs used as parameters + * @param boolean $reset Whether or not to set route defaults with those provided in $data + * @param boolean $encode + * @param boolean $partial + * @throws Zend_Controller_Router_Exception + * @return string Route path with user submitted parameters + */ + public function assemble($data = array(), $reset = false, $encode = false, $partial = false) + { + $host = array(); + $flag = false; + + foreach ($this->_parts as $key => $part) { + $name = isset($this->_variables[$key]) ? $this->_variables[$key] : null; + + $useDefault = false; + if (isset($name) && array_key_exists($name, $data) && $data[$name] === null) { + $useDefault = true; + } + + if (isset($name)) { + if (isset($data[$name]) && !$useDefault) { + $host[$key] = $data[$name]; + unset($data[$name]); + } elseif (!$reset && !$useDefault && isset($this->_values[$name])) { + $host[$key] = $this->_values[$name]; + } elseif (isset($this->_defaults[$name])) { + $host[$key] = $this->_defaults[$name]; + } else { + throw new Zend_Controller_Router_Exception($name . ' is not specified'); + } + } else { + $host[$key] = $part; + } + } + + $return = ''; + + foreach (array_reverse($host, true) as $key => $value) { + if ($flag || !isset($this->_variables[$key]) || $value !== $this->getDefault($this->_variables[$key]) + || $partial + ) { + if ($encode) { + $value = urlencode($value); + } + $return = '.' . $value . $return; + $flag = true; + } + } + + $url = trim($return, '.'); + + if ($this->_scheme !== null) { + $scheme = $this->_scheme; + } else { + $request = $this->getRequest(); + if ($request instanceof Zend_Controller_Request_Http) { + $scheme = $request->getScheme(); + } else { + $scheme = 'http'; + } + } + + $url = $scheme . '://' . $url; + + return $url; + } + + /** + * Return a single parameter of route's defaults + * + * @param string $name Array key of the parameter + * @return string Previously set default + */ + public function getDefault($name) + { + if (isset($this->_defaults[$name])) { + return $this->_defaults[$name]; + } + + return null; + } + + /** + * Return an array of defaults + * + * @return array Route defaults + */ + public function getDefaults() + { + return $this->_defaults; + } + + /** + * Get all variables which are used by the route + * + * @return array + */ + public function getVariables() + { + return $this->_variables; + } +} diff --git a/library/vendor/Zend/Controller/Router/Route/Interface.php b/library/vendor/Zend/Controller/Router/Route/Interface.php new file mode 100644 index 0000000..6a14f9d --- /dev/null +++ b/library/vendor/Zend/Controller/Router/Route/Interface.php @@ -0,0 +1,38 @@ +defaults instanceof Zend_Config) ? $config->defaults->toArray() : array(); + $dispatcher = $frontController->getDispatcher(); + $request = $frontController->getRequest(); + + return new self($defs, $dispatcher, $request); + } + + /** + * Constructor + * + * @param array $defaults Defaults for map variables with keys as variable names + * @param Zend_Controller_Dispatcher_Interface $dispatcher Dispatcher object + * @param Zend_Controller_Request_Abstract $request Request object + */ + public function __construct( + array $defaults = array(), + Zend_Controller_Dispatcher_Interface $dispatcher = null, + Zend_Controller_Request_Abstract $request = null + ) + { + $this->_defaults = $defaults; + + if (isset($request)) { + $this->_request = $request; + } + + if (isset($dispatcher)) { + $this->_dispatcher = $dispatcher; + } + } + + /** + * Set request keys based on values in request object + * + * @return void + */ + protected function _setRequestKeys() + { + if (null !== $this->_request) { + $this->_moduleKey = $this->_request->getModuleKey(); + $this->_controllerKey = $this->_request->getControllerKey(); + $this->_actionKey = $this->_request->getActionKey(); + } + + if (null !== $this->_dispatcher) { + $this->_defaults += array( + $this->_controllerKey => $this->_dispatcher->getDefaultControllerName(), + $this->_actionKey => $this->_dispatcher->getDefaultAction(), + $this->_moduleKey => $this->_dispatcher->getDefaultModule() + ); + } + + $this->_keysSet = true; + } + + /** + * Matches a user submitted path. Assigns and returns an array of variables + * on a successful match. + * + * If a request object is registered, it uses its setModuleName(), + * setControllerName(), and setActionName() accessors to set those values. + * Always returns the values as an array. + * + * @param string $path Path used to match against this routing map + * @param boolean $partial + * @return array An array of assigned values or a false on a mismatch + */ + public function match($path, $partial = false) + { + $this->_setRequestKeys(); + + $values = array(); + $params = array(); + + if (!$partial) { + $path = trim($path, self::URI_DELIMITER); + } else { + $matchedPath = $path; + } + + if ($path != '') { + $path = explode(self::URI_DELIMITER, $path); + + if ($this->_dispatcher && $this->_dispatcher->isValidModule($path[0])) { + $values[$this->_moduleKey] = array_shift($path); + $this->_moduleValid = true; + } + + if (count($path) && !empty($path[0])) { + $values[$this->_controllerKey] = array_shift($path); + } + + if (count($path) && !empty($path[0])) { + $values[$this->_actionKey] = array_shift($path); + } + + if ($numSegs = count($path)) { + for ($i = 0; $i < $numSegs; $i = $i + 2) { + $key = urldecode($path[$i]); + $val = isset($path[$i + 1]) ? urldecode($path[$i + 1]) : null; + $params[$key] = (isset($params[$key]) ? (array_merge((array)$params[$key], array($val))) : $val); + } + } + } + + if ($partial) { + $this->setMatchedPath($matchedPath); + } + + $this->_values = $values + $params; + + return $this->_values + $this->_defaults; + } + + /** + * Assembles user submitted parameters forming a URL path defined by this route + * + * @param array $data An array of variable and value pairs used as parameters + * @param boolean $reset Weither to reset the current params + * @param boolean $encode + * @param boolean $partial + * @return string Route path with user submitted parameters + */ + public function assemble($data = array(), $reset = false, $encode = true, $partial = false) + { + if (!$this->_keysSet) { + $this->_setRequestKeys(); + } + + $params = (!$reset) ? $this->_values : array(); + + foreach ($data as $key => $value) { + if ($value !== null) { + $params[$key] = $value; + } elseif (isset($params[$key])) { + unset($params[$key]); + } + } + + $params += $this->_defaults; + + $url = ''; + + if ($this->_moduleValid || array_key_exists($this->_moduleKey, $data)) { + if ($params[$this->_moduleKey] != $this->_defaults[$this->_moduleKey]) { + $module = $params[$this->_moduleKey]; + } + } + unset($params[$this->_moduleKey]); + + $controller = $params[$this->_controllerKey]; + unset($params[$this->_controllerKey]); + + $action = $params[$this->_actionKey]; + unset($params[$this->_actionKey]); + + foreach ($params as $key => $value) { + $key = ($encode) ? urlencode($key) : $key; + if (is_array($value)) { + foreach ($value as $arrayValue) { + $arrayValue = ($encode) ? urlencode($arrayValue) : $arrayValue; + $url .= self::URI_DELIMITER . $key; + $url .= self::URI_DELIMITER . $arrayValue; + } + } else { + if ($encode) { + $value = urlencode($value); + } + $url .= self::URI_DELIMITER . $key; + $url .= self::URI_DELIMITER . $value; + } + } + + if (!empty($url) || $action !== $this->_defaults[$this->_actionKey]) { + if ($encode) { + $action = urlencode($action); + } + $url = self::URI_DELIMITER . $action . $url; + } + + if (!empty($url) || $controller !== $this->_defaults[$this->_controllerKey]) { + if ($encode) { + $controller = urlencode($controller); + } + $url = self::URI_DELIMITER . $controller . $url; + } + + if (isset($module)) { + if ($encode) { + $module = urlencode($module); + } + $url = self::URI_DELIMITER . $module . $url; + } + + return ltrim($url, self::URI_DELIMITER); + } + + /** + * Return a single parameter of route's defaults + * + * @param string $name Array key of the parameter + * @return string Previously set default + */ + public function getDefault($name) + { + if (isset($this->_defaults[$name])) { + return $this->_defaults[$name]; + } + } + + /** + * Return an array of defaults + * + * @return array Route defaults + */ + public function getDefaults() + { + return $this->_defaults; + } +} diff --git a/library/vendor/Zend/Controller/Router/Route/Regex.php b/library/vendor/Zend/Controller/Router/Route/Regex.php new file mode 100644 index 0000000..8dea1c0 --- /dev/null +++ b/library/vendor/Zend/Controller/Router/Route/Regex.php @@ -0,0 +1,316 @@ +defaults instanceof Zend_Config) ? $config->defaults->toArray() : array(); + $map = ($config->map instanceof Zend_Config) ? $config->map->toArray() : array(); + $reverse = (isset($config->reverse)) ? $config->reverse : null; + + return new self($config->route, $defs, $map, $reverse); + } + + /** + * Constructor + * + * @param $route + * @param array $defaults + * @param array $map + * @param null $reverse + */ + public function __construct($route, $defaults = array(), $map = array(), $reverse = null) + { + $this->_regex = $route; + $this->_defaults = (array) $defaults; + $this->_map = (array) $map; + $this->_reverse = $reverse; + } + + /** + * Get the version of the route + * + * @return int + */ + public function getVersion() + { + return 1; + } + + /** + * Matches a user submitted path with a previously defined route. + * Assigns and returns an array of defaults on a successful match. + * + * @param string $path Path used to match against this routing map + * @return array|false An array of assigned values or a false on a mismatch + */ + public function match($path, $partial = false) + { + if (!$partial) { + $path = trim(urldecode($path), self::URI_DELIMITER); + $regex = '#^' . $this->_regex . '$#i'; + } else { + $regex = '#^' . $this->_regex . '#i'; + } + + $res = preg_match($regex, $path, $values); + + if ($res === 0) { + return false; + } + + if ($partial) { + $this->setMatchedPath($values[0]); + } + + // array_filter_key()? Why isn't this in a standard PHP function set yet? :) + foreach ($values as $i => $value) { + if (!is_int($i) || $i === 0) { + unset($values[$i]); + } + } + + $this->_values = $values; + + $values = $this->_getMappedValues($values); + $defaults = $this->_getMappedValues($this->_defaults, false, true); + $return = $values + $defaults; + + return $return; + } + + /** + * Maps numerically indexed array values to it's associative mapped counterpart. + * Or vice versa. Uses user provided map array which consists of index => name + * parameter mapping. If map is not found, it returns original array. + * + * Method strips destination type of keys form source array. Ie. if source array is + * indexed numerically then every associative key will be stripped. Vice versa if reversed + * is set to true. + * + * @param array $values Indexed or associative array of values to map + * @param boolean $reversed False means translation of index to association. True means reverse. + * @param boolean $preserve Should wrong type of keys be preserved or stripped. + * @return array An array of mapped values + */ + protected function _getMappedValues($values, $reversed = false, $preserve = false) + { + if (count($this->_map) == 0) { + return $values; + } + + $return = array(); + + foreach ($values as $key => $value) { + if (is_int($key) && !$reversed) { + if (array_key_exists($key, $this->_map)) { + $index = $this->_map[$key]; + } elseif (false === ($index = array_search($key, $this->_map))) { + $index = $key; + } + $return[$index] = $values[$key]; + } elseif ($reversed) { + $index = $key; + if (!is_int($key)) { + if (array_key_exists($key, $this->_map)) { + $index = $this->_map[$key]; + } else { + $index = array_search($key, $this->_map, true); + } + } + if (false !== $index) { + $return[$index] = $values[$key]; + } + } elseif ($preserve) { + $return[$key] = $value; + } + } + + return $return; + } + + /** + * Assembles a URL path defined by this route + * + * @param array $data An array of name (or index) and value pairs used as parameters + * @param boolean $reset + * @param boolean $encode + * @param boolean $partial + * @throws Zend_Controller_Router_Exception + * @return string Route path with user submitted parameters + */ + public function assemble($data = array(), $reset = false, $encode = false, $partial = false) + { + if ($this->_reverse === null) { + throw new Zend_Controller_Router_Exception('Cannot assemble. Reversed route is not specified.'); + } + + $defaultValuesMapped = $this->_getMappedValues($this->_defaults, true, false); + $matchedValuesMapped = $this->_getMappedValues($this->_values, true, false); + $dataValuesMapped = $this->_getMappedValues($data, true, false); + + // handle resets, if so requested (By null value) to do so + if (($resetKeys = array_search(null, $dataValuesMapped, true)) !== false) { + foreach ((array)$resetKeys as $resetKey) { + if (isset($matchedValuesMapped[$resetKey])) { + unset($matchedValuesMapped[$resetKey]); + unset($dataValuesMapped[$resetKey]); + } + } + } + + // merge all the data together, first defaults, then values matched, then supplied + $mergedData = $defaultValuesMapped; + $mergedData = $this->_arrayMergeNumericKeys($mergedData, $matchedValuesMapped); + $mergedData = $this->_arrayMergeNumericKeys($mergedData, $dataValuesMapped); + + if ($encode) { + foreach ($mergedData as $key => &$value) { + $value = urlencode($value); + } + } + + ksort($mergedData); + + $return = @vsprintf($this->_reverse, $mergedData); + + if ($return === false) { + throw new Zend_Controller_Router_Exception('Cannot assemble. Too few arguments?'); + } + + return $return; + } + + /** + * Return a single parameter of route's defaults + * + * @param string $name Array key of the parameter + * @return string Previously set default + */ + public function getDefault($name) + { + if (isset($this->_defaults[$name])) { + return $this->_defaults[$name]; + } + } + + /** + * Return an array of defaults + * + * @return array Route defaults + */ + public function getDefaults() + { + return $this->_defaults; + } + + /** + * Get all variables which are used by the route + * + * @return array + */ + public function getVariables() + { + $variables = array(); + + foreach ($this->_map as $key => $value) { + if (is_numeric($key)) { + $variables[] = $value; + } else { + $variables[] = $key; + } + } + + return $variables; + } + + /** + * _arrayMergeNumericKeys() - allows for a strict key (numeric's included) array_merge. + * php's array_merge() lacks the ability to merge with numeric keys. + * + * @param array $array1 + * @param array $array2 + * @return array + */ + protected function _arrayMergeNumericKeys(Array $array1, Array $array2) + { + $returnArray = $array1; + foreach ($array2 as $array2Index => $array2Value) { + $returnArray[$array2Index] = $array2Value; + } + + return $returnArray; + } +} diff --git a/library/vendor/Zend/Controller/Router/Route/Static.php b/library/vendor/Zend/Controller/Router/Route/Static.php new file mode 100644 index 0000000..86363da --- /dev/null +++ b/library/vendor/Zend/Controller/Router/Route/Static.php @@ -0,0 +1,148 @@ +defaults instanceof Zend_Config) ? $config->defaults->toArray() : array(); + + return new self($config->route, $defs); + } + + /** + * Prepares the route for mapping. + * + * @param string $route Map used to match with later submitted URL path + * @param array $defaults Defaults for map variables with keys as variable names + */ + public function __construct($route, $defaults = array()) + { + $this->_route = trim($route, self::URI_DELIMITER); + $this->_defaults = (array) $defaults; + } + + /** + * Matches a user submitted path with a previously defined route. + * Assigns and returns an array of defaults on a successful match. + * + * @param string $path Path used to match against this routing map + * @return array|false An array of assigned values or a false on a mismatch + */ + public function match($path, $partial = false) + { + if ($partial) { + if ((empty($path) && empty($this->_route)) + || (substr($path, 0, strlen($this->_route)) === $this->_route) + ) { + $this->setMatchedPath($this->_route); + + return $this->_defaults; + } + } else { + if (trim($path, self::URI_DELIMITER) == $this->_route) { + return $this->_defaults; + } + } + + return false; + } + + /** + * Assembles a URL path defined by this route + * + * @param array $data An array of variable and value pairs used as parameters + * @return string Route path with user submitted parameters + */ + public function assemble($data = array(), $reset = false, $encode = false, $partial = false) + { + return $this->_route; + } + + /** + * Return a single parameter of route's defaults + * + * @param string $name Array key of the parameter + * @return string Previously set default + */ + public function getDefault($name) + { + if (isset($this->_defaults[$name])) { + return $this->_defaults[$name]; + } + + return null; + } + + /** + * Return an array of defaults + * + * @return array Route defaults + */ + public function getDefaults() + { + return $this->_defaults; + } +} diff --git a/library/vendor/Zend/Crypt.php b/library/vendor/Zend/Crypt.php new file mode 100644 index 0000000..391a5fa --- /dev/null +++ b/library/vendor/Zend/Crypt.php @@ -0,0 +1,167 @@ +setPrime($prime); + $this->setGenerator($generator); + if ($privateKey !== null) { + $this->setPrivateKey($privateKey, $privateKeyType); + } + $this->setBigIntegerMath(); + } + + /** + * Generate own public key. If a private number has not already been + * set, one will be generated at this stage. + * + * @return Zend_Crypt_DiffieHellman + */ + public function generateKeys() + { + if (function_exists('openssl_dh_compute_key') && self::$useOpenssl !== false) { + $details = array(); + $details['p'] = $this->getPrime(); + $details['g'] = $this->getGenerator(); + if ($this->hasPrivateKey()) { + $details['priv_key'] = $this->getPrivateKey(); + } + $opensslKeyResource = openssl_pkey_new( array('dh' => $details) ); + $data = openssl_pkey_get_details($opensslKeyResource); + $this->setPrivateKey($data['dh']['priv_key'], self::BINARY); + $this->setPublicKey($data['dh']['pub_key'], self::BINARY); + } else { + // Private key is lazy generated in the absence of PHP 5.3's ext/openssl + $publicKey = $this->_math->powmod($this->getGenerator(), $this->getPrivateKey(), $this->getPrime()); + $this->setPublicKey($publicKey); + } + return $this; + } + + /** + * Setter for the value of the public number + * + * @param string $number + * @param string $type + * @throws Zend_Crypt_DiffieHellman_Exception + * @return Zend_Crypt_DiffieHellman + */ + public function setPublicKey($number, $type = self::NUMBER) + { + if ($type == self::BINARY) { + $number = $this->_math->fromBinary($number); + } + if (!preg_match("/^\d+$/", $number)) { + throw new Zend_Crypt_DiffieHellman_Exception('invalid parameter; not a positive natural number'); + } + $this->_publicKey = (string) $number; + return $this; + } + + /** + * Returns own public key for communication to the second party to this + * transaction. + * + * @param string $type + * @throws Zend_Crypt_DiffieHellman_Exception + * @return string + */ + public function getPublicKey($type = self::NUMBER) + { + if ($this->_publicKey === null) { + throw new Zend_Crypt_DiffieHellman_Exception('A public key has not yet been generated using a prior call to generateKeys()'); + } + if ($type == self::BINARY) { + return $this->_math->toBinary($this->_publicKey); + } elseif ($type == self::BTWOC) { + return $this->_math->btwoc($this->_math->toBinary($this->_publicKey)); + } + return $this->_publicKey; + } + + /** + * Compute the shared secret key based on the public key received from the + * the second party to this transaction. This should agree to the secret + * key the second party computes on our own public key. + * Once in agreement, the key is known to only to both parties. + * By default, the function expects the public key to be in binary form + * which is the typical format when being transmitted. + * + * If you need the binary form of the shared secret key, call + * getSharedSecretKey() with the optional parameter for Binary output. + * + * @param string $publicKey + * @param string $type + * @param string $output + * @throws Zend_Crypt_DiffieHellman_Exception + * @return mixed + */ + public function computeSecretKey($publicKey, $type = self::NUMBER, $output = self::NUMBER) + { + if ($type == self::BINARY) { + $publicKey = $this->_math->fromBinary($publicKey); + } + if (!preg_match("/^\d+$/", $publicKey)) { + throw new Zend_Crypt_DiffieHellman_Exception('invalid parameter; not a positive natural number'); + } + if (function_exists('openssl_dh_compute_key') && self::$useOpenssl !== false) { + $this->_secretKey = openssl_dh_compute_key($publicKey, $this->getPublicKey()); + } else { + $this->_secretKey = $this->_math->powmod($publicKey, $this->getPrivateKey(), $this->getPrime()); + } + return $this->getSharedSecretKey($output); + } + + /** + * Return the computed shared secret key from the DiffieHellman transaction + * + * @param string $type + * @throws Zend_Crypt_DiffieHellman_Exception + * @return string + */ + public function getSharedSecretKey($type = self::NUMBER) + { + if (!isset($this->_secretKey)) { + throw new Zend_Crypt_DiffieHellman_Exception('A secret key has not yet been computed; call computeSecretKey()'); + } + if ($type == self::BINARY) { + return $this->_math->toBinary($this->_secretKey); + } elseif ($type == self::BTWOC) { + return $this->_math->btwoc($this->_math->toBinary($this->_secretKey)); + } + return $this->_secretKey; + } + + /** + * Setter for the value of the prime number + * + * @param string $number + * @throws Zend_Crypt_DiffieHellman_Exception + * @return Zend_Crypt_DiffieHellman + */ + public function setPrime($number) + { + if (!preg_match("/^\d+$/", $number) || $number < 11) { + throw new Zend_Crypt_DiffieHellman_Exception('invalid parameter; not a positive natural number or too small: should be a large natural number prime'); + } + $this->_prime = (string) $number; + return $this; + } + + /** + * Getter for the value of the prime number + * + * @throws Zend_Crypt_DiffieHellman_Exception + * @return string + */ + public function getPrime() + { + if (!isset($this->_prime)) { + throw new Zend_Crypt_DiffieHellman_Exception('No prime number has been set'); + } + return $this->_prime; + } + + /** + * Setter for the value of the generator number + * + * @param string $number + * @throws Zend_Crypt_DiffieHellman_Exception + * @return Zend_Crypt_DiffieHellman + */ + public function setGenerator($number) + { + if (!preg_match("/^\d+$/", $number) || $number < 2) { + throw new Zend_Crypt_DiffieHellman_Exception('invalid parameter; not a positive natural number greater than 1'); + } + $this->_generator = (string) $number; + return $this; + } + + /** + * Getter for the value of the generator number + * + * @throws Zend_Crypt_DiffieHellman_Exception + * @return string + */ + public function getGenerator() + { + if (!isset($this->_generator)) { + throw new Zend_Crypt_DiffieHellman_Exception('No generator number has been set'); + } + return $this->_generator; + } + + /** + * Setter for the value of the private number + * + * @param string $number + * @param string $type + * @throws Zend_Crypt_DiffieHellman_Exception + * @return Zend_Crypt_DiffieHellman + */ + public function setPrivateKey($number, $type = self::NUMBER) + { + if ($type == self::BINARY) { + $number = $this->_math->fromBinary($number); + } + if (!preg_match("/^\d+$/", $number)) { + throw new Zend_Crypt_DiffieHellman_Exception('invalid parameter; not a positive natural number'); + } + $this->_privateKey = (string) $number; + return $this; + } + + /** + * Getter for the value of the private number + * + * @param string $type + * @return string + */ + public function getPrivateKey($type = self::NUMBER) + { + if (!$this->hasPrivateKey()) { + $this->setPrivateKey($this->_generatePrivateKey(), self::BINARY); + } + if ($type == self::BINARY) { + return $this->_math->toBinary($this->_privateKey); + } elseif ($type == self::BTWOC) { + return $this->_math->btwoc($this->_math->toBinary($this->_privateKey)); + } + return $this->_privateKey; + } + + /** + * Check whether a private key currently exists. + * + * @return boolean + */ + public function hasPrivateKey() + { + return isset($this->_privateKey); + } + + /** + * Setter to pass an extension parameter which is used to create + * a specific BigInteger instance for a specific extension type. + * Allows manual setting of the class in case of an extension + * problem or bug. + * + * @param string $extension + * @return void + */ + public function setBigIntegerMath($extension = null) + { + /** + * @see Zend_Crypt_Math + */ + $this->_math = new Zend_Crypt_Math($extension); + } + + /** + * In the event a private number/key has not been set by the user, + * or generated by ext/openssl, a best attempt will be made to + * generate a random key. Having a random number generator installed + * on linux/bsd is highly recommended! The alternative is not recommended + * for production unless without any other option. + * + * @return string + */ + protected function _generatePrivateKey() + { + $rand = $this->_math->rand($this->getGenerator(), $this->getPrime()); + return $rand; + } + +} diff --git a/library/vendor/Zend/Crypt/DiffieHellman/Exception.php b/library/vendor/Zend/Crypt/DiffieHellman/Exception.php new file mode 100644 index 0000000..7a84526 --- /dev/null +++ b/library/vendor/Zend/Crypt/DiffieHellman/Exception.php @@ -0,0 +1,35 @@ +80 using internal algo) + * @todo Check if mhash() is a required alternative (will be PECL-only soon) + * @category Zend + * @package Zend_Crypt + * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +class Zend_Crypt_Hmac extends Zend_Crypt +{ + + /** + * The key to use for the hash + * + * @var string + */ + protected static $_key = null; + + /** + * pack() format to be used for current hashing method + * + * @var string + */ + protected static $_packFormat = null; + + /** + * Hashing algorithm; can be the md5/sha1 functions or any algorithm name + * listed in the output of PHP 5.1.2+ hash_algos(). + * + * @var string + */ + protected static $_hashAlgorithm = 'md5'; + + /** + * List of algorithms supported my mhash() + * + * @var array + */ + protected static $_supportedMhashAlgorithms = array('adler32',' crc32', 'crc32b', 'gost', + 'haval128', 'haval160', 'haval192', 'haval256', 'md4', 'md5', 'ripemd160', + 'sha1', 'sha256', 'tiger', 'tiger128', 'tiger160'); + + /** + * Constants representing the output mode of the hash algorithm + */ + const STRING = 'string'; + const BINARY = 'binary'; + + /** + * Performs a HMAC computation given relevant details such as Key, Hashing + * algorithm, the data to compute MAC of, and an output format of String, + * Binary notation or BTWOC. + * + * @param string $key + * @param string $hash + * @param string $data + * @param string $output + * @throws Zend_Crypt_Hmac_Exception + * @return string + */ + public static function compute($key, $hash, $data, $output = self::STRING) + { + // set the key + if (!isset($key) || empty($key)) { + throw new Zend_Crypt_Hmac_Exception('provided key is null or empty'); + } + self::$_key = $key; + + // set the hash + self::_setHashAlgorithm($hash); + + // perform hashing and return + return self::_hash($data, $output); + } + + /** + * Setter for the hash method. + * + * @param string $hash + * @throws Zend_Crypt_Hmac_Exception + * @return Zend_Crypt_Hmac + */ + protected static function _setHashAlgorithm($hash) + { + if (!isset($hash) || empty($hash)) { + throw new Zend_Crypt_Hmac_Exception('provided hash string is null or empty'); + } + + $hash = strtolower($hash); + $hashSupported = false; + + if (function_exists('hash_algos') && in_array($hash, hash_algos())) { + $hashSupported = true; + } + + if ($hashSupported === false && function_exists('mhash') && in_array($hash, self::$_supportedAlgosMhash)) { + $hashSupported = true; + } + + if ($hashSupported === false) { + throw new Zend_Crypt_Hmac_Exception('hash algorithm provided is not supported on this PHP installation; please enable the hash or mhash extensions'); + } + self::$_hashAlgorithm = $hash; + } + + /** + * Perform HMAC and return the keyed data + * + * @param string $data + * @param string $output + * @param bool $internal Option to not use hash() functions for testing + * @return string + */ + protected static function _hash($data, $output = self::STRING, $internal = false) + { + if (function_exists('hash_hmac')) { + if ($output == self::BINARY) { + return hash_hmac(self::$_hashAlgorithm, $data, self::$_key, true); + } + return hash_hmac(self::$_hashAlgorithm, $data, self::$_key); + } + + if (function_exists('mhash')) { + if ($output == self::BINARY) { + return mhash(self::_getMhashDefinition(self::$_hashAlgorithm), $data, self::$_key); + } + $bin = mhash(self::_getMhashDefinition(self::$_hashAlgorithm), $data, self::$_key); + return bin2hex($bin); + } + } + + /** + * Since MHASH accepts an integer constant representing the hash algorithm + * we need to make a small detour to get the correct integer matching our + * algorithm's name. + * + * @param string $hashAlgorithm + * @return integer + */ + protected static function _getMhashDefinition($hashAlgorithm) + { + for ($i = 0; $i <= mhash_count(); $i++) + { + $types[mhash_get_hash_name($i)] = $i; + } + return $types[strtoupper($hashAlgorithm)]; + } + +} diff --git a/library/vendor/Zend/Crypt/Hmac/Exception.php b/library/vendor/Zend/Crypt/Hmac/Exception.php new file mode 100644 index 0000000..9f266e0 --- /dev/null +++ b/library/vendor/Zend/Crypt/Hmac/Exception.php @@ -0,0 +1,35 @@ + $max) { + throw new Zend_Crypt_Exception( + 'The min parameter must be lower than max parameter' + ); + } + $range = $max - $min; + if ($range == 0) { + return $max; + } elseif ($range > PHP_INT_MAX || is_float($range)) { + throw new Zend_Crypt_Exception( + 'The supplied range is too great to generate' + ); + } + if (function_exists('random_int')) { // available in PHP 7 + return random_int($min, $max); + } + // calculate number of bits required to store range on this machine + $r = $range; + $bits = 0; + while ($r) { + $bits++; + $r >>= 1; + } + $bits = (int) max($bits, 1); + $bytes = (int) max(ceil($bits / 8), 1); + $filter = (int) ((1 << $bits) - 1); + do { + $rnd = hexdec(bin2hex(self::randBytes($bytes, $strong))); + $rnd &= $filter; + } while ($rnd > $range); + return ($min + $rnd); + } + + /** + * Get the big endian two's complement of a given big integer in + * binary notation + * + * @param string $long + * @return string + */ + public function btwoc($long) + { + if (ord($long[0]) > 127) { + return "\x00" . $long; + } + return $long; + } + + /** + * Translate a binary form into a big integer string + * + * @param string $binary + * @return string + */ + public function fromBinary($binary) + { + return $this->_math->binaryToInteger($binary); + } + + /** + * Translate a big integer string into a binary form + * + * @param string $integer + * @return string + */ + public function toBinary($integer) + { + return $this->_math->integerToBinary($integer); + } +} diff --git a/library/vendor/Zend/Crypt/Math/BigInteger.php b/library/vendor/Zend/Crypt/Math/BigInteger.php new file mode 100644 index 0000000..0b98cec --- /dev/null +++ b/library/vendor/Zend/Crypt/Math/BigInteger.php @@ -0,0 +1,113 @@ +_loadAdapter($extension); + } + + /** + * Redirect all public method calls to the wrapped extension object. + * + * @param string $methodName + * @param array $args + * @return mixed + * @throws Zend_Crypt_Math_BigInteger_Exception + */ + public function __call($methodName, $args) + { + if(!method_exists($this->_math, $methodName)) { + throw new Zend_Crypt_Math_BigInteger_Exception('invalid method call: ' . get_class($this->_math) . '::' . $methodName . '() does not exist'); + } + return call_user_func_array(array($this->_math, $methodName), $args); + } + + /** + * @param string $extension + * @throws Zend_Crypt_Math_BigInteger_Exception + */ + protected function _loadAdapter($extension = null) + { + if ($extension === null) { + if (extension_loaded('gmp')) { + $extension = 'gmp'; + //} elseif (extension_loaded('big_int')) { + // $extension = 'big_int'; + } else { + $extension = 'bcmath'; + } + } + if($extension == 'gmp' && extension_loaded('gmp')) { + $this->_math = new Zend_Crypt_Math_BigInteger_Gmp(); + //} elseif($extension == 'bigint' && extension_loaded('big_int')) { + // require_once 'Zend/Crypt_Math/BigInteger/Bigint.php'; + // $this->_math = new Zend_Crypt_Math_BigInteger_Bigint(); + } elseif ($extension == 'bcmath' && extension_loaded('bcmath')) { + $this->_math = new Zend_Crypt_Math_BigInteger_Bcmath(); + } else { + throw new Zend_Crypt_Math_BigInteger_Exception($extension . ' big integer precision math support not detected'); + } + } + +} diff --git a/library/vendor/Zend/Crypt/Math/BigInteger/Bcmath.php b/library/vendor/Zend/Crypt/Math/BigInteger/Bcmath.php new file mode 100644 index 0000000..2fb4a67 --- /dev/null +++ b/library/vendor/Zend/Crypt/Math/BigInteger/Bcmath.php @@ -0,0 +1,226 @@ + 0) { + $return = chr(bcmod($operand, 256)) . $return; + $operand = bcdiv($operand, 256); + } + if (ord($return[0]) > 127) { + $return = "\0" . $return; + } + return $return; + } + + /**public function integerToBinary($operand) + { + $return = ''; + while(bccomp($operand, '0')) { + $return .= chr(bcmod($operand, '256')); + $operand = bcdiv($operand, '256'); + } + return $return; + }**/ // Prior version for referenced offset + + /** + * @param string $operand + * @return string + */ + public function hexToDecimal($operand) + { + $return = '0'; + while(strlen($hex)) { + $hex = hexdec(substr($operand, 0, 4)); + $dec = bcadd(bcmul($return, 65536), $hex); + $operand = substr($operand, 4); + } + return $return; + } +} diff --git a/library/vendor/Zend/Crypt/Math/BigInteger/Exception.php b/library/vendor/Zend/Crypt/Math/BigInteger/Exception.php new file mode 100644 index 0000000..c1c865d --- /dev/null +++ b/library/vendor/Zend/Crypt/Math/BigInteger/Exception.php @@ -0,0 +1,35 @@ + '7') { + $bigInt = '00' . $bigInt; + } + $return = pack("H*", $bigInt); + return $return; + } + + /** + * @param string $operand + * @return string + */ + public function hexToDecimal($operand) + { + $return = '0'; + while(strlen($hex)) { + $hex = hexdec(substr($operand, 0, 4)); + $dec = gmp_add(gmp_mul($return, 65536), $hex); + $operand = substr($operand, 4); + } + return $return; + } + +} diff --git a/library/vendor/Zend/Crypt/Math/BigInteger/Interface.php b/library/vendor/Zend/Crypt/Math/BigInteger/Interface.php new file mode 100644 index 0000000..9fa9281 --- /dev/null +++ b/library/vendor/Zend/Crypt/Math/BigInteger/Interface.php @@ -0,0 +1,51 @@ +_hashAlgorithm = OPENSSL_ALGO_SHA1; + + if (isset($options)) { + $this->setOptions($options); + } + } + + public function setOptions(array $options) + { + if (isset($options['passPhrase'])) { + $this->_passPhrase = $options['passPhrase']; + } + foreach ($options as $option=>$value) { + switch ($option) { + case 'pemString': + $this->setPemString($value); + break; + case 'pemPath': + $this->setPemPath($value); + break; + case 'certificateString': + $this->setCertificateString($value); + break; + case 'certificatePath': + $this->setCertificatePath($value); + break; + case 'hashAlgorithm': + $this->setHashAlgorithm($value); + break; + } + } + } + + public function getPrivateKey() + { + return $this->_privateKey; + } + + public function getPublicKey() + { + return $this->_publicKey; + } + + /** + * @param string $data + * @param Zend_Crypt_Rsa_Key_Private $privateKey + * @param string $format + * @return string + */ + public function sign($data, Zend_Crypt_Rsa_Key_Private $privateKey = null, $format = null) + { + $signature = ''; + if (isset($privateKey)) { + $opensslKeyResource = $privateKey->getOpensslKeyResource(); + } else { + $opensslKeyResource = $this->_privateKey->getOpensslKeyResource(); + } + $result = openssl_sign( + $data, $signature, + $opensslKeyResource, + $this->getHashAlgorithm() + ); + if ($format == self::BASE64) { + return base64_encode($signature); + } + return $signature; + } + + /** + * @param string $data + * @param string $signature + * @param string $format + * @return string + */ + public function verifySignature($data, $signature, $format = null) + { + if ($format == self::BASE64) { + $signature = base64_decode($signature); + } + $result = openssl_verify($data, $signature, + $this->getPublicKey()->getOpensslKeyResource(), + $this->getHashAlgorithm()); + return $result; + } + + /** + * @param string $data + * @param Zend_Crypt_Rsa_Key $key + * @param string $format + * @return string + */ + public function encrypt($data, Zend_Crypt_Rsa_Key $key, $format = null) + { + $encrypted = ''; + $function = 'openssl_public_encrypt'; + if ($key instanceof Zend_Crypt_Rsa_Key_Private) { + $function = 'openssl_private_encrypt'; + } + $function($data, $encrypted, $key->getOpensslKeyResource()); + if ($format == self::BASE64) { + return base64_encode($encrypted); + } + return $encrypted; + } + + /** + * @param string $data + * @param Zend_Crypt_Rsa_Key $key + * @param string $format + * @return string + */ + public function decrypt($data, Zend_Crypt_Rsa_Key $key, $format = null) + { + $decrypted = ''; + if ($format == self::BASE64) { + $data = base64_decode($data); + } + $function = 'openssl_private_decrypt'; + if ($key instanceof Zend_Crypt_Rsa_Key_Public) { + $function = 'openssl_public_decrypt'; + } + $function($data, $decrypted, $key->getOpensslKeyResource()); + return $decrypted; + } + + /** + * @param array $configargs + * + * @throws Zend_Crypt_Rsa_Exception + * + * @return ArrayObject + */ + public function generateKeys(array $configargs = null) + { + $config = null; + $passPhrase = null; + if ($configargs !== null) { + if (isset($configargs['passPhrase'])) { + $passPhrase = $configargs['passPhrase']; + unset($configargs['passPhrase']); + } + $config = $this->_parseConfigArgs($configargs); + } + $privateKey = null; + $publicKey = null; + $resource = openssl_pkey_new($config); + if (!$resource) { + throw new Zend_Crypt_Rsa_Exception('Failed to generate a new private key'); + } + // above fails on PHP 5.3 + openssl_pkey_export($resource, $private, $passPhrase); + $privateKey = new Zend_Crypt_Rsa_Key_Private($private, $passPhrase); + $details = openssl_pkey_get_details($resource); + $publicKey = new Zend_Crypt_Rsa_Key_Public($details['key']); + $return = new ArrayObject(array( + 'privateKey'=>$privateKey, + 'publicKey'=>$publicKey + ), ArrayObject::ARRAY_AS_PROPS); + return $return; + } + + /** + * @param string $value + */ + public function setPemString($value) + { + $this->_pemString = $value; + try { + $this->_privateKey = new Zend_Crypt_Rsa_Key_Private($this->_pemString, $this->_passPhrase); + $this->_publicKey = $this->_privateKey->getPublicKey(); + } catch (Zend_Crypt_Exception $e) { + $this->_privateKey = null; + $this->_publicKey = new Zend_Crypt_Rsa_Key_Public($this->_pemString); + } + } + + public function setPemPath($value) + { + $this->_pemPath = $value; + $this->setPemString(file_get_contents($this->_pemPath)); + } + + public function setCertificateString($value) + { + $this->_certificateString = $value; + $this->_publicKey = new Zend_Crypt_Rsa_Key_Public($this->_certificateString, $this->_passPhrase); + } + + public function setCertificatePath($value) + { + $this->_certificatePath = $value; + $this->setCertificateString(file_get_contents($this->_certificatePath)); + } + + public function setHashAlgorithm($name) + { + switch (strtolower($name)) { + case 'md2': + $this->_hashAlgorithm = OPENSSL_ALGO_MD2; + break; + case 'md4': + $this->_hashAlgorithm = OPENSSL_ALGO_MD4; + break; + case 'md5': + $this->_hashAlgorithm = OPENSSL_ALGO_MD5; + break; + case 'sha1': + $this->_hashAlgorithm = OPENSSL_ALGO_SHA1; + break; + case 'dss1': + $this->_hashAlgorithm = OPENSSL_ALGO_DSS1; + break; + } + } + + /** + * @return string + */ + public function getPemString() + { + return $this->_pemString; + } + + public function getPemPath() + { + return $this->_pemPath; + } + + public function getCertificateString() + { + return $this->_certificateString; + } + + public function getCertificatePath() + { + return $this->_certificatePath; + } + + public function getHashAlgorithm() + { + return $this->_hashAlgorithm; + } + + protected function _parseConfigArgs(array $config = null) + { + $configs = array(); + if (isset($config['private_key_bits'])) { + $configs['private_key_bits'] = $config['private_key_bits']; + } + if (isset($config['privateKeyBits'])) { + $configs['private_key_bits'] = $config['privateKeyBits']; + } + if (!empty($configs)) { + return $configs; + } + return null; + } + +} diff --git a/library/vendor/Zend/Crypt/Rsa/Exception.php b/library/vendor/Zend/Crypt/Rsa/Exception.php new file mode 100644 index 0000000..3b3944f --- /dev/null +++ b/library/vendor/Zend/Crypt/Rsa/Exception.php @@ -0,0 +1,35 @@ +_opensslKeyResource; + } + + /** + * @return string + * @throws Zend_Crypt_Exception + */ + public function toString() + { + if (!empty($this->_pemString)) { + return $this->_pemString; + } elseif (!empty($this->_certificateString)) { + return $this->_certificateString; + } + /** + * @see Zend_Crypt_Exception + */ + throw new Zend_Crypt_Exception('No public key string representation is available'); + } + + /** + * @return string + */ + public function __toString() + { + return $this->toString(); + } + + public function count() + { + return $this->_details['bits']; + } + + public function getType() + { + return $this->_details['type']; + } +} diff --git a/library/vendor/Zend/Crypt/Rsa/Key/Private.php b/library/vendor/Zend/Crypt/Rsa/Key/Private.php new file mode 100644 index 0000000..b736b58 --- /dev/null +++ b/library/vendor/Zend/Crypt/Rsa/Key/Private.php @@ -0,0 +1,72 @@ +_pemString = $pemString; + $this->_parse($passPhrase); + } + + /** + * @param string $passPhrase + * @throws Zend_Crypt_Exception + */ + protected function _parse($passPhrase) + { + $result = openssl_get_privatekey($this->_pemString, $passPhrase); + if (!$result) { + /** + * @see Zend_Crypt_Exception + */ + throw new Zend_Crypt_Exception('Unable to load private key'); + } + $this->_opensslKeyResource = $result; + $this->_details = openssl_pkey_get_details($this->_opensslKeyResource); + } + + public function getPublicKey() + { + if ($this->_publicKey === null) { + /** + * @see Zend_Crypt_Rsa_Key_Public + */ + $this->_publicKey = new Zend_Crypt_Rsa_Key_Public($this->_details['key']); + } + return $this->_publicKey; + } + +} diff --git a/library/vendor/Zend/Crypt/Rsa/Key/Public.php b/library/vendor/Zend/Crypt/Rsa/Key/Public.php new file mode 100644 index 0000000..85b2eb6 --- /dev/null +++ b/library/vendor/Zend/Crypt/Rsa/Key/Public.php @@ -0,0 +1,72 @@ +_parse($string); + } + + /** + * @param string $string + * @throws Zend_Crypt_Exception + */ + protected function _parse($string) + { + if (preg_match("/^-----BEGIN CERTIFICATE-----/", $string)) { + $this->_certificateString = $string; + } else { + $this->_pemString = $string; + } + $result = openssl_get_publickey($string); + if (!$result) { + /** + * @see Zend_Crypt_Exception + */ + throw new Zend_Crypt_Exception('Unable to load public key'); + } + //openssl_pkey_export($result, $public); + //$this->_pemString = $public; + $this->_opensslKeyResource = $result; + $this->_details = openssl_pkey_get_details($this->_opensslKeyResource); + } + + public function getCertificate() + { + return $this->_certificateString; + } + +} diff --git a/library/vendor/Zend/Date.php b/library/vendor/Zend/Date.php new file mode 100644 index 0000000..6223f36 --- /dev/null +++ b/library/vendor/Zend/Date.php @@ -0,0 +1,4872 @@ + 'iso', // format for date strings 'iso' or 'php' + 'fix_dst' => true, // fix dst on summer/winter time change + 'extend_month' => false, // false - addMonth like SQL, true like excel + 'cache' => null, // cache to set + 'timesync' => null // timesync server to set + ); + + // Class wide Date Constants + const DAY = 'dd'; + const DAY_SHORT = 'd'; + const DAY_SUFFIX = 'SS'; + const DAY_OF_YEAR = 'D'; + const WEEKDAY = 'EEEE'; + const WEEKDAY_SHORT = 'EEE'; + const WEEKDAY_NARROW = 'E'; + const WEEKDAY_NAME = 'EE'; + const WEEKDAY_8601 = 'eee'; + const WEEKDAY_DIGIT = 'e'; + const WEEK = 'ww'; + const MONTH = 'MM'; + const MONTH_SHORT = 'M'; + const MONTH_DAYS = 'ddd'; + const MONTH_NAME = 'MMMM'; + const MONTH_NAME_SHORT = 'MMM'; + const MONTH_NAME_NARROW = 'MMMMM'; + const YEAR = 'y'; + const YEAR_SHORT = 'yy'; + const YEAR_8601 = 'Y'; + const YEAR_SHORT_8601 = 'YY'; + const LEAPYEAR = 'l'; + const MERIDIEM = 'a'; + const SWATCH = 'B'; + const HOUR = 'HH'; + const HOUR_SHORT = 'H'; + const HOUR_AM = 'hh'; + const HOUR_SHORT_AM = 'h'; + const MINUTE = 'mm'; + const MINUTE_SHORT = 'm'; + const SECOND = 'ss'; + const SECOND_SHORT = 's'; + const MILLISECOND = 'S'; + const TIMEZONE_NAME = 'zzzz'; + const DAYLIGHT = 'I'; + const GMT_DIFF = 'Z'; + const GMT_DIFF_SEP = 'ZZZZ'; + const TIMEZONE = 'z'; + const TIMEZONE_SECS = 'X'; + const ISO_8601 = 'c'; + const RFC_2822 = 'r'; + const TIMESTAMP = 'U'; + const ERA = 'G'; + const ERA_NAME = 'GGGG'; + const ERA_NARROW = 'GGGGG'; + const DATES = 'F'; + const DATE_FULL = 'FFFFF'; + const DATE_LONG = 'FFFF'; + const DATE_MEDIUM = 'FFF'; + const DATE_SHORT = 'FF'; + const TIMES = 'WW'; + const TIME_FULL = 'TTTTT'; + const TIME_LONG = 'TTTT'; + const TIME_MEDIUM = 'TTT'; + const TIME_SHORT = 'TT'; + const DATETIME = 'K'; + const DATETIME_FULL = 'KKKKK'; + const DATETIME_LONG = 'KKKK'; + const DATETIME_MEDIUM = 'KKK'; + const DATETIME_SHORT = 'KK'; + const ATOM = 'OOO'; + const COOKIE = 'CCC'; + const RFC_822 = 'R'; + const RFC_850 = 'RR'; + const RFC_1036 = 'RRR'; + const RFC_1123 = 'RRRR'; + const RFC_3339 = 'RRRRR'; + const RSS = 'SSS'; + const W3C = 'WWW'; + + /** + * Generates the standard date object, could be a unix timestamp, localized date, + * string, integer, array and so on. Also parts of dates or time are supported + * Always set the default timezone: http://php.net/date_default_timezone_set + * For example, in your bootstrap: date_default_timezone_set('America/Los_Angeles'); + * For detailed instructions please look in the docu. + * + * @param string|integer|Zend_Date|array $date OPTIONAL Date value or value of date part to set + * ,depending on $part. If null the actual time is set + * @param string $part OPTIONAL Defines the input format of $date + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date + * @throws Zend_Date_Exception + */ + public function __construct($date = null, $part = null, $locale = null) + { + if (is_object($date) and !($date instanceof Zend_TimeSync_Protocol) and + !($date instanceof Zend_Date)) { + if ($locale instanceof Zend_Locale) { + $locale = $date; + $date = null; + $part = null; + } else { + $date = (string) $date; + } + } + + if (($date !== null) and !is_array($date) and !($date instanceof Zend_TimeSync_Protocol) and + !($date instanceof Zend_Date) and !defined($date) and Zend_Locale::isLocale($date, true, false)) { + $locale = $date; + $date = null; + $part = null; + } else if (($part !== null) and !defined($part) and Zend_Locale::isLocale($part, true, false)) { + $locale = $part; + $part = null; + } + + $this->setLocale($locale); + if (is_string($date) && ($part === null) && (strlen($date) <= 5)) { + $part = $date; + $date = null; + } + + if ($date === null) { + if ($part === null) { + $date = time(); + } else if ($part !== self::TIMESTAMP) { + $date = self::now($locale); + $date = $date->get($part); + } + } + + if ($date instanceof Zend_TimeSync_Protocol) { + $date = $date->getInfo(); + $date = $this->_getTime($date['offset']); + $part = null; + } else if (parent::$_defaultOffset != 0) { + $date = $this->_getTime(parent::$_defaultOffset); + } + + // set the timezone and offset for $this + $zone = @date_default_timezone_get(); + $this->setTimezone($zone); + + // try to get timezone from date-string + if (!is_int($date)) { + $zone = $this->getTimezoneFromString($date); + $this->setTimezone($zone); + } + + // set datepart + if (($part !== null && $part !== self::TIMESTAMP) or (!is_numeric($date))) { + // switch off dst handling for value setting + $this->setUnixTimestamp($this->getGmtOffset()); + $this->set($date, $part, $this->_locale); + + // DST fix + if (is_array($date) === true) { + if (!isset($date['hour'])) { + $date['hour'] = 0; + } + + $hour = $this->toString('H', 'iso', true); + $hour = $date['hour'] - $hour; + switch ($hour) { + case 1 : + case -23 : + $this->addTimestamp(3600); + break; + case -1 : + case 23 : + $this->subTimestamp(3600); + break; + case 2 : + case -22 : + $this->addTimestamp(7200); + break; + case -2 : + case 22 : + $this->subTimestamp(7200); + break; + } + } + } else { + $this->setUnixTimestamp($date); + } + } + + /** + * Sets class wide options, if no option was given, the actual set options will be returned + * + * @param array $options Options to set + * @throws Zend_Date_Exception + * @return Options array if no option was given + */ + public static function setOptions(array $options = array()) + { + if (empty($options)) { + return self::$_options; + } + + foreach ($options as $name => $value) { + $name = strtolower($name); + + if (array_key_exists($name, self::$_options)) { + switch($name) { + case 'format_type' : + if ((strtolower($value) != 'php') && (strtolower($value) != 'iso')) { + throw new Zend_Date_Exception("Unknown format type ($value) for dates, only 'iso' and 'php' supported", 0, null, $value); + } + break; + case 'fix_dst' : + if (!is_bool($value)) { + throw new Zend_Date_Exception("'fix_dst' has to be boolean", 0, null, $value); + } + break; + case 'extend_month' : + if (!is_bool($value)) { + throw new Zend_Date_Exception("'extend_month' has to be boolean", 0, null, $value); + } + break; + case 'cache' : + if ($value === null) { + parent::$_cache = null; + } else { + if (!$value instanceof Zend_Cache_Core) { + throw new Zend_Date_Exception("Instance of Zend_Cache expected"); + } + + parent::$_cache = $value; + parent::$_cacheTags = Zend_Date_DateObject::_getTagSupportForCache(); + Zend_Locale_Data::setCache($value); + } + break; + case 'timesync' : + if ($value === null) { + parent::$_defaultOffset = 0; + } else { + if (!$value instanceof Zend_TimeSync_Protocol) { + throw new Zend_Date_Exception("Instance of Zend_TimeSync expected"); + } + + $date = $value->getInfo(); + parent::$_defaultOffset = $date['offset']; + } + break; + } + self::$_options[$name] = $value; + } + else { + throw new Zend_Date_Exception("Unknown option: $name = $value"); + } + } + } + + /** + * Returns this object's internal UNIX timestamp (equivalent to Zend_Date::TIMESTAMP). + * If the timestamp is too large for integers, then the return value will be a string. + * This function does not return the timestamp as an object. + * Use clone() or copyPart() instead. + * + * @return integer|string UNIX timestamp + */ + public function getTimestamp() + { + return $this->getUnixTimestamp(); + } + + /** + * Returns the calculated timestamp + * HINT: timestamps are always GMT + * + * @param string $calc Type of calculation to make + * @param string|integer|array|Zend_Date $stamp Timestamp to calculate, when null the actual timestamp is calculated + * @return Zend_Date|integer + * @throws Zend_Date_Exception + */ + private function _timestamp($calc, $stamp) + { + if ($stamp instanceof Zend_Date) { + // extract timestamp from object + $stamp = $stamp->getTimestamp(); + } + + if (is_array($stamp)) { + if (isset($stamp['timestamp']) === true) { + $stamp = $stamp['timestamp']; + } else { + throw new Zend_Date_Exception('no timestamp given in array'); + } + } + + if ($calc === 'set') { + $return = $this->setUnixTimestamp($stamp); + } else { + $return = $this->_calcdetail($calc, $stamp, self::TIMESTAMP, null); + } + if ($calc != 'cmp') { + return $this; + } + return $return; + } + + /** + * Sets a new timestamp + * + * @param integer|string|array|Zend_Date $timestamp Timestamp to set + * @return Zend_Date Provides a fluent interface + * @throws Zend_Date_Exception + */ + public function setTimestamp($timestamp) + { + return $this->_timestamp('set', $timestamp); + } + + /** + * Adds a timestamp + * + * @param integer|string|array|Zend_Date $timestamp Timestamp to add + * @return Zend_Date Provides a fluent interface + * @throws Zend_Date_Exception + */ + public function addTimestamp($timestamp) + { + return $this->_timestamp('add', $timestamp); + } + + /** + * Subtracts a timestamp + * + * @param integer|string|array|Zend_Date $timestamp Timestamp to sub + * @return Zend_Date Provides a fluent interface + * @throws Zend_Date_Exception + */ + public function subTimestamp($timestamp) + { + return $this->_timestamp('sub', $timestamp); + } + + /** + * Compares two timestamps, returning the difference as integer + * + * @param integer|string|array|Zend_Date $timestamp Timestamp to compare + * @return integer 0 = equal, 1 = later, -1 = earlier + * @throws Zend_Date_Exception + */ + public function compareTimestamp($timestamp) + { + return $this->_timestamp('cmp', $timestamp); + } + + /** + * Returns a string representation of the object + * Supported format tokens are: + * G - era, y - year, Y - ISO year, M - month, w - week of year, D - day of year, d - day of month + * E - day of week, e - number of weekday (1-7), h - hour 1-12, H - hour 0-23, m - minute, s - second + * A - milliseconds of day, z - timezone, Z - timezone offset, S - fractional second, a - period of day + * + * Additionally format tokens but non ISO conform are: + * SS - day suffix, eee - php number of weekday(0-6), ddd - number of days per month + * l - Leap year, B - swatch internet time, I - daylight saving time, X - timezone offset in seconds + * r - RFC2822 format, U - unix timestamp + * + * Not supported ISO tokens are + * u - extended year, Q - quarter, q - quarter, L - stand alone month, W - week of month + * F - day of week of month, g - modified julian, c - stand alone weekday, k - hour 0-11, K - hour 1-24 + * v - wall zone + * + * @param string $format OPTIONAL Rule for formatting output. If null the default date format is used + * @param string $type OPTIONAL Type for the format string which overrides the standard setting + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return string + */ + public function toString($format = null, $type = null, $locale = null) + { + if (is_object($format)) { + if ($format instanceof Zend_Locale) { + $locale = $format; + $format = null; + } else { + $format = (string) $format; + } + } + + if (is_object($type)) { + if ($type instanceof Zend_Locale) { + $locale = $type; + $type = null; + } else { + $type = (string) $type; + } + } + + if (($format !== null) && !defined($format) + && ($format != 'ee') && ($format != 'ss') && ($format != 'GG') && ($format != 'MM') && ($format != 'EE') && ($format != 'TT') + && Zend_Locale::isLocale($format, null, false)) { + $locale = $format; + $format = null; + } + + if (($type !== null) and ($type != 'php') and ($type != 'iso') and + Zend_Locale::isLocale($type, null, false)) { + $locale = $type; + $type = null; + } + + if ($locale === null) { + $locale = $this->getLocale(); + } + + if ($format === null) { + $format = Zend_Locale_Format::getDateFormat($locale) . ' ' . Zend_Locale_Format::getTimeFormat($locale); + } else if (((self::$_options['format_type'] == 'php') && ($type === null)) or ($type == 'php')) { + $format = Zend_Locale_Format::convertPhpToIsoFormat($format); + } + + return $this->date($this->_toToken($format, $locale), $this->getUnixTimestamp(), false); + } + + /** + * Returns a string representation of the date which is equal with the timestamp + * + * @return string + */ + public function __toString() + { + return $this->toString(null, $this->_locale); + } + + /** + * Returns a integer representation of the object + * But returns false when the given part is no value f.e. Month-Name + * + * @param string|integer|Zend_Date $part OPTIONAL Defines the date or datepart to return as integer + * @return integer|false + */ + public function toValue($part = null) + { + $result = $this->get($part); + if (is_numeric($result)) { + return intval("$result"); + } else { + return false; + } + } + + /** + * Returns an array representation of the object + * + * @return array + */ + public function toArray() + { + return array('day' => $this->toString(self::DAY_SHORT, 'iso'), + 'month' => $this->toString(self::MONTH_SHORT, 'iso'), + 'year' => $this->toString(self::YEAR, 'iso'), + 'hour' => $this->toString(self::HOUR_SHORT, 'iso'), + 'minute' => $this->toString(self::MINUTE_SHORT, 'iso'), + 'second' => $this->toString(self::SECOND_SHORT, 'iso'), + 'timezone' => $this->toString(self::TIMEZONE, 'iso'), + 'timestamp' => $this->toString(self::TIMESTAMP, 'iso'), + 'weekday' => $this->toString(self::WEEKDAY_8601, 'iso'), + 'dayofyear' => $this->toString(self::DAY_OF_YEAR, 'iso'), + 'week' => $this->toString(self::WEEK, 'iso'), + 'gmtsecs' => $this->toString(self::TIMEZONE_SECS, 'iso')); + } + + /** + * Returns a representation of a date or datepart + * This could be for example a localized monthname, the time without date, + * the era or only the fractional seconds. There are about 50 different supported date parts. + * For a complete list of supported datepart values look into the docu + * + * @param string $part OPTIONAL Part of the date to return, if null the timestamp is returned + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return string date or datepart + */ + public function get($part = null, $locale = null) + { + if ($locale === null) { + $locale = $this->getLocale(); + } + + if (($part !== null) && !defined($part) + && ($part != 'ee') && ($part != 'ss') && ($part != 'GG') && ($part != 'MM') && ($part != 'EE') && ($part != 'TT') + && Zend_Locale::isLocale($part, null, false)) { + $locale = $part; + $part = null; + } + + if ($part === null) { + $part = self::TIMESTAMP; + } else if (self::$_options['format_type'] == 'php') { + $part = Zend_Locale_Format::convertPhpToIsoFormat($part); + } + + return $this->date($this->_toToken($part, $locale), $this->getUnixTimestamp(), false); + } + + /** + * Internal method to apply tokens + * + * @param string $part + * @param string $locale + * @return string + */ + private function _toToken($part, $locale) { + // get format tokens + $comment = false; + $format = ''; + $orig = ''; + for ($i = 0; isset($part[$i]); ++$i) { + if ($part[$i] == "'") { + $comment = $comment ? false : true; + if (isset($part[$i+1]) && ($part[$i+1] == "'")) { + $comment = $comment ? false : true; + $format .= "\\'"; + ++$i; + } + + $orig = ''; + continue; + } + + if ($comment) { + $format .= '\\' . $part[$i]; + $orig = ''; + } else { + $orig .= $part[$i]; + if (!isset($part[$i+1]) || (isset($orig[0]) && ($orig[0] != $part[$i+1]))) { + $format .= $this->_parseIsoToDate($orig, $locale); + $orig = ''; + } + } + } + + return $format; + } + + /** + * Internal parsing method + * + * @param string $token + * @param string $locale + * @return string + */ + private function _parseIsoToDate($token, $locale) { + switch($token) { + case self::DAY : + return 'd'; + break; + + case self::WEEKDAY_SHORT : + $weekday = strtolower($this->date('D', $this->getUnixTimestamp(), false)); + $day = Zend_Locale_Data::getContent($locale, 'day', array('gregorian', 'format', 'wide', $weekday)); + return $this->_toComment(iconv_substr($day, 0, 3, 'UTF-8')); + break; + + case self::DAY_SHORT : + return 'j'; + break; + + case self::WEEKDAY : + $weekday = strtolower($this->date('D', $this->getUnixTimestamp(), false)); + return $this->_toComment(Zend_Locale_Data::getContent($locale, 'day', array('gregorian', 'format', 'wide', $weekday))); + break; + + case self::WEEKDAY_8601 : + return 'N'; + break; + + case 'ee' : + return $this->_toComment(str_pad($this->date('N', $this->getUnixTimestamp(), false), 2, '0', STR_PAD_LEFT)); + break; + + case self::DAY_SUFFIX : + return 'S'; + break; + + case self::WEEKDAY_DIGIT : + return 'w'; + break; + + case self::DAY_OF_YEAR : + return 'z'; + break; + + case 'DDD' : + return $this->_toComment(str_pad($this->date('z', $this->getUnixTimestamp(), false), 3, '0', STR_PAD_LEFT)); + break; + + case 'DD' : + return $this->_toComment(str_pad($this->date('z', $this->getUnixTimestamp(), false), 2, '0', STR_PAD_LEFT)); + break; + + case self::WEEKDAY_NARROW : + case 'EEEEE' : + $weekday = strtolower($this->date('D', $this->getUnixTimestamp(), false)); + $day = Zend_Locale_Data::getContent($locale, 'day', array('gregorian', 'format', 'abbreviated', $weekday)); + return $this->_toComment(iconv_substr($day, 0, 1, 'UTF-8')); + break; + + case self::WEEKDAY_NAME : + $weekday = strtolower($this->date('D', $this->getUnixTimestamp(), false)); + return $this->_toComment(Zend_Locale_Data::getContent($locale, 'day', array('gregorian', 'format', 'abbreviated', $weekday))); + break; + + case 'w' : + $week = $this->date('W', $this->getUnixTimestamp(), false); + return $this->_toComment(($week[0] == '0') ? $week[1] : $week); + break; + + case self::WEEK : + return 'W'; + break; + + case self::MONTH_NAME : + $month = $this->date('n', $this->getUnixTimestamp(), false); + return $this->_toComment(Zend_Locale_Data::getContent($locale, 'month', array('gregorian', 'format', 'wide', $month))); + break; + + case self::MONTH : + return 'm'; + break; + + case self::MONTH_NAME_SHORT : + $month = $this->date('n', $this->getUnixTimestamp(), false); + return $this->_toComment(Zend_Locale_Data::getContent($locale, 'month', array('gregorian', 'format', 'abbreviated', $month))); + break; + + case self::MONTH_SHORT : + return 'n'; + break; + + case self::MONTH_DAYS : + return 't'; + break; + + case self::MONTH_NAME_NARROW : + $month = $this->date('n', $this->getUnixTimestamp(), false); + $mon = Zend_Locale_Data::getContent($locale, 'month', array('gregorian', 'format', 'abbreviated', $month)); + return $this->_toComment(iconv_substr($mon, 0, 1, 'UTF-8')); + break; + + case self::LEAPYEAR : + return 'L'; + break; + + case self::YEAR_8601 : + return 'o'; + break; + + case self::YEAR : + return 'Y'; + break; + + case self::YEAR_SHORT : + return 'y'; + break; + + case self::YEAR_SHORT_8601 : + return $this->_toComment(substr($this->date('o', $this->getUnixTimestamp(), false), -2, 2)); + break; + + case self::MERIDIEM : + $am = $this->date('a', $this->getUnixTimestamp(), false); + if ($am == 'am') { + return $this->_toComment(Zend_Locale_Data::getContent($locale, 'am')); + } + + return $this->_toComment(Zend_Locale_Data::getContent($locale, 'pm')); + break; + + case self::SWATCH : + return 'B'; + break; + + case self::HOUR_SHORT_AM : + return 'g'; + break; + + case self::HOUR_SHORT : + return 'G'; + break; + + case self::HOUR_AM : + return 'h'; + break; + + case self::HOUR : + return 'H'; + break; + + case self::MINUTE : + return $this->_toComment(str_pad($this->date('i', $this->getUnixTimestamp(), false), 2, '0', STR_PAD_LEFT)); + break; + + case self::SECOND : + return $this->_toComment(str_pad($this->date('s', $this->getUnixTimestamp(), false), 2, '0', STR_PAD_LEFT)); + break; + + case self::MINUTE_SHORT : + return 'i'; + break; + + case self::SECOND_SHORT : + return 's'; + break; + + case self::MILLISECOND : + return $this->_toComment($this->getMilliSecond()); + break; + + case self::TIMEZONE_NAME : + case 'vvvv' : + return 'e'; + break; + + case self::DAYLIGHT : + return 'I'; + break; + + case self::GMT_DIFF : + case 'ZZ' : + case 'ZZZ' : + return 'O'; + break; + + case self::GMT_DIFF_SEP : + return 'P'; + break; + + case self::TIMEZONE : + case 'v' : + case 'zz' : + case 'zzz' : + return 'T'; + break; + + case self::TIMEZONE_SECS : + return 'Z'; + break; + + case self::ISO_8601 : + return 'c'; + break; + + case self::RFC_2822 : + return 'r'; + break; + + case self::TIMESTAMP : + return 'U'; + break; + + case self::ERA : + case 'GG' : + case 'GGG' : + $year = $this->date('Y', $this->getUnixTimestamp(), false); + if ($year < 0) { + return $this->_toComment(Zend_Locale_Data::getContent($locale, 'era', array('gregorian', 'Abbr', '0'))); + } + + return $this->_toComment(Zend_Locale_Data::getContent($locale, 'era', array('gregorian', 'Abbr', '1'))); + break; + + case self::ERA_NARROW : + $year = $this->date('Y', $this->getUnixTimestamp(), false); + if ($year < 0) { + return $this->_toComment(iconv_substr(Zend_Locale_Data::getContent($locale, 'era', array('gregorian', 'Abbr', '0')), 0, 1, 'UTF-8')) . '.'; + } + + return $this->_toComment(iconv_substr(Zend_Locale_Data::getContent($locale, 'era', array('gregorian', 'Abbr', '1')), 0, 1, 'UTF-8')) . '.'; + break; + + case self::ERA_NAME : + $year = $this->date('Y', $this->getUnixTimestamp(), false); + if ($year < 0) { + return $this->_toComment(Zend_Locale_Data::getContent($locale, 'era', array('gregorian', 'Names', '0'))); + } + + return $this->_toComment(Zend_Locale_Data::getContent($locale, 'era', array('gregorian', 'Names', '1'))); + break; + + case self::DATES : + return $this->_toToken(Zend_Locale_Format::getDateFormat($locale), $locale); + break; + + case self::DATE_FULL : + return $this->_toToken(Zend_Locale_Data::getContent($locale, 'date', array('gregorian', 'full')), $locale); + break; + + case self::DATE_LONG : + return $this->_toToken(Zend_Locale_Data::getContent($locale, 'date', array('gregorian', 'long')), $locale); + break; + + case self::DATE_MEDIUM : + return $this->_toToken(Zend_Locale_Data::getContent($locale, 'date', array('gregorian', 'medium')), $locale); + break; + + case self::DATE_SHORT : + return $this->_toToken(Zend_Locale_Data::getContent($locale, 'date', array('gregorian', 'short')), $locale); + break; + + case self::TIMES : + return $this->_toToken(Zend_Locale_Format::getTimeFormat($locale), $locale); + break; + + case self::TIME_FULL : + return $this->_toToken(Zend_Locale_Data::getContent($locale, 'time', 'full'), $locale); + break; + + case self::TIME_LONG : + return $this->_toToken(Zend_Locale_Data::getContent($locale, 'time', 'long'), $locale); + break; + + case self::TIME_MEDIUM : + return $this->_toToken(Zend_Locale_Data::getContent($locale, 'time', 'medium'), $locale); + break; + + case self::TIME_SHORT : + return $this->_toToken(Zend_Locale_Data::getContent($locale, 'time', 'short'), $locale); + break; + + case self::DATETIME : + return $this->_toToken(Zend_Locale_Format::getDateTimeFormat($locale), $locale); + break; + + case self::DATETIME_FULL : + return $this->_toToken(Zend_Locale_Data::getContent($locale, 'datetime', array('gregorian', 'full')), $locale); + break; + + case self::DATETIME_LONG : + return $this->_toToken(Zend_Locale_Data::getContent($locale, 'datetime', array('gregorian', 'long')), $locale); + break; + + case self::DATETIME_MEDIUM : + return $this->_toToken(Zend_Locale_Data::getContent($locale, 'datetime', array('gregorian', 'medium')), $locale); + break; + + case self::DATETIME_SHORT : + return $this->_toToken(Zend_Locale_Data::getContent($locale, 'datetime', array('gregorian', 'short')), $locale); + break; + + case self::ATOM : + return 'Y\-m\-d\TH\:i\:sP'; + break; + + case self::COOKIE : + return 'l\, d\-M\-y H\:i\:s e'; + break; + + case self::RFC_822 : + return 'D\, d M y H\:i\:s O'; + break; + + case self::RFC_850 : + return 'l\, d\-M\-y H\:i\:s e'; + break; + + case self::RFC_1036 : + return 'D\, d M y H\:i\:s O'; + break; + + case self::RFC_1123 : + return 'D\, d M Y H\:i\:s O'; + break; + + case self::RFC_3339 : + return 'Y\-m\-d\TH\:i\:sP'; + break; + + case self::RSS : + return 'D\, d M Y H\:i\:s O'; + break; + + case self::W3C : + return 'Y\-m\-d\TH\:i\:sP'; + break; + } + + if ($token == '') { + return ''; + } + + switch ($token[0]) { + case 'y' : + if ((strlen($token) == 4) && (abs($this->getUnixTimestamp()) <= 0x7FFFFFFF)) { + return 'Y'; + } + + $length = iconv_strlen($token, 'UTF-8'); + return $this->_toComment(str_pad($this->date('Y', $this->getUnixTimestamp(), false), $length, '0', STR_PAD_LEFT)); + break; + + case 'Y' : + if ((strlen($token) == 4) && (abs($this->getUnixTimestamp()) <= 0x7FFFFFFF)) { + return 'o'; + } + + $length = iconv_strlen($token, 'UTF-8'); + return $this->_toComment(str_pad($this->date('o', $this->getUnixTimestamp(), false), $length, '0', STR_PAD_LEFT)); + break; + + case 'A' : + $length = iconv_strlen($token, 'UTF-8'); + $result = substr($this->getMilliSecond(), 0, 3); + $result += $this->date('s', $this->getUnixTimestamp(), false) * 1000; + $result += $this->date('i', $this->getUnixTimestamp(), false) * 60000; + $result += $this->date('H', $this->getUnixTimestamp(), false) * 3600000; + + return $this->_toComment(str_pad($result, $length, '0', STR_PAD_LEFT)); + break; + } + + return $this->_toComment($token); + } + + /** + * Private function to make a comment of a token + * + * @param string $token + * @return string + */ + private function _toComment($token) + { + $token = str_split($token); + $result = ''; + foreach ($token as $tok) { + $result .= '\\' . $tok; + } + + return $result; + } + + /** + * Return digit from standard names (english) + * Faster implementation than locale aware searching + * + * @param string $name + * @return integer Number of this month + * @throws Zend_Date_Exception + */ + private function _getDigitFromName($name) + { + switch($name) { + case "Jan": + return 1; + + case "Feb": + return 2; + + case "Mar": + return 3; + + case "Apr": + return 4; + + case "May": + return 5; + + case "Jun": + return 6; + + case "Jul": + return 7; + + case "Aug": + return 8; + + case "Sep": + return 9; + + case "Oct": + return 10; + + case "Nov": + return 11; + + case "Dec": + return 12; + + default: + throw new Zend_Date_Exception('Month ($name) is not a known month'); + } + } + + /** + * Counts the exact year number + * < 70 - 2000 added, >70 < 100 - 1900, others just returned + * + * @param integer $value year number + * @return integer Number of year + */ + public static function getFullYear($value) + { + if ($value >= 0) { + if ($value < 70) { + $value += 2000; + } else if ($value < 100) { + $value += 1900; + } + } + return $value; + } + + /** + * Sets the given date as new date or a given datepart as new datepart returning the new datepart + * This could be for example a localized dayname, the date without time, + * the month or only the seconds. There are about 50 different supported date parts. + * For a complete list of supported datepart values look into the docu + * + * @param string|integer|array|Zend_Date $date Date or datepart to set + * @param string $part OPTIONAL Part of the date to set, if null the timestamp is set + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date Provides a fluent interface + * @throws Zend_Date_Exception + */ + public function set($date, $part = null, $locale = null) + { + if (self::$_options['format_type'] == 'php') { + $part = Zend_Locale_Format::convertPhpToIsoFormat($part); + } + + $zone = $this->getTimezoneFromString($date); + $this->setTimezone($zone); + + $this->_calculate('set', $date, $part, $locale); + return $this; + } + + /** + * Adds a date or datepart to the existing date, by extracting $part from $date, + * and modifying this object by adding that part. The $part is then extracted from + * this object and returned as an integer or numeric string (for large values, or $part's + * corresponding to pre-defined formatted date strings). + * This could be for example a ISO 8601 date, the hour the monthname or only the minute. + * There are about 50 different supported date parts. + * For a complete list of supported datepart values look into the docu. + * + * @param string|integer|array|Zend_Date $date Date or datepart to add + * @param string $part OPTIONAL Part of the date to add, if null the timestamp is added + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date Provides a fluent interface + * @throws Zend_Date_Exception + */ + public function add($date, $part = self::TIMESTAMP, $locale = null) + { + if (self::$_options['format_type'] == 'php') { + $part = Zend_Locale_Format::convertPhpToIsoFormat($part); + } + + $this->_calculate('add', $date, $part, $locale); + return $this; + } + + /** + * Subtracts a date from another date. + * This could be for example a RFC2822 date, the time, + * the year or only the timestamp. There are about 50 different supported date parts. + * For a complete list of supported datepart values look into the docu + * Be aware: Adding -2 Months is not equal to Subtracting 2 Months !!! + * + * @param string|integer|array|Zend_Date $date Date or datepart to subtract + * @param string $part OPTIONAL Part of the date to sub, if null the timestamp is subtracted + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date Provides a fluent interface + * @throws Zend_Date_Exception + */ + public function sub($date, $part = self::TIMESTAMP, $locale = null) + { + if (self::$_options['format_type'] == 'php') { + $part = Zend_Locale_Format::convertPhpToIsoFormat($part); + } + + $this->_calculate('sub', $date, $part, $locale); + return $this; + } + + /** + * Compares a date or datepart with the existing one. + * Returns -1 if earlier, 0 if equal and 1 if later. + * + * @param string|integer|array|Zend_Date $date Date or datepart to compare with the date object + * @param string $part OPTIONAL Part of the date to compare, if null the timestamp is subtracted + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return integer 0 = equal, 1 = later, -1 = earlier + * @throws Zend_Date_Exception + */ + public function compare($date, $part = self::TIMESTAMP, $locale = null) + { + if (self::$_options['format_type'] == 'php') { + $part = Zend_Locale_Format::convertPhpToIsoFormat($part); + } + + $compare = $this->_calculate('cmp', $date, $part, $locale); + + if ($compare > 0) { + return 1; + } else if ($compare < 0) { + return -1; + } + return 0; + } + + /** + * Returns a new instance of Zend_Date with the selected part copied. + * To make an exact copy, use PHP's clone keyword. + * For a complete list of supported date part values look into the docu. + * If a date part is copied, all other date parts are set to standard values. + * For example: If only YEAR is copied, the returned date object is equal to + * 01-01-YEAR 00:00:00 (01-01-1970 00:00:00 is equal to timestamp 0) + * If only HOUR is copied, the returned date object is equal to + * 01-01-1970 HOUR:00:00 (so $this contains a timestamp equal to a timestamp of 0 plus HOUR). + * + * @param string $part Part of the date to compare, if null the timestamp is subtracted + * @param string|Zend_Locale $locale OPTIONAL New object's locale. No adjustments to timezone are made. + * @return Zend_Date New clone with requested part + */ + public function copyPart($part, $locale = null) + { + $clone = clone $this; // copy all instance variables + $clone->setUnixTimestamp(0); // except the timestamp + if ($locale != null) { + $clone->setLocale($locale); // set an other locale if selected + } + $clone->set($this, $part); + return $clone; + } + + /** + * Internal function, returns the offset of a given timezone + * + * @param string $zone + * @return integer + */ + public function getTimezoneFromString($zone) + { + if (is_array($zone)) { + return $this->getTimezone(); + } + + if ($zone instanceof Zend_Date) { + return $zone->getTimezone(); + } + + $match = array(); + preg_match('/\dZ$/', $zone, $match); + if (!empty($match)) { + return "Etc/UTC"; + } + + preg_match('/([+-]\d{2}):{0,1}\d{2}/', $zone, $match); + if (!empty($match) and ($match[count($match) - 1] <= 14) and ($match[count($match) - 1] >= -12)) { + $zone = "Etc/GMT"; + $zone .= ($match[count($match) - 1] < 0) ? "+" : "-"; + $zone .= (int) abs($match[count($match) - 1]); + return $zone; + } + + preg_match('/([[:alpha:]\/_]{3,30})(?!.*([[:alpha:]\/]{3,30}))/', $zone, $match); + try { + if (!empty($match) and (!is_int($match[count($match) - 1]))) { + $oldzone = $this->getTimezone(); + $this->setTimezone($match[count($match) - 1]); + $result = $this->getTimezone(); + $this->setTimezone($oldzone); + if ($result !== $oldzone) { + return $match[count($match) - 1]; + } + } + } catch (Exception $e) { + // fall through + } + + return $this->getTimezone(); + } + + /** + * Calculates the date or object + * + * @param string $calc Calculation to make + * @param string|integer $date Date for calculation + * @param string|integer $comp Second date for calculation + * @param boolean|integer $dst Use dst correction if option is set + * @return integer|string|Zend_Date new timestamp or Zend_Date depending on calculation + */ + private function _assign($calc, $date, $comp = 0, $dst = false) + { + switch ($calc) { + case 'set' : + if (!empty($comp)) { + $this->setUnixTimestamp(call_user_func(Zend_Locale_Math::$sub, $this->getUnixTimestamp(), $comp)); + } + $this->setUnixTimestamp(call_user_func(Zend_Locale_Math::$add, $this->getUnixTimestamp(), $date)); + $value = $this->getUnixTimestamp(); + break; + case 'add' : + $this->setUnixTimestamp(call_user_func(Zend_Locale_Math::$add, $this->getUnixTimestamp(), $date)); + $value = $this->getUnixTimestamp(); + break; + case 'sub' : + $this->setUnixTimestamp(call_user_func(Zend_Locale_Math::$sub, $this->getUnixTimestamp(), $date)); + $value = $this->getUnixTimestamp(); + break; + default : + // cmp - compare + return call_user_func(Zend_Locale_Math::$comp, $comp, $date); + break; + } + + // dst-correction if 'fix_dst' = true and dst !== false but only for non UTC and non GMT + if ((self::$_options['fix_dst'] === true) and ($dst !== false) and ($this->_dst === true)) { + $hour = $this->toString(self::HOUR, 'iso'); + if ($hour != $dst) { + if (($dst == ($hour + 1)) or ($dst == ($hour - 23))) { + $value += 3600; + } else if (($dst == ($hour - 1)) or ($dst == ($hour + 23))) { + $value -= 3600; + } + $this->setUnixTimestamp($value); + } + } + return $this->getUnixTimestamp(); + } + + + /** + * Calculates the date or object + * + * @param string $calc Calculation to make, one of: 'add'|'sub'|'cmp'|'copy'|'set' + * @param string|integer|array|Zend_Date $date Date or datepart to calculate with + * @param string $part Part of the date to calculate, if null the timestamp is used + * @param string|Zend_Locale $locale Locale for parsing input + * @return integer|string|Zend_Date new timestamp + * @throws Zend_Date_Exception + */ + private function _calculate($calc, $date, $part, $locale) + { + if ($date === null) { + throw new Zend_Date_Exception('parameter $date must be set, null is not allowed'); + } + + if (($part !== null) && (strlen($part) !== 2) && (Zend_Locale::isLocale($part, null, false))) { + $locale = $part; + $part = null; + } + + if ($locale === null) { + $locale = $this->getLocale(); + } + + $locale = (string) $locale; + + // Create date parts + $year = $this->toString(self::YEAR, 'iso'); + $month = $this->toString(self::MONTH_SHORT, 'iso'); + $day = $this->toString(self::DAY_SHORT, 'iso'); + $hour = $this->toString(self::HOUR_SHORT, 'iso'); + $minute = $this->toString(self::MINUTE_SHORT, 'iso'); + $second = $this->toString(self::SECOND_SHORT, 'iso'); + // If object extract value + if ($date instanceof Zend_Date) { + $date = $date->toString($part, 'iso', $locale); + } + + if (is_array($date) === true) { + if (empty($part) === false) { + switch($part) { + // Fall through + case self::DAY: + case self::DAY_SHORT: + if (isset($date['day']) === true) { + $date = $date['day']; + } + break; + // Fall through + case self::WEEKDAY_SHORT: + case self::WEEKDAY: + case self::WEEKDAY_8601: + case self::WEEKDAY_DIGIT: + case self::WEEKDAY_NARROW: + case self::WEEKDAY_NAME: + if (isset($date['weekday']) === true) { + $date = $date['weekday']; + $part = self::WEEKDAY_DIGIT; + } + break; + case self::DAY_OF_YEAR: + if (isset($date['day_of_year']) === true) { + $date = $date['day_of_year']; + } + break; + // Fall through + case self::MONTH: + case self::MONTH_SHORT: + case self::MONTH_NAME: + case self::MONTH_NAME_SHORT: + case self::MONTH_NAME_NARROW: + if (isset($date['month']) === true) { + $date = $date['month']; + } + break; + // Fall through + case self::YEAR: + case self::YEAR_SHORT: + case self::YEAR_8601: + case self::YEAR_SHORT_8601: + if (isset($date['year']) === true) { + $date = $date['year']; + } + break; + // Fall through + case self::HOUR: + case self::HOUR_AM: + case self::HOUR_SHORT: + case self::HOUR_SHORT_AM: + if (isset($date['hour']) === true) { + $date = $date['hour']; + } + break; + // Fall through + case self::MINUTE: + case self::MINUTE_SHORT: + if (isset($date['minute']) === true) { + $date = $date['minute']; + } + break; + // Fall through + case self::SECOND: + case self::SECOND_SHORT: + if (isset($date['second']) === true) { + $date = $date['second']; + } + break; + // Fall through + case self::TIMEZONE: + case self::TIMEZONE_NAME: + if (isset($date['timezone']) === true) { + $date = $date['timezone']; + } + break; + case self::TIMESTAMP: + if (isset($date['timestamp']) === true) { + $date = $date['timestamp']; + } + break; + case self::WEEK: + if (isset($date['week']) === true) { + $date = $date['week']; + } + break; + case self::TIMEZONE_SECS: + if (isset($date['gmtsecs']) === true) { + $date = $date['gmtsecs']; + } + break; + default: + throw new Zend_Date_Exception("datepart for part ($part) not found in array"); + break; + } + } else { + $hours = 0; + if (isset($date['hour']) === true) { + $hours = $date['hour']; + } + $minutes = 0; + if (isset($date['minute']) === true) { + $minutes = $date['minute']; + } + $seconds = 0; + if (isset($date['second']) === true) { + $seconds = $date['second']; + } + $months = 0; + if (isset($date['month']) === true) { + $months = $date['month']; + } + $days = 0; + if (isset($date['day']) === true) { + $days = $date['day']; + } + $years = 0; + if (isset($date['year']) === true) { + $years = $date['year']; + } + return $this->_assign($calc, $this->mktime($hours, $minutes, $seconds, $months, $days, $years, true), + $this->mktime($hour, $minute, $second, $month, $day, $year, true), $hour); + } + } + + // $date as object, part of foreign date as own date + switch($part) { + + // day formats + case self::DAY: + if (is_numeric($date)) { + return $this->_assign($calc, $this->mktime(0, 0, 0, 1, 1 + intval($date), 1970, true), + $this->mktime(0, 0, 0, 1, 1 + intval($day), 1970, true), $hour); + } + + throw new Zend_Date_Exception("invalid date ($date) operand, day expected", 0, null, $date); + break; + + case self::WEEKDAY_SHORT: + $daylist = Zend_Locale_Data::getList($locale, 'day'); + $weekday = (int) $this->toString(self::WEEKDAY_DIGIT, 'iso', $locale); + $cnt = 0; + + foreach ($daylist as $key => $value) { + if (strtoupper(iconv_substr($value, 0, 3, 'UTF-8')) == strtoupper($date)) { + $found = $cnt; + break; + } + ++$cnt; + } + + // Weekday found + if ($cnt < 7) { + return $this->_assign($calc, $this->mktime(0, 0, 0, 1, 1 + $found, 1970, true), + $this->mktime(0, 0, 0, 1, 1 + $weekday, 1970, true), $hour); + } + + // Weekday not found + throw new Zend_Date_Exception("invalid date ($date) operand, weekday expected", 0, null, $date); + break; + + case self::DAY_SHORT: + if (is_numeric($date)) { + return $this->_assign($calc, $this->mktime(0, 0, 0, 1, 1 + intval($date), 1970, true), + $this->mktime(0, 0, 0, 1, 1 + intval($day), 1970, true), $hour); + } + + throw new Zend_Date_Exception("invalid date ($date) operand, day expected", 0, null, $date); + break; + + case self::WEEKDAY: + $daylist = Zend_Locale_Data::getList($locale, 'day'); + $weekday = (int) $this->toString(self::WEEKDAY_DIGIT, 'iso', $locale); + $cnt = 0; + + foreach ($daylist as $key => $value) { + if (strtoupper($value) == strtoupper($date)) { + $found = $cnt; + break; + } + ++$cnt; + } + + // Weekday found + if ($cnt < 7) { + return $this->_assign($calc, $this->mktime(0, 0, 0, 1, 1 + $found, 1970, true), + $this->mktime(0, 0, 0, 1, 1 + $weekday, 1970, true), $hour); + } + + // Weekday not found + throw new Zend_Date_Exception("invalid date ($date) operand, weekday expected", 0, null, $date); + break; + + case self::WEEKDAY_8601: + $weekday = (int) $this->toString(self::WEEKDAY_8601, 'iso', $locale); + if ((intval($date) > 0) and (intval($date) < 8)) { + return $this->_assign($calc, $this->mktime(0, 0, 0, 1, 1 + intval($date), 1970, true), + $this->mktime(0, 0, 0, 1, 1 + $weekday, 1970, true), $hour); + } + + // Weekday not found + throw new Zend_Date_Exception("invalid date ($date) operand, weekday expected", 0, null, $date); + break; + + case self::DAY_SUFFIX: + throw new Zend_Date_Exception('day suffix not supported', 0, null, $date); + break; + + case self::WEEKDAY_DIGIT: + $weekday = (int) $this->toString(self::WEEKDAY_DIGIT, 'iso', $locale); + if (is_numeric($date) and (intval($date) >= 0) and (intval($date) < 7)) { + return $this->_assign($calc, $this->mktime(0, 0, 0, 1, 1 + $date, 1970, true), + $this->mktime(0, 0, 0, 1, 1 + $weekday, 1970, true), $hour); + } + + // Weekday not found + throw new Zend_Date_Exception("invalid date ($date) operand, weekday expected", 0, null, $date); + break; + + case self::DAY_OF_YEAR: + if (is_numeric($date)) { + if (($calc == 'add') || ($calc == 'sub')) { + $year = 1970; + ++$date; + ++$day; + } + + return $this->_assign($calc, $this->mktime(0, 0, 0, 1, $date, $year, true), + $this->mktime(0, 0, 0, $month, $day, $year, true), $hour); + } + + throw new Zend_Date_Exception("invalid date ($date) operand, day expected", 0, null, $date); + break; + + case self::WEEKDAY_NARROW: + $daylist = Zend_Locale_Data::getList($locale, 'day', array('gregorian', 'format', 'abbreviated')); + $weekday = (int) $this->toString(self::WEEKDAY_DIGIT, 'iso', $locale); + $cnt = 0; + foreach ($daylist as $key => $value) { + if (strtoupper(iconv_substr($value, 0, 1, 'UTF-8')) == strtoupper($date)) { + $found = $cnt; + break; + } + ++$cnt; + } + + // Weekday found + if ($cnt < 7) { + return $this->_assign($calc, $this->mktime(0, 0, 0, 1, 1 + $found, 1970, true), + $this->mktime(0, 0, 0, 1, 1 + $weekday, 1970, true), $hour); + } + + // Weekday not found + throw new Zend_Date_Exception("invalid date ($date) operand, weekday expected", 0, null, $date); + break; + + case self::WEEKDAY_NAME: + $daylist = Zend_Locale_Data::getList($locale, 'day', array('gregorian', 'format', 'abbreviated')); + $weekday = (int) $this->toString(self::WEEKDAY_DIGIT, 'iso', $locale); + $cnt = 0; + foreach ($daylist as $key => $value) { + if (strtoupper($value) == strtoupper($date)) { + $found = $cnt; + break; + } + ++$cnt; + } + + // Weekday found + if ($cnt < 7) { + return $this->_assign($calc, $this->mktime(0, 0, 0, 1, 1 + $found, 1970, true), + $this->mktime(0, 0, 0, 1, 1 + $weekday, 1970, true), $hour); + } + + // Weekday not found + throw new Zend_Date_Exception("invalid date ($date) operand, weekday expected", 0, null, $date); + break; + + // week formats + case self::WEEK: + if (is_numeric($date)) { + $week = (int) $this->toString(self::WEEK, 'iso', $locale); + return $this->_assign($calc, parent::mktime(0, 0, 0, 1, 1 + ($date * 7), 1970, true), + parent::mktime(0, 0, 0, 1, 1 + ($week * 7), 1970, true), $hour); + } + + throw new Zend_Date_Exception("invalid date ($date) operand, week expected", 0, null, $date); + break; + + // month formats + case self::MONTH_NAME: + $monthlist = Zend_Locale_Data::getList($locale, 'month'); + $cnt = 0; + foreach ($monthlist as $key => $value) { + if (strtoupper($value) == strtoupper($date)) { + $found = $key; + break; + } + ++$cnt; + } + $date = array_search($date, $monthlist); + + // Monthname found + if ($cnt < 12) { + $fixday = 0; + if ($calc == 'add') { + $date += $found; + $calc = 'set'; + if (self::$_options['extend_month'] == false) { + $parts = $this->getDateParts($this->mktime($hour, $minute, $second, $date, $day, $year, false)); + if ($parts['mday'] != $day) { + $fixday = ($parts['mday'] < $day) ? -$parts['mday'] : ($parts['mday'] - $day); + } + } + } else if ($calc == 'sub') { + $date = $month - $found; + $calc = 'set'; + if (self::$_options['extend_month'] == false) { + $parts = $this->getDateParts($this->mktime($hour, $minute, $second, $date, $day, $year, false)); + if ($parts['mday'] != $day) { + $fixday = ($parts['mday'] < $day) ? -$parts['mday'] : ($parts['mday'] - $day); + } + } + } + return $this->_assign($calc, $this->mktime(0, 0, 0, $date, $day + $fixday, $year, true), + $this->mktime(0, 0, 0, $month, $day, $year, true), $hour); + } + + // Monthname not found + throw new Zend_Date_Exception("invalid date ($date) operand, month expected", 0, null, $date); + break; + + case self::MONTH: + if (is_numeric($date)) { + $fixday = 0; + if ($calc == 'add') { + $date += $month; + $calc = 'set'; + if (self::$_options['extend_month'] == false) { + $parts = $this->getDateParts($this->mktime($hour, $minute, $second, $date, $day, $year, false)); + if ($parts['mday'] != $day) { + $fixday = ($parts['mday'] < $day) ? -$parts['mday'] : ($parts['mday'] - $day); + } + } + } else if ($calc == 'sub') { + $date = $month - $date; + $calc = 'set'; + if (self::$_options['extend_month'] == false) { + $parts = $this->getDateParts($this->mktime($hour, $minute, $second, $date, $day, $year, false)); + if ($parts['mday'] != $day) { + $fixday = ($parts['mday'] < $day) ? -$parts['mday'] : ($parts['mday'] - $day); + } + } + } + return $this->_assign($calc, $this->mktime(0, 0, 0, $date, $day + $fixday, $year, true), + $this->mktime(0, 0, 0, $month, $day, $year, true), $hour); + } + + throw new Zend_Date_Exception("invalid date ($date) operand, month expected", 0, null, $date); + break; + + case self::MONTH_NAME_SHORT: + $monthlist = Zend_Locale_Data::getList($locale, 'month', array('gregorian', 'format', 'abbreviated')); + $cnt = 0; + foreach ($monthlist as $key => $value) { + if (strtoupper($value) == strtoupper($date)) { + $found = $key; + break; + } + ++$cnt; + } + $date = array_search($date, $monthlist); + + // Monthname found + if ($cnt < 12) { + $fixday = 0; + if ($calc == 'add') { + $date += $found; + $calc = 'set'; + if (self::$_options['extend_month'] === false) { + $parts = $this->getDateParts($this->mktime($hour, $minute, $second, $date, $day, $year, false)); + if ($parts['mday'] != $day) { + $fixday = ($parts['mday'] < $day) ? -$parts['mday'] : ($parts['mday'] - $day); + } + } + } else if ($calc == 'sub') { + $date = $month - $found; + $calc = 'set'; + if (self::$_options['extend_month'] === false) { + $parts = $this->getDateParts($this->mktime($hour, $minute, $second, $date, $day, $year, false)); + if ($parts['mday'] != $day) { + $fixday = ($parts['mday'] < $day) ? -$parts['mday'] : ($parts['mday'] - $day); + } + } + } + return $this->_assign($calc, $this->mktime(0, 0, 0, $date, $day + $fixday, $year, true), + $this->mktime(0, 0, 0, $month, $day, $year, true), $hour); + } + + // Monthname not found + throw new Zend_Date_Exception("invalid date ($date) operand, month expected", 0, null, $date); + break; + + case self::MONTH_SHORT: + if (is_numeric($date) === true) { + $fixday = 0; + if ($calc === 'add') { + $date += $month; + $calc = 'set'; + if (self::$_options['extend_month'] === false) { + $parts = $this->getDateParts($this->mktime($hour, $minute, $second, $date, $day, $year, false)); + if ($parts['mday'] != $day) { + $fixday = ($parts['mday'] < $day) ? -$parts['mday'] : ($parts['mday'] - $day); + } + } + } else if ($calc === 'sub') { + $date = $month - $date; + $calc = 'set'; + if (self::$_options['extend_month'] === false) { + $parts = $this->getDateParts($this->mktime($hour, $minute, $second, $date, $day, $year, false)); + if ($parts['mday'] != $day) { + $fixday = ($parts['mday'] < $day) ? -$parts['mday'] : ($parts['mday'] - $day); + } + } + } + + return $this->_assign($calc, $this->mktime(0, 0, 0, $date, $day + $fixday, $year, true), + $this->mktime(0, 0, 0, $month, $day, $year, true), $hour); + } + + throw new Zend_Date_Exception("invalid date ($date) operand, month expected", 0, null, $date); + break; + + case self::MONTH_DAYS: + throw new Zend_Date_Exception('month days not supported', 0, null, $date); + break; + + case self::MONTH_NAME_NARROW: + $monthlist = Zend_Locale_Data::getList($locale, 'month', array('gregorian', 'stand-alone', 'narrow')); + $cnt = 0; + foreach ($monthlist as $key => $value) { + if (strtoupper($value) === strtoupper($date)) { + $found = $key; + break; + } + ++$cnt; + } + $date = array_search($date, $monthlist); + + // Monthname found + if ($cnt < 12) { + $fixday = 0; + if ($calc === 'add') { + $date += $found; + $calc = 'set'; + if (self::$_options['extend_month'] === false) { + $parts = $this->getDateParts($this->mktime($hour, $minute, $second, $date, $day, $year, false)); + if ($parts['mday'] != $day) { + $fixday = ($parts['mday'] < $day) ? -$parts['mday'] : ($parts['mday'] - $day); + } + } + } else if ($calc === 'sub') { + $date = $month - $found; + $calc = 'set'; + if (self::$_options['extend_month'] === false) { + $parts = $this->getDateParts($this->mktime($hour, $minute, $second, $date, $day, $year, false)); + if ($parts['mday'] != $day) { + $fixday = ($parts['mday'] < $day) ? -$parts['mday'] : ($parts['mday'] - $day); + } + } + } + return $this->_assign($calc, $this->mktime(0, 0, 0, $date, $day + $fixday, $year, true), + $this->mktime(0, 0, 0, $month, $day, $year, true), $hour); + } + + // Monthname not found + throw new Zend_Date_Exception("invalid date ($date) operand, month expected", 0, null, $date); + break; + + // year formats + case self::LEAPYEAR: + throw new Zend_Date_Exception('leap year not supported', 0, null, $date); + break; + + case self::YEAR_8601: + if (is_numeric($date)) { + if ($calc === 'add') { + $date += $year; + $calc = 'set'; + } else if ($calc === 'sub') { + $date = $year - $date; + $calc = 'set'; + } + + return $this->_assign($calc, $this->mktime(0, 0, 0, $month, $day, intval($date), true), + $this->mktime(0, 0, 0, $month, $day, $year, true), false); + } + + throw new Zend_Date_Exception("invalid date ($date) operand, year expected", 0, null, $date); + break; + + case self::YEAR: + if (is_numeric($date)) { + if ($calc === 'add') { + $date += $year; + $calc = 'set'; + } else if ($calc === 'sub') { + $date = $year - $date; + $calc = 'set'; + } + + return $this->_assign($calc, $this->mktime(0, 0, 0, $month, $day, intval($date), true), + $this->mktime(0, 0, 0, $month, $day, $year, true), false); + } + + throw new Zend_Date_Exception("invalid date ($date) operand, year expected", 0, null, $date); + break; + + case self::YEAR_SHORT: + if (is_numeric($date)) { + $date = intval($date); + if (($calc == 'set') || ($calc == 'cmp')) { + $date = self::getFullYear($date); + } + if ($calc === 'add') { + $date += $year; + $calc = 'set'; + } else if ($calc === 'sub') { + $date = $year - $date; + $calc = 'set'; + } + + return $this->_assign($calc, $this->mktime(0, 0, 0, $month, $day, $date, true), + $this->mktime(0, 0, 0, $month, $day, $year, true), false); + } + + throw new Zend_Date_Exception("invalid date ($date) operand, year expected", 0, null, $date); + break; + + case self::YEAR_SHORT_8601: + if (is_numeric($date)) { + $date = intval($date); + if (($calc === 'set') || ($calc === 'cmp')) { + $date = self::getFullYear($date); + } + if ($calc === 'add') { + $date += $year; + $calc = 'set'; + } else if ($calc === 'sub') { + $date = $year - $date; + $calc = 'set'; + } + + return $this->_assign($calc, $this->mktime(0, 0, 0, $month, $day, $date, true), + $this->mktime(0, 0, 0, $month, $day, $year, true), false); + } + + throw new Zend_Date_Exception("invalid date ($date) operand, year expected", 0, null, $date); + break; + + // time formats + case self::MERIDIEM: + throw new Zend_Date_Exception('meridiem not supported', 0, null, $date); + break; + + case self::SWATCH: + if (is_numeric($date)) { + $rest = intval($date); + $hours = floor($rest * 24 / 1000); + $rest = $rest - ($hours * 1000 / 24); + $minutes = floor($rest * 1440 / 1000); + $rest = $rest - ($minutes * 1000 / 1440); + $seconds = floor($rest * 86400 / 1000); + return $this->_assign($calc, $this->mktime($hours, $minutes, $seconds, 1, 1, 1970, true), + $this->mktime($hour, $minute, $second, 1, 1, 1970, true), false); + } + + throw new Zend_Date_Exception("invalid date ($date) operand, swatchstamp expected", 0, null, $date); + break; + + case self::HOUR_SHORT_AM: + if (is_numeric($date)) { + return $this->_assign($calc, $this->mktime(intval($date), 0, 0, 1, 1, 1970, true), + $this->mktime($hour, 0, 0, 1, 1, 1970, true), false); + } + + throw new Zend_Date_Exception("invalid date ($date) operand, hour expected", 0, null, $date); + break; + + case self::HOUR_SHORT: + if (is_numeric($date)) { + return $this->_assign($calc, $this->mktime(intval($date), 0, 0, 1, 1, 1970, true), + $this->mktime($hour, 0, 0, 1, 1, 1970, true), false); + } + + throw new Zend_Date_Exception("invalid date ($date) operand, hour expected", 0, null, $date); + break; + + case self::HOUR_AM: + if (is_numeric($date)) { + return $this->_assign($calc, $this->mktime(intval($date), 0, 0, 1, 1, 1970, true), + $this->mktime($hour, 0, 0, 1, 1, 1970, true), false); + } + + throw new Zend_Date_Exception("invalid date ($date) operand, hour expected", 0, null, $date); + break; + + case self::HOUR: + if (is_numeric($date)) { + return $this->_assign($calc, $this->mktime(intval($date), 0, 0, 1, 1, 1970, true), + $this->mktime($hour, 0, 0, 1, 1, 1970, true), false); + } + + throw new Zend_Date_Exception("invalid date ($date) operand, hour expected", 0, null, $date); + break; + + case self::MINUTE: + if (is_numeric($date)) { + return $this->_assign($calc, $this->mktime(0, intval($date), 0, 1, 1, 1970, true), + $this->mktime(0, $minute, 0, 1, 1, 1970, true), false); + } + + throw new Zend_Date_Exception("invalid date ($date) operand, minute expected", 0, null, $date); + break; + + case self::SECOND: + if (is_numeric($date)) { + return $this->_assign($calc, $this->mktime(0, 0, intval($date), 1, 1, 1970, true), + $this->mktime(0, 0, $second, 1, 1, 1970, true), false); + } + + throw new Zend_Date_Exception("invalid date ($date) operand, second expected", 0, null, $date); + break; + + case self::MILLISECOND: + if (is_numeric($date)) { + switch($calc) { + case 'set' : + return $this->setMillisecond($date); + break; + case 'add' : + return $this->addMillisecond($date); + break; + case 'sub' : + return $this->subMillisecond($date); + break; + } + + return $this->compareMillisecond($date); + } + + throw new Zend_Date_Exception("invalid date ($date) operand, milliseconds expected", 0, null, $date); + break; + + case self::MINUTE_SHORT: + if (is_numeric($date)) { + return $this->_assign($calc, $this->mktime(0, intval($date), 0, 1, 1, 1970, true), + $this->mktime(0, $minute, 0, 1, 1, 1970, true), false); + } + + throw new Zend_Date_Exception("invalid date ($date) operand, minute expected", 0, null, $date); + break; + + case self::SECOND_SHORT: + if (is_numeric($date)) { + return $this->_assign($calc, $this->mktime(0, 0, intval($date), 1, 1, 1970, true), + $this->mktime(0, 0, $second, 1, 1, 1970, true), false); + } + + throw new Zend_Date_Exception("invalid date ($date) operand, second expected", 0, null, $date); + break; + + // timezone formats + // break intentionally omitted + case self::TIMEZONE_NAME: + case self::TIMEZONE: + case self::TIMEZONE_SECS: + throw new Zend_Date_Exception('timezone not supported', 0, null, $date); + break; + + case self::DAYLIGHT: + throw new Zend_Date_Exception('daylight not supported', 0, null, $date); + break; + + case self::GMT_DIFF: + case self::GMT_DIFF_SEP: + throw new Zend_Date_Exception('gmtdiff not supported', 0, null, $date); + break; + + // date strings + case self::ISO_8601: + // (-)YYYY-MM-dd + preg_match('/^(-{0,1}\d{4})-(\d{2})-(\d{2})/', $date, $datematch); + // (-)YY-MM-dd + if (empty($datematch)) { + preg_match('/^(-{0,1}\d{2})-(\d{2})-(\d{2})/', $date, $datematch); + } + // (-)YYYYMMdd + if (empty($datematch)) { + preg_match('/^(-{0,1}\d{4})(\d{2})(\d{2})/', $date, $datematch); + } + // (-)YYMMdd + if (empty($datematch)) { + preg_match('/^(-{0,1}\d{2})(\d{2})(\d{2})/', $date, $datematch); + } + $tmpdate = $date; + if (!empty($datematch)) { + $dateMatchCharCount = iconv_strlen($datematch[0], 'UTF-8'); + $tmpdate = iconv_substr($date, + $dateMatchCharCount, + iconv_strlen($date, 'UTF-8') - $dateMatchCharCount, + 'UTF-8'); + } + // (T)hh:mm:ss + preg_match('/[T,\s]{0,1}(\d{2}):(\d{2}):(\d{2})/', $tmpdate, $timematch); + // (T)hhmmss + if (empty($timematch)) { + preg_match('/[T,\s]{0,1}(\d{2})(\d{2})(\d{2})/', $tmpdate, $timematch); + } + // (T)hh:mm + if (empty($timematch)) { + preg_match('/[T,\s]{0,1}(\d{2}):(\d{2})/', $tmpdate, $timematch); + } + // (T)hhmm + if (empty($timematch)) { + preg_match('/[T,\s]{0,1}(\d{2})(\d{2})/', $tmpdate, $timematch); + } + if (empty($datematch) and empty($timematch)) { + throw new Zend_Date_Exception("unsupported ISO8601 format ($date)", 0, null, $date); + } + if (!empty($timematch)) { + $timeMatchCharCount = iconv_strlen($timematch[0], 'UTF-8'); + $tmpdate = iconv_substr($tmpdate, + $timeMatchCharCount, + iconv_strlen($tmpdate, 'UTF-8') - $timeMatchCharCount, + 'UTF-8'); + } + if (empty($datematch)) { + $datematch[1] = 1970; + $datematch[2] = 1; + $datematch[3] = 1; + } else if (iconv_strlen($datematch[1], 'UTF-8') == 2) { + $datematch[1] = self::getFullYear($datematch[1]); + } + if (empty($timematch)) { + $timematch[1] = 0; + $timematch[2] = 0; + $timematch[3] = 0; + } + if (!isset($timematch[3])) { + $timematch[3] = 0; + } + + if (($calc == 'set') || ($calc == 'cmp')) { + --$datematch[2]; + --$month; + --$datematch[3]; + --$day; + $datematch[1] -= 1970; + $year -= 1970; + } + return $this->_assign($calc, $this->mktime($timematch[1], $timematch[2], $timematch[3], 1 + $datematch[2], 1 + $datematch[3], 1970 + $datematch[1], false), + $this->mktime($hour, $minute, $second, 1 + $month, 1 + $day, 1970 + $year, false), false); + break; + + case self::RFC_2822: + $result = preg_match('/^\w{3},\s(\d{1,2})\s(\w{3})\s(\d{4})\s' + . '(\d{2}):(\d{2}):{0,1}(\d{0,2})\s([+-]' + . '{1}\d{4}|\w{1,20})$/', $date, $match); + + if (!$result) { + throw new Zend_Date_Exception("no RFC 2822 format ($date)", 0, null, $date); + } + + $months = $this->_getDigitFromName($match[2]); + + if (($calc == 'set') || ($calc == 'cmp')) { + --$months; + --$month; + --$match[1]; + --$day; + $match[3] -= 1970; + $year -= 1970; + } + return $this->_assign($calc, $this->mktime($match[4], $match[5], $match[6], 1 + $months, 1 + $match[1], 1970 + $match[3], false), + $this->mktime($hour, $minute, $second, 1 + $month, 1 + $day, 1970 + $year, false), false); + break; + + case self::TIMESTAMP: + if (is_numeric($date)) { + return $this->_assign($calc, $date, $this->getUnixTimestamp()); + } + + throw new Zend_Date_Exception("invalid date ($date) operand, timestamp expected", 0, null, $date); + break; + + // additional formats + // break intentionally omitted + case self::ERA: + case self::ERA_NAME: + throw new Zend_Date_Exception('era not supported', 0, null, $date); + break; + + case self::DATES: + try { + $parsed = Zend_Locale_Format::getDate($date, array('locale' => $locale, 'format_type' => 'iso', 'fix_date' => true)); + + if (($calc == 'set') || ($calc == 'cmp')) { + --$parsed['month']; + --$month; + --$parsed['day']; + --$day; + $parsed['year'] -= 1970; + $year -= 1970; + } + + return $this->_assign($calc, $this->mktime(0, 0, 0, 1 + $parsed['month'], 1 + $parsed['day'], 1970 + $parsed['year'], true), + $this->mktime(0, 0, 0, 1 + $month, 1 + $day, 1970 + $year, true), $hour); + } catch (Zend_Locale_Exception $e) { + throw new Zend_Date_Exception($e->getMessage(), 0, $e, $date); + } + break; + + case self::DATE_FULL: + try { + $format = Zend_Locale_Data::getContent($locale, 'date', array('gregorian', 'full')); + $parsed = Zend_Locale_Format::getDate($date, array('date_format' => $format, 'format_type' => 'iso', 'locale' => $locale)); + + if (($calc == 'set') || ($calc == 'cmp')) { + --$parsed['month']; + --$month; + --$parsed['day']; + --$day; + $parsed['year'] -= 1970; + $year -= 1970; + } + return $this->_assign($calc, $this->mktime(0, 0, 0, 1 + $parsed['month'], 1 + $parsed['day'], 1970 + $parsed['year'], true), + $this->mktime(0, 0, 0, 1 + $month, 1 + $day, 1970 + $year, true), $hour); + } catch (Zend_Locale_Exception $e) { + throw new Zend_Date_Exception($e->getMessage(), 0, $e, $date); + } + break; + + case self::DATE_LONG: + try { + $format = Zend_Locale_Data::getContent($locale, 'date', array('gregorian', 'long')); + $parsed = Zend_Locale_Format::getDate($date, array('date_format' => $format, 'format_type' => 'iso', 'locale' => $locale)); + + if (($calc == 'set') || ($calc == 'cmp')){ + --$parsed['month']; + --$month; + --$parsed['day']; + --$day; + $parsed['year'] -= 1970; + $year -= 1970; + } + return $this->_assign($calc, $this->mktime(0, 0, 0, 1 + $parsed['month'], 1 + $parsed['day'], 1970 + $parsed['year'], true), + $this->mktime(0, 0, 0, 1 + $month, 1 + $day, 1970 + $year, true), $hour); + } catch (Zend_Locale_Exception $e) { + throw new Zend_Date_Exception($e->getMessage(), 0, $e, $date); + } + break; + + case self::DATE_MEDIUM: + try { + $format = Zend_Locale_Data::getContent($locale, 'date', array('gregorian', 'medium')); + $parsed = Zend_Locale_Format::getDate($date, array('date_format' => $format, 'format_type' => 'iso', 'locale' => $locale)); + + if (($calc == 'set') || ($calc == 'cmp')) { + --$parsed['month']; + --$month; + --$parsed['day']; + --$day; + $parsed['year'] -= 1970; + $year -= 1970; + } + return $this->_assign($calc, $this->mktime(0, 0, 0, 1 + $parsed['month'], 1 + $parsed['day'], 1970 + $parsed['year'], true), + $this->mktime(0, 0, 0, 1 + $month, 1 + $day, 1970 + $year, true), $hour); + } catch (Zend_Locale_Exception $e) { + throw new Zend_Date_Exception($e->getMessage(), 0, $e, $date); + } + break; + + case self::DATE_SHORT: + try { + $format = Zend_Locale_Data::getContent($locale, 'date', array('gregorian', 'short')); + $parsed = Zend_Locale_Format::getDate($date, array('date_format' => $format, 'format_type' => 'iso', 'locale' => $locale)); + + $parsed['year'] = self::getFullYear($parsed['year']); + + if (($calc == 'set') || ($calc == 'cmp')) { + --$parsed['month']; + --$month; + --$parsed['day']; + --$day; + $parsed['year'] -= 1970; + $year -= 1970; + } + return $this->_assign($calc, $this->mktime(0, 0, 0, 1 + $parsed['month'], 1 + $parsed['day'], 1970 + $parsed['year'], true), + $this->mktime(0, 0, 0, 1 + $month, 1 + $day, 1970 + $year, true), $hour); + } catch (Zend_Locale_Exception $e) { + throw new Zend_Date_Exception($e->getMessage(), 0, $e, $date); + } + break; + + case self::TIMES: + try { + if ($calc != 'set') { + $month = 1; + $day = 1; + $year = 1970; + } + $parsed = Zend_Locale_Format::getTime($date, array('locale' => $locale, 'format_type' => 'iso', 'fix_date' => true)); + return $this->_assign($calc, $this->mktime($parsed['hour'], $parsed['minute'], $parsed['second'], $month, $day, $year, true), + $this->mktime($hour, $minute, $second, $month, $day, $year, true), false); + } catch (Zend_Locale_Exception $e) { + throw new Zend_Date_Exception($e->getMessage(), 0, $e, $date); + } + break; + + case self::TIME_FULL: + try { + $format = Zend_Locale_Data::getContent($locale, 'time', array('gregorian', 'full')); + $parsed = Zend_Locale_Format::getTime($date, array('date_format' => $format, 'format_type' => 'iso', 'locale' => $locale)); + if ($calc != 'set') { + $month = 1; + $day = 1; + $year = 1970; + } + + if (!isset($parsed['second'])) { + $parsed['second'] = 0; + } + + return $this->_assign($calc, $this->mktime($parsed['hour'], $parsed['minute'], $parsed['second'], $month, $day, $year, true), + $this->mktime($hour, $minute, $second, $month, $day, $year, true), false); + } catch (Zend_Locale_Exception $e) { + throw new Zend_Date_Exception($e->getMessage(), 0, $e, $date); + } + break; + + case self::TIME_LONG: + try { + $format = Zend_Locale_Data::getContent($locale, 'time', array('gregorian', 'long')); + $parsed = Zend_Locale_Format::getTime($date, array('date_format' => $format, 'format_type' => 'iso', 'locale' => $locale)); + if ($calc != 'set') { + $month = 1; + $day = 1; + $year = 1970; + } + return $this->_assign($calc, $this->mktime($parsed['hour'], $parsed['minute'], $parsed['second'], $month, $day, $year, true), + $this->mktime($hour, $minute, $second, $month, $day, $year, true), false); + } catch (Zend_Locale_Exception $e) { + throw new Zend_Date_Exception($e->getMessage(), 0, $e, $date); + } + break; + + case self::TIME_MEDIUM: + try { + $format = Zend_Locale_Data::getContent($locale, 'time', array('gregorian', 'medium')); + $parsed = Zend_Locale_Format::getTime($date, array('date_format' => $format, 'format_type' => 'iso', 'locale' => $locale)); + if ($calc != 'set') { + $month = 1; + $day = 1; + $year = 1970; + } + return $this->_assign($calc, $this->mktime($parsed['hour'], $parsed['minute'], $parsed['second'], $month, $day, $year, true), + $this->mktime($hour, $minute, $second, $month, $day, $year, true), false); + } catch (Zend_Locale_Exception $e) { + throw new Zend_Date_Exception($e->getMessage(), 0, $e, $date); + } + break; + + case self::TIME_SHORT: + try { + $format = Zend_Locale_Data::getContent($locale, 'time', array('gregorian', 'short')); + $parsed = Zend_Locale_Format::getTime($date, array('date_format' => $format, 'format_type' => 'iso', 'locale' => $locale)); + if ($calc != 'set') { + $month = 1; + $day = 1; + $year = 1970; + } + + if (!isset($parsed['second'])) { + $parsed['second'] = 0; + } + + return $this->_assign($calc, $this->mktime($parsed['hour'], $parsed['minute'], $parsed['second'], $month, $day, $year, true), + $this->mktime($hour, $minute, $second, $month, $day, $year, true), false); + } catch (Zend_Locale_Exception $e) { + throw new Zend_Date_Exception($e->getMessage(), 0, $e, $date); + } + break; + + case self::DATETIME: + try { + $parsed = Zend_Locale_Format::getDateTime($date, array('locale' => $locale, 'format_type' => 'iso', 'fix_date' => true)); + if (($calc == 'set') || ($calc == 'cmp')) { + --$parsed['month']; + --$month; + --$parsed['day']; + --$day; + $parsed['year'] -= 1970; + $year -= 1970; + } + return $this->_assign($calc, $this->mktime($parsed['hour'], $parsed['minute'], $parsed['second'], 1 + $parsed['month'], 1 + $parsed['day'], 1970 + $parsed['year'], true), + $this->mktime($hour, $minute, $second, 1 + $month, 1 + $day, 1970 + $year, true), $hour); + } catch (Zend_Locale_Exception $e) { + throw new Zend_Date_Exception($e->getMessage(), 0, $e, $date); + } + break; + + case self::DATETIME_FULL: + try { + $format = Zend_Locale_Data::getContent($locale, 'datetime', array('gregorian', 'full')); + $parsed = Zend_Locale_Format::getDateTime($date, array('date_format' => $format, 'format_type' => 'iso', 'locale' => $locale)); + + if (($calc == 'set') || ($calc == 'cmp')) { + --$parsed['month']; + --$month; + --$parsed['day']; + --$day; + $parsed['year'] -= 1970; + $year -= 1970; + } + + if (!isset($parsed['second'])) { + $parsed['second'] = 0; + } + + return $this->_assign($calc, $this->mktime($parsed['hour'], $parsed['minute'], $parsed['second'], 1 + $parsed['month'], 1 + $parsed['day'], 1970 + $parsed['year'], true), + $this->mktime($hour, $minute, $second, 1 + $month, 1 + $day, 1970 + $year, true), $hour); + } catch (Zend_Locale_Exception $e) { + throw new Zend_Date_Exception($e->getMessage(), 0, $e, $date); + } + break; + + case self::DATETIME_LONG: + try { + $format = Zend_Locale_Data::getContent($locale, 'datetime', array('gregorian', 'long')); + $parsed = Zend_Locale_Format::getDateTime($date, array('date_format' => $format, 'format_type' => 'iso', 'locale' => $locale)); + + if (($calc == 'set') || ($calc == 'cmp')){ + --$parsed['month']; + --$month; + --$parsed['day']; + --$day; + $parsed['year'] -= 1970; + $year -= 1970; + } + return $this->_assign($calc, $this->mktime($parsed['hour'], $parsed['minute'], $parsed['second'], 1 + $parsed['month'], 1 + $parsed['day'], 1970 + $parsed['year'], true), + $this->mktime($hour, $minute, $second, 1 + $month, 1 + $day, 1970 + $year, true), $hour); + } catch (Zend_Locale_Exception $e) { + throw new Zend_Date_Exception($e->getMessage(), 0, $e, $date); + } + break; + + case self::DATETIME_MEDIUM: + try { + $format = Zend_Locale_Data::getContent($locale, 'datetime', array('gregorian', 'medium')); + $parsed = Zend_Locale_Format::getDateTime($date, array('date_format' => $format, 'format_type' => 'iso', 'locale' => $locale)); + if (($calc == 'set') || ($calc == 'cmp')) { + --$parsed['month']; + --$month; + --$parsed['day']; + --$day; + $parsed['year'] -= 1970; + $year -= 1970; + } + return $this->_assign($calc, $this->mktime($parsed['hour'], $parsed['minute'], $parsed['second'], 1 + $parsed['month'], 1 + $parsed['day'], 1970 + $parsed['year'], true), + $this->mktime($hour, $minute, $second, 1 + $month, 1 + $day, 1970 + $year, true), $hour); + } catch (Zend_Locale_Exception $e) { + throw new Zend_Date_Exception($e->getMessage(), 0, $e, $date); + } + break; + + case self::DATETIME_SHORT: + try { + $format = Zend_Locale_Data::getContent($locale, 'datetime', array('gregorian', 'short')); + $parsed = Zend_Locale_Format::getDateTime($date, array('date_format' => $format, 'format_type' => 'iso', 'locale' => $locale)); + + $parsed['year'] = self::getFullYear($parsed['year']); + + if (($calc == 'set') || ($calc == 'cmp')) { + --$parsed['month']; + --$month; + --$parsed['day']; + --$day; + $parsed['year'] -= 1970; + $year -= 1970; + } + + if (!isset($parsed['second'])) { + $parsed['second'] = 0; + } + + return $this->_assign($calc, $this->mktime($parsed['hour'], $parsed['minute'], $parsed['second'], 1 + $parsed['month'], 1 + $parsed['day'], 1970 + $parsed['year'], true), + $this->mktime($hour, $minute, $second, 1 + $month, 1 + $day, 1970 + $year, true), $hour); + } catch (Zend_Locale_Exception $e) { + throw new Zend_Date_Exception($e->getMessage(), 0, $e, $date); + } + break; + + // ATOM and RFC_3339 are identical + case self::ATOM: + case self::RFC_3339: + $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); + if (!$result) { + throw new Zend_Date_Exception("invalid date ($date) operand, ATOM format expected", 0, null, $date); + } + + if (($calc == 'set') || ($calc == 'cmp')) { + --$match[2]; + --$month; + --$match[3]; + --$day; + $match[1] -= 1970; + $year -= 1970; + } + return $this->_assign($calc, $this->mktime($match[4], $match[5], $match[6], 1 + $match[2], 1 + $match[3], 1970 + $match[1], true), + $this->mktime($hour, $minute, $second, 1 + $month, 1 + $day, 1970 + $year, true), false); + break; + + case self::COOKIE: + $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); + if (!$result) { + throw new Zend_Date_Exception("invalid date ($date) operand, COOKIE format expected", 0, null, $date); + } + $matchStartPos = iconv_strpos($match[0], ' ', 0, 'UTF-8') + 1; + $match[0] = iconv_substr($match[0], + $matchStartPos, + iconv_strlen($match[0], 'UTF-8') - $matchStartPos, + 'UTF-8'); + + $months = $this->_getDigitFromName($match[2]); + $match[3] = self::getFullYear($match[3]); + + if (($calc == 'set') || ($calc == 'cmp')) { + --$months; + --$month; + --$match[1]; + --$day; + $match[3] -= 1970; + $year -= 1970; + } + return $this->_assign($calc, $this->mktime($match[4], $match[5], $match[6], 1 + $months, 1 + $match[1], 1970 + $match[3], true), + $this->mktime($hour, $minute, $second, 1 + $month, 1 + $day, 1970 + $year, true), false); + break; + + case self::RFC_822: + case self::RFC_1036: + // new RFC 822 format, identical to RFC 1036 standard + $result = preg_match('/^\w{0,3},{0,1}\s{0,1}(\d{1,2})\s(\w{3})\s(\d{2})\s(\d{2}):(\d{2}):{0,1}(\d{0,2})\s([+-]{1}\d{4}|\w{1,20})$/', $date, $match); + if (!$result) { + throw new Zend_Date_Exception("invalid date ($date) operand, RFC 822 date format expected", 0, null, $date); + } + + $months = $this->_getDigitFromName($match[2]); + $match[3] = self::getFullYear($match[3]); + + if (($calc == 'set') || ($calc == 'cmp')) { + --$months; + --$month; + --$match[1]; + --$day; + $match[3] -= 1970; + $year -= 1970; + } + return $this->_assign($calc, $this->mktime($match[4], $match[5], $match[6], 1 + $months, 1 + $match[1], 1970 + $match[3], false), + $this->mktime($hour, $minute, $second, 1 + $month, 1 + $day, 1970 + $year, false), false); + break; + + case self::RFC_850: + $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); + if (!$result) { + throw new Zend_Date_Exception("invalid date ($date) operand, RFC 850 date format expected", 0, null, $date); + } + + $months = $this->_getDigitFromName($match[2]); + $match[3] = self::getFullYear($match[3]); + + if (($calc == 'set') || ($calc == 'cmp')) { + --$months; + --$month; + --$match[1]; + --$day; + $match[3] -= 1970; + $year -= 1970; + } + return $this->_assign($calc, $this->mktime($match[4], $match[5], $match[6], 1 + $months, 1 + $match[1], 1970 + $match[3], true), + $this->mktime($hour, $minute, $second, 1 + $month, 1 + $day, 1970 + $year, true), false); + break; + + case self::RFC_1123: + $result = preg_match('/^\w{0,3},{0,1}\s{0,1}(\d{1,2})\s(\w{3})\s(\d{2,4})\s(\d{2}):(\d{2}):{0,1}(\d{0,2})\s([+-]{1}\d{4}|\w{1,20})$/', $date, $match); + if (!$result) { + throw new Zend_Date_Exception("invalid date ($date) operand, RFC 1123 date format expected", 0, null, $date); + } + + $months = $this->_getDigitFromName($match[2]); + + if (($calc == 'set') || ($calc == 'cmp')) { + --$months; + --$month; + --$match[1]; + --$day; + $match[3] -= 1970; + $year -= 1970; + } + return $this->_assign($calc, $this->mktime($match[4], $match[5], $match[6], 1 + $months, 1 + $match[1], 1970 + $match[3], true), + $this->mktime($hour, $minute, $second, 1 + $month, 1 + $day, 1970 + $year, true), false); + break; + + case self::RSS: + $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); + if (!$result) { + throw new Zend_Date_Exception("invalid date ($date) operand, RSS date format expected", 0, null, $date); + } + + $months = $this->_getDigitFromName($match[2]); + $match[3] = self::getFullYear($match[3]); + + if (($calc == 'set') || ($calc == 'cmp')) { + --$months; + --$month; + --$match[1]; + --$day; + $match[3] -= 1970; + $year -= 1970; + } + return $this->_assign($calc, $this->mktime($match[4], $match[5], $match[6], 1 + $months, 1 + $match[1], 1970 + $match[3], true), + $this->mktime($hour, $minute, $second, 1 + $month, 1 + $day, 1970 + $year, true), false); + break; + + case self::W3C: + $result = preg_match('/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})[+-]{1}\d{2}:\d{2}$/', $date, $match); + if (!$result) { + throw new Zend_Date_Exception("invalid date ($date) operand, W3C date format expected", 0, null, $date); + } + + if (($calc == 'set') || ($calc == 'cmp')) { + --$match[2]; + --$month; + --$match[3]; + --$day; + $match[1] -= 1970; + $year -= 1970; + } + return $this->_assign($calc, $this->mktime($match[4], $match[5], $match[6], 1 + $match[2], 1 + $match[3], 1970 + $match[1], true), + $this->mktime($hour, $minute, $second, 1 + $month, 1 + $day, 1970 + $year, true), false); + break; + + default: + if (!is_numeric($date) || !empty($part)) { + try { + if (empty($part)) { + $part = Zend_Locale_Format::getDateFormat($locale) . " "; + $part .= Zend_Locale_Format::getTimeFormat($locale); + } + + $parsed = Zend_Locale_Format::getDate($date, array('date_format' => $part, 'locale' => $locale, 'fix_date' => true, 'format_type' => 'iso')); + if ((strpos(strtoupper($part), 'YY') !== false) and (strpos(strtoupper($part), 'YYYY') === false)) { + $parsed['year'] = self::getFullYear($parsed['year']); + } + + if (($calc == 'set') || ($calc == 'cmp')) { + if (isset($parsed['month'])) { + --$parsed['month']; + } else { + $parsed['month'] = 0; + } + + if (isset($parsed['day'])) { + --$parsed['day']; + } else { + $parsed['day'] = 0; + } + + if (!isset($parsed['year'])) { + $parsed['year'] = 1970; + } + } + + return $this->_assign($calc, $this->mktime( + isset($parsed['hour']) ? $parsed['hour'] : 0, + isset($parsed['minute']) ? $parsed['minute'] : 0, + isset($parsed['second']) ? $parsed['second'] : 0, + isset($parsed['month']) ? (1 + $parsed['month']) : 1, + isset($parsed['day']) ? (1 + $parsed['day']) : 1, + $parsed['year'], + false), $this->getUnixTimestamp(), false); + } catch (Zend_Locale_Exception $e) { + if (!is_numeric($date)) { + throw new Zend_Date_Exception($e->getMessage(), 0, $e, $date); + } + } + } + + return $this->_assign($calc, $date, $this->getUnixTimestamp(), false); + break; + } + } + + /** + * Returns true when both date objects or date parts are equal. + * For example: + * 15.May.2000 <-> 15.June.2000 Equals only for Day or Year... all other will return false + * + * @param string|integer|array|Zend_Date $date Date or datepart to equal with + * @param string $part OPTIONAL Part of the date to compare, if null the timestamp is used + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return boolean + * @throws Zend_Date_Exception + */ + public function equals($date, $part = self::TIMESTAMP, $locale = null) + { + $result = $this->compare($date, $part, $locale); + + if ($result == 0) { + return true; + } + + return false; + } + + /** + * Returns if the given date or datepart is earlier + * For example: + * 15.May.2000 <-> 13.June.1999 will return true for day, year and date, but not for month + * + * @param string|integer|array|Zend_Date $date Date or datepart to compare with + * @param string $part OPTIONAL Part of the date to compare, if null the timestamp is used + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return boolean + * @throws Zend_Date_Exception + */ + public function isEarlier($date, $part = null, $locale = null) + { + $result = $this->compare($date, $part, $locale); + + if ($result == -1) { + return true; + } + + return false; + } + + /** + * Returns if the given date or datepart is later + * For example: + * 15.May.2000 <-> 13.June.1999 will return true for month but false for day, year and date + * Returns if the given date is later + * + * @param string|integer|array|Zend_Date $date Date or datepart to compare with + * @param string $part OPTIONAL Part of the date to compare, if null the timestamp is used + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return boolean + * @throws Zend_Date_Exception + */ + public function isLater($date, $part = null, $locale = null) + { + $result = $this->compare($date, $part, $locale); + + if ($result == 1) { + return true; + } + + return false; + } + + /** + * Returns only the time of the date as new Zend_Date object + * For example: + * 15.May.2000 10:11:23 will return a dateobject equal to 01.Jan.1970 10:11:23 + * + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date + */ + public function getTime($locale = null) + { + if (self::$_options['format_type'] == 'php') { + $format = 'H:i:s'; + } else { + $format = self::TIME_MEDIUM; + } + + return $this->copyPart($format, $locale); + } + + /** + * Returns the calculated time + * + * @param string $calc Calculation to make + * @param string|integer|array|Zend_Date $time Time to calculate with, if null the actual time is taken + * @param string $format Timeformat for parsing input + * @param string|Zend_Locale $locale Locale for parsing input + * @return integer|Zend_Date new time + * @throws Zend_Date_Exception + */ + private function _time($calc, $time, $format, $locale) + { + if ($time === null) { + throw new Zend_Date_Exception('parameter $time must be set, null is not allowed'); + } + + if ($time instanceof Zend_Date) { + // extract time from object + $time = $time->toString('HH:mm:ss', 'iso'); + } else { + if (is_array($time)) { + if ((isset($time['hour']) === true) or (isset($time['minute']) === true) or + (isset($time['second']) === true)) { + $parsed = $time; + } else { + throw new Zend_Date_Exception("no hour, minute or second given in array"); + } + } else { + if (self::$_options['format_type'] == 'php') { + $format = Zend_Locale_Format::convertPhpToIsoFormat($format); + } + try { + if ($locale === null) { + $locale = $this->getLocale(); + } + + $parsed = Zend_Locale_Format::getTime($time, array('date_format' => $format, 'locale' => $locale, 'format_type' => 'iso')); + } catch (Zend_Locale_Exception $e) { + throw new Zend_Date_Exception($e->getMessage(), 0, $e); + } + } + + if (!array_key_exists('hour', $parsed)) { + $parsed['hour'] = 0; + } + + if (!array_key_exists('minute', $parsed)) { + $parsed['minute'] = 0; + } + + if (!array_key_exists('second', $parsed)) { + $parsed['second'] = 0; + } + + $time = str_pad($parsed['hour'], 2, '0', STR_PAD_LEFT) . ":"; + $time .= str_pad($parsed['minute'], 2, '0', STR_PAD_LEFT) . ":"; + $time .= str_pad($parsed['second'], 2, '0', STR_PAD_LEFT); + } + + $return = $this->_calcdetail($calc, $time, self::TIMES, 'de'); + if ($calc != 'cmp') { + return $this; + } + + return $return; + } + + + /** + * Sets a new time for the date object. Format defines how to parse the time string. + * Also a complete date can be given, but only the time is used for setting. + * For example: dd.MMMM.yyTHH:mm' and 'ss sec'-> 10.May.07T25:11 and 44 sec => 1h11min44sec + 1 day + * Returned is the new date object and the existing date is left as it was before + * + * @param string|integer|array|Zend_Date $time Time to set + * @param string $format OPTIONAL Timeformat for parsing input + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date Provides a fluent interface + * @throws Zend_Date_Exception + */ + public function setTime($time, $format = null, $locale = null) + { + return $this->_time('set', $time, $format, $locale); + } + + + /** + * Adds a time to the existing date. Format defines how to parse the time string. + * If only parts are given the other parts are set to 0. + * If no format is given, the standardformat of this locale is used. + * For example: HH:mm:ss -> 10 -> +10 hours + * + * @param string|integer|array|Zend_Date $time Time to add + * @param string $format OPTIONAL Timeformat for parsing input + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date Provides a fluent interface + * @throws Zend_Date_Exception + */ + public function addTime($time, $format = null, $locale = null) + { + return $this->_time('add', $time, $format, $locale); + } + + + /** + * Subtracts a time from the existing date. Format defines how to parse the time string. + * If only parts are given the other parts are set to 0. + * If no format is given, the standardformat of this locale is used. + * For example: HH:mm:ss -> 10 -> -10 hours + * + * @param string|integer|array|Zend_Date $time Time to sub + * @param string $format OPTIONAL Timeformat for parsing input + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date Provides a fluent inteface + * @throws Zend_Date_Exception + */ + public function subTime($time, $format = null, $locale = null) + { + return $this->_time('sub', $time, $format, $locale); + } + + + /** + * Compares the time from the existing date. Format defines how to parse the time string. + * If only parts are given the other parts are set to default. + * If no format us given, the standardformat of this locale is used. + * For example: HH:mm:ss -> 10 -> 10 hours + * + * @param string|integer|array|Zend_Date $time Time to compare + * @param string $format OPTIONAL Timeformat for parsing input + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return integer 0 = equal, 1 = later, -1 = earlier + * @throws Zend_Date_Exception + */ + public function compareTime($time, $format = null, $locale = null) + { + return $this->_time('cmp', $time, $format, $locale); + } + + /** + * Returns a clone of $this, with the time part set to 00:00:00. + * + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date + */ + public function getDate($locale = null) + { + $orig = self::$_options['format_type']; + if (self::$_options['format_type'] == 'php') { + self::$_options['format_type'] = 'iso'; + } + + $date = $this->copyPart(self::DATE_MEDIUM, $locale); + $date->addTimestamp($this->getGmtOffset()); + self::$_options['format_type'] = $orig; + + return $date; + } + + /** + * Returns the calculated date + * + * @param string $calc Calculation to make + * @param string|integer|array|Zend_Date $date Date to calculate with, if null the actual date is taken + * @param string $format Date format for parsing + * @param string|Zend_Locale $locale Locale for parsing input + * @return integer|Zend_Date new date + * @throws Zend_Date_Exception + */ + private function _date($calc, $date, $format, $locale) + { + if ($date === null) { + throw new Zend_Date_Exception('parameter $date must be set, null is not allowed'); + } + + if ($date instanceof Zend_Date) { + // extract date from object + $date = $date->toString('d.M.y', 'iso'); + } else { + if (is_array($date)) { + if ((isset($date['year']) === true) or (isset($date['month']) === true) or + (isset($date['day']) === true)) { + $parsed = $date; + } else { + throw new Zend_Date_Exception("no day,month or year given in array"); + } + } else { + if ((self::$_options['format_type'] == 'php') && !defined($format)) { + $format = Zend_Locale_Format::convertPhpToIsoFormat($format); + } + try { + if ($locale === null) { + $locale = $this->getLocale(); + } + + $parsed = Zend_Locale_Format::getDate($date, array('date_format' => $format, 'locale' => $locale, 'format_type' => 'iso')); + if ((strpos(strtoupper($format), 'YY') !== false) and (strpos(strtoupper($format), 'YYYY') === false)) { + $parsed['year'] = self::getFullYear($parsed['year']); + } + } catch (Zend_Locale_Exception $e) { + throw new Zend_Date_Exception($e->getMessage(), 0, $e); + } + } + + if (!array_key_exists('day', $parsed)) { + $parsed['day'] = 1; + } + + if (!array_key_exists('month', $parsed)) { + $parsed['month'] = 1; + } + + if (!array_key_exists('year', $parsed)) { + $parsed['year'] = 0; + } + + $date = $parsed['day'] . "." . $parsed['month'] . "." . $parsed['year']; + } + + $return = $this->_calcdetail($calc, $date, self::DATE_MEDIUM, 'de'); + if ($calc != 'cmp') { + return $this; + } + return $return; + } + + + /** + * Sets a new date for the date object. Format defines how to parse the date string. + * Also a complete date with time can be given, but only the date is used for setting. + * For example: MMMM.yy HH:mm-> May.07 22:11 => 01.May.07 00:00 + * Returned is the new date object and the existing time is left as it was before + * + * @param string|integer|array|Zend_Date $date Date to set + * @param string $format OPTIONAL Date format for parsing + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date Provides a fluent interface + * @throws Zend_Date_Exception + */ + public function setDate($date, $format = null, $locale = null) + { + return $this->_date('set', $date, $format, $locale); + } + + + /** + * Adds a date to the existing date object. Format defines how to parse the date string. + * If only parts are given the other parts are set to 0. + * If no format is given, the standardformat of this locale is used. + * For example: MM.dd.YYYY -> 10 -> +10 months + * + * @param string|integer|array|Zend_Date $date Date to add + * @param string $format OPTIONAL Date format for parsing input + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date Provides a fluent interface + * @throws Zend_Date_Exception + */ + public function addDate($date, $format = null, $locale = null) + { + return $this->_date('add', $date, $format, $locale); + } + + + /** + * Subtracts a date from the existing date object. Format defines how to parse the date string. + * If only parts are given the other parts are set to 0. + * If no format is given, the standardformat of this locale is used. + * For example: MM.dd.YYYY -> 10 -> -10 months + * Be aware: Subtracting 2 months is not equal to Adding -2 months !!! + * + * @param string|integer|array|Zend_Date $date Date to sub + * @param string $format OPTIONAL Date format for parsing input + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date Provides a fluent interface + * @throws Zend_Date_Exception + */ + public function subDate($date, $format = null, $locale = null) + { + return $this->_date('sub', $date, $format, $locale); + } + + + /** + * Compares the date from the existing date object, ignoring the time. + * Format defines how to parse the date string. + * If only parts are given the other parts are set to 0. + * If no format is given, the standardformat of this locale is used. + * For example: 10.01.2000 => 10.02.1999 -> false + * + * @param string|integer|array|Zend_Date $date Date to compare + * @param string $format OPTIONAL Date format for parsing input + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return integer 0 = equal, 1 = later, -1 = earlier + * @throws Zend_Date_Exception + */ + public function compareDate($date, $format = null, $locale = null) + { + return $this->_date('cmp', $date, $format, $locale); + } + + + /** + * Returns the full ISO 8601 date from the date object. + * Always the complete ISO 8601 specifiction is used. If an other ISO date is needed + * (ISO 8601 defines several formats) use toString() instead. + * This function does not return the ISO date as object. Use copy() instead. + * + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return string + */ + public function getIso($locale = null) + { + return $this->toString(self::ISO_8601, 'iso', $locale); + } + + + /** + * Sets a new date for the date object. Not given parts are set to default. + * Only supported ISO 8601 formats are accepted. + * For example: 050901 -> 01.Sept.2005 00:00:00, 20050201T10:00:30 -> 01.Feb.2005 10h00m30s + * Returned is the new date object + * + * @param string|integer|Zend_Date $date ISO Date to set + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date Provides a fluent interface + * @throws Zend_Date_Exception + */ + public function setIso($date, $locale = null) + { + return $this->_calcvalue('set', $date, 'iso', self::ISO_8601, $locale); + } + + + /** + * Adds a ISO date to the date object. Not given parts are set to default. + * Only supported ISO 8601 formats are accepted. + * For example: 050901 -> + 01.Sept.2005 00:00:00, 10:00:00 -> +10h + * Returned is the new date object + * + * @param string|integer|Zend_Date $date ISO Date to add + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date Provides a fluent interface + * @throws Zend_Date_Exception + */ + public function addIso($date, $locale = null) + { + return $this->_calcvalue('add', $date, 'iso', self::ISO_8601, $locale); + } + + + /** + * Subtracts a ISO date from the date object. Not given parts are set to default. + * Only supported ISO 8601 formats are accepted. + * For example: 050901 -> - 01.Sept.2005 00:00:00, 10:00:00 -> -10h + * Returned is the new date object + * + * @param string|integer|Zend_Date $date ISO Date to sub + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date Provides a fluent interface + * @throws Zend_Date_Exception + */ + public function subIso($date, $locale = null) + { + return $this->_calcvalue('sub', $date, 'iso', self::ISO_8601, $locale); + } + + + /** + * Compares a ISO date with the date object. Not given parts are set to default. + * Only supported ISO 8601 formats are accepted. + * For example: 050901 -> - 01.Sept.2005 00:00:00, 10:00:00 -> -10h + * Returns if equal, earlier or later + * + * @param string|integer|Zend_Date $date ISO Date to sub + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return integer 0 = equal, 1 = later, -1 = earlier + * @throws Zend_Date_Exception + */ + public function compareIso($date, $locale = null) + { + return $this->_calcvalue('cmp', $date, 'iso', self::ISO_8601, $locale); + } + + + /** + * Returns a RFC 822 compilant datestring from the date object. + * This function does not return the RFC date as object. Use copy() instead. + * + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return string + */ + public function getArpa($locale = null) + { + if (self::$_options['format_type'] == 'php') { + $format = 'D\, d M y H\:i\:s O'; + } else { + $format = self::RFC_822; + } + + return $this->toString($format, 'iso', $locale); + } + + + /** + * Sets a RFC 822 date as new date for the date object. + * Only RFC 822 compilant date strings are accepted. + * For example: Sat, 14 Feb 09 00:31:30 +0100 + * Returned is the new date object + * + * @param string|integer|Zend_Date $date RFC 822 to set + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date Provides a fluent interface + * @throws Zend_Date_Exception + */ + public function setArpa($date, $locale = null) + { + return $this->_calcvalue('set', $date, 'arpa', self::RFC_822, $locale); + } + + + /** + * Adds a RFC 822 date to the date object. + * ARPA messages are used in emails or HTTP Headers. + * Only RFC 822 compilant date strings are accepted. + * For example: Sat, 14 Feb 09 00:31:30 +0100 + * Returned is the new date object + * + * @param string|integer|Zend_Date $date RFC 822 Date to add + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date Provides a fluent interface + * @throws Zend_Date_Exception + */ + public function addArpa($date, $locale = null) + { + return $this->_calcvalue('add', $date, 'arpa', self::RFC_822, $locale); + } + + + /** + * Subtracts a RFC 822 date from the date object. + * ARPA messages are used in emails or HTTP Headers. + * Only RFC 822 compilant date strings are accepted. + * For example: Sat, 14 Feb 09 00:31:30 +0100 + * Returned is the new date object + * + * @param string|integer|Zend_Date $date RFC 822 Date to sub + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date Provides a fluent interface + * @throws Zend_Date_Exception + */ + public function subArpa($date, $locale = null) + { + return $this->_calcvalue('sub', $date, 'arpa', self::RFC_822, $locale); + } + + + /** + * Compares a RFC 822 compilant date with the date object. + * ARPA messages are used in emails or HTTP Headers. + * Only RFC 822 compilant date strings are accepted. + * For example: Sat, 14 Feb 09 00:31:30 +0100 + * Returns if equal, earlier or later + * + * @param string|integer|Zend_Date $date RFC 822 Date to sub + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return integer 0 = equal, 1 = later, -1 = earlier + * @throws Zend_Date_Exception + */ + public function compareArpa($date, $locale = null) + { + return $this->_calcvalue('cmp', $date, 'arpa', self::RFC_822, $locale); + } + + /** + * Check if location is supported + * + * @param array $location locations array + * @throws Zend_Date_Exception + * @return float $horizon float + */ + private function _checkLocation($location) + { + if (!isset($location['longitude']) or !isset($location['latitude'])) { + throw new Zend_Date_Exception('Location must include \'longitude\' and \'latitude\'', 0, null, $location); + } + if (($location['longitude'] > 180) or ($location['longitude'] < -180)) { + throw new Zend_Date_Exception('Longitude must be between -180 and 180', 0, null, $location); + } + if (($location['latitude'] > 90) or ($location['latitude'] < -90)) { + throw new Zend_Date_Exception('Latitude must be between -90 and 90', 0, null, $location); + } + + if (!isset($location['horizon'])){ + $location['horizon'] = 'effective'; + } + + switch ($location['horizon']) { + case 'civil' : + return -0.104528; + break; + case 'nautic' : + return -0.207912; + break; + case 'astronomic' : + return -0.309017; + break; + default : + return -0.0145439; + break; + } + } + + + /** + * Returns the time of sunrise for this date and a given location as new date object + * For a list of cities and correct locations use the class Zend_Date_Cities + * + * @param array $location location of sunrise + * ['horizon'] -> civil, nautic, astronomical, effective (default) + * ['longitude'] -> longitude of location + * ['latitude'] -> latitude of location + * @return Zend_Date + * @throws Zend_Date_Exception + */ + public function getSunrise($location) + { + $horizon = $this->_checkLocation($location); + $result = clone $this; + $result->set($this->calcSun($location, $horizon, true), self::TIMESTAMP); + return $result; + } + + + /** + * Returns the time of sunset for this date and a given location as new date object + * For a list of cities and correct locations use the class Zend_Date_Cities + * + * @param array $location location of sunset + * ['horizon'] -> civil, nautic, astronomical, effective (default) + * ['longitude'] -> longitude of location + * ['latitude'] -> latitude of location + * @return Zend_Date + * @throws Zend_Date_Exception + */ + public function getSunset($location) + { + $horizon = $this->_checkLocation($location); + $result = clone $this; + $result->set($this->calcSun($location, $horizon, false), self::TIMESTAMP); + return $result; + } + + + /** + * Returns an array with the sunset and sunrise dates for all horizon types + * For a list of cities and correct locations use the class Zend_Date_Cities + * + * @param array $location location of suninfo + * ['horizon'] -> civil, nautic, astronomical, effective (default) + * ['longitude'] -> longitude of location + * ['latitude'] -> latitude of location + * @return array - [sunset|sunrise][effective|civil|nautic|astronomic] + * @throws Zend_Date_Exception + */ + public function getSunInfo($location) + { + $suninfo = array(); + for ($i = 0; $i < 4; ++$i) { + switch ($i) { + case 0 : + $location['horizon'] = 'effective'; + break; + case 1 : + $location['horizon'] = 'civil'; + break; + case 2 : + $location['horizon'] = 'nautic'; + break; + case 3 : + $location['horizon'] = 'astronomic'; + break; + } + $horizon = $this->_checkLocation($location); + $result = clone $this; + $result->set($this->calcSun($location, $horizon, true), self::TIMESTAMP); + $suninfo['sunrise'][$location['horizon']] = $result; + $result = clone $this; + $result->set($this->calcSun($location, $horizon, false), self::TIMESTAMP); + $suninfo['sunset'][$location['horizon']] = $result; + } + return $suninfo; + } + + /** + * Check a given year for leap year. + * + * @param integer|array|Zend_Date $year Year to check + * @throws Zend_Date_Exception + * @return boolean + */ + public static function checkLeapYear($year) + { + if ($year instanceof Zend_Date) { + $year = (int) $year->toString(self::YEAR, 'iso'); + } + + if (is_array($year)) { + if (isset($year['year']) === true) { + $year = $year['year']; + } else { + throw new Zend_Date_Exception("no year given in array"); + } + } + + if (!is_numeric($year)) { + throw new Zend_Date_Exception("year ($year) has to be integer for checkLeapYear()", 0, null, $year); + } + + return (bool) parent::isYearLeapYear($year); + } + + + /** + * Returns true, if the year is a leap year. + * + * @return boolean + */ + public function isLeapYear() + { + return self::checkLeapYear($this); + } + + + /** + * Returns if the set date is todays date + * + * @return boolean + */ + public function isToday() + { + $today = $this->date('Ymd', $this->_getTime()); + $day = $this->date('Ymd', $this->getUnixTimestamp()); + return ($today == $day); + } + + + /** + * Returns if the set date is yesterdays date + * + * @return boolean + */ + public function isYesterday() + { + list($year, $month, $day) = explode('-', $this->date('Y-m-d', $this->_getTime())); + // adjusts for leap days and DST changes that are timezone specific + $yesterday = $this->date('Ymd', $this->mktime(0, 0, 0, $month, $day -1, $year)); + $day = $this->date('Ymd', $this->getUnixTimestamp()); + return $day == $yesterday; + } + + + /** + * Returns if the set date is tomorrows date + * + * @return boolean + */ + public function isTomorrow() + { + list($year, $month, $day) = explode('-', $this->date('Y-m-d', $this->_getTime())); + // adjusts for leap days and DST changes that are timezone specific + $tomorrow = $this->date('Ymd', $this->mktime(0, 0, 0, $month, $day +1, $year)); + $day = $this->date('Ymd', $this->getUnixTimestamp()); + return $day == $tomorrow; + } + + /** + * Returns the actual date as new date object + * + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date + */ + public static function now($locale = null) + { + return new Zend_Date(time(), self::TIMESTAMP, $locale); + } + + /** + * Calculate date details + * + * @param string $calc Calculation to make + * @param string|integer|array|Zend_Date $date Date or Part to calculate + * @param string $type Datepart for Calculation + * @param string|Zend_Locale $locale Locale for parsing input + * @return integer|string new date + * @throws Zend_Date_Exception + */ + private function _calcdetail($calc, $date, $type, $locale) + { + $old = false; + if (self::$_options['format_type'] == 'php') { + self::$_options['format_type'] = 'iso'; + $old = true; + } + + switch($calc) { + case 'set' : + $return = $this->set($date, $type, $locale); + break; + case 'add' : + $return = $this->add($date, $type, $locale); + break; + case 'sub' : + $return = $this->sub($date, $type, $locale); + break; + default : + $return = $this->compare($date, $type, $locale); + break; + } + + if ($old) { + self::$_options['format_type'] = 'php'; + } + + return $return; + } + + /** + * Internal calculation, returns the requested date type + * + * @param string $calc Calculation to make + * @param string|integer|Zend_Date $value Datevalue to calculate with, if null the actual value is taken + * @param string $type + * @param string $parameter + * @param string|Zend_Locale $locale Locale for parsing input + * @throws Zend_Date_Exception + * @return integer|Zend_Date new date + */ + private function _calcvalue($calc, $value, $type, $parameter, $locale) + { + if ($value === null) { + throw new Zend_Date_Exception("parameter $type must be set, null is not allowed"); + } + + if ($locale === null) { + $locale = $this->getLocale(); + } + + if ($value instanceof Zend_Date) { + // extract value from object + $value = $value->toString($parameter, 'iso', $locale); + } else if (!is_array($value) && !is_numeric($value) && ($type != 'iso') && ($type != 'arpa')) { + throw new Zend_Date_Exception("invalid $type ($value) operand", 0, null, $value); + } + + $return = $this->_calcdetail($calc, $value, $parameter, $locale); + if ($calc != 'cmp') { + return $this; + } + return $return; + } + + + /** + * Returns only the year from the date object as new object. + * For example: 10.May.2000 10:30:00 -> 01.Jan.2000 00:00:00 + * + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date + */ + public function getYear($locale = null) + { + if (self::$_options['format_type'] == 'php') { + $format = 'Y'; + } else { + $format = self::YEAR; + } + + return $this->copyPart($format, $locale); + } + + + /** + * Sets a new year + * If the year is between 0 and 69, 2000 will be set (2000-2069) + * If the year if between 70 and 99, 1999 will be set (1970-1999) + * 3 or 4 digit years are set as expected. If you need to set year 0-99 + * use set() instead. + * Returned is the new date object + * + * @param string|integer|array|Zend_Date $year Year to set + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date Provides a fluent interface + * @throws Zend_Date_Exception + */ + public function setYear($year, $locale = null) + { + return $this->_calcvalue('set', $year, 'year', self::YEAR, $locale); + } + + + /** + * Adds the year to the existing date object + * If the year is between 0 and 69, 2000 will be added (2000-2069) + * If the year if between 70 and 99, 1999 will be added (1970-1999) + * 3 or 4 digit years are added as expected. If you need to add years from 0-99 + * use add() instead. + * Returned is the new date object + * + * @param string|integer|array|Zend_Date $year Year to add + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date Provides a fluent interface + * @throws Zend_Date_Exception + */ + public function addYear($year, $locale = null) + { + return $this->_calcvalue('add', $year, 'year', self::YEAR, $locale); + } + + + /** + * Subs the year from the existing date object + * If the year is between 0 and 69, 2000 will be subtracted (2000-2069) + * If the year if between 70 and 99, 1999 will be subtracted (1970-1999) + * 3 or 4 digit years are subtracted as expected. If you need to subtract years from 0-99 + * use sub() instead. + * Returned is the new date object + * + * @param string|integer|array|Zend_Date $year Year to sub + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date Provides a fluent interface + * @throws Zend_Date_Exception + */ + public function subYear($year, $locale = null) + { + return $this->_calcvalue('sub', $year, 'year', self::YEAR, $locale); + } + + + /** + * Compares the year with the existing date object, ignoring other date parts. + * For example: 10.03.2000 -> 15.02.2000 -> true + * Returns if equal, earlier or later + * + * @param string|integer|array|Zend_Date $year Year to compare + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return integer 0 = equal, 1 = later, -1 = earlier + * @throws Zend_Date_Exception + */ + public function compareYear($year, $locale = null) + { + return $this->_calcvalue('cmp', $year, 'year', self::YEAR, $locale); + } + + + /** + * Returns only the month from the date object as new object. + * For example: 10.May.2000 10:30:00 -> 01.May.1970 00:00:00 + * + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date + */ + public function getMonth($locale = null) + { + if (self::$_options['format_type'] == 'php') { + $format = 'm'; + } else { + $format = self::MONTH; + } + + return $this->copyPart($format, $locale); + } + + + /** + * Returns the calculated month + * + * @param string $calc Calculation to make + * @param string|integer|array|Zend_Date $month Month to calculate with, if null the actual month is taken + * @param string|Zend_Locale $locale Locale for parsing input + * @return integer|Zend_Date new time + * @throws Zend_Date_Exception + */ + private function _month($calc, $month, $locale) + { + if ($month === null) { + throw new Zend_Date_Exception('parameter $month must be set, null is not allowed'); + } + + if ($locale === null) { + $locale = $this->getLocale(); + } + + if ($month instanceof Zend_Date) { + // extract month from object + $found = $month->toString(self::MONTH_SHORT, 'iso', $locale); + } else { + if (is_numeric($month)) { + $found = $month; + } else if (is_array($month)) { + if (isset($month['month']) === true) { + $month = $month['month']; + } else { + throw new Zend_Date_Exception("no month given in array"); + } + } else { + $monthlist = Zend_Locale_Data::getList($locale, 'month'); + $monthlist2 = Zend_Locale_Data::getList($locale, 'month', array('gregorian', 'format', 'abbreviated')); + + $monthlist = array_merge($monthlist, $monthlist2); + $found = 0; + $cnt = 0; + foreach ($monthlist as $key => $value) { + if (strtoupper($value) == strtoupper($month)) { + $found = ($key % 12) + 1; + break; + } + ++$cnt; + } + if ($found == 0) { + foreach ($monthlist2 as $key => $value) { + if (strtoupper(iconv_substr($value, 0, 1, 'UTF-8')) == strtoupper($month)) { + $found = $key + 1; + break; + } + ++$cnt; + } + } + if ($found == 0) { + throw new Zend_Date_Exception("unknown month name ($month)", 0, null, $month); + } + } + } + $return = $this->_calcdetail($calc, $found, self::MONTH_SHORT, $locale); + if ($calc != 'cmp') { + return $this; + } + return $return; + } + + + /** + * Sets a new month + * The month can be a number or a string. Setting months lower then 0 and greater then 12 + * will result in adding or subtracting the relevant year. (12 months equal one year) + * If a localized monthname is given it will be parsed with the default locale or the optional + * set locale. + * Returned is the new date object + * + * @param string|integer|array|Zend_Date $month Month to set + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date Provides a fluent interface + * @throws Zend_Date_Exception + */ + public function setMonth($month, $locale = null) + { + return $this->_month('set', $month, $locale); + } + + + /** + * Adds months to the existing date object. + * The month can be a number or a string. Adding months lower then 0 and greater then 12 + * will result in adding or subtracting the relevant year. (12 months equal one year) + * If a localized monthname is given it will be parsed with the default locale or the optional + * set locale. + * Returned is the new date object + * + * @param string|integer|array|Zend_Date $month Month to add + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date Provides a fluent interface + * @throws Zend_Date_Exception + */ + public function addMonth($month, $locale = null) + { + return $this->_month('add', $month, $locale); + } + + + /** + * Subtracts months from the existing date object. + * The month can be a number or a string. Subtracting months lower then 0 and greater then 12 + * will result in adding or subtracting the relevant year. (12 months equal one year) + * If a localized monthname is given it will be parsed with the default locale or the optional + * set locale. + * Returned is the new date object + * + * @param string|integer|array|Zend_Date $month Month to sub + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date Provides a fluent interface + * @throws Zend_Date_Exception + */ + public function subMonth($month, $locale = null) + { + return $this->_month('sub', $month, $locale); + } + + + /** + * Compares the month with the existing date object, ignoring other date parts. + * For example: 10.03.2000 -> 15.03.1950 -> true + * Returns if equal, earlier or later + * + * @param string|integer|array|Zend_Date $month Month to compare + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return integer 0 = equal, 1 = later, -1 = earlier + * @throws Zend_Date_Exception + */ + public function compareMonth($month, $locale = null) + { + return $this->_month('cmp', $month, $locale); + } + + + /** + * Returns the day as new date object + * Example: 20.May.1986 -> 20.Jan.1970 00:00:00 + * + * @param Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date + */ + public function getDay($locale = null) + { + return $this->copyPart(self::DAY_SHORT, $locale); + } + + /** + * Returns the calculated day + * + * @param string $calc Type of calculation to make + * @param Zend_Date $day Day to calculate, when null the actual day is calculated + * @param Zend_Locale $locale Locale for parsing input + * @throws Zend_Date_Exception + * @return Zend_Date|integer + */ + private function _day($calc, $day, $locale) + { + if ($day === null) { + throw new Zend_Date_Exception('parameter $day must be set, null is not allowed'); + } + + if ($locale === null) { + $locale = $this->getLocale(); + } + + if ($day instanceof Zend_Date) { + $day = $day->toString(self::DAY_SHORT, 'iso', $locale); + } + + if (is_numeric($day)) { + $type = self::DAY_SHORT; + } else if (is_array($day)) { + if (isset($day['day']) === true) { + $day = $day['day']; + $type = self::WEEKDAY; + } else { + throw new Zend_Date_Exception("no day given in array"); + } + } else { + switch (iconv_strlen($day, 'UTF-8')) { + case 1 : + $type = self::WEEKDAY_NARROW; + break; + case 2: + $type = self::WEEKDAY_NAME; + break; + case 3: + $type = self::WEEKDAY_SHORT; + break; + default: + $type = self::WEEKDAY; + break; + } + } + $return = $this->_calcdetail($calc, $day, $type, $locale); + if ($calc != 'cmp') { + return $this; + } + return $return; + } + + + /** + * Sets a new day + * The day can be a number or a string. Setting days lower then 0 or greater than the number of this months days + * will result in adding or subtracting the relevant month. + * If a localized dayname is given it will be parsed with the default locale or the optional + * set locale. + * Returned is the new date object + * Example: setDay('Montag', 'de_AT'); will set the monday of this week as day. + * + * @param string|integer|array|Zend_Date $day Day to set + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date Provides a fluent interface + * @throws Zend_Date_Exception + */ + public function setDay($day, $locale = null) + { + return $this->_day('set', $day, $locale); + } + + + /** + * Adds days to the existing date object. + * The day can be a number or a string. Adding days lower then 0 or greater than the number of this months days + * will result in adding or subtracting the relevant month. + * If a localized dayname is given it will be parsed with the default locale or the optional + * set locale. + * + * @param string|integer|array|Zend_Date $day Day to add + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date Provides a fluent interface + * @throws Zend_Date_Exception + */ + public function addDay($day, $locale = null) + { + return $this->_day('add', $day, $locale); + } + + + /** + * Subtracts days from the existing date object. + * The day can be a number or a string. Subtracting days lower then 0 or greater than the number of this months days + * will result in adding or subtracting the relevant month. + * If a localized dayname is given it will be parsed with the default locale or the optional + * set locale. + * + * @param string|integer|array|Zend_Date $day Day to sub + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date Provides a fluent interface + * @throws Zend_Date_Exception + */ + public function subDay($day, $locale = null) + { + return $this->_day('sub', $day, $locale); + } + + + /** + * Compares the day with the existing date object, ignoring other date parts. + * For example: 'Monday', 'en' -> 08.Jan.2007 -> 0 + * Returns if equal, earlier or later + * + * @param string|integer|array|Zend_Date $day Day to compare + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return integer 0 = equal, 1 = later, -1 = earlier + * @throws Zend_Date_Exception + */ + public function compareDay($day, $locale = null) + { + return $this->_day('cmp', $day, $locale); + } + + + /** + * Returns the weekday as new date object + * Weekday is always from 1-7 + * Example: 09-Jan-2007 -> 2 = Tuesday -> 02-Jan-1970 (when 02.01.1970 is also Tuesday) + * + * @param Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date + */ + public function getWeekday($locale = null) + { + if (self::$_options['format_type'] == 'php') { + $format = 'l'; + } else { + $format = self::WEEKDAY; + } + + return $this->copyPart($format, $locale); + } + + + /** + * Returns the calculated weekday + * + * @param string $calc Type of calculation to make + * @param Zend_Date $weekday Weekday to calculate, when null the actual weekday is calculated + * @param Zend_Locale $locale Locale for parsing input + * @return Zend_Date|integer + * @throws Zend_Date_Exception + */ + private function _weekday($calc, $weekday, $locale) + { + if ($weekday === null) { + throw new Zend_Date_Exception('parameter $weekday must be set, null is not allowed'); + } + + if ($locale === null) { + $locale = $this->getLocale(); + } + + if ($weekday instanceof Zend_Date) { + $weekday = $weekday->toString(self::WEEKDAY_8601, 'iso', $locale); + } + + if (is_numeric($weekday)) { + $type = self::WEEKDAY_8601; + } else if (is_array($weekday)) { + if (isset($weekday['weekday']) === true) { + $weekday = $weekday['weekday']; + $type = self::WEEKDAY; + } else { + throw new Zend_Date_Exception("no weekday given in array"); + } + } else { + switch(iconv_strlen($weekday, 'UTF-8')) { + case 1: + $type = self::WEEKDAY_NARROW; + break; + case 2: + $type = self::WEEKDAY_NAME; + break; + case 3: + $type = self::WEEKDAY_SHORT; + break; + default: + $type = self::WEEKDAY; + break; + } + } + $return = $this->_calcdetail($calc, $weekday, $type, $locale); + if ($calc != 'cmp') { + return $this; + } + return $return; + } + + + /** + * Sets a new weekday + * The weekday can be a number or a string. If a localized weekday name is given, + * then it will be parsed as a date in $locale (defaults to the same locale as $this). + * Returned is the new date object. + * Example: setWeekday(3); will set the wednesday of this week as day. + * + * @param string|integer|array|Zend_Date $weekday Weekday to set + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date Provides a fluent interface + * @throws Zend_Date_Exception + */ + public function setWeekday($weekday, $locale = null) + { + return $this->_weekday('set', $weekday, $locale); + } + + + /** + * Adds weekdays to the existing date object. + * The weekday can be a number or a string. + * If a localized dayname is given it will be parsed with the default locale or the optional + * set locale. + * Returned is the new date object + * Example: addWeekday(3); will add the difference of days from the begining of the month until + * wednesday. + * + * @param string|integer|array|Zend_Date $weekday Weekday to add + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date Provides a fluent interface + * @throws Zend_Date_Exception + */ + public function addWeekday($weekday, $locale = null) + { + return $this->_weekday('add', $weekday, $locale); + } + + + /** + * Subtracts weekdays from the existing date object. + * The weekday can be a number or a string. + * If a localized dayname is given it will be parsed with the default locale or the optional + * set locale. + * Returned is the new date object + * Example: subWeekday(3); will subtract the difference of days from the begining of the month until + * wednesday. + * + * @param string|integer|array|Zend_Date $weekday Weekday to sub + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date Provides a fluent interface + * @throws Zend_Date_Exception + */ + public function subWeekday($weekday, $locale = null) + { + return $this->_weekday('sub', $weekday, $locale); + } + + + /** + * Compares the weekday with the existing date object, ignoring other date parts. + * For example: 'Monday', 'en' -> 08.Jan.2007 -> 0 + * Returns if equal, earlier or later + * + * @param string|integer|array|Zend_Date $weekday Weekday to compare + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return integer 0 = equal, 1 = later, -1 = earlier + * @throws Zend_Date_Exception + */ + public function compareWeekday($weekday, $locale = null) + { + return $this->_weekday('cmp', $weekday, $locale); + } + + + /** + * Returns the day of year as new date object + * Example: 02.Feb.1986 10:00:00 -> 02.Feb.1970 00:00:00 + * + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date + */ + public function getDayOfYear($locale = null) + { + if (self::$_options['format_type'] == 'php') { + $format = 'D'; + } else { + $format = self::DAY_OF_YEAR; + } + + return $this->copyPart($format, $locale); + } + + + /** + * Sets a new day of year + * The day of year is always a number. + * Returned is the new date object + * Example: 04.May.2004 -> setDayOfYear(10) -> 10.Jan.2004 + * + * @param string|integer|array|Zend_Date $day Day of Year to set + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date Provides a fluent interface + * @throws Zend_Date_Exception + */ + public function setDayOfYear($day, $locale = null) + { + return $this->_calcvalue('set', $day, 'day of year', self::DAY_OF_YEAR, $locale); + } + + + /** + * Adds a day of year to the existing date object. + * The day of year is always a number. + * Returned is the new date object + * Example: addDayOfYear(10); will add 10 days to the existing date object. + * + * @param string|integer|array|Zend_Date $day Day of Year to add + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date Provides a fluent interface + * @throws Zend_Date_Exception + */ + public function addDayOfYear($day, $locale = null) + { + return $this->_calcvalue('add', $day, 'day of year', self::DAY_OF_YEAR, $locale); + } + + + /** + * Subtracts a day of year from the existing date object. + * The day of year is always a number. + * Returned is the new date object + * Example: subDayOfYear(10); will subtract 10 days from the existing date object. + * + * @param string|integer|array|Zend_Date $day Day of Year to sub + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date Provides a fluent interface + * @throws Zend_Date_Exception + */ + public function subDayOfYear($day, $locale = null) + { + return $this->_calcvalue('sub', $day, 'day of year', self::DAY_OF_YEAR, $locale); + } + + + /** + * Compares the day of year with the existing date object. + * For example: compareDayOfYear(33) -> 02.Feb.2007 -> 0 + * Returns if equal, earlier or later + * + * @param string|integer|array|Zend_Date $day Day of Year to compare + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return integer 0 = equal, 1 = later, -1 = earlier + * @throws Zend_Date_Exception + */ + public function compareDayOfYear($day, $locale = null) + { + return $this->_calcvalue('cmp', $day, 'day of year', self::DAY_OF_YEAR, $locale); + } + + + /** + * Returns the hour as new date object + * Example: 02.Feb.1986 10:30:25 -> 01.Jan.1970 10:00:00 + * + * @param Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date + */ + public function getHour($locale = null) + { + return $this->copyPart(self::HOUR, $locale); + } + + + /** + * Sets a new hour + * The hour is always a number. + * Returned is the new date object + * Example: 04.May.1993 13:07:25 -> setHour(7); -> 04.May.1993 07:07:25 + * + * @param string|integer|array|Zend_Date $hour Hour to set + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date Provides a fluent interface + * @throws Zend_Date_Exception + */ + public function setHour($hour, $locale = null) + { + return $this->_calcvalue('set', $hour, 'hour', self::HOUR_SHORT, $locale); + } + + + /** + * Adds hours to the existing date object. + * The hour is always a number. + * Returned is the new date object + * Example: 04.May.1993 13:07:25 -> addHour(12); -> 05.May.1993 01:07:25 + * + * @param string|integer|array|Zend_Date $hour Hour to add + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date Provides a fluent interface + * @throws Zend_Date_Exception + */ + public function addHour($hour, $locale = null) + { + return $this->_calcvalue('add', $hour, 'hour', self::HOUR_SHORT, $locale); + } + + + /** + * Subtracts hours from the existing date object. + * The hour is always a number. + * Returned is the new date object + * Example: 04.May.1993 13:07:25 -> subHour(6); -> 05.May.1993 07:07:25 + * + * @param string|integer|array|Zend_Date $hour Hour to sub + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date Provides a fluent interface + * @throws Zend_Date_Exception + */ + public function subHour($hour, $locale = null) + { + return $this->_calcvalue('sub', $hour, 'hour', self::HOUR_SHORT, $locale); + } + + + /** + * Compares the hour with the existing date object. + * For example: 10:30:25 -> compareHour(10) -> 0 + * Returns if equal, earlier or later + * + * @param string|integer|array|Zend_Date $hour Hour to compare + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return integer 0 = equal, 1 = later, -1 = earlier + * @throws Zend_Date_Exception + */ + public function compareHour($hour, $locale = null) + { + return $this->_calcvalue('cmp', $hour, 'hour', self::HOUR_SHORT, $locale); + } + + + /** + * Returns the minute as new date object + * Example: 02.Feb.1986 10:30:25 -> 01.Jan.1970 00:30:00 + * + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date + */ + public function getMinute($locale = null) + { + if (self::$_options['format_type'] == 'php') { + $format = 'i'; + } else { + $format = self::MINUTE; + } + + return $this->copyPart($format, $locale); + } + + + /** + * Sets a new minute + * The minute is always a number. + * Returned is the new date object + * Example: 04.May.1993 13:07:25 -> setMinute(29); -> 04.May.1993 13:29:25 + * + * @param string|integer|array|Zend_Date $minute Minute to set + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date Provides a fluent interface + * @throws Zend_Date_Exception + */ + public function setMinute($minute, $locale = null) + { + return $this->_calcvalue('set', $minute, 'minute', self::MINUTE_SHORT, $locale); + } + + + /** + * Adds minutes to the existing date object. + * The minute is always a number. + * Returned is the new date object + * Example: 04.May.1993 13:07:25 -> addMinute(65); -> 04.May.1993 13:12:25 + * + * @param string|integer|array|Zend_Date $minute Minute to add + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date Provides a fluent interface + * @throws Zend_Date_Exception + */ + public function addMinute($minute, $locale = null) + { + return $this->_calcvalue('add', $minute, 'minute', self::MINUTE_SHORT, $locale); + } + + + /** + * Subtracts minutes from the existing date object. + * The minute is always a number. + * Returned is the new date object + * Example: 04.May.1993 13:07:25 -> subMinute(9); -> 04.May.1993 12:58:25 + * + * @param string|integer|array|Zend_Date $minute Minute to sub + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date Provides a fluent interface + * @throws Zend_Date_Exception + */ + public function subMinute($minute, $locale = null) + { + return $this->_calcvalue('sub', $minute, 'minute', self::MINUTE_SHORT, $locale); + } + + + /** + * Compares the minute with the existing date object. + * For example: 10:30:25 -> compareMinute(30) -> 0 + * Returns if equal, earlier or later + * + * @param string|integer|array|Zend_Date $minute Hour to compare + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return integer 0 = equal, 1 = later, -1 = earlier + * @throws Zend_Date_Exception + */ + public function compareMinute($minute, $locale = null) + { + return $this->_calcvalue('cmp', $minute, 'minute', self::MINUTE_SHORT, $locale); + } + + + /** + * Returns the second as new date object + * Example: 02.Feb.1986 10:30:25 -> 01.Jan.1970 00:00:25 + * + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date + */ + public function getSecond($locale = null) + { + if (self::$_options['format_type'] == 'php') { + $format = 's'; + } else { + $format = self::SECOND; + } + + return $this->copyPart($format, $locale); + } + + + /** + * Sets new seconds to the existing date object. + * The second is always a number. + * Returned is the new date object + * Example: 04.May.1993 13:07:25 -> setSecond(100); -> 04.May.1993 13:08:40 + * + * @param string|integer|array|Zend_Date $second Second to set + * @param string|Zend_Locale $locale (Optional) Locale for parsing input + * @return Zend_Date Provides a fluent interface + * @throws Zend_Date_Exception + */ + public function setSecond($second, $locale = null) + { + return $this->_calcvalue('set', $second, 'second', self::SECOND_SHORT, $locale); + } + + + /** + * Adds seconds to the existing date object. + * The second is always a number. + * Returned is the new date object + * Example: 04.May.1993 13:07:25 -> addSecond(65); -> 04.May.1993 13:08:30 + * + * @param string|integer|array|Zend_Date $second Second to add + * @param string|Zend_Locale $locale (Optional) Locale for parsing input + * @return Zend_Date Provides a fluent interface + * @throws Zend_Date_Exception + */ + public function addSecond($second, $locale = null) + { + return $this->_calcvalue('add', $second, 'second', self::SECOND_SHORT, $locale); + } + + + /** + * Subtracts seconds from the existing date object. + * The second is always a number. + * Returned is the new date object + * Example: 04.May.1993 13:07:25 -> subSecond(10); -> 04.May.1993 13:07:15 + * + * @param string|integer|array|Zend_Date $second Second to sub + * @param string|Zend_Locale $locale (Optional) Locale for parsing input + * @return Zend_Date Provides a fluent interface + * @throws Zend_Date_Exception + */ + public function subSecond($second, $locale = null) + { + return $this->_calcvalue('sub', $second, 'second', self::SECOND_SHORT, $locale); + } + + + /** + * Compares the second with the existing date object. + * For example: 10:30:25 -> compareSecond(25) -> 0 + * Returns if equal, earlier or later + * + * @param string|integer|array|Zend_Date $second Second to compare + * @param string|Zend_Locale $locale (Optional) Locale for parsing input + * @return integer 0 = equal, 1 = later, -1 = earlier + * @throws Zend_Date_Exception + */ + public function compareSecond($second, $locale = null) + { + return $this->_calcvalue('cmp', $second, 'second', self::SECOND_SHORT, $locale); + } + + + /** + * Returns the precision for fractional seconds + * + * @return integer + */ + public function getFractionalPrecision() + { + return $this->_precision; + } + + + /** + * Sets a new precision for fractional seconds + * + * @param integer $precision Precision for the fractional datepart 3 = milliseconds + * @throws Zend_Date_Exception + * @return Zend_Date Provides a fluent interface + */ + public function setFractionalPrecision($precision) + { + if (!intval($precision) or ($precision < 0) or ($precision > 9)) { + throw new Zend_Date_Exception("precision ($precision) must be a positive integer less than 10", 0, null, $precision); + } + + $this->_precision = (int) $precision; + if ($this->_precision < strlen($this->_fractional)) { + $this->_fractional = substr($this->_fractional, 0, $this->_precision); + } else { + $this->_fractional = str_pad($this->_fractional, $this->_precision, '0', STR_PAD_RIGHT); + } + + return $this; + } + + + /** + * Returns the milliseconds of the date object + * + * @return string + */ + public function getMilliSecond() + { + return $this->_fractional; + } + + /** + * Sets new milliseconds for the date object + * Example: setMilliSecond(550, 2) -> equals +5 Sec +50 MilliSec + * + * @param integer|Zend_Date $milli (Optional) Millisecond to set, when null the actual millisecond is set + * @param integer $precision (Optional) Fraction precision of the given milliseconds + * @throws Zend_Date_Exception + * @return Zend_Date Provides a fluent interface + */ + public function setMilliSecond($milli = null, $precision = null) + { + if ($milli === null) { + list($milli, $time) = explode(" ", microtime()); + $milli = intval($milli); + $precision = 6; + } else if (!is_numeric($milli)) { + throw new Zend_Date_Exception("invalid milli second ($milli) operand", 0, null, $milli); + } + + if ($precision === null) { + $precision = $this->_precision; + } + + if (!is_int($precision) || $precision < 1 || $precision > 9) { + throw new Zend_Date_Exception("precision ($precision) must be a positive integer less than 10", 0, null, $precision); + } + + $this->_fractional = 0; + $this->addMilliSecond($milli, $precision); + return $this; + } + + /** + * Adds milliseconds to the date object + * + * @param integer|Zend_Date $milli (Optional) Millisecond to add, when null the actual millisecond is added + * @param integer $precision (Optional) Fractional precision for the given milliseconds + * @throws Zend_Date_Exception + * @return Zend_Date Provides a fluent interface + */ + public function addMilliSecond($milli = null, $precision = null) + { + if ($milli === null) { + list($milli, $time) = explode(" ", microtime()); + $milli = intval($milli); + } else if (!is_numeric($milli)) { + throw new Zend_Date_Exception("invalid milli second ($milli) operand", 0, null, $milli); + } + + if ($precision === null) { + // Use internal default precision + // Is not as logic as using the length of the input. But this would break tests and maybe other things + // as an input value of integer 10, which is used in tests, must be parsed as 10 milliseconds (real milliseconds, precision 3) + // but with auto-detect of precision, 100 milliseconds would be added. + $precision = $this->_precision; + } + + if (!is_int($precision) || $precision < 1 || $precision > 9) { + throw new Zend_Date_Exception( + "precision ($precision) must be a positive integer less than 10", 0, null, $precision + ); + } + + if ($this->_precision > $precision) { + $milli = $milli * pow(10, $this->_precision - $precision); + } elseif ($this->_precision < $precision) { + $milli = round($milli / pow(10, $precision - $this->_precision)); + } + + $this->_fractional += $milli; + + // Add/sub milliseconds + add/sub seconds + $max = pow(10, $this->_precision); + // Milli includes seconds + if ($this->_fractional >= $max) { + while ($this->_fractional >= $max) { + $this->addSecond(1); + $this->_fractional -= $max; + } + } + + if ($this->_fractional < 0) { + while ($this->_fractional < 0) { + $this->subSecond(1); + $this->_fractional += $max; + } + } + + if ($this->_precision > strlen($this->_fractional)) { + $this->_fractional = str_pad($this->_fractional, $this->_precision, '0', STR_PAD_LEFT); + } + + return $this; + } + + + /** + * Subtracts a millisecond + * + * @param integer|Zend_Date $milli (Optional) Millisecond to sub, when null the actual millisecond is subtracted + * @param integer $precision (Optional) Fractional precision for the given milliseconds + * @return Zend_Date Provides a fluent interface + */ + public function subMilliSecond($milli = null, $precision = null) + { + $this->addMilliSecond(0 - $milli, $precision); + return $this; + } + + /** + * Compares only the millisecond part, returning the difference + * + * @param integer|Zend_Date $milli OPTIONAL Millisecond to compare, when null the actual millisecond is compared + * @param integer $precision OPTIONAL Fractional precision for the given milliseconds + * @throws Zend_Date_Exception On invalid input + * @return integer 0 = equal, 1 = later, -1 = earlier + */ + public function compareMilliSecond($milli = null, $precision = null) + { + if ($milli === null) { + list($milli, $time) = explode(" ", microtime()); + $milli = intval($milli); + } else if (is_numeric($milli) === false) { + throw new Zend_Date_Exception("invalid milli second ($milli) operand", 0, null, $milli); + } + + if ($precision === null) { + $precision = strlen($milli); + } else if (!is_int($precision) || $precision < 1 || $precision > 9) { + throw new Zend_Date_Exception("precision ($precision) must be a positive integer less than 10", 0, null, $precision); + } + + if ($precision === 0) { + throw new Zend_Date_Exception('precision is 0'); + } + + if ($precision != $this->_precision) { + if ($precision > $this->_precision) { + $diff = $precision - $this->_precision; + $milli = (int) ($milli / (10 * $diff)); + } else { + $diff = $this->_precision - $precision; + $milli = (int) ($milli * (10 * $diff)); + } + } + + $comp = $this->_fractional - $milli; + if ($comp < 0) { + return -1; + } else if ($comp > 0) { + return 1; + } + return 0; + } + + /** + * Returns the week as new date object using monday as begining of the week + * Example: 12.Jan.2007 -> 08.Jan.1970 00:00:00 + * + * @param Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date + */ + public function getWeek($locale = null) + { + if (self::$_options['format_type'] == 'php') { + $format = 'W'; + } else { + $format = self::WEEK; + } + + return $this->copyPart($format, $locale); + } + + /** + * Sets a new week. The week is always a number. The day of week is not changed. + * Returned is the new date object + * Example: 09.Jan.2007 13:07:25 -> setWeek(1); -> 02.Jan.2007 13:07:25 + * + * @param string|integer|array|Zend_Date $week Week to set + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date Provides a fluent interface + * @throws Zend_Date_Exception + */ + public function setWeek($week, $locale = null) + { + return $this->_calcvalue('set', $week, 'week', self::WEEK, $locale); + } + + /** + * Adds a week. The week is always a number. The day of week is not changed. + * Returned is the new date object + * Example: 09.Jan.2007 13:07:25 -> addWeek(1); -> 16.Jan.2007 13:07:25 + * + * @param string|integer|array|Zend_Date $week Week to add + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date Provides a fluent interface + * @throws Zend_Date_Exception + */ + public function addWeek($week, $locale = null) + { + return $this->_calcvalue('add', $week, 'week', self::WEEK, $locale); + } + + /** + * Subtracts a week. The week is always a number. The day of week is not changed. + * Returned is the new date object + * Example: 09.Jan.2007 13:07:25 -> subWeek(1); -> 02.Jan.2007 13:07:25 + * + * @param string|integer|array|Zend_Date $week Week to sub + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date Provides a fluent interface + * @throws Zend_Date_Exception + */ + public function subWeek($week, $locale = null) + { + return $this->_calcvalue('sub', $week, 'week', self::WEEK, $locale); + } + + /** + * Compares only the week part, returning the difference + * Returned is the new date object + * Returns if equal, earlier or later + * Example: 09.Jan.2007 13:07:25 -> compareWeek(2); -> 0 + * + * @param string|integer|array|Zend_Date $week Week to compare + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return integer 0 = equal, 1 = later, -1 = earlier + */ + public function compareWeek($week, $locale = null) + { + return $this->_calcvalue('cmp', $week, 'week', self::WEEK, $locale); + } + + /** + * Sets a new standard locale for the date object. + * This locale will be used for all functions + * Returned is the really set locale. + * Example: 'de_XX' will be set to 'de' because 'de_XX' does not exist + * 'xx_YY' will be set to 'root' because 'xx' does not exist + * + * @param string|Zend_Locale $locale (Optional) Locale for parsing input + * @throws Zend_Date_Exception When the given locale does not exist + * @return Zend_Date Provides fluent interface + */ + public function setLocale($locale = null) + { + try { + $this->_locale = Zend_Locale::findLocale($locale); + } catch (Zend_Locale_Exception $e) { + throw new Zend_Date_Exception($e->getMessage(), 0, $e); + } + + return $this; + } + + /** + * Returns the actual set locale + * + * @return string + */ + public function getLocale() + { + return $this->_locale; + } + + /** + * Checks if the given date is a real date or datepart. + * Returns false if a expected datepart is missing or a datepart exceeds its possible border. + * But the check will only be done for the expected dateparts which are given by format. + * If no format is given the standard dateformat for the actual locale is used. + * f.e. 30.February.2007 will return false if format is 'dd.MMMM.YYYY' + * + * @param string|array|Zend_Date $date Date to parse for correctness + * @param string $format (Optional) Format for parsing the date string + * @param string|Zend_Locale $locale (Optional) Locale for parsing date parts + * @return boolean True when all date parts are correct + */ + public static function isDate($date, $format = null, $locale = null) + { + if (!is_string($date) && !is_numeric($date) && !($date instanceof Zend_Date) && + !is_array($date)) { + return false; + } + + if (($format !== null) && ($format != 'ee') && ($format != 'ss') && ($format != 'GG') && ($format != 'MM') && ($format != 'EE') && ($format != 'TT') + && (Zend_Locale::isLocale($format, null, false))) { + $locale = $format; + $format = null; + } + + $locale = Zend_Locale::findLocale($locale); + + if ($format === null) { + $format = Zend_Locale_Format::getDateFormat($locale); + } else if ((self::$_options['format_type'] == 'php') && !defined($format)) { + $format = Zend_Locale_Format::convertPhpToIsoFormat($format); + } + + $format = self::_getLocalizedToken($format, $locale); + if (!is_array($date)) { + try { + $parsed = Zend_Locale_Format::getDate($date, array('locale' => $locale, + 'date_format' => $format, 'format_type' => 'iso', + 'fix_date' => false)); + } catch (Zend_Locale_Exception $e) { + // Date can not be parsed + return false; + } + } else { + $parsed = $date; + } + + if (((strpos($format, 'Y') !== false) or (strpos($format, 'y') !== false)) and + (!isset($parsed['year']))) { + // Year expected but not found + return false; + } + + if ((strpos($format, 'M') !== false) and (!isset($parsed['month']))) { + // Month expected but not found + return false; + } + + if ((strpos($format, 'd') !== false) and (!isset($parsed['day']))) { + // Day expected but not found + return false; + } + + if (((strpos($format, 'H') !== false) or (strpos($format, 'h') !== false)) and + (!isset($parsed['hour']))) { + // Hour expected but not found + return false; + } + + if ((strpos($format, 'm') !== false) and (!isset($parsed['minute']))) { + // Minute expected but not found + return false; + } + + if ((strpos($format, 's') !== false) and (!isset($parsed['second']))) { + // Second expected but not found + return false; + } + + // Set not given dateparts + if (isset($parsed['hour']) === false) { + $parsed['hour'] = 12; + } + + if (isset($parsed['minute']) === false) { + $parsed['minute'] = 0; + } + + if (isset($parsed['second']) === false) { + $parsed['second'] = 0; + } + + if (isset($parsed['month']) === false) { + $parsed['month'] = 1; + } + + if (isset($parsed['day']) === false) { + $parsed['day'] = 1; + } + + if (isset($parsed['year']) === false) { + $parsed['year'] = 1970; + } + + if (self::isYearLeapYear($parsed['year'])) { + $parsed['year'] = 1972; + } else { + $parsed['year'] = 1971; + } + + $date = new self($parsed, null, $locale); + $timestamp = $date->mktime($parsed['hour'], $parsed['minute'], $parsed['second'], + $parsed['month'], $parsed['day'], $parsed['year']); + + if ($parsed['year'] != $date->date('Y', $timestamp)) { + // Given year differs from parsed year + return false; + } + + if ($parsed['month'] != $date->date('n', $timestamp)) { + // Given month differs from parsed month + return false; + } + + if ($parsed['day'] != $date->date('j', $timestamp)) { + // Given day differs from parsed day + return false; + } + + if ($parsed['hour'] != $date->date('G', $timestamp)) { + // Given hour differs from parsed hour + return false; + } + + if ($parsed['minute'] != $date->date('i', $timestamp)) { + // Given minute differs from parsed minute + return false; + } + + if ($parsed['second'] != $date->date('s', $timestamp)) { + // Given second differs from parsed second + return false; + } + + return true; + } + + /** + * Returns the ISO Token for all localized constants + * + * @param string $token Token to normalize + * @param string $locale Locale to search + * @return string + */ + protected static function _getLocalizedToken($token, $locale) + { + switch($token) { + case self::ISO_8601 : + return "yyyy-MM-ddThh:mm:ss"; + break; + case self::RFC_2822 : + return "EEE, dd MMM yyyy HH:mm:ss"; + break; + case self::DATES : + return Zend_Locale_Data::getContent($locale, 'date'); + break; + case self::DATE_FULL : + return Zend_Locale_Data::getContent($locale, 'date', array('gregorian', 'full')); + break; + case self::DATE_LONG : + return Zend_Locale_Data::getContent($locale, 'date', array('gregorian', 'long')); + break; + case self::DATE_MEDIUM : + return Zend_Locale_Data::getContent($locale, 'date', array('gregorian', 'medium')); + break; + case self::DATE_SHORT : + return Zend_Locale_Data::getContent($locale, 'date', array('gregorian', 'short')); + break; + case self::TIMES : + return Zend_Locale_Data::getContent($locale, 'time'); + break; + case self::TIME_FULL : + return Zend_Locale_Data::getContent($locale, 'time', array('gregorian', 'full')); + break; + case self::TIME_LONG : + return Zend_Locale_Data::getContent($locale, 'time', array('gregorian', 'long')); + break; + case self::TIME_MEDIUM : + return Zend_Locale_Data::getContent($locale, 'time', array('gregorian', 'medium')); + break; + case self::TIME_SHORT : + return Zend_Locale_Data::getContent($locale, 'time', array('gregorian', 'short')); + break; + case self::DATETIME : + return Zend_Locale_Data::getContent($locale, 'datetime'); + break; + case self::DATETIME_FULL : + return Zend_Locale_Data::getContent($locale, 'datetime', array('gregorian', 'full')); + break; + case self::DATETIME_LONG : + return Zend_Locale_Data::getContent($locale, 'datetime', array('gregorian', 'long')); + break; + case self::DATETIME_MEDIUM : + return Zend_Locale_Data::getContent($locale, 'datetime', array('gregorian', 'medium')); + break; + case self::DATETIME_SHORT : + return Zend_Locale_Data::getContent($locale, 'datetime', array('gregorian', 'short')); + break; + case self::ATOM : + case self::RFC_3339 : + case self::W3C : + return "yyyy-MM-DD HH:mm:ss"; + break; + case self::COOKIE : + case self::RFC_850 : + return "EEEE, dd-MM-yyyy HH:mm:ss"; + break; + case self::RFC_822 : + case self::RFC_1036 : + case self::RFC_1123 : + case self::RSS : + return "EEE, dd MM yyyy HH:mm:ss"; + break; + } + + return $token; + } +} diff --git a/library/vendor/Zend/Date/Cities.php b/library/vendor/Zend/Date/Cities.php new file mode 100644 index 0000000..7b5f59a --- /dev/null +++ b/library/vendor/Zend/Date/Cities.php @@ -0,0 +1,321 @@ + array('latitude' => 5.3411111, 'longitude' => -4.0280556), + 'Abu Dhabi' => array('latitude' => 24.4666667, 'longitude' => 54.3666667), + 'Abuja' => array('latitude' => 9.1758333, 'longitude' => 7.1808333), + 'Accra' => array('latitude' => 5.55, 'longitude' => -0.2166667), + 'Adamstown' => array('latitude' => -25.0666667, 'longitude' => -130.0833333), + 'Addis Ababa' => array('latitude' => 9.0333333, 'longitude' => 38.7), + 'Adelaide' => array('latitude' => -34.9333333, 'longitude' => 138.6), + 'Algiers' => array('latitude' => 36.7630556, 'longitude' => 3.0505556), + 'Alofi' => array('latitude' => -19.0166667, 'longitude' => -169.9166667), + 'Amman' => array('latitude' => 31.95, 'longitude' => 35.9333333), + 'Amsterdam' => array('latitude' => 52.35, 'longitude' => 4.9166667), + 'Andorra la Vella' => array('latitude' => 42.5, 'longitude' => 1.5166667), + 'Ankara' => array('latitude' => 39.9272222, 'longitude' => 32.8644444), + 'Antananarivo' => array('latitude' => -18.9166667, 'longitude' => 47.5166667), + 'Apia' => array('latitude' => -13.8333333, 'longitude' => -171.7333333), + 'Ashgabat' => array('latitude' => 37.95, 'longitude' => 58.3833333), + 'Asmara' => array('latitude' => 15.3333333, 'longitude' => 38.9333333), + 'Astana' => array('latitude' => 51.1811111, 'longitude' => 71.4277778), + 'Asunción' => array('latitude' => -25.2666667, 'longitude' => -57.6666667), + 'Athens' => array('latitude' => 37.9833333, 'longitude' => 23.7333333), + 'Auckland' => array('latitude' => -36.8666667, 'longitude' => 174.7666667), + 'Avarua' => array('latitude' => -21.2, 'longitude' => -159.7666667), + 'Baghdad' => array('latitude' => 33.3386111, 'longitude' => 44.3938889), + 'Baku' => array('latitude' => 40.3952778, 'longitude' => 49.8822222), + 'Bamako' => array('latitude' => 12.65, 'longitude' => -8), + 'Bandar Seri Begawan' => array('latitude' => 4.8833333, 'longitude' => 114.9333333), + 'Bankok' => array('latitude' => 13.5833333, 'longitude' => 100.2166667), + 'Bangui' => array('latitude' => 4.3666667, 'longitude' => 18.5833333), + 'Banjul' => array('latitude' => 13.4530556, 'longitude' => -16.5775), + 'Basel' => array('latitude' => 47.5666667, 'longitude' => 7.6), + 'Basseterre' => array('latitude' => 17.3, 'longitude' => -62.7166667), + 'Beijing' => array('latitude' => 39.9288889, 'longitude' => 116.3883333), + 'Beirut' => array('latitude' => 33.8719444, 'longitude' => 35.5097222), + 'Belgrade' => array('latitude' => 44.8186111, 'longitude' => 20.4680556), + 'Belmopan' => array('latitude' => 17.25, 'longitude' => -88.7666667), + 'Berlin' => array('latitude' => 52.5166667, 'longitude' => 13.4), + 'Bern' => array('latitude' => 46.9166667, 'longitude' => 7.4666667), + 'Bishkek' => array('latitude' => 42.8730556, 'longitude' => 74.6002778), + 'Bissau' => array('latitude' => 11.85, 'longitude' => -15.5833333), + 'Bloemfontein' => array('latitude' => -29.1333333, 'longitude' => 26.2), + 'Bogotá' => array('latitude' => 4.6, 'longitude' => -74.0833333), + 'Brasilia' => array('latitude' => -15.7833333, 'longitude' => -47.9166667), + 'Bratislava' => array('latitude' => 48.15, 'longitude' => 17.1166667), + 'Brazzaville' => array('latitude' => -4.2591667, 'longitude' => 15.2847222), + 'Bridgetown' => array('latitude' => 13.1, 'longitude' => -59.6166667), + 'Brisbane' => array('latitude' => -27.5, 'longitude' => 153.0166667), + 'Brussels' => array('latitude' => 50.8333333, 'longitude' => 4.3333333), + 'Bucharest' => array('latitude' => 44.4333333, 'longitude' => 26.1), + 'Budapest' => array('latitude' => 47.5, 'longitude' => 19.0833333), + 'Buenos Aires' => array('latitude' => -34.5875, 'longitude' => -58.6725), + 'Bujumbura' => array('latitude' => -3.3761111, 'longitude' => 29.36), + 'Cairo' => array('latitude' => 30.05, 'longitude' => 31.25), + 'Calgary' => array('latitude' => 51.0833333, 'longitude' => -114.0833333), + 'Canberra' => array('latitude' => -35.2833333, 'longitude' => 149.2166667), + 'Cape Town' => array('latitude' => -33.9166667, 'longitude' => 18.4166667), + 'Caracas' => array('latitude' => 10.5, 'longitude' => -66.9166667), + 'Castries' => array('latitude' => 14, 'longitude' => -61), + 'Charlotte Amalie' => array('latitude' => 18.34389, 'longitude' => -64.93111), + 'Chicago' => array('latitude' => 41.85, 'longitude' => -87.65), + 'Chisinau' => array('latitude' => 47.055556, 'longitude' => 28.8575), + 'Cockburn Town' => array('latitude' => 21.4666667, 'longitude' => -71.1333333), + 'Colombo' => array('latitude' => 6.9319444, 'longitude' => 79.8477778), + 'Conakry' => array('latitude' => 9.5091667, 'longitude' => -13.7122222), + 'Copenhagen' => array('latitude' => 55.6666667, 'longitude' => 12.5833333), + 'Cotonou' => array('latitude' => 6.35, 'longitude' => 2.4333333), + 'Dakar' => array('latitude' => 14.6708333, 'longitude' => -17.4380556), + 'Damascus' => array('latitude' => 33.5, 'longitude' => 36.3), + 'Dar es Salaam' => array('latitude' => -6.8, 'longitude' => 39.2833333), + 'Dhaka' => array('latitude' => 23.7230556, 'longitude' => 90.4086111), + 'Dili' => array('latitude' => -8.5586111, 'longitude' => 125.5736111), + 'Djibouti' => array('latitude' => 11.595, 'longitude' => 43.1480556), + 'Dodoma' => array('latitude' => -6.1833333, 'longitude' => 35.75), + 'Doha' => array('latitude' => 25.2866667, 'longitude' => 51.5333333), + 'Dubai' => array('latitude' => 25.2522222, 'longitude' => 55.28), + 'Dublin' => array('latitude' => 53.3330556, 'longitude' => -6.2488889), + 'Dushanbe' => array('latitude' => 38.56, 'longitude' => 68.7738889 ), + 'Fagatogo' => array('latitude' => -14.2825, 'longitude' => -170.69), + 'Fongafale' => array('latitude' => -8.5166667, 'longitude' => 179.2166667), + 'Freetown' => array('latitude' => 8.49, 'longitude' => -13.2341667), + 'Gaborone' => array('latitude' => -24.6463889, 'longitude' => 25.9119444), + 'Geneva' => array('latitude' => 46.2, 'longitude' => 6.1666667), + 'George Town' => array('latitude' => 19.3, 'longitude' => -81.3833333), + 'Georgetown' => array('latitude' => 6.8, 'longitude' => -58.1666667), + 'Gibraltar' => array('latitude' => 36.1333333, 'longitude' => -5.35), + 'Glasgow' => array('latitude' => 55.8333333, 'longitude' => -4.25), + 'Guatemala la Nueva' => array('latitude' => 14.6211111, 'longitude' => -90.5269444), + 'Hagatna' => array('latitude' => 13.47417, 'longitude' => 144.74778), + 'The Hague' => array('latitude' => 52.0833333, 'longitude' => 4.3), + 'Hamilton' => array('latitude' => 32.2941667, 'longitude' => -64.7838889), + 'Hanoi' => array('latitude' => 21.0333333, 'longitude' => 105.85), + 'Harare' => array('latitude' => -17.8177778, 'longitude' => 31.0447222), + 'Havana' => array('latitude' => 23.1319444, 'longitude' => -82.3641667), + 'Helsinki' => array('latitude' => 60.1755556, 'longitude' => 24.9341667), + 'Honiara' => array('latitude' => -9.4333333, 'longitude' => 159.95), + 'Islamabad' => array('latitude' => 30.8486111, 'longitude' => 72.4944444), + 'Istanbul' => array('latitude' => 41.0186111, 'longitude' => 28.9647222), + 'Jakarta' => array('latitude' => -6.1744444, 'longitude' => 106.8294444), + 'Jamestown' => array('latitude' => -15.9333333, 'longitude' => -5.7166667), + 'Jerusalem' => array('latitude' => 31.7666667, 'longitude' => 35.2333333), + 'Johannesburg' => array('latitude' => -26.2, 'longitude' => 28.0833333), + 'Kabul' => array('latitude' => 34.5166667, 'longitude' => 69.1833333), + 'Kampala' => array('latitude' => 0.3155556, 'longitude' => 32.5655556), + 'Kathmandu' => array('latitude' => 27.7166667, 'longitude' => 85.3166667), + 'Khartoum' => array('latitude' => 15.5880556, 'longitude' => 32.5341667), + 'Kigali' => array('latitude' => -1.9536111, 'longitude' => 30.0605556), + 'Kingston' => array('latitude' => -29.05, 'longitude' => 167.95), + 'Kingstown' => array('latitude' => 13.1333333, 'longitude' => -61.2166667), + 'Kinshasa' => array('latitude' => -4.3, 'longitude' => 15.3), + 'Kolkata' => array('latitude' => 22.5697222, 'longitude' => 88.3697222), + 'Kuala Lumpur' => array('latitude' => 3.1666667, 'longitude' => 101.7), + 'Kuwait City' => array('latitude' => 29.3697222, 'longitude' => 47.9783333), + 'Kiev' => array('latitude' => 50.4333333, 'longitude' => 30.5166667), + 'La Paz' => array('latitude' => -16.5, 'longitude' => -68.15), + 'Libreville' => array('latitude' => 0.3833333, 'longitude' => 9.45), + 'Lilongwe' => array('latitude' => -13.9833333, 'longitude' => 33.7833333), + 'Lima' => array('latitude' => -12.05, 'longitude' => -77.05), + 'Lisbon' => array('latitude' => 38.7166667, 'longitude' => -9.1333333), + 'Ljubljana' => array('latitude' => 46.0552778, 'longitude' => 14.5144444), + 'Lobamba' => array('latitude' => -26.4666667, 'longitude' => 31.2), + 'Lomé' => array('latitude' => 9.7166667, 'longitude' => 38.3), + 'London' => array('latitude' => 51.5, 'longitude' => -0.1166667), + 'Los Angeles' => array('latitude' => 34.05222, 'longitude' => -118.24278), + 'Luanda' => array('latitude' => -8.8383333, 'longitude' => 13.2344444), + 'Lusaka' => array('latitude' => -15.4166667, 'longitude' => 28.2833333), + 'Luxembourg' => array('latitude' => 49.6116667, 'longitude' => 6.13), + 'Madrid' => array('latitude' => 40.4, 'longitude' => -3.6833333), + 'Majuro' => array('latitude' => 7.1, 'longitude' => 171.3833333), + 'Malabo' => array('latitude' => 3.75, 'longitude' => 8.7833333), + 'Managua' => array('latitude' => 12.1508333, 'longitude' => -86.2683333), + 'Manama' => array('latitude' => 26.2361111, 'longitude' => 50.5830556), + 'Manila' => array('latitude' => 14.6041667, 'longitude' => 120.9822222), + 'Maputo' => array('latitude' => -25.9652778, 'longitude' => 32.5891667), + 'Maseru' => array('latitude' => -29.3166667, 'longitude' => 27.4833333), + 'Mbabane' => array('latitude' => -26.3166667, 'longitude' => 31.1333333), + 'Melbourne' => array('latitude' => -37.8166667, 'longitude' => 144.9666667), + 'Melekeok' => array('latitude' => 7.4933333, 'longitude' => 134.6341667), + 'Mexiko City' => array('latitude' => 19.4341667, 'longitude' => -99.1386111), + 'Minsk' => array('latitude' => 53.9, 'longitude' => 27.5666667), + 'Mogadishu' => array('latitude' => 2.0666667, 'longitude' => 45.3666667), + 'Monaco' => array('latitude' => 43.7333333, 'longitude' => 7.4166667), + 'Monrovia' => array('latitude' => 6.3105556, 'longitude' => -10.8047222), + 'Montevideo' => array('latitude' => -34.8580556, 'longitude' => -56.1708333), + 'Montreal' => array('latitude' => 45.5, 'longitude' => -73.5833333), + 'Moroni' => array('latitude' => -11.7041667, 'longitude' => 43.2402778), + 'Moscow' => array('latitude' => 55.7522222, 'longitude' => 37.6155556), + 'Muscat' => array('latitude' => 23.6133333, 'longitude' => 58.5933333), + 'Nairobi' => array('latitude' => -1.3166667, 'longitude' => 36.8333333), + 'Nassau' => array('latitude' => 25.0833333, 'longitude' => -77.35), + 'N´Djamena' => array('latitude' => 12.1130556, 'longitude' => 15.0491667), + 'New Dehli' => array('latitude' => 28.6, 'longitude' => 77.2), + 'New York' => array('latitude' => 40.71417, 'longitude' => -74.00639), + 'Newcastle' => array('latitude' => -32.9166667, 'longitude' => 151.75), + 'Niamey' => array('latitude' => 13.6666667, 'longitude' => 1.7833333), + 'Nicosia' => array('latitude' => 35.1666667, 'longitude' => 33.3666667), + 'Nouakchott' => array('latitude' => 18.0863889, 'longitude' => -15.9752778), + 'Noumea' => array('latitude' => -22.2666667, 'longitude' => 166.45), + 'Nuku´alofa' => array('latitude' => -21.1333333, 'longitude' => -175.2), + 'Nuuk' => array('latitude' => 64.1833333, 'longitude' => -51.75), + 'Oranjestad' => array('latitude' => 12.5166667, 'longitude' => -70.0333333), + 'Oslo' => array('latitude' => 59.9166667, 'longitude' => 10.75), + 'Ouagadougou' => array('latitude' => 12.3702778, 'longitude' => -1.5247222), + 'Palikir' => array('latitude' => 6.9166667, 'longitude' => 158.15), + 'Panama City' => array('latitude' => 8.9666667, 'longitude' => -79.5333333), + 'Papeete' => array('latitude' => -17.5333333, 'longitude' => -149.5666667), + 'Paramaribo' => array('latitude' => 5.8333333, 'longitude' => -55.1666667), + 'Paris' => array('latitude' => 48.8666667, 'longitude' => 2.3333333), + 'Perth' => array('latitude' => -31.9333333, 'longitude' => 115.8333333), + 'Phnom Penh' => array('latitude' => 11.55, 'longitude' => 104.9166667), + 'Podgorica' => array('latitude' => 43.7752778, 'longitude' => 19.6827778), + 'Port Louis' => array('latitude' => -20.1666667, 'longitude' => 57.5), + 'Port Moresby' => array('latitude' => -9.4647222, 'longitude' => 147.1925), + 'Port-au-Prince' => array('latitude' => 18.5391667, 'longitude' => -72.335), + 'Port of Spain' => array('latitude' => 10.6666667, 'longitude' => -61.5), + 'Porto-Novo' => array('latitude' => 6.4833333, 'longitude' => 2.6166667), + 'Prague' => array('latitude' => 50.0833333, 'longitude' => 14.4666667), + 'Praia' => array('latitude' => 14.9166667, 'longitude' => -23.5166667), + 'Pretoria' => array('latitude' => -25.7069444, 'longitude' => 28.2294444), + 'Pyongyang' => array('latitude' => 39.0194444, 'longitude' => 125.7547222), + 'Quito' => array('latitude' => -0.2166667, 'longitude' => -78.5), + 'Rabat' => array('latitude' => 34.0252778, 'longitude' => -6.8361111), + 'Reykjavik' => array('latitude' => 64.15, 'longitude' => -21.95), + 'Riga' => array('latitude' => 56.95, 'longitude' => 24.1), + 'Rio de Janero' => array('latitude' => -22.9, 'longitude' => -43.2333333), + 'Road Town' => array('latitude' => 18.4166667, 'longitude' => -64.6166667), + 'Rome' => array('latitude' => 41.9, 'longitude' => 12.4833333), + 'Roseau' => array('latitude' => 15.3, 'longitude' => -61.4), + 'Rotterdam' => array('latitude' => 51.9166667, 'longitude' => 4.5), + 'Salvador' => array('latitude' => -12.9833333, 'longitude' => -38.5166667), + 'San José' => array('latitude' => 9.9333333, 'longitude' => -84.0833333), + 'San Juan' => array('latitude' => 18.46833, 'longitude' => -66.10611), + 'San Marino' => array('latitude' => 43.5333333, 'longitude' => 12.9666667), + 'San Salvador' => array('latitude' => 13.7086111, 'longitude' => -89.2030556), + 'Sanaá' => array('latitude' => 15.3547222, 'longitude' => 44.2066667), + 'Santa Cruz' => array('latitude' => -17.8, 'longitude' => -63.1666667), + 'Santiago' => array('latitude' => -33.45, 'longitude' => -70.6666667), + 'Santo Domingo' => array('latitude' => 18.4666667, 'longitude' => -69.9), + 'Sao Paulo' => array('latitude' => -23.5333333, 'longitude' => -46.6166667), + 'Sarajevo' => array('latitude' => 43.85, 'longitude' => 18.3833333), + 'Seoul' => array('latitude' => 37.5663889, 'longitude' => 126.9997222), + 'Shanghai' => array('latitude' => 31.2222222, 'longitude' => 121.4580556), + 'Sydney' => array('latitude' => -33.8833333, 'longitude' => 151.2166667), + 'Singapore' => array('latitude' => 1.2930556, 'longitude' => 103.8558333), + 'Skopje' => array('latitude' => 42, 'longitude' => 21.4333333), + 'Sofia' => array('latitude' => 42.6833333, 'longitude' => 23.3166667), + 'St. George´s' => array('latitude' => 12.05, 'longitude' => -61.75), + 'St. John´s' => array('latitude' => 17.1166667, 'longitude' => -61.85), + 'Stanley' => array('latitude' => -51.7, 'longitude' => -57.85), + 'Stockholm' => array('latitude' => 59.3333333, 'longitude' => 18.05), + 'Suva' => array('latitude' => -18.1333333, 'longitude' => 178.4166667), + 'Taipei' => array('latitude' => 25.0166667, 'longitude' => 121.45), + 'Tallinn' => array('latitude' => 59.4338889, 'longitude' => 24.7280556), + 'Tashkent' => array('latitude' => 41.3166667, 'longitude' => 69.25), + 'Tbilisi' => array('latitude' => 41.725, 'longitude' => 44.7908333), + 'Tegucigalpa' => array('latitude' => 14.1, 'longitude' => -87.2166667), + 'Tehran' => array('latitude' => 35.6719444, 'longitude' => 51.4244444), + 'The Hague' => array('latitude' => 52.0833333, 'longitude' => 4.3), + 'Thimphu' => array('latitude' => 27.4833333, 'longitude' => 89.6), + 'Tirana' => array('latitude' => 41.3275, 'longitude' => 19.8188889), + 'Tiraspol' => array('latitude' => 46.8402778, 'longitude' => 29.6433333), + 'Tokyo' => array('latitude' => 35.685, 'longitude' => 139.7513889), + 'Toronto' => array('latitude' => 43.6666667, 'longitude' => -79.4166667), + 'Tórshavn' => array('latitude' => 62.0166667, 'longitude' => -6.7666667), + 'Tripoli' => array('latitude' => 32.8925, 'longitude' => 13.18), + 'Tunis' => array('latitude' => 36.8027778, 'longitude' => 10.1797222), + 'Ulaanbaatar' => array('latitude' => 47.9166667, 'longitude' => 106.9166667), + 'Vaduz' => array('latitude' => 47.1333333, 'longitude' => 9.5166667), + 'Valletta' => array('latitude' => 35.8997222, 'longitude' => 14.5147222), + 'Valparaiso' => array('latitude' => -33.0477778, 'longitude' => -71.6011111), + 'Vancouver' => array('latitude' => 49.25, 'longitude' => -123.1333333), + 'Vatican City' => array('latitude' => 41.9, 'longitude' => 12.4833333), + 'Victoria' => array('latitude' => -4.6166667, 'longitude' => 55.45), + 'Vienna' => array('latitude' => 48.2, 'longitude' => 16.3666667), + 'Vientaine' => array('latitude' => 17.9666667, 'longitude' => 102.6), + 'Vilnius' => array('latitude' => 54.6833333, 'longitude' => 25.3166667), + 'Warsaw' => array('latitude' => 52.25, 'longitude' => 21), + 'Washington dc' => array('latitude' => 38.895, 'longitude' => -77.03667), + 'Wellington' => array('latitude' => -41.3, 'longitude' => 174.7833333), + 'Willemstad' => array('latitude' => 12.1, 'longitude' => -68.9166667), + 'Windhoek' => array('latitude' => -22.57, 'longitude' => 17.0836111), + 'Yamoussoukro' => array('latitude' => 6.8166667, 'longitude' => -5.2833333), + 'Yaoundé' => array('latitude' => 3.8666667, 'longitude' => 11.5166667), + 'Yerevan' => array('latitude' => 40.1811111, 'longitude' => 44.5136111), + 'Zürich' => array('latitude' => 47.3666667, 'longitude' => 8.55), + 'Zagreb' => array('latitude' => 45.8, 'longitude' => 16) + ); + + /** + * Returns the location from the selected city + * + * @param string $city City to get location for + * @param string $horizon Horizon to use : + * default: effective + * others are civil, nautic, astronomic + * @return array + * @throws Zend_Date_Exception When city is unknown + */ + public static function City($city, $horizon = false) + { + foreach (self::$cities as $key => $value) { + if (strtolower($key) === strtolower($city)) { + $return = $value; + $return['horizon'] = $horizon; + return $return; + } + } + throw new Zend_Date_Exception('unknown city'); + } + + /** + * Return a list with all known cities + * + * @return array + */ + public static function getCityList() + { + return array_keys(self::$cities); + } +} diff --git a/library/vendor/Zend/Date/DateObject.php b/library/vendor/Zend/Date/DateObject.php new file mode 100644 index 0000000..5c01d15 --- /dev/null +++ b/library/vendor/Zend/Date/DateObject.php @@ -0,0 +1,1094 @@ + 0, 1960 => -315619200, 1950 => -631152000, + 1940 => -946771200, 1930 => -1262304000, 1920 => -1577923200, + 1910 => -1893456000, 1900 => -2208988800, 1890 => -2524521600, + 1880 => -2840140800, 1870 => -3155673600, 1860 => -3471292800, + 1850 => -3786825600, 1840 => -4102444800, 1830 => -4417977600, + 1820 => -4733596800, 1810 => -5049129600, 1800 => -5364662400, + 1790 => -5680195200, 1780 => -5995814400, 1770 => -6311347200, + 1760 => -6626966400, 1750 => -6942499200, 1740 => -7258118400, + 1730 => -7573651200, 1720 => -7889270400, 1710 => -8204803200, + 1700 => -8520336000, 1690 => -8835868800, 1680 => -9151488000, + 1670 => -9467020800, 1660 => -9782640000, 1650 => -10098172800, + 1640 => -10413792000, 1630 => -10729324800, 1620 => -11044944000, + 1610 => -11360476800, 1600 => -11676096000); + + /** + * Set this object to have a new UNIX timestamp. + * + * @param string|integer $timestamp OPTIONAL timestamp; defaults to local time using time() + * @return string|integer old timestamp + * @throws Zend_Date_Exception + */ + protected function setUnixTimestamp($timestamp = null) + { + $old = $this->_unixTimestamp; + + if (is_numeric($timestamp)) { + $this->_unixTimestamp = $timestamp; + } else if ($timestamp === null) { + $this->_unixTimestamp = time(); + } else { + throw new Zend_Date_Exception('\'' . $timestamp . '\' is not a valid UNIX timestamp', 0, null, $timestamp); + } + + return $old; + } + + /** + * Returns this object's UNIX timestamp + * A timestamp greater then the integer range will be returned as string + * This function does not return the timestamp as object. Use copy() instead. + * + * @return integer|string timestamp + */ + protected function getUnixTimestamp() + { + if ($this->_unixTimestamp === intval($this->_unixTimestamp)) { + return (int) $this->_unixTimestamp; + } else { + return (string) $this->_unixTimestamp; + } + } + + /** + * Internal function. + * Returns time(). This method exists to allow unit tests to work-around methods that might otherwise + * be hard-coded to use time(). For example, this makes it possible to test isYesterday() in Date.php. + * + * @param integer $sync OPTIONAL time syncronisation value + * @return integer timestamp + */ + protected function _getTime($sync = null) + { + if ($sync !== null) { + $this->_syncronised = round($sync); + } + return (time() + $this->_syncronised); + } + + /** + * Internal mktime function used by Zend_Date. + * The timestamp returned by mktime() can exceed the precision of traditional UNIX timestamps, + * by allowing PHP to auto-convert to using a float value. + * + * Returns a timestamp relative to 1970/01/01 00:00:00 GMT/UTC. + * DST (Summer/Winter) is depriciated since php 5.1.0. + * Year has to be 4 digits otherwise it would be recognised as + * year 70 AD instead of 1970 AD as expected !! + * + * @param integer $hour + * @param integer $minute + * @param integer $second + * @param integer $month + * @param integer $day + * @param integer $year + * @param boolean $gmt OPTIONAL true = other arguments are for UTC time, false = arguments are for local time/date + * @return integer|float timestamp (number of seconds elapsed relative to 1970/01/01 00:00:00 GMT/UTC) + */ + protected function mktime($hour, $minute, $second, $month, $day, $year, $gmt = false) + { + // complete date but in 32bit timestamp - use PHP internal + if ((1901 < $year) and ($year < 2038)) { + + $oldzone = @date_default_timezone_get(); + // Timezone also includes DST settings, therefor substracting the GMT offset is not enough + // We have to set the correct timezone to get the right value + if (($this->_timezone != $oldzone) and ($gmt === false)) { + date_default_timezone_set($this->_timezone); + } + $result = ($gmt) ? @gmmktime($hour, $minute, $second, $month, $day, $year) + : @mktime($hour, $minute, $second, $month, $day, $year); + date_default_timezone_set($oldzone); + + return $result; + } + + if ($gmt !== true) { + $second += $this->_offset; + } + + if (isset(self::$_cache)) { + $id = strtr('Zend_DateObject_mkTime_' . $this->_offset . '_' . $year.$month.$day.'_'.$hour.$minute.$second . '_'.(int)$gmt, '-','_'); + if ($result = self::$_cache->load($id)) { + return unserialize($result); + } + } + + // date to integer + $day = intval($day); + $month = intval($month); + $year = intval($year); + + // correct months > 12 and months < 1 + if ($month > 12) { + $overlap = floor($month / 12); + $year += $overlap; + $month -= $overlap * 12; + } else { + $overlap = ceil((1 - $month) / 12); + $year -= $overlap; + $month += $overlap * 12; + } + + $date = 0; + if ($year >= 1970) { + + // Date is after UNIX epoch + // go through leapyears + // add months from latest given year + for ($count = 1970; $count <= $year; $count++) { + + $leapyear = self::isYearLeapYear($count); + if ($count < $year) { + + $date += 365; + if ($leapyear === true) { + $date++; + } + + } else { + + for ($mcount = 0; $mcount < ($month - 1); $mcount++) { + $date += self::$_monthTable[$mcount]; + if (($leapyear === true) and ($mcount == 1)) { + $date++; + } + + } + } + } + + $date += $day - 1; + $date = (($date * 86400) + ($hour * 3600) + ($minute * 60) + $second); + } else { + + // Date is before UNIX epoch + // go through leapyears + // add months from latest given year + for ($count = 1969; $count >= $year; $count--) { + + $leapyear = self::isYearLeapYear($count); + if ($count > $year) + { + $date += 365; + if ($leapyear === true) + $date++; + } else { + + for ($mcount = 11; $mcount > ($month - 1); $mcount--) { + $date += self::$_monthTable[$mcount]; + if (($leapyear === true) and ($mcount == 2)) { + $date++; + } + + } + } + } + + $date += (self::$_monthTable[$month - 1] - $day); + $date = -(($date * 86400) + (86400 - (($hour * 3600) + ($minute * 60) + $second))); + + // gregorian correction for 5.Oct.1582 + if ($date < -12220185600) { + $date += 864000; + } else if ($date < -12219321600) { + $date = -12219321600; + } + } + + if (isset(self::$_cache)) { + if (self::$_cacheTags) { + self::$_cache->save( serialize($date), $id, array('Zend_Date')); + } else { + self::$_cache->save( serialize($date), $id); + } + } + + return $date; + } + + /** + * Returns true, if given $year is a leap year. + * + * @param integer $year + * @return boolean true, if year is leap year + */ + protected static function isYearLeapYear($year) + { + // all leapyears can be divided through 4 + if (($year % 4) != 0) { + return false; + } + + // all leapyears can be divided through 400 + if ($year % 400 == 0) { + return true; + } else if (($year > 1582) and ($year % 100 == 0)) { + return false; + } + + return true; + } + + /** + * Internal mktime function used by Zend_Date for handling 64bit timestamps. + * + * Returns a formatted date for a given timestamp. + * + * @param string $format format for output + * @param mixed $timestamp + * @param boolean $gmt OPTIONAL true = other arguments are for UTC time, false = arguments are for local time/date + * @return string + */ + protected function date($format, $timestamp = null, $gmt = false) + { + $oldzone = @date_default_timezone_get(); + if ($this->_timezone != $oldzone) { + date_default_timezone_set($this->_timezone); + } + + if ($timestamp === null) { + $result = ($gmt) ? @gmdate($format) : @date($format); + date_default_timezone_set($oldzone); + return $result; + } + + if (abs($timestamp) <= 0x7FFFFFFF) { + // See ZF-11992 + // "o" will sometimes resolve to the previous year (see + // http://php.net/date ; it's part of the ISO 8601 + // standard). However, this is not desired, so replacing + // all occurrences of "o" not preceded by a backslash + // with "Y" + $format = preg_replace('/(?_offset . '_'. $timestamp . '_'.(int)$gmt, '-','_'); + if ($result2 = self::$_cache->load($idstamp)) { + $timestamp = unserialize($result2); + $jump = true; + } + } + + // check on false or null alone fails + if (empty($gmt) and empty($jump)) { + $tempstamp = $timestamp; + if ($tempstamp > 0) { + while (abs($tempstamp) > 0x7FFFFFFF) { + $tempstamp -= (86400 * 23376); + } + + $dst = date("I", $tempstamp); + if ($dst === 1) { + $timestamp += 3600; + } + + $temp = date('Z', $tempstamp); + $timestamp += $temp; + } + + if (isset(self::$_cache)) { + if (self::$_cacheTags) { + self::$_cache->save( serialize($timestamp), $idstamp, array('Zend_Date')); + } else { + self::$_cache->save( serialize($timestamp), $idstamp); + } + } + } + + if (($timestamp < 0) and ($gmt !== true)) { + $timestamp -= $this->_offset; + } + + date_default_timezone_set($oldzone); + $date = $this->getDateParts($timestamp, true); + $length = strlen($format); + $output = ''; + + for ($i = 0; $i < $length; $i++) { + switch($format[$i]) { + // day formats + case 'd': // day of month, 2 digits, with leading zero, 01 - 31 + $output .= (($date['mday'] < 10) ? '0' . $date['mday'] : $date['mday']); + break; + + case 'D': // day of week, 3 letters, Mon - Sun + $output .= date('D', 86400 * (3 + self::dayOfWeek($date['year'], $date['mon'], $date['mday']))); + break; + + case 'j': // day of month, without leading zero, 1 - 31 + $output .= $date['mday']; + break; + + case 'l': // day of week, full string name, Sunday - Saturday + $output .= date('l', 86400 * (3 + self::dayOfWeek($date['year'], $date['mon'], $date['mday']))); + break; + + case 'N': // ISO 8601 numeric day of week, 1 - 7 + $day = self::dayOfWeek($date['year'], $date['mon'], $date['mday']); + if ($day == 0) { + $day = 7; + } + $output .= $day; + break; + + case 'S': // english suffix for day of month, st nd rd th + if (($date['mday'] % 10) == 1) { + $output .= 'st'; + } else if ((($date['mday'] % 10) == 2) and ($date['mday'] != 12)) { + $output .= 'nd'; + } else if (($date['mday'] % 10) == 3) { + $output .= 'rd'; + } else { + $output .= 'th'; + } + break; + + case 'w': // numeric day of week, 0 - 6 + $output .= self::dayOfWeek($date['year'], $date['mon'], $date['mday']); + break; + + case 'z': // day of year, 0 - 365 + $output .= $date['yday']; + break; + + + // week formats + case 'W': // ISO 8601, week number of year + $output .= $this->weekNumber($date['year'], $date['mon'], $date['mday']); + break; + + + // month formats + case 'F': // string month name, january - december + $output .= date('F', mktime(0, 0, 0, $date['mon'], 2, 1971)); + break; + + case 'm': // number of month, with leading zeros, 01 - 12 + $output .= (($date['mon'] < 10) ? '0' . $date['mon'] : $date['mon']); + break; + + case 'M': // 3 letter month name, Jan - Dec + $output .= date('M',mktime(0, 0, 0, $date['mon'], 2, 1971)); + break; + + case 'n': // number of month, without leading zeros, 1 - 12 + $output .= $date['mon']; + break; + + case 't': // number of day in month + $output .= self::$_monthTable[$date['mon'] - 1]; + break; + + + // year formats + case 'L': // is leap year ? + $output .= (self::isYearLeapYear($date['year'])) ? '1' : '0'; + break; + + case 'o': // ISO 8601 year number + $week = $this->weekNumber($date['year'], $date['mon'], $date['mday']); + if (($week > 50) and ($date['mon'] == 1)) { + $output .= ($date['year'] - 1); + } else { + $output .= $date['year']; + } + break; + + case 'Y': // year number, 4 digits + $output .= $date['year']; + break; + + case 'y': // year number, 2 digits + $output .= substr($date['year'], strlen($date['year']) - 2, 2); + break; + + + // time formats + case 'a': // lower case am/pm + $output .= (($date['hours'] >= 12) ? 'pm' : 'am'); + break; + + case 'A': // upper case am/pm + $output .= (($date['hours'] >= 12) ? 'PM' : 'AM'); + break; + + case 'B': // swatch internet time + $dayseconds = ($date['hours'] * 3600) + ($date['minutes'] * 60) + $date['seconds']; + if ($gmt === true) { + $dayseconds += 3600; + } + $output .= (int) (($dayseconds % 86400) / 86.4); + break; + + case 'g': // hours without leading zeros, 12h format + if ($date['hours'] > 12) { + $hour = $date['hours'] - 12; + } else { + if ($date['hours'] == 0) { + $hour = '12'; + } else { + $hour = $date['hours']; + } + } + $output .= $hour; + break; + + case 'G': // hours without leading zeros, 24h format + $output .= $date['hours']; + break; + + case 'h': // hours with leading zeros, 12h format + if ($date['hours'] > 12) { + $hour = $date['hours'] - 12; + } else { + if ($date['hours'] == 0) { + $hour = '12'; + } else { + $hour = $date['hours']; + } + } + $output .= (($hour < 10) ? '0'.$hour : $hour); + break; + + case 'H': // hours with leading zeros, 24h format + $output .= (($date['hours'] < 10) ? '0' . $date['hours'] : $date['hours']); + break; + + case 'i': // minutes with leading zeros + $output .= (($date['minutes'] < 10) ? '0' . $date['minutes'] : $date['minutes']); + break; + + case 's': // seconds with leading zeros + $output .= (($date['seconds'] < 10) ? '0' . $date['seconds'] : $date['seconds']); + break; + + + // timezone formats + case 'e': // timezone identifier + if ($gmt === true) { + $output .= gmdate('e', mktime($date['hours'], $date['minutes'], $date['seconds'], + $date['mon'], $date['mday'], 2000)); + } else { + $output .= date('e', mktime($date['hours'], $date['minutes'], $date['seconds'], + $date['mon'], $date['mday'], 2000)); + } + break; + + case 'I': // daylight saving time or not + if ($gmt === true) { + $output .= gmdate('I', mktime($date['hours'], $date['minutes'], $date['seconds'], + $date['mon'], $date['mday'], 2000)); + } else { + $output .= date('I', mktime($date['hours'], $date['minutes'], $date['seconds'], + $date['mon'], $date['mday'], 2000)); + } + break; + + case 'O': // difference to GMT in hours + $gmtstr = ($gmt === true) ? 0 : $this->getGmtOffset(); + $output .= sprintf('%s%04d', ($gmtstr <= 0) ? '+' : '-', abs($gmtstr) / 36); + break; + + case 'P': // difference to GMT with colon + $gmtstr = ($gmt === true) ? 0 : $this->getGmtOffset(); + $gmtstr = sprintf('%s%04d', ($gmtstr <= 0) ? '+' : '-', abs($gmtstr) / 36); + $output = $output . substr($gmtstr, 0, 3) . ':' . substr($gmtstr, 3); + break; + + case 'T': // timezone settings + if ($gmt === true) { + $output .= gmdate('T', mktime($date['hours'], $date['minutes'], $date['seconds'], + $date['mon'], $date['mday'], 2000)); + } else { + $output .= date('T', mktime($date['hours'], $date['minutes'], $date['seconds'], + $date['mon'], $date['mday'], 2000)); + } + break; + + case 'Z': // timezone offset in seconds + $output .= ($gmt === true) ? 0 : -$this->getGmtOffset(); + break; + + + // complete time formats + case 'c': // ISO 8601 date format + $difference = $this->getGmtOffset(); + $difference = sprintf('%s%04d', ($difference <= 0) ? '+' : '-', abs($difference) / 36); + $difference = substr($difference, 0, 3) . ':' . substr($difference, 3); + $output .= $date['year'] . '-' + . (($date['mon'] < 10) ? '0' . $date['mon'] : $date['mon']) . '-' + . (($date['mday'] < 10) ? '0' . $date['mday'] : $date['mday']) . 'T' + . (($date['hours'] < 10) ? '0' . $date['hours'] : $date['hours']) . ':' + . (($date['minutes'] < 10) ? '0' . $date['minutes'] : $date['minutes']) . ':' + . (($date['seconds'] < 10) ? '0' . $date['seconds'] : $date['seconds']) + . $difference; + break; + + case 'r': // RFC 2822 date format + $difference = $this->getGmtOffset(); + $difference = sprintf('%s%04d', ($difference <= 0) ? '+' : '-', abs($difference) / 36); + $output .= gmdate('D', 86400 * (3 + self::dayOfWeek($date['year'], $date['mon'], $date['mday']))) . ', ' + . (($date['mday'] < 10) ? '0' . $date['mday'] : $date['mday']) . ' ' + . date('M', mktime(0, 0, 0, $date['mon'], 2, 1971)) . ' ' + . $date['year'] . ' ' + . (($date['hours'] < 10) ? '0' . $date['hours'] : $date['hours']) . ':' + . (($date['minutes'] < 10) ? '0' . $date['minutes'] : $date['minutes']) . ':' + . (($date['seconds'] < 10) ? '0' . $date['seconds'] : $date['seconds']) . ' ' + . $difference; + break; + + case 'U': // Unix timestamp + $output .= $origstamp; + break; + + + // special formats + case "\\": // next letter to print with no format + $i++; + if ($i < $length) { + $output .= $format[$i]; + } + break; + + default: // letter is no format so add it direct + $output .= $format[$i]; + break; + } + } + + return (string) $output; + } + + /** + * Returns the day of week for a Gregorian calendar date. + * 0 = sunday, 6 = saturday + * + * @param integer $year + * @param integer $month + * @param integer $day + * @return integer dayOfWeek + */ + protected static function dayOfWeek($year, $month, $day) + { + if ((1901 < $year) and ($year < 2038)) { + return (int) date('w', mktime(0, 0, 0, $month, $day, $year)); + } + + // gregorian correction + $correction = 0; + if (($year < 1582) or (($year == 1582) and (($month < 10) or (($month == 10) && ($day < 15))))) { + $correction = 3; + } + + if ($month > 2) { + $month -= 2; + } else { + $month += 10; + $year--; + } + + $day = floor((13 * $month - 1) / 5) + $day + ($year % 100) + floor(($year % 100) / 4); + $day += floor(($year / 100) / 4) - 2 * floor($year / 100) + 77 + $correction; + + return (int) ($day - 7 * floor($day / 7)); + } + + /** + * Internal getDateParts function for handling 64bit timestamps, similar to: + * http://www.php.net/getdate + * + * Returns an array of date parts for $timestamp, relative to 1970/01/01 00:00:00 GMT/UTC. + * + * $fast specifies ALL date parts should be returned (slower) + * Default is false, and excludes $dayofweek, weekday, month and timestamp from parts returned. + * + * @param mixed $timestamp + * @param boolean $fast OPTIONAL defaults to fast (false), resulting in fewer date parts + * @return array + */ + protected function getDateParts($timestamp = null, $fast = null) + { + + // actual timestamp + if (!is_numeric($timestamp)) { + return getdate(); + } + + // 32bit timestamp + if (abs($timestamp) <= 0x7FFFFFFF) { + return @getdate((int) $timestamp); + } + + if (isset(self::$_cache)) { + $id = strtr('Zend_DateObject_getDateParts_' . $timestamp.'_'.(int)$fast, '-','_'); + if ($result = self::$_cache->load($id)) { + return unserialize($result); + } + } + + $otimestamp = $timestamp; + $numday = 0; + $month = 0; + // gregorian correction + if ($timestamp < -12219321600) { + $timestamp -= 864000; + } + + // timestamp lower 0 + if ($timestamp < 0) { + $sec = 0; + $act = 1970; + + // iterate through 10 years table, increasing speed + foreach(self::$_yearTable as $year => $seconds) { + if ($timestamp >= $seconds) { + $i = $act; + break; + } + $sec = $seconds; + $act = $year; + } + + $timestamp -= $sec; + if (!isset($i)) { + $i = $act; + } + + // iterate the max last 10 years + do { + --$i; + $day = $timestamp; + + $timestamp += 31536000; + $leapyear = self::isYearLeapYear($i); + if ($leapyear === true) { + $timestamp += 86400; + } + + if ($timestamp >= 0) { + $year = $i; + break; + } + } while ($timestamp < 0); + + $secondsPerYear = 86400 * ($leapyear ? 366 : 365) + $day; + + $timestamp = $day; + // iterate through months + for ($i = 12; --$i >= 0;) { + $day = $timestamp; + + $timestamp += self::$_monthTable[$i] * 86400; + if (($leapyear === true) and ($i == 1)) { + $timestamp += 86400; + } + + if ($timestamp >= 0) { + $month = $i; + $numday = self::$_monthTable[$i]; + if (($leapyear === true) and ($i == 1)) { + ++$numday; + } + break; + } + } + + $timestamp = $day; + $numberdays = $numday + ceil(($timestamp + 1) / 86400); + + $timestamp += ($numday - $numberdays + 1) * 86400; + $hours = floor($timestamp / 3600); + } else { + + // iterate through years + for ($i = 1970;;$i++) { + $day = $timestamp; + + $timestamp -= 31536000; + $leapyear = self::isYearLeapYear($i); + if ($leapyear === true) { + $timestamp -= 86400; + } + + if ($timestamp < 0) { + $year = $i; + break; + } + } + + $secondsPerYear = $day; + + $timestamp = $day; + // iterate through months + for ($i = 0; $i <= 11; $i++) { + $day = $timestamp; + $timestamp -= self::$_monthTable[$i] * 86400; + + if (($leapyear === true) and ($i == 1)) { + $timestamp -= 86400; + } + + if ($timestamp < 0) { + $month = $i; + $numday = self::$_monthTable[$i]; + if (($leapyear === true) and ($i == 1)) { + ++$numday; + } + break; + } + } + + $timestamp = $day; + $numberdays = ceil(($timestamp + 1) / 86400); + $timestamp = $timestamp - ($numberdays - 1) * 86400; + $hours = floor($timestamp / 3600); + } + + $timestamp -= $hours * 3600; + + $month += 1; + $minutes = floor($timestamp / 60); + $seconds = $timestamp - $minutes * 60; + + if ($fast === true) { + $array = array( + 'seconds' => $seconds, + 'minutes' => $minutes, + 'hours' => $hours, + 'mday' => $numberdays, + 'mon' => $month, + 'year' => $year, + 'yday' => floor($secondsPerYear / 86400), + ); + } else { + + $dayofweek = self::dayOfWeek($year, $month, $numberdays); + $array = array( + 'seconds' => $seconds, + 'minutes' => $minutes, + 'hours' => $hours, + 'mday' => $numberdays, + 'wday' => $dayofweek, + 'mon' => $month, + 'year' => $year, + 'yday' => floor($secondsPerYear / 86400), + 'weekday' => gmdate('l', 86400 * (3 + $dayofweek)), + 'month' => gmdate('F', mktime(0, 0, 0, $month, 1, 1971)), + 0 => $otimestamp + ); + } + + if (isset(self::$_cache)) { + if (self::$_cacheTags) { + self::$_cache->save( serialize($array), $id, array('Zend_Date')); + } else { + self::$_cache->save( serialize($array), $id); + } + } + + return $array; + } + + /** + * Internal getWeekNumber function for handling 64bit timestamps + * + * Returns the ISO 8601 week number of a given date + * + * @param integer $year + * @param integer $month + * @param integer $day + * @return integer + */ + protected function weekNumber($year, $month, $day) + { + if ((1901 < $year) and ($year < 2038)) { + return (int) date('W', mktime(0, 0, 0, $month, $day, $year)); + } + + $dayofweek = self::dayOfWeek($year, $month, $day); + $firstday = self::dayOfWeek($year, 1, 1); + if (($month == 1) and (($firstday < 1) or ($firstday > 4)) and ($day < 4)) { + $firstday = self::dayOfWeek($year - 1, 1, 1); + $month = 12; + $day = 31; + + } else if (($month == 12) and ((self::dayOfWeek($year + 1, 1, 1) < 5) and + (self::dayOfWeek($year + 1, 1, 1) > 0))) { + return 1; + } + + return intval (((self::dayOfWeek($year, 1, 1) < 5) and (self::dayOfWeek($year, 1, 1) > 0)) + + 4 * ($month - 1) + (2 * ($month - 1) + ($day - 1) + $firstday - $dayofweek + 6) * 36 / 256); + } + + /** + * Internal _range function + * Sets the value $a to be in the range of [0, $b] + * + * @param float $a - value to correct + * @param float $b - maximum range to set + */ + private function _range($a, $b) { + while ($a < 0) { + $a += $b; + } + while ($a >= $b) { + $a -= $b; + } + return $a; + } + + /** + * Calculates the sunrise or sunset based on a location + * + * @param array $location Location for calculation MUST include 'latitude', 'longitude', 'horizon' + * @param bool $horizon true: sunrise; false: sunset + * @return mixed - false: midnight sun, integer: + */ + protected function calcSun($location, $horizon, $rise = false) + { + // timestamp within 32bit + if (abs($this->_unixTimestamp) <= 0x7FFFFFFF) { + if ($rise === false) { + return date_sunset($this->_unixTimestamp, SUNFUNCS_RET_TIMESTAMP, $location['latitude'], + $location['longitude'], 90 + $horizon, $this->getGmtOffset() / 3600); + } + return date_sunrise($this->_unixTimestamp, SUNFUNCS_RET_TIMESTAMP, $location['latitude'], + $location['longitude'], 90 + $horizon, $this->getGmtOffset() / 3600); + } + + // self calculation - timestamp bigger than 32bit + // fix circle values + $quarterCircle = 0.5 * M_PI; + $halfCircle = M_PI; + $threeQuarterCircle = 1.5 * M_PI; + $fullCircle = 2 * M_PI; + + // radiant conversion for coordinates + $radLatitude = $location['latitude'] * $halfCircle / 180; + $radLongitude = $location['longitude'] * $halfCircle / 180; + + // get solar coordinates + $tmpRise = $rise ? $quarterCircle : $threeQuarterCircle; + $radDay = $this->date('z',$this->_unixTimestamp) + ($tmpRise - $radLongitude) / $fullCircle; + + // solar anomoly and longitude + $solAnomoly = $radDay * 0.017202 - 0.0574039; + $solLongitude = $solAnomoly + 0.0334405 * sin($solAnomoly); + $solLongitude += 4.93289 + 3.49066E-4 * sin(2 * $solAnomoly); + + // get quadrant + $solLongitude = $this->_range($solLongitude, $fullCircle); + + if (($solLongitude / $quarterCircle) - intval($solLongitude / $quarterCircle) == 0) { + $solLongitude += 4.84814E-6; + } + + // solar ascension + $solAscension = sin($solLongitude) / cos($solLongitude); + $solAscension = atan2(0.91746 * $solAscension, 1); + + // adjust quadrant + if ($solLongitude > $threeQuarterCircle) { + $solAscension += $fullCircle; + } else if ($solLongitude > $quarterCircle) { + $solAscension += $halfCircle; + } + + // solar declination + $solDeclination = 0.39782 * sin($solLongitude); + $solDeclination /= sqrt(-$solDeclination * $solDeclination + 1); + $solDeclination = atan2($solDeclination, 1); + + $solHorizon = $horizon - sin($solDeclination) * sin($radLatitude); + $solHorizon /= cos($solDeclination) * cos($radLatitude); + + // midnight sun, always night + if (abs($solHorizon) > 1) { + return false; + } + + $solHorizon /= sqrt(-$solHorizon * $solHorizon + 1); + $solHorizon = $quarterCircle - atan2($solHorizon, 1); + + if ($rise) { + $solHorizon = $fullCircle - $solHorizon; + } + + // time calculation + $localTime = $solHorizon + $solAscension - 0.0172028 * $radDay - 1.73364; + $universalTime = $localTime - $radLongitude; + + // determinate quadrant + $universalTime = $this->_range($universalTime, $fullCircle); + + // radiant to hours + $universalTime *= 24 / $fullCircle; + + // convert to time + $hour = intval($universalTime); + $universalTime = ($universalTime - $hour) * 60; + $min = intval($universalTime); + $universalTime = ($universalTime - $min) * 60; + $sec = intval($universalTime); + + return $this->mktime($hour, $min, $sec, $this->date('m', $this->_unixTimestamp), + $this->date('j', $this->_unixTimestamp), $this->date('Y', $this->_unixTimestamp), + -1, true); + } + + /** + * Sets a new timezone for calculation of $this object's gmt offset. + * For a list of supported timezones look here: http://php.net/timezones + * If no timezone can be detected or the given timezone is wrong UTC will be set. + * + * @param string $zone OPTIONAL timezone for date calculation; defaults to date_default_timezone_get() + * @return Zend_Date_DateObject Provides fluent interface + * @throws Zend_Date_Exception + */ + public function setTimezone($zone = null) + { + $oldzone = @date_default_timezone_get(); + if ($zone === null) { + $zone = $oldzone; + } + + // throw an error on false input, but only if the new date extension is available + if (function_exists('timezone_open')) { + if (!@timezone_open($zone)) { + throw new Zend_Date_Exception("timezone ($zone) is not a known timezone", 0, null, $zone); + } + } + // this can generate an error if the date extension is not available and a false timezone is given + $result = @date_default_timezone_set($zone); + if ($result === true) { + $this->_offset = mktime(0, 0, 0, 1, 2, 1970) - gmmktime(0, 0, 0, 1, 2, 1970); + $this->_timezone = $zone; + } + date_default_timezone_set($oldzone); + + if (($zone == 'UTC') or ($zone == 'GMT')) { + $this->_dst = false; + } else { + $this->_dst = true; + } + + return $this; + } + + /** + * Return the timezone of $this object. + * The timezone is initially set when the object is instantiated. + * + * @return string actual set timezone string + */ + public function getTimezone() + { + return $this->_timezone; + } + + /** + * Return the offset to GMT of $this object's timezone. + * The offset to GMT is initially set when the object is instantiated using the currently, + * in effect, default timezone for PHP functions. + * + * @return integer seconds difference between GMT timezone and timezone when object was instantiated + */ + public function getGmtOffset() + { + $date = $this->getDateParts($this->getUnixTimestamp(), true); + $zone = @date_default_timezone_get(); + $result = @date_default_timezone_set($this->_timezone); + if ($result === true) { + $offset = $this->mktime($date['hours'], $date['minutes'], $date['seconds'], + $date['mon'], $date['mday'], $date['year'], false) + - $this->mktime($date['hours'], $date['minutes'], $date['seconds'], + $date['mon'], $date['mday'], $date['year'], true); + } + date_default_timezone_set($zone); + + return $offset; + } + + /** + * Internal method to check if the given cache supports tags + * + * @param Zend_Cache $cache + */ + protected static function _getTagSupportForCache() + { + $backend = self::$_cache->getBackend(); + if ($backend instanceof Zend_Cache_Backend_ExtendedInterface) { + $cacheOptions = $backend->getCapabilities(); + self::$_cacheTags = $cacheOptions['tags']; + } else { + self::$_cacheTags = false; + } + + return self::$_cacheTags; + } +} diff --git a/library/vendor/Zend/Date/Exception.php b/library/vendor/Zend/Date/Exception.php new file mode 100644 index 0000000..2585d0b --- /dev/null +++ b/library/vendor/Zend/Date/Exception.php @@ -0,0 +1,48 @@ +operand = $op; + parent::__construct($message, $code, $e); + } + + public function getOperand() + { + return $this->operand; + } +} diff --git a/library/vendor/Zend/Db.php b/library/vendor/Zend/Db.php new file mode 100644 index 0000000..1712929 --- /dev/null +++ b/library/vendor/Zend/Db.php @@ -0,0 +1,282 @@ +toArray(); + } + + /* + * Convert Zend_Config argument to plain string + * adapter name and separate config object. + */ + if ($adapter instanceof Zend_Config) { + if (isset($adapter->params)) { + $config = $adapter->params->toArray(); + } + if (isset($adapter->adapter)) { + $adapter = (string) $adapter->adapter; + } else { + $adapter = null; + } + } + + /* + * Verify that adapter parameters are in an array. + */ + if (!is_array($config)) { + /** + * @see Zend_Db_Exception + */ + throw new Zend_Db_Exception('Adapter parameters must be in an array or a Zend_Config object'); + } + + /* + * Verify that an adapter name has been specified. + */ + if (!is_string($adapter) || empty($adapter)) { + /** + * @see Zend_Db_Exception + */ + throw new Zend_Db_Exception('Adapter name must be specified in a string'); + } + + /* + * Form full adapter class name + */ + $adapterNamespace = 'Zend_Db_Adapter'; + if (isset($config['adapterNamespace'])) { + if ($config['adapterNamespace'] != '') { + $adapterNamespace = $config['adapterNamespace']; + } + unset($config['adapterNamespace']); + } + + // Adapter no longer normalized- see http://framework.zend.com/issues/browse/ZF-5606 + $adapterName = $adapterNamespace . '_'; + $adapterName .= str_replace(' ', '_', ucwords(str_replace('_', ' ', strtolower($adapter)))); + + /* + * Load the adapter class. This throws an exception + * if the specified class cannot be loaded. + */ + if (!class_exists($adapterName)) { + Zend_Loader::loadClass($adapterName); + } + + /* + * Create an instance of the adapter class. + * Pass the config to the adapter class constructor. + */ + $dbAdapter = new $adapterName($config); + + /* + * Verify that the object created is a descendent of the abstract adapter type. + */ + if (! $dbAdapter instanceof Zend_Db_Adapter_Abstract) { + /** + * @see Zend_Db_Exception + */ + throw new Zend_Db_Exception("Adapter class '$adapterName' does not extend Zend_Db_Adapter_Abstract"); + } + + return $dbAdapter; + } + +} diff --git a/library/vendor/Zend/Db/Adapter/Abstract.php b/library/vendor/Zend/Db/Adapter/Abstract.php new file mode 100644 index 0000000..cc00ea1 --- /dev/null +++ b/library/vendor/Zend/Db/Adapter/Abstract.php @@ -0,0 +1,1267 @@ + Zend_Db::INT_TYPE, + Zend_Db::BIGINT_TYPE => Zend_Db::BIGINT_TYPE, + Zend_Db::FLOAT_TYPE => Zend_Db::FLOAT_TYPE + ); + + /** Weither or not that object can get serialized + * + * @var bool + */ + protected $_allowSerialization = true; + + /** + * Weither or not the database should be reconnected + * to that adapter when waking up + * + * @var bool + */ + protected $_autoReconnectOnUnserialize = false; + + /** + * Constructor. + * + * $config is an array of key/value pairs or an instance of Zend_Config + * containing configuration options. These options are common to most adapters: + * + * dbname => (string) The name of the database to user + * username => (string) Connect to the database as this username. + * password => (string) Password associated with the username. + * host => (string) What host to connect to, defaults to localhost + * + * Some options are used on a case-by-case basis by adapters: + * + * port => (string) The port of the database + * persistent => (boolean) Whether to use a persistent connection or not, defaults to false + * protocol => (string) The network protocol, defaults to TCPIP + * caseFolding => (int) style of case-alteration used for identifiers + * socket => (string) The socket or named pipe that should be used + * + * @param array|Zend_Config $config An array or instance of Zend_Config having configuration data + * @throws Zend_Db_Adapter_Exception + */ + public function __construct($config) + { + /* + * Verify that adapter parameters are in an array. + */ + if (!is_array($config)) { + /* + * Convert Zend_Config argument to a plain array. + */ + if ($config instanceof Zend_Config) { + $config = $config->toArray(); + } else { + /** + * @see Zend_Db_Adapter_Exception + */ + throw new Zend_Db_Adapter_Exception('Adapter parameters must be in an array or a Zend_Config object'); + } + } + + $this->_checkRequiredOptions($config); + + $options = array( + Zend_Db::CASE_FOLDING => $this->_caseFolding, + Zend_Db::AUTO_QUOTE_IDENTIFIERS => $this->_autoQuoteIdentifiers, + Zend_Db::FETCH_MODE => $this->_fetchMode, + ); + $driverOptions = array(); + + /* + * normalize the config and merge it with the defaults + */ + if (array_key_exists('options', $config)) { + // can't use array_merge() because keys might be integers + foreach ((array) $config['options'] as $key => $value) { + $options[$key] = $value; + } + } + if (array_key_exists('driver_options', $config)) { + if (!empty($config['driver_options'])) { + // can't use array_merge() because keys might be integers + foreach ((array) $config['driver_options'] as $key => $value) { + $driverOptions[$key] = $value; + } + } + } + + if (!isset($config['charset'])) { + $config['charset'] = null; + } + + if (!isset($config['persistent'])) { + $config['persistent'] = false; + } + + $this->_config = array_merge($this->_config, $config); + $this->_config['options'] = $options; + $this->_config['driver_options'] = $driverOptions; + + + // obtain the case setting, if there is one + if (array_key_exists(Zend_Db::CASE_FOLDING, $options)) { + $case = (int) $options[Zend_Db::CASE_FOLDING]; + switch ($case) { + case Zend_Db::CASE_LOWER: + case Zend_Db::CASE_UPPER: + case Zend_Db::CASE_NATURAL: + $this->_caseFolding = $case; + break; + default: + /** @see Zend_Db_Adapter_Exception */ + throw new Zend_Db_Adapter_Exception('Case must be one of the following constants: ' + . 'Zend_Db::CASE_NATURAL, Zend_Db::CASE_LOWER, Zend_Db::CASE_UPPER'); + } + } + + if (array_key_exists(Zend_Db::FETCH_MODE, $options)) { + if (is_string($options[Zend_Db::FETCH_MODE])) { + $constant = 'Zend_Db::FETCH_' . strtoupper($options[Zend_Db::FETCH_MODE]); + if(defined($constant)) { + $options[Zend_Db::FETCH_MODE] = constant($constant); + } + } + $this->setFetchMode((int) $options[Zend_Db::FETCH_MODE]); + } + + // obtain quoting property if there is one + if (array_key_exists(Zend_Db::AUTO_QUOTE_IDENTIFIERS, $options)) { + $this->_autoQuoteIdentifiers = (bool) $options[Zend_Db::AUTO_QUOTE_IDENTIFIERS]; + } + + // obtain allow serialization property if there is one + if (array_key_exists(Zend_Db::ALLOW_SERIALIZATION, $options)) { + $this->_allowSerialization = (bool) $options[Zend_Db::ALLOW_SERIALIZATION]; + } + + // obtain auto reconnect on unserialize property if there is one + if (array_key_exists(Zend_Db::AUTO_RECONNECT_ON_UNSERIALIZE, $options)) { + $this->_autoReconnectOnUnserialize = (bool) $options[Zend_Db::AUTO_RECONNECT_ON_UNSERIALIZE]; + } + + // create a profiler object + $profiler = false; + if (array_key_exists(Zend_Db::PROFILER, $this->_config)) { + $profiler = $this->_config[Zend_Db::PROFILER]; + unset($this->_config[Zend_Db::PROFILER]); + } + $this->setProfiler($profiler); + } + + /** + * Check for config options that are mandatory. + * Throw exceptions if any are missing. + * + * @param array $config + * @throws Zend_Db_Adapter_Exception + */ + protected function _checkRequiredOptions(array $config) + { + // we need at least a dbname + if (! array_key_exists('dbname', $config)) { + /** @see Zend_Db_Adapter_Exception */ + throw new Zend_Db_Adapter_Exception("Configuration array must have a key for 'dbname' that names the database instance"); + } + + if (! array_key_exists('password', $config)) { + /** + * @see Zend_Db_Adapter_Exception + */ + throw new Zend_Db_Adapter_Exception("Configuration array must have a key for 'password' for login credentials"); + } + + if (! array_key_exists('username', $config)) { + /** + * @see Zend_Db_Adapter_Exception + */ + throw new Zend_Db_Adapter_Exception("Configuration array must have a key for 'username' for login credentials"); + } + } + + /** + * Returns the underlying database connection object or resource. + * If not presently connected, this initiates the connection. + * + * @return object|resource|null + */ + public function getConnection() + { + $this->_connect(); + return $this->_connection; + } + + /** + * Returns the configuration variables in this adapter. + * + * @return array + */ + public function getConfig() + { + return $this->_config; + } + + /** + * Set the adapter's profiler object. + * + * The argument may be a boolean, an associative array, an instance of + * Zend_Db_Profiler, or an instance of Zend_Config. + * + * A boolean argument sets the profiler to enabled if true, or disabled if + * false. The profiler class is the adapter's default profiler class, + * Zend_Db_Profiler. + * + * An instance of Zend_Db_Profiler sets the adapter's instance to that + * object. The profiler is enabled and disabled separately. + * + * An associative array argument may contain any of the keys 'enabled', + * 'class', and 'instance'. The 'enabled' and 'instance' keys correspond to the + * boolean and object types documented above. The 'class' key is used to name a + * class to use for a custom profiler. The class must be Zend_Db_Profiler or a + * subclass. The class is instantiated with no constructor arguments. The 'class' + * option is ignored when the 'instance' option is supplied. + * + * An object of type Zend_Config may contain the properties 'enabled', 'class', and + * 'instance', just as if an associative array had been passed instead. + * + * @param Zend_Db_Profiler|Zend_Config|array|boolean $profiler + * @return Zend_Db_Adapter_Abstract Provides a fluent interface + * @throws Zend_Db_Profiler_Exception if the object instance or class specified + * is not Zend_Db_Profiler or an extension of that class. + */ + public function setProfiler($profiler) + { + $enabled = null; + $profilerClass = $this->_defaultProfilerClass; + $profilerInstance = null; + + if ($profilerIsObject = is_object($profiler)) { + if ($profiler instanceof Zend_Db_Profiler) { + $profilerInstance = $profiler; + } else if ($profiler instanceof Zend_Config) { + $profiler = $profiler->toArray(); + } else { + /** + * @see Zend_Db_Profiler_Exception + */ + throw new Zend_Db_Profiler_Exception('Profiler argument must be an instance of either Zend_Db_Profiler' + . ' or Zend_Config when provided as an object'); + } + } + + if (is_array($profiler)) { + if (isset($profiler['enabled'])) { + $enabled = (bool) $profiler['enabled']; + } + if (isset($profiler['class'])) { + $profilerClass = $profiler['class']; + } + if (isset($profiler['instance'])) { + $profilerInstance = $profiler['instance']; + } + } else if (!$profilerIsObject) { + $enabled = (bool) $profiler; + } + + if ($profilerInstance === null) { + if (!class_exists($profilerClass)) { + Zend_Loader::loadClass($profilerClass); + } + $profilerInstance = new $profilerClass(); + } + + if (!$profilerInstance instanceof Zend_Db_Profiler) { + /** @see Zend_Db_Profiler_Exception */ + throw new Zend_Db_Profiler_Exception('Class ' . get_class($profilerInstance) . ' does not extend ' + . 'Zend_Db_Profiler'); + } + + if (null !== $enabled) { + $profilerInstance->setEnabled($enabled); + } + + $this->_profiler = $profilerInstance; + + return $this; + } + + + /** + * Returns the profiler for this adapter. + * + * @return Zend_Db_Profiler + */ + public function getProfiler() + { + return $this->_profiler; + } + + /** + * Get the default statement class. + * + * @return string + */ + public function getStatementClass() + { + return $this->_defaultStmtClass; + } + + /** + * Set the default statement class. + * + * @return Zend_Db_Adapter_Abstract Fluent interface + */ + public function setStatementClass($class) + { + $this->_defaultStmtClass = $class; + return $this; + } + + /** + * Prepares and executes an SQL statement with bound data. + * + * @param mixed $sql The SQL statement with placeholders. + * May be a string or Zend_Db_Select. + * @param mixed $bind An array of data to bind to the placeholders. + * @return Zend_Db_Statement_Interface + */ + public function query($sql, $bind = array()) + { + // connect to the database if needed + $this->_connect(); + + // is the $sql a Zend_Db_Select object? + if ($sql instanceof Zend_Db_Select) { + if (empty($bind)) { + $bind = $sql->getBind(); + } + + $sql = $sql->assemble(); + } + + // make sure $bind to an array; + // don't use (array) typecasting because + // because $bind may be a Zend_Db_Expr object + if (!is_array($bind)) { + $bind = array($bind); + } + + // prepare and execute the statement with profiling + $stmt = $this->prepare($sql); + $stmt->execute($bind); + + // return the results embedded in the prepared statement object + $stmt->setFetchMode($this->_fetchMode); + return $stmt; + } + + /** + * Leave autocommit mode and begin a transaction. + * + * @return Zend_Db_Adapter_Abstract + */ + public function beginTransaction() + { + $this->_connect(); + $q = $this->_profiler->queryStart('begin', Zend_Db_Profiler::TRANSACTION); + $this->_beginTransaction(); + $this->_profiler->queryEnd($q); + return $this; + } + + /** + * Commit a transaction and return to autocommit mode. + * + * @return Zend_Db_Adapter_Abstract + */ + public function commit() + { + $this->_connect(); + $q = $this->_profiler->queryStart('commit', Zend_Db_Profiler::TRANSACTION); + $this->_commit(); + $this->_profiler->queryEnd($q); + return $this; + } + + /** + * Roll back a transaction and return to autocommit mode. + * + * @return Zend_Db_Adapter_Abstract + */ + public function rollBack() + { + $this->_connect(); + $q = $this->_profiler->queryStart('rollback', Zend_Db_Profiler::TRANSACTION); + $this->_rollBack(); + $this->_profiler->queryEnd($q); + return $this; + } + + /** + * Inserts a table row with specified data. + * + * @param mixed $table The table to insert data into. + * @param array $bind Column-value pairs. + * @return int The number of affected rows. + * @throws Zend_Db_Adapter_Exception + */ + public function insert($table, array $bind) + { + // extract and quote col names from the array keys + $cols = array(); + $vals = array(); + $i = 0; + foreach ($bind as $col => $val) { + $cols[] = $this->quoteIdentifier($col, true); + if ($val instanceof Zend_Db_Expr) { + $vals[] = $val->__toString(); + unset($bind[$col]); + } else { + if ($this->supportsParameters('positional')) { + $vals[] = '?'; + } else { + if ($this->supportsParameters('named')) { + unset($bind[$col]); + $bind[':col'.$i] = $val; + $vals[] = ':col'.$i; + $i++; + } else { + /** @see Zend_Db_Adapter_Exception */ + throw new Zend_Db_Adapter_Exception(get_class($this) ." doesn't support positional or named binding"); + } + } + } + } + + // build the statement + $sql = "INSERT INTO " + . $this->quoteIdentifier($table, true) + . ' (' . implode(', ', $cols) . ') ' + . 'VALUES (' . implode(', ', $vals) . ')'; + + // execute the statement and return the number of affected rows + if ($this->supportsParameters('positional')) { + $bind = array_values($bind); + } + $stmt = $this->query($sql, $bind); + $result = $stmt->rowCount(); + return $result; + } + + /** + * Updates table rows with specified data based on a WHERE clause. + * + * @param mixed $table The table to update. + * @param array $bind Column-value pairs. + * @param mixed $where UPDATE WHERE clause(s). + * @return int The number of affected rows. + * @throws Zend_Db_Adapter_Exception + */ + public function update($table, array $bind, $where = '') + { + /** + * Build "col = ?" pairs for the statement, + * except for Zend_Db_Expr which is treated literally. + */ + $set = array(); + $i = 0; + foreach ($bind as $col => $val) { + if ($val instanceof Zend_Db_Expr) { + $val = $val->__toString(); + unset($bind[$col]); + } else { + if ($this->supportsParameters('positional')) { + $val = '?'; + } else { + if ($this->supportsParameters('named')) { + unset($bind[$col]); + $bind[':col'.$i] = $val; + $val = ':col'.$i; + $i++; + } else { + /** @see Zend_Db_Adapter_Exception */ + throw new Zend_Db_Adapter_Exception(get_class($this) ." doesn't support positional or named binding"); + } + } + } + $set[] = $this->quoteIdentifier($col, true) . ' = ' . $val; + } + + $where = $this->_whereExpr($where); + + /** + * Build the UPDATE statement + */ + $sql = "UPDATE " + . $this->quoteIdentifier($table, true) + . ' SET ' . implode(', ', $set) + . (($where) ? " WHERE $where" : ''); + + /** + * Execute the statement and return the number of affected rows + */ + if ($this->supportsParameters('positional')) { + $stmt = $this->query($sql, array_values($bind)); + } else { + $stmt = $this->query($sql, $bind); + } + $result = $stmt->rowCount(); + return $result; + } + + /** + * Deletes table rows based on a WHERE clause. + * + * @param mixed $table The table to update. + * @param mixed $where DELETE WHERE clause(s). + * @return int The number of affected rows. + */ + public function delete($table, $where = '') + { + $where = $this->_whereExpr($where); + + /** + * Build the DELETE statement + */ + $sql = "DELETE FROM " + . $this->quoteIdentifier($table, true) + . (($where) ? " WHERE $where" : ''); + + /** + * Execute the statement and return the number of affected rows + */ + $stmt = $this->query($sql); + $result = $stmt->rowCount(); + return $result; + } + + /** + * Convert an array, string, or Zend_Db_Expr object + * into a string to put in a WHERE clause. + * + * @param mixed $where + * @return string + */ + protected function _whereExpr($where) + { + if (empty($where)) { + return $where; + } + if (!is_array($where)) { + $where = array($where); + } + foreach ($where as $cond => &$term) { + // is $cond an int? (i.e. Not a condition) + if (is_int($cond)) { + // $term is the full condition + if ($term instanceof Zend_Db_Expr) { + $term = $term->__toString(); + } + } else { + // $cond is the condition with placeholder, + // and $term is quoted into the condition + $term = $this->quoteInto($cond, $term); + } + $term = '(' . $term . ')'; + } + + $where = implode(' AND ', $where); + return $where; + } + + /** + * Creates and returns a new Zend_Db_Select object for this adapter. + * + * @return Zend_Db_Select + */ + public function select() + { + return new Zend_Db_Select($this); + } + + /** + * Get the fetch mode. + * + * @return int + */ + public function getFetchMode() + { + return $this->_fetchMode; + } + + /** + * Fetches all SQL result rows as a sequential array. + * Uses the current fetchMode for the adapter. + * + * @param string|Zend_Db_Select $sql An SQL SELECT statement. + * @param mixed $bind Data to bind into SELECT placeholders. + * @param mixed $fetchMode Override current fetch mode. + * @return array + */ + public function fetchAll($sql, $bind = array(), $fetchMode = null) + { + if ($fetchMode === null) { + $fetchMode = $this->_fetchMode; + } + $stmt = $this->query($sql, $bind); + $result = $stmt->fetchAll($fetchMode); + return $result; + } + + /** + * Fetches the first row of the SQL result. + * Uses the current fetchMode for the adapter. + * + * @param string|Zend_Db_Select $sql An SQL SELECT statement. + * @param mixed $bind Data to bind into SELECT placeholders. + * @param mixed $fetchMode Override current fetch mode. + * @return mixed Array, object, or scalar depending on fetch mode. + */ + public function fetchRow($sql, $bind = array(), $fetchMode = null) + { + if ($fetchMode === null) { + $fetchMode = $this->_fetchMode; + } + $stmt = $this->query($sql, $bind); + $result = $stmt->fetch($fetchMode); + return $result; + } + + /** + * Fetches all SQL result rows as an associative array. + * + * The first column is the key, the entire row array is the + * value. You should construct the query to be sure that + * the first column contains unique values, or else + * rows with duplicate values in the first column will + * overwrite previous data. + * + * @param string|Zend_Db_Select $sql An SQL SELECT statement. + * @param mixed $bind Data to bind into SELECT placeholders. + * @return array + */ + public function fetchAssoc($sql, $bind = array()) + { + $stmt = $this->query($sql, $bind); + $data = array(); + while ($row = $stmt->fetch(Zend_Db::FETCH_ASSOC)) { + $tmp = array_values(array_slice($row, 0, 1)); + $data[$tmp[0]] = $row; + } + return $data; + } + + /** + * Fetches the first column of all SQL result rows as an array. + * + * @param string|Zend_Db_Select $sql An SQL SELECT statement. + * @param mixed $bind Data to bind into SELECT placeholders. + * @return array + */ + public function fetchCol($sql, $bind = array()) + { + $stmt = $this->query($sql, $bind); + $result = $stmt->fetchAll(Zend_Db::FETCH_COLUMN, 0); + return $result; + } + + /** + * Fetches all SQL result rows as an array of key-value pairs. + * + * The first column is the key, the second column is the + * value. + * + * @param string|Zend_Db_Select $sql An SQL SELECT statement. + * @param mixed $bind Data to bind into SELECT placeholders. + * @return array + */ + public function fetchPairs($sql, $bind = array()) + { + $stmt = $this->query($sql, $bind); + $data = array(); + while ($row = $stmt->fetch(Zend_Db::FETCH_NUM)) { + $data[$row[0]] = $row[1]; + } + return $data; + } + + /** + * Fetches the first column of the first row of the SQL result. + * + * @param string|Zend_Db_Select $sql An SQL SELECT statement. + * @param mixed $bind Data to bind into SELECT placeholders. + * @return string + */ + public function fetchOne($sql, $bind = array()) + { + $stmt = $this->query($sql, $bind); + $result = $stmt->fetchColumn(0); + return $result; + } + + /** + * Quote a raw string. + * + * @param string $value Raw string + * @return string Quoted string + */ + protected function _quote($value) + { + if (is_int($value)) { + return $value; + } elseif (is_float($value)) { + return sprintf('%F', $value); + } + return "'" . addcslashes($value, "\000\n\r\\'\"\032") . "'"; + } + + /** + * Safely quotes a value for an SQL statement. + * + * If an array is passed as the value, the array values are quoted + * and then returned as a comma-separated string. + * + * @param mixed $value The value to quote. + * @param mixed $type OPTIONAL the SQL datatype name, or constant, or null. + * @return mixed An SQL-safe quoted value (or string of separated values). + */ + public function quote($value, $type = null) + { + $this->_connect(); + + if ($value instanceof Zend_Db_Select) { + return '(' . $value->assemble() . ')'; + } + + if ($value instanceof Zend_Db_Expr) { + return $value->__toString(); + } + + if (is_array($value)) { + foreach ($value as &$val) { + $val = $this->quote($val, $type); + } + return implode(', ', $value); + } + + if ($type !== null && array_key_exists($type = strtoupper($type), $this->_numericDataTypes)) { + $quotedValue = '0'; + switch ($this->_numericDataTypes[$type]) { + case Zend_Db::INT_TYPE: // 32-bit integer + $quotedValue = (string) intval($value); + break; + case Zend_Db::BIGINT_TYPE: // 64-bit integer + // ANSI SQL-style hex literals (e.g. x'[\dA-F]+') + // are not supported here, because these are string + // literals, not numeric literals. + if (preg_match('/^( + [+-]? # optional sign + (?: + 0[Xx][\da-fA-F]+ # ODBC-style hexadecimal + |\d+ # decimal or octal, or MySQL ZEROFILL decimal + (?:[eE][+-]?\d+)? # optional exponent on decimals or octals + ) + )/x', + (string) $value, $matches)) { + $quotedValue = $matches[1]; + } + break; + case Zend_Db::FLOAT_TYPE: // float or decimal + $quotedValue = sprintf('%F', $value); + } + return $quotedValue; + } + + return $this->_quote($value); + } + + /** + * Quotes a value and places into a piece of text at a placeholder. + * + * The placeholder is a question-mark; all placeholders will be replaced + * with the quoted value. For example: + * + * + * $text = "WHERE date < ?"; + * $date = "2005-01-02"; + * $safe = $sql->quoteInto($text, $date); + * // $safe = "WHERE date < '2005-01-02'" + * + * + * @param string $text The text with a placeholder. + * @param mixed $value The value to quote. + * @param string $type OPTIONAL SQL datatype + * @param integer $count OPTIONAL count of placeholders to replace + * @return string An SQL-safe quoted value placed into the original text. + */ + public function quoteInto($text, $value, $type = null, $count = null) + { + if ($count === null) { + return str_replace('?', $this->quote($value, $type), $text); + } else { + return implode($this->quote($value, $type), explode('?', $text, $count + 1)); + } + } + + /** + * Quotes an identifier. + * + * Accepts a string representing a qualified indentifier. For Example: + * + * $adapter->quoteIdentifier('myschema.mytable') + * + * Returns: "myschema"."mytable" + * + * Or, an array of one or more identifiers that may form a qualified identifier: + * + * $adapter->quoteIdentifier(array('myschema','my.table')) + * + * Returns: "myschema"."my.table" + * + * The actual quote character surrounding the identifiers may vary depending on + * the adapter. + * + * @param string|array|Zend_Db_Expr $ident The identifier. + * @param boolean $auto If true, heed the AUTO_QUOTE_IDENTIFIERS config option. + * @return string The quoted identifier. + */ + public function quoteIdentifier($ident, $auto=false) + { + return $this->_quoteIdentifierAs($ident, null, $auto); + } + + /** + * Quote a column identifier and alias. + * + * @param string|array|Zend_Db_Expr $ident The identifier or expression. + * @param string $alias An alias for the column. + * @param boolean $auto If true, heed the AUTO_QUOTE_IDENTIFIERS config option. + * @return string The quoted identifier and alias. + */ + public function quoteColumnAs($ident, $alias, $auto=false) + { + return $this->_quoteIdentifierAs($ident, $alias, $auto); + } + + /** + * Quote a table identifier and alias. + * + * @param string|array|Zend_Db_Expr $ident The identifier or expression. + * @param string $alias An alias for the table. + * @param boolean $auto If true, heed the AUTO_QUOTE_IDENTIFIERS config option. + * @return string The quoted identifier and alias. + */ + public function quoteTableAs($ident, $alias = null, $auto = false) + { + return $this->_quoteIdentifierAs($ident, $alias, $auto); + } + + /** + * Quote an identifier and an optional alias. + * + * @param string|array|Zend_Db_Expr $ident The identifier or expression. + * @param string $alias An optional alias. + * @param boolean $auto If true, heed the AUTO_QUOTE_IDENTIFIERS config option. + * @param string $as The string to add between the identifier/expression and the alias. + * @return string The quoted identifier and alias. + */ + protected function _quoteIdentifierAs($ident, $alias = null, $auto = false, $as = ' AS ') + { + if ($ident instanceof Zend_Db_Expr) { + $quoted = $ident->__toString(); + } elseif ($ident instanceof Zend_Db_Select) { + $quoted = '(' . $ident->assemble() . ')'; + } else { + if (is_string($ident)) { + $ident = explode('.', $ident); + } + if (is_array($ident)) { + $segments = array(); + foreach ($ident as $segment) { + if ($segment instanceof Zend_Db_Expr) { + $segments[] = $segment->__toString(); + } else { + $segments[] = $this->_quoteIdentifier($segment, $auto); + } + } + if ($alias !== null && end($ident) == $alias) { + $alias = null; + } + $quoted = implode('.', $segments); + } else { + $quoted = $this->_quoteIdentifier($ident, $auto); + } + } + if ($alias !== null) { + $quoted .= $as . $this->_quoteIdentifier($alias, $auto); + } + return $quoted; + } + + /** + * Quote an identifier. + * + * @param string $value The identifier or expression. + * @param boolean $auto If true, heed the AUTO_QUOTE_IDENTIFIERS config option. + * @return string The quoted identifier and alias. + */ + protected function _quoteIdentifier($value, $auto=false) + { + if ($auto === false || $this->_autoQuoteIdentifiers === true) { + $q = $this->getQuoteIdentifierSymbol(); + return ($q . str_replace("$q", "$q$q", $value) . $q); + } + return $value; + } + + /** + * Returns the symbol the adapter uses for delimited identifiers. + * + * @return string + */ + public function getQuoteIdentifierSymbol() + { + return '"'; + } + + /** + * Return the most recent value from the specified sequence in the database. + * This is supported only on RDBMS brands that support sequences + * (e.g. Oracle, PostgreSQL, DB2). Other RDBMS brands return null. + * + * @param string $sequenceName + * @return string + */ + public function lastSequenceId($sequenceName) + { + return null; + } + + /** + * Generate a new value from the specified sequence in the database, and return it. + * This is supported only on RDBMS brands that support sequences + * (e.g. Oracle, PostgreSQL, DB2). Other RDBMS brands return null. + * + * @param string $sequenceName + * @return string + */ + public function nextSequenceId($sequenceName) + { + return null; + } + + /** + * Helper method to change the case of the strings used + * when returning result sets in FETCH_ASSOC and FETCH_BOTH + * modes. + * + * This is not intended to be used by application code, + * but the method must be public so the Statement class + * can invoke it. + * + * @param string $key + * @return string + */ + public function foldCase($key) + { + switch ($this->_caseFolding) { + case Zend_Db::CASE_LOWER: + $value = strtolower((string) $key); + break; + case Zend_Db::CASE_UPPER: + $value = strtoupper((string) $key); + break; + case Zend_Db::CASE_NATURAL: + default: + $value = (string) $key; + } + return $value; + } + + /** + * called when object is getting serialized + * This disconnects the DB object that cant be serialized + * + * @throws Zend_Db_Adapter_Exception + * @return array + */ + public function __sleep() + { + if ($this->_allowSerialization == false) { + /** @see Zend_Db_Adapter_Exception */ + throw new Zend_Db_Adapter_Exception( + get_class($this) . ' is not allowed to be serialized' + ); + } + $this->_connection = null; + + return array_keys( + array_diff_key(get_object_vars($this), array('_connection' => null)) + ); + } + + /** + * called when object is getting unserialized + * + * @return void + */ + public function __wakeup() + { + if ($this->_autoReconnectOnUnserialize == true) { + $this->getConnection(); + } + } + + /** + * Abstract Methods + */ + + /** + * Returns a list of the tables in the database. + * + * @return array + */ + abstract public function listTables(); + + /** + * Returns the column descriptions for a table. + * + * The return value is an associative array keyed by the column name, + * as returned by the RDBMS. + * + * The value of each array element is an associative array + * with the following keys: + * + * SCHEMA_NAME => string; name of database or schema + * TABLE_NAME => string; + * COLUMN_NAME => string; column name + * COLUMN_POSITION => number; ordinal position of column in table + * DATA_TYPE => string; SQL datatype name of column + * DEFAULT => string; default expression of column, null if none + * NULLABLE => boolean; true if column can have nulls + * LENGTH => number; length of CHAR/VARCHAR + * SCALE => number; scale of NUMERIC/DECIMAL + * PRECISION => number; precision of NUMERIC/DECIMAL + * UNSIGNED => boolean; unsigned property of an integer type + * PRIMARY => boolean; true if column is part of the primary key + * PRIMARY_POSITION => integer; position of column in primary key + * + * @param string $tableName + * @param string $schemaName OPTIONAL + * @return array + */ + abstract public function describeTable($tableName, $schemaName = null); + + /** + * Creates a connection to the database. + * + * @return void + */ + abstract protected function _connect(); + + /** + * Test if a connection is active + * + * @return boolean + */ + abstract public function isConnected(); + + /** + * Force the connection to close. + * + * @return void + */ + abstract public function closeConnection(); + + /** + * Prepare a statement and return a PDOStatement-like object. + * + * @param string|Zend_Db_Select $sql SQL query + * @return Zend_Db_Statement|PDOStatement + */ + abstract public function prepare($sql); + + /** + * Gets the last ID generated automatically by an IDENTITY/AUTOINCREMENT column. + * + * As a convention, on RDBMS brands that support sequences + * (e.g. Oracle, PostgreSQL, DB2), this method forms the name of a sequence + * from the arguments and returns the last id generated by that sequence. + * On RDBMS brands that support IDENTITY/AUTOINCREMENT columns, this method + * returns the last value generated for such a column, and the table name + * argument is disregarded. + * + * @param string $tableName OPTIONAL Name of table. + * @param string $primaryKey OPTIONAL Name of primary key column. + * @return string + */ + abstract public function lastInsertId($tableName = null, $primaryKey = null); + + /** + * Begin a transaction. + */ + abstract protected function _beginTransaction(); + + /** + * Commit a transaction. + */ + abstract protected function _commit(); + + /** + * Roll-back a transaction. + */ + abstract protected function _rollBack(); + + /** + * Set the fetch mode. + * + * @param integer $mode + * @return void + * @throws Zend_Db_Adapter_Exception + */ + abstract public function setFetchMode($mode); + + /** + * Adds an adapter-specific LIMIT clause to the SELECT statement. + * + * @param mixed $sql + * @param integer $count + * @param integer $offset + * @return string + */ + abstract public function limit($sql, $count, $offset = 0); + + /** + * Check if the adapter supports real SQL parameters. + * + * @param string $type 'positional' or 'named' + * @return bool + */ + abstract public function supportsParameters($type); + + /** + * Retrieve server version in PHP style + * + * @return string + */ + abstract public function getServerVersion(); +} diff --git a/library/vendor/Zend/Db/Adapter/Db2.php b/library/vendor/Zend/Db/Adapter/Db2.php new file mode 100644 index 0000000..28793d1 --- /dev/null +++ b/library/vendor/Zend/Db/Adapter/Db2.php @@ -0,0 +1,827 @@ + (string) Connect to the database as this username. + * password => (string) Password associated with the username. + * host => (string) What host to connect to (default 127.0.0.1) + * dbname => (string) The name of the database to user + * protocol => (string) Protocol to use, defaults to "TCPIP" + * port => (integer) Port number to use for TCP/IP if protocol is "TCPIP" + * persistent => (boolean) Set TRUE to use a persistent connection (db2_pconnect) + * os => (string) This should be set to 'i5' if the db is on an os400/i5 + * schema => (string) The default schema the connection should use + * + * @var array + */ + protected $_config = array( + 'dbname' => null, + 'username' => null, + 'password' => null, + 'host' => 'localhost', + 'port' => '50000', + 'protocol' => 'TCPIP', + 'persistent' => false, + 'os' => null, + 'schema' => null + ); + + /** + * Execution mode + * + * @var int execution flag (DB2_AUTOCOMMIT_ON or DB2_AUTOCOMMIT_OFF) + */ + protected $_execute_mode = DB2_AUTOCOMMIT_ON; + + /** + * Default class name for a DB statement. + * + * @var string + */ + protected $_defaultStmtClass = 'Zend_Db_Statement_Db2'; + protected $_isI5 = false; + + /** + * Keys are UPPERCASE SQL datatypes or the constants + * Zend_Db::INT_TYPE, Zend_Db::BIGINT_TYPE, or Zend_Db::FLOAT_TYPE. + * + * Values are: + * 0 = 32-bit integer + * 1 = 64-bit integer + * 2 = float or decimal + * + * @var array Associative array of datatypes to values 0, 1, or 2. + */ + protected $_numericDataTypes = array( + Zend_Db::INT_TYPE => Zend_Db::INT_TYPE, + Zend_Db::BIGINT_TYPE => Zend_Db::BIGINT_TYPE, + Zend_Db::FLOAT_TYPE => Zend_Db::FLOAT_TYPE, + 'INTEGER' => Zend_Db::INT_TYPE, + 'SMALLINT' => Zend_Db::INT_TYPE, + 'BIGINT' => Zend_Db::BIGINT_TYPE, + 'DECIMAL' => Zend_Db::FLOAT_TYPE, + 'NUMERIC' => Zend_Db::FLOAT_TYPE + ); + + /** + * Creates a connection resource. + * + * @return void + */ + protected function _connect() + { + if (is_resource($this->_connection)) { + // connection already exists + return; + } + + if (!extension_loaded('ibm_db2')) { + /** + * @see Zend_Db_Adapter_Db2_Exception + */ + throw new Zend_Db_Adapter_Db2_Exception('The IBM DB2 extension is required for this adapter but the extension is not loaded'); + } + + $this->_determineI5(); + if ($this->_config['persistent']) { + // use persistent connection + $conn_func_name = 'db2_pconnect'; + } else { + // use "normal" connection + $conn_func_name = 'db2_connect'; + } + + if (!isset($this->_config['driver_options']['autocommit'])) { + // set execution mode + $this->_config['driver_options']['autocommit'] = &$this->_execute_mode; + } + + if (isset($this->_config['options'][Zend_Db::CASE_FOLDING])) { + $caseAttrMap = array( + Zend_Db::CASE_NATURAL => DB2_CASE_NATURAL, + Zend_Db::CASE_UPPER => DB2_CASE_UPPER, + Zend_Db::CASE_LOWER => DB2_CASE_LOWER + ); + $this->_config['driver_options']['DB2_ATTR_CASE'] = $caseAttrMap[$this->_config['options'][Zend_Db::CASE_FOLDING]]; + } + + if ($this->_isI5 && isset($this->_config['driver_options']['i5_naming'])) { + if ($this->_config['driver_options']['i5_naming']) { + $this->_config['driver_options']['i5_naming'] = DB2_I5_NAMING_ON; + } else { + $this->_config['driver_options']['i5_naming'] = DB2_I5_NAMING_OFF; + } + } + + if ($this->_config['host'] !== 'localhost' && !$this->_isI5) { + // if the host isn't localhost, use extended connection params + $dbname = 'DRIVER={IBM DB2 ODBC DRIVER}' . + ';DATABASE=' . $this->_config['dbname'] . + ';HOSTNAME=' . $this->_config['host'] . + ';PORT=' . $this->_config['port'] . + ';PROTOCOL=' . $this->_config['protocol'] . + ';UID=' . $this->_config['username'] . + ';PWD=' . $this->_config['password'] .';'; + $this->_connection = $conn_func_name( + $dbname, + null, + null, + $this->_config['driver_options'] + ); + } else { + // host is localhost, so use standard connection params + $this->_connection = $conn_func_name( + $this->_config['dbname'], + $this->_config['username'], + $this->_config['password'], + $this->_config['driver_options'] + ); + } + + // check the connection + if (!$this->_connection) { + /** + * @see Zend_Db_Adapter_Db2_Exception + */ + throw new Zend_Db_Adapter_Db2_Exception(db2_conn_errormsg(), db2_conn_error()); + } + } + + /** + * Test if a connection is active + * + * @return boolean + */ + public function isConnected() + { + return ((bool) (is_resource($this->_connection) + && get_resource_type($this->_connection) == 'DB2 Connection')); + } + + /** + * Force the connection to close. + * + * @return void + */ + public function closeConnection() + { + if ($this->isConnected()) { + db2_close($this->_connection); + } + $this->_connection = null; + } + + /** + * Returns an SQL statement for preparation. + * + * @param string $sql The SQL statement with placeholders. + * @return Zend_Db_Statement_Db2 + */ + public function prepare($sql) + { + $this->_connect(); + $stmtClass = $this->_defaultStmtClass; + if (!class_exists($stmtClass)) { + Zend_Loader::loadClass($stmtClass); + } + $stmt = new $stmtClass($this, $sql); + $stmt->setFetchMode($this->_fetchMode); + return $stmt; + } + + /** + * Gets the execution mode + * + * @return int the execution mode (DB2_AUTOCOMMIT_ON or DB2_AUTOCOMMIT_OFF) + */ + public function _getExecuteMode() + { + return $this->_execute_mode; + } + + /** + * @param integer $mode + * @return void + */ + public function _setExecuteMode($mode) + { + switch ($mode) { + case DB2_AUTOCOMMIT_OFF: + case DB2_AUTOCOMMIT_ON: + $this->_execute_mode = $mode; + db2_autocommit($this->_connection, $mode); + break; + default: + /** + * @see Zend_Db_Adapter_Db2_Exception + */ + throw new Zend_Db_Adapter_Db2_Exception("execution mode not supported"); + break; + } + } + + /** + * Quote a raw string. + * + * @param string $value Raw string + * @return string Quoted string + */ + protected function _quote($value) + { + if (is_int($value) || is_float($value)) { + return $value; + } + /** + * Use db2_escape_string() if it is present in the IBM DB2 extension. + * But some supported versions of PHP do not include this function, + * so fall back to default quoting in the parent class. + */ + if (function_exists('db2_escape_string')) { + return "'" . db2_escape_string($value) . "'"; + } + return parent::_quote($value); + } + + /** + * @return string + */ + public function getQuoteIdentifierSymbol() + { + $this->_connect(); + $info = db2_server_info($this->_connection); + if ($info) { + $identQuote = $info->IDENTIFIER_QUOTE_CHAR; + } else { + // db2_server_info() does not return result on some i5 OS version + if ($this->_isI5) { + $identQuote ="'"; + } + } + return $identQuote; + } + + /** + * Returns a list of the tables in the database. + * @param string $schema OPTIONAL + * @return array + */ + public function listTables($schema = null) + { + $this->_connect(); + + if ($schema === null && $this->_config['schema'] != null) { + $schema = $this->_config['schema']; + } + + $tables = array(); + + if (!$this->_isI5) { + if ($schema) { + $stmt = db2_tables($this->_connection, null, $schema); + } else { + $stmt = db2_tables($this->_connection); + } + while ($row = db2_fetch_assoc($stmt)) { + $tables[] = $row['TABLE_NAME']; + } + } else { + $tables = $this->_i5listTables($schema); + } + + return $tables; + } + + + /** + * Returns the column descriptions for a table. + * + * The return value is an associative array keyed by the column name, + * as returned by the RDBMS. + * + * The value of each array element is an associative array + * with the following keys: + * + * SCHEMA_NAME => string; name of database or schema + * TABLE_NAME => string; + * COLUMN_NAME => string; column name + * COLUMN_POSITION => number; ordinal position of column in table + * DATA_TYPE => string; SQL datatype name of column + * DEFAULT => string; default expression of column, null if none + * NULLABLE => boolean; true if column can have nulls + * LENGTH => number; length of CHAR/VARCHAR + * SCALE => number; scale of NUMERIC/DECIMAL + * PRECISION => number; precision of NUMERIC/DECIMAL + * UNSIGNED => boolean; unsigned property of an integer type + * DB2 not supports UNSIGNED integer. + * PRIMARY => boolean; true if column is part of the primary key + * PRIMARY_POSITION => integer; position of column in primary key + * IDENTITY => integer; true if column is auto-generated with unique values + * + * @param string $tableName + * @param string $schemaName OPTIONAL + * @return array + */ + public function describeTable($tableName, $schemaName = null) + { + // Ensure the connection is made so that _isI5 is set + $this->_connect(); + + if ($schemaName === null && $this->_config['schema'] != null) { + $schemaName = $this->_config['schema']; + } + + if (!$this->_isI5) { + + $sql = "SELECT DISTINCT c.tabschema, c.tabname, c.colname, c.colno, + c.typename, c.default, c.nulls, c.length, c.scale, + c.identity, tc.type AS tabconsttype, k.colseq + FROM syscat.columns c + LEFT JOIN (syscat.keycoluse k JOIN syscat.tabconst tc + ON (k.tabschema = tc.tabschema + AND k.tabname = tc.tabname + AND tc.type = 'P')) + ON (c.tabschema = k.tabschema + AND c.tabname = k.tabname + AND c.colname = k.colname) + WHERE " + . $this->quoteInto('UPPER(c.tabname) = UPPER(?)', $tableName); + + if ($schemaName) { + $sql .= $this->quoteInto(' AND UPPER(c.tabschema) = UPPER(?)', $schemaName); + } + + $sql .= " ORDER BY c.colno"; + + } else { + + // DB2 On I5 specific query + $sql = "SELECT DISTINCT C.TABLE_SCHEMA, C.TABLE_NAME, C.COLUMN_NAME, C.ORDINAL_POSITION, + C.DATA_TYPE, C.COLUMN_DEFAULT, C.NULLS ,C.LENGTH, C.SCALE, LEFT(C.IDENTITY,1), + LEFT(tc.TYPE, 1) AS tabconsttype, k.COLSEQ + FROM QSYS2.SYSCOLUMNS C + LEFT JOIN (QSYS2.syskeycst k JOIN QSYS2.SYSCST tc + ON (k.TABLE_SCHEMA = tc.TABLE_SCHEMA + AND k.TABLE_NAME = tc.TABLE_NAME + AND LEFT(tc.type,1) = 'P')) + ON (C.TABLE_SCHEMA = k.TABLE_SCHEMA + AND C.TABLE_NAME = k.TABLE_NAME + AND C.COLUMN_NAME = k.COLUMN_NAME) + WHERE " + . $this->quoteInto('UPPER(C.TABLE_NAME) = UPPER(?)', $tableName); + + if ($schemaName) { + $sql .= $this->quoteInto(' AND UPPER(C.TABLE_SCHEMA) = UPPER(?)', $schemaName); + } + + $sql .= " ORDER BY C.ORDINAL_POSITION FOR FETCH ONLY"; + } + + $desc = array(); + $stmt = $this->query($sql); + + /** + * To avoid case issues, fetch using FETCH_NUM + */ + $result = $stmt->fetchAll(Zend_Db::FETCH_NUM); + + /** + * The ordering of columns is defined by the query so we can map + * to variables to improve readability + */ + $tabschema = 0; + $tabname = 1; + $colname = 2; + $colno = 3; + $typename = 4; + $default = 5; + $nulls = 6; + $length = 7; + $scale = 8; + $identityCol = 9; + $tabconstType = 10; + $colseq = 11; + + foreach ($result as $key => $row) { + list ($primary, $primaryPosition, $identity) = array(false, null, false); + if ($row[$tabconstType] == 'P') { + $primary = true; + $primaryPosition = $row[$colseq]; + } + /** + * In IBM DB2, an column can be IDENTITY + * even if it is not part of the PRIMARY KEY. + */ + if ($row[$identityCol] == 'Y') { + $identity = true; + } + + // only colname needs to be case adjusted + $desc[$this->foldCase($row[$colname])] = array( + 'SCHEMA_NAME' => $this->foldCase($row[$tabschema]), + 'TABLE_NAME' => $this->foldCase($row[$tabname]), + 'COLUMN_NAME' => $this->foldCase($row[$colname]), + 'COLUMN_POSITION' => (!$this->_isI5) ? $row[$colno]+1 : $row[$colno], + 'DATA_TYPE' => $row[$typename], + 'DEFAULT' => $row[$default], + 'NULLABLE' => (bool) ($row[$nulls] == 'Y'), + 'LENGTH' => $row[$length], + 'SCALE' => $row[$scale], + 'PRECISION' => ($row[$typename] == 'DECIMAL' ? $row[$length] : 0), + 'UNSIGNED' => false, + 'PRIMARY' => $primary, + 'PRIMARY_POSITION' => $primaryPosition, + 'IDENTITY' => $identity + ); + } + + return $desc; + } + + /** + * Return the most recent value from the specified sequence in the database. + * This is supported only on RDBMS brands that support sequences + * (e.g. Oracle, PostgreSQL, DB2). Other RDBMS brands return null. + * + * @param string $sequenceName + * @return string + */ + public function lastSequenceId($sequenceName) + { + $this->_connect(); + + if (!$this->_isI5) { + $quotedSequenceName = $this->quoteIdentifier($sequenceName, true); + $sql = 'SELECT PREVVAL FOR ' . $quotedSequenceName . ' AS VAL FROM SYSIBM.SYSDUMMY1'; + } else { + $quotedSequenceName = $sequenceName; + $sql = 'SELECT PREVVAL FOR ' . $this->quoteIdentifier($sequenceName, true) . ' AS VAL FROM QSYS2.QSQPTABL'; + } + + $value = $this->fetchOne($sql); + return (string) $value; + } + + /** + * Generate a new value from the specified sequence in the database, and return it. + * This is supported only on RDBMS brands that support sequences + * (e.g. Oracle, PostgreSQL, DB2). Other RDBMS brands return null. + * + * @param string $sequenceName + * @return string + */ + public function nextSequenceId($sequenceName) + { + $this->_connect(); + $sql = 'SELECT NEXTVAL FOR '.$this->quoteIdentifier($sequenceName, true).' AS VAL FROM SYSIBM.SYSDUMMY1'; + $value = $this->fetchOne($sql); + return (string) $value; + } + + /** + * Gets the last ID generated automatically by an IDENTITY/AUTOINCREMENT column. + * + * As a convention, on RDBMS brands that support sequences + * (e.g. Oracle, PostgreSQL, DB2), this method forms the name of a sequence + * from the arguments and returns the last id generated by that sequence. + * On RDBMS brands that support IDENTITY/AUTOINCREMENT columns, this method + * returns the last value generated for such a column, and the table name + * argument is disregarded. + * + * The IDENTITY_VAL_LOCAL() function gives the last generated identity value + * in the current process, even if it was for a GENERATED column. + * + * @param string $tableName OPTIONAL + * @param string $primaryKey OPTIONAL + * @param string $idType OPTIONAL used for i5 platform to define sequence/idenity unique value + * @return string + */ + + public function lastInsertId($tableName = null, $primaryKey = null, $idType = null) + { + $this->_connect(); + + if ($this->_isI5) { + return (string) $this->_i5LastInsertId($tableName, $idType); + } + + if ($tableName !== null) { + $sequenceName = $tableName; + if ($primaryKey) { + $sequenceName .= "_$primaryKey"; + } + $sequenceName .= '_seq'; + return $this->lastSequenceId($sequenceName); + } + + $sql = 'SELECT IDENTITY_VAL_LOCAL() AS VAL FROM SYSIBM.SYSDUMMY1'; + $value = $this->fetchOne($sql); + return (string) $value; + } + + /** + * Begin a transaction. + * + * @return void + */ + protected function _beginTransaction() + { + $this->_setExecuteMode(DB2_AUTOCOMMIT_OFF); + } + + /** + * Commit a transaction. + * + * @return void + */ + protected function _commit() + { + if (!db2_commit($this->_connection)) { + /** + * @see Zend_Db_Adapter_Db2_Exception + */ + throw new Zend_Db_Adapter_Db2_Exception( + db2_conn_errormsg($this->_connection), + db2_conn_error($this->_connection)); + } + + $this->_setExecuteMode(DB2_AUTOCOMMIT_ON); + } + + /** + * Rollback a transaction. + * + * @return void + */ + protected function _rollBack() + { + if (!db2_rollback($this->_connection)) { + /** + * @see Zend_Db_Adapter_Db2_Exception + */ + throw new Zend_Db_Adapter_Db2_Exception( + db2_conn_errormsg($this->_connection), + db2_conn_error($this->_connection)); + } + $this->_setExecuteMode(DB2_AUTOCOMMIT_ON); + } + + /** + * Set the fetch mode. + * + * @param integer $mode + * @return void + * @throws Zend_Db_Adapter_Db2_Exception + */ + public function setFetchMode($mode) + { + switch ($mode) { + case Zend_Db::FETCH_NUM: // seq array + case Zend_Db::FETCH_ASSOC: // assoc array + case Zend_Db::FETCH_BOTH: // seq+assoc array + case Zend_Db::FETCH_OBJ: // object + $this->_fetchMode = $mode; + break; + case Zend_Db::FETCH_BOUND: // bound to PHP variable + /** + * @see Zend_Db_Adapter_Db2_Exception + */ + throw new Zend_Db_Adapter_Db2_Exception('FETCH_BOUND is not supported yet'); + break; + default: + /** + * @see Zend_Db_Adapter_Db2_Exception + */ + throw new Zend_Db_Adapter_Db2_Exception("Invalid fetch mode '$mode' specified"); + break; + } + } + + /** + * Adds an adapter-specific LIMIT clause to the SELECT statement. + * + * @param string $sql + * @param integer $count + * @param integer $offset OPTIONAL + * @return string + */ + public function limit($sql, $count, $offset = 0) + { + $count = intval($count); + if ($count <= 0) { + /** + * @see Zend_Db_Adapter_Db2_Exception + */ + throw new Zend_Db_Adapter_Db2_Exception("LIMIT argument count=$count is not valid"); + } + + $offset = intval($offset); + if ($offset < 0) { + /** + * @see Zend_Db_Adapter_Db2_Exception + */ + throw new Zend_Db_Adapter_Db2_Exception("LIMIT argument offset=$offset is not valid"); + } + + if ($offset == 0) { + $limit_sql = $sql . " FETCH FIRST $count ROWS ONLY"; + return $limit_sql; + } + + /** + * DB2 does not implement the LIMIT clause as some RDBMS do. + * We have to simulate it with subqueries and ROWNUM. + * Unfortunately because we use the column wildcard "*", + * this puts an extra column into the query result set. + */ + $limit_sql = "SELECT z2.* + FROM ( + SELECT ROW_NUMBER() OVER() AS \"ZEND_DB_ROWNUM\", z1.* + FROM ( + " . $sql . " + ) z1 + ) z2 + WHERE z2.zend_db_rownum BETWEEN " . ($offset+1) . " AND " . ($offset+$count); + return $limit_sql; + } + + /** + * Check if the adapter supports real SQL parameters. + * + * @param string $type 'positional' or 'named' + * @return bool + */ + public function supportsParameters($type) + { + if ($type == 'positional') { + return true; + } + + // if its 'named' or anything else + return false; + } + + /** + * Retrieve server version in PHP style + * + * @return string + */ + public function getServerVersion() + { + $this->_connect(); + $server_info = db2_server_info($this->_connection); + if ($server_info !== false) { + $version = $server_info->DBMS_VER; + if ($this->_isI5) { + $version = (int) substr($version, 0, 2) . '.' . (int) substr($version, 2, 2) . '.' . (int) substr($version, 4); + } + return $version; + } else { + return null; + } + } + + /** + * Return whether or not this is running on i5 + * + * @return bool + */ + public function isI5() + { + if ($this->_isI5 === null) { + $this->_determineI5(); + } + + return (bool) $this->_isI5; + } + + /** + * Check the connection parameters according to verify + * type of used OS + * + * @return void + */ + protected function _determineI5() + { + // first us the compiled flag. + $this->_isI5 = (php_uname('s') == 'OS400') ? true : false; + + // if this is set, then us it + if (isset($this->_config['os'])){ + if (strtolower($this->_config['os']) === 'i5') { + $this->_isI5 = true; + } else { + // any other value passed in, its null + $this->_isI5 = false; + } + } + + } + + /** + * Db2 On I5 specific method + * + * Returns a list of the tables in the database . + * Used only for DB2/400. + * + * @return array + */ + protected function _i5listTables($schema = null) + { + //list of i5 libraries. + $tables = array(); + if ($schema) { + $tablesStatement = db2_tables($this->_connection, null, $schema); + while ($rowTables = db2_fetch_assoc($tablesStatement) ) { + if ($rowTables['TABLE_NAME'] !== null) { + $tables[] = $rowTables['TABLE_NAME']; + } + } + } else { + $schemaStatement = db2_tables($this->_connection); + while ($schema = db2_fetch_assoc($schemaStatement)) { + if ($schema['TABLE_SCHEM'] !== null) { + // list of the tables which belongs to the selected library + $tablesStatement = db2_tables($this->_connection, NULL, $schema['TABLE_SCHEM']); + if (is_resource($tablesStatement)) { + while ($rowTables = db2_fetch_assoc($tablesStatement) ) { + if ($rowTables['TABLE_NAME'] !== null) { + $tables[] = $rowTables['TABLE_NAME']; + } + } + } + } + } + } + + return $tables; + } + + protected function _i5LastInsertId($objectName = null, $idType = null) + { + + if ($objectName === null) { + $sql = 'SELECT IDENTITY_VAL_LOCAL() AS VAL FROM QSYS2.QSQPTABL'; + $value = $this->fetchOne($sql); + return $value; + } + + if (strtoupper($idType) === 'S'){ + //check i5_lib option + $sequenceName = $objectName; + return $this->lastSequenceId($sequenceName); + } + + //returns last identity value for the specified table + //if (strtoupper($idType) === 'I') { + $tableName = $objectName; + return $this->fetchOne('SELECT IDENTITY_VAL_LOCAL() from ' . $this->quoteIdentifier($tableName)); + } + +} + + diff --git a/library/vendor/Zend/Db/Adapter/Db2/Exception.php b/library/vendor/Zend/Db/Adapter/Db2/Exception.php new file mode 100644 index 0000000..d12dc48 --- /dev/null +++ b/library/vendor/Zend/Db/Adapter/Db2/Exception.php @@ -0,0 +1,44 @@ +getCode(); + } + parent::__construct($message, $code, $e); + } + + public function hasChainedException() + { + return ($this->getPrevious() !== null); + } + + public function getChainedException() + { + return $this->getPrevious(); + } + +} diff --git a/library/vendor/Zend/Db/Adapter/Mysqli.php b/library/vendor/Zend/Db/Adapter/Mysqli.php new file mode 100644 index 0000000..087d3ac --- /dev/null +++ b/library/vendor/Zend/Db/Adapter/Mysqli.php @@ -0,0 +1,543 @@ + Zend_Db::INT_TYPE, + Zend_Db::BIGINT_TYPE => Zend_Db::BIGINT_TYPE, + Zend_Db::FLOAT_TYPE => Zend_Db::FLOAT_TYPE, + 'INT' => Zend_Db::INT_TYPE, + 'INTEGER' => Zend_Db::INT_TYPE, + 'MEDIUMINT' => Zend_Db::INT_TYPE, + 'SMALLINT' => Zend_Db::INT_TYPE, + 'TINYINT' => Zend_Db::INT_TYPE, + 'BIGINT' => Zend_Db::BIGINT_TYPE, + 'SERIAL' => Zend_Db::BIGINT_TYPE, + 'DEC' => Zend_Db::FLOAT_TYPE, + 'DECIMAL' => Zend_Db::FLOAT_TYPE, + 'DOUBLE' => Zend_Db::FLOAT_TYPE, + 'DOUBLE PRECISION' => Zend_Db::FLOAT_TYPE, + 'FIXED' => Zend_Db::FLOAT_TYPE, + 'FLOAT' => Zend_Db::FLOAT_TYPE + ); + + /** + * @var Zend_Db_Statement_Mysqli + */ + protected $_stmt = null; + + /** + * Default class name for a DB statement. + * + * @var string + */ + protected $_defaultStmtClass = 'Zend_Db_Statement_Mysqli'; + + /** + * Quote a raw string. + * + * @param mixed $value Raw string + * + * @return string Quoted string + */ + protected function _quote($value) + { + if (is_int($value) || is_float($value)) { + return $value; + } + $this->_connect(); + return "'" . $this->_connection->real_escape_string($value) . "'"; + } + + /** + * Returns the symbol the adapter uses for delimiting identifiers. + * + * @return string + */ + public function getQuoteIdentifierSymbol() + { + return "`"; + } + + /** + * Returns a list of the tables in the database. + * + * @return array + */ + public function listTables() + { + $result = array(); + // Use mysqli extension API, because SHOW doesn't work + // well as a prepared statement on MySQL 4.1. + $sql = 'SHOW TABLES'; + if ($queryResult = $this->getConnection()->query($sql)) { + while ($row = $queryResult->fetch_row()) { + $result[] = $row[0]; + } + $queryResult->close(); + } else { + /** + * @see Zend_Db_Adapter_Mysqli_Exception + */ + throw new Zend_Db_Adapter_Mysqli_Exception($this->getConnection()->error); + } + return $result; + } + + /** + * Returns the column descriptions for a table. + * + * The return value is an associative array keyed by the column name, + * as returned by the RDBMS. + * + * The value of each array element is an associative array + * with the following keys: + * + * SCHEMA_NAME => string; name of database or schema + * TABLE_NAME => string; + * COLUMN_NAME => string; column name + * COLUMN_POSITION => number; ordinal position of column in table + * DATA_TYPE => string; SQL datatype name of column + * DEFAULT => string; default expression of column, null if none + * NULLABLE => boolean; true if column can have nulls + * LENGTH => number; length of CHAR/VARCHAR + * SCALE => number; scale of NUMERIC/DECIMAL + * PRECISION => number; precision of NUMERIC/DECIMAL + * UNSIGNED => boolean; unsigned property of an integer type + * PRIMARY => boolean; true if column is part of the primary key + * PRIMARY_POSITION => integer; position of column in primary key + * IDENTITY => integer; true if column is auto-generated with unique values + * + * @param string $tableName + * @param string $schemaName OPTIONAL + * @return array + */ + public function describeTable($tableName, $schemaName = null) + { + /** + * @todo use INFORMATION_SCHEMA someday when + * MySQL's implementation isn't too slow. + */ + + if ($schemaName) { + $sql = 'DESCRIBE ' . $this->quoteIdentifier("$schemaName.$tableName", true); + } else { + $sql = 'DESCRIBE ' . $this->quoteIdentifier($tableName, true); + } + + /** + * Use mysqli extension API, because DESCRIBE doesn't work + * well as a prepared statement on MySQL 4.1. + */ + if ($queryResult = $this->getConnection()->query($sql)) { + while ($row = $queryResult->fetch_assoc()) { + $result[] = $row; + } + $queryResult->close(); + } else { + /** + * @see Zend_Db_Adapter_Mysqli_Exception + */ + throw new Zend_Db_Adapter_Mysqli_Exception($this->getConnection()->error); + } + + $desc = array(); + + $row_defaults = array( + 'Length' => null, + 'Scale' => null, + 'Precision' => null, + 'Unsigned' => null, + 'Primary' => false, + 'PrimaryPosition' => null, + 'Identity' => false + ); + $i = 1; + $p = 1; + foreach ($result as $key => $row) { + $row = array_merge($row_defaults, $row); + if (preg_match('/unsigned/', $row['Type'])) { + $row['Unsigned'] = true; + } + if (preg_match('/^((?:var)?char)\((\d+)\)/', $row['Type'], $matches)) { + $row['Type'] = $matches[1]; + $row['Length'] = $matches[2]; + } else if (preg_match('/^decimal\((\d+),(\d+)\)/', $row['Type'], $matches)) { + $row['Type'] = 'decimal'; + $row['Precision'] = $matches[1]; + $row['Scale'] = $matches[2]; + } else if (preg_match('/^float\((\d+),(\d+)\)/', $row['Type'], $matches)) { + $row['Type'] = 'float'; + $row['Precision'] = $matches[1]; + $row['Scale'] = $matches[2]; + } else if (preg_match('/^((?:big|medium|small|tiny)?int)\((\d+)\)/', $row['Type'], $matches)) { + $row['Type'] = $matches[1]; + /** + * The optional argument of a MySQL int type is not precision + * or length; it is only a hint for display width. + */ + } + if (strtoupper($row['Key']) == 'PRI') { + $row['Primary'] = true; + $row['PrimaryPosition'] = $p; + if ($row['Extra'] == 'auto_increment') { + $row['Identity'] = true; + } else { + $row['Identity'] = false; + } + ++$p; + } + $desc[$this->foldCase($row['Field'])] = array( + 'SCHEMA_NAME' => null, // @todo + 'TABLE_NAME' => $this->foldCase($tableName), + 'COLUMN_NAME' => $this->foldCase($row['Field']), + 'COLUMN_POSITION' => $i, + 'DATA_TYPE' => $row['Type'], + 'DEFAULT' => $row['Default'], + 'NULLABLE' => (bool) ($row['Null'] == 'YES'), + 'LENGTH' => $row['Length'], + 'SCALE' => $row['Scale'], + 'PRECISION' => $row['Precision'], + 'UNSIGNED' => $row['Unsigned'], + 'PRIMARY' => $row['Primary'], + 'PRIMARY_POSITION' => $row['PrimaryPosition'], + 'IDENTITY' => $row['Identity'] + ); + ++$i; + } + return $desc; + } + + /** + * Creates a connection to the database. + * + * @return void + * @throws Zend_Db_Adapter_Mysqli_Exception + */ + protected function _connect() + { + if ($this->_connection) { + return; + } + + if (!extension_loaded('mysqli')) { + /** + * @see Zend_Db_Adapter_Mysqli_Exception + */ + throw new Zend_Db_Adapter_Mysqli_Exception('The Mysqli extension is required for this adapter but the extension is not loaded'); + } + + if (isset($this->_config['port'])) { + $port = (integer) $this->_config['port']; + } else { + $port = null; + } + + if (isset($this->_config['socket'])) { + $socket = $this->_config['socket']; + } else { + $socket = null; + } + + $this->_connection = mysqli_init(); + + if(!empty($this->_config['driver_options'])) { + foreach($this->_config['driver_options'] as $option=>$value) { + if(is_string($option)) { + // Suppress warnings here + // Ignore it if it's not a valid constant + $option = @constant(strtoupper($option)); + if($option === null) + continue; + } + mysqli_options($this->_connection, $option, $value); + } + } + + // Suppress connection warnings here. + // Throw an exception instead. + $_isConnected = @mysqli_real_connect( + $this->_connection, + $this->_config['host'], + $this->_config['username'], + $this->_config['password'], + $this->_config['dbname'], + $port, + $socket + ); + + if ($_isConnected === false || mysqli_connect_errno()) { + + $this->closeConnection(); + /** + * @see Zend_Db_Adapter_Mysqli_Exception + */ + throw new Zend_Db_Adapter_Mysqli_Exception(mysqli_connect_error()); + } + + if (!empty($this->_config['charset'])) { + mysqli_set_charset($this->_connection, $this->_config['charset']); + } + } + + /** + * Test if a connection is active + * + * @return boolean + */ + public function isConnected() + { + return ((bool) ($this->_connection instanceof mysqli)); + } + + /** + * Force the connection to close. + * + * @return void + */ + public function closeConnection() + { + if ($this->isConnected()) { + $this->_connection->close(); + } + $this->_connection = null; + } + + /** + * Prepare a statement and return a PDOStatement-like object. + * + * @param string $sql SQL query + * @return Zend_Db_Statement_Mysqli + */ + public function prepare($sql) + { + $this->_connect(); + if ($this->_stmt) { + $this->_stmt->close(); + } + $stmtClass = $this->_defaultStmtClass; + if (!class_exists($stmtClass)) { + Zend_Loader::loadClass($stmtClass); + } + $stmt = new $stmtClass($this, $sql); + if ($stmt === false) { + return false; + } + $stmt->setFetchMode($this->_fetchMode); + $this->_stmt = $stmt; + return $stmt; + } + + /** + * Gets the last ID generated automatically by an IDENTITY/AUTOINCREMENT column. + * + * As a convention, on RDBMS brands that support sequences + * (e.g. Oracle, PostgreSQL, DB2), this method forms the name of a sequence + * from the arguments and returns the last id generated by that sequence. + * On RDBMS brands that support IDENTITY/AUTOINCREMENT columns, this method + * returns the last value generated for such a column, and the table name + * argument is disregarded. + * + * MySQL does not support sequences, so $tableName and $primaryKey are ignored. + * + * @param string $tableName OPTIONAL Name of table. + * @param string $primaryKey OPTIONAL Name of primary key column. + * @return string + * @todo Return value should be int? + */ + public function lastInsertId($tableName = null, $primaryKey = null) + { + $mysqli = $this->_connection; + return (string) $mysqli->insert_id; + } + + /** + * Begin a transaction. + * + * @return void + */ + protected function _beginTransaction() + { + $this->_connect(); + $this->_connection->autocommit(false); + } + + /** + * Commit a transaction. + * + * @return void + */ + protected function _commit() + { + $this->_connect(); + $this->_connection->commit(); + $this->_connection->autocommit(true); + } + + /** + * Roll-back a transaction. + * + * @return void + */ + protected function _rollBack() + { + $this->_connect(); + $this->_connection->rollback(); + $this->_connection->autocommit(true); + } + + /** + * Set the fetch mode. + * + * @param int $mode + * @return void + * @throws Zend_Db_Adapter_Mysqli_Exception + */ + public function setFetchMode($mode) + { + switch ($mode) { + case Zend_Db::FETCH_LAZY: + case Zend_Db::FETCH_ASSOC: + case Zend_Db::FETCH_NUM: + case Zend_Db::FETCH_BOTH: + case Zend_Db::FETCH_NAMED: + case Zend_Db::FETCH_OBJ: + $this->_fetchMode = $mode; + break; + case Zend_Db::FETCH_BOUND: // bound to PHP variable + /** + * @see Zend_Db_Adapter_Mysqli_Exception + */ + throw new Zend_Db_Adapter_Mysqli_Exception('FETCH_BOUND is not supported yet'); + break; + default: + /** + * @see Zend_Db_Adapter_Mysqli_Exception + */ + throw new Zend_Db_Adapter_Mysqli_Exception("Invalid fetch mode '$mode' specified"); + } + } + + /** + * Adds an adapter-specific LIMIT clause to the SELECT statement. + * + * @param string $sql + * @param int $count + * @param int $offset OPTIONAL + * @return string + */ + public function limit($sql, $count, $offset = 0) + { + $count = intval($count); + if ($count <= 0) { + /** + * @see Zend_Db_Adapter_Mysqli_Exception + */ + throw new Zend_Db_Adapter_Mysqli_Exception("LIMIT argument count=$count is not valid"); + } + + $offset = intval($offset); + if ($offset < 0) { + /** + * @see Zend_Db_Adapter_Mysqli_Exception + */ + throw new Zend_Db_Adapter_Mysqli_Exception("LIMIT argument offset=$offset is not valid"); + } + + $sql .= " LIMIT $count"; + if ($offset > 0) { + $sql .= " OFFSET $offset"; + } + + return $sql; + } + + /** + * Check if the adapter supports real SQL parameters. + * + * @param string $type 'positional' or 'named' + * @return bool + */ + public function supportsParameters($type) + { + switch ($type) { + case 'positional': + return true; + case 'named': + default: + return false; + } + } + + /** + * Retrieve server version in PHP style + * + *@return string + */ + public function getServerVersion() + { + $this->_connect(); + $version = $this->_connection->server_version; + $major = (int) ($version / 10000); + $minor = (int) ($version % 10000 / 100); + $revision = (int) ($version % 100); + return $major . '.' . $minor . '.' . $revision; + } +} diff --git a/library/vendor/Zend/Db/Adapter/Mysqli/Exception.php b/library/vendor/Zend/Db/Adapter/Mysqli/Exception.php new file mode 100644 index 0000000..9c94adc --- /dev/null +++ b/library/vendor/Zend/Db/Adapter/Mysqli/Exception.php @@ -0,0 +1,39 @@ + (string) Connect to the database as this username. + * password => (string) Password associated with the username. + * dbname => Either the name of the local Oracle instance, or the + * name of the entry in tnsnames.ora to which you want to connect. + * persistent => (boolean) Set TRUE to use a persistent connection + * @var array + */ + protected $_config = array( + 'dbname' => null, + 'username' => null, + 'password' => null, + 'persistent' => false + ); + + /** + * Keys are UPPERCASE SQL datatypes or the constants + * Zend_Db::INT_TYPE, Zend_Db::BIGINT_TYPE, or Zend_Db::FLOAT_TYPE. + * + * Values are: + * 0 = 32-bit integer + * 1 = 64-bit integer + * 2 = float or decimal + * + * @var array Associative array of datatypes to values 0, 1, or 2. + */ + protected $_numericDataTypes = array( + Zend_Db::INT_TYPE => Zend_Db::INT_TYPE, + Zend_Db::BIGINT_TYPE => Zend_Db::BIGINT_TYPE, + Zend_Db::FLOAT_TYPE => Zend_Db::FLOAT_TYPE, + 'BINARY_DOUBLE' => Zend_Db::FLOAT_TYPE, + 'BINARY_FLOAT' => Zend_Db::FLOAT_TYPE, + 'NUMBER' => Zend_Db::FLOAT_TYPE, + ); + + /** + * @var integer + */ + protected $_execute_mode = null; + + /** + * Default class name for a DB statement. + * + * @var string + */ + protected $_defaultStmtClass = 'Zend_Db_Statement_Oracle'; + + /** + * Check if LOB field are returned as string + * instead of OCI-Lob object + * + * @var boolean + */ + protected $_lobAsString = null; + + /** + * Creates a connection resource. + * + * @return void + * @throws Zend_Db_Adapter_Oracle_Exception + */ + protected function _connect() + { + if (is_resource($this->_connection)) { + // connection already exists + return; + } + + if (!extension_loaded('oci8')) { + /** + * @see Zend_Db_Adapter_Oracle_Exception + */ + throw new Zend_Db_Adapter_Oracle_Exception('The OCI8 extension is required for this adapter but the extension is not loaded'); + } + + $this->_setExecuteMode(OCI_COMMIT_ON_SUCCESS); + + $connectionFuncName = ($this->_config['persistent'] == true) ? 'oci_pconnect' : 'oci_connect'; + + $this->_connection = @$connectionFuncName( + $this->_config['username'], + $this->_config['password'], + $this->_config['dbname'], + $this->_config['charset']); + + // check the connection + if (!$this->_connection) { + /** + * @see Zend_Db_Adapter_Oracle_Exception + */ + throw new Zend_Db_Adapter_Oracle_Exception(oci_error()); + } + } + + /** + * Test if a connection is active + * + * @return boolean + */ + public function isConnected() + { + return ((bool) (is_resource($this->_connection) + && (get_resource_type($this->_connection) == 'oci8 connection' + || get_resource_type($this->_connection) == 'oci8 persistent connection'))); + } + + /** + * Force the connection to close. + * + * @return void + */ + public function closeConnection() + { + if ($this->isConnected()) { + oci_close($this->_connection); + } + $this->_connection = null; + } + + /** + * Activate/deactivate return of LOB as string + * + * @param string $lob_as_string + * @return Zend_Db_Adapter_Oracle + */ + public function setLobAsString($lobAsString) + { + $this->_lobAsString = (bool) $lobAsString; + return $this; + } + + /** + * Return whether or not LOB are returned as string + * + * @return boolean + */ + public function getLobAsString() + { + if ($this->_lobAsString === null) { + // if never set by user, we use driver option if it exists otherwise false + if (isset($this->_config['driver_options']) && + isset($this->_config['driver_options']['lob_as_string'])) { + $this->_lobAsString = (bool) $this->_config['driver_options']['lob_as_string']; + } else { + $this->_lobAsString = false; + } + } + return $this->_lobAsString; + } + + /** + * Returns an SQL statement for preparation. + * + * @param string $sql The SQL statement with placeholders. + * @return Zend_Db_Statement_Oracle + */ + public function prepare($sql) + { + $this->_connect(); + $stmtClass = $this->_defaultStmtClass; + if (!class_exists($stmtClass)) { + Zend_Loader::loadClass($stmtClass); + } + $stmt = new $stmtClass($this, $sql); + if ($stmt instanceof Zend_Db_Statement_Oracle) { + $stmt->setLobAsString($this->getLobAsString()); + } + $stmt->setFetchMode($this->_fetchMode); + return $stmt; + } + + /** + * Quote a raw string. + * + * @param string $value Raw string + * @return string Quoted string + */ + protected function _quote($value) + { + if (is_int($value) || is_float($value)) { + return $value; + } + $value = str_replace("'", "''", $value); + return "'" . addcslashes($value, "\000\n\r\\\032") . "'"; + } + + /** + * Quote a table identifier and alias. + * + * @param string|array|Zend_Db_Expr $ident The identifier or expression. + * @param string $alias An alias for the table. + * @param boolean $auto If true, heed the AUTO_QUOTE_IDENTIFIERS config option. + * @return string The quoted identifier and alias. + */ + public function quoteTableAs($ident, $alias = null, $auto = false) + { + // Oracle doesn't allow the 'AS' keyword between the table identifier/expression and alias. + return $this->_quoteIdentifierAs($ident, $alias, $auto, ' '); + } + + /** + * Return the most recent value from the specified sequence in the database. + * This is supported only on RDBMS brands that support sequences + * (e.g. Oracle, PostgreSQL, DB2). Other RDBMS brands return null. + * + * @param string $sequenceName + * @return string + */ + public function lastSequenceId($sequenceName) + { + $this->_connect(); + $sql = 'SELECT '.$this->quoteIdentifier($sequenceName, true).'.CURRVAL FROM dual'; + $value = $this->fetchOne($sql); + return $value; + } + + /** + * Generate a new value from the specified sequence in the database, and return it. + * This is supported only on RDBMS brands that support sequences + * (e.g. Oracle, PostgreSQL, DB2). Other RDBMS brands return null. + * + * @param string $sequenceName + * @return string + */ + public function nextSequenceId($sequenceName) + { + $this->_connect(); + $sql = 'SELECT '.$this->quoteIdentifier($sequenceName, true).'.NEXTVAL FROM dual'; + $value = $this->fetchOne($sql); + return $value; + } + + /** + * Gets the last ID generated automatically by an IDENTITY/AUTOINCREMENT column. + * + * As a convention, on RDBMS brands that support sequences + * (e.g. Oracle, PostgreSQL, DB2), this method forms the name of a sequence + * from the arguments and returns the last id generated by that sequence. + * On RDBMS brands that support IDENTITY/AUTOINCREMENT columns, this method + * returns the last value generated for such a column, and the table name + * argument is disregarded. + * + * Oracle does not support IDENTITY columns, so if the sequence is not + * specified, this method returns null. + * + * @param string $tableName OPTIONAL Name of table. + * @param string $primaryKey OPTIONAL Name of primary key column. + * @return string + */ + public function lastInsertId($tableName = null, $primaryKey = null) + { + if ($tableName !== null) { + $sequenceName = $tableName; + if ($primaryKey) { + $sequenceName .= "_$primaryKey"; + } + $sequenceName .= '_seq'; + return $this->lastSequenceId($sequenceName); + } + + // No support for IDENTITY columns; return null + return null; + } + + /** + * Returns a list of the tables in the database. + * + * @return array + */ + public function listTables() + { + $this->_connect(); + $data = $this->fetchCol('SELECT table_name FROM all_tables'); + return $data; + } + + /** + * Returns the column descriptions for a table. + * + * The return value is an associative array keyed by the column name, + * as returned by the RDBMS. + * + * The value of each array element is an associative array + * with the following keys: + * + * SCHEMA_NAME => string; name of schema + * TABLE_NAME => string; + * COLUMN_NAME => string; column name + * COLUMN_POSITION => number; ordinal position of column in table + * DATA_TYPE => string; SQL datatype name of column + * DEFAULT => string; default expression of column, null if none + * NULLABLE => boolean; true if column can have nulls + * LENGTH => number; length of CHAR/VARCHAR + * SCALE => number; scale of NUMERIC/DECIMAL + * PRECISION => number; precision of NUMERIC/DECIMAL + * UNSIGNED => boolean; unsigned property of an integer type + * PRIMARY => boolean; true if column is part of the primary key + * PRIMARY_POSITION => integer; position of column in primary key + * IDENTITY => integer; true if column is auto-generated with unique values + * + * @todo Discover integer unsigned property. + * + * @param string $tableName + * @param string $schemaName OPTIONAL + * @return array + */ + public function describeTable($tableName, $schemaName = null) + { + $version = $this->getServerVersion(); + if (($version === null) || version_compare($version, '9.0.0', '>=')) { + $sql = "SELECT TC.TABLE_NAME, TC.OWNER, TC.COLUMN_NAME, TC.DATA_TYPE, + TC.DATA_DEFAULT, TC.NULLABLE, TC.COLUMN_ID, TC.DATA_LENGTH, + TC.DATA_SCALE, TC.DATA_PRECISION, C.CONSTRAINT_TYPE, CC.POSITION + FROM ALL_TAB_COLUMNS TC + LEFT JOIN (ALL_CONS_COLUMNS CC JOIN ALL_CONSTRAINTS C + ON (CC.CONSTRAINT_NAME = C.CONSTRAINT_NAME AND CC.TABLE_NAME = C.TABLE_NAME AND CC.OWNER = C.OWNER AND C.CONSTRAINT_TYPE = 'P')) + ON TC.TABLE_NAME = CC.TABLE_NAME AND TC.COLUMN_NAME = CC.COLUMN_NAME + WHERE UPPER(TC.TABLE_NAME) = UPPER(:TBNAME)"; + $bind[':TBNAME'] = $tableName; + if ($schemaName) { + $sql .= ' AND UPPER(TC.OWNER) = UPPER(:SCNAME)'; + $bind[':SCNAME'] = $schemaName; + } + $sql .= ' ORDER BY TC.COLUMN_ID'; + } else { + $subSql="SELECT AC.OWNER, AC.TABLE_NAME, ACC.COLUMN_NAME, AC.CONSTRAINT_TYPE, ACC.POSITION + from ALL_CONSTRAINTS AC, ALL_CONS_COLUMNS ACC + WHERE ACC.CONSTRAINT_NAME = AC.CONSTRAINT_NAME + AND ACC.TABLE_NAME = AC.TABLE_NAME + AND ACC.OWNER = AC.OWNER + AND AC.CONSTRAINT_TYPE = 'P' + AND UPPER(AC.TABLE_NAME) = UPPER(:TBNAME)"; + $bind[':TBNAME'] = $tableName; + if ($schemaName) { + $subSql .= ' AND UPPER(ACC.OWNER) = UPPER(:SCNAME)'; + $bind[':SCNAME'] = $schemaName; + } + $sql="SELECT TC.TABLE_NAME, TC.OWNER, TC.COLUMN_NAME, TC.DATA_TYPE, + TC.DATA_DEFAULT, TC.NULLABLE, TC.COLUMN_ID, TC.DATA_LENGTH, + TC.DATA_SCALE, TC.DATA_PRECISION, CC.CONSTRAINT_TYPE, CC.POSITION + FROM ALL_TAB_COLUMNS TC, ($subSql) CC + WHERE UPPER(TC.TABLE_NAME) = UPPER(:TBNAME) + AND TC.OWNER = CC.OWNER(+) AND TC.TABLE_NAME = CC.TABLE_NAME(+) AND TC.COLUMN_NAME = CC.COLUMN_NAME(+)"; + if ($schemaName) { + $sql .= ' AND UPPER(TC.OWNER) = UPPER(:SCNAME)'; + } + $sql .= ' ORDER BY TC.COLUMN_ID'; + } + + $stmt = $this->query($sql, $bind); + + /** + * Use FETCH_NUM so we are not dependent on the CASE attribute of the PDO connection + */ + $result = $stmt->fetchAll(Zend_Db::FETCH_NUM); + + $table_name = 0; + $owner = 1; + $column_name = 2; + $data_type = 3; + $data_default = 4; + $nullable = 5; + $column_id = 6; + $data_length = 7; + $data_scale = 8; + $data_precision = 9; + $constraint_type = 10; + $position = 11; + + $desc = array(); + foreach ($result as $key => $row) { + list ($primary, $primaryPosition, $identity) = array(false, null, false); + if ($row[$constraint_type] == 'P') { + $primary = true; + $primaryPosition = $row[$position]; + /** + * Oracle does not support auto-increment keys. + */ + $identity = false; + } + $desc[$this->foldCase($row[$column_name])] = array( + 'SCHEMA_NAME' => $this->foldCase($row[$owner]), + 'TABLE_NAME' => $this->foldCase($row[$table_name]), + 'COLUMN_NAME' => $this->foldCase($row[$column_name]), + 'COLUMN_POSITION' => $row[$column_id], + 'DATA_TYPE' => $row[$data_type], + 'DEFAULT' => $row[$data_default], + 'NULLABLE' => (bool) ($row[$nullable] == 'Y'), + 'LENGTH' => $row[$data_length], + 'SCALE' => $row[$data_scale], + 'PRECISION' => $row[$data_precision], + 'UNSIGNED' => null, // @todo + 'PRIMARY' => $primary, + 'PRIMARY_POSITION' => $primaryPosition, + 'IDENTITY' => $identity + ); + } + return $desc; + } + + /** + * Leave autocommit mode and begin a transaction. + * + * @return void + */ + protected function _beginTransaction() + { + $this->_setExecuteMode(OCI_DEFAULT); + } + + /** + * Commit a transaction and return to autocommit mode. + * + * @return void + * @throws Zend_Db_Adapter_Oracle_Exception + */ + protected function _commit() + { + if (!oci_commit($this->_connection)) { + /** + * @see Zend_Db_Adapter_Oracle_Exception + */ + throw new Zend_Db_Adapter_Oracle_Exception(oci_error($this->_connection)); + } + $this->_setExecuteMode(OCI_COMMIT_ON_SUCCESS); + } + + /** + * Roll back a transaction and return to autocommit mode. + * + * @return void + * @throws Zend_Db_Adapter_Oracle_Exception + */ + protected function _rollBack() + { + if (!oci_rollback($this->_connection)) { + /** + * @see Zend_Db_Adapter_Oracle_Exception + */ + throw new Zend_Db_Adapter_Oracle_Exception(oci_error($this->_connection)); + } + $this->_setExecuteMode(OCI_COMMIT_ON_SUCCESS); + } + + /** + * Set the fetch mode. + * + * @todo Support FETCH_CLASS and FETCH_INTO. + * + * @param integer $mode A fetch mode. + * @return void + * @throws Zend_Db_Adapter_Oracle_Exception + */ + public function setFetchMode($mode) + { + switch ($mode) { + case Zend_Db::FETCH_NUM: // seq array + case Zend_Db::FETCH_ASSOC: // assoc array + case Zend_Db::FETCH_BOTH: // seq+assoc array + case Zend_Db::FETCH_OBJ: // object + $this->_fetchMode = $mode; + break; + case Zend_Db::FETCH_BOUND: // bound to PHP variable + /** + * @see Zend_Db_Adapter_Oracle_Exception + */ + throw new Zend_Db_Adapter_Oracle_Exception('FETCH_BOUND is not supported yet'); + break; + default: + /** + * @see Zend_Db_Adapter_Oracle_Exception + */ + throw new Zend_Db_Adapter_Oracle_Exception("Invalid fetch mode '$mode' specified"); + break; + } + } + + /** + * Adds an adapter-specific LIMIT clause to the SELECT statement. + * + * @param string $sql + * @param integer $count + * @param integer $offset OPTIONAL + * @return string + * @throws Zend_Db_Adapter_Oracle_Exception + */ + public function limit($sql, $count, $offset = 0) + { + $count = intval($count); + if ($count <= 0) { + /** + * @see Zend_Db_Adapter_Oracle_Exception + */ + throw new Zend_Db_Adapter_Oracle_Exception("LIMIT argument count=$count is not valid"); + } + + $offset = intval($offset); + if ($offset < 0) { + /** + * @see Zend_Db_Adapter_Oracle_Exception + */ + throw new Zend_Db_Adapter_Oracle_Exception("LIMIT argument offset=$offset is not valid"); + } + + /** + * Oracle does not implement the LIMIT clause as some RDBMS do. + * We have to simulate it with subqueries and ROWNUM. + * Unfortunately because we use the column wildcard "*", + * this puts an extra column into the query result set. + */ + $limit_sql = "SELECT z2.* + FROM ( + SELECT z1.*, ROWNUM AS \"zend_db_rownum\" + FROM ( + " . $sql . " + ) z1 + ) z2 + WHERE z2.\"zend_db_rownum\" BETWEEN " . ($offset+1) . " AND " . ($offset+$count); + return $limit_sql; + } + + /** + * @param integer $mode + * @throws Zend_Db_Adapter_Oracle_Exception + */ + private function _setExecuteMode($mode) + { + switch($mode) { + case OCI_COMMIT_ON_SUCCESS: + case OCI_DEFAULT: + case OCI_DESCRIBE_ONLY: + $this->_execute_mode = $mode; + break; + default: + /** + * @see Zend_Db_Adapter_Oracle_Exception + */ + throw new Zend_Db_Adapter_Oracle_Exception("Invalid execution mode '$mode' specified"); + break; + } + } + + /** + * @return int + */ + public function _getExecuteMode() + { + return $this->_execute_mode; + } + + /** + * Check if the adapter supports real SQL parameters. + * + * @param string $type 'positional' or 'named' + * @return bool + */ + public function supportsParameters($type) + { + switch ($type) { + case 'named': + return true; + case 'positional': + default: + return false; + } + } + + /** + * Retrieve server version in PHP style + * + * @return string + */ + public function getServerVersion() + { + $this->_connect(); + $version = oci_server_version($this->_connection); + if ($version !== false) { + $matches = null; + if (preg_match('/((?:[0-9]{1,2}\.){1,3}[0-9]{1,2})/', $version, $matches)) { + return $matches[1]; + } else { + return null; + } + } else { + return null; + } + } +} diff --git a/library/vendor/Zend/Db/Adapter/Oracle/Exception.php b/library/vendor/Zend/Db/Adapter/Oracle/Exception.php new file mode 100644 index 0000000..6b7d914 --- /dev/null +++ b/library/vendor/Zend/Db/Adapter/Oracle/Exception.php @@ -0,0 +1,59 @@ +message = $error['code'] .' '. $error['message']; + } else { + $this->message = $error['code'] .' '. $error['message']." " + . substr($error['sqltext'], 0, $error['offset']) + . "*" + . substr($error['sqltext'], $error['offset']); + } + $this->code = $error['code']; + } else if (is_string($error)) { + $this->message = $error; + } + if (!$this->code && $code) { + $this->code = $code; + } + } +} diff --git a/library/vendor/Zend/Db/Adapter/Pdo/Abstract.php b/library/vendor/Zend/Db/Adapter/Pdo/Abstract.php new file mode 100644 index 0000000..3a0e13e --- /dev/null +++ b/library/vendor/Zend/Db/Adapter/Pdo/Abstract.php @@ -0,0 +1,397 @@ +_config settings. + * + * @return string + */ + protected function _dsn() + { + // baseline of DSN parts + $dsn = $this->_config; + + // don't pass the username, password, charset, persistent and driver_options in the DSN + unset($dsn['username']); + unset($dsn['password']); + unset($dsn['options']); + unset($dsn['charset']); + unset($dsn['persistent']); + unset($dsn['driver_options']); + + // use all remaining parts in the DSN + foreach ($dsn as $key => $val) { + $dsn[$key] = "$key=$val"; + } + + return $this->_pdoType . ':' . implode(';', $dsn); + } + + /** + * Creates a PDO object and connects to the database. + * + * @return void + * @throws Zend_Db_Adapter_Exception + */ + protected function _connect() + { + // if we already have a PDO object, no need to re-connect. + if ($this->_connection) { + return; + } + + // get the dsn first, because some adapters alter the $_pdoType + $dsn = $this->_dsn(); + + // check for PDO extension + if (!extension_loaded('pdo')) { + /** + * @see Zend_Db_Adapter_Exception + */ + throw new Zend_Db_Adapter_Exception('The PDO extension is required for this adapter but the extension is not loaded'); + } + + // check the PDO driver is available + if (!in_array($this->_pdoType, PDO::getAvailableDrivers())) { + /** + * @see Zend_Db_Adapter_Exception + */ + throw new Zend_Db_Adapter_Exception('The ' . $this->_pdoType . ' driver is not currently installed'); + } + + // create PDO connection + $q = $this->_profiler->queryStart('connect', Zend_Db_Profiler::CONNECT); + + // add the persistence flag if we find it in our config array + if (isset($this->_config['persistent']) && ($this->_config['persistent'] == true)) { + $this->_config['driver_options'][PDO::ATTR_PERSISTENT] = true; + } + + try { + $this->_connection = new PDO( + $dsn, + $this->_config['username'], + $this->_config['password'], + $this->_config['driver_options'] + ); + + $this->_profiler->queryEnd($q); + + // set the PDO connection to perform case-folding on array keys, or not + $this->_connection->setAttribute(PDO::ATTR_CASE, $this->_caseFolding); + + // always use exceptions. + $this->_connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); + + } catch (PDOException $e) { + $message = $e->getMessage(); + if ($e->getPrevious() !== null && preg_match('~^SQLSTATE\[HY000\] \[\d{1,4}\]\s$~', $message)) { + // See https://bugs.php.net/bug.php?id=76604 + $message .= $e->getPrevious()->getMessage(); + } + + /** + * @see Zend_Db_Adapter_Exception + */ + throw new Zend_Db_Adapter_Exception($message, $e->getCode(), $e); + } + + } + + /** + * Test if a connection is active + * + * @return boolean + */ + public function isConnected() + { + return ((bool) ($this->_connection instanceof PDO)); + } + + /** + * Force the connection to close. + * + * @return void + */ + public function closeConnection() + { + $this->_connection = null; + } + + /** + * Prepares an SQL statement. + * + * @param string $sql The SQL statement with placeholders. + * @param array $bind An array of data to bind to the placeholders. + * @return PDOStatement + */ + public function prepare($sql) + { + $this->_connect(); + $stmtClass = $this->_defaultStmtClass; + if (!class_exists($stmtClass)) { + Zend_Loader::loadClass($stmtClass); + } + $stmt = new $stmtClass($this, $sql); + $stmt->setFetchMode($this->_fetchMode); + return $stmt; + } + + /** + * Gets the last ID generated automatically by an IDENTITY/AUTOINCREMENT column. + * + * As a convention, on RDBMS brands that support sequences + * (e.g. Oracle, PostgreSQL, DB2), this method forms the name of a sequence + * from the arguments and returns the last id generated by that sequence. + * On RDBMS brands that support IDENTITY/AUTOINCREMENT columns, this method + * returns the last value generated for such a column, and the table name + * argument is disregarded. + * + * On RDBMS brands that don't support sequences, $tableName and $primaryKey + * are ignored. + * + * @param string $tableName OPTIONAL Name of table. + * @param string $primaryKey OPTIONAL Name of primary key column. + * @return string + */ + public function lastInsertId($tableName = null, $primaryKey = null) + { + $this->_connect(); + return $this->_connection->lastInsertId(); + } + + /** + * Special handling for PDO query(). + * All bind parameter names must begin with ':' + * + * @param string|Zend_Db_Select $sql The SQL statement with placeholders. + * @param array $bind An array of data to bind to the placeholders. + * @return Zend_Db_Statement_Pdo + * @throws Zend_Db_Adapter_Exception To re-throw PDOException. + */ + public function query($sql, $bind = array()) + { + if (empty($bind) && $sql instanceof Zend_Db_Select) { + $bind = $sql->getBind(); + } + + if (is_array($bind)) { + foreach ($bind as $name => $value) { + if (!is_int($name) && !preg_match('/^:/', $name)) { + $newName = ":$name"; + unset($bind[$name]); + $bind[$newName] = $value; + } + } + } + + try { + return parent::query($sql, $bind); + } catch (PDOException $e) { + /** + * @see Zend_Db_Statement_Exception + */ + throw new Zend_Db_Statement_Exception($e->getMessage(), $e->getCode(), $e); + } + } + + /** + * Executes an SQL statement and return the number of affected rows + * + * @param mixed $sql The SQL statement with placeholders. + * May be a string or Zend_Db_Select. + * @return integer Number of rows that were modified + * or deleted by the SQL statement + */ + public function exec($sql) + { + if ($sql instanceof Zend_Db_Select) { + $sql = $sql->assemble(); + } + + try { + $affected = $this->getConnection()->exec($sql); + + if ($affected === false) { + $errorInfo = $this->getConnection()->errorInfo(); + /** + * @see Zend_Db_Adapter_Exception + */ + throw new Zend_Db_Adapter_Exception($errorInfo[2]); + } + + return $affected; + } catch (PDOException $e) { + /** + * @see Zend_Db_Adapter_Exception + */ + throw new Zend_Db_Adapter_Exception($e->getMessage(), $e->getCode(), $e); + } + } + + /** + * Quote a raw string. + * + * @param string $value Raw string + * @return string Quoted string + */ + protected function _quote($value) + { + if ($value === null) { + $value = ''; + } elseif (is_int($value) || is_float($value)) { + return $value; + } + $this->_connect(); + return $this->_connection->quote($value); + } + + /** + * Begin a transaction. + */ + protected function _beginTransaction() + { + $this->_connect(); + $this->_connection->beginTransaction(); + } + + /** + * Commit a transaction. + */ + protected function _commit() + { + $this->_connect(); + $this->_connection->commit(); + } + + /** + * Roll-back a transaction. + */ + protected function _rollBack() { + $this->_connect(); + $this->_connection->rollBack(); + } + + /** + * Set the PDO fetch mode. + * + * @todo Support FETCH_CLASS and FETCH_INTO. + * + * @param int $mode A PDO fetch mode. + * @return void + * @throws Zend_Db_Adapter_Exception + */ + public function setFetchMode($mode) + { + //check for PDO extension + if (!extension_loaded('pdo')) { + /** + * @see Zend_Db_Adapter_Exception + */ + throw new Zend_Db_Adapter_Exception('The PDO extension is required for this adapter but the extension is not loaded'); + } + switch ($mode) { + case PDO::FETCH_LAZY: + case PDO::FETCH_ASSOC: + case PDO::FETCH_NUM: + case PDO::FETCH_BOTH: + case PDO::FETCH_NAMED: + case PDO::FETCH_OBJ: + $this->_fetchMode = $mode; + break; + default: + /** + * @see Zend_Db_Adapter_Exception + */ + throw new Zend_Db_Adapter_Exception("Invalid fetch mode '$mode' specified"); + break; + } + } + + /** + * Check if the adapter supports real SQL parameters. + * + * @param string $type 'positional' or 'named' + * @return bool + */ + public function supportsParameters($type) + { + switch ($type) { + case 'positional': + case 'named': + default: + return true; + } + } + + /** + * Retrieve server version in PHP style + * + * @return string + */ + public function getServerVersion() + { + $this->_connect(); + try { + $version = $this->_connection->getAttribute(PDO::ATTR_SERVER_VERSION); + } catch (PDOException $e) { + // In case of the driver doesn't support getting attributes + return null; + } + $matches = null; + if (preg_match('/((?:[0-9]{1,2}\.){1,3}[0-9]{1,2})/', $version, $matches)) { + return $matches[1]; + } else { + return null; + } + } +} diff --git a/library/vendor/Zend/Db/Adapter/Pdo/Ibm.php b/library/vendor/Zend/Db/Adapter/Pdo/Ibm.php new file mode 100644 index 0000000..cfb11a3 --- /dev/null +++ b/library/vendor/Zend/Db/Adapter/Pdo/Ibm.php @@ -0,0 +1,354 @@ + Zend_Db::INT_TYPE, + Zend_Db::BIGINT_TYPE => Zend_Db::BIGINT_TYPE, + Zend_Db::FLOAT_TYPE => Zend_Db::FLOAT_TYPE, + 'INTEGER' => Zend_Db::INT_TYPE, + 'SMALLINT' => Zend_Db::INT_TYPE, + 'BIGINT' => Zend_Db::BIGINT_TYPE, + 'DECIMAL' => Zend_Db::FLOAT_TYPE, + 'DEC' => Zend_Db::FLOAT_TYPE, + 'REAL' => Zend_Db::FLOAT_TYPE, + 'NUMERIC' => Zend_Db::FLOAT_TYPE, + 'DOUBLE PRECISION' => Zend_Db::FLOAT_TYPE, + 'FLOAT' => Zend_Db::FLOAT_TYPE + ); + + /** + * Creates a PDO object and connects to the database. + * + * The IBM data server is set. + * Current options are DB2 or IDS + * @todo also differentiate between z/OS and i/5 + * + * @return void + * @throws Zend_Db_Adapter_Exception + */ + public function _connect() + { + if ($this->_connection) { + return; + } + parent::_connect(); + + $this->getConnection()->setAttribute(Zend_Db::ATTR_STRINGIFY_FETCHES, true); + + try { + if ($this->_serverType === null) { + $server = substr($this->getConnection()->getAttribute(PDO::ATTR_SERVER_INFO), 0, 3); + + switch ($server) { + case 'DB2': + $this->_serverType = new Zend_Db_Adapter_Pdo_Ibm_Db2($this); + + // Add DB2-specific numeric types + $this->_numericDataTypes['DECFLOAT'] = Zend_Db::FLOAT_TYPE; + $this->_numericDataTypes['DOUBLE'] = Zend_Db::FLOAT_TYPE; + $this->_numericDataTypes['NUM'] = Zend_Db::FLOAT_TYPE; + + break; + case 'IDS': + $this->_serverType = new Zend_Db_Adapter_Pdo_Ibm_Ids($this); + + // Add IDS-specific numeric types + $this->_numericDataTypes['SERIAL'] = Zend_Db::INT_TYPE; + $this->_numericDataTypes['SERIAL8'] = Zend_Db::BIGINT_TYPE; + $this->_numericDataTypes['INT8'] = Zend_Db::BIGINT_TYPE; + $this->_numericDataTypes['SMALLFLOAT'] = Zend_Db::FLOAT_TYPE; + $this->_numericDataTypes['MONEY'] = Zend_Db::FLOAT_TYPE; + + break; + } + } + } catch (PDOException $e) { + /** @see Zend_Db_Adapter_Exception */ + $error = strpos($e->getMessage(), 'driver does not support that attribute'); + if ($error) { + throw new Zend_Db_Adapter_Exception("PDO_IBM driver extension is downlevel. Please use driver release version 1.2.1 or later", 0, $e); + } else { + throw new Zend_Db_Adapter_Exception($e->getMessage(), $e->getCode(), $e); + } + } + } + + /** + * Creates a PDO DSN for the adapter from $this->_config settings. + * + * @return string + */ + protected function _dsn() + { + $this->_checkRequiredOptions($this->_config); + + // check if using full connection string + if (array_key_exists('host', $this->_config)) { + $dsn = ';DATABASE=' . $this->_config['dbname'] + . ';HOSTNAME=' . $this->_config['host'] + . ';PORT=' . $this->_config['port'] + // PDO_IBM supports only DB2 TCPIP protocol + . ';PROTOCOL=' . 'TCPIP;'; + } else { + // catalogued connection + $dsn = $this->_config['dbname']; + } + return $this->_pdoType . ': ' . $dsn; + } + + /** + * Checks required options + * + * @param array $config + * @throws Zend_Db_Adapter_Exception + * @return void + */ + protected function _checkRequiredOptions(array $config) + { + parent::_checkRequiredOptions($config); + + if (array_key_exists('host', $this->_config) && + !array_key_exists('port', $config)) { + /** @see Zend_Db_Adapter_Exception */ + throw new Zend_Db_Adapter_Exception("Configuration must have a key for 'port' when 'host' is specified"); + } + } + + /** + * Prepares an SQL statement. + * + * @param string $sql The SQL statement with placeholders. + * @param array $bind An array of data to bind to the placeholders. + * @return PDOStatement + */ + public function prepare($sql) + { + $this->_connect(); + $stmtClass = $this->_defaultStmtClass; + $stmt = new $stmtClass($this, $sql); + $stmt->setFetchMode($this->_fetchMode); + return $stmt; + } + + /** + * Returns a list of the tables in the database. + * + * @return array + */ + public function listTables() + { + $this->_connect(); + return $this->_serverType->listTables(); + } + + /** + * Returns the column descriptions for a table. + * + * The return value is an associative array keyed by the column name, + * as returned by the RDBMS. + * + * The value of each array element is an associative array + * with the following keys: + * + * SCHEMA_NAME => string; name of database or schema + * TABLE_NAME => string; + * COLUMN_NAME => string; column name + * COLUMN_POSITION => number; ordinal position of column in table + * DATA_TYPE => string; SQL datatype name of column + * DEFAULT => string; default expression of column, null if none + * NULLABLE => boolean; true if column can have nulls + * LENGTH => number; length of CHAR/VARCHAR + * SCALE => number; scale of NUMERIC/DECIMAL + * PRECISION => number; precision of NUMERIC/DECIMAL + * UNSIGNED => boolean; unsigned property of an integer type + * PRIMARY => boolean; true if column is part of the primary key + * PRIMARY_POSITION => integer; position of column in primary key + * + * @todo Discover integer unsigned property. + * + * @param string $tableName + * @param string $schemaName OPTIONAL + * @return array + */ + public function describeTable($tableName, $schemaName = null) + { + $this->_connect(); + return $this->_serverType->describeTable($tableName, $schemaName); + } + + /** + * Inserts a table row with specified data. + * Special handling for PDO_IBM + * remove empty slots + * + * @param mixed $table The table to insert data into. + * @param array $bind Column-value pairs. + * @return int The number of affected rows. + */ + public function insert($table, array $bind) + { + $this->_connect(); + $newbind = array(); + if (is_array($bind)) { + foreach ($bind as $name => $value) { + if($value !== null) { + $newbind[$name] = $value; + } + } + } + + return parent::insert($table, $newbind); + } + + /** + * Adds an adapter-specific LIMIT clause to the SELECT statement. + * + * @param string $sql + * @param integer $count + * @param integer $offset OPTIONAL + * @return string + */ + public function limit($sql, $count, $offset = 0) + { + $this->_connect(); + return $this->_serverType->limit($sql, $count, $offset); + } + + /** + * Gets the last ID generated automatically by an IDENTITY/AUTOINCREMENT + * column. + * + * @param string $tableName OPTIONAL + * @param string $primaryKey OPTIONAL + * @return integer + */ + public function lastInsertId($tableName = null, $primaryKey = null) + { + $this->_connect(); + + if ($tableName !== null) { + $sequenceName = $tableName; + if ($primaryKey) { + $sequenceName .= "_$primaryKey"; + } + $sequenceName .= '_seq'; + return $this->lastSequenceId($sequenceName); + } + + $id = $this->getConnection()->lastInsertId(); + + return $id; + } + + /** + * Return the most recent value from the specified sequence in the database. + * + * @param string $sequenceName + * @return integer + */ + public function lastSequenceId($sequenceName) + { + $this->_connect(); + return $this->_serverType->lastSequenceId($sequenceName); + } + + /** + * Generate a new value from the specified sequence in the database, + * and return it. + * + * @param string $sequenceName + * @return integer + */ + public function nextSequenceId($sequenceName) + { + $this->_connect(); + return $this->_serverType->nextSequenceId($sequenceName); + } + + /** + * Retrieve server version in PHP style + * Pdo_Idm doesn't support getAttribute(PDO::ATTR_SERVER_VERSION) + * @return string + */ + public function getServerVersion() + { + try { + $stmt = $this->query('SELECT service_level, fixpack_num FROM TABLE (sysproc.env_get_inst_info()) as INSTANCEINFO'); + $result = $stmt->fetchAll(Zend_Db::FETCH_NUM); + if (count($result)) { + $matches = null; + if (preg_match('/((?:[0-9]{1,2}\.){1,3}[0-9]{1,2})/', $result[0][0], $matches)) { + return $matches[1]; + } else { + return null; + } + } + return null; + } catch (PDOException $e) { + return null; + } + } +} diff --git a/library/vendor/Zend/Db/Adapter/Pdo/Ibm/Db2.php b/library/vendor/Zend/Db/Adapter/Pdo/Ibm/Db2.php new file mode 100644 index 0000000..1c11c8b --- /dev/null +++ b/library/vendor/Zend/Db/Adapter/Pdo/Ibm/Db2.php @@ -0,0 +1,224 @@ +_adapter = $adapter; + } + + /** + * Returns a list of the tables in the database. + * + * @return array + */ + public function listTables() + { + $sql = "SELECT tabname " + . "FROM SYSCAT.TABLES "; + return $this->_adapter->fetchCol($sql); + } + + /** + * DB2 catalog lookup for describe table + * + * @param string $tableName + * @param string $schemaName OPTIONAL + * @return array + */ + public function describeTable($tableName, $schemaName = null) + { + $sql = "SELECT DISTINCT c.tabschema, c.tabname, c.colname, c.colno, + c.typename, c.default, c.nulls, c.length, c.scale, + c.identity, tc.type AS tabconsttype, k.colseq + FROM syscat.columns c + LEFT JOIN (syscat.keycoluse k JOIN syscat.tabconst tc + ON (k.tabschema = tc.tabschema + AND k.tabname = tc.tabname + AND tc.type = 'P')) + ON (c.tabschema = k.tabschema + AND c.tabname = k.tabname + AND c.colname = k.colname) + WHERE " + . $this->_adapter->quoteInto('UPPER(c.tabname) = UPPER(?)', $tableName); + if ($schemaName) { + $sql .= $this->_adapter->quoteInto(' AND UPPER(c.tabschema) = UPPER(?)', $schemaName); + } + $sql .= " ORDER BY c.colno"; + + $desc = array(); + $stmt = $this->_adapter->query($sql); + + /** + * To avoid case issues, fetch using FETCH_NUM + */ + $result = $stmt->fetchAll(Zend_Db::FETCH_NUM); + + /** + * The ordering of columns is defined by the query so we can map + * to variables to improve readability + */ + $tabschema = 0; + $tabname = 1; + $colname = 2; + $colno = 3; + $typename = 4; + $default = 5; + $nulls = 6; + $length = 7; + $scale = 8; + $identityCol = 9; + $tabconstype = 10; + $colseq = 11; + + foreach ($result as $key => $row) { + list ($primary, $primaryPosition, $identity) = array(false, null, false); + if ($row[$tabconstype] == 'P') { + $primary = true; + $primaryPosition = $row[$colseq]; + } + /** + * In IBM DB2, an column can be IDENTITY + * even if it is not part of the PRIMARY KEY. + */ + if ($row[$identityCol] == 'Y') { + $identity = true; + } + + $desc[$this->_adapter->foldCase($row[$colname])] = array( + 'SCHEMA_NAME' => $this->_adapter->foldCase($row[$tabschema]), + 'TABLE_NAME' => $this->_adapter->foldCase($row[$tabname]), + 'COLUMN_NAME' => $this->_adapter->foldCase($row[$colname]), + 'COLUMN_POSITION' => $row[$colno]+1, + 'DATA_TYPE' => $row[$typename], + 'DEFAULT' => $row[$default], + 'NULLABLE' => (bool) ($row[$nulls] == 'Y'), + 'LENGTH' => $row[$length], + 'SCALE' => $row[$scale], + 'PRECISION' => ($row[$typename] == 'DECIMAL' ? $row[$length] : 0), + 'UNSIGNED' => false, + 'PRIMARY' => $primary, + 'PRIMARY_POSITION' => $primaryPosition, + 'IDENTITY' => $identity + ); + } + + return $desc; + } + + /** + * Adds a DB2-specific LIMIT clause to the SELECT statement. + * + * @param string $sql + * @param integer $count + * @param integer $offset OPTIONAL + * @throws Zend_Db_Adapter_Exception + * @return string + */ + public function limit($sql, $count, $offset = 0) + { + $count = intval($count); + if ($count < 0) { + /** @see Zend_Db_Adapter_Exception */ + throw new Zend_Db_Adapter_Exception("LIMIT argument count=$count is not valid"); + } else { + $offset = intval($offset); + if ($offset < 0) { + /** @see Zend_Db_Adapter_Exception */ + throw new Zend_Db_Adapter_Exception("LIMIT argument offset=$offset is not valid"); + } + + if ($offset == 0 && $count > 0) { + $limit_sql = $sql . " FETCH FIRST $count ROWS ONLY"; + return $limit_sql; + } + /** + * DB2 does not implement the LIMIT clause as some RDBMS do. + * We have to simulate it with subqueries and ROWNUM. + * Unfortunately because we use the column wildcard "*", + * this puts an extra column into the query result set. + */ + $limit_sql = "SELECT z2.* + FROM ( + SELECT ROW_NUMBER() OVER() AS \"ZEND_DB_ROWNUM\", z1.* + FROM ( + " . $sql . " + ) z1 + ) z2 + WHERE z2.zend_db_rownum BETWEEN " . ($offset+1) . " AND " . ($offset+$count); + } + return $limit_sql; + } + + /** + * DB2-specific last sequence id + * + * @param string $sequenceName + * @return integer + */ + public function lastSequenceId($sequenceName) + { + $sql = 'SELECT PREVVAL FOR '.$this->_adapter->quoteIdentifier($sequenceName).' AS VAL FROM SYSIBM.SYSDUMMY1'; + $value = $this->_adapter->fetchOne($sql); + return $value; + } + + /** + * DB2-specific sequence id value + * + * @param string $sequenceName + * @return integer + */ + public function nextSequenceId($sequenceName) + { + $sql = 'SELECT NEXTVAL FOR '.$this->_adapter->quoteIdentifier($sequenceName).' AS VAL FROM SYSIBM.SYSDUMMY1'; + $value = $this->_adapter->fetchOne($sql); + return $value; + } +} diff --git a/library/vendor/Zend/Db/Adapter/Pdo/Ibm/Ids.php b/library/vendor/Zend/Db/Adapter/Pdo/Ibm/Ids.php new file mode 100644 index 0000000..eeec43f --- /dev/null +++ b/library/vendor/Zend/Db/Adapter/Pdo/Ibm/Ids.php @@ -0,0 +1,297 @@ +_adapter = $adapter; + } + + /** + * Returns a list of the tables in the database. + * + * @return array + */ + public function listTables() + { + $sql = "SELECT tabname " + . "FROM systables "; + + return $this->_adapter->fetchCol($sql); + } + + /** + * IDS catalog lookup for describe table + * + * @param string $tableName + * @param string $schemaName OPTIONAL + * @return array + */ + public function describeTable($tableName, $schemaName = null) + { + // this is still a work in progress + + $sql= "SELECT DISTINCT t.owner, t.tabname, c.colname, c.colno, c.coltype, + d.default, c.collength, t.tabid + FROM syscolumns c + JOIN systables t ON c.tabid = t.tabid + LEFT JOIN sysdefaults d ON c.tabid = d.tabid AND c.colno = d.colno + WHERE " + . $this->_adapter->quoteInto('UPPER(t.tabname) = UPPER(?)', $tableName); + if ($schemaName) { + $sql .= $this->_adapter->quoteInto(' AND UPPER(t.owner) = UPPER(?)', $schemaName); + } + $sql .= " ORDER BY c.colno"; + + $desc = array(); + $stmt = $this->_adapter->query($sql); + + $result = $stmt->fetchAll(Zend_Db::FETCH_NUM); + + /** + * The ordering of columns is defined by the query so we can map + * to variables to improve readability + */ + $tabschema = 0; + $tabname = 1; + $colname = 2; + $colno = 3; + $typename = 4; + $default = 5; + $length = 6; + $tabid = 7; + + $primaryCols = null; + + foreach ($result as $key => $row) { + $primary = false; + $primaryPosition = null; + + if (!$primaryCols) { + $primaryCols = $this->_getPrimaryInfo($row[$tabid]); + } + + if (array_key_exists($row[$colno], $primaryCols)) { + $primary = true; + $primaryPosition = $primaryCols[$row[$colno]]; + } + + $identity = false; + if ($row[$typename] == 6 + 256 || + $row[$typename] == 18 + 256) { + $identity = true; + } + + $desc[$this->_adapter->foldCase($row[$colname])] = array ( + 'SCHEMA_NAME' => $this->_adapter->foldCase($row[$tabschema]), + 'TABLE_NAME' => $this->_adapter->foldCase($row[$tabname]), + 'COLUMN_NAME' => $this->_adapter->foldCase($row[$colname]), + 'COLUMN_POSITION' => $row[$colno], + 'DATA_TYPE' => $this->_getDataType($row[$typename]), + 'DEFAULT' => $row[$default], + 'NULLABLE' => (bool) !($row[$typename] - 256 >= 0), + 'LENGTH' => $row[$length], + 'SCALE' => ($row[$typename] == 5 ? $row[$length]&255 : 0), + 'PRECISION' => ($row[$typename] == 5 ? (int)($row[$length]/256) : 0), + 'UNSIGNED' => false, + 'PRIMARY' => $primary, + 'PRIMARY_POSITION' => $primaryPosition, + 'IDENTITY' => $identity + ); + } + + return $desc; + } + + /** + * Map number representation of a data type + * to a string + * + * @param int $typeNo + * @return string + */ + protected function _getDataType($typeNo) + { + $typemap = array( + 0 => "CHAR", + 1 => "SMALLINT", + 2 => "INTEGER", + 3 => "FLOAT", + 4 => "SMALLFLOAT", + 5 => "DECIMAL", + 6 => "SERIAL", + 7 => "DATE", + 8 => "MONEY", + 9 => "NULL", + 10 => "DATETIME", + 11 => "BYTE", + 12 => "TEXT", + 13 => "VARCHAR", + 14 => "INTERVAL", + 15 => "NCHAR", + 16 => "NVARCHAR", + 17 => "INT8", + 18 => "SERIAL8", + 19 => "SET", + 20 => "MULTISET", + 21 => "LIST", + 22 => "Unnamed ROW", + 40 => "Variable-length opaque type", + 4118 => "Named ROW" + ); + + if ($typeNo - 256 >= 0) { + $typeNo = $typeNo - 256; + } + + return $typemap[$typeNo]; + } + + /** + * Helper method to retrieve primary key column + * and column location + * + * @param int $tabid + * @return array + */ + protected function _getPrimaryInfo($tabid) + { + $sql = "SELECT i.part1, i.part2, i.part3, i.part4, i.part5, i.part6, + i.part7, i.part8, i.part9, i.part10, i.part11, i.part12, + i.part13, i.part14, i.part15, i.part16 + FROM sysindexes i + JOIN sysconstraints c ON c.idxname = i.idxname + WHERE i.tabid = " . $tabid . " AND c.constrtype = 'P'"; + + $stmt = $this->_adapter->query($sql); + $results = $stmt->fetchAll(); + + $cols = array(); + + // this should return only 1 row + // unless there is no primary key, + // in which case, the empty array is returned + if ($results) { + $row = $results[0]; + } else { + return $cols; + } + + $position = 0; + foreach ($row as $key => $colno) { + $position++; + if ($colno == 0) { + return $cols; + } else { + $cols[$colno] = $position; + } + } + } + + /** + * Adds an IDS-specific LIMIT clause to the SELECT statement. + * + * @param string $sql + * @param integer $count + * @param integer $offset OPTIONAL + * @throws Zend_Db_Adapter_Exception + * @return string + */ + public function limit($sql, $count, $offset = 0) + { + $count = intval($count); + if ($count < 0) { + /** @see Zend_Db_Adapter_Exception */ + throw new Zend_Db_Adapter_Exception("LIMIT argument count=$count is not valid"); + } else if ($count == 0) { + $limit_sql = str_ireplace("SELECT", "SELECT * FROM (SELECT", $sql); + $limit_sql .= ") WHERE 0 = 1"; + } else { + $offset = intval($offset); + if ($offset < 0) { + /** @see Zend_Db_Adapter_Exception */ + throw new Zend_Db_Adapter_Exception("LIMIT argument offset=$offset is not valid"); + } + if ($offset == 0) { + $limit_sql = str_ireplace("SELECT", "SELECT FIRST $count", $sql); + } else { + $limit_sql = str_ireplace("SELECT", "SELECT SKIP $offset LIMIT $count", $sql); + } + } + return $limit_sql; + } + + /** + * IDS-specific last sequence id + * + * @param string $sequenceName + * @return integer + */ + public function lastSequenceId($sequenceName) + { + $sql = 'SELECT '.$this->_adapter->quoteIdentifier($sequenceName).'.CURRVAL FROM ' + .'systables WHERE tabid = 1'; + $value = $this->_adapter->fetchOne($sql); + return $value; + } + + /** + * IDS-specific sequence id value + * + * @param string $sequenceName + * @return integer + */ + public function nextSequenceId($sequenceName) + { + $sql = 'SELECT '.$this->_adapter->quoteIdentifier($sequenceName).'.NEXTVAL FROM ' + .'systables WHERE tabid = 1'; + $value = $this->_adapter->fetchOne($sql); + return $value; + } +} diff --git a/library/vendor/Zend/Db/Adapter/Pdo/Mssql.php b/library/vendor/Zend/Db/Adapter/Pdo/Mssql.php new file mode 100644 index 0000000..7c7c1cd --- /dev/null +++ b/library/vendor/Zend/Db/Adapter/Pdo/Mssql.php @@ -0,0 +1,435 @@ + Zend_Db::INT_TYPE, + Zend_Db::BIGINT_TYPE => Zend_Db::BIGINT_TYPE, + Zend_Db::FLOAT_TYPE => Zend_Db::FLOAT_TYPE, + 'INT' => Zend_Db::INT_TYPE, + 'SMALLINT' => Zend_Db::INT_TYPE, + 'TINYINT' => Zend_Db::INT_TYPE, + 'BIGINT' => Zend_Db::BIGINT_TYPE, + 'DECIMAL' => Zend_Db::FLOAT_TYPE, + 'FLOAT' => Zend_Db::FLOAT_TYPE, + 'MONEY' => Zend_Db::FLOAT_TYPE, + 'NUMERIC' => Zend_Db::FLOAT_TYPE, + 'REAL' => Zend_Db::FLOAT_TYPE, + 'SMALLMONEY' => Zend_Db::FLOAT_TYPE + ); + + /** + * Creates a PDO DSN for the adapter from $this->_config settings. + * + * @return string + */ + protected function _dsn() + { + // baseline of DSN parts + $dsn = $this->_config; + + // don't pass the username and password in the DSN + unset($dsn['username']); + unset($dsn['password']); + unset($dsn['options']); + unset($dsn['persistent']); + unset($dsn['driver_options']); + + if (isset($dsn['port'])) { + $seperator = ':'; + if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') { + $seperator = ','; + } + $dsn['host'] .= $seperator . $dsn['port']; + unset($dsn['port']); + } + + // this driver supports multiple DSN prefixes + // @see http://www.php.net/manual/en/ref.pdo-dblib.connection.php + if (isset($dsn['pdoType'])) { + switch (strtolower($dsn['pdoType'])) { + case 'freetds': + case 'sybase': + $this->_pdoType = 'sybase'; + break; + case 'mssql': + $this->_pdoType = 'mssql'; + break; + case 'dblib': + default: + $this->_pdoType = 'dblib'; + break; + } + unset($dsn['pdoType']); + } + + // use all remaining parts in the DSN + foreach ($dsn as $key => $val) { + $dsn[$key] = "$key=$val"; + } + + $dsn = $this->_pdoType . ':' . implode(';', $dsn); + return $dsn; + } + + /** + * @return void + */ + protected function _connect() + { + if ($this->_connection) { + return; + } + parent::_connect(); + $this->_connection->exec('SET QUOTED_IDENTIFIER ON'); + } + + /** + * Begin a transaction. + * + * It is necessary to override the abstract PDO transaction functions here, as + * the PDO driver for MSSQL does not support transactions. + */ + protected function _beginTransaction() + { + $this->_connect(); + $this->_connection->exec('BEGIN TRANSACTION'); + return true; + } + + /** + * Commit a transaction. + * + * It is necessary to override the abstract PDO transaction functions here, as + * the PDO driver for MSSQL does not support transactions. + */ + protected function _commit() + { + $this->_connect(); + $this->_connection->exec('COMMIT TRANSACTION'); + return true; + } + + /** + * Roll-back a transaction. + * + * It is necessary to override the abstract PDO transaction functions here, as + * the PDO driver for MSSQL does not support transactions. + */ + protected function _rollBack() { + $this->_connect(); + $this->_connection->exec('ROLLBACK TRANSACTION'); + return true; + } + + /** + * Returns a list of the tables in the database. + * + * @return array + */ + public function listTables() + { + $sql = "SELECT name FROM sysobjects WHERE type = 'U' ORDER BY name"; + return $this->fetchCol($sql); + } + + /** + * Returns the column descriptions for a table. + * + * The return value is an associative array keyed by the column name, + * as returned by the RDBMS. + * + * The value of each array element is an associative array + * with the following keys: + * + * SCHEMA_NAME => string; name of database or schema + * TABLE_NAME => string; + * COLUMN_NAME => string; column name + * COLUMN_POSITION => number; ordinal position of column in table + * DATA_TYPE => string; SQL datatype name of column + * DEFAULT => string; default expression of column, null if none + * NULLABLE => boolean; true if column can have nulls + * LENGTH => number; length of CHAR/VARCHAR + * SCALE => number; scale of NUMERIC/DECIMAL + * PRECISION => number; precision of NUMERIC/DECIMAL + * UNSIGNED => boolean; unsigned property of an integer type + * PRIMARY => boolean; true if column is part of the primary key + * PRIMARY_POSITION => integer; position of column in primary key + * PRIMARY_AUTO => integer; position of auto-generated column in primary key + * + * @todo Discover column primary key position. + * @todo Discover integer unsigned property. + * + * @param string $tableName + * @param string $schemaName OPTIONAL + * @return array + */ + public function describeTable($tableName, $schemaName = null) + { + if ($schemaName != null) { + if (strpos($schemaName, '.') !== false) { + $result = explode('.', $schemaName); + $schemaName = $result[1]; + } + } + /** + * Discover metadata information about this table. + */ + $sql = "exec sp_columns @table_name = " . $this->quoteIdentifier($tableName, true); + if ($schemaName != null) { + $sql .= ", @table_owner = " . $this->quoteIdentifier($schemaName, true); + } + + $stmt = $this->query($sql); + $result = $stmt->fetchAll(Zend_Db::FETCH_NUM); + + $table_name = 2; + $column_name = 3; + $type_name = 5; + $precision = 6; + $length = 7; + $scale = 8; + $nullable = 10; + $column_def = 12; + $column_position = 16; + + /** + * Discover primary key column(s) for this table. + */ + $sql = "exec sp_pkeys @table_name = " . $this->quoteIdentifier($tableName, true); + if ($schemaName != null) { + $sql .= ", @table_owner = " . $this->quoteIdentifier($schemaName, true); + } + + $stmt = $this->query($sql); + $primaryKeysResult = $stmt->fetchAll(Zend_Db::FETCH_NUM); + $primaryKeyColumn = array(); + $pkey_column_name = 3; + $pkey_key_seq = 4; + foreach ($primaryKeysResult as $pkeysRow) { + $primaryKeyColumn[$pkeysRow[$pkey_column_name]] = $pkeysRow[$pkey_key_seq]; + } + + $desc = array(); + $p = 1; + foreach ($result as $key => $row) { + $identity = false; + $words = explode(' ', $row[$type_name], 2); + if (isset($words[0])) { + $type = $words[0]; + if (isset($words[1])) { + $identity = (bool) preg_match('/identity/', $words[1]); + } + } + + $isPrimary = array_key_exists($row[$column_name], $primaryKeyColumn); + if ($isPrimary) { + $primaryPosition = $primaryKeyColumn[$row[$column_name]]; + } else { + $primaryPosition = null; + } + + $desc[$this->foldCase($row[$column_name])] = array( + 'SCHEMA_NAME' => null, // @todo + 'TABLE_NAME' => $this->foldCase($row[$table_name]), + 'COLUMN_NAME' => $this->foldCase($row[$column_name]), + 'COLUMN_POSITION' => (int) $row[$column_position], + 'DATA_TYPE' => $type, + 'DEFAULT' => $row[$column_def], + 'NULLABLE' => (bool) $row[$nullable], + 'LENGTH' => $row[$length], + 'SCALE' => $row[$scale], + 'PRECISION' => $row[$precision], + 'UNSIGNED' => null, // @todo + 'PRIMARY' => $isPrimary, + 'PRIMARY_POSITION' => $primaryPosition, + 'IDENTITY' => $identity + ); + } + return $desc; + } + + /** + * Adds an adapter-specific LIMIT clause to the SELECT statement. + * + * @link http://lists.bestpractical.com/pipermail/rt-devel/2005-June/007339.html + * + * @param string $sql + * @param integer $count + * @param integer $offset OPTIONAL + * @throws Zend_Db_Adapter_Exception + * @return string + */ + public function limit($sql, $count, $offset = 0) + { + $count = intval($count); + if ($count <= 0) { + /** @see Zend_Db_Adapter_Exception */ + throw new Zend_Db_Adapter_Exception("LIMIT argument count=$count is not valid"); + } + + $offset = intval($offset); + if ($offset < 0) { + /** @see Zend_Db_Adapter_Exception */ + throw new Zend_Db_Adapter_Exception("LIMIT argument offset=$offset is not valid"); + } + + $sql = preg_replace( + '/^SELECT\s+(DISTINCT\s)?/i', + 'SELECT $1TOP ' . ($count+$offset) . ' ', + $sql + ); + + if ($offset > 0) { + $orderby = stristr($sql, 'ORDER BY'); + + if ($orderby !== false) { + $orderParts = explode(',', substr($orderby, 8)); + $pregReplaceCount = null; + $orderbyInverseParts = array(); + foreach ($orderParts as $orderPart) { + $orderPart = rtrim($orderPart); + $inv = preg_replace('/\s+desc$/i', ' ASC', $orderPart, 1, $pregReplaceCount); + if ($pregReplaceCount) { + $orderbyInverseParts[] = $inv; + continue; + } + $inv = preg_replace('/\s+asc$/i', ' DESC', $orderPart, 1, $pregReplaceCount); + if ($pregReplaceCount) { + $orderbyInverseParts[] = $inv; + continue; + } else { + $orderbyInverseParts[] = $orderPart . ' DESC'; + } + } + + $orderbyInverse = 'ORDER BY ' . implode(', ', $orderbyInverseParts); + } + + + + + $sql = 'SELECT * FROM (SELECT TOP ' . $count . ' * FROM (' . $sql . ') AS inner_tbl'; + if ($orderby !== false) { + $sql .= ' ' . $orderbyInverse . ' '; + } + $sql .= ') AS outer_tbl'; + if ($orderby !== false) { + $sql .= ' ' . $orderby; + } + } + + return $sql; + } + + /** + * Gets the last ID generated automatically by an IDENTITY/AUTOINCREMENT column. + * + * As a convention, on RDBMS brands that support sequences + * (e.g. Oracle, PostgreSQL, DB2), this method forms the name of a sequence + * from the arguments and returns the last id generated by that sequence. + * On RDBMS brands that support IDENTITY/AUTOINCREMENT columns, this method + * returns the last value generated for such a column, and the table name + * argument is disregarded. + * + * Microsoft SQL Server does not support sequences, so the arguments to + * this method are ignored. + * + * @param string $tableName OPTIONAL Name of table. + * @param string $primaryKey OPTIONAL Name of primary key column. + * @return string + * @throws Zend_Db_Adapter_Exception + */ + public function lastInsertId($tableName = null, $primaryKey = null) + { + $sql = 'SELECT SCOPE_IDENTITY()'; + return (int)$this->fetchOne($sql); + } + + /** + * Retrieve server version in PHP style + * Pdo_Mssql doesn't support getAttribute(PDO::ATTR_SERVER_VERSION) + * @return string + */ + public function getServerVersion() + { + try { + $stmt = $this->query("SELECT CAST(SERVERPROPERTY('productversion') AS VARCHAR)"); + $result = $stmt->fetchAll(Zend_Db::FETCH_NUM); + if (count($result)) { + return $result[0][0]; + } + return null; + } catch (PDOException $e) { + return null; + } + } + + /** + * Quote a raw string. + * + * @param string $value Raw string + * @return string Quoted string + */ + protected function _quote($value) + { + if (!is_int($value) && !is_float($value)) { + // Fix for null-byte injection + $value = addcslashes($value, "\000\032"); + } + return parent::_quote($value); + } +} diff --git a/library/vendor/Zend/Db/Adapter/Pdo/Mysql.php b/library/vendor/Zend/Db/Adapter/Pdo/Mysql.php new file mode 100644 index 0000000..951d665 --- /dev/null +++ b/library/vendor/Zend/Db/Adapter/Pdo/Mysql.php @@ -0,0 +1,269 @@ + Zend_Db::INT_TYPE, + Zend_Db::BIGINT_TYPE => Zend_Db::BIGINT_TYPE, + Zend_Db::FLOAT_TYPE => Zend_Db::FLOAT_TYPE, + 'INT' => Zend_Db::INT_TYPE, + 'INTEGER' => Zend_Db::INT_TYPE, + 'MEDIUMINT' => Zend_Db::INT_TYPE, + 'SMALLINT' => Zend_Db::INT_TYPE, + 'TINYINT' => Zend_Db::INT_TYPE, + 'BIGINT' => Zend_Db::BIGINT_TYPE, + 'SERIAL' => Zend_Db::BIGINT_TYPE, + 'DEC' => Zend_Db::FLOAT_TYPE, + 'DECIMAL' => Zend_Db::FLOAT_TYPE, + 'DOUBLE' => Zend_Db::FLOAT_TYPE, + 'DOUBLE PRECISION' => Zend_Db::FLOAT_TYPE, + 'FIXED' => Zend_Db::FLOAT_TYPE, + 'FLOAT' => Zend_Db::FLOAT_TYPE + ); + + /** + * Override _dsn() and ensure that charset is incorporated in mysql + * @see Zend_Db_Adapter_Pdo_Abstract::_dsn() + */ + protected function _dsn() + { + $dsn = parent::_dsn(); + if (isset($this->_config['charset'])) { + $dsn .= ';charset=' . $this->_config['charset']; + } + return $dsn; + } + + /** + * Creates a PDO object and connects to the database. + * + * @return void + * @throws Zend_Db_Adapter_Exception + */ + protected function _connect() + { + if ($this->_connection) { + return; + } + + if (!empty($this->_config['charset']) + && version_compare(PHP_VERSION, '5.3.6', '<') + ) { + $initCommand = "SET NAMES '" . $this->_config['charset'] . "'"; + $this->_config['driver_options'][1002] = $initCommand; // 1002 = PDO::MYSQL_ATTR_INIT_COMMAND + } + + parent::_connect(); + } + + /** + * @return string + */ + public function getQuoteIdentifierSymbol() + { + return "`"; + } + + /** + * Returns a list of the tables in the database. + * + * @return array + */ + public function listTables() + { + return $this->fetchCol('SHOW TABLES'); + } + + /** + * Returns the column descriptions for a table. + * + * The return value is an associative array keyed by the column name, + * as returned by the RDBMS. + * + * The value of each array element is an associative array + * with the following keys: + * + * SCHEMA_NAME => string; name of database or schema + * TABLE_NAME => string; + * COLUMN_NAME => string; column name + * COLUMN_POSITION => number; ordinal position of column in table + * DATA_TYPE => string; SQL datatype name of column + * DEFAULT => string; default expression of column, null if none + * NULLABLE => boolean; true if column can have nulls + * LENGTH => number; length of CHAR/VARCHAR + * SCALE => number; scale of NUMERIC/DECIMAL + * PRECISION => number; precision of NUMERIC/DECIMAL + * UNSIGNED => boolean; unsigned property of an integer type + * PRIMARY => boolean; true if column is part of the primary key + * PRIMARY_POSITION => integer; position of column in primary key + * IDENTITY => integer; true if column is auto-generated with unique values + * + * @param string $tableName + * @param string $schemaName OPTIONAL + * @return array + */ + public function describeTable($tableName, $schemaName = null) + { + // @todo use INFORMATION_SCHEMA someday when MySQL's + // implementation has reasonably good performance and + // the version with this improvement is in wide use. + + if ($schemaName) { + $sql = 'DESCRIBE ' . $this->quoteIdentifier("$schemaName.$tableName", true); + } else { + $sql = 'DESCRIBE ' . $this->quoteIdentifier($tableName, true); + } + $stmt = $this->query($sql); + + // Use FETCH_NUM so we are not dependent on the CASE attribute of the PDO connection + $result = $stmt->fetchAll(Zend_Db::FETCH_NUM); + + $field = 0; + $type = 1; + $null = 2; + $key = 3; + $default = 4; + $extra = 5; + + $desc = array(); + $i = 1; + $p = 1; + foreach ($result as $row) { + list($length, $scale, $precision, $unsigned, $primary, $primaryPosition, $identity) + = array(null, null, null, null, false, null, false); + if (preg_match('/unsigned/', $row[$type])) { + $unsigned = true; + } + if (preg_match('/^((?:var)?char)\((\d+)\)/', $row[$type], $matches)) { + $row[$type] = $matches[1]; + $length = $matches[2]; + } else if (preg_match('/^decimal\((\d+),(\d+)\)/', $row[$type], $matches)) { + $row[$type] = 'decimal'; + $precision = $matches[1]; + $scale = $matches[2]; + } else if (preg_match('/^float\((\d+),(\d+)\)/', $row[$type], $matches)) { + $row[$type] = 'float'; + $precision = $matches[1]; + $scale = $matches[2]; + } else if (preg_match('/^((?:big|medium|small|tiny)?int)\((\d+)\)/', $row[$type], $matches)) { + $row[$type] = $matches[1]; + // The optional argument of a MySQL int type is not precision + // or length; it is only a hint for display width. + } + if (strtoupper($row[$key]) == 'PRI') { + $primary = true; + $primaryPosition = $p; + if ($row[$extra] == 'auto_increment') { + $identity = true; + } else { + $identity = false; + } + ++$p; + } + $desc[$this->foldCase($row[$field])] = array( + 'SCHEMA_NAME' => null, // @todo + 'TABLE_NAME' => $this->foldCase($tableName), + 'COLUMN_NAME' => $this->foldCase($row[$field]), + 'COLUMN_POSITION' => $i, + 'DATA_TYPE' => $row[$type], + 'DEFAULT' => $row[$default], + 'NULLABLE' => (bool) ($row[$null] == 'YES'), + 'LENGTH' => $length, + 'SCALE' => $scale, + 'PRECISION' => $precision, + 'UNSIGNED' => $unsigned, + 'PRIMARY' => $primary, + 'PRIMARY_POSITION' => $primaryPosition, + 'IDENTITY' => $identity + ); + ++$i; + } + return $desc; + } + + /** + * Adds an adapter-specific LIMIT clause to the SELECT statement. + * + * @param string $sql + * @param integer $count + * @param integer $offset OPTIONAL + * @throws Zend_Db_Adapter_Exception + * @return string + */ + public function limit($sql, $count, $offset = 0) + { + $count = intval($count); + if ($count <= 0) { + /** @see Zend_Db_Adapter_Exception */ + throw new Zend_Db_Adapter_Exception("LIMIT argument count=$count is not valid"); + } + + $offset = intval($offset); + if ($offset < 0) { + /** @see Zend_Db_Adapter_Exception */ + throw new Zend_Db_Adapter_Exception("LIMIT argument offset=$offset is not valid"); + } + + $sql .= " LIMIT $count"; + if ($offset > 0) { + $sql .= " OFFSET $offset"; + } + + return $sql; + } + +} diff --git a/library/vendor/Zend/Db/Adapter/Pdo/Oci.php b/library/vendor/Zend/Db/Adapter/Pdo/Oci.php new file mode 100644 index 0000000..eb4e6fc --- /dev/null +++ b/library/vendor/Zend/Db/Adapter/Pdo/Oci.php @@ -0,0 +1,375 @@ + Zend_Db::INT_TYPE, + Zend_Db::BIGINT_TYPE => Zend_Db::BIGINT_TYPE, + Zend_Db::FLOAT_TYPE => Zend_Db::FLOAT_TYPE, + 'BINARY_DOUBLE' => Zend_Db::FLOAT_TYPE, + 'BINARY_FLOAT' => Zend_Db::FLOAT_TYPE, + 'NUMBER' => Zend_Db::FLOAT_TYPE + ); + + /** + * Creates a PDO DSN for the adapter from $this->_config settings. + * + * @return string + */ + protected function _dsn() + { + // baseline of DSN parts + $dsn = $this->_config; + + if (isset($dsn['host'])) { + $tns = 'dbname=(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)' . + '(HOST=' . $dsn['host'] . ')'; + + if (isset($dsn['port'])) { + $tns .= '(PORT=' . $dsn['port'] . ')'; + } else { + $tns .= '(PORT=1521)'; + } + + $tns .= '))(CONNECT_DATA=(SID=' . $dsn['dbname'] . ')))'; + } else { + $tns = 'dbname=' . $dsn['dbname']; + } + + if (isset($dsn['charset'])) { + $tns .= ';charset=' . $dsn['charset']; + } + + return $this->_pdoType . ':' . $tns; + } + + /** + * Quote a raw string. + * Most PDO drivers have an implementation for the quote() method, + * but the Oracle OCI driver must use the same implementation as the + * Zend_Db_Adapter_Abstract class. + * + * @param string $value Raw string + * @return string Quoted string + */ + protected function _quote($value) + { + if (is_int($value) || is_float($value)) { + return $value; + } + $value = str_replace("'", "''", $value); + return "'" . addcslashes($value, "\000\n\r\\\032") . "'"; + } + + /** + * Quote a table identifier and alias. + * + * @param string|array|Zend_Db_Expr $ident The identifier or expression. + * @param string $alias An alias for the table. + * @return string The quoted identifier and alias. + */ + public function quoteTableAs($ident, $alias = null, $auto = false) + { + // Oracle doesn't allow the 'AS' keyword between the table identifier/expression and alias. + return $this->_quoteIdentifierAs($ident, $alias, $auto, ' '); + } + + /** + * Returns a list of the tables in the database. + * + * @return array + */ + public function listTables() + { + $data = $this->fetchCol('SELECT table_name FROM all_tables'); + return $data; + } + + /** + * Returns the column descriptions for a table. + * + * The return value is an associative array keyed by the column name, + * as returned by the RDBMS. + * + * The value of each array element is an associative array + * with the following keys: + * + * SCHEMA_NAME => string; name of schema + * TABLE_NAME => string; + * COLUMN_NAME => string; column name + * COLUMN_POSITION => number; ordinal position of column in table + * DATA_TYPE => string; SQL datatype name of column + * DEFAULT => string; default expression of column, null if none + * NULLABLE => boolean; true if column can have nulls + * LENGTH => number; length of CHAR/VARCHAR + * SCALE => number; scale of NUMERIC/DECIMAL + * PRECISION => number; precision of NUMERIC/DECIMAL + * UNSIGNED => boolean; unsigned property of an integer type + * PRIMARY => boolean; true if column is part of the primary key + * PRIMARY_POSITION => integer; position of column in primary key + * IDENTITY => integer; true if column is auto-generated with unique values + * + * @todo Discover integer unsigned property. + * + * @param string $tableName + * @param string $schemaName OPTIONAL + * @return array + */ + public function describeTable($tableName, $schemaName = null) + { + $version = $this->getServerVersion(); + if (($version === null) || version_compare($version, '9.0.0', '>=')) { + $sql = "SELECT TC.TABLE_NAME, TC.OWNER, TC.COLUMN_NAME, TC.DATA_TYPE, + TC.DATA_DEFAULT, TC.NULLABLE, TC.COLUMN_ID, TC.DATA_LENGTH, + TC.DATA_SCALE, TC.DATA_PRECISION, C.CONSTRAINT_TYPE, CC.POSITION + FROM ALL_TAB_COLUMNS TC + LEFT JOIN (ALL_CONS_COLUMNS CC JOIN ALL_CONSTRAINTS C + ON (CC.CONSTRAINT_NAME = C.CONSTRAINT_NAME AND CC.TABLE_NAME = C.TABLE_NAME AND CC.OWNER = C.OWNER AND C.CONSTRAINT_TYPE = 'P')) + ON TC.TABLE_NAME = CC.TABLE_NAME AND TC.COLUMN_NAME = CC.COLUMN_NAME + WHERE UPPER(TC.TABLE_NAME) = UPPER(:TBNAME)"; + $bind[':TBNAME'] = $tableName; + if ($schemaName) { + $sql .= ' AND UPPER(TC.OWNER) = UPPER(:SCNAME)'; + $bind[':SCNAME'] = $schemaName; + } + $sql .= ' ORDER BY TC.COLUMN_ID'; + } else { + $subSql="SELECT AC.OWNER, AC.TABLE_NAME, ACC.COLUMN_NAME, AC.CONSTRAINT_TYPE, ACC.POSITION + from ALL_CONSTRAINTS AC, ALL_CONS_COLUMNS ACC + WHERE ACC.CONSTRAINT_NAME = AC.CONSTRAINT_NAME + AND ACC.TABLE_NAME = AC.TABLE_NAME + AND ACC.OWNER = AC.OWNER + AND AC.CONSTRAINT_TYPE = 'P' + AND UPPER(AC.TABLE_NAME) = UPPER(:TBNAME)"; + $bind[':TBNAME'] = $tableName; + if ($schemaName) { + $subSql .= ' AND UPPER(ACC.OWNER) = UPPER(:SCNAME)'; + $bind[':SCNAME'] = $schemaName; + } + $sql="SELECT TC.TABLE_NAME, TC.OWNER, TC.COLUMN_NAME, TC.DATA_TYPE, + TC.DATA_DEFAULT, TC.NULLABLE, TC.COLUMN_ID, TC.DATA_LENGTH, + TC.DATA_SCALE, TC.DATA_PRECISION, CC.CONSTRAINT_TYPE, CC.POSITION + FROM ALL_TAB_COLUMNS TC, ($subSql) CC + WHERE UPPER(TC.TABLE_NAME) = UPPER(:TBNAME) + AND TC.OWNER = CC.OWNER(+) AND TC.TABLE_NAME = CC.TABLE_NAME(+) AND TC.COLUMN_NAME = CC.COLUMN_NAME(+)"; + if ($schemaName) { + $sql .= ' AND UPPER(TC.OWNER) = UPPER(:SCNAME)'; + } + $sql .= ' ORDER BY TC.COLUMN_ID'; + } + + $stmt = $this->query($sql, $bind); + + /** + * Use FETCH_NUM so we are not dependent on the CASE attribute of the PDO connection + */ + $result = $stmt->fetchAll(Zend_Db::FETCH_NUM); + + $table_name = 0; + $owner = 1; + $column_name = 2; + $data_type = 3; + $data_default = 4; + $nullable = 5; + $column_id = 6; + $data_length = 7; + $data_scale = 8; + $data_precision = 9; + $constraint_type = 10; + $position = 11; + + $desc = array(); + foreach ($result as $key => $row) { + list ($primary, $primaryPosition, $identity) = array(false, null, false); + if ($row[$constraint_type] == 'P') { + $primary = true; + $primaryPosition = $row[$position]; + /** + * Oracle does not support auto-increment keys. + */ + $identity = false; + } + $desc[$this->foldCase($row[$column_name])] = array( + 'SCHEMA_NAME' => $this->foldCase($row[$owner]), + 'TABLE_NAME' => $this->foldCase($row[$table_name]), + 'COLUMN_NAME' => $this->foldCase($row[$column_name]), + 'COLUMN_POSITION' => $row[$column_id], + 'DATA_TYPE' => $row[$data_type], + 'DEFAULT' => $row[$data_default], + 'NULLABLE' => (bool) ($row[$nullable] == 'Y'), + 'LENGTH' => $row[$data_length], + 'SCALE' => $row[$data_scale], + 'PRECISION' => $row[$data_precision], + 'UNSIGNED' => null, // @todo + 'PRIMARY' => $primary, + 'PRIMARY_POSITION' => $primaryPosition, + 'IDENTITY' => $identity + ); + } + return $desc; + } + + /** + * Return the most recent value from the specified sequence in the database. + * This is supported only on RDBMS brands that support sequences + * (e.g. Oracle, PostgreSQL, DB2). Other RDBMS brands return null. + * + * @param string $sequenceName + * @return integer + */ + public function lastSequenceId($sequenceName) + { + $this->_connect(); + $value = $this->fetchOne('SELECT '.$this->quoteIdentifier($sequenceName, true).'.CURRVAL FROM dual'); + return $value; + } + + /** + * Generate a new value from the specified sequence in the database, and return it. + * This is supported only on RDBMS brands that support sequences + * (e.g. Oracle, PostgreSQL, DB2). Other RDBMS brands return null. + * + * @param string $sequenceName + * @return integer + */ + public function nextSequenceId($sequenceName) + { + $this->_connect(); + $value = $this->fetchOne('SELECT '.$this->quoteIdentifier($sequenceName, true).'.NEXTVAL FROM dual'); + return $value; + } + + /** + * Gets the last ID generated automatically by an IDENTITY/AUTOINCREMENT column. + * + * As a convention, on RDBMS brands that support sequences + * (e.g. Oracle, PostgreSQL, DB2), this method forms the name of a sequence + * from the arguments and returns the last id generated by that sequence. + * On RDBMS brands that support IDENTITY/AUTOINCREMENT columns, this method + * returns the last value generated for such a column, and the table name + * argument is disregarded. + * + * Oracle does not support IDENTITY columns, so if the sequence is not + * specified, this method returns null. + * + * @param string $tableName OPTIONAL Name of table. + * @param string $primaryKey OPTIONAL Name of primary key column. + * @return string + * @throws Zend_Db_Adapter_Oracle_Exception + */ + public function lastInsertId($tableName = null, $primaryKey = null) + { + if ($tableName !== null) { + $sequenceName = $tableName; + if ($primaryKey) { + $sequenceName .= $this->foldCase("_$primaryKey"); + } + $sequenceName .= $this->foldCase('_seq'); + return $this->lastSequenceId($sequenceName); + } + // No support for IDENTITY columns; return null + return null; + } + + /** + * Adds an adapter-specific LIMIT clause to the SELECT statement. + * + * @param string $sql + * @param integer $count + * @param integer $offset + * @throws Zend_Db_Adapter_Exception + * @return string + */ + public function limit($sql, $count, $offset = 0) + { + $count = intval($count); + if ($count <= 0) { + /** @see Zend_Db_Adapter_Exception */ + throw new Zend_Db_Adapter_Exception("LIMIT argument count=$count is not valid"); + } + + $offset = intval($offset); + if ($offset < 0) { + /** @see Zend_Db_Adapter_Exception */ + throw new Zend_Db_Adapter_Exception("LIMIT argument offset=$offset is not valid"); + } + + /** + * Oracle does not implement the LIMIT clause as some RDBMS do. + * We have to simulate it with subqueries and ROWNUM. + * Unfortunately because we use the column wildcard "*", + * this puts an extra column into the query result set. + */ + $limit_sql = "SELECT z2.* + FROM ( + SELECT z1.*, ROWNUM AS \"zend_db_rownum\" + FROM ( + " . $sql . " + ) z1 + ) z2 + WHERE z2.\"zend_db_rownum\" BETWEEN " . ($offset+1) . " AND " . ($offset+$count); + return $limit_sql; + } + +} diff --git a/library/vendor/Zend/Db/Adapter/Pdo/Pgsql.php b/library/vendor/Zend/Db/Adapter/Pdo/Pgsql.php new file mode 100644 index 0000000..060ed28 --- /dev/null +++ b/library/vendor/Zend/Db/Adapter/Pdo/Pgsql.php @@ -0,0 +1,333 @@ + Zend_Db::INT_TYPE, + Zend_Db::BIGINT_TYPE => Zend_Db::BIGINT_TYPE, + Zend_Db::FLOAT_TYPE => Zend_Db::FLOAT_TYPE, + 'INTEGER' => Zend_Db::INT_TYPE, + 'SERIAL' => Zend_Db::INT_TYPE, + 'SMALLINT' => Zend_Db::INT_TYPE, + 'BIGINT' => Zend_Db::BIGINT_TYPE, + 'BIGSERIAL' => Zend_Db::BIGINT_TYPE, + 'DECIMAL' => Zend_Db::FLOAT_TYPE, + 'DOUBLE PRECISION' => Zend_Db::FLOAT_TYPE, + 'NUMERIC' => Zend_Db::FLOAT_TYPE, + 'REAL' => Zend_Db::FLOAT_TYPE + ); + + /** + * Creates a PDO object and connects to the database. + * + * @return void + * @throws Zend_Db_Adapter_Exception + */ + protected function _connect() + { + if ($this->_connection) { + return; + } + + parent::_connect(); + + if (!empty($this->_config['charset'])) { + $sql = "SET NAMES '" . $this->_config['charset'] . "'"; + $this->_connection->exec($sql); + } + } + + /** + * Returns a list of the tables in the database. + * + * @return array + */ + public function listTables() + { + // @todo use a better query with joins instead of subqueries + $sql = "SELECT c.relname AS table_name " + . "FROM pg_class c, pg_user u " + . "WHERE c.relowner = u.usesysid AND c.relkind = 'r' " + . "AND NOT EXISTS (SELECT 1 FROM pg_views WHERE viewname = c.relname) " + . "AND c.relname !~ '^(pg_|sql_)' " + . "UNION " + . "SELECT c.relname AS table_name " + . "FROM pg_class c " + . "WHERE c.relkind = 'r' " + . "AND NOT EXISTS (SELECT 1 FROM pg_views WHERE viewname = c.relname) " + . "AND NOT EXISTS (SELECT 1 FROM pg_user WHERE usesysid = c.relowner) " + . "AND c.relname !~ '^pg_'"; + + return $this->fetchCol($sql); + } + + /** + * Returns the column descriptions for a table. + * + * The return value is an associative array keyed by the column name, + * as returned by the RDBMS. + * + * The value of each array element is an associative array + * with the following keys: + * + * SCHEMA_NAME => string; name of database or schema + * TABLE_NAME => string; + * COLUMN_NAME => string; column name + * COLUMN_POSITION => number; ordinal position of column in table + * DATA_TYPE => string; SQL datatype name of column + * DEFAULT => string; default expression of column, null if none + * NULLABLE => boolean; true if column can have nulls + * LENGTH => number; length of CHAR/VARCHAR + * SCALE => number; scale of NUMERIC/DECIMAL + * PRECISION => number; precision of NUMERIC/DECIMAL + * UNSIGNED => boolean; unsigned property of an integer type + * PRIMARY => boolean; true if column is part of the primary key + * PRIMARY_POSITION => integer; position of column in primary key + * IDENTITY => integer; true if column is auto-generated with unique values + * + * @todo Discover integer unsigned property. + * + * @param string $tableName + * @param string $schemaName OPTIONAL + * @return array + */ + public function describeTable($tableName, $schemaName = null) + { + $sql = "SELECT + a.attnum, + n.nspname, + c.relname, + a.attname AS colname, + t.typname AS type, + a.atttypmod, + FORMAT_TYPE(a.atttypid, a.atttypmod) AS complete_type, + d.adsrc AS default_value, + a.attnotnull AS notnull, + a.attlen AS length, + co.contype, + ARRAY_TO_STRING(co.conkey, ',') AS conkey + FROM pg_attribute AS a + JOIN pg_class AS c ON a.attrelid = c.oid + JOIN pg_namespace AS n ON c.relnamespace = n.oid + JOIN pg_type AS t ON a.atttypid = t.oid + LEFT OUTER JOIN pg_constraint AS co ON (co.conrelid = c.oid + AND a.attnum = ANY(co.conkey) AND co.contype = 'p') + LEFT OUTER JOIN pg_attrdef AS d ON d.adrelid = c.oid AND d.adnum = a.attnum + WHERE a.attnum > 0 AND c.relname = ".$this->quote($tableName); + if ($schemaName) { + $sql .= " AND n.nspname = ".$this->quote($schemaName); + } + $sql .= ' ORDER BY a.attnum'; + + $stmt = $this->query($sql); + + // Use FETCH_NUM so we are not dependent on the CASE attribute of the PDO connection + $result = $stmt->fetchAll(Zend_Db::FETCH_NUM); + + $attnum = 0; + $nspname = 1; + $relname = 2; + $colname = 3; + $type = 4; + $atttypemod = 5; + $complete_type = 6; + $default_value = 7; + $notnull = 8; + $length = 9; + $contype = 10; + $conkey = 11; + + $desc = array(); + foreach ($result as $key => $row) { + $defaultValue = $row[$default_value]; + if ($row[$type] == 'varchar' || $row[$type] == 'bpchar' ) { + if (preg_match('/character(?: varying)?(?:\((\d+)\))?/', $row[$complete_type], $matches)) { + if (isset($matches[1])) { + $row[$length] = $matches[1]; + } else { + $row[$length] = null; // unlimited + } + } + if (preg_match("/^'(.*?)'::(?:character varying|bpchar)$/", $defaultValue, $matches)) { + $defaultValue = $matches[1]; + } + } + list($primary, $primaryPosition, $identity) = array(false, null, false); + if ($row[$contype] == 'p') { + $primary = true; + $primaryPosition = array_search($row[$attnum], explode(',', $row[$conkey])) + 1; + $identity = (bool) (preg_match('/^nextval/', $row[$default_value])); + } + $desc[$this->foldCase($row[$colname])] = array( + 'SCHEMA_NAME' => $this->foldCase($row[$nspname]), + 'TABLE_NAME' => $this->foldCase($row[$relname]), + 'COLUMN_NAME' => $this->foldCase($row[$colname]), + 'COLUMN_POSITION' => $row[$attnum], + 'DATA_TYPE' => $row[$type], + 'DEFAULT' => $defaultValue, + 'NULLABLE' => (bool) ($row[$notnull] != 't'), + 'LENGTH' => $row[$length], + 'SCALE' => null, // @todo + 'PRECISION' => null, // @todo + 'UNSIGNED' => null, // @todo + 'PRIMARY' => $primary, + 'PRIMARY_POSITION' => $primaryPosition, + 'IDENTITY' => $identity + ); + } + return $desc; + } + + + /** + * Adds an adapter-specific LIMIT clause to the SELECT statement. + * + * @param string $sql + * @param integer $count + * @param integer $offset OPTIONAL + * @return string + */ + public function limit($sql, $count, $offset = 0) + { + $count = intval($count); + if ($count <= 0) { + /** + * @see Zend_Db_Adapter_Exception + */ + throw new Zend_Db_Adapter_Exception("LIMIT argument count=$count is not valid"); + } + + $offset = intval($offset); + if ($offset < 0) { + /** + * @see Zend_Db_Adapter_Exception + */ + throw new Zend_Db_Adapter_Exception("LIMIT argument offset=$offset is not valid"); + } + + $sql .= " LIMIT $count"; + if ($offset > 0) { + $sql .= " OFFSET $offset"; + } + + return $sql; + } + + /** + * Return the most recent value from the specified sequence in the database. + * This is supported only on RDBMS brands that support sequences + * (e.g. Oracle, PostgreSQL, DB2). Other RDBMS brands return null. + * + * @param string $sequenceName + * @return string + */ + public function lastSequenceId($sequenceName) + { + $this->_connect(); + $sequenceName = str_replace($this->getQuoteIdentifierSymbol(), '', (string) $sequenceName); + $value = $this->fetchOne("SELECT CURRVAL(" + . $this->quote($this->quoteIdentifier($sequenceName, true)) + . ")"); + return $value; + } + + /** + * Generate a new value from the specified sequence in the database, and return it. + * This is supported only on RDBMS brands that support sequences + * (e.g. Oracle, PostgreSQL, DB2). Other RDBMS brands return null. + * + * @param string $sequenceName + * @return string + */ + public function nextSequenceId($sequenceName) + { + $this->_connect(); + $sequenceName = str_replace($this->getQuoteIdentifierSymbol(), '', (string) $sequenceName); + $value = $this->fetchOne("SELECT NEXTVAL(" + . $this->quote($this->quoteIdentifier($sequenceName, true)) + . ")"); + return $value; + } + + /** + * Gets the last ID generated automatically by an IDENTITY/AUTOINCREMENT column. + * + * As a convention, on RDBMS brands that support sequences + * (e.g. Oracle, PostgreSQL, DB2), this method forms the name of a sequence + * from the arguments and returns the last id generated by that sequence. + * On RDBMS brands that support IDENTITY/AUTOINCREMENT columns, this method + * returns the last value generated for such a column, and the table name + * argument is disregarded. + * + * @param string $tableName OPTIONAL Name of table. + * @param string $primaryKey OPTIONAL Name of primary key column. + * @return string + */ + public function lastInsertId($tableName = null, $primaryKey = null) + { + if ($tableName !== null) { + $sequenceName = $tableName; + if ($primaryKey) { + $sequenceName .= "_$primaryKey"; + } + $sequenceName .= '_seq'; + return $this->lastSequenceId($sequenceName); + } + return $this->_connection->lastInsertId($tableName); + } + +} diff --git a/library/vendor/Zend/Db/Adapter/Pdo/Sqlite.php b/library/vendor/Zend/Db/Adapter/Pdo/Sqlite.php new file mode 100644 index 0000000..6453339 --- /dev/null +++ b/library/vendor/Zend/Db/Adapter/Pdo/Sqlite.php @@ -0,0 +1,305 @@ + Zend_Db::INT_TYPE, + Zend_Db::BIGINT_TYPE => Zend_Db::BIGINT_TYPE, + Zend_Db::FLOAT_TYPE => Zend_Db::FLOAT_TYPE, + 'INTEGER' => Zend_Db::BIGINT_TYPE, + 'REAL' => Zend_Db::FLOAT_TYPE + ); + + /** + * Constructor. + * + * $config is an array of key/value pairs containing configuration + * options. Note that the SQLite options are different than most of + * the other PDO adapters in that no username or password are needed. + * Also, an extra config key "sqlite2" specifies compatibility mode. + * + * dbname => (string) The name of the database to user (required, + * use :memory: for memory-based database) + * + * sqlite2 => (boolean) PDO_SQLITE defaults to SQLite 3. For compatibility + * with an older SQLite 2 database, set this to TRUE. + * + * @param array $config An array of configuration keys. + */ + public function __construct(array $config = array()) + { + if (isset($config['sqlite2']) && $config['sqlite2']) { + $this->_pdoType = 'sqlite2'; + } + + // SQLite uses no username/password. Stub to satisfy parent::_connect() + $this->_config['username'] = null; + $this->_config['password'] = null; + + return parent::__construct($config); + } + + /** + * Check for config options that are mandatory. + * Throw exceptions if any are missing. + * + * @param array $config + * @throws Zend_Db_Adapter_Exception + */ + protected function _checkRequiredOptions(array $config) + { + // we need at least a dbname + if (! array_key_exists('dbname', $config)) { + /** @see Zend_Db_Adapter_Exception */ + throw new Zend_Db_Adapter_Exception("Configuration array must have a key for 'dbname' that names the database instance"); + } + } + + /** + * DSN builder + */ + protected function _dsn() + { + return $this->_pdoType .':'. $this->_config['dbname']; + } + + /** + * Special configuration for SQLite behavior: make sure that result sets + * contain keys like 'column' instead of 'table.column'. + * + * @throws Zend_Db_Adapter_Exception + */ + protected function _connect() + { + /** + * if we already have a PDO object, no need to re-connect. + */ + if ($this->_connection) { + return; + } + + parent::_connect(); + + $retval = $this->_connection->exec('PRAGMA full_column_names=0'); + if ($retval === false) { + $error = $this->_connection->errorInfo(); + /** @see Zend_Db_Adapter_Exception */ + throw new Zend_Db_Adapter_Exception($error[2]); + } + + $retval = $this->_connection->exec('PRAGMA short_column_names=1'); + if ($retval === false) { + $error = $this->_connection->errorInfo(); + /** @see Zend_Db_Adapter_Exception */ + throw new Zend_Db_Adapter_Exception($error[2]); + } + } + + /** + * Returns a list of the tables in the database. + * + * @return array + */ + public function listTables() + { + $sql = "SELECT name FROM sqlite_master WHERE type='table' " + . "UNION ALL SELECT name FROM sqlite_temp_master " + . "WHERE type='table' ORDER BY name"; + + return $this->fetchCol($sql); + } + + /** + * Returns the column descriptions for a table. + * + * The return value is an associative array keyed by the column name, + * as returned by the RDBMS. + * + * The value of each array element is an associative array + * with the following keys: + * + * SCHEMA_NAME => string; name of database or schema + * TABLE_NAME => string; + * COLUMN_NAME => string; column name + * COLUMN_POSITION => number; ordinal position of column in table + * DATA_TYPE => string; SQL datatype name of column + * DEFAULT => string; default expression of column, null if none + * NULLABLE => boolean; true if column can have nulls + * LENGTH => number; length of CHAR/VARCHAR + * SCALE => number; scale of NUMERIC/DECIMAL + * PRECISION => number; precision of NUMERIC/DECIMAL + * UNSIGNED => boolean; unsigned property of an integer type + * PRIMARY => boolean; true if column is part of the primary key + * PRIMARY_POSITION => integer; position of column in primary key + * IDENTITY => integer; true if column is auto-generated with unique values + * + * @param string $tableName + * @param string $schemaName OPTIONAL + * @return array + */ + public function describeTable($tableName, $schemaName = null) + { + $sql = 'PRAGMA '; + + if ($schemaName) { + $sql .= $this->quoteIdentifier($schemaName) . '.'; + } + + $sql .= 'table_info('.$this->quoteIdentifier($tableName).')'; + + $stmt = $this->query($sql); + + /** + * Use FETCH_NUM so we are not dependent on the CASE attribute of the PDO connection + */ + $result = $stmt->fetchAll(Zend_Db::FETCH_NUM); + + $cid = 0; + $name = 1; + $type = 2; + $notnull = 3; + $dflt_value = 4; + $pk = 5; + + $desc = array(); + + $p = 1; + foreach ($result as $key => $row) { + list($length, $scale, $precision, $primary, $primaryPosition, $identity) = + array(null, null, null, false, null, false); + if (preg_match('/^((?:var)?char)\((\d+)\)/i', $row[$type], $matches)) { + $row[$type] = $matches[1]; + $length = $matches[2]; + } else if (preg_match('/^decimal\((\d+),(\d+)\)/i', $row[$type], $matches)) { + $row[$type] = 'DECIMAL'; + $precision = $matches[1]; + $scale = $matches[2]; + } + if ((bool) $row[$pk]) { + $primary = true; + $primaryPosition = $p; + /** + * SQLite INTEGER primary key is always auto-increment. + */ + $identity = (bool) ($row[$type] == 'INTEGER'); + ++$p; + } + $desc[$this->foldCase($row[$name])] = array( + 'SCHEMA_NAME' => $this->foldCase($schemaName), + 'TABLE_NAME' => $this->foldCase($tableName), + 'COLUMN_NAME' => $this->foldCase($row[$name]), + 'COLUMN_POSITION' => $row[$cid]+1, + 'DATA_TYPE' => $row[$type], + 'DEFAULT' => $row[$dflt_value], + 'NULLABLE' => ! (bool) $row[$notnull], + 'LENGTH' => $length, + 'SCALE' => $scale, + 'PRECISION' => $precision, + 'UNSIGNED' => null, // Sqlite3 does not support unsigned data + 'PRIMARY' => $primary, + 'PRIMARY_POSITION' => $primaryPosition, + 'IDENTITY' => $identity + ); + } + return $desc; + } + + /** + * Adds an adapter-specific LIMIT clause to the SELECT statement. + * + * @param string $sql + * @param integer $count + * @param integer $offset OPTIONAL + * @return string + */ + public function limit($sql, $count, $offset = 0) + { + $count = intval($count); + if ($count <= 0) { + /** @see Zend_Db_Adapter_Exception */ + throw new Zend_Db_Adapter_Exception("LIMIT argument count=$count is not valid"); + } + + $offset = intval($offset); + if ($offset < 0) { + /** @see Zend_Db_Adapter_Exception */ + throw new Zend_Db_Adapter_Exception("LIMIT argument offset=$offset is not valid"); + } + + $sql .= " LIMIT $count"; + if ($offset > 0) { + $sql .= " OFFSET $offset"; + } + + return $sql; + } + + /** + * Quote a raw string. + * + * @param string $value Raw string + * @return string Quoted string + */ + protected function _quote($value) + { + if (!is_int($value) && !is_float($value)) { + // Fix for null-byte injection + $value = addcslashes($value, "\000\032"); + } + return parent::_quote($value); + } +} diff --git a/library/vendor/Zend/Db/Adapter/Sqlsrv.php b/library/vendor/Zend/Db/Adapter/Sqlsrv.php new file mode 100644 index 0000000..ce3324f --- /dev/null +++ b/library/vendor/Zend/Db/Adapter/Sqlsrv.php @@ -0,0 +1,662 @@ + (string) Connect to the database as this username. + * password => (string) Password associated with the username. + * dbname => The name of the local SQL Server instance + * + * @var array + */ + protected $_config = array( + 'dbname' => null, + 'username' => null, + 'password' => null, + ); + + /** + * Last insert id from INSERT query + * + * @var int + */ + protected $_lastInsertId; + + /** + * Query used to fetch last insert id + * + * @var string + */ + protected $_lastInsertSQL = 'SELECT SCOPE_IDENTITY() as Current_Identity'; + + /** + * Keys are UPPERCASE SQL datatypes or the constants + * Zend_Db::INT_TYPE, Zend_Db::BIGINT_TYPE, or Zend_Db::FLOAT_TYPE. + * + * Values are: + * 0 = 32-bit integer + * 1 = 64-bit integer + * 2 = float or decimal + * + * @var array Associative array of datatypes to values 0, 1, or 2. + */ + protected $_numericDataTypes = array( + Zend_Db::INT_TYPE => Zend_Db::INT_TYPE, + Zend_Db::BIGINT_TYPE => Zend_Db::BIGINT_TYPE, + Zend_Db::FLOAT_TYPE => Zend_Db::FLOAT_TYPE, + 'INT' => Zend_Db::INT_TYPE, + 'SMALLINT' => Zend_Db::INT_TYPE, + 'TINYINT' => Zend_Db::INT_TYPE, + 'BIGINT' => Zend_Db::BIGINT_TYPE, + 'DECIMAL' => Zend_Db::FLOAT_TYPE, + 'FLOAT' => Zend_Db::FLOAT_TYPE, + 'MONEY' => Zend_Db::FLOAT_TYPE, + 'NUMERIC' => Zend_Db::FLOAT_TYPE, + 'REAL' => Zend_Db::FLOAT_TYPE, + 'SMALLMONEY' => Zend_Db::FLOAT_TYPE, + ); + + /** + * Default class name for a DB statement. + * + * @var string + */ + protected $_defaultStmtClass = 'Zend_Db_Statement_Sqlsrv'; + + /** + * Creates a connection resource. + * + * @return void + * @throws Zend_Db_Adapter_Sqlsrv_Exception + */ + protected function _connect() + { + if (is_resource($this->_connection)) { + // connection already exists + return; + } + + if (!extension_loaded('sqlsrv')) { + /** + * @see Zend_Db_Adapter_Sqlsrv_Exception + */ + throw new Zend_Db_Adapter_Sqlsrv_Exception('The Sqlsrv extension is required for this adapter but the extension is not loaded'); + } + + $serverName = $this->_config['host']; + if (isset($this->_config['port'])) { + $port = (integer) $this->_config['port']; + $serverName .= ', ' . $port; + } + + $connectionInfo = array( + 'Database' => $this->_config['dbname'], + ); + + if (isset($this->_config['username']) && isset($this->_config['password'])) + { + $connectionInfo += array( + 'UID' => $this->_config['username'], + 'PWD' => $this->_config['password'], + ); + } + // else - windows authentication + + if (!empty($this->_config['driver_options'])) { + foreach ($this->_config['driver_options'] as $option => $value) { + // A value may be a constant. + if (is_string($value)) { + $constantName = strtoupper($value); + if (defined($constantName)) { + $connectionInfo[$option] = constant($constantName); + } else { + $connectionInfo[$option] = $value; + } + } + } + } + + $this->_connection = sqlsrv_connect($serverName, $connectionInfo); + + if (!$this->_connection) { + /** + * @see Zend_Db_Adapter_Sqlsrv_Exception + */ + throw new Zend_Db_Adapter_Sqlsrv_Exception(sqlsrv_errors()); + } + } + + /** + * Check for config options that are mandatory. + * Throw exceptions if any are missing. + * + * @param array $config + * @throws Zend_Db_Adapter_Exception + */ + protected function _checkRequiredOptions(array $config) + { + // we need at least a dbname + if (! array_key_exists('dbname', $config)) { + /** @see Zend_Db_Adapter_Exception */ + throw new Zend_Db_Adapter_Exception("Configuration array must have a key for 'dbname' that names the database instance"); + } + + if (! array_key_exists('password', $config) && array_key_exists('username', $config)) { + /** + * @see Zend_Db_Adapter_Exception + */ + throw new Zend_Db_Adapter_Exception("Configuration array must have a key for 'password' for login credentials. + If Windows Authentication is desired, both keys 'username' and 'password' should be ommited from config."); + } + + if (array_key_exists('password', $config) && !array_key_exists('username', $config)) { + /** + * @see Zend_Db_Adapter_Exception + */ + throw new Zend_Db_Adapter_Exception("Configuration array must have a key for 'username' for login credentials. + If Windows Authentication is desired, both keys 'username' and 'password' should be ommited from config."); + } + } + + /** + * Set the transaction isoltion level. + * + * @param integer|null $level A fetch mode from SQLSRV_TXN_*. + * @return true + * @throws Zend_Db_Adapter_Sqlsrv_Exception + */ + public function setTransactionIsolationLevel($level = null) + { + $this->_connect(); + $sql = null; + + // Default transaction level in sql server + if ($level === null) + { + $level = SQLSRV_TXN_READ_COMMITTED; + } + + switch ($level) { + case SQLSRV_TXN_READ_UNCOMMITTED: + $sql = "READ UNCOMMITTED"; + break; + case SQLSRV_TXN_READ_COMMITTED: + $sql = "READ COMMITTED"; + break; + case SQLSRV_TXN_REPEATABLE_READ: + $sql = "REPEATABLE READ"; + break; + case SQLSRV_TXN_SNAPSHOT: + $sql = "SNAPSHOT"; + break; + case SQLSRV_TXN_SERIALIZABLE: + $sql = "SERIALIZABLE"; + break; + default: + throw new Zend_Db_Adapter_Sqlsrv_Exception("Invalid transaction isolation level mode '$level' specified"); + } + + if (!sqlsrv_query($this->_connection, "SET TRANSACTION ISOLATION LEVEL $sql;")) { + throw new Zend_Db_Adapter_Sqlsrv_Exception("Transaction cannot be changed to '$level'"); + } + + return true; + } + + /** + * Test if a connection is active + * + * @return boolean + */ + public function isConnected() + { + return (is_resource($this->_connection) + && (get_resource_type($this->_connection) == 'SQL Server Connection') + ); + } + + /** + * Force the connection to close. + * + * @return void + */ + public function closeConnection() + { + if ($this->isConnected()) { + sqlsrv_close($this->_connection); + } + $this->_connection = null; + } + + /** + * Returns an SQL statement for preparation. + * + * @param string $sql The SQL statement with placeholders. + * @return Zend_Db_Statement_Sqlsrv + */ + public function prepare($sql) + { + $this->_connect(); + $stmtClass = $this->_defaultStmtClass; + + if (!class_exists($stmtClass)) { + /** + * @see Zend_Loader + */ + Zend_Loader::loadClass($stmtClass); + } + + $stmt = new $stmtClass($this, $sql); + $stmt->setFetchMode($this->_fetchMode); + return $stmt; + } + + /** + * Quote a raw string. + * + * @param string $value Raw string + * @return string Quoted string + */ + protected function _quote($value) + { + if (is_int($value)) { + return $value; + } elseif (is_float($value)) { + return sprintf('%F', $value); + } + + $value = addcslashes($value, "\000\032"); + return "'" . str_replace("'", "''", $value) . "'"; + } + + /** + * Gets the last ID generated automatically by an IDENTITY/AUTOINCREMENT column. + * + * As a convention, on RDBMS brands that support sequences + * (e.g. Oracle, PostgreSQL, DB2), this method forms the name of a sequence + * from the arguments and returns the last id generated by that sequence. + * On RDBMS brands that support IDENTITY/AUTOINCREMENT columns, this method + * returns the last value generated for such a column, and the table name + * argument is disregarded. + * + * @param string $tableName OPTIONAL Name of table. + * @param string $primaryKey OPTIONAL Name of primary key column. + * @return string + */ + public function lastInsertId($tableName = null, $primaryKey = null) + { + if ($tableName) { + $tableName = $this->quote($tableName); + $sql = 'SELECT IDENT_CURRENT (' . $tableName . ') as Current_Identity'; + return (string) $this->fetchOne($sql); + } + + if ($this->_lastInsertId > 0) { + return (string) $this->_lastInsertId; + } + + $sql = $this->_lastInsertSQL; + return (string) $this->fetchOne($sql); + } + + /** + * Inserts a table row with specified data. + * + * @param mixed $table The table to insert data into. + * @param array $bind Column-value pairs. + * @return int The number of affected rows. + */ + public function insert($table, array $bind) + { + // extract and quote col names from the array keys + $cols = array(); + $vals = array(); + foreach ($bind as $col => $val) { + $cols[] = $this->quoteIdentifier($col, true); + if ($val instanceof Zend_Db_Expr) { + $vals[] = $val->__toString(); + unset($bind[$col]); + } else { + $vals[] = '?'; + } + } + + // build the statement + $sql = "INSERT INTO " + . $this->quoteIdentifier($table, true) + . ' (' . implode(', ', $cols) . ') ' + . 'VALUES (' . implode(', ', $vals) . ')' + . ' ' . $this->_lastInsertSQL; + + // execute the statement and return the number of affected rows + $stmt = $this->query($sql, array_values($bind)); + $result = $stmt->rowCount(); + + $stmt->nextRowset(); + + $this->_lastInsertId = $stmt->fetchColumn(); + + return $result; + } + + /** + * Returns a list of the tables in the database. + * + * @return array + */ + public function listTables() + { + $this->_connect(); + $sql = "SELECT name FROM sysobjects WHERE type = 'U' ORDER BY name"; + return $this->fetchCol($sql); + } + + /** + * Returns the column descriptions for a table. + * + * The return value is an associative array keyed by the column name, + * as returned by the RDBMS. + * + * The value of each array element is an associative array + * with the following keys: + * + * SCHEMA_NAME => string; name of schema + * TABLE_NAME => string; + * COLUMN_NAME => string; column name + * COLUMN_POSITION => number; ordinal position of column in table + * DATA_TYPE => string; SQL datatype name of column + * DEFAULT => string; default expression of column, null if none + * NULLABLE => boolean; true if column can have nulls + * LENGTH => number; length of CHAR/VARCHAR + * SCALE => number; scale of NUMERIC/DECIMAL + * PRECISION => number; precision of NUMERIC/DECIMAL + * UNSIGNED => boolean; unsigned property of an integer type + * PRIMARY => boolean; true if column is part of the primary key + * PRIMARY_POSITION => integer; position of column in primary key + * IDENTITY => integer; true if column is auto-generated with unique values + * + * @todo Discover integer unsigned property. + * + * @param string $tableName + * @param string $schemaName OPTIONAL + * @return array + */ + public function describeTable($tableName, $schemaName = null) + { + /** + * Discover metadata information about this table. + */ + $sql = "exec sp_columns @table_name = " . $this->quoteIdentifier($tableName, true); + $stmt = $this->query($sql); + $result = $stmt->fetchAll(Zend_Db::FETCH_NUM); + + // ZF-7698 + $stmt->closeCursor(); + + if (count($result) == 0) { + return array(); + } + + $owner = 1; + $table_name = 2; + $column_name = 3; + $type_name = 5; + $precision = 6; + $length = 7; + $scale = 8; + $nullable = 10; + $column_def = 12; + $column_position = 16; + + /** + * Discover primary key column(s) for this table. + */ + $tableOwner = $result[0][$owner]; + $sql = "exec sp_pkeys @table_owner = " . $tableOwner + . ", @table_name = " . $this->quoteIdentifier($tableName, true); + $stmt = $this->query($sql); + + $primaryKeysResult = $stmt->fetchAll(Zend_Db::FETCH_NUM); + $primaryKeyColumn = array(); + + // Per http://msdn.microsoft.com/en-us/library/ms189813.aspx, + // results from sp_keys stored procedure are: + // 0=TABLE_QUALIFIER 1=TABLE_OWNER 2=TABLE_NAME 3=COLUMN_NAME 4=KEY_SEQ 5=PK_NAME + + $pkey_column_name = 3; + $pkey_key_seq = 4; + foreach ($primaryKeysResult as $pkeysRow) { + $primaryKeyColumn[$pkeysRow[$pkey_column_name]] = $pkeysRow[$pkey_key_seq]; + } + + $desc = array(); + $p = 1; + foreach ($result as $key => $row) { + $identity = false; + $words = explode(' ', $row[$type_name], 2); + if (isset($words[0])) { + $type = $words[0]; + if (isset($words[1])) { + $identity = (bool) preg_match('/identity/', $words[1]); + } + } + + $isPrimary = array_key_exists($row[$column_name], $primaryKeyColumn); + if ($isPrimary) { + $primaryPosition = $primaryKeyColumn[$row[$column_name]]; + } else { + $primaryPosition = null; + } + + $desc[$this->foldCase($row[$column_name])] = array( + 'SCHEMA_NAME' => null, // @todo + 'TABLE_NAME' => $this->foldCase($row[$table_name]), + 'COLUMN_NAME' => $this->foldCase($row[$column_name]), + 'COLUMN_POSITION' => (int) $row[$column_position], + 'DATA_TYPE' => $type, + 'DEFAULT' => $row[$column_def], + 'NULLABLE' => (bool) $row[$nullable], + 'LENGTH' => $row[$length], + 'SCALE' => $row[$scale], + 'PRECISION' => $row[$precision], + 'UNSIGNED' => null, // @todo + 'PRIMARY' => $isPrimary, + 'PRIMARY_POSITION' => $primaryPosition, + 'IDENTITY' => $identity, + ); + } + + return $desc; + } + + /** + * Leave autocommit mode and begin a transaction. + * + * @return void + * @throws Zend_Db_Adapter_Sqlsrv_Exception + */ + protected function _beginTransaction() + { + if (!sqlsrv_begin_transaction($this->_connection)) { + throw new Zend_Db_Adapter_Sqlsrv_Exception(sqlsrv_errors()); + } + } + + /** + * Commit a transaction and return to autocommit mode. + * + * @return void + * @throws Zend_Db_Adapter_Sqlsrv_Exception + */ + protected function _commit() + { + if (!sqlsrv_commit($this->_connection)) { + throw new Zend_Db_Adapter_Sqlsrv_Exception(sqlsrv_errors()); + } + } + + /** + * Roll back a transaction and return to autocommit mode. + * + * @return void + * @throws Zend_Db_Adapter_Sqlsrv_Exception + */ + protected function _rollBack() + { + if (!sqlsrv_rollback($this->_connection)) { + throw new Zend_Db_Adapter_Sqlsrv_Exception(sqlsrv_errors()); + } + } + + /** + * Set the fetch mode. + * + * @todo Support FETCH_CLASS and FETCH_INTO. + * + * @param integer $mode A fetch mode. + * @return void + * @throws Zend_Db_Adapter_Sqlsrv_Exception + */ + public function setFetchMode($mode) + { + switch ($mode) { + case Zend_Db::FETCH_NUM: // seq array + case Zend_Db::FETCH_ASSOC: // assoc array + case Zend_Db::FETCH_BOTH: // seq+assoc array + case Zend_Db::FETCH_OBJ: // object + $this->_fetchMode = $mode; + break; + case Zend_Db::FETCH_BOUND: // bound to PHP variable + throw new Zend_Db_Adapter_Sqlsrv_Exception('FETCH_BOUND is not supported yet'); + break; + default: + throw new Zend_Db_Adapter_Sqlsrv_Exception("Invalid fetch mode '$mode' specified"); + break; + } + } + + /** + * Adds an adapter-specific LIMIT clause to the SELECT statement. + * + * @param string $sql + * @param integer $count + * @param integer $offset OPTIONAL + * @return string + * @throws Zend_Db_Adapter_Sqlsrv_Exception + */ + public function limit($sql, $count, $offset = 0) + { + $count = intval($count); + if ($count <= 0) { + throw new Zend_Db_Adapter_Exception("LIMIT argument count=$count is not valid"); + } + + $offset = intval($offset); + if ($offset < 0) { + /** @see Zend_Db_Adapter_Exception */ + throw new Zend_Db_Adapter_Exception("LIMIT argument offset=$offset is not valid"); + } + + if ($offset == 0) { + $sql = preg_replace('/^SELECT\s/i', 'SELECT TOP ' . $count . ' ', $sql); + } else { + $orderby = stristr($sql, 'ORDER BY'); + + if (!$orderby) { + $over = 'ORDER BY (SELECT 0)'; + } else { + $over = preg_replace('/\"[^,]*\".\"([^,]*)\"/i', '"inner_tbl"."$1"', $orderby); + } + + // Remove ORDER BY clause from $sql + $sql = preg_replace('/\s+ORDER BY(.*)/', '', $sql); + + // Add ORDER BY clause as an argument for ROW_NUMBER() + $sql = "SELECT ROW_NUMBER() OVER ($over) AS \"ZEND_DB_ROWNUM\", * FROM ($sql) AS inner_tbl"; + + $start = $offset + 1; + + if ($count == PHP_INT_MAX) { + $sql = "WITH outer_tbl AS ($sql) SELECT * FROM outer_tbl WHERE \"ZEND_DB_ROWNUM\" >= $start"; + } + else { + $end = $offset + $count; + $sql = "WITH outer_tbl AS ($sql) SELECT * FROM outer_tbl WHERE \"ZEND_DB_ROWNUM\" BETWEEN $start AND $end"; + } + } + + return $sql; + } + + /** + * Check if the adapter supports real SQL parameters. + * + * @param string $type 'positional' or 'named' + * @return bool + */ + public function supportsParameters($type) + { + if ($type == 'positional') { + return true; + } + + // if its 'named' or anything else + return false; + } + + /** + * Retrieve server version in PHP style + * + * @return string + */ + public function getServerVersion() + { + $this->_connect(); + $serverInfo = sqlsrv_server_info($this->_connection); + + if ($serverInfo !== false) { + return $serverInfo['SQLServerVersion']; + } + + return null; + } +} diff --git a/library/vendor/Zend/Db/Adapter/Sqlsrv/Exception.php b/library/vendor/Zend/Db/Adapter/Sqlsrv/Exception.php new file mode 100644 index 0000000..2bbc84d --- /dev/null +++ b/library/vendor/Zend/Db/Adapter/Sqlsrv/Exception.php @@ -0,0 +1,62 @@ +_expression = (string) $expression; + } + + /** + * @return string The string of the SQL expression stored in this object. + */ + public function __toString() + { + return $this->_expression; + } + +} diff --git a/library/vendor/Zend/Db/Profiler.php b/library/vendor/Zend/Db/Profiler.php new file mode 100644 index 0000000..c80ec5d --- /dev/null +++ b/library/vendor/Zend/Db/Profiler.php @@ -0,0 +1,469 @@ +setEnabled($enabled); + } + + /** + * Enable or disable the profiler. If $enable is false, the profiler + * is disabled and will not log any queries sent to it. + * + * @param boolean $enable + * @return Zend_Db_Profiler Provides a fluent interface + */ + public function setEnabled($enable) + { + $this->_enabled = (boolean) $enable; + + return $this; + } + + /** + * Get the current state of enable. If True is returned, + * the profiler is enabled. + * + * @return boolean + */ + public function getEnabled() + { + return $this->_enabled; + } + + /** + * Sets a minimum number of seconds for saving query profiles. If this + * is set, only those queries whose elapsed time is equal or greater than + * $minimumSeconds will be saved. To save all queries regardless of + * elapsed time, set $minimumSeconds to null. + * + * @param integer $minimumSeconds OPTIONAL + * @return Zend_Db_Profiler Provides a fluent interface + */ + public function setFilterElapsedSecs($minimumSeconds = null) + { + if (null === $minimumSeconds) { + $this->_filterElapsedSecs = null; + } else { + $this->_filterElapsedSecs = (integer) $minimumSeconds; + } + + return $this; + } + + /** + * Returns the minimum number of seconds for saving query profiles, or null if + * query profiles are saved regardless of elapsed time. + * + * @return integer|null + */ + public function getFilterElapsedSecs() + { + return $this->_filterElapsedSecs; + } + + /** + * Sets the types of query profiles to save. Set $queryType to one of + * the Zend_Db_Profiler::* constants to only save profiles for that type of + * query. To save more than one type, logical OR them together. To + * save all queries regardless of type, set $queryType to null. + * + * @param integer $queryTypes OPTIONAL + * @return Zend_Db_Profiler Provides a fluent interface + */ + public function setFilterQueryType($queryTypes = null) + { + $this->_filterTypes = $queryTypes; + + return $this; + } + + /** + * Returns the types of query profiles saved, or null if queries are saved regardless + * of their types. + * + * @return integer|null + * @see Zend_Db_Profiler::setFilterQueryType() + */ + public function getFilterQueryType() + { + return $this->_filterTypes; + } + + /** + * Clears the history of any past query profiles. This is relentless + * and will even clear queries that were started and may not have + * been marked as ended. + * + * @return Zend_Db_Profiler Provides a fluent interface + */ + public function clear() + { + $this->_queryProfiles = array(); + + return $this; + } + + /** + * Clone a profiler query + * + * @param Zend_Db_Profiler_Query $query + * @return integer or null + */ + public function queryClone(Zend_Db_Profiler_Query $query) + { + $this->_queryProfiles[] = clone $query; + + end($this->_queryProfiles); + + return key($this->_queryProfiles); + } + + /** + * Starts a query. Creates a new query profile object (Zend_Db_Profiler_Query) + * and returns the "query profiler handle". Run the query, then call + * queryEnd() and pass it this handle to make the query as ended and + * record the time. If the profiler is not enabled, this takes no + * action and immediately returns null. + * + * @param string $queryText SQL statement + * @param integer $queryType OPTIONAL Type of query, one of the Zend_Db_Profiler::* constants + * @return integer|null + */ + public function queryStart($queryText, $queryType = null) + { + if (!$this->_enabled) { + return null; + } + + // make sure we have a query type + if (null === $queryType) { + switch (strtolower(substr(ltrim($queryText), 0, 6))) { + case 'insert': + $queryType = self::INSERT; + break; + case 'update': + $queryType = self::UPDATE; + break; + case 'delete': + $queryType = self::DELETE; + break; + case 'select': + $queryType = self::SELECT; + break; + default: + $queryType = self::QUERY; + break; + } + } + + /** + * @see Zend_Db_Profiler_Query + */ + $this->_queryProfiles[] = new Zend_Db_Profiler_Query($queryText, $queryType); + + end($this->_queryProfiles); + + return key($this->_queryProfiles); + } + + /** + * Ends a query. Pass it the handle that was returned by queryStart(). + * This will mark the query as ended and save the time. + * + * @param integer $queryId + * @throws Zend_Db_Profiler_Exception + * @return string Inform that a query is stored or ignored. + */ + public function queryEnd($queryId) + { + // Don't do anything if the Zend_Db_Profiler is not enabled. + if (!$this->_enabled) { + return self::IGNORED; + } + + // Check for a valid query handle. + if (!isset($this->_queryProfiles[$queryId])) { + /** + * @see Zend_Db_Profiler_Exception + */ + throw new Zend_Db_Profiler_Exception("Profiler has no query with handle '$queryId'."); + } + + $qp = $this->_queryProfiles[$queryId]; + + // Ensure that the query profile has not already ended + if ($qp->hasEnded()) { + /** + * @see Zend_Db_Profiler_Exception + */ + throw new Zend_Db_Profiler_Exception("Query with profiler handle '$queryId' has already ended."); + } + + // End the query profile so that the elapsed time can be calculated. + $qp->end(); + + /** + * If filtering by elapsed time is enabled, only keep the profile if + * it ran for the minimum time. + */ + if (null !== $this->_filterElapsedSecs && $qp->getElapsedSecs() < $this->_filterElapsedSecs) { + unset($this->_queryProfiles[$queryId]); + return self::IGNORED; + } + + /** + * If filtering by query type is enabled, only keep the query if + * it was one of the allowed types. + */ + if (null !== $this->_filterTypes && !($qp->getQueryType() & $this->_filterTypes)) { + unset($this->_queryProfiles[$queryId]); + return self::IGNORED; + } + + return self::STORED; + } + + /** + * Get a profile for a query. Pass it the same handle that was returned + * by queryStart() and it will return a Zend_Db_Profiler_Query object. + * + * @param integer $queryId + * @throws Zend_Db_Profiler_Exception + * @return Zend_Db_Profiler_Query + */ + public function getQueryProfile($queryId) + { + if (!array_key_exists($queryId, $this->_queryProfiles)) { + /** + * @see Zend_Db_Profiler_Exception + */ + throw new Zend_Db_Profiler_Exception("Query handle '$queryId' not found in profiler log."); + } + + return $this->_queryProfiles[$queryId]; + } + + /** + * Get an array of query profiles (Zend_Db_Profiler_Query objects). If $queryType + * is set to one of the Zend_Db_Profiler::* constants then only queries of that + * type will be returned. Normally, queries that have not yet ended will + * not be returned unless $showUnfinished is set to True. If no + * queries were found, False is returned. The returned array is indexed by the query + * profile handles. + * + * @param integer $queryType + * @param boolean $showUnfinished + * @return array|false + */ + public function getQueryProfiles($queryType = null, $showUnfinished = false) + { + $queryProfiles = array(); + foreach ($this->_queryProfiles as $key => $qp) { + if ($queryType === null) { + $condition = true; + } else { + $condition = ($qp->getQueryType() & $queryType); + } + + if (($qp->hasEnded() || $showUnfinished) && $condition) { + $queryProfiles[$key] = $qp; + } + } + + if (empty($queryProfiles)) { + $queryProfiles = false; + } + + return $queryProfiles; + } + + /** + * Get the total elapsed time (in seconds) of all of the profiled queries. + * Only queries that have ended will be counted. If $queryType is set to + * one or more of the Zend_Db_Profiler::* constants, the elapsed time will be calculated + * only for queries of the given type(s). + * + * @param integer $queryType OPTIONAL + * @return float + */ + public function getTotalElapsedSecs($queryType = null) + { + $elapsedSecs = 0; + foreach ($this->_queryProfiles as $key => $qp) { + if (null === $queryType) { + $condition = true; + } else { + $condition = ($qp->getQueryType() & $queryType); + } + if (($qp->hasEnded()) && $condition) { + $elapsedSecs += $qp->getElapsedSecs(); + } + } + return $elapsedSecs; + } + + /** + * Get the total number of queries that have been profiled. Only queries that have ended will + * be counted. If $queryType is set to one of the Zend_Db_Profiler::* constants, only queries of + * that type will be counted. + * + * @param integer $queryType OPTIONAL + * @return integer + */ + public function getTotalNumQueries($queryType = null) + { + if (null === $queryType) { + return count($this->_queryProfiles); + } + + $numQueries = 0; + foreach ($this->_queryProfiles as $qp) { + if ($qp->hasEnded() && ($qp->getQueryType() & $queryType)) { + $numQueries++; + } + } + + return $numQueries; + } + + /** + * Get the Zend_Db_Profiler_Query object for the last query that was run, regardless if it has + * ended or not. If the query has not ended, its end time will be null. If no queries have + * been profiled, false is returned. + * + * @return Zend_Db_Profiler_Query|false + */ + public function getLastQueryProfile() + { + if (empty($this->_queryProfiles)) { + return false; + } + + end($this->_queryProfiles); + + return current($this->_queryProfiles); + } + +} + diff --git a/library/vendor/Zend/Db/Profiler/Exception.php b/library/vendor/Zend/Db/Profiler/Exception.php new file mode 100644 index 0000000..c2f76fa --- /dev/null +++ b/library/vendor/Zend/Db/Profiler/Exception.php @@ -0,0 +1,39 @@ +_query = $query; + $this->_queryType = $queryType; + // by default, and for backward-compatibility, start the click ticking + $this->start(); + } + + /** + * Clone handler for the query object. + * @return void + */ + public function __clone() + { + $this->_boundParams = array(); + $this->_endedMicrotime = null; + $this->start(); + } + + /** + * Starts the elapsed time click ticking. + * This can be called subsequent to object creation, + * to restart the clock. For instance, this is useful + * right before executing a prepared query. + * + * @return void + */ + public function start() + { + $this->_startedMicrotime = microtime(true); + } + + /** + * Ends the query and records the time so that the elapsed time can be determined later. + * + * @return void + */ + public function end() + { + $this->_endedMicrotime = microtime(true); + } + + /** + * Returns true if and only if the query has ended. + * + * @return boolean + */ + public function hasEnded() + { + return $this->_endedMicrotime !== null; + } + + /** + * Get the original SQL text of the query. + * + * @return string + */ + public function getQuery() + { + return $this->_query; + } + + /** + * Get the type of this query (one of the Zend_Db_Profiler::* constants) + * + * @return integer + */ + public function getQueryType() + { + return $this->_queryType; + } + + /** + * @param string $param + * @param mixed $variable + * @return void + */ + public function bindParam($param, $variable) + { + $this->_boundParams[$param] = $variable; + } + + /** + * @param array $param + * @return void + */ + public function bindParams(array $params) + { + if (array_key_exists(0, $params)) { + array_unshift($params, null); + unset($params[0]); + } + foreach ($params as $param => $value) { + $this->bindParam($param, $value); + } + } + + /** + * @return array + */ + public function getQueryParams() + { + return $this->_boundParams; + } + + /** + * Get the elapsed time (in seconds) that the query ran. + * If the query has not yet ended, false is returned. + * + * @return float|false + */ + public function getElapsedSecs() + { + if (null === $this->_endedMicrotime) { + return false; + } + + return $this->_endedMicrotime - $this->_startedMicrotime; + } + + /** + * Get the time (in seconds) when the profiler started running. + * + * @return bool|float + */ + public function getStartedMicrotime() + { + if(null === $this->_startedMicrotime) { + return false; + } + + return $this->_startedMicrotime; + } +} + diff --git a/library/vendor/Zend/Db/Select.php b/library/vendor/Zend/Db/Select.php new file mode 100644 index 0000000..64908e3 --- /dev/null +++ b/library/vendor/Zend/Db/Select.php @@ -0,0 +1,1368 @@ + false, + self::COLUMNS => array(), + self::UNION => array(), + self::FROM => array(), + self::WHERE => array(), + self::GROUP => array(), + self::HAVING => array(), + self::ORDER => array(), + self::LIMIT_COUNT => null, + self::LIMIT_OFFSET => null, + self::FOR_UPDATE => false + ); + + /** + * Specify legal join types. + * + * @var array + */ + protected static $_joinTypes = array( + self::INNER_JOIN, + self::LEFT_JOIN, + self::RIGHT_JOIN, + self::FULL_JOIN, + self::CROSS_JOIN, + self::NATURAL_JOIN, + ); + + /** + * Specify legal union types. + * + * @var array + */ + protected static $_unionTypes = array( + self::SQL_UNION, + self::SQL_UNION_ALL + ); + + /** + * The component parts of a SELECT statement. + * Initialized to the $_partsInit array in the constructor. + * + * @var array + */ + protected $_parts = array(); + + /** + * Tracks which columns are being select from each table and join. + * + * @var array + */ + protected $_tableCols = array(); + + /** + * Class constructor + * + * @param Zend_Db_Adapter_Abstract $adapter + */ + public function __construct(Zend_Db_Adapter_Abstract $adapter) + { + $this->_adapter = $adapter; + $this->_parts = self::$_partsInit; + } + + /** + * Get bind variables + * + * @return array + */ + public function getBind() + { + return $this->_bind; + } + + /** + * Set bind variables + * + * @param mixed $bind + * @return Zend_Db_Select + */ + public function bind($bind) + { + $this->_bind = $bind; + + return $this; + } + + /** + * Makes the query SELECT DISTINCT. + * + * @param bool $flag Whether or not the SELECT is DISTINCT (default true). + * @return Zend_Db_Select This Zend_Db_Select object. + */ + public function distinct($flag = true) + { + $this->_parts[self::DISTINCT] = (bool) $flag; + return $this; + } + + /** + * Adds a FROM table and optional columns to the query. + * + * The first parameter $name can be a simple string, in which case the + * correlation name is generated automatically. If you want to specify + * the correlation name, the first parameter must be an associative + * array in which the key is the correlation name, and the value is + * the physical table name. For example, array('alias' => 'table'). + * The correlation name is prepended to all columns fetched for this + * table. + * + * The second parameter can be a single string or Zend_Db_Expr object, + * or else an array of strings or Zend_Db_Expr objects. + * + * The first parameter can be null or an empty string, in which case + * no correlation name is generated or prepended to the columns named + * in the second parameter. + * + * @param array|string|Zend_Db_Expr $name The table name or an associative array + * relating correlation name to table name. + * @param array|string|Zend_Db_Expr $cols The columns to select from this table. + * @param string $schema The schema name to specify, if any. + * @return Zend_Db_Select This Zend_Db_Select object. + */ + public function from($name, $cols = '*', $schema = null) + { + return $this->_join(self::FROM, $name, null, $cols, $schema); + } + + /** + * Specifies the columns used in the FROM clause. + * + * The parameter can be a single string or Zend_Db_Expr object, + * or else an array of strings or Zend_Db_Expr objects. + * + * @param array|string|Zend_Db_Expr $cols The columns to select from this table. + * @param string $correlationName Correlation name of target table. OPTIONAL + * @return Zend_Db_Select This Zend_Db_Select object. + */ + public function columns($cols = '*', $correlationName = null) + { + if ($correlationName === null && count($this->_parts[self::FROM])) { + $correlationNameKeys = array_keys($this->_parts[self::FROM]); + $correlationName = current($correlationNameKeys); + } + + if (!array_key_exists($correlationName, $this->_parts[self::FROM])) { + /** + * @see Zend_Db_Select_Exception + */ + throw new Zend_Db_Select_Exception("No table has been specified for the FROM clause"); + } + + $this->_tableCols($correlationName, $cols); + + return $this; + } + + /** + * Adds a UNION clause to the query. + * + * The first parameter has to be an array of Zend_Db_Select or + * sql query strings. + * + * + * $sql1 = $db->select(); + * $sql2 = "SELECT ..."; + * $select = $db->select() + * ->union(array($sql1, $sql2)) + * ->order("id"); + * + * + * @param array $select Array of select clauses for the union. + * @return Zend_Db_Select This Zend_Db_Select object. + */ + public function union($select = array(), $type = self::SQL_UNION) + { + if (!is_array($select)) { + throw new Zend_Db_Select_Exception( + "union() only accepts an array of Zend_Db_Select instances of sql query strings." + ); + } + + if (!in_array($type, self::$_unionTypes)) { + throw new Zend_Db_Select_Exception("Invalid union type '{$type}'"); + } + + foreach ($select as $target) { + $this->_parts[self::UNION][] = array($target, $type); + } + + return $this; + } + + /** + * Adds a JOIN table and columns to the query. + * + * The $name and $cols parameters follow the same logic + * as described in the from() method. + * + * @param array|string|Zend_Db_Expr $name The table name. + * @param string $cond Join on this condition. + * @param array|string $cols The columns to select from the joined table. + * @param string $schema The database name to specify, if any. + * @return Zend_Db_Select This Zend_Db_Select object. + */ + public function join($name, $cond, $cols = self::SQL_WILDCARD, $schema = null) + { + return $this->joinInner($name, $cond, $cols, $schema); + } + + /** + * Add an INNER JOIN table and colums to the query + * Rows in both tables are matched according to the expression + * in the $cond argument. The result set is comprised + * of all cases where rows from the left table match + * rows from the right table. + * + * The $name and $cols parameters follow the same logic + * as described in the from() method. + * + * @param array|string|Zend_Db_Expr $name The table name. + * @param string $cond Join on this condition. + * @param array|string $cols The columns to select from the joined table. + * @param string $schema The database name to specify, if any. + * @return Zend_Db_Select This Zend_Db_Select object. + */ + public function joinInner($name, $cond, $cols = self::SQL_WILDCARD, $schema = null) + { + return $this->_join(self::INNER_JOIN, $name, $cond, $cols, $schema); + } + + /** + * Add a LEFT OUTER JOIN table and colums to the query + * All rows from the left operand table are included, + * matching rows from the right operand table included, + * and the columns from the right operand table are filled + * with NULLs if no row exists matching the left table. + * + * The $name and $cols parameters follow the same logic + * as described in the from() method. + * + * @param array|string|Zend_Db_Expr $name The table name. + * @param string $cond Join on this condition. + * @param array|string $cols The columns to select from the joined table. + * @param string $schema The database name to specify, if any. + * @return Zend_Db_Select This Zend_Db_Select object. + */ + public function joinLeft($name, $cond, $cols = self::SQL_WILDCARD, $schema = null) + { + return $this->_join(self::LEFT_JOIN, $name, $cond, $cols, $schema); + } + + /** + * Add a RIGHT OUTER JOIN table and colums to the query. + * Right outer join is the complement of left outer join. + * All rows from the right operand table are included, + * matching rows from the left operand table included, + * and the columns from the left operand table are filled + * with NULLs if no row exists matching the right table. + * + * The $name and $cols parameters follow the same logic + * as described in the from() method. + * + * @param array|string|Zend_Db_Expr $name The table name. + * @param string $cond Join on this condition. + * @param array|string $cols The columns to select from the joined table. + * @param string $schema The database name to specify, if any. + * @return Zend_Db_Select This Zend_Db_Select object. + */ + public function joinRight($name, $cond, $cols = self::SQL_WILDCARD, $schema = null) + { + return $this->_join(self::RIGHT_JOIN, $name, $cond, $cols, $schema); + } + + /** + * Add a FULL OUTER JOIN table and colums to the query. + * A full outer join is like combining a left outer join + * and a right outer join. All rows from both tables are + * included, paired with each other on the same row of the + * result set if they satisfy the join condition, and otherwise + * paired with NULLs in place of columns from the other table. + * + * The $name and $cols parameters follow the same logic + * as described in the from() method. + * + * @param array|string|Zend_Db_Expr $name The table name. + * @param string $cond Join on this condition. + * @param array|string $cols The columns to select from the joined table. + * @param string $schema The database name to specify, if any. + * @return Zend_Db_Select This Zend_Db_Select object. + */ + public function joinFull($name, $cond, $cols = self::SQL_WILDCARD, $schema = null) + { + return $this->_join(self::FULL_JOIN, $name, $cond, $cols, $schema); + } + + /** + * Add a CROSS JOIN table and colums to the query. + * A cross join is a cartesian product; there is no join condition. + * + * The $name and $cols parameters follow the same logic + * as described in the from() method. + * + * @param array|string|Zend_Db_Expr $name The table name. + * @param array|string $cols The columns to select from the joined table. + * @param string $schema The database name to specify, if any. + * @return Zend_Db_Select This Zend_Db_Select object. + */ + public function joinCross($name, $cols = self::SQL_WILDCARD, $schema = null) + { + return $this->_join(self::CROSS_JOIN, $name, null, $cols, $schema); + } + + /** + * Add a NATURAL JOIN table and colums to the query. + * A natural join assumes an equi-join across any column(s) + * that appear with the same name in both tables. + * Only natural inner joins are supported by this API, + * even though SQL permits natural outer joins as well. + * + * The $name and $cols parameters follow the same logic + * as described in the from() method. + * + * @param array|string|Zend_Db_Expr $name The table name. + * @param array|string $cols The columns to select from the joined table. + * @param string $schema The database name to specify, if any. + * @return Zend_Db_Select This Zend_Db_Select object. + */ + public function joinNatural($name, $cols = self::SQL_WILDCARD, $schema = null) + { + return $this->_join(self::NATURAL_JOIN, $name, null, $cols, $schema); + } + + /** + * Adds a WHERE condition to the query by AND. + * + * If a value is passed as the second param, it will be quoted + * and replaced into the condition wherever a question-mark + * appears. Array values are quoted and comma-separated. + * + * + * // simplest but non-secure + * $select->where("id = $id"); + * + * // secure (ID is quoted but matched anyway) + * $select->where('id = ?', $id); + * + * // alternatively, with named binding + * $select->where('id = :id'); + * + * + * Note that it is more correct to use named bindings in your + * queries for values other than strings. When you use named + * bindings, don't forget to pass the values when actually + * making a query: + * + * + * $db->fetchAll($select, array('id' => 5)); + * + * + * @param string $cond The WHERE condition. + * @param mixed $value OPTIONAL The value to quote into the condition. + * @param int $type OPTIONAL The type of the given value + * @return Zend_Db_Select This Zend_Db_Select object. + */ + public function where($cond, $value = null, $type = null) + { + $this->_parts[self::WHERE][] = $this->_where($cond, $value, $type, true); + + return $this; + } + + /** + * Adds a WHERE condition to the query by OR. + * + * Otherwise identical to where(). + * + * @param string $cond The WHERE condition. + * @param mixed $value OPTIONAL The value to quote into the condition. + * @param int $type OPTIONAL The type of the given value + * @return Zend_Db_Select This Zend_Db_Select object. + * + * @see where() + */ + public function orWhere($cond, $value = null, $type = null) + { + $this->_parts[self::WHERE][] = $this->_where($cond, $value, $type, false); + + return $this; + } + + /** + * Adds grouping to the query. + * + * @param array|string $spec The column(s) to group by. + * @return Zend_Db_Select This Zend_Db_Select object. + */ + public function group($spec) + { + if (!is_array($spec)) { + $spec = array($spec); + } + + foreach ($spec as $val) { + // Remove comments from SQL statement + $noComments = preg_replace(self::REGEX_SQL_COMMENTS, '$1', (string) $val); + if (preg_match(self::REGEX_COLUMN_EXPR_GROUP, $noComments)) { + $val = new Zend_Db_Expr($val); + } + $this->_parts[self::GROUP][] = $val; + } + + return $this; + } + + /** + * Adds a HAVING condition to the query by AND. + * + * If a value is passed as the second param, it will be quoted + * and replaced into the condition wherever a question-mark + * appears. See {@link where()} for an example + * + * @param string $cond The HAVING condition. + * @param mixed $value OPTIONAL The value to quote into the condition. + * @param int $type OPTIONAL The type of the given value + * @return Zend_Db_Select This Zend_Db_Select object. + */ + public function having($cond, $value = null, $type = null) + { + if ($value !== null) { + $cond = $this->_adapter->quoteInto($cond, $value, $type); + } + + if ($this->_parts[self::HAVING]) { + $this->_parts[self::HAVING][] = self::SQL_AND . " ($cond)"; + } else { + $this->_parts[self::HAVING][] = "($cond)"; + } + + return $this; + } + + /** + * Adds a HAVING condition to the query by OR. + * + * Otherwise identical to orHaving(). + * + * @param string $cond The HAVING condition. + * @param mixed $value OPTIONAL The value to quote into the condition. + * @param int $type OPTIONAL The type of the given value + * @return Zend_Db_Select This Zend_Db_Select object. + * + * @see having() + */ + public function orHaving($cond, $value = null, $type = null) + { + if ($value !== null) { + $cond = $this->_adapter->quoteInto($cond, $value, $type); + } + + if ($this->_parts[self::HAVING]) { + $this->_parts[self::HAVING][] = self::SQL_OR . " ($cond)"; + } else { + $this->_parts[self::HAVING][] = "($cond)"; + } + + return $this; + } + + /** + * Adds a row order to the query. + * + * @param mixed $spec The column(s) and direction to order by. + * @return Zend_Db_Select This Zend_Db_Select object. + */ + public function order($spec) + { + if (!is_array($spec)) { + $spec = array($spec); + } + + // force 'ASC' or 'DESC' on each order spec, default is ASC. + foreach ($spec as $val) { + if ($val instanceof Zend_Db_Expr) { + $expr = $val->__toString(); + if (empty($expr)) { + continue; + } + $this->_parts[self::ORDER][] = $val; + } else { + if (empty($val)) { + continue; + } + $direction = self::SQL_ASC; + if (preg_match('/(.*\W)(' . self::SQL_ASC . '|' . self::SQL_DESC . ')\b/si', $val, $matches)) { + $val = trim($matches[1]); + $direction = $matches[2]; + } + // Remove comments from SQL statement + $noComments = preg_replace(self::REGEX_SQL_COMMENTS, '$1', (string) $val); + if (preg_match(self::REGEX_COLUMN_EXPR_ORDER, $noComments)) { + $val = new Zend_Db_Expr($val); + } + $this->_parts[self::ORDER][] = array($val, $direction); + } + } + + return $this; + } + + /** + * Sets a limit count and offset to the query. + * + * @param int $count OPTIONAL The number of rows to return. + * @param int $offset OPTIONAL Start returning after this many rows. + * @return Zend_Db_Select This Zend_Db_Select object. + */ + public function limit($count = null, $offset = null) + { + $this->_parts[self::LIMIT_COUNT] = (int) $count; + $this->_parts[self::LIMIT_OFFSET] = (int) $offset; + return $this; + } + + /** + * Sets the limit and count by page number. + * + * @param int $page Limit results to this page number. + * @param int $rowCount Use this many rows per page. + * @return Zend_Db_Select This Zend_Db_Select object. + */ + public function limitPage($page, $rowCount) + { + $page = ($page > 0) ? $page : 1; + $rowCount = ($rowCount > 0) ? $rowCount : 1; + $this->_parts[self::LIMIT_COUNT] = (int) $rowCount; + $this->_parts[self::LIMIT_OFFSET] = (int) $rowCount * ($page - 1); + return $this; + } + + /** + * Makes the query SELECT FOR UPDATE. + * + * @param bool $flag Whether or not the SELECT is FOR UPDATE (default true). + * @return Zend_Db_Select This Zend_Db_Select object. + */ + public function forUpdate($flag = true) + { + $this->_parts[self::FOR_UPDATE] = (bool) $flag; + return $this; + } + + /** + * Get part of the structured information for the current query. + * + * @param string $part + * @return mixed + * @throws Zend_Db_Select_Exception + */ + public function getPart($part) + { + $part = strtolower($part); + if (!array_key_exists($part, $this->_parts)) { + throw new Zend_Db_Select_Exception("Invalid Select part '$part'"); + } + return $this->_parts[$part]; + } + + /** + * Executes the current select object and returns the result + * + * @param integer $fetchMode OPTIONAL + * @param mixed $bind An array of data to bind to the placeholders. + * @return PDO_Statement|Zend_Db_Statement + */ + public function query($fetchMode = null, $bind = array()) + { + if (!empty($bind)) { + $this->bind($bind); + } + + $stmt = $this->_adapter->query($this); + if ($fetchMode == null) { + $fetchMode = $this->_adapter->getFetchMode(); + } + $stmt->setFetchMode($fetchMode); + return $stmt; + } + + /** + * Converts this object to an SQL SELECT string. + * + * @return string|null This object as a SELECT string. (or null if a string cannot be produced.) + */ + public function assemble() + { + $sql = self::SQL_SELECT; + foreach (array_keys(self::$_partsInit) as $part) { + $method = '_render' . ucfirst($part); + if (method_exists($this, $method)) { + $sql = $this->$method($sql); + } + } + return $sql; + } + + /** + * Clear parts of the Select object, or an individual part. + * + * @param string $part OPTIONAL + * @return Zend_Db_Select + */ + public function reset($part = null) + { + if ($part == null) { + $this->_parts = self::$_partsInit; + } elseif (array_key_exists($part, self::$_partsInit)) { + $this->_parts[$part] = self::$_partsInit[$part]; + } + return $this; + } + + /** + * Gets the Zend_Db_Adapter_Abstract for this + * particular Zend_Db_Select object. + * + * @return Zend_Db_Adapter_Abstract + */ + public function getAdapter() + { + return $this->_adapter; + } + + /** + * Populate the {@link $_parts} 'join' key + * + * Does the dirty work of populating the join key. + * + * The $name and $cols parameters follow the same logic + * as described in the from() method. + * + * @param null|string $type Type of join; inner, left, and null are currently supported + * @param array|string|Zend_Db_Expr $name Table name + * @param string $cond Join on this condition + * @param array|string $cols The columns to select from the joined table + * @param string $schema The database name to specify, if any. + * @return Zend_Db_Select This Zend_Db_Select object + * @throws Zend_Db_Select_Exception + */ + protected function _join($type, $name, $cond, $cols, $schema = null) + { + if (!in_array($type, self::$_joinTypes) && $type != self::FROM) { + /** + * @see Zend_Db_Select_Exception + */ + throw new Zend_Db_Select_Exception("Invalid join type '$type'"); + } + + if (count($this->_parts[self::UNION])) { + throw new Zend_Db_Select_Exception("Invalid use of table with " . self::SQL_UNION); + } + + if (empty($name)) { + $correlationName = $tableName = ''; + } elseif (is_array($name)) { + // Must be array($correlationName => $tableName) or array($ident, ...) + foreach ($name as $_correlationName => $_tableName) { + if (is_string($_correlationName)) { + // We assume the key is the correlation name and value is the table name + $tableName = $_tableName; + $correlationName = $_correlationName; + } else { + // We assume just an array of identifiers, with no correlation name + $tableName = $_tableName; + $correlationName = $this->_uniqueCorrelation($tableName); + } + break; + } + } elseif ($name instanceof Zend_Db_Expr|| $name instanceof Zend_Db_Select) { + $tableName = $name; + $correlationName = $this->_uniqueCorrelation('t'); + } elseif (preg_match('/^(.+)\s+AS\s+(.+)$/i', $name, $m)) { + $tableName = $m[1]; + $correlationName = $m[2]; + } else { + $tableName = $name; + $correlationName = $this->_uniqueCorrelation($tableName); + } + + // Schema from table name overrides schema argument + if (!is_object($tableName) && false !== strpos($tableName, '.')) { + list($schema, $tableName) = explode('.', $tableName); + } + + $lastFromCorrelationName = null; + if (!empty($correlationName)) { + if (array_key_exists($correlationName, $this->_parts[self::FROM])) { + /** + * @see Zend_Db_Select_Exception + */ + throw new Zend_Db_Select_Exception("You cannot define a correlation name '$correlationName' more than once"); + } + + if ($type == self::FROM) { + // append this from after the last from joinType + $tmpFromParts = $this->_parts[self::FROM]; + $this->_parts[self::FROM] = array(); + // move all the froms onto the stack + while ($tmpFromParts) { + $currentCorrelationName = key($tmpFromParts); + if ($tmpFromParts[$currentCorrelationName]['joinType'] != self::FROM) { + break; + } + $lastFromCorrelationName = $currentCorrelationName; + $this->_parts[self::FROM][$currentCorrelationName] = array_shift($tmpFromParts); + } + } else { + $tmpFromParts = array(); + } + $this->_parts[self::FROM][$correlationName] = array( + 'joinType' => $type, + 'schema' => $schema, + 'tableName' => $tableName, + 'joinCondition' => $cond + ); + while ($tmpFromParts) { + $currentCorrelationName = key($tmpFromParts); + $this->_parts[self::FROM][$currentCorrelationName] = array_shift($tmpFromParts); + } + } + + // add to the columns from this joined table + if ($type == self::FROM && $lastFromCorrelationName == null) { + $lastFromCorrelationName = true; + } + $this->_tableCols($correlationName, $cols, $lastFromCorrelationName); + + return $this; + } + + /** + * Handle JOIN... USING... syntax + * + * This is functionality identical to the existing JOIN methods, however + * the join condition can be passed as a single column name. This method + * then completes the ON condition by using the same field for the FROM + * table and the JOIN table. + * + * + * $select = $db->select()->from('table1') + * ->joinUsing('table2', 'column1'); + * + * // SELECT * FROM table1 JOIN table2 ON table1.column1 = table2.column2 + * + * + * These joins are called by the developer simply by adding 'Using' to the + * method name. E.g. + * * joinUsing + * * joinInnerUsing + * * joinFullUsing + * * joinRightUsing + * * joinLeftUsing + * + * @return Zend_Db_Select This Zend_Db_Select object. + */ + public function _joinUsing($type, $name, $cond, $cols = '*', $schema = null) + { + if (empty($this->_parts[self::FROM])) { + throw new Zend_Db_Select_Exception("You can only perform a joinUsing after specifying a FROM table"); + } + + $join = $this->_adapter->quoteIdentifier(key($this->_parts[self::FROM]), true); + $from = $this->_adapter->quoteIdentifier($this->_uniqueCorrelation($name), true); + + $joinCond = array(); + foreach ((array)$cond as $fieldName) { + $cond1 = $from . '.' . $fieldName; + $cond2 = $join . '.' . $fieldName; + $joinCond[] = $cond1 . ' = ' . $cond2; + } + $cond = implode(' '.self::SQL_AND.' ', $joinCond); + + return $this->_join($type, $name, $cond, $cols, $schema); + } + + /** + * Generate a unique correlation name + * + * @param string|array $name A qualified identifier. + * @return string A unique correlation name. + */ + private function _uniqueCorrelation($name) + { + if (is_array($name)) { + $k = key($name); + $c = is_string($k) ? $k : end($name); + } else { + // Extract just the last name of a qualified table name + $dot = strrpos($name,'.'); + $c = ($dot === false) ? $name : substr($name, $dot+1); + } + for ($i = 2; array_key_exists($c, $this->_parts[self::FROM]); ++$i) { + $c = $name . '_' . (string) $i; + } + return $c; + } + + /** + * Adds to the internal table-to-column mapping array. + * + * @param string $tbl The table/join the columns come from. + * @param array|string $cols The list of columns; preferably as + * an array, but possibly as a string containing one column. + * @param bool|string True if it should be prepended, a correlation name if it should be inserted + * @return void + */ + protected function _tableCols($correlationName, $cols, $afterCorrelationName = null) + { + if (!is_array($cols)) { + $cols = array($cols); + } + + if ($correlationName == null) { + $correlationName = ''; + } + + $columnValues = array(); + + foreach (array_filter($cols) as $alias => $col) { + $currentCorrelationName = $correlationName; + if (is_string($col)) { + // Check for a column matching " AS " and extract the alias name + $col = trim(str_replace("\n", ' ', $col)); + if (preg_match('/^(.+)\s+' . self::SQL_AS . '\s+(.+)$/i', $col, $m)) { + $col = $m[1]; + $alias = $m[2]; + } + // Check for columns that look like functions and convert to Zend_Db_Expr + if (preg_match(self::REGEX_COLUMN_EXPR, (string) $col)) { + $col = new Zend_Db_Expr($col); + } elseif (preg_match('/(.+)\.(.+)/', $col, $m)) { + $currentCorrelationName = $m[1]; + $col = $m[2]; + } + } + $columnValues[] = array($currentCorrelationName, $col, is_string($alias) ? $alias : null); + } + + if ($columnValues) { + + // should we attempt to prepend or insert these values? + if ($afterCorrelationName === true || is_string($afterCorrelationName)) { + $tmpColumns = $this->_parts[self::COLUMNS]; + $this->_parts[self::COLUMNS] = array(); + } else { + $tmpColumns = array(); + } + + // find the correlation name to insert after + if (is_string($afterCorrelationName)) { + while ($tmpColumns) { + $this->_parts[self::COLUMNS][] = $currentColumn = array_shift($tmpColumns); + if ($currentColumn[0] == $afterCorrelationName) { + break; + } + } + } + + // apply current values to current stack + foreach ($columnValues as $columnValue) { + array_push($this->_parts[self::COLUMNS], $columnValue); + } + + // finish ensuring that all previous values are applied (if they exist) + while ($tmpColumns) { + array_push($this->_parts[self::COLUMNS], array_shift($tmpColumns)); + } + } + } + + /** + * Internal function for creating the where clause + * + * @param string $condition + * @param mixed $value optional + * @param string $type optional + * @param boolean $bool true = AND, false = OR + * @return string clause + */ + protected function _where($condition, $value = null, $type = null, $bool = true) + { + if (count($this->_parts[self::UNION])) { + throw new Zend_Db_Select_Exception("Invalid use of where clause with " . self::SQL_UNION); + } + + if ($value !== null) { + $condition = $this->_adapter->quoteInto($condition, $value, $type); + } + + $cond = ""; + if ($this->_parts[self::WHERE]) { + if ($bool === true) { + $cond = self::SQL_AND . ' '; + } else { + $cond = self::SQL_OR . ' '; + } + } + + return $cond . "($condition)"; + } + + /** + * @return array + */ + protected function _getDummyTable() + { + return array(); + } + + /** + * Return a quoted schema name + * + * @param string $schema The schema name OPTIONAL + * @return string|null + */ + protected function _getQuotedSchema($schema = null) + { + if ($schema === null) { + return null; + } + return $this->_adapter->quoteIdentifier($schema, true) . '.'; + } + + /** + * Return a quoted table name + * + * @param string $tableName The table name + * @param string $correlationName The correlation name OPTIONAL + * @return string + */ + protected function _getQuotedTable($tableName, $correlationName = null) + { + return $this->_adapter->quoteTableAs($tableName, $correlationName, true); + } + + /** + * Render DISTINCT clause + * + * @param string $sql SQL query + * @return string + */ + protected function _renderDistinct($sql) + { + if ($this->_parts[self::DISTINCT]) { + $sql .= ' ' . self::SQL_DISTINCT; + } + + return $sql; + } + + /** + * Render DISTINCT clause + * + * @param string $sql SQL query + * @return string|null + */ + protected function _renderColumns($sql) + { + if (!count($this->_parts[self::COLUMNS])) { + return null; + } + + $columns = array(); + foreach ($this->_parts[self::COLUMNS] as $columnEntry) { + list($correlationName, $column, $alias) = $columnEntry; + if ($column instanceof Zend_Db_Expr) { + $columns[] = $this->_adapter->quoteColumnAs($column, $alias, true); + } else { + if ($column == self::SQL_WILDCARD) { + $column = new Zend_Db_Expr(self::SQL_WILDCARD); + $alias = null; + } + if (empty($correlationName)) { + $columns[] = $this->_adapter->quoteColumnAs($column, $alias, true); + } else { + $columns[] = $this->_adapter->quoteColumnAs(array($correlationName, $column), $alias, true); + } + } + } + + return $sql . ' ' . implode(', ', $columns); + } + + /** + * Render FROM clause + * + * @param string $sql SQL query + * @return string + */ + protected function _renderFrom($sql) + { + /* + * If no table specified, use RDBMS-dependent solution + * for table-less query. e.g. DUAL in Oracle. + */ + if (empty($this->_parts[self::FROM])) { + $this->_parts[self::FROM] = $this->_getDummyTable(); + } + + $from = array(); + + foreach ($this->_parts[self::FROM] as $correlationName => $table) { + $tmp = ''; + + $joinType = ($table['joinType'] == self::FROM) ? self::INNER_JOIN : $table['joinType']; + + // Add join clause (if applicable) + if (! empty($from)) { + $tmp .= ' ' . strtoupper($joinType) . ' '; + } + + $tmp .= $this->_getQuotedSchema($table['schema']); + $tmp .= $this->_getQuotedTable($table['tableName'], $correlationName); + + // Add join conditions (if applicable) + if (!empty($from) && ! empty($table['joinCondition'])) { + $tmp .= ' ' . self::SQL_ON . ' ' . $table['joinCondition']; + } + + // Add the table name and condition add to the list + $from[] = $tmp; + } + + // Add the list of all joins + if (!empty($from)) { + $sql .= ' ' . self::SQL_FROM . ' ' . implode("\n", $from); + } + + return $sql; + } + + /** + * Render UNION query + * + * @param string $sql SQL query + * @return string + */ + protected function _renderUnion($sql) + { + if ($this->_parts[self::UNION]) { + $parts = count($this->_parts[self::UNION]); + foreach ($this->_parts[self::UNION] as $cnt => $union) { + list($target, $type) = $union; + if ($target instanceof Zend_Db_Select) { + $target = $target->assemble(); + } + $sql .= $target; + if ($cnt < $parts - 1) { + $sql .= ' ' . $type . ' '; + } + } + } + + return $sql; + } + + /** + * Render WHERE clause + * + * @param string $sql SQL query + * @return string + */ + protected function _renderWhere($sql) + { + if ($this->_parts[self::FROM] && $this->_parts[self::WHERE]) { + $sql .= ' ' . self::SQL_WHERE . ' ' . implode(' ', $this->_parts[self::WHERE]); + } + + return $sql; + } + + /** + * Render GROUP clause + * + * @param string $sql SQL query + * @return string + */ + protected function _renderGroup($sql) + { + if ($this->_parts[self::FROM] && $this->_parts[self::GROUP]) { + $group = array(); + foreach ($this->_parts[self::GROUP] as $term) { + $group[] = $this->_adapter->quoteIdentifier($term, true); + } + $sql .= ' ' . self::SQL_GROUP_BY . ' ' . implode(",\n\t", $group); + } + + return $sql; + } + + /** + * Render HAVING clause + * + * @param string $sql SQL query + * @return string + */ + protected function _renderHaving($sql) + { + if ($this->_parts[self::FROM] && $this->_parts[self::HAVING]) { + $sql .= ' ' . self::SQL_HAVING . ' ' . implode(' ', $this->_parts[self::HAVING]); + } + + return $sql; + } + + /** + * Render ORDER clause + * + * @param string $sql SQL query + * @return string + */ + protected function _renderOrder($sql) + { + if ($this->_parts[self::ORDER]) { + $order = array(); + foreach ($this->_parts[self::ORDER] as $term) { + if (is_array($term)) { + if(is_numeric($term[0]) && strval(intval($term[0])) == $term[0]) { + $order[] = (int)trim($term[0]) . ' ' . $term[1]; + } else { + $order[] = $this->_adapter->quoteIdentifier($term[0], true) . ' ' . $term[1]; + } + } elseif (is_numeric($term) && strval(intval($term)) == $term) { + $order[] = (int)trim($term); + } else { + $order[] = $this->_adapter->quoteIdentifier($term, true); + } + } + $sql .= ' ' . self::SQL_ORDER_BY . ' ' . implode(', ', $order); + } + + return $sql; + } + + /** + * Render LIMIT OFFSET clause + * + * @param string $sql SQL query + * @return string + */ + protected function _renderLimitoffset($sql) + { + $count = 0; + $offset = 0; + + if (!empty($this->_parts[self::LIMIT_OFFSET])) { + $offset = (int) $this->_parts[self::LIMIT_OFFSET]; + $count = PHP_INT_MAX; + } + + if (!empty($this->_parts[self::LIMIT_COUNT])) { + $count = (int) $this->_parts[self::LIMIT_COUNT]; + } + + /* + * Add limits clause + */ + if ($count > 0) { + $sql = trim($this->_adapter->limit($sql, $count, $offset)); + } + + return $sql; + } + + /** + * Render FOR UPDATE clause + * + * @param string $sql SQL query + * @return string + */ + protected function _renderForupdate($sql) + { + if ($this->_parts[self::FOR_UPDATE]) { + $sql .= ' ' . self::SQL_FOR_UPDATE; + } + + return $sql; + } + + /** + * Turn magic function calls into non-magic function calls + * for joinUsing syntax + * + * @param string $method + * @param array $args OPTIONAL Zend_Db_Table_Select query modifier + * @return Zend_Db_Select + * @throws Zend_Db_Select_Exception If an invalid method is called. + */ + public function __call($method, array $args) + { + $matches = array(); + + /** + * Recognize methods for Has-Many cases: + * findParent() + * findParentBy() + * Use the non-greedy pattern repeat modifier e.g. \w+? + */ + if (preg_match('/^join([a-zA-Z]*?)Using$/', $method, $matches)) { + $type = strtolower($matches[1]); + if ($type) { + $type .= ' join'; + if (!in_array($type, self::$_joinTypes)) { + throw new Zend_Db_Select_Exception("Unrecognized method '$method()'"); + } + if (in_array($type, array(self::CROSS_JOIN, self::NATURAL_JOIN))) { + throw new Zend_Db_Select_Exception("Cannot perform a joinUsing with method '$method()'"); + } + } else { + $type = self::INNER_JOIN; + } + array_unshift($args, $type); + return call_user_func_array(array($this, '_joinUsing'), $args); + } + + throw new Zend_Db_Select_Exception("Unrecognized method '$method()'"); + } + + /** + * Implements magic method. + * + * @return string This object as a SELECT string. + */ + public function __toString() + { + try { + $sql = $this->assemble(); + } catch (Exception $e) { + trigger_error($e->getMessage(), E_USER_WARNING); + $sql = ''; + } + return (string)$sql; + } + +} diff --git a/library/vendor/Zend/Db/Select/Exception.php b/library/vendor/Zend/Db/Select/Exception.php new file mode 100644 index 0000000..6e7bfac --- /dev/null +++ b/library/vendor/Zend/Db/Select/Exception.php @@ -0,0 +1,38 @@ +_adapter = $adapter; + if ($sql instanceof Zend_Db_Select) { + $sql = $sql->assemble(); + } + $this->_parseParameters($sql); + $this->_prepare($sql); + + $this->_queryId = $this->_adapter->getProfiler()->queryStart($sql); + } + + /** + * Internal method called by abstract statment constructor to setup + * the driver level statement + * + * @return void + */ + protected function _prepare($sql) + { + return; + } + + /** + * @param string $sql + * @return void + */ + protected function _parseParameters($sql) + { + $sql = $this->_stripQuoted($sql); + + // split into text and params + $this->_sqlSplit = empty($sql) ? [] : preg_split('/(\?|\:[a-zA-Z0-9_]+)/', + $sql, -1, PREG_SPLIT_DELIM_CAPTURE|PREG_SPLIT_NO_EMPTY); + + // map params + $this->_sqlParam = array(); + foreach ($this->_sqlSplit as $key => $val) { + if ($val == '?') { + if ($this->_adapter->supportsParameters('positional') === false) { + /** + * @see Zend_Db_Statement_Exception + */ + throw new Zend_Db_Statement_Exception("Invalid bind-variable position '$val'"); + } + } else if ($val[0] == ':') { + if ($this->_adapter->supportsParameters('named') === false) { + /** + * @see Zend_Db_Statement_Exception + */ + throw new Zend_Db_Statement_Exception("Invalid bind-variable name '$val'"); + } + } + $this->_sqlParam[] = $val; + } + + // set up for binding + $this->_bindParam = array(); + } + + /** + * Remove parts of a SQL string that contain quoted strings + * of values or identifiers. + * + * @param string $sql + * @return string + */ + protected function _stripQuoted($sql) + { + + // get the character for value quoting + // this should be ' + $q = $this->_adapter->quote('a'); + $q = $q[0]; + // get the value used as an escaped quote, + // e.g. \' or '' + $qe = $this->_adapter->quote($q); + $qe = substr($qe, 1, 2); + $qe = preg_quote($qe); + $escapeChar = substr($qe,0,1); + // remove 'foo\'bar' + if (!empty($q)) { + $escapeChar = preg_quote($escapeChar); + if ($sql !== null) { + // this segfaults only after 65,000 characters instead of 9,000 + $sql = preg_replace("/$q([^$q{$escapeChar}]*|($qe)*)*$q/s", '', $sql); + } + } + + // get a version of the SQL statement with all quoted + // values and delimited identifiers stripped out + // remove "foo\"bar" + if ($sql !== null) { + $sql = preg_replace("/\"(\\\\\"|[^\"])*\"/Us", '', $sql); + } + + // get the character for delimited id quotes, + // this is usually " but in MySQL is ` + $d = $this->_adapter->quoteIdentifier('a'); + $d = $d[0]; + // get the value used as an escaped delimited id quote, + // e.g. \" or "" or \` + $de = $this->_adapter->quoteIdentifier($d); + $de = substr($de, 1, 2); + $de = preg_quote($de); + // Note: $de and $d where never used..., now they are: + if ($sql !== null) { + $sql = preg_replace("/$d($de|\\\\{2}|[^$d])*$d/Us", '', $sql); + } + + return $sql; + } + + /** + * Bind a column of the statement result set to a PHP variable. + * + * @param string $column Name the column in the result set, either by + * position or by name. + * @param mixed $param Reference to the PHP variable containing the value. + * @param mixed $type OPTIONAL + * @return bool + */ + public function bindColumn($column, &$param, $type = null) + { + $this->_bindColumn[$column] =& $param; + return true; + } + + /** + * Binds a parameter to the specified variable name. + * + * @param mixed $parameter Name the parameter, either integer or string. + * @param mixed $variable Reference to PHP variable containing the value. + * @param mixed $type OPTIONAL Datatype of SQL parameter. + * @param mixed $length OPTIONAL Length of SQL parameter. + * @param mixed $options OPTIONAL Other options. + * @return bool + */ + public function bindParam($parameter, &$variable, $type = null, $length = null, $options = null) + { + if (!is_int($parameter) && !is_string($parameter)) { + /** + * @see Zend_Db_Statement_Exception + */ + throw new Zend_Db_Statement_Exception('Invalid bind-variable position'); + } + + $position = null; + if (($intval = (int) $parameter) > 0 && $this->_adapter->supportsParameters('positional')) { + if ($intval >= 1 || $intval <= count($this->_sqlParam)) { + $position = $intval; + } + } else if ($this->_adapter->supportsParameters('named')) { + if ($parameter[0] != ':') { + $parameter = ':' . $parameter; + } + if (in_array($parameter, $this->_sqlParam) !== false) { + $position = $parameter; + } + } + + if ($position === null) { + /** + * @see Zend_Db_Statement_Exception + */ + throw new Zend_Db_Statement_Exception("Invalid bind-variable position '$parameter'"); + } + + // Finally we are assured that $position is valid + $this->_bindParam[$position] =& $variable; + return $this->_bindParam($position, $variable, $type, $length, $options); + } + + /** + * Binds a value to a parameter. + * + * @param mixed $parameter Name the parameter, either integer or string. + * @param mixed $value Scalar value to bind to the parameter. + * @param mixed $type OPTIONAL Datatype of the parameter. + * @return bool + */ + public function bindValue($parameter, $value, $type = null) + { + return $this->bindParam($parameter, $value, $type); + } + + /** + * Executes a prepared statement. + * + * @param array $params OPTIONAL Values to bind to parameter placeholders. + * @return bool + */ + public function execute(array $params = null) + { + /* + * Simple case - no query profiler to manage. + */ + if ($this->_queryId === null) { + return $this->_execute($params); + } + + /* + * Do the same thing, but with query profiler + * management before and after the execute. + */ + $prof = $this->_adapter->getProfiler(); + $qp = $prof->getQueryProfile($this->_queryId); + if ($qp->hasEnded()) { + $this->_queryId = $prof->queryClone($qp); + $qp = $prof->getQueryProfile($this->_queryId); + } + if ($params !== null) { + $qp->bindParams($params); + } else { + $qp->bindParams($this->_bindParam); + } + $qp->start($this->_queryId); + + $retval = $this->_execute($params); + + $prof->queryEnd($this->_queryId); + + return $retval; + } + + /** + * Returns an array containing all of the result set rows. + * + * @param int $style OPTIONAL Fetch mode. + * @param int $col OPTIONAL Column number, if fetch mode is by column. + * @return array Collection of rows, each in a format by the fetch mode. + */ + public function fetchAll($style = null, $col = null) + { + $data = array(); + if ($style === Zend_Db::FETCH_COLUMN && $col === null) { + $col = 0; + } + if ($col === null) { + while ($row = $this->fetch($style)) { + $data[] = $row; + } + } else { + while (false !== ($val = $this->fetchColumn($col))) { + $data[] = $val; + } + } + return $data; + } + + /** + * Returns a single column from the next row of a result set. + * + * @param int $col OPTIONAL Position of the column to fetch. + * @return string One value from the next row of result set, or false. + */ + public function fetchColumn($col = 0) + { + $data = array(); + $col = (int) $col; + $row = $this->fetch(Zend_Db::FETCH_NUM); + if (!is_array($row)) { + return false; + } + return $row[$col]; + } + + /** + * Fetches the next row and returns it as an object. + * + * @param string $class OPTIONAL Name of the class to create. + * @param array $config OPTIONAL Constructor arguments for the class. + * @return mixed One object instance of the specified class, or false. + */ + public function fetchObject($class = 'stdClass', array $config = array()) + { + $obj = new $class($config); + $row = $this->fetch(Zend_Db::FETCH_ASSOC); + if (!is_array($row)) { + return false; + } + foreach ($row as $key => $val) { + $obj->$key = $val; + } + return $obj; + } + + /** + * Retrieve a statement attribute. + * + * @param string $key Attribute name. + * @return mixed Attribute value. + */ + public function getAttribute($key) + { + if (array_key_exists($key, $this->_attribute)) { + return $this->_attribute[$key]; + } + } + + /** + * Set a statement attribute. + * + * @param string $key Attribute name. + * @param mixed $val Attribute value. + * @return bool + */ + public function setAttribute($key, $val) + { + $this->_attribute[$key] = $val; + } + + /** + * Set the default fetch mode for this statement. + * + * @param int $mode The fetch mode. + * @return bool + * @throws Zend_Db_Statement_Exception + */ + public function setFetchMode($mode) + { + switch ($mode) { + case Zend_Db::FETCH_NUM: + case Zend_Db::FETCH_ASSOC: + case Zend_Db::FETCH_BOTH: + case Zend_Db::FETCH_OBJ: + $this->_fetchMode = $mode; + break; + case Zend_Db::FETCH_BOUND: + default: + $this->closeCursor(); + /** + * @see Zend_Db_Statement_Exception + */ + throw new Zend_Db_Statement_Exception('invalid fetch mode'); + break; + } + } + + /** + * Helper function to map retrieved row + * to bound column variables + * + * @param array $row + * @return bool True + */ + public function _fetchBound($row) + { + foreach ($row as $key => $value) { + // bindColumn() takes 1-based integer positions + // but fetch() returns 0-based integer indexes + if (is_int($key)) { + $key++; + } + // set results only to variables that were bound previously + if (isset($this->_bindColumn[$key])) { + $this->_bindColumn[$key] = $value; + } + } + return true; + } + + /** + * Gets the Zend_Db_Adapter_Abstract for this + * particular Zend_Db_Statement object. + * + * @return Zend_Db_Adapter_Abstract + */ + public function getAdapter() + { + return $this->_adapter; + } + + /** + * Gets the resource or object setup by the + * _parse + * @return unknown_type + */ + public function getDriverStatement() + { + return $this->_stmt; + } +} diff --git a/library/vendor/Zend/Db/Statement/Db2.php b/library/vendor/Zend/Db/Statement/Db2.php new file mode 100644 index 0000000..b817864 --- /dev/null +++ b/library/vendor/Zend/Db/Statement/Db2.php @@ -0,0 +1,354 @@ +_adapter->getConnection(); + + // db2_prepare on i5 emits errors, these need to be + // suppressed so that proper exceptions can be thrown + $this->_stmt = @db2_prepare($connection, $sql); + + if (!$this->_stmt) { + /** + * @see Zend_Db_Statement_Db2_Exception + */ + throw new Zend_Db_Statement_Db2_Exception( + db2_stmt_errormsg(), + db2_stmt_error() + ); + } + } + + /** + * Binds a parameter to the specified variable name. + * + * @param mixed $parameter Name the parameter, either integer or string. + * @param mixed $variable Reference to PHP variable containing the value. + * @param mixed $type OPTIONAL Datatype of SQL parameter. + * @param mixed $length OPTIONAL Length of SQL parameter. + * @param mixed $options OPTIONAL Other options. + * @return bool + * @throws Zend_Db_Statement_Db2_Exception + */ + public function _bindParam($parameter, &$variable, $type = null, $length = null, $options = null) + { + if ($type === null) { + $type = DB2_PARAM_IN; + } + + if (isset($options['data-type'])) { + $datatype = $options['data-type']; + } else { + $datatype = DB2_CHAR; + } + + if (!db2_bind_param($this->_stmt, $parameter, "variable", $type, $datatype)) { + /** + * @see Zend_Db_Statement_Db2_Exception + */ + throw new Zend_Db_Statement_Db2_Exception( + db2_stmt_errormsg(), + db2_stmt_error() + ); + } + + return true; + } + + /** + * Closes the cursor, allowing the statement to be executed again. + * + * @return bool + */ + public function closeCursor() + { + if (!$this->_stmt) { + return false; + } + db2_free_stmt($this->_stmt); + $this->_stmt = false; + return true; + } + + + /** + * Returns the number of columns in the result set. + * Returns null if the statement has no result set metadata. + * + * @return int The number of columns. + */ + public function columnCount() + { + if (!$this->_stmt) { + return false; + } + return db2_num_fields($this->_stmt); + } + + /** + * Retrieves the error code, if any, associated with the last operation on + * the statement handle. + * + * @return string error code. + */ + public function errorCode() + { + if (!$this->_stmt) { + return false; + } + + $error = db2_stmt_error(); + if ($error === '') { + return false; + } + + return $error; + } + + /** + * Retrieves an array of error information, if any, associated with the + * last operation on the statement handle. + * + * @return array + */ + public function errorInfo() + { + $error = $this->errorCode(); + if ($error === false){ + return false; + } + + /* + * Return three-valued array like PDO. But DB2 does not distinguish + * between SQLCODE and native RDBMS error code, so repeat the SQLCODE. + */ + return array( + $error, + $error, + db2_stmt_errormsg() + ); + } + + /** + * Executes a prepared statement. + * + * @param array $params OPTIONAL Values to bind to parameter placeholders. + * @return bool + * @throws Zend_Db_Statement_Db2_Exception + */ + public function _execute(array $params = null) + { + if (!$this->_stmt) { + return false; + } + + $retval = true; + if ($params !== null) { + $retval = @db2_execute($this->_stmt, $params); + } else { + $retval = @db2_execute($this->_stmt); + } + + if ($retval === false) { + /** + * @see Zend_Db_Statement_Db2_Exception + */ + throw new Zend_Db_Statement_Db2_Exception( + db2_stmt_errormsg(), + db2_stmt_error()); + } + + $this->_keys = array(); + if ($field_num = $this->columnCount()) { + for ($i = 0; $i < $field_num; $i++) { + $name = db2_field_name($this->_stmt, $i); + $this->_keys[] = $name; + } + } + + $this->_values = array(); + if ($this->_keys) { + $this->_values = array_fill(0, count($this->_keys), null); + } + + return $retval; + } + + /** + * Fetches a row from the result set. + * + * @param int $style OPTIONAL Fetch mode for this fetch operation. + * @param int $cursor OPTIONAL Absolute, relative, or other. + * @param int $offset OPTIONAL Number for absolute or relative cursors. + * @return mixed Array, object, or scalar depending on fetch mode. + * @throws Zend_Db_Statement_Db2_Exception + */ + public function fetch($style = null, $cursor = null, $offset = null) + { + if (!$this->_stmt) { + return false; + } + + if ($style === null) { + $style = $this->_fetchMode; + } + + switch ($style) { + case Zend_Db::FETCH_NUM : + $row = db2_fetch_array($this->_stmt); + break; + case Zend_Db::FETCH_ASSOC : + $row = db2_fetch_assoc($this->_stmt); + break; + case Zend_Db::FETCH_BOTH : + $row = db2_fetch_both($this->_stmt); + break; + case Zend_Db::FETCH_OBJ : + $row = db2_fetch_object($this->_stmt); + break; + case Zend_Db::FETCH_BOUND: + $row = db2_fetch_both($this->_stmt); + if ($row !== false) { + return $this->_fetchBound($row); + } + break; + default: + /** + * @see Zend_Db_Statement_Db2_Exception + */ + throw new Zend_Db_Statement_Db2_Exception("Invalid fetch mode '$style' specified"); + break; + } + + return $row; + } + + /** + * Fetches the next row and returns it as an object. + * + * @param string $class OPTIONAL Name of the class to create. + * @param array $config OPTIONAL Constructor arguments for the class. + * @return mixed One object instance of the specified class. + */ + public function fetchObject($class = 'stdClass', array $config = array()) + { + $obj = $this->fetch(Zend_Db::FETCH_OBJ); + return $obj; + } + + /** + * Retrieves the next rowset (result set) for a SQL statement that has + * multiple result sets. An example is a stored procedure that returns + * the results of multiple queries. + * + * @return bool + * @throws Zend_Db_Statement_Db2_Exception + */ + public function nextRowset() + { + /** + * @see Zend_Db_Statement_Db2_Exception + */ + throw new Zend_Db_Statement_Db2_Exception(__FUNCTION__ . '() is not implemented'); + } + + /** + * Returns the number of rows affected by the execution of the + * last INSERT, DELETE, or UPDATE statement executed by this + * statement object. + * + * @return int The number of rows affected. + */ + public function rowCount() + { + if (!$this->_stmt) { + return false; + } + + $num = @db2_num_rows($this->_stmt); + + if ($num === false) { + return 0; + } + + return $num; + } + + /** + * Returns an array containing all of the result set rows. + * + * @param int $style OPTIONAL Fetch mode. + * @param int $col OPTIONAL Column number, if fetch mode is by column. + * @return array Collection of rows, each in a format by the fetch mode. + * + * Behaves like parent, but if limit() + * is used, the final result removes the extra column + * 'zend_db_rownum' + */ + public function fetchAll($style = null, $col = null) + { + $data = parent::fetchAll($style, $col); + $results = array(); + $remove = $this->_adapter->foldCase('ZEND_DB_ROWNUM'); + + foreach ($data as $row) { + if (is_array($row) && array_key_exists($remove, $row)) { + unset($row[$remove]); + } + $results[] = $row; + } + return $results; + } +} diff --git a/library/vendor/Zend/Db/Statement/Db2/Exception.php b/library/vendor/Zend/Db/Statement/Db2/Exception.php new file mode 100644 index 0000000..d598a85 --- /dev/null +++ b/library/vendor/Zend/Db/Statement/Db2/Exception.php @@ -0,0 +1,57 @@ +message = $msg; + $this->code = $state; + } + +} + diff --git a/library/vendor/Zend/Db/Statement/Exception.php b/library/vendor/Zend/Db/Statement/Exception.php new file mode 100644 index 0000000..af58699 --- /dev/null +++ b/library/vendor/Zend/Db/Statement/Exception.php @@ -0,0 +1,55 @@ +getPrevious() !== null); + } + + /** + * @return Exception|null + */ + public function getChainedException() + { + return $this->getPrevious(); + } +} diff --git a/library/vendor/Zend/Db/Statement/Interface.php b/library/vendor/Zend/Db/Statement/Interface.php new file mode 100644 index 0000000..7154d91 --- /dev/null +++ b/library/vendor/Zend/Db/Statement/Interface.php @@ -0,0 +1,203 @@ +_adapter->getConnection(); + + $this->_stmt = $mysqli->prepare($sql); + + if ($this->_stmt === false || $mysqli->errno) { + /** + * @see Zend_Db_Statement_Mysqli_Exception + */ + throw new Zend_Db_Statement_Mysqli_Exception("Mysqli prepare error: " . $mysqli->error, $mysqli->errno); + } + } + + /** + * Binds a parameter to the specified variable name. + * + * @param mixed $parameter Name the parameter, either integer or string. + * @param mixed $variable Reference to PHP variable containing the value. + * @param mixed $type OPTIONAL Datatype of SQL parameter. + * @param mixed $length OPTIONAL Length of SQL parameter. + * @param mixed $options OPTIONAL Other options. + * @return bool + * @throws Zend_Db_Statement_Mysqli_Exception + */ + protected function _bindParam($parameter, &$variable, $type = null, $length = null, $options = null) + { + return true; + } + + /** + * Closes the cursor and the statement. + * + * @return bool + */ + public function close() + { + if ($this->_stmt) { + $r = $this->_stmt->close(); + $this->_stmt = null; + return $r; + } + return false; + } + + /** + * Closes the cursor, allowing the statement to be executed again. + * + * @return bool + */ + public function closeCursor() + { + if ($stmt = $this->_stmt) { + $mysqli = $this->_adapter->getConnection(); + while ($mysqli->more_results()) { + $mysqli->next_result(); + } + $this->_stmt->free_result(); + return $this->_stmt->reset(); + } + return false; + } + + /** + * Returns the number of columns in the result set. + * Returns null if the statement has no result set metadata. + * + * @return int The number of columns. + */ + public function columnCount() + { + if (isset($this->_meta) && $this->_meta) { + return $this->_meta->field_count; + } + return 0; + } + + /** + * Retrieves the error code, if any, associated with the last operation on + * the statement handle. + * + * @return string error code. + */ + public function errorCode() + { + if (!$this->_stmt) { + return false; + } + return substr($this->_stmt->sqlstate, 0, 5); + } + + /** + * Retrieves an array of error information, if any, associated with the + * last operation on the statement handle. + * + * @return array + */ + public function errorInfo() + { + if (!$this->_stmt) { + return false; + } + return array( + substr($this->_stmt->sqlstate, 0, 5), + $this->_stmt->errno, + $this->_stmt->error, + ); + } + + /** + * Executes a prepared statement. + * + * @param array $params OPTIONAL Values to bind to parameter placeholders. + * @return bool + * @throws Zend_Db_Statement_Mysqli_Exception + */ + public function _execute(array $params = null) + { + if (!$this->_stmt) { + return false; + } + + // if no params were given as an argument to execute(), + // then default to the _bindParam array + if ($params === null) { + $params = $this->_bindParam; + } + // send $params as input parameters to the statement + if ($params) { + array_unshift($params, str_repeat('s', count($params))); + $stmtParams = array(); + foreach ($params as $k => &$value) { + $stmtParams[$k] = &$value; + } + call_user_func_array( + array($this->_stmt, 'bind_param'), + $stmtParams + ); + } + + // execute the statement + $retval = $this->_stmt->execute(); + if ($retval === false) { + /** + * @see Zend_Db_Statement_Mysqli_Exception + */ + throw new Zend_Db_Statement_Mysqli_Exception("Mysqli statement execute error : " . $this->_stmt->error, $this->_stmt->errno); + } + + + // retain metadata + if ($this->_meta === null) { + $this->_meta = $this->_stmt->result_metadata(); + if ($this->_stmt->errno) { + /** + * @see Zend_Db_Statement_Mysqli_Exception + */ + throw new Zend_Db_Statement_Mysqli_Exception("Mysqli statement metadata error: " . $this->_stmt->error, $this->_stmt->errno); + } + } + + // statements that have no result set do not return metadata + if ($this->_meta !== false) { + + // get the column names that will result + $this->_keys = array(); + foreach ($this->_meta->fetch_fields() as $col) { + $this->_keys[] = $this->_adapter->foldCase($col->name); + } + + // set up a binding space for result variables + $this->_values = array_fill(0, count($this->_keys), null); + + // set up references to the result binding space. + // just passing $this->_values in the call_user_func_array() + // below won't work, you need references. + $refs = array(); + foreach ($this->_values as $i => &$f) { + $refs[$i] = &$f; + } + + $this->_stmt->store_result(); + // bind to the result variables + call_user_func_array( + array($this->_stmt, 'bind_result'), + $this->_values + ); + } + return $retval; + } + + + /** + * Fetches a row from the result set. + * + * @param int $style OPTIONAL Fetch mode for this fetch operation. + * @param int $cursor OPTIONAL Absolute, relative, or other. + * @param int $offset OPTIONAL Number for absolute or relative cursors. + * @return mixed Array, object, or scalar depending on fetch mode. + * @throws Zend_Db_Statement_Mysqli_Exception + */ + public function fetch($style = null, $cursor = null, $offset = null) + { + if (!$this->_stmt) { + return false; + } + // fetch the next result + $retval = $this->_stmt->fetch(); + switch ($retval) { + case null: // end of data + case false: // error occurred + $this->_stmt->reset(); + return false; + default: + // fallthrough + } + + // make sure we have a fetch mode + if ($style === null) { + $style = $this->_fetchMode; + } + + // dereference the result values, otherwise things like fetchAll() + // return the same values for every entry (because of the reference). + $values = array(); + foreach ($this->_values as $key => $val) { + $values[] = $val; + } + + $row = false; + switch ($style) { + case Zend_Db::FETCH_NUM: + $row = $values; + break; + case Zend_Db::FETCH_ASSOC: + $row = array_combine($this->_keys, $values); + break; + case Zend_Db::FETCH_BOTH: + $assoc = array_combine($this->_keys, $values); + $row = array_merge($values, $assoc); + break; + case Zend_Db::FETCH_OBJ: + $row = (object) array_combine($this->_keys, $values); + break; + case Zend_Db::FETCH_BOUND: + $assoc = array_combine($this->_keys, $values); + $row = array_merge($values, $assoc); + return $this->_fetchBound($row); + break; + default: + /** + * @see Zend_Db_Statement_Mysqli_Exception + */ + throw new Zend_Db_Statement_Mysqli_Exception("Invalid fetch mode '$style' specified"); + break; + } + return $row; + } + + /** + * Retrieves the next rowset (result set) for a SQL statement that has + * multiple result sets. An example is a stored procedure that returns + * the results of multiple queries. + * + * @return bool + * @throws Zend_Db_Statement_Mysqli_Exception + */ + public function nextRowset() + { + /** + * @see Zend_Db_Statement_Mysqli_Exception + */ + throw new Zend_Db_Statement_Mysqli_Exception(__FUNCTION__.'() is not implemented'); + } + + /** + * Returns the number of rows affected by the execution of the + * last INSERT, DELETE, or UPDATE statement executed by this + * statement object. + * + * @return int The number of rows affected. + */ + public function rowCount() + { + if (!$this->_adapter) { + return false; + } + $mysqli = $this->_adapter->getConnection(); + return $mysqli->affected_rows; + } + +} diff --git a/library/vendor/Zend/Db/Statement/Mysqli/Exception.php b/library/vendor/Zend/Db/Statement/Mysqli/Exception.php new file mode 100644 index 0000000..89c74ec --- /dev/null +++ b/library/vendor/Zend/Db/Statement/Mysqli/Exception.php @@ -0,0 +1,37 @@ +_lobAsString = (bool) $lob_as_string; + return $this; + } + + /** + * Return whether or not LOB are returned as string + * + * @return boolean + */ + public function getLobAsString() + { + return $this->_lobAsString; + } + + /** + * Prepares statement handle + * + * @param string $sql + * @return void + * @throws Zend_Db_Statement_Oracle_Exception + */ + protected function _prepare($sql) + { + $connection = $this->_adapter->getConnection(); + $this->_stmt = @oci_parse($connection, $sql); + if (!$this->_stmt) { + /** + * @see Zend_Db_Statement_Oracle_Exception + */ + throw new Zend_Db_Statement_Oracle_Exception(oci_error($connection)); + } + } + + /** + * Binds a parameter to the specified variable name. + * + * @param mixed $parameter Name the parameter, either integer or string. + * @param mixed $variable Reference to PHP variable containing the value. + * @param mixed $type OPTIONAL Datatype of SQL parameter. + * @param mixed $length OPTIONAL Length of SQL parameter. + * @param mixed $options OPTIONAL Other options. + * @return bool + * @throws Zend_Db_Statement_Exception + */ + protected function _bindParam($parameter, &$variable, $type = null, $length = null, $options = null) + { + // default value + if ($type === NULL) { + $type = SQLT_CHR; + } + + // default value + if ($length === NULL) { + $length = -1; + } + + $retval = @oci_bind_by_name($this->_stmt, $parameter, $variable, $length, $type); + if ($retval === false) { + /** + * @see Zend_Db_Adapter_Oracle_Exception + */ + throw new Zend_Db_Statement_Oracle_Exception(oci_error($this->_stmt)); + } + + return true; + } + + /** + * Closes the cursor, allowing the statement to be executed again. + * + * @return bool + */ + public function closeCursor() + { + if (!$this->_stmt) { + return false; + } + + oci_free_statement($this->_stmt); + $this->_stmt = false; + return true; + } + + /** + * Returns the number of columns in the result set. + * Returns null if the statement has no result set metadata. + * + * @return int The number of columns. + */ + public function columnCount() + { + if (!$this->_stmt) { + return false; + } + + return oci_num_fields($this->_stmt); + } + + + /** + * Retrieves the error code, if any, associated with the last operation on + * the statement handle. + * + * @return string error code. + */ + public function errorCode() + { + if (!$this->_stmt) { + return false; + } + + $error = oci_error($this->_stmt); + + if (!$error) { + return false; + } + + return $error['code']; + } + + + /** + * Retrieves an array of error information, if any, associated with the + * last operation on the statement handle. + * + * @return array + */ + public function errorInfo() + { + if (!$this->_stmt) { + return false; + } + + $error = oci_error($this->_stmt); + if (!$error) { + return false; + } + + if (isset($error['sqltext'])) { + return array( + $error['code'], + $error['message'], + $error['offset'], + $error['sqltext'], + ); + } else { + return array( + $error['code'], + $error['message'], + ); + } + } + + + /** + * Executes a prepared statement. + * + * @param array $params OPTIONAL Values to bind to parameter placeholders. + * @return bool + * @throws Zend_Db_Statement_Exception + */ + public function _execute(array $params = null) + { + $connection = $this->_adapter->getConnection(); + + if (!$this->_stmt) { + return false; + } + + if ($params !== null) { + if (!is_array($params)) { + $params = array($params); + } + $error = false; + foreach (array_keys($params) as $name) { + if (!$this->bindParam($name, $params[$name], null, -1)) { + $error = true; + break; + } + } + if ($error) { + /** + * @see Zend_Db_Adapter_Oracle_Exception + */ + throw new Zend_Db_Statement_Oracle_Exception(oci_error($this->_stmt)); + } + } + + $retval = @oci_execute($this->_stmt, $this->_adapter->_getExecuteMode()); + if ($retval === false) { + /** + * @see Zend_Db_Adapter_Oracle_Exception + */ + throw new Zend_Db_Statement_Oracle_Exception(oci_error($this->_stmt)); + } + + $this->_keys = Array(); + if ($field_num = oci_num_fields($this->_stmt)) { + for ($i = 1; $i <= $field_num; $i++) { + $name = oci_field_name($this->_stmt, $i); + $this->_keys[] = $name; + } + } + + $this->_values = Array(); + if ($this->_keys) { + $this->_values = array_fill(0, count($this->_keys), null); + } + + return $retval; + } + + /** + * Fetches a row from the result set. + * + * @param int $style OPTIONAL Fetch mode for this fetch operation. + * @param int $cursor OPTIONAL Absolute, relative, or other. + * @param int $offset OPTIONAL Number for absolute or relative cursors. + * @return mixed Array, object, or scalar depending on fetch mode. + * @throws Zend_Db_Statement_Exception + */ + public function fetch($style = null, $cursor = null, $offset = null) + { + if (!$this->_stmt) { + return false; + } + + if ($style === null) { + $style = $this->_fetchMode; + } + + $lob_as_string = $this->getLobAsString() ? OCI_RETURN_LOBS : 0; + + switch ($style) { + case Zend_Db::FETCH_NUM: + $row = oci_fetch_array($this->_stmt, OCI_NUM | OCI_RETURN_NULLS | $lob_as_string); + break; + case Zend_Db::FETCH_ASSOC: + $row = oci_fetch_array($this->_stmt, OCI_ASSOC | OCI_RETURN_NULLS | $lob_as_string); + break; + case Zend_Db::FETCH_BOTH: + $row = oci_fetch_array($this->_stmt, OCI_BOTH | OCI_RETURN_NULLS | $lob_as_string); + break; + case Zend_Db::FETCH_OBJ: + $row = oci_fetch_object($this->_stmt); + break; + case Zend_Db::FETCH_BOUND: + $row = oci_fetch_array($this->_stmt, OCI_BOTH | OCI_RETURN_NULLS | $lob_as_string); + if ($row !== false) { + return $this->_fetchBound($row); + } + break; + default: + /** + * @see Zend_Db_Adapter_Oracle_Exception + */ + throw new Zend_Db_Statement_Oracle_Exception( + array( + 'code' => 'HYC00', + 'message' => "Invalid fetch mode '$style' specified" + ) + ); + break; + } + + if (! $row && $error = oci_error($this->_stmt)) { + /** + * @see Zend_Db_Adapter_Oracle_Exception + */ + throw new Zend_Db_Statement_Oracle_Exception($error); + } + + if (is_array($row) && array_key_exists('zend_db_rownum', $row)) { + unset($row['zend_db_rownum']); + } + + return $row; + } + + /** + * Returns an array containing all of the result set rows. + * + * @param int $style OPTIONAL Fetch mode. + * @param int $col OPTIONAL Column number, if fetch mode is by column. + * @return array Collection of rows, each in a format by the fetch mode. + * @throws Zend_Db_Statement_Exception + */ + public function fetchAll($style = null, $col = 0) + { + if (!$this->_stmt) { + return false; + } + + // make sure we have a fetch mode + if ($style === null) { + $style = $this->_fetchMode; + } + + $flags = OCI_FETCHSTATEMENT_BY_ROW; + + switch ($style) { + case Zend_Db::FETCH_BOTH: + /** + * @see Zend_Db_Adapter_Oracle_Exception + */ + throw new Zend_Db_Statement_Oracle_Exception( + array( + 'code' => 'HYC00', + 'message' => "OCI8 driver does not support fetchAll(FETCH_BOTH), use fetch() in a loop instead" + ) + ); + // notreached + $flags |= OCI_NUM; + $flags |= OCI_ASSOC; + break; + case Zend_Db::FETCH_NUM: + $flags |= OCI_NUM; + break; + case Zend_Db::FETCH_ASSOC: + $flags |= OCI_ASSOC; + break; + case Zend_Db::FETCH_OBJ: + break; + case Zend_Db::FETCH_COLUMN: + $flags = $flags &~ OCI_FETCHSTATEMENT_BY_ROW; + $flags |= OCI_FETCHSTATEMENT_BY_COLUMN; + $flags |= OCI_NUM; + break; + default: + /** + * @see Zend_Db_Adapter_Oracle_Exception + */ + throw new Zend_Db_Statement_Oracle_Exception( + array( + 'code' => 'HYC00', + 'message' => "Invalid fetch mode '$style' specified" + ) + ); + break; + } + + $result = Array(); + if ($flags != OCI_FETCHSTATEMENT_BY_ROW) { /* not Zend_Db::FETCH_OBJ */ + if (! ($rows = oci_fetch_all($this->_stmt, $result, 0, -1, $flags) )) { + if ($error = oci_error($this->_stmt)) { + /** + * @see Zend_Db_Adapter_Oracle_Exception + */ + throw new Zend_Db_Statement_Oracle_Exception($error); + } + if (!$rows) { + return array(); + } + } + if ($style == Zend_Db::FETCH_COLUMN) { + $result = $result[$col]; + } + foreach ($result as &$row) { + if (is_array($row) && array_key_exists('zend_db_rownum', $row)) { + unset($row['zend_db_rownum']); + } + } + } else { + while (($row = oci_fetch_object($this->_stmt)) !== false) { + $result [] = $row; + } + if ($error = oci_error($this->_stmt)) { + /** + * @see Zend_Db_Adapter_Oracle_Exception + */ + throw new Zend_Db_Statement_Oracle_Exception($error); + } + } + + return $result; + } + + + /** + * Returns a single column from the next row of a result set. + * + * @param int $col OPTIONAL Position of the column to fetch. + * @return string + * @throws Zend_Db_Statement_Exception + */ + public function fetchColumn($col = 0) + { + if (!$this->_stmt) { + return false; + } + + if (!oci_fetch($this->_stmt)) { + // if no error, there is simply no record + if (!$error = oci_error($this->_stmt)) { + return false; + } + /** + * @see Zend_Db_Adapter_Oracle_Exception + */ + throw new Zend_Db_Statement_Oracle_Exception($error); + } + + $data = oci_result($this->_stmt, $col+1); //1-based + if ($data === false) { + /** + * @see Zend_Db_Adapter_Oracle_Exception + */ + throw new Zend_Db_Statement_Oracle_Exception(oci_error($this->_stmt)); + } + + if ($this->getLobAsString()) { + // instanceof doesn't allow '-', we must use a temporary string + $type = 'OCI-Lob'; + if ($data instanceof $type) { + $data = $data->read($data->size()); + } + } + + return $data; + } + + /** + * Fetches the next row and returns it as an object. + * + * @param string $class OPTIONAL Name of the class to create. + * @param array $config OPTIONAL Constructor arguments for the class. + * @return mixed One object instance of the specified class. + * @throws Zend_Db_Statement_Exception + */ + public function fetchObject($class = 'stdClass', array $config = array()) + { + if (!$this->_stmt) { + return false; + } + + $obj = oci_fetch_object($this->_stmt); + + if ($error = oci_error($this->_stmt)) { + /** + * @see Zend_Db_Adapter_Oracle_Exception + */ + throw new Zend_Db_Statement_Oracle_Exception($error); + } + + /* @todo XXX handle parameters */ + + return $obj; + } + + /** + * Retrieves the next rowset (result set) for a SQL statement that has + * multiple result sets. An example is a stored procedure that returns + * the results of multiple queries. + * + * @return bool + * @throws Zend_Db_Statement_Exception + */ + public function nextRowset() + { + /** + * @see Zend_Db_Statement_Oracle_Exception + */ + throw new Zend_Db_Statement_Oracle_Exception( + array( + 'code' => 'HYC00', + 'message' => 'Optional feature not implemented' + ) + ); + } + + /** + * Returns the number of rows affected by the execution of the + * last INSERT, DELETE, or UPDATE statement executed by this + * statement object. + * + * @return int The number of rows affected. + * @throws Zend_Db_Statement_Exception + */ + public function rowCount() + { + if (!$this->_stmt) { + return false; + } + + $num_rows = oci_num_rows($this->_stmt); + + if ($num_rows === false) { + /** + * @see Zend_Db_Adapter_Oracle_Exception + */ + throw new Zend_Db_Statement_Oracle_Exception(oci_error($this->_stmt)); + } + + return $num_rows; + } + +} diff --git a/library/vendor/Zend/Db/Statement/Oracle/Exception.php b/library/vendor/Zend/Db/Statement/Oracle/Exception.php new file mode 100644 index 0000000..feaa4cb --- /dev/null +++ b/library/vendor/Zend/Db/Statement/Oracle/Exception.php @@ -0,0 +1,58 @@ +message = $error['code']." ".$error['message']; + } else { + $this->message = $error['code']." ".$error['message']." "; + $this->message .= substr($error['sqltext'], 0, $error['offset']); + $this->message .= "*"; + $this->message .= substr($error['sqltext'], $error['offset']); + } + $this->code = $error['code']; + } + if (!$this->code && $code) { + $this->code = $code; + } + } +} + diff --git a/library/vendor/Zend/Db/Statement/Pdo.php b/library/vendor/Zend/Db/Statement/Pdo.php new file mode 100644 index 0000000..47f9031 --- /dev/null +++ b/library/vendor/Zend/Db/Statement/Pdo.php @@ -0,0 +1,426 @@ +_stmt = $this->_adapter->getConnection()->prepare($sql); + } catch (PDOException $e) { + throw new Zend_Db_Statement_Exception($e->getMessage(), $e->getCode(), $e); + } + } + + /** + * Bind a column of the statement result set to a PHP variable. + * + * @param string $column Name the column in the result set, either by + * position or by name. + * @param mixed $param Reference to the PHP variable containing the value. + * @param mixed $type OPTIONAL + * @return bool + * @throws Zend_Db_Statement_Exception + */ + public function bindColumn($column, &$param, $type = null) + { + try { + if ($type === null) { + return $this->_stmt->bindColumn($column, $param); + } else { + return $this->_stmt->bindColumn($column, $param, $type); + } + } catch (PDOException $e) { + throw new Zend_Db_Statement_Exception($e->getMessage(), $e->getCode(), $e); + } + } + + /** + * Binds a parameter to the specified variable name. + * + * @param mixed $parameter Name the parameter, either integer or string. + * @param mixed $variable Reference to PHP variable containing the value. + * @param mixed $type OPTIONAL Datatype of SQL parameter. + * @param mixed $length OPTIONAL Length of SQL parameter. + * @param mixed $options OPTIONAL Other options. + * @return bool + * @throws Zend_Db_Statement_Exception + */ + protected function _bindParam($parameter, &$variable, $type = null, $length = null, $options = null) + { + try { + if ($type === null) { + if (is_bool($variable)) { + $type = PDO::PARAM_BOOL; + } elseif ($variable === null) { + $type = PDO::PARAM_NULL; + } elseif (is_integer($variable)) { + $type = PDO::PARAM_INT; + } else { + $type = PDO::PARAM_STR; + } + } + return $this->_stmt->bindParam($parameter, $variable, $type, $length, $options); + } catch (PDOException $e) { + throw new Zend_Db_Statement_Exception($e->getMessage(), $e->getCode(), $e); + } + } + + /** + * Binds a value to a parameter. + * + * @param mixed $parameter Name the parameter, either integer or string. + * @param mixed $value Scalar value to bind to the parameter. + * @param mixed $type OPTIONAL Datatype of the parameter. + * @return bool + * @throws Zend_Db_Statement_Exception + */ + public function bindValue($parameter, $value, $type = null) + { + if (is_string($parameter) && $parameter[0] != ':') { + $parameter = ":$parameter"; + } + + $this->_bindParam[$parameter] = $value; + + try { + if ($type === null) { + return $this->_stmt->bindValue($parameter, $value); + } else { + return $this->_stmt->bindValue($parameter, $value, $type); + } + } catch (PDOException $e) { + throw new Zend_Db_Statement_Exception($e->getMessage(), $e->getCode(), $e); + } + } + + /** + * Closes the cursor, allowing the statement to be executed again. + * + * @return bool + * @throws Zend_Db_Statement_Exception + */ + public function closeCursor() + { + try { + return $this->_stmt->closeCursor(); + } catch (PDOException $e) { + throw new Zend_Db_Statement_Exception($e->getMessage(), $e->getCode(), $e); + } + } + + /** + * Returns the number of columns in the result set. + * Returns null if the statement has no result set metadata. + * + * @return int The number of columns. + * @throws Zend_Db_Statement_Exception + */ + public function columnCount() + { + try { + return $this->_stmt->columnCount(); + } catch (PDOException $e) { + throw new Zend_Db_Statement_Exception($e->getMessage(), $e->getCode(), $e); + } + } + + /** + * Retrieves the error code, if any, associated with the last operation on + * the statement handle. + * + * @return string error code. + * @throws Zend_Db_Statement_Exception + */ + public function errorCode() + { + try { + return $this->_stmt->errorCode(); + } catch (PDOException $e) { + throw new Zend_Db_Statement_Exception($e->getMessage(), $e->getCode(), $e); + } + } + + /** + * Retrieves an array of error information, if any, associated with the + * last operation on the statement handle. + * + * @return array + * @throws Zend_Db_Statement_Exception + */ + public function errorInfo() + { + try { + return $this->_stmt->errorInfo(); + } catch (PDOException $e) { + throw new Zend_Db_Statement_Exception($e->getMessage(), $e->getCode(), $e); + } + } + + /** + * Executes a prepared statement. + * + * @param array $params OPTIONAL Values to bind to parameter placeholders. + * @return bool + * @throws Zend_Db_Statement_Exception + */ + public function _execute(array $params = null) + { + try { + if ($params !== null) { + return $this->_stmt->execute($params); + } else { + return $this->_stmt->execute(); + } + } catch (PDOException $e) { + $message = sprintf('%s, query was: %s', $e->getMessage(), $this->_stmt->queryString); + throw new Zend_Db_Statement_Exception($message, (int) $e->getCode(), $e); + } + } + + /** + * Fetches a row from the result set. + * + * @param int $style OPTIONAL Fetch mode for this fetch operation. + * @param int $cursor OPTIONAL Absolute, relative, or other. + * @param int $offset OPTIONAL Number for absolute or relative cursors. + * @return mixed Array, object, or scalar depending on fetch mode. + * @throws Zend_Db_Statement_Exception + */ + public function fetch($style = null, $cursor = null, $offset = null) + { + if ($style === null) { + $style = $this->_fetchMode; + } + if ($cursor === null) { + $cursor = PDO::FETCH_ORI_NEXT; + } + if ($offset === null) { + $offset = 0; + } + try { + return $this->_stmt->fetch($style, $cursor, $offset); + } catch (PDOException $e) { + throw new Zend_Db_Statement_Exception($e->getMessage(), $e->getCode(), $e); + } + } + + /** + * Required by IteratorAggregate interface + * + * @return IteratorIterator + */ + public function getIterator(): Traversable + { + return new IteratorIterator($this->_stmt); + } + + /** + * Returns an array containing all of the result set rows. + * + * @param int $style OPTIONAL Fetch mode. + * @param int $col OPTIONAL Column number, if fetch mode is by column. + * @return array Collection of rows, each in a format by the fetch mode. + * @throws Zend_Db_Statement_Exception + */ + public function fetchAll($style = null, $col = null) + { + if ($style === null) { + $style = $this->_fetchMode; + } + try { + if ($style == PDO::FETCH_COLUMN) { + if ($col === null) { + $col = 0; + } + return $this->_stmt->fetchAll($style, $col); + } else { + return $this->_stmt->fetchAll($style); + } + } catch (PDOException $e) { + throw new Zend_Db_Statement_Exception($e->getMessage(), $e->getCode(), $e); + } + } + + /** + * Returns a single column from the next row of a result set. + * + * @param int $col OPTIONAL Position of the column to fetch. + * @return string + * @throws Zend_Db_Statement_Exception + */ + public function fetchColumn($col = 0) + { + try { + return $this->_stmt->fetchColumn($col); + } catch (PDOException $e) { + throw new Zend_Db_Statement_Exception($e->getMessage(), $e->getCode(), $e); + } + } + + /** + * Fetches the next row and returns it as an object. + * + * @param string $class OPTIONAL Name of the class to create. + * @param array $config OPTIONAL Constructor arguments for the class. + * @return mixed One object instance of the specified class. + * @throws Zend_Db_Statement_Exception + */ + public function fetchObject($class = 'stdClass', array $config = array()) + { + try { + return $this->_stmt->fetchObject($class, $config); + } catch (PDOException $e) { + throw new Zend_Db_Statement_Exception($e->getMessage(), $e->getCode(), $e); + } + } + + /** + * Retrieve a statement attribute. + * + * @param integer $key Attribute name. + * @return mixed Attribute value. + * @throws Zend_Db_Statement_Exception + */ + public function getAttribute($key) + { + try { + return $this->_stmt->getAttribute($key); + } catch (PDOException $e) { + throw new Zend_Db_Statement_Exception($e->getMessage(), $e->getCode(), $e); + } + } + + /** + * Returns metadata for a column in a result set. + * + * @param int $column + * @return mixed + * @throws Zend_Db_Statement_Exception + */ + public function getColumnMeta($column) + { + try { + return $this->_stmt->getColumnMeta($column); + } catch (PDOException $e) { + throw new Zend_Db_Statement_Exception($e->getMessage(), $e->getCode(), $e); + } + } + + /** + * Retrieves the next rowset (result set) for a SQL statement that has + * multiple result sets. An example is a stored procedure that returns + * the results of multiple queries. + * + * @return bool + * @throws Zend_Db_Statement_Exception + */ + public function nextRowset() + { + try { + return $this->_stmt->nextRowset(); + } catch (PDOException $e) { + throw new Zend_Db_Statement_Exception($e->getMessage(), $e->getCode(), $e); + } + } + + /** + * Returns the number of rows affected by the execution of the + * last INSERT, DELETE, or UPDATE statement executed by this + * statement object. + * + * @return int The number of rows affected. + * @throws Zend_Db_Statement_Exception + */ + public function rowCount() + { + try { + return $this->_stmt->rowCount(); + } catch (PDOException $e) { + throw new Zend_Db_Statement_Exception($e->getMessage(), $e->getCode(), $e); + } + } + + /** + * Set a statement attribute. + * + * @param string $key Attribute name. + * @param mixed $val Attribute value. + * @return bool + * @throws Zend_Db_Statement_Exception + */ + public function setAttribute($key, $val) + { + try { + return $this->_stmt->setAttribute($key, $val); + } catch (PDOException $e) { + throw new Zend_Db_Statement_Exception($e->getMessage(), $e->getCode(), $e); + } + } + + /** + * Set the default fetch mode for this statement. + * + * @param int $mode The fetch mode. + * @return bool + * @throws Zend_Db_Statement_Exception + */ + public function setFetchMode($mode) + { + $this->_fetchMode = $mode; + try { + return $this->_stmt->setFetchMode($mode); + } catch (PDOException $e) { + throw new Zend_Db_Statement_Exception($e->getMessage(), $e->getCode(), $e); + } + } + +} diff --git a/library/vendor/Zend/Db/Statement/Pdo/Ibm.php b/library/vendor/Zend/Db/Statement/Pdo/Ibm.php new file mode 100644 index 0000000..84f265e --- /dev/null +++ b/library/vendor/Zend/Db/Statement/Pdo/Ibm.php @@ -0,0 +1,92 @@ +_adapter->foldCase('ZEND_DB_ROWNUM'); + + foreach ($data as $row) { + if (is_array($row) && array_key_exists($remove, $row)) { + unset($row[$remove]); + } + $results[] = $row; + } + return $results; + } + + /** + * Binds a parameter to the specified variable name. + * + * @param mixed $parameter Name the parameter, either integer or string. + * @param mixed $variable Reference to PHP variable containing the value. + * @param mixed $type OPTIONAL Datatype of SQL parameter. + * @param mixed $length OPTIONAL Length of SQL parameter. + * @param mixed $options OPTIONAL Other options. + * @return bool + * @throws Zend_Db_Statement_Exception + */ + public function _bindParam($parameter, &$variable, $type = null, $length = null, $options = null) + { + try { + if (($type === null) && ($length === null) && ($options === null)) { + return $this->_stmt->bindParam($parameter, $variable); + } else { + return $this->_stmt->bindParam($parameter, $variable, $type, $length, $options); + } + } catch (PDOException $e) { + throw new Zend_Db_Statement_Exception($e->getMessage(), $e->getCode(), $e); + } + } + +} diff --git a/library/vendor/Zend/Db/Statement/Pdo/Oci.php b/library/vendor/Zend/Db/Statement/Pdo/Oci.php new file mode 100644 index 0000000..79334ad --- /dev/null +++ b/library/vendor/Zend/Db/Statement/Pdo/Oci.php @@ -0,0 +1,90 @@ +_adapter->foldCase('zend_db_rownum'); + + foreach ($data as $row) { + if (is_array($row) && array_key_exists($remove, $row)) { + unset($row[$remove]); + } + $results[] = $row; + } + return $results; + } + + + /** + * Fetches a row from the result set. + * + * @param int $style OPTIONAL Fetch mode for this fetch operation. + * @param int $cursor OPTIONAL Absolute, relative, or other. + * @param int $offset OPTIONAL Number for absolute or relative cursors. + * @return mixed Array, object, or scalar depending on fetch mode. + * @throws Zend_Db_Statement_Exception + */ + public function fetch($style = null, $cursor = null, $offset = null) + { + $row = parent::fetch($style, $cursor, $offset); + + $remove = $this->_adapter->foldCase('zend_db_rownum'); + if (is_array($row) && array_key_exists($remove, $row)) { + unset($row[$remove]); + } + + return $row; + } +} diff --git a/library/vendor/Zend/Db/Statement/Sqlsrv.php b/library/vendor/Zend/Db/Statement/Sqlsrv.php new file mode 100644 index 0000000..84294e8 --- /dev/null +++ b/library/vendor/Zend/Db/Statement/Sqlsrv.php @@ -0,0 +1,430 @@ +_adapter->getConnection(); + + $this->_stmt = sqlsrv_prepare($connection, $sql); + + if (!$this->_stmt) { + throw new Zend_Db_Statement_Sqlsrv_Exception(sqlsrv_errors()); + } + + $this->_originalSQL = $sql; + } + + /** + * Binds a parameter to the specified variable name. + * + * @param mixed $parameter Name the parameter, either integer or string. + * @param mixed $variable Reference to PHP variable containing the value. + * @param mixed $type OPTIONAL Datatype of SQL parameter. + * @param mixed $length OPTIONAL Length of SQL parameter. + * @param mixed $options OPTIONAL Other options. + * @return bool + * @throws Zend_Db_Statement_Exception + */ + protected function _bindParam($parameter, &$variable, $type = null, $length = null, $options = null) + { + //Sql server doesn't support bind by name + return true; + } + + /** + * Closes the cursor, allowing the statement to be executed again. + * + * @return bool + */ + public function closeCursor() + { + if (!$this->_stmt) { + return false; + } + + sqlsrv_free_stmt($this->_stmt); + $this->_stmt = false; + return true; + } + + /** + * Returns the number of columns in the result set. + * Returns null if the statement has no result set metadata. + * + * @return int The number of columns. + */ + public function columnCount() + { + if ($this->_stmt && $this->_executed) { + return sqlsrv_num_fields($this->_stmt); + } + + return 0; + } + + + /** + * Retrieves the error code, if any, associated with the last operation on + * the statement handle. + * + * @return string error code. + */ + public function errorCode() + { + if (!$this->_stmt) { + return false; + } + + $error = sqlsrv_errors(); + if (!$error) { + return false; + } + + return $error[0]['code']; + } + + + /** + * Retrieves an array of error information, if any, associated with the + * last operation on the statement handle. + * + * @return array + */ + public function errorInfo() + { + if (!$this->_stmt) { + return false; + } + + $error = sqlsrv_errors(); + if (!$error) { + return false; + } + + return array( + $error[0]['code'], + $error[0]['message'], + ); + } + + + /** + * Executes a prepared statement. + * + * @param array $params OPTIONAL Values to bind to parameter placeholders. + * @return bool + * @throws Zend_Db_Statement_Exception + */ + public function _execute(array $params = null) + { + $connection = $this->_adapter->getConnection(); + if (!$this->_stmt) { + return false; + } + + if ($params !== null) { + if (!is_array($params)) { + $params = array($params); + } + $error = false; + + // make all params passed by reference + $params_ = array(); + $temp = array(); + $i = 1; + foreach ($params as $param) { + $temp[$i] = $param; + $params_[] = &$temp[$i]; + $i++; + } + $params = $params_; + } + + $this->_stmt = sqlsrv_query($connection, $this->_originalSQL, $params); + + if (!$this->_stmt) { + throw new Zend_Db_Statement_Sqlsrv_Exception(sqlsrv_errors()); + } + + $this->_executed = true; + + return (!$this->_stmt); + } + + /** + * Fetches a row from the result set. + * + * @param int $style OPTIONAL Fetch mode for this fetch operation. + * @param int $cursor OPTIONAL Absolute, relative, or other. + * @param int $offset OPTIONAL Number for absolute or relative cursors. + * @return mixed Array, object, or scalar depending on fetch mode. + * @throws Zend_Db_Statement_Exception + */ + public function fetch($style = null, $cursor = null, $offset = null) + { + if (!$this->_stmt) { + return false; + } + + if (null === $style) { + $style = $this->_fetchMode; + } + + $values = sqlsrv_fetch_array($this->_stmt, SQLSRV_FETCH_ASSOC); + + if (!$values && (null !== $error = sqlsrv_errors())) { + throw new Zend_Db_Statement_Sqlsrv_Exception($error); + } + + if (null === $values) { + return null; + } + + if (!$this->_keys) { + foreach ($values as $key => $value) { + $this->_keys[] = $this->_adapter->foldCase($key); + } + } + + $values = array_values($values); + + $row = false; + switch ($style) { + case Zend_Db::FETCH_NUM: + $row = $values; + break; + case Zend_Db::FETCH_ASSOC: + $row = array_combine($this->_keys, $values); + break; + case Zend_Db::FETCH_BOTH: + $assoc = array_combine($this->_keys, $values); + $row = array_merge($values, $assoc); + break; + case Zend_Db::FETCH_OBJ: + $row = (object) array_combine($this->_keys, $values); + break; + case Zend_Db::FETCH_BOUND: + $assoc = array_combine($this->_keys, $values); + $row = array_merge($values, $assoc); + $row = $this->_fetchBound($row); + break; + default: + throw new Zend_Db_Statement_Sqlsrv_Exception("Invalid fetch mode '$style' specified"); + break; + } + + return $row; + } + + /** + * Returns a single column from the next row of a result set. + * + * @param int $col OPTIONAL Position of the column to fetch. + * @return string + * @throws Zend_Db_Statement_Exception + */ + public function fetchColumn($col = 0) + { + if (!$this->_stmt) { + return false; + } + + if (!sqlsrv_fetch($this->_stmt)) { + if (null !== $error = sqlsrv_errors()) { + throw new Zend_Db_Statement_Sqlsrv_Exception($error); + } + + // If no error, there is simply no record + return false; + } + + $data = sqlsrv_get_field($this->_stmt, $col); //0-based + if ($data === false) { + throw new Zend_Db_Statement_Sqlsrv_Exception(sqlsrv_errors()); + } + + return $data; + } + + /** + * Fetches the next row and returns it as an object. + * + * @param string $class OPTIONAL Name of the class to create. + * @param array $config OPTIONAL Constructor arguments for the class. + * @return mixed One object instance of the specified class. + * @throws Zend_Db_Statement_Exception + */ + public function fetchObject($class = 'stdClass', array $config = array()) + { + if (!$this->_stmt) { + return false; + } + + $obj = sqlsrv_fetch_object($this->_stmt); + + if ($error = sqlsrv_errors()) { + throw new Zend_Db_Statement_Sqlsrv_Exception($error); + } + + /* @todo XXX handle parameters */ + + if (null === $obj) { + return false; + } + + return $obj; + } + + /** + * Returns metadata for a column in a result set. + * + * @param int $column + * @return mixed + * @throws Zend_Db_Statement_Sqlsrv_Exception + */ + public function getColumnMeta($column) + { + $fields = sqlsrv_field_metadata($this->_stmt); + + if (!$fields) { + throw new Zend_Db_Statement_Sqlsrv_Exception('Column metadata can not be fetched'); + } + + if (!isset($fields[$column])) { + throw new Zend_Db_Statement_Sqlsrv_Exception('Column index does not exist in statement'); + } + + return $fields[$column]; + } + + /** + * Retrieves the next rowset (result set) for a SQL statement that has + * multiple result sets. An example is a stored procedure that returns + * the results of multiple queries. + * + * @return bool + * @throws Zend_Db_Statement_Exception + */ + public function nextRowset() + { + if (sqlsrv_next_result($this->_stmt) === false) { + throw new Zend_Db_Statement_Sqlsrv_Exception(sqlsrv_errors()); + } + + // reset column keys + $this->_keys = null; + + return true; + } + + /** + * Returns the number of rows affected by the execution of the + * last INSERT, DELETE, or UPDATE statement executed by this + * statement object. + * + * @return int The number of rows affected. + * @throws Zend_Db_Statement_Exception + */ + public function rowCount() + { + if (!$this->_stmt) { + return false; + } + + if (!$this->_executed) { + return 0; + } + + $num_rows = sqlsrv_rows_affected($this->_stmt); + + // Strict check is necessary; 0 is a valid return value + if ($num_rows === false) { + throw new Zend_Db_Statement_Sqlsrv_Exception(sqlsrv_errors()); + } + + return $num_rows; + } + + /** + * Returns an array containing all of the result set rows. + * + * @param int $style OPTIONAL Fetch mode. + * @param int $col OPTIONAL Column number, if fetch mode is by column. + * @return array Collection of rows, each in a format by the fetch mode. + * + * Behaves like parent, but if limit() + * is used, the final result removes the extra column + * 'zend_db_rownum' + */ + public function fetchAll($style = null, $col = null) + { + $data = parent::fetchAll($style, $col); + $results = array(); + $remove = $this->_adapter->foldCase('ZEND_DB_ROWNUM'); + + foreach ($data as $row) { + if (is_array($row) && array_key_exists($remove, $row)) { + unset($row[$remove]); + } + $results[] = $row; + } + return $results; + } +} diff --git a/library/vendor/Zend/Db/Statement/Sqlsrv/Exception.php b/library/vendor/Zend/Db/Statement/Sqlsrv/Exception.php new file mode 100644 index 0000000..3358f3b --- /dev/null +++ b/library/vendor/Zend/Db/Statement/Sqlsrv/Exception.php @@ -0,0 +1,60 @@ + $config); + } else { + // process this as table with or without a definition + if ($definition instanceof Zend_Db_Table_Definition + && $definition->hasTableConfig($config)) { + // this will have DEFINITION_CONFIG_NAME & DEFINITION + $config = $definition->getTableConfig($config); + } else { + $config = array(self::NAME => $config); + } + } + } + + parent::__construct($config); + } +} diff --git a/library/vendor/Zend/Db/Table/Abstract.php b/library/vendor/Zend/Db/Table/Abstract.php new file mode 100644 index 0000000..ea393f2 --- /dev/null +++ b/library/vendor/Zend/Db/Table/Abstract.php @@ -0,0 +1,1599 @@ + $config); + } + + if ($config) { + $this->setOptions($config); + } + + $this->_setup(); + $this->init(); + } + + /** + * setOptions() + * + * @param array $options + * @return Zend_Db_Table_Abstract + */ + public function setOptions(Array $options) + { + foreach ($options as $key => $value) { + switch ($key) { + case self::ADAPTER: + $this->_setAdapter($value); + break; + case self::DEFINITION: + $this->setDefinition($value); + break; + case self::DEFINITION_CONFIG_NAME: + $this->setDefinitionConfigName($value); + break; + case self::SCHEMA: + $this->_schema = (string) $value; + break; + case self::NAME: + $this->_name = (string) $value; + break; + case self::PRIMARY: + $this->_primary = (array) $value; + break; + case self::ROW_CLASS: + $this->setRowClass($value); + break; + case self::ROWSET_CLASS: + $this->setRowsetClass($value); + break; + case self::REFERENCE_MAP: + $this->setReferences($value); + break; + case self::DEPENDENT_TABLES: + $this->setDependentTables($value); + break; + case self::METADATA_CACHE: + $this->_setMetadataCache($value); + break; + case self::METADATA_CACHE_IN_CLASS: + $this->setMetadataCacheInClass($value); + break; + case self::SEQUENCE: + $this->_setSequence($value); + break; + default: + // ignore unrecognized configuration directive + break; + } + } + + return $this; + } + + /** + * setDefinition() + * + * @param Zend_Db_Table_Definition $definition + * @return Zend_Db_Table_Abstract + */ + public function setDefinition(Zend_Db_Table_Definition $definition) + { + $this->_definition = $definition; + return $this; + } + + /** + * getDefinition() + * + * @return Zend_Db_Table_Definition|null + */ + public function getDefinition() + { + return $this->_definition; + } + + /** + * setDefinitionConfigName() + * + * @param string $definition + * @return Zend_Db_Table_Abstract + */ + public function setDefinitionConfigName($definitionConfigName) + { + $this->_definitionConfigName = $definitionConfigName; + return $this; + } + + /** + * getDefinitionConfigName() + * + * @return string + */ + public function getDefinitionConfigName() + { + return $this->_definitionConfigName; + } + + /** + * @param string $classname + * @return Zend_Db_Table_Abstract Provides a fluent interface + */ + public function setRowClass($classname) + { + $this->_rowClass = (string) $classname; + + return $this; + } + + /** + * @return string + */ + public function getRowClass() + { + return $this->_rowClass; + } + + /** + * @param string $classname + * @return Zend_Db_Table_Abstract Provides a fluent interface + */ + public function setRowsetClass($classname) + { + $this->_rowsetClass = (string) $classname; + + return $this; + } + + /** + * @return string + */ + public function getRowsetClass() + { + return $this->_rowsetClass; + } + + /** + * Add a reference to the reference map + * + * @param string $ruleKey + * @param string|array $columns + * @param string $refTableClass + * @param string|array $refColumns + * @param string $onDelete + * @param string $onUpdate + * @return Zend_Db_Table_Abstract + */ + public function addReference($ruleKey, $columns, $refTableClass, $refColumns, + $onDelete = null, $onUpdate = null) + { + $reference = array(self::COLUMNS => (array) $columns, + self::REF_TABLE_CLASS => $refTableClass, + self::REF_COLUMNS => (array) $refColumns); + + if (!empty($onDelete)) { + $reference[self::ON_DELETE] = $onDelete; + } + + if (!empty($onUpdate)) { + $reference[self::ON_UPDATE] = $onUpdate; + } + + $this->_referenceMap[$ruleKey] = $reference; + + return $this; + } + + /** + * @param array $referenceMap + * @return Zend_Db_Table_Abstract Provides a fluent interface + */ + public function setReferences(array $referenceMap) + { + $this->_referenceMap = $referenceMap; + + return $this; + } + + /** + * @param string $tableClassname + * @param string $ruleKey OPTIONAL + * @return array + * @throws Zend_Db_Table_Exception + */ + public function getReference($tableClassname, $ruleKey = null) + { + $thisClass = get_class($this); + if ($thisClass === 'Zend_Db_Table') { + $thisClass = $this->_definitionConfigName; + } + $refMap = $this->_getReferenceMapNormalized(); + if ($ruleKey !== null) { + if (!isset($refMap[$ruleKey])) { + throw new Zend_Db_Table_Exception("No reference rule \"$ruleKey\" from table $thisClass to table $tableClassname"); + } + if ($refMap[$ruleKey][self::REF_TABLE_CLASS] != $tableClassname) { + throw new Zend_Db_Table_Exception("Reference rule \"$ruleKey\" does not reference table $tableClassname"); + } + return $refMap[$ruleKey]; + } + foreach ($refMap as $reference) { + if ($reference[self::REF_TABLE_CLASS] == $tableClassname) { + return $reference; + } + } + throw new Zend_Db_Table_Exception("No reference from table $thisClass to table $tableClassname"); + } + + /** + * @param array $dependentTables + * @return Zend_Db_Table_Abstract Provides a fluent interface + */ + public function setDependentTables(array $dependentTables) + { + $this->_dependentTables = $dependentTables; + + return $this; + } + + /** + * @return array + */ + public function getDependentTables() + { + return $this->_dependentTables; + } + + /** + * set the defaultSource property - this tells the table class where to find default values + * + * @param string $defaultSource + * @return Zend_Db_Table_Abstract + */ + public function setDefaultSource($defaultSource = self::DEFAULT_NONE) + { + if (!in_array($defaultSource, array(self::DEFAULT_CLASS, self::DEFAULT_DB, self::DEFAULT_NONE))) { + $defaultSource = self::DEFAULT_NONE; + } + + $this->_defaultSource = $defaultSource; + return $this; + } + + /** + * returns the default source flag that determines where defaultSources come from + * + * @return unknown + */ + public function getDefaultSource() + { + return $this->_defaultSource; + } + + /** + * set the default values for the table class + * + * @param array $defaultValues + * @return Zend_Db_Table_Abstract + */ + public function setDefaultValues(Array $defaultValues) + { + foreach ($defaultValues as $defaultName => $defaultValue) { + if (array_key_exists($defaultName, $this->_metadata)) { + $this->_defaultValues[$defaultName] = $defaultValue; + } + } + return $this; + } + + public function getDefaultValues() + { + return $this->_defaultValues; + } + + + /** + * Sets the default Zend_Db_Adapter_Abstract for all Zend_Db_Table objects. + * + * @param mixed $db Either an Adapter object, or a string naming a Registry key + * @return void + */ + public static function setDefaultAdapter($db = null) + { + self::$_defaultDb = self::_setupAdapter($db); + } + + /** + * Gets the default Zend_Db_Adapter_Abstract for all Zend_Db_Table objects. + * + * @return Zend_Db_Adapter_Abstract or null + */ + public static function getDefaultAdapter() + { + return self::$_defaultDb; + } + + /** + * @param mixed $db Either an Adapter object, or a string naming a Registry key + * @return Zend_Db_Table_Abstract Provides a fluent interface + */ + protected function _setAdapter($db) + { + $this->_db = self::_setupAdapter($db); + return $this; + } + + /** + * Gets the Zend_Db_Adapter_Abstract for this particular Zend_Db_Table object. + * + * @return Zend_Db_Adapter_Abstract + */ + public function getAdapter() + { + return $this->_db; + } + + /** + * @param mixed $db Either an Adapter object, or a string naming a Registry key + * @return Zend_Db_Adapter_Abstract + * @throws Zend_Db_Table_Exception + */ + protected static function _setupAdapter($db) + { + if ($db === null) { + return null; + } + if (is_string($db)) { + $db = Zend_Registry::get($db); + } + if (!$db instanceof Zend_Db_Adapter_Abstract) { + throw new Zend_Db_Table_Exception('Argument must be of type Zend_Db_Adapter_Abstract, or a Registry key where a Zend_Db_Adapter_Abstract object is stored'); + } + return $db; + } + + /** + * Sets the default metadata cache for information returned by Zend_Db_Adapter_Abstract::describeTable(). + * + * If $defaultMetadataCache is null, then no metadata cache is used by default. + * + * @param mixed $metadataCache Either a Cache object, or a string naming a Registry key + * @return void + */ + public static function setDefaultMetadataCache($metadataCache = null) + { + self::$_defaultMetadataCache = self::_setupMetadataCache($metadataCache); + } + + /** + * Gets the default metadata cache for information returned by Zend_Db_Adapter_Abstract::describeTable(). + * + * @return Zend_Cache_Core or null + */ + public static function getDefaultMetadataCache() + { + return self::$_defaultMetadataCache; + } + + /** + * Sets the metadata cache for information returned by Zend_Db_Adapter_Abstract::describeTable(). + * + * If $metadataCache is null, then no metadata cache is used. Since there is no opportunity to reload metadata + * after instantiation, this method need not be public, particularly because that it would have no effect + * results in unnecessary API complexity. To configure the metadata cache, use the metadataCache configuration + * option for the class constructor upon instantiation. + * + * @param mixed $metadataCache Either a Cache object, or a string naming a Registry key + * @return Zend_Db_Table_Abstract Provides a fluent interface + */ + protected function _setMetadataCache($metadataCache) + { + $this->_metadataCache = self::_setupMetadataCache($metadataCache); + return $this; + } + + /** + * Gets the metadata cache for information returned by Zend_Db_Adapter_Abstract::describeTable(). + * + * @return Zend_Cache_Core or null + */ + public function getMetadataCache() + { + return $this->_metadataCache; + } + + /** + * Indicate whether metadata should be cached in the class for the duration + * of the instance + * + * @param bool $flag + * @return Zend_Db_Table_Abstract + */ + public function setMetadataCacheInClass($flag) + { + $this->_metadataCacheInClass = (bool) $flag; + return $this; + } + + /** + * Retrieve flag indicating if metadata should be cached for duration of + * instance + * + * @return bool + */ + public function metadataCacheInClass() + { + return $this->_metadataCacheInClass; + } + + /** + * @param mixed $metadataCache Either a Cache object, or a string naming a Registry key + * @return Zend_Cache_Core + * @throws Zend_Db_Table_Exception + */ + protected static function _setupMetadataCache($metadataCache) + { + if ($metadataCache === null) { + return null; + } + if (is_string($metadataCache)) { + $metadataCache = Zend_Registry::get($metadataCache); + } + if (!$metadataCache instanceof Zend_Cache_Core) { + throw new Zend_Db_Table_Exception('Argument must be of type Zend_Cache_Core, or a Registry key where a Zend_Cache_Core object is stored'); + } + return $metadataCache; + } + + /** + * Sets the sequence member, which defines the behavior for generating + * primary key values in new rows. + * - If this is a string, then the string names the sequence object. + * - If this is boolean true, then the key uses an auto-incrementing + * or identity mechanism. + * - If this is boolean false, then the key is user-defined. + * Use this for natural keys, for example. + * + * @param mixed $sequence + * @return Zend_Db_Table_Adapter_Abstract Provides a fluent interface + */ + protected function _setSequence($sequence) + { + $this->_sequence = $sequence; + + return $this; + } + + /** + * Turnkey for initialization of a table object. + * Calls other protected methods for individual tasks, to make it easier + * for a subclass to override part of the setup logic. + * + * @return void + */ + protected function _setup() + { + $this->_setupDatabaseAdapter(); + $this->_setupTableName(); + } + + /** + * Initialize database adapter. + * + * @return void + * @throws Zend_Db_Table_Exception + */ + protected function _setupDatabaseAdapter() + { + if (! $this->_db) { + $this->_db = self::getDefaultAdapter(); + if (!$this->_db instanceof Zend_Db_Adapter_Abstract) { + throw new Zend_Db_Table_Exception('No adapter found for ' . get_class($this)); + } + } + } + + /** + * Initialize table and schema names. + * + * If the table name is not set in the class definition, + * use the class name itself as the table name. + * + * A schema name provided with the table name (e.g., "schema.table") overrides + * any existing value for $this->_schema. + * + * @return void + */ + protected function _setupTableName() + { + if (! $this->_name) { + $this->_name = get_class($this); + } else if (strpos($this->_name, '.')) { + list($this->_schema, $this->_name) = explode('.', $this->_name); + } + } + + /** + * Initializes metadata. + * + * If metadata cannot be loaded from cache, adapter's describeTable() method is called to discover metadata + * information. Returns true if and only if the metadata are loaded from cache. + * + * @return boolean + * @throws Zend_Db_Table_Exception + */ + protected function _setupMetadata() + { + if ($this->metadataCacheInClass() && (count($this->_metadata) > 0)) { + return true; + } + + // Assume that metadata will be loaded from cache + $isMetadataFromCache = true; + + // If $this has no metadata cache but the class has a default metadata cache + if (null === $this->_metadataCache && null !== self::$_defaultMetadataCache) { + // Make $this use the default metadata cache of the class + $this->_setMetadataCache(self::$_defaultMetadataCache); + } + + // If $this has a metadata cache + if (null !== $this->_metadataCache) { + // Define the cache identifier where the metadata are saved + + //get db configuration + $dbConfig = $this->_db->getConfig(); + + $port = isset($dbConfig['options']['port']) + ? ':'.$dbConfig['options']['port'] + : (isset($dbConfig['port']) + ? ':'.$dbConfig['port'] + : null); + + $host = isset($dbConfig['options']['host']) + ? ':'.$dbConfig['options']['host'] + : (isset($dbConfig['host']) + ? ':'.$dbConfig['host'] + : null); + + // Define the cache identifier where the metadata are saved + $cacheId = md5( // port:host/dbname:schema.table (based on availabilty) + $port . $host . '/'. $dbConfig['dbname'] . ':' + . $this->_schema. '.' . $this->_name + ); + } + + // If $this has no metadata cache or metadata cache misses + if (null === $this->_metadataCache || !($metadata = $this->_metadataCache->load($cacheId))) { + // Metadata are not loaded from cache + $isMetadataFromCache = false; + // Fetch metadata from the adapter's describeTable() method + $metadata = $this->_db->describeTable($this->_name, $this->_schema); + // If $this has a metadata cache, then cache the metadata + if (null !== $this->_metadataCache && !$this->_metadataCache->save($metadata, $cacheId)) { + trigger_error('Failed saving metadata to metadataCache', E_USER_NOTICE); + } + } + + // Assign the metadata to $this + $this->_metadata = $metadata; + + // Return whether the metadata were loaded from cache + return $isMetadataFromCache; + } + + /** + * Retrieve table columns + * + * @return array + */ + protected function _getCols() + { + if (null === $this->_cols) { + $this->_setupMetadata(); + $this->_cols = array_keys($this->_metadata); + } + return $this->_cols; + } + + /** + * Initialize primary key from metadata. + * If $_primary is not defined, discover primary keys + * from the information returned by describeTable(). + * + * @return void + * @throws Zend_Db_Table_Exception + */ + protected function _setupPrimaryKey() + { + if (!$this->_primary) { + $this->_setupMetadata(); + $this->_primary = array(); + foreach ($this->_metadata as $col) { + if ($col['PRIMARY']) { + $this->_primary[ $col['PRIMARY_POSITION'] ] = $col['COLUMN_NAME']; + if ($col['IDENTITY']) { + $this->_identity = $col['PRIMARY_POSITION']; + } + } + } + // if no primary key was specified and none was found in the metadata + // then throw an exception. + if (empty($this->_primary)) { + throw new Zend_Db_Table_Exception("A table must have a primary key, but none was found for table '{$this->_name}'"); + } + } else if (!is_array($this->_primary)) { + $this->_primary = array(1 => $this->_primary); + } else if (isset($this->_primary[0])) { + array_unshift($this->_primary, null); + unset($this->_primary[0]); + } + + $cols = $this->_getCols(); + if (! array_intersect((array) $this->_primary, $cols) == (array) $this->_primary) { + throw new Zend_Db_Table_Exception("Primary key column(s) (" + . implode(',', (array) $this->_primary) + . ") are not columns in this table (" + . implode(',', $cols) + . ")"); + } + + $primary = (array) $this->_primary; + $pkIdentity = $primary[(int) $this->_identity]; + + /** + * Special case for PostgreSQL: a SERIAL key implicitly uses a sequence + * object whose name is "__seq". + */ + if ($this->_sequence === true && $this->_db instanceof Zend_Db_Adapter_Pdo_Pgsql) { + $this->_sequence = $this->_db->quoteIdentifier("{$this->_name}_{$pkIdentity}_seq"); + if ($this->_schema) { + $this->_sequence = $this->_db->quoteIdentifier($this->_schema) . '.' . $this->_sequence; + } + } + } + + /** + * Returns a normalized version of the reference map + * + * @return array + */ + protected function _getReferenceMapNormalized() + { + $referenceMapNormalized = array(); + + foreach ($this->_referenceMap as $rule => $map) { + + $referenceMapNormalized[$rule] = array(); + + foreach ($map as $key => $value) { + switch ($key) { + + // normalize COLUMNS and REF_COLUMNS to arrays + case self::COLUMNS: + case self::REF_COLUMNS: + if (!is_array($value)) { + $referenceMapNormalized[$rule][$key] = array($value); + } else { + $referenceMapNormalized[$rule][$key] = $value; + } + break; + + // other values are copied as-is + default: + $referenceMapNormalized[$rule][$key] = $value; + break; + } + } + } + + return $referenceMapNormalized; + } + + /** + * Initialize object + * + * Called from {@link __construct()} as final step of object instantiation. + * + * @return void + */ + public function init() + { + } + + /** + * Returns table information. + * + * You can elect to return only a part of this information by supplying its key name, + * otherwise all information is returned as an array. + * + * @param string $key The specific info part to return OPTIONAL + * @return mixed + * @throws Zend_Db_Table_Exception + */ + public function info($key = null) + { + $this->_setupPrimaryKey(); + + $info = array( + self::SCHEMA => $this->_schema, + self::NAME => $this->_name, + self::COLS => $this->_getCols(), + self::PRIMARY => (array) $this->_primary, + self::METADATA => $this->_metadata, + self::ROW_CLASS => $this->getRowClass(), + self::ROWSET_CLASS => $this->getRowsetClass(), + self::REFERENCE_MAP => $this->_referenceMap, + self::DEPENDENT_TABLES => $this->_dependentTables, + self::SEQUENCE => $this->_sequence + ); + + if ($key === null) { + return $info; + } + + if (!array_key_exists($key, $info)) { + throw new Zend_Db_Table_Exception('There is no table information for the key "' . $key . '"'); + } + + return $info[$key]; + } + + /** + * Returns an instance of a Zend_Db_Table_Select object. + * + * @param bool $withFromPart Whether or not to include the from part of the select based on the table + * @return Zend_Db_Table_Select + */ + public function select($withFromPart = self::SELECT_WITHOUT_FROM_PART) + { + $select = new Zend_Db_Table_Select($this); + if ($withFromPart == self::SELECT_WITH_FROM_PART) { + $select->from($this->info(self::NAME), Zend_Db_Table_Select::SQL_WILDCARD, $this->info(self::SCHEMA)); + } + return $select; + } + + /** + * Inserts a new row. + * + * @param array $data Column-value pairs. + * @return mixed The primary key of the row inserted. + */ + public function insert(array $data) + { + $this->_setupPrimaryKey(); + + /** + * Zend_Db_Table assumes that if you have a compound primary key + * and one of the columns in the key uses a sequence, + * it's the _first_ column in the compound key. + */ + $primary = (array) $this->_primary; + $pkIdentity = $primary[(int)$this->_identity]; + + + /** + * If the primary key can be generated automatically, and no value was + * specified in the user-supplied data, then omit it from the tuple. + * + * Note: this checks for sensible values in the supplied primary key + * position of the data. The following values are considered empty: + * null, false, true, '', array() + */ + if (array_key_exists($pkIdentity, $data)) { + if ($data[$pkIdentity] === null // null + || $data[$pkIdentity] === '' // empty string + || is_bool($data[$pkIdentity]) // boolean + || (is_array($data[$pkIdentity]) && empty($data[$pkIdentity]))) { // empty array + unset($data[$pkIdentity]); + } + } + + /** + * If this table uses a database sequence object and the data does not + * specify a value, then get the next ID from the sequence and add it + * to the row. We assume that only the first column in a compound + * primary key takes a value from a sequence. + */ + if (is_string($this->_sequence) && !isset($data[$pkIdentity])) { + $data[$pkIdentity] = $this->_db->nextSequenceId($this->_sequence); + } + + /** + * INSERT the new row. + */ + $tableSpec = ($this->_schema ? $this->_schema . '.' : '') . $this->_name; + $this->_db->insert($tableSpec, $data); + + /** + * Fetch the most recent ID generated by an auto-increment + * or IDENTITY column, unless the user has specified a value, + * overriding the auto-increment mechanism. + */ + if ($this->_sequence === true && !isset($data[$pkIdentity])) { + $data[$pkIdentity] = $this->_db->lastInsertId(); + } + + /** + * Return the primary key value if the PK is a single column, + * else return an associative array of the PK column/value pairs. + */ + $pkData = array_intersect_key($data, array_flip($primary)); + if (count($primary) == 1) { + reset($pkData); + return current($pkData); + } + + return $pkData; + } + + /** + * Check if the provided column is an identity of the table + * + * @param string $column + * @throws Zend_Db_Table_Exception + * @return boolean + */ + public function isIdentity($column) + { + $this->_setupPrimaryKey(); + + if (!isset($this->_metadata[$column])) { + /** + * @see Zend_Db_Table_Exception + */ + + throw new Zend_Db_Table_Exception('Column "' . $column . '" not found in table.'); + } + + return (bool) $this->_metadata[$column]['IDENTITY']; + } + + /** + * Updates existing rows. + * + * @param array $data Column-value pairs. + * @param array|string $where An SQL WHERE clause, or an array of SQL WHERE clauses. + * @return int The number of rows updated. + */ + public function update(array $data, $where) + { + $tableSpec = ($this->_schema ? $this->_schema . '.' : '') . $this->_name; + return $this->_db->update($tableSpec, $data, $where); + } + + /** + * Called by a row object for the parent table's class during save() method. + * + * @param string $parentTableClassname + * @param array $oldPrimaryKey + * @param array $newPrimaryKey + * @return int + */ + public function _cascadeUpdate($parentTableClassname, array $oldPrimaryKey, array $newPrimaryKey) + { + $this->_setupMetadata(); + $rowsAffected = 0; + foreach ($this->_getReferenceMapNormalized() as $map) { + if ($map[self::REF_TABLE_CLASS] == $parentTableClassname && isset($map[self::ON_UPDATE])) { + switch ($map[self::ON_UPDATE]) { + case self::CASCADE: + $newRefs = array(); + $where = array(); + for ($i = 0; $i < count($map[self::COLUMNS]); ++$i) { + $col = $this->_db->foldCase($map[self::COLUMNS][$i]); + $refCol = $this->_db->foldCase($map[self::REF_COLUMNS][$i]); + if (array_key_exists($refCol, $newPrimaryKey)) { + $newRefs[$col] = $newPrimaryKey[$refCol]; + } + $type = $this->_metadata[$col]['DATA_TYPE']; + $where[] = $this->_db->quoteInto( + $this->_db->quoteIdentifier($col, true) . ' = ?', + $oldPrimaryKey[$refCol], $type); + } + $rowsAffected += $this->update($newRefs, $where); + break; + default: + // no action + break; + } + } + } + return $rowsAffected; + } + + /** + * Deletes existing rows. + * + * @param array|string $where SQL WHERE clause(s). + * @return int The number of rows deleted. + */ + public function delete($where) + { + $depTables = $this->getDependentTables(); + if (!empty($depTables)) { + $resultSet = $this->fetchAll($where); + if (count($resultSet) > 0 ) { + foreach ($resultSet as $row) { + /** + * Execute cascading deletes against dependent tables + */ + foreach ($depTables as $tableClass) { + $t = self::getTableFromString($tableClass, $this); + $t->_cascadeDelete( + get_class($this), $row->getPrimaryKey() + ); + } + } + } + } + + $tableSpec = ($this->_schema ? $this->_schema . '.' : '') . $this->_name; + return $this->_db->delete($tableSpec, $where); + } + + /** + * Called by parent table's class during delete() method. + * + * @param string $parentTableClassname + * @param array $primaryKey + * @return int Number of affected rows + */ + public function _cascadeDelete($parentTableClassname, array $primaryKey) + { + // setup metadata + $this->_setupMetadata(); + + // get this class name + $thisClass = get_class($this); + if ($thisClass === 'Zend_Db_Table') { + $thisClass = $this->_definitionConfigName; + } + + $rowsAffected = 0; + + foreach ($this->_getReferenceMapNormalized() as $map) { + if ($map[self::REF_TABLE_CLASS] == $parentTableClassname && isset($map[self::ON_DELETE])) { + + $where = array(); + + // CASCADE or CASCADE_RECURSE + if (in_array($map[self::ON_DELETE], array(self::CASCADE, self::CASCADE_RECURSE))) { + for ($i = 0; $i < count($map[self::COLUMNS]); ++$i) { + $col = $this->_db->foldCase($map[self::COLUMNS][$i]); + $refCol = $this->_db->foldCase($map[self::REF_COLUMNS][$i]); + $type = $this->_metadata[$col]['DATA_TYPE']; + $where[] = $this->_db->quoteInto( + $this->_db->quoteIdentifier($col, true) . ' = ?', + $primaryKey[$refCol], $type); + } + } + + // CASCADE_RECURSE + if ($map[self::ON_DELETE] == self::CASCADE_RECURSE) { + + /** + * Execute cascading deletes against dependent tables + */ + $depTables = $this->getDependentTables(); + if (!empty($depTables)) { + foreach ($depTables as $tableClass) { + $t = self::getTableFromString($tableClass, $this); + foreach ($this->fetchAll($where) as $depRow) { + $rowsAffected += $t->_cascadeDelete($thisClass, $depRow->getPrimaryKey()); + } + } + } + } + + // CASCADE or CASCADE_RECURSE + if (in_array($map[self::ON_DELETE], array(self::CASCADE, self::CASCADE_RECURSE))) { + $rowsAffected += $this->delete($where); + } + + } + } + return $rowsAffected; + } + + /** + * Fetches rows by primary key. The argument specifies one or more primary + * key value(s). To find multiple rows by primary key, the argument must + * be an array. + * + * This method accepts a variable number of arguments. If the table has a + * multi-column primary key, the number of arguments must be the same as + * the number of columns in the primary key. To find multiple rows in a + * table with a multi-column primary key, each argument must be an array + * with the same number of elements. + * + * The find() method always returns a Rowset object, even if only one row + * was found. + * + * @param mixed $key The value(s) of the primary keys. + * @return Zend_Db_Table_Rowset_Abstract Row(s) matching the criteria. + * @throws Zend_Db_Table_Exception + */ + public function find() + { + $this->_setupPrimaryKey(); + $args = func_get_args(); + $keyNames = array_values((array) $this->_primary); + + if (count($args) < count($keyNames)) { + throw new Zend_Db_Table_Exception("Too few columns for the primary key"); + } + + if (count($args) > count($keyNames)) { + throw new Zend_Db_Table_Exception("Too many columns for the primary key"); + } + + $whereList = array(); + $numberTerms = 0; + foreach ($args as $keyPosition => $keyValues) { + $keyValuesCount = count($keyValues); + // Coerce the values to an array. + // Don't simply typecast to array, because the values + // might be Zend_Db_Expr objects. + if (!is_array($keyValues)) { + $keyValues = array($keyValues); + } + if ($numberTerms == 0) { + $numberTerms = $keyValuesCount; + } else if ($keyValuesCount != $numberTerms) { + throw new Zend_Db_Table_Exception("Missing value(s) for the primary key"); + } + $keyValues = array_values($keyValues); + for ($i = 0; $i < $keyValuesCount; ++$i) { + if (!isset($whereList[$i])) { + $whereList[$i] = array(); + } + $whereList[$i][$keyPosition] = $keyValues[$i]; + } + } + + $whereClause = null; + if (count($whereList)) { + $whereOrTerms = array(); + $tableName = $this->_db->quoteTableAs($this->_name, null, true); + foreach ($whereList as $keyValueSets) { + $whereAndTerms = array(); + foreach ($keyValueSets as $keyPosition => $keyValue) { + $type = $this->_metadata[$keyNames[$keyPosition]]['DATA_TYPE']; + $columnName = $this->_db->quoteIdentifier($keyNames[$keyPosition], true); + $whereAndTerms[] = $this->_db->quoteInto( + $tableName . '.' . $columnName . ' = ?', + $keyValue, $type); + } + $whereOrTerms[] = '(' . implode(' AND ', $whereAndTerms) . ')'; + } + $whereClause = '(' . implode(' OR ', $whereOrTerms) . ')'; + } + + // issue ZF-5775 (empty where clause should return empty rowset) + if ($whereClause == null) { + $rowsetClass = $this->getRowsetClass(); + if (!class_exists($rowsetClass)) { + Zend_Loader::loadClass($rowsetClass); + } + return new $rowsetClass(array('table' => $this, 'rowClass' => $this->getRowClass(), 'stored' => true)); + } + + return $this->fetchAll($whereClause); + } + + /** + * Fetches all rows. + * + * Honors the Zend_Db_Adapter fetch mode. + * + * @param string|array|Zend_Db_Table_Select $where OPTIONAL An SQL WHERE clause or Zend_Db_Table_Select object. + * @param string|array $order OPTIONAL An SQL ORDER clause. + * @param int $count OPTIONAL An SQL LIMIT count. + * @param int $offset OPTIONAL An SQL LIMIT offset. + * @return Zend_Db_Table_Rowset_Abstract The row results per the Zend_Db_Adapter fetch mode. + */ + public function fetchAll($where = null, $order = null, $count = null, $offset = null) + { + if (!($where instanceof Zend_Db_Table_Select)) { + $select = $this->select(); + + if ($where !== null) { + $this->_where($select, $where); + } + + if ($order !== null) { + $this->_order($select, $order); + } + + if ($count !== null || $offset !== null) { + $select->limit($count, $offset); + } + + } else { + $select = $where; + } + + $rows = $this->_fetch($select); + + $data = array( + 'table' => $this, + 'data' => $rows, + 'readOnly' => $select->isReadOnly(), + 'rowClass' => $this->getRowClass(), + 'stored' => true + ); + + $rowsetClass = $this->getRowsetClass(); + if (!class_exists($rowsetClass)) { + Zend_Loader::loadClass($rowsetClass); + } + return new $rowsetClass($data); + } + + /** + * Fetches one row in an object of type Zend_Db_Table_Row_Abstract, + * or returns null if no row matches the specified criteria. + * + * @param string|array|Zend_Db_Table_Select $where OPTIONAL An SQL WHERE clause or Zend_Db_Table_Select object. + * @param string|array $order OPTIONAL An SQL ORDER clause. + * @param int $offset OPTIONAL An SQL OFFSET value. + * @return Zend_Db_Table_Row_Abstract|null The row results per the + * Zend_Db_Adapter fetch mode, or null if no row found. + */ + public function fetchRow($where = null, $order = null, $offset = null) + { + if (!($where instanceof Zend_Db_Table_Select)) { + $select = $this->select(); + + if ($where !== null) { + $this->_where($select, $where); + } + + if ($order !== null) { + $this->_order($select, $order); + } + + $select->limit(1, ((is_numeric($offset)) ? (int) $offset : null)); + + } else { + $select = $where->limit(1, $where->getPart(Zend_Db_Select::LIMIT_OFFSET)); + } + + $rows = $this->_fetch($select); + + if (count($rows) == 0) { + return null; + } + + $data = array( + 'table' => $this, + 'data' => $rows[0], + 'readOnly' => $select->isReadOnly(), + 'stored' => true + ); + + $rowClass = $this->getRowClass(); + if (!class_exists($rowClass)) { + Zend_Loader::loadClass($rowClass); + } + return new $rowClass($data); + } + + /** + * Fetches a new blank row (not from the database). + * + * @return Zend_Db_Table_Row_Abstract + * @deprecated since 0.9.3 - use createRow() instead. + */ + public function fetchNew() + { + return $this->createRow(); + } + + /** + * Fetches a new blank row (not from the database). + * + * @param array $data OPTIONAL data to populate in the new row. + * @param string $defaultSource OPTIONAL flag to force default values into new row + * @return Zend_Db_Table_Row_Abstract + */ + public function createRow(array $data = array(), $defaultSource = null) + { + $cols = $this->_getCols(); + $defaults = array_combine($cols, array_fill(0, count($cols), null)); + + // nothing provided at call-time, take the class value + if ($defaultSource == null) { + $defaultSource = $this->_defaultSource; + } + + if (!in_array($defaultSource, array(self::DEFAULT_CLASS, self::DEFAULT_DB, self::DEFAULT_NONE))) { + $defaultSource = self::DEFAULT_NONE; + } + + if ($defaultSource == self::DEFAULT_DB) { + foreach ($this->_metadata as $metadataName => $metadata) { + if (($metadata['DEFAULT'] != null) && + ($metadata['NULLABLE'] !== true || ($metadata['NULLABLE'] === true && isset($this->_defaultValues[$metadataName]) && $this->_defaultValues[$metadataName] === true)) && + (!(isset($this->_defaultValues[$metadataName]) && $this->_defaultValues[$metadataName] === false))) { + $defaults[$metadataName] = $metadata['DEFAULT']; + } + } + } elseif ($defaultSource == self::DEFAULT_CLASS && $this->_defaultValues) { + foreach ($this->_defaultValues as $defaultName => $defaultValue) { + if (array_key_exists($defaultName, $defaults)) { + $defaults[$defaultName] = $defaultValue; + } + } + } + + $config = array( + 'table' => $this, + 'data' => $defaults, + 'readOnly' => false, + 'stored' => false + ); + + $rowClass = $this->getRowClass(); + if (!class_exists($rowClass)) { + Zend_Loader::loadClass($rowClass); + } + $row = new $rowClass($config); + $row->setFromArray($data); + return $row; + } + + /** + * Generate WHERE clause from user-supplied string or array + * + * @param string|array $where OPTIONAL An SQL WHERE clause. + * @return Zend_Db_Table_Select + */ + protected function _where(Zend_Db_Table_Select $select, $where) + { + $where = (array) $where; + + foreach ($where as $key => $val) { + // is $key an int? + if (is_int($key)) { + // $val is the full condition + $select->where($val); + } else { + // $key is the condition with placeholder, + // and $val is quoted into the condition + $select->where($key, $val); + } + } + + return $select; + } + + /** + * Generate ORDER clause from user-supplied string or array + * + * @param string|array $order OPTIONAL An SQL ORDER clause. + * @return Zend_Db_Table_Select + */ + protected function _order(Zend_Db_Table_Select $select, $order) + { + if (!is_array($order)) { + $order = array($order); + } + + foreach ($order as $val) { + $select->order($val); + } + + return $select; + } + + /** + * Support method for fetching rows. + * + * @param Zend_Db_Table_Select $select query options. + * @return array An array containing the row results in FETCH_ASSOC mode. + */ + protected function _fetch(Zend_Db_Table_Select $select) + { + $stmt = $this->_db->query($select); + $data = $stmt->fetchAll(Zend_Db::FETCH_ASSOC); + return $data; + } + + /** + * Get table gateway object from string + * + * @param string $tableName + * @param Zend_Db_Table_Abstract $referenceTable + * @throws Zend_Db_Table_Row_Exception + * @return Zend_Db_Table_Abstract + */ + public static function getTableFromString($tableName, Zend_Db_Table_Abstract $referenceTable = null) + { + if ($referenceTable instanceof Zend_Db_Table_Abstract) { + $tableDefinition = $referenceTable->getDefinition(); + + if ($tableDefinition !== null && $tableDefinition->hasTableConfig($tableName)) { + return new Zend_Db_Table($tableName, $tableDefinition); + } + } + + // assume the tableName is the class name + if (!class_exists($tableName)) { + try { + Zend_Loader::loadClass($tableName); + } catch (Zend_Exception $e) { + throw new Zend_Db_Table_Row_Exception($e->getMessage(), $e->getCode(), $e); + } + } + + $options = array(); + + if ($referenceTable instanceof Zend_Db_Table_Abstract) { + $options['db'] = $referenceTable->getAdapter(); + } + + if (isset($tableDefinition) && $tableDefinition !== null) { + $options[Zend_Db_Table_Abstract::DEFINITION] = $tableDefinition; + } + + return new $tableName($options); + } + +} diff --git a/library/vendor/Zend/Db/Table/Definition.php b/library/vendor/Zend/Db/Table/Definition.php new file mode 100644 index 0000000..76265ae --- /dev/null +++ b/library/vendor/Zend/Db/Table/Definition.php @@ -0,0 +1,131 @@ +setConfig($options); + } elseif (is_array($options)) { + $this->setOptions($options); + } + } + + /** + * setConfig() + * + * @param Zend_Config $config + * @return Zend_Db_Table_Definition + */ + public function setConfig(Zend_Config $config) + { + $this->setOptions($config->toArray()); + return $this; + } + + /** + * setOptions() + * + * @param array $options + * @return Zend_Db_Table_Definition + */ + public function setOptions(Array $options) + { + foreach ($options as $optionName => $optionValue) { + $this->setTableConfig($optionName, $optionValue); + } + return $this; + } + + /** + * @param string $tableName + * @param array $tableConfig + * @return Zend_Db_Table_Definition + */ + public function setTableConfig($tableName, array $tableConfig) + { + // @todo logic here + $tableConfig[Zend_Db_Table::DEFINITION_CONFIG_NAME] = $tableName; + $tableConfig[Zend_Db_Table::DEFINITION] = $this; + + if (!isset($tableConfig[Zend_Db_Table::NAME])) { + $tableConfig[Zend_Db_Table::NAME] = $tableName; + } + + $this->_tableConfigs[$tableName] = $tableConfig; + return $this; + } + + /** + * getTableConfig() + * + * @param string $tableName + * @return array + */ + public function getTableConfig($tableName) + { + return $this->_tableConfigs[$tableName]; + } + + /** + * removeTableConfig() + * + * @param string $tableName + */ + public function removeTableConfig($tableName) + { + unset($this->_tableConfigs[$tableName]); + } + + /** + * hasTableConfig() + * + * @param string $tableName + * @return bool + */ + public function hasTableConfig($tableName) + { + return (isset($this->_tableConfigs[$tableName])); + } + +} diff --git a/library/vendor/Zend/Db/Table/Exception.php b/library/vendor/Zend/Db/Table/Exception.php new file mode 100644 index 0000000..e1599a0 --- /dev/null +++ b/library/vendor/Zend/Db/Table/Exception.php @@ -0,0 +1,37 @@ + value). + * The keys must match the physical names of columns in the + * table for which this row is defined. + * + * @var array + */ + protected $_data = array(); + + /** + * This is set to a copy of $_data when the data is fetched from + * a database, specified as a new tuple in the constructor, or + * when dirty data is posted to the database with save(). + * + * @var array + */ + protected $_cleanData = array(); + + /** + * Tracks columns where data has been updated. Allows more specific insert and + * update operations. + * + * @var array + */ + protected $_modifiedFields = array(); + + /** + * Zend_Db_Table_Abstract parent class or instance. + * + * @var Zend_Db_Table_Abstract + */ + protected $_table = null; + + /** + * Connected is true if we have a reference to a live + * Zend_Db_Table_Abstract object. + * This is false after the Rowset has been deserialized. + * + * @var boolean + */ + protected $_connected = true; + + /** + * A row is marked read only if it contains columns that are not physically represented within + * the database schema (e.g. evaluated columns/Zend_Db_Expr columns). This can also be passed + * as a run-time config options as a means of protecting row data. + * + * @var boolean + */ + protected $_readOnly = false; + + /** + * Name of the class of the Zend_Db_Table_Abstract object. + * + * @var string + */ + protected $_tableClass = null; + + /** + * Primary row key(s). + * + * @var array + */ + protected $_primary; + + /** + * Constructor. + * + * Supported params for $config are:- + * - table = class name or object of type Zend_Db_Table_Abstract + * - data = values of columns in this row. + * + * @param array $config OPTIONAL Array of user-specified config options. + * @return void + * @throws Zend_Db_Table_Row_Exception + */ + public function __construct(array $config = array()) + { + if (isset($config['table']) && $config['table'] instanceof Zend_Db_Table_Abstract) { + $this->_table = $config['table']; + $this->_tableClass = get_class($this->_table); + } elseif ($this->_tableClass !== null) { + $this->_table = $this->_getTableFromString($this->_tableClass); + } + + if (isset($config['data'])) { + if (!is_array($config['data'])) { + throw new Zend_Db_Table_Row_Exception('Data must be an array'); + } + $this->_data = $config['data']; + } + if (isset($config['stored']) && $config['stored'] === true) { + $this->_cleanData = $this->_data; + } + + if (isset($config['readOnly']) && $config['readOnly'] === true) { + $this->setReadOnly(true); + } + + // Retrieve primary keys from table schema + if (($table = $this->_getTable())) { + $info = $table->info(); + $this->_primary = (array) $info['primary']; + } + + $this->init(); + } + + /** + * Transform a column name from the user-specified form + * to the physical form used in the database. + * You can override this method in a custom Row class + * to implement column name mappings, for example inflection. + * + * @param string $columnName Column name given. + * @return string The column name after transformation applied (none by default). + * @throws Zend_Db_Table_Row_Exception if the $columnName is not a string. + */ + protected function _transformColumn($columnName) + { + if (!is_string($columnName)) { + throw new Zend_Db_Table_Row_Exception('Specified column is not a string'); + } + // Perform no transformation by default + return $columnName; + } + + /** + * Retrieve row field value + * + * @param string $columnName The user-specified column name. + * @return string The corresponding column value. + * @throws Zend_Db_Table_Row_Exception if the $columnName is not a column in the row. + */ + public function __get($columnName) + { + $columnName = $this->_transformColumn($columnName); + if (!array_key_exists($columnName, $this->_data)) { + throw new Zend_Db_Table_Row_Exception("Specified column \"$columnName\" is not in the row"); + } + return $this->_data[$columnName]; + } + + /** + * Set row field value + * + * @param string $columnName The column key. + * @param mixed $value The value for the property. + * @return void + * @throws Zend_Db_Table_Row_Exception + */ + public function __set($columnName, $value) + { + $columnName = $this->_transformColumn($columnName); + if (!array_key_exists($columnName, $this->_data)) { + throw new Zend_Db_Table_Row_Exception("Specified column \"$columnName\" is not in the row"); + } + $this->_data[$columnName] = $value; + $this->_modifiedFields[$columnName] = true; + } + + /** + * Unset row field value + * + * @param string $columnName The column key. + * @return Zend_Db_Table_Row_Abstract + * @throws Zend_Db_Table_Row_Exception + */ + public function __unset($columnName) + { + $columnName = $this->_transformColumn($columnName); + if (!array_key_exists($columnName, $this->_data)) { + throw new Zend_Db_Table_Row_Exception("Specified column \"$columnName\" is not in the row"); + } + if ($this->isConnected() && in_array($columnName, $this->_table->info('primary'))) { + throw new Zend_Db_Table_Row_Exception("Specified column \"$columnName\" is a primary key and should not be unset"); + } + unset($this->_data[$columnName]); + return $this; + } + + /** + * Test existence of row field + * + * @param string $columnName The column key. + * @return boolean + */ + public function __isset($columnName) + { + $columnName = $this->_transformColumn($columnName); + return array_key_exists($columnName, $this->_data); + } + + /** + * Store table, primary key and data in serialized object + * + * @return array + */ + public function __sleep() + { + return array('_tableClass', '_primary', '_data', '_cleanData', '_readOnly' ,'_modifiedFields'); + } + + /** + * Setup to do on wakeup. + * A de-serialized Row should not be assumed to have access to a live + * database connection, so set _connected = false. + * + * @return void + */ + public function __wakeup() + { + $this->_connected = false; + } + + /** + * Proxy to __isset + * Required by the ArrayAccess implementation + * + * @param string $offset + * @return boolean + */ + public function offsetExists($offset) + { + return $this->__isset($offset); + } + + /** + * Proxy to __get + * Required by the ArrayAccess implementation + * + * @param string $offset + * @return string + */ + public function offsetGet($offset) + { + return $this->__get($offset); + } + + /** + * Proxy to __set + * Required by the ArrayAccess implementation + * + * @param string $offset + * @param mixed $value + */ + public function offsetSet($offset, $value) + { + $this->__set($offset, $value); + } + + /** + * Proxy to __unset + * Required by the ArrayAccess implementation + * + * @param string $offset + */ + public function offsetUnset($offset) + { + return $this->__unset($offset); + } + + /** + * Initialize object + * + * Called from {@link __construct()} as final step of object instantiation. + * + * @return void + */ + public function init() + { + } + + /** + * Returns the table object, or null if this is disconnected row + * + * @return Zend_Db_Table_Abstract|null + */ + public function getTable() + { + return $this->_table; + } + + /** + * Set the table object, to re-establish a live connection + * to the database for a Row that has been de-serialized. + * + * @param Zend_Db_Table_Abstract $table + * @return boolean + * @throws Zend_Db_Table_Row_Exception + */ + public function setTable(Zend_Db_Table_Abstract $table = null) + { + if ($table == null) { + $this->_table = null; + $this->_connected = false; + return false; + } + + $tableClass = get_class($table); + if (! $table instanceof $this->_tableClass) { + throw new Zend_Db_Table_Row_Exception("The specified Table is of class $tableClass, expecting class to be instance of $this->_tableClass"); + } + + $this->_table = $table; + $this->_tableClass = $tableClass; + + $info = $this->_table->info(); + + if ($info['cols'] != array_keys($this->_data)) { + throw new Zend_Db_Table_Row_Exception('The specified Table does not have the same columns as the Row'); + } + + if (! array_intersect((array) $this->_primary, $info['primary']) == (array) $this->_primary) { + + throw new Zend_Db_Table_Row_Exception("The specified Table '$tableClass' does not have the same primary key as the Row"); + } + + $this->_connected = true; + return true; + } + + /** + * Query the class name of the Table object for which this + * Row was created. + * + * @return string + */ + public function getTableClass() + { + return $this->_tableClass; + } + + /** + * Test the connected status of the row. + * + * @return boolean + */ + public function isConnected() + { + return $this->_connected; + } + + /** + * Test the read-only status of the row. + * + * @return boolean + */ + public function isReadOnly() + { + return $this->_readOnly; + } + + /** + * Set the read-only status of the row. + * + * @param boolean $flag + * @return boolean + */ + public function setReadOnly($flag) + { + $this->_readOnly = (bool) $flag; + } + + /** + * Returns an instance of the parent table's Zend_Db_Table_Select object. + * + * @return Zend_Db_Table_Select + */ + public function select() + { + return $this->getTable()->select(); + } + + /** + * Saves the properties to the database. + * + * This performs an intelligent insert/update, and reloads the + * properties with fresh data from the table on success. + * + * @return mixed The primary key value(s), as an associative array if the + * key is compound, or a scalar if the key is single-column. + */ + public function save() + { + /** + * If the _cleanData array is empty, + * this is an INSERT of a new row. + * Otherwise it is an UPDATE. + */ + if (empty($this->_cleanData)) { + return $this->_doInsert(); + } else { + return $this->_doUpdate(); + } + } + + /** + * @return mixed The primary key value(s), as an associative array if the + * key is compound, or a scalar if the key is single-column. + */ + protected function _doInsert() + { + /** + * A read-only row cannot be saved. + */ + if ($this->_readOnly === true) { + throw new Zend_Db_Table_Row_Exception('This row has been marked read-only'); + } + + /** + * Run pre-INSERT logic + */ + $this->_insert(); + + /** + * Execute the INSERT (this may throw an exception) + */ + $data = array_intersect_key($this->_data, $this->_modifiedFields); + $primaryKey = $this->_getTable()->insert($data); + + /** + * Normalize the result to an array indexed by primary key column(s). + * The table insert() method may return a scalar. + */ + if (is_array($primaryKey)) { + $newPrimaryKey = $primaryKey; + } else { + //ZF-6167 Use tempPrimaryKey temporary to avoid that zend encoding fails. + $tempPrimaryKey = (array) $this->_primary; + $newPrimaryKey = array(current($tempPrimaryKey) => $primaryKey); + } + + /** + * Save the new primary key value in _data. The primary key may have + * been generated by a sequence or auto-increment mechanism, and this + * merge should be done before the _postInsert() method is run, so the + * new values are available for logging, etc. + */ + $this->_data = array_merge($this->_data, $newPrimaryKey); + + /** + * Run post-INSERT logic + */ + $this->_postInsert(); + + /** + * Update the _cleanData to reflect that the data has been inserted. + */ + $this->_refresh(); + + return $primaryKey; + } + + /** + * @return mixed The primary key value(s), as an associative array if the + * key is compound, or a scalar if the key is single-column. + */ + protected function _doUpdate() + { + /** + * A read-only row cannot be saved. + */ + if ($this->_readOnly === true) { + throw new Zend_Db_Table_Row_Exception('This row has been marked read-only'); + } + + /** + * Get expressions for a WHERE clause + * based on the primary key value(s). + */ + $where = $this->_getWhereQuery(false); + + /** + * Run pre-UPDATE logic + */ + $this->_update(); + + /** + * Compare the data to the modified fields array to discover + * which columns have been changed. + */ + $diffData = array_intersect_key($this->_data, $this->_modifiedFields); + + /** + * Were any of the changed columns part of the primary key? + */ + $pkDiffData = array_intersect_key($diffData, array_flip((array)$this->_primary)); + + /** + * Execute cascading updates against dependent tables. + * Do this only if primary key value(s) were changed. + */ + if (count($pkDiffData) > 0) { + $depTables = $this->_getTable()->getDependentTables(); + if (!empty($depTables)) { + $pkNew = $this->_getPrimaryKey(true); + $pkOld = $this->_getPrimaryKey(false); + foreach ($depTables as $tableClass) { + $t = $this->_getTableFromString($tableClass); + $t->_cascadeUpdate($this->getTableClass(), $pkOld, $pkNew); + } + } + } + + /** + * Execute the UPDATE (this may throw an exception) + * Do this only if data values were changed. + * Use the $diffData variable, so the UPDATE statement + * includes SET terms only for data values that changed. + */ + if (count($diffData) > 0) { + $this->_getTable()->update($diffData, $where); + } + + /** + * Run post-UPDATE logic. Do this before the _refresh() + * so the _postUpdate() function can tell the difference + * between changed data and clean (pre-changed) data. + */ + $this->_postUpdate(); + + /** + * Refresh the data just in case triggers in the RDBMS changed + * any columns. Also this resets the _cleanData. + */ + $this->_refresh(); + + /** + * Return the primary key value(s) as an array + * if the key is compound or a scalar if the key + * is a scalar. + */ + $primaryKey = $this->_getPrimaryKey(true); + if (count($primaryKey) == 1) { + return current($primaryKey); + } + + return $primaryKey; + } + + /** + * Deletes existing rows. + * + * @return int The number of rows deleted. + */ + public function delete() + { + /** + * A read-only row cannot be deleted. + */ + if ($this->_readOnly === true) { + throw new Zend_Db_Table_Row_Exception('This row has been marked read-only'); + } + + $where = $this->_getWhereQuery(); + + /** + * Execute pre-DELETE logic + */ + $this->_delete(); + + /** + * Execute cascading deletes against dependent tables + */ + $depTables = $this->_getTable()->getDependentTables(); + if (!empty($depTables)) { + $pk = $this->_getPrimaryKey(); + foreach ($depTables as $tableClass) { + $t = $this->_getTableFromString($tableClass); + $t->_cascadeDelete($this->getTableClass(), $pk); + } + } + + /** + * Execute the DELETE (this may throw an exception) + */ + $result = $this->_getTable()->delete($where); + + /** + * Execute post-DELETE logic + */ + $this->_postDelete(); + + /** + * Reset all fields to null to indicate that the row is not there + */ + $this->_data = array_combine( + array_keys($this->_data), + array_fill(0, count($this->_data), null) + ); + + return $result; + } + + public function getIterator() + { + return new ArrayIterator((array) $this->_data); + } + + /** + * Returns the column/value data as an array. + * + * @return array + */ + public function toArray() + { + return (array)$this->_data; + } + + /** + * Sets all data in the row from an array. + * + * @param array $data + * @return Zend_Db_Table_Row_Abstract Provides a fluent interface + */ + public function setFromArray(array $data) + { + $data = array_intersect_key($data, $this->_data); + + foreach ($data as $columnName => $value) { + $this->__set($columnName, $value); + } + + return $this; + } + + /** + * Refreshes properties from the database. + * + * @return void + */ + public function refresh() + { + return $this->_refresh(); + } + + /** + * Retrieves an instance of the parent table. + * + * @return Zend_Db_Table_Abstract + */ + protected function _getTable() + { + if (!$this->_connected) { + throw new Zend_Db_Table_Row_Exception('Cannot save a Row unless it is connected'); + } + return $this->_table; + } + + /** + * Retrieves an associative array of primary keys. + * + * @param bool $useDirty + * @return array + */ + protected function _getPrimaryKey($useDirty = true) + { + if (!is_array($this->_primary)) { + throw new Zend_Db_Table_Row_Exception("The primary key must be set as an array"); + } + + $primary = array_flip($this->_primary); + if ($useDirty) { + $array = array_intersect_key($this->_data, $primary); + } else { + $array = array_intersect_key($this->_cleanData, $primary); + } + if (count($primary) != count($array)) { + throw new Zend_Db_Table_Row_Exception("The specified Table '$this->_tableClass' does not have the same primary key as the Row"); + } + return $array; + } + + /** + * Retrieves an associative array of primary keys. + * + * @param bool $useDirty + * @return array + */ + public function getPrimaryKey($useDirty = true) + { + return $this->_getPrimaryKey($useDirty); + } + + /** + * Constructs where statement for retrieving row(s). + * + * @param bool $useDirty + * @return array + */ + protected function _getWhereQuery($useDirty = true) + { + $where = array(); + $db = $this->_getTable()->getAdapter(); + $primaryKey = $this->_getPrimaryKey($useDirty); + $info = $this->_getTable()->info(); + $metadata = $info[Zend_Db_Table_Abstract::METADATA]; + + // retrieve recently updated row using primary keys + $where = array(); + foreach ($primaryKey as $column => $value) { + $tableName = $db->quoteIdentifier($info[Zend_Db_Table_Abstract::NAME], true); + $type = $metadata[$column]['DATA_TYPE']; + $columnName = $db->quoteIdentifier($column, true); + $where[] = $db->quoteInto("{$tableName}.{$columnName} = ?", $value, $type); + } + return $where; + } + + /** + * Refreshes properties from the database. + * + * @return void + */ + protected function _refresh() + { + $where = $this->_getWhereQuery(); + $row = $this->_getTable()->fetchRow($where); + + if (null === $row) { + throw new Zend_Db_Table_Row_Exception('Cannot refresh row as parent is missing'); + } + + $this->_data = $row->toArray(); + $this->_cleanData = $this->_data; + $this->_modifiedFields = array(); + } + + /** + * Allows pre-insert logic to be applied to row. + * Subclasses may override this method. + * + * @return void + */ + protected function _insert() + { + } + + /** + * Allows post-insert logic to be applied to row. + * Subclasses may override this method. + * + * @return void + */ + protected function _postInsert() + { + } + + /** + * Allows pre-update logic to be applied to row. + * Subclasses may override this method. + * + * @return void + */ + protected function _update() + { + } + + /** + * Allows post-update logic to be applied to row. + * Subclasses may override this method. + * + * @return void + */ + protected function _postUpdate() + { + } + + /** + * Allows pre-delete logic to be applied to row. + * Subclasses may override this method. + * + * @return void + */ + protected function _delete() + { + } + + /** + * Allows post-delete logic to be applied to row. + * Subclasses may override this method. + * + * @return void + */ + protected function _postDelete() + { + } + + /** + * Prepares a table reference for lookup. + * + * Ensures all reference keys are set and properly formatted. + * + * @param Zend_Db_Table_Abstract $dependentTable + * @param Zend_Db_Table_Abstract $parentTable + * @param string $ruleKey + * @return array + */ + protected function _prepareReference(Zend_Db_Table_Abstract $dependentTable, Zend_Db_Table_Abstract $parentTable, $ruleKey) + { + $parentTableName = (get_class($parentTable) === 'Zend_Db_Table') ? $parentTable->getDefinitionConfigName() : get_class($parentTable); + $map = $dependentTable->getReference($parentTableName, $ruleKey); + + if (!isset($map[Zend_Db_Table_Abstract::REF_COLUMNS])) { + $parentInfo = $parentTable->info(); + $map[Zend_Db_Table_Abstract::REF_COLUMNS] = array_values((array) $parentInfo['primary']); + } + + $map[Zend_Db_Table_Abstract::COLUMNS] = (array) $map[Zend_Db_Table_Abstract::COLUMNS]; + $map[Zend_Db_Table_Abstract::REF_COLUMNS] = (array) $map[Zend_Db_Table_Abstract::REF_COLUMNS]; + + return $map; + } + + /** + * Query a dependent table to retrieve rows matching the current row. + * + * @param string|Zend_Db_Table_Abstract $dependentTable + * @param string OPTIONAL $ruleKey + * @param Zend_Db_Table_Select OPTIONAL $select + * @return Zend_Db_Table_Rowset_Abstract Query result from $dependentTable + * @throws Zend_Db_Table_Row_Exception If $dependentTable is not a table or is not loadable. + */ + public function findDependentRowset($dependentTable, $ruleKey = null, Zend_Db_Table_Select $select = null) + { + $db = $this->_getTable()->getAdapter(); + + if (is_string($dependentTable)) { + $dependentTable = $this->_getTableFromString($dependentTable); + } + + if (!$dependentTable instanceof Zend_Db_Table_Abstract) { + $type = gettype($dependentTable); + if ($type == 'object') { + $type = get_class($dependentTable); + } + throw new Zend_Db_Table_Row_Exception("Dependent table must be a Zend_Db_Table_Abstract, but it is $type"); + } + + // even if we are interacting between a table defined in a class and a + // table via extension, ensure to persist the definition + if (($tableDefinition = $this->_table->getDefinition()) !== null + && ($dependentTable->getDefinition() == null)) { + $dependentTable->setOptions(array(Zend_Db_Table_Abstract::DEFINITION => $tableDefinition)); + } + + if ($select === null) { + $select = $dependentTable->select(); + } else { + $select->setTable($dependentTable); + } + + $map = $this->_prepareReference($dependentTable, $this->_getTable(), $ruleKey); + + for ($i = 0; $i < count($map[Zend_Db_Table_Abstract::COLUMNS]); ++$i) { + $parentColumnName = $db->foldCase($map[Zend_Db_Table_Abstract::REF_COLUMNS][$i]); + $value = $this->_data[$parentColumnName]; + // Use adapter from dependent table to ensure correct query construction + $dependentDb = $dependentTable->getAdapter(); + $dependentColumnName = $dependentDb->foldCase($map[Zend_Db_Table_Abstract::COLUMNS][$i]); + $dependentColumn = $dependentDb->quoteIdentifier($dependentColumnName, true); + $dependentInfo = $dependentTable->info(); + $type = $dependentInfo[Zend_Db_Table_Abstract::METADATA][$dependentColumnName]['DATA_TYPE']; + $select->where("$dependentColumn = ?", $value, $type); + } + + return $dependentTable->fetchAll($select); + } + + /** + * Query a parent table to retrieve the single row matching the current row. + * + * @param string|Zend_Db_Table_Abstract $parentTable + * @param string OPTIONAL $ruleKey + * @param Zend_Db_Table_Select OPTIONAL $select + * @return Zend_Db_Table_Row_Abstract Query result from $parentTable + * @throws Zend_Db_Table_Row_Exception If $parentTable is not a table or is not loadable. + */ + public function findParentRow($parentTable, $ruleKey = null, Zend_Db_Table_Select $select = null) + { + $db = $this->_getTable()->getAdapter(); + + if (is_string($parentTable)) { + $parentTable = $this->_getTableFromString($parentTable); + } + + if (!$parentTable instanceof Zend_Db_Table_Abstract) { + $type = gettype($parentTable); + if ($type == 'object') { + $type = get_class($parentTable); + } + throw new Zend_Db_Table_Row_Exception("Parent table must be a Zend_Db_Table_Abstract, but it is $type"); + } + + // even if we are interacting between a table defined in a class and a + // table via extension, ensure to persist the definition + if (($tableDefinition = $this->_table->getDefinition()) !== null + && ($parentTable->getDefinition() == null)) { + $parentTable->setOptions(array(Zend_Db_Table_Abstract::DEFINITION => $tableDefinition)); + } + + if ($select === null) { + $select = $parentTable->select(); + } else { + $select->setTable($parentTable); + } + + $map = $this->_prepareReference($this->_getTable(), $parentTable, $ruleKey); + + // iterate the map, creating the proper wheres + for ($i = 0; $i < count($map[Zend_Db_Table_Abstract::COLUMNS]); ++$i) { + $dependentColumnName = $db->foldCase($map[Zend_Db_Table_Abstract::COLUMNS][$i]); + $value = $this->_data[$dependentColumnName]; + // Use adapter from parent table to ensure correct query construction + $parentDb = $parentTable->getAdapter(); + $parentColumnName = $parentDb->foldCase($map[Zend_Db_Table_Abstract::REF_COLUMNS][$i]); + $parentColumn = $parentDb->quoteIdentifier($parentColumnName, true); + $parentInfo = $parentTable->info(); + + // determine where part + $type = $parentInfo[Zend_Db_Table_Abstract::METADATA][$parentColumnName]['DATA_TYPE']; + $nullable = $parentInfo[Zend_Db_Table_Abstract::METADATA][$parentColumnName]['NULLABLE']; + if ($value === null && $nullable == true) { + $select->where("$parentColumn IS NULL"); + } elseif ($value === null && $nullable == false) { + return null; + } else { + $select->where("$parentColumn = ?", $value, $type); + } + + } + + return $parentTable->fetchRow($select); + } + + /** + * @param string|Zend_Db_Table_Abstract $matchTable + * @param string|Zend_Db_Table_Abstract $intersectionTable + * @param string OPTIONAL $callerRefRule + * @param string OPTIONAL $matchRefRule + * @param Zend_Db_Table_Select OPTIONAL $select + * @return Zend_Db_Table_Rowset_Abstract Query result from $matchTable + * @throws Zend_Db_Table_Row_Exception If $matchTable or $intersectionTable is not a table class or is not loadable. + */ + public function findManyToManyRowset($matchTable, $intersectionTable, $callerRefRule = null, + $matchRefRule = null, Zend_Db_Table_Select $select = null) + { + $db = $this->_getTable()->getAdapter(); + + if (is_string($intersectionTable)) { + $intersectionTable = $this->_getTableFromString($intersectionTable); + } + + if (!$intersectionTable instanceof Zend_Db_Table_Abstract) { + $type = gettype($intersectionTable); + if ($type == 'object') { + $type = get_class($intersectionTable); + } + throw new Zend_Db_Table_Row_Exception("Intersection table must be a Zend_Db_Table_Abstract, but it is $type"); + } + + // even if we are interacting between a table defined in a class and a + // table via extension, ensure to persist the definition + if (($tableDefinition = $this->_table->getDefinition()) !== null + && ($intersectionTable->getDefinition() == null)) { + $intersectionTable->setOptions(array(Zend_Db_Table_Abstract::DEFINITION => $tableDefinition)); + } + + if (is_string($matchTable)) { + $matchTable = $this->_getTableFromString($matchTable); + } + + if (! $matchTable instanceof Zend_Db_Table_Abstract) { + $type = gettype($matchTable); + if ($type == 'object') { + $type = get_class($matchTable); + } + throw new Zend_Db_Table_Row_Exception("Match table must be a Zend_Db_Table_Abstract, but it is $type"); + } + + // even if we are interacting between a table defined in a class and a + // table via extension, ensure to persist the definition + if (($tableDefinition = $this->_table->getDefinition()) !== null + && ($matchTable->getDefinition() == null)) { + $matchTable->setOptions(array(Zend_Db_Table_Abstract::DEFINITION => $tableDefinition)); + } + + if ($select === null) { + $select = $matchTable->select(); + } else { + $select->setTable($matchTable); + } + + // Use adapter from intersection table to ensure correct query construction + $interInfo = $intersectionTable->info(); + $interDb = $intersectionTable->getAdapter(); + $interName = $interInfo['name']; + $interSchema = isset($interInfo['schema']) ? $interInfo['schema'] : null; + $matchInfo = $matchTable->info(); + $matchName = $matchInfo['name']; + $matchSchema = isset($matchInfo['schema']) ? $matchInfo['schema'] : null; + + $matchMap = $this->_prepareReference($intersectionTable, $matchTable, $matchRefRule); + + for ($i = 0; $i < count($matchMap[Zend_Db_Table_Abstract::COLUMNS]); ++$i) { + $interCol = $interDb->quoteIdentifier('i' . '.' . $matchMap[Zend_Db_Table_Abstract::COLUMNS][$i], true); + $matchCol = $interDb->quoteIdentifier('m' . '.' . $matchMap[Zend_Db_Table_Abstract::REF_COLUMNS][$i], true); + $joinCond[] = "$interCol = $matchCol"; + } + $joinCond = implode(' AND ', $joinCond); + + $select->from(array('i' => $interName), array(), $interSchema) + ->joinInner(array('m' => $matchName), $joinCond, Zend_Db_Select::SQL_WILDCARD, $matchSchema) + ->setIntegrityCheck(false); + + $callerMap = $this->_prepareReference($intersectionTable, $this->_getTable(), $callerRefRule); + + for ($i = 0; $i < count($callerMap[Zend_Db_Table_Abstract::COLUMNS]); ++$i) { + $callerColumnName = $db->foldCase($callerMap[Zend_Db_Table_Abstract::REF_COLUMNS][$i]); + $value = $this->_data[$callerColumnName]; + $interColumnName = $interDb->foldCase($callerMap[Zend_Db_Table_Abstract::COLUMNS][$i]); + $interCol = $interDb->quoteIdentifier("i.$interColumnName", true); + $interInfo = $intersectionTable->info(); + $type = $interInfo[Zend_Db_Table_Abstract::METADATA][$interColumnName]['DATA_TYPE']; + $select->where($interDb->quoteInto("$interCol = ?", $value, $type)); + } + + $stmt = $select->query(); + + $config = array( + 'table' => $matchTable, + 'data' => $stmt->fetchAll(Zend_Db::FETCH_ASSOC), + 'rowClass' => $matchTable->getRowClass(), + 'readOnly' => false, + 'stored' => true + ); + + $rowsetClass = $matchTable->getRowsetClass(); + if (!class_exists($rowsetClass)) { + try { + Zend_Loader::loadClass($rowsetClass); + } catch (Zend_Exception $e) { + throw new Zend_Db_Table_Row_Exception($e->getMessage(), $e->getCode(), $e); + } + } + $rowset = new $rowsetClass($config); + return $rowset; + } + + /** + * Turn magic function calls into non-magic function calls + * to the above methods. + * + * @param string $method + * @param array $args OPTIONAL Zend_Db_Table_Select query modifier + * @return Zend_Db_Table_Row_Abstract|Zend_Db_Table_Rowset_Abstract + * @throws Zend_Db_Table_Row_Exception If an invalid method is called. + */ + public function __call($method, array $args) + { + $matches = array(); + + if (count($args) && $args[0] instanceof Zend_Db_Table_Select) { + $select = $args[0]; + } else { + $select = null; + } + + /** + * Recognize methods for Has-Many cases: + * findParent() + * findParentBy() + * Use the non-greedy pattern repeat modifier e.g. \w+? + */ + if (preg_match('/^findParent(\w+?)(?:By(\w+))?$/', $method, $matches)) { + $class = $matches[1]; + $ruleKey1 = isset($matches[2]) ? $matches[2] : null; + return $this->findParentRow($class, $ruleKey1, $select); + } + + /** + * Recognize methods for Many-to-Many cases: + * findVia() + * findViaBy() + * findViaByAnd() + * Use the non-greedy pattern repeat modifier e.g. \w+? + */ + if (preg_match('/^find(\w+?)Via(\w+?)(?:By(\w+?)(?:And(\w+))?)?$/', $method, $matches)) { + $class = $matches[1]; + $viaClass = $matches[2]; + $ruleKey1 = isset($matches[3]) ? $matches[3] : null; + $ruleKey2 = isset($matches[4]) ? $matches[4] : null; + return $this->findManyToManyRowset($class, $viaClass, $ruleKey1, $ruleKey2, $select); + } + + /** + * Recognize methods for Belongs-To cases: + * find() + * findBy() + * Use the non-greedy pattern repeat modifier e.g. \w+? + */ + if (preg_match('/^find(\w+?)(?:By(\w+))?$/', $method, $matches)) { + $class = $matches[1]; + $ruleKey1 = isset($matches[2]) ? $matches[2] : null; + return $this->findDependentRowset($class, $ruleKey1, $select); + } + + throw new Zend_Db_Table_Row_Exception("Unrecognized method '$method()'"); + } + + + /** + * _getTableFromString + * + * @param string $tableName + * @return Zend_Db_Table_Abstract + */ + protected function _getTableFromString($tableName) + { + return Zend_Db_Table_Abstract::getTableFromString($tableName, $this->_table); + } + +} diff --git a/library/vendor/Zend/Db/Table/Row/Exception.php b/library/vendor/Zend/Db/Table/Row/Exception.php new file mode 100644 index 0000000..fe23d66 --- /dev/null +++ b/library/vendor/Zend/Db/Table/Row/Exception.php @@ -0,0 +1,37 @@ +_table = $config['table']; + $this->_tableClass = get_class($this->_table); + } + if (isset($config['rowClass'])) { + $this->_rowClass = $config['rowClass']; + } + if (!class_exists($this->_rowClass)) { + Zend_Loader::loadClass($this->_rowClass); + } + if (isset($config['data'])) { + $this->_data = $config['data']; + } + if (isset($config['readOnly'])) { + $this->_readOnly = $config['readOnly']; + } + if (isset($config['stored'])) { + $this->_stored = $config['stored']; + } + + // set the count of rows + $this->_count = count($this->_data); + + $this->init(); + } + + /** + * Store data, class names, and state in serialized object + * + * @return array + */ + public function __sleep() + { + return array('_data', '_tableClass', '_rowClass', '_pointer', '_count', '_rows', '_stored', + '_readOnly'); + } + + /** + * Setup to do on wakeup. + * A de-serialized Rowset should not be assumed to have access to a live + * database connection, so set _connected = false. + * + * @return void + */ + public function __wakeup() + { + $this->_connected = false; + } + + /** + * Initialize object + * + * Called from {@link __construct()} as final step of object instantiation. + * + * @return void + */ + public function init() + { + } + + /** + * Return the connected state of the rowset. + * + * @return boolean + */ + public function isConnected() + { + return $this->_connected; + } + + /** + * Returns the table object, or null if this is disconnected rowset + * + * @return Zend_Db_Table_Abstract + */ + public function getTable() + { + return $this->_table; + } + + /** + * Set the table object, to re-establish a live connection + * to the database for a Rowset that has been de-serialized. + * + * @param Zend_Db_Table_Abstract $table + * @return boolean + * @throws Zend_Db_Table_Row_Exception + */ + public function setTable(Zend_Db_Table_Abstract $table) + { + $this->_table = $table; + $this->_connected = false; + // @todo This works only if we have iterated through + // the result set once to instantiate the rows. + foreach ($this as $row) { + $connected = $row->setTable($table); + if ($connected == true) { + $this->_connected = true; + } + } + $this->rewind(); + return $this->_connected; + } + + /** + * Query the class name of the Table object for which this + * Rowset was created. + * + * @return string + */ + public function getTableClass() + { + return $this->_tableClass; + } + + /** + * Rewind the Iterator to the first element. + * Similar to the reset() function for arrays in PHP. + * Required by interface Iterator. + * + * @return Zend_Db_Table_Rowset_Abstract Fluent interface. + */ + public function rewind() + { + $this->_pointer = 0; + return $this; + } + + /** + * Return the current element. + * Similar to the current() function for arrays in PHP + * Required by interface Iterator. + * + * @return Zend_Db_Table_Row_Abstract current element from the collection + */ + public function current() + { + if ($this->valid() === false) { + return null; + } + + // return the row object + return $this->_loadAndReturnRow($this->_pointer); + } + + /** + * Return the identifying key of the current element. + * Similar to the key() function for arrays in PHP. + * Required by interface Iterator. + * + * @return int + */ + public function key() + { + return $this->_pointer; + } + + /** + * Move forward to next element. + * Similar to the next() function for arrays in PHP. + * Required by interface Iterator. + * + * @return void + */ + public function next() + { + ++$this->_pointer; + } + + /** + * Check if there is a current element after calls to rewind() or next(). + * Used to check if we've iterated to the end of the collection. + * Required by interface Iterator. + * + * @return bool False if there's nothing more to iterate over + */ + public function valid() + { + return $this->_pointer >= 0 && $this->_pointer < $this->_count; + } + + /** + * Returns the number of elements in the collection. + * + * Implements Countable::count() + * + * @return int + */ + public function count() + { + return $this->_count; + } + + /** + * Take the Iterator to position $position + * Required by interface SeekableIterator. + * + * @param int $position the position to seek to + * @return Zend_Db_Table_Rowset_Abstract + * @throws Zend_Db_Table_Rowset_Exception + */ + public function seek($position) + { + $position = (int) $position; + if ($position < 0 || $position >= $this->_count) { + throw new Zend_Db_Table_Rowset_Exception("Illegal index $position"); + } + $this->_pointer = $position; + return $this; + } + + /** + * Check if an offset exists + * Required by the ArrayAccess implementation + * + * @param string $offset + * @return boolean + */ + public function offsetExists($offset) + { + return isset($this->_data[(int) $offset]); + } + + /** + * Get the row for the given offset + * Required by the ArrayAccess implementation + * + * @param string $offset + * @return Zend_Db_Table_Row_Abstract + */ + public function offsetGet($offset) + { + $offset = (int) $offset; + if ($offset < 0 || $offset >= $this->_count) { + throw new Zend_Db_Table_Rowset_Exception("Illegal index $offset"); + } + $this->_pointer = $offset; + + return $this->current(); + } + + /** + * Does nothing + * Required by the ArrayAccess implementation + * + * @param string $offset + * @param mixed $value + */ + public function offsetSet($offset, $value) + { + } + + /** + * Does nothing + * Required by the ArrayAccess implementation + * + * @param string $offset + */ + public function offsetUnset($offset) + { + } + + /** + * Returns a Zend_Db_Table_Row from a known position into the Iterator + * + * @param int $position the position of the row expected + * @param bool $seek wether or not seek the iterator to that position after + * @return Zend_Db_Table_Row + * @throws Zend_Db_Table_Rowset_Exception + */ + public function getRow($position, $seek = false) + { + try { + $row = $this->_loadAndReturnRow($position); + } catch (Zend_Db_Table_Rowset_Exception $e) { + throw new Zend_Db_Table_Rowset_Exception('No row could be found at position ' . (int) $position, 0, $e); + } + + if ($seek == true) { + $this->seek($position); + } + + return $row; + } + + /** + * Returns all data as an array. + * + * Updates the $_data property with current row object values. + * + * @return array + */ + public function toArray() + { + // @todo This works only if we have iterated through + // the result set once to instantiate the rows. + foreach ($this->_rows as $i => $row) { + $this->_data[$i] = $row->toArray(); + } + return $this->_data; + } + + protected function _loadAndReturnRow($position) + { + if (!isset($this->_data[$position])) { + throw new Zend_Db_Table_Rowset_Exception("Data for provided position does not exist"); + } + + // do we already have a row object for this position? + if (empty($this->_rows[$position])) { + $this->_rows[$position] = new $this->_rowClass( + array( + 'table' => $this->_table, + 'data' => $this->_data[$position], + 'stored' => $this->_stored, + 'readOnly' => $this->_readOnly + ) + ); + + if ( $this->_table instanceof Zend_Db_Table_Abstract ) { + $info = $this->_table->info(); + + if ( $this->_rows[$position] instanceof Zend_Db_Table_Row_Abstract ) { + if ($info['cols'] == array_keys($this->_data[$position])) { + $this->_rows[$position]->setTable($this->getTable()); + } + } + } else { + $this->_rows[$position]->setTable(null); + } + } + + // return the row object + return $this->_rows[$position]; + } + +} diff --git a/library/vendor/Zend/Db/Table/Rowset/Exception.php b/library/vendor/Zend/Db/Table/Rowset/Exception.php new file mode 100644 index 0000000..9879113 --- /dev/null +++ b/library/vendor/Zend/Db/Table/Rowset/Exception.php @@ -0,0 +1,36 @@ +getAdapter()); + + $this->setTable($table); + } + + /** + * Return the table that created this select object + * + * @return Zend_Db_Table_Abstract + */ + public function getTable() + { + return $this->_table; + } + + /** + * Sets the primary table name and retrieves the table schema. + * + * @param Zend_Db_Table_Abstract $adapter + * @return Zend_Db_Select This Zend_Db_Select object. + */ + public function setTable(Zend_Db_Table_Abstract $table) + { + $this->_adapter = $table->getAdapter(); + $this->_info = $table->info(); + $this->_table = $table; + + return $this; + } + + /** + * Sets the integrity check flag. + * + * Setting this flag to false skips the checks for table joins, allowing + * 'hybrid' table rows to be created. + * + * @param Zend_Db_Table_Abstract $adapter + * @return Zend_Db_Select This Zend_Db_Select object. + */ + public function setIntegrityCheck($flag = true) + { + $this->_integrityCheck = $flag; + return $this; + } + + /** + * Tests query to determine if expressions or aliases columns exist. + * + * @return boolean + */ + public function isReadOnly() + { + $readOnly = false; + $fields = $this->getPart(Zend_Db_Table_Select::COLUMNS); + $cols = $this->_info[Zend_Db_Table_Abstract::COLS]; + + if (!count($fields)) { + return $readOnly; + } + + foreach ($fields as $columnEntry) { + $column = $columnEntry[1]; + $alias = $columnEntry[2]; + + if ($alias !== null) { + $column = $alias; + } + + switch (true) { + case ($column == self::SQL_WILDCARD): + break; + + case ($column instanceof Zend_Db_Expr): + case (!in_array($column, $cols)): + $readOnly = true; + break 2; + } + } + + return $readOnly; + } + + /** + * Adds a FROM table and optional columns to the query. + * + * The table name can be expressed + * + * @param array|string|Zend_Db_Expr|Zend_Db_Table_Abstract $name The table name or an + associative array relating + table name to correlation + name. + * @param array|string|Zend_Db_Expr $cols The columns to select from this table. + * @param string $schema The schema name to specify, if any. + * @return Zend_Db_Table_Select This Zend_Db_Table_Select object. + */ + public function from($name, $cols = self::SQL_WILDCARD, $schema = null) + { + if ($name instanceof Zend_Db_Table_Abstract) { + $info = $name->info(); + $name = $info[Zend_Db_Table_Abstract::NAME]; + if (isset($info[Zend_Db_Table_Abstract::SCHEMA])) { + $schema = $info[Zend_Db_Table_Abstract::SCHEMA]; + } + } + + return $this->joinInner($name, null, $cols, $schema); + } + + /** + * Performs a validation on the select query before passing back to the parent class. + * Ensures that only columns from the primary Zend_Db_Table are returned in the result. + * + * @return string|null This object as a SELECT string (or null if a string cannot be produced) + */ + public function assemble() + { + $fields = $this->getPart(Zend_Db_Table_Select::COLUMNS); + $primary = $this->_info[Zend_Db_Table_Abstract::NAME]; + $schema = $this->_info[Zend_Db_Table_Abstract::SCHEMA]; + + + if (count($this->_parts[self::UNION]) == 0) { + + // If no fields are specified we assume all fields from primary table + if (!count($fields)) { + $this->from($primary, self::SQL_WILDCARD, $schema); + $fields = $this->getPart(Zend_Db_Table_Select::COLUMNS); + } + + $from = $this->getPart(Zend_Db_Table_Select::FROM); + + if ($this->_integrityCheck !== false) { + foreach ($fields as $columnEntry) { + list($table, $column) = $columnEntry; + + // Check each column to ensure it only references the primary table + if ($column) { + if (!isset($from[$table]) || $from[$table]['tableName'] != $primary) { + throw new Zend_Db_Table_Select_Exception('Select query cannot join with another table'); + } + } + } + } + } + + return parent::assemble(); + } +} diff --git a/library/vendor/Zend/Db/Table/Select/Exception.php b/library/vendor/Zend/Db/Table/Select/Exception.php new file mode 100644 index 0000000..7ed15be --- /dev/null +++ b/library/vendor/Zend/Db/Table/Select/Exception.php @@ -0,0 +1,38 @@ +_previous = $previous; + } else { + parent::__construct($msg, (int) $code, $previous); + } + } + + /** + * Overloading + * + * For PHP < 5.3.0, provides access to the getPrevious() method. + * + * @param string $method + * @param array $args + * @return mixed + */ + public function __call($method, array $args) + { + if ('getprevious' == strtolower($method)) { + return $this->_getPrevious(); + } + return null; + } + + /** + * String representation of the exception + * + * @return string + */ + public function __toString() + { + if (version_compare(PHP_VERSION, '5.3.0', '<')) { + if (null !== ($e = $this->getPrevious())) { + return $e->__toString() + . "\n\nNext " + . parent::__toString(); + } + } + return parent::__toString(); + } + + /** + * Returns previous Exception + * + * @return Exception|null + */ + protected function _getPrevious() + { + return $this->_previous; + } +} diff --git a/library/vendor/Zend/File/ClassFileLocator.php b/library/vendor/Zend/File/ClassFileLocator.php new file mode 100644 index 0000000..24e0541 --- /dev/null +++ b/library/vendor/Zend/File/ClassFileLocator.php @@ -0,0 +1,177 @@ +setInfoClass('Zend_File_PhpClassFile'); + + // Forward-compat with PHP 5.3 + if (version_compare(PHP_VERSION, '5.3.0', '<')) { + if (!defined('T_NAMESPACE')) { + define('T_NAMESPACE', 'namespace'); + } + if (!defined('T_NS_SEPARATOR')) { + define('T_NS_SEPARATOR', '\\'); + } + } + } + + /** + * Filter for files containing PHP classes, interfaces, or abstracts + * + * @return bool + */ + public function accept() + { + $file = $this->getInnerIterator()->current(); + // If we somehow have something other than an SplFileInfo object, just + // return false + if (!$file instanceof SplFileInfo) { + return false; + } + + // If we have a directory, it's not a file, so return false + if (!$file->isFile()) { + return false; + } + + // If not a PHP file, skip + if ($file->getBasename('.php') == $file->getBasename()) { + return false; + } + + $contents = file_get_contents($file->getRealPath()); + $tokens = token_get_all($contents); + $count = count($tokens); + $t_trait = defined('T_TRAIT') ? T_TRAIT : -1; // For preserve PHP 5.3 compatibility + for ($i = 0; $i < $count; $i++) { + $token = $tokens[$i]; + if (!is_array($token)) { + // single character token found; skip + $i++; + continue; + } + switch ($token[0]) { + case T_NAMESPACE: + // Namespace found; grab it for later + $namespace = ''; + for ($i++; $i < $count; $i++) { + $token = $tokens[$i]; + if (is_string($token)) { + if (';' === $token) { + $saveNamespace = false; + break; + } + if ('{' === $token) { + $saveNamespace = true; + break; + } + continue; + } + list($type, $content, $line) = $token; + switch ($type) { + case T_STRING: + case T_NS_SEPARATOR: + $namespace .= $content; + break; + } + } + if ($saveNamespace) { + $savedNamespace = $namespace; + } + break; + case $t_trait: + case T_CLASS: + case T_INTERFACE: + // Abstract class, class, interface or trait found + + // Get the classname + for ($i++; $i < $count; $i++) { + $token = $tokens[$i]; + if (is_string($token)) { + continue; + } + list($type, $content, $line) = $token; + if (T_STRING == $type) { + // If a classname was found, set it in the object, and + // return boolean true (found) + if (!isset($namespace) || null === $namespace) { + if (isset($saveNamespace) && $saveNamespace) { + $namespace = $savedNamespace; + } else { + $namespace = null; + } + + } + $class = (null === $namespace) ? $content : $namespace . '\\' . $content; + $file->addClass($class); + $namespace = null; + break; + } + } + break; + default: + break; + } + } + $classes = $file->getClasses(); + if (!empty($classes)) { + return true; + } + // No class-type tokens found; return false + return false; + } +} diff --git a/library/vendor/Zend/File/PhpClassFile.php b/library/vendor/Zend/File/PhpClassFile.php new file mode 100644 index 0000000..0edf340 --- /dev/null +++ b/library/vendor/Zend/File/PhpClassFile.php @@ -0,0 +1,56 @@ +classes; + } + + /** + * Add class + * + * @param string $class + * @return Zend_File_PhpClassFile + */ + public function addClass($class) + { + $this->classes[] = $class; + return $this; + } +} diff --git a/library/vendor/Zend/File/Transfer.php b/library/vendor/Zend/File/Transfer.php new file mode 100644 index 0000000..4ff0763 --- /dev/null +++ b/library/vendor/Zend/File/Transfer.php @@ -0,0 +1,122 @@ +setAdapter($adapter, $direction, $options); + } + + /** + * Sets a new adapter + * + * @param string $adapter Adapter to use + * @param boolean $direction OPTIONAL False means Download, true means upload + * @param array $options OPTIONAL Options to set for this adapter + * @throws Zend_File_Transfer_Exception + */ + public function setAdapter($adapter, $direction = false, $options = array()) + { + if (Zend_Loader::isReadable('Zend/File/Transfer/Adapter/' . ucfirst($adapter). '.php')) { + $adapter = 'Zend_File_Transfer_Adapter_' . ucfirst($adapter); + } + + if (!class_exists($adapter)) { + Zend_Loader::loadClass($adapter); + } + + $direction = (integer) $direction; + $this->_adapter[$direction] = new $adapter($options); + if (!$this->_adapter[$direction] instanceof Zend_File_Transfer_Adapter_Abstract) { + throw new Zend_File_Transfer_Exception("Adapter " . $adapter . " does not extend Zend_File_Transfer_Adapter_Abstract"); + } + + return $this; + } + + /** + * Returns all set adapters + * + * @param boolean $direction On null, all directions are returned + * On false, download direction is returned + * On true, upload direction is returned + * @return array|Zend_File_Transfer_Adapter + */ + public function getAdapter($direction = null) + { + if ($direction === null) { + return $this->_adapter; + } + + $direction = (integer) $direction; + return $this->_adapter[$direction]; + } + + /** + * Calls all methods from the adapter + * + * @param string $method Method to call + * @param array $options Options for this method + * @return mixed + */ + public function __call($method, array $options) + { + if (array_key_exists('direction', $options)) { + $direction = (integer) $options['direction']; + } else { + $direction = 0; + } + + if (method_exists($this->_adapter[$direction], $method)) { + return call_user_func_array(array($this->_adapter[$direction], $method), $options); + } + + throw new Zend_File_Transfer_Exception("Unknown method '" . $method . "' called!"); + } +} diff --git a/library/vendor/Zend/File/Transfer/Adapter/Abstract.php b/library/vendor/Zend/File/Transfer/Adapter/Abstract.php new file mode 100644 index 0000000..0a6b76c --- /dev/null +++ b/library/vendor/Zend/File/Transfer/Adapter/Abstract.php @@ -0,0 +1,1548 @@ + array( - Form is the name within the form or, if not set the filename + * name, - Original name of this file + * type, - Mime type of this file + * size, - Filesize in bytes + * tmp_name, - Internalally temporary filename for uploaded files + * error, - Error which has occured + * destination, - New destination for this file + * validators, - Set validator names for this file + * files - Set file names for this file + * )) + * + * @var array + */ + protected $_files = array(); + + /** + * TMP directory + * @var string + */ + protected $_tmpDir; + + /** + * Available options for file transfers + */ + protected $_options = array( + 'ignoreNoFile' => false, + 'useByteString' => true, + 'magicFile' => null, + 'detectInfos' => true, + ); + + /** + * Send file + * + * @param mixed $options + * @return bool + */ + abstract public function send($options = null); + + /** + * Receive file + * + * @param mixed $options + * @return bool + */ + abstract public function receive($options = null); + + /** + * Is file sent? + * + * @param array|string|null $files + * @return bool + */ + abstract public function isSent($files = null); + + /** + * Is file received? + * + * @param array|string|null $files + * @return bool + */ + abstract public function isReceived($files = null); + + /** + * Has a file been uploaded ? + * + * @param array|string|null $files + * @return bool + */ + abstract public function isUploaded($files = null); + + /** + * Has the file been filtered ? + * + * @param array|string|null $files + * @return bool + */ + abstract public function isFiltered($files = null); + + /** + * Retrieve progress of transfer + * + * @return float + */ + public static function getProgress() + { + throw new Zend_File_Transfer_Exception('Method must be implemented within the adapter'); + } + + /** + * Set plugin loader to use for validator or filter chain + * + * @param Zend_Loader_PluginLoader_Interface $loader + * @param string $type 'filter', or 'validate' + * @return Zend_File_Transfer_Adapter_Abstract + * @throws Zend_File_Transfer_Exception on invalid type + */ + public function setPluginLoader(Zend_Loader_PluginLoader_Interface $loader, $type) + { + $type = strtoupper($type); + switch ($type) { + case self::FILTER: + case self::VALIDATE: + $this->_loaders[$type] = $loader; + return $this; + default: + throw new Zend_File_Transfer_Exception(sprintf('Invalid type "%s" provided to setPluginLoader()', $type)); + } + } + + /** + * Retrieve plugin loader for validator or filter chain + * + * Instantiates with default rules if none available for that type. Use + * 'filter' or 'validate' for $type. + * + * @param string $type + * @return Zend_Loader_PluginLoader + * @throws Zend_File_Transfer_Exception on invalid type. + */ + public function getPluginLoader($type) + { + $type = strtoupper($type); + switch ($type) { + case self::FILTER: + case self::VALIDATE: + $prefixSegment = ucfirst(strtolower($type)); + $pathSegment = $prefixSegment; + if (!isset($this->_loaders[$type])) { + $paths = array( + 'Zend_' . $prefixSegment . '_' => 'Zend/' . $pathSegment . '/', + 'Zend_' . $prefixSegment . '_File' => 'Zend/' . $pathSegment . '/File', + ); + + $this->_loaders[$type] = new Zend_Loader_PluginLoader($paths); + } else { + $loader = $this->_loaders[$type]; + $prefix = 'Zend_' . $prefixSegment . '_File_'; + if (!$loader->getPaths($prefix)) { + $loader->addPrefixPath($prefix, str_replace('_', '/', $prefix)); + } + } + return $this->_loaders[$type]; + default: + throw new Zend_File_Transfer_Exception(sprintf('Invalid type "%s" provided to getPluginLoader()', $type)); + } + } + + /** + * Add prefix path for plugin loader + * + * If no $type specified, assumes it is a base path for both filters and + * validators, and sets each according to the following rules: + * - filters: $prefix = $prefix . '_Filter' + * - validators: $prefix = $prefix . '_Validate' + * + * Otherwise, the path prefix is set on the appropriate plugin loader. + * + * @param string $prefix + * @param string $path + * @param string $type + * @return Zend_File_Transfer_Adapter_Abstract + * @throws Zend_File_Transfer_Exception for invalid type + */ + public function addPrefixPath($prefix, $path, $type = null) + { + $type = strtoupper($type); + switch ($type) { + case self::FILTER: + case self::VALIDATE: + $loader = $this->getPluginLoader($type); + $loader->addPrefixPath($prefix, $path); + return $this; + case null: + $prefix = rtrim($prefix, '_'); + $path = rtrim($path, DIRECTORY_SEPARATOR); + foreach (array(self::FILTER, self::VALIDATE) as $type) { + $cType = ucfirst(strtolower($type)); + $pluginPath = $path . DIRECTORY_SEPARATOR . $cType . DIRECTORY_SEPARATOR; + $pluginPrefix = $prefix . '_' . $cType; + $loader = $this->getPluginLoader($type); + $loader->addPrefixPath($pluginPrefix, $pluginPath); + } + return $this; + default: + throw new Zend_File_Transfer_Exception(sprintf('Invalid type "%s" provided to getPluginLoader()', $type)); + } + } + + /** + * Add many prefix paths at once + * + * @param array $spec + * @return Zend_File_Transfer_Exception + */ + public function addPrefixPaths(array $spec) + { + if (isset($spec['prefix']) && isset($spec['path'])) { + return $this->addPrefixPath($spec['prefix'], $spec['path']); + } + foreach ($spec as $type => $paths) { + if (is_numeric($type) && is_array($paths)) { + $type = null; + if (isset($paths['prefix']) && isset($paths['path'])) { + if (isset($paths['type'])) { + $type = $paths['type']; + } + $this->addPrefixPath($paths['prefix'], $paths['path'], $type); + } + } elseif (!is_numeric($type)) { + if (!isset($paths['prefix']) || !isset($paths['path'])) { + foreach ($paths as $prefix => $spec) { + if (is_array($spec)) { + foreach ($spec as $path) { + if (!is_string($path)) { + continue; + } + $this->addPrefixPath($prefix, $path, $type); + } + } elseif (is_string($spec)) { + $this->addPrefixPath($prefix, $spec, $type); + } + } + } else { + $this->addPrefixPath($paths['prefix'], $paths['path'], $type); + } + } + } + return $this; + } + + /** + * Adds a new validator for this class + * + * @param string|array $validator Type of validator to add + * @param boolean $breakChainOnFailure If the validation chain should stop an failure + * @param string|array $options Options to set for the validator + * @param string|array $files Files to limit this validator to + * @return Zend_File_Transfer_Adapter + */ + public function addValidator($validator, $breakChainOnFailure = false, $options = null, $files = null) + { + if ($validator instanceof Zend_Validate_Interface) { + $name = get_class($validator); + } elseif (is_string($validator)) { + $name = $this->getPluginLoader(self::VALIDATE)->load($validator); + $validator = new $name($options); + if (is_array($options) && isset($options['messages'])) { + if (is_array($options['messages'])) { + $validator->setMessages($options['messages']); + } elseif (is_string($options['messages'])) { + $validator->setMessage($options['messages']); + } + + unset($options['messages']); + } + } else { + throw new Zend_File_Transfer_Exception('Invalid validator provided to addValidator; must be string or Zend_Validate_Interface'); + } + + $this->_validators[$name] = $validator; + $this->_break[$name] = $breakChainOnFailure; + $files = $this->_getFiles($files, true, true); + foreach ($files as $file) { + if ($name == 'NotEmpty') { + $temp = $this->_files[$file]['validators']; + $this->_files[$file]['validators'] = array($name); + $this->_files[$file]['validators'] += $temp; + } else { + $this->_files[$file]['validators'][] = $name; + } + + $this->_files[$file]['validated'] = false; + } + + return $this; + } + + /** + * Add Multiple validators at once + * + * @param array $validators + * @param string|array $files + * @return Zend_File_Transfer_Adapter_Abstract + */ + public function addValidators(array $validators, $files = null) + { + foreach ($validators as $name => $validatorInfo) { + if ($validatorInfo instanceof Zend_Validate_Interface) { + $this->addValidator($validatorInfo, null, null, $files); + } else if (is_string($validatorInfo)) { + if (!is_int($name)) { + $this->addValidator($name, null, $validatorInfo, $files); + } else { + $this->addValidator($validatorInfo, null, null, $files); + } + } else if (is_array($validatorInfo)) { + $argc = count($validatorInfo); + $breakChainOnFailure = false; + $options = array(); + if (isset($validatorInfo['validator'])) { + $validator = $validatorInfo['validator']; + if (isset($validatorInfo['breakChainOnFailure'])) { + $breakChainOnFailure = $validatorInfo['breakChainOnFailure']; + } + + if (isset($validatorInfo['options'])) { + $options = $validatorInfo['options']; + } + + $this->addValidator($validator, $breakChainOnFailure, $options, $files); + } else { + if (is_string($name)) { + $validator = $name; + $options = $validatorInfo; + $this->addValidator($validator, $breakChainOnFailure, $options, $files); + } else { + $file = $files; + switch (true) { + case (0 == $argc): + break; + case (1 <= $argc): + $validator = array_shift($validatorInfo); + case (2 <= $argc): + $breakChainOnFailure = array_shift($validatorInfo); + case (3 <= $argc): + $options = array_shift($validatorInfo); + case (4 <= $argc): + if (!empty($validatorInfo)) { + $file = array_shift($validatorInfo); + } + default: + $this->addValidator($validator, $breakChainOnFailure, $options, $file); + break; + } + } + } + } else { + throw new Zend_File_Transfer_Exception('Invalid validator passed to addValidators()'); + } + } + + return $this; + } + + /** + * Sets a validator for the class, erasing all previous set + * + * @param string|array $validator Validator to set + * @param string|array $files Files to limit this validator to + * @return Zend_File_Transfer_Adapter + */ + public function setValidators(array $validators, $files = null) + { + $this->clearValidators(); + return $this->addValidators($validators, $files); + } + + /** + * Determine if a given validator has already been registered + * + * @param string $name + * @return bool + */ + public function hasValidator($name) + { + return (false !== $this->_getValidatorIdentifier($name)); + } + + /** + * Retrieve individual validator + * + * @param string $name + * @return Zend_Validate_Interface|null + */ + public function getValidator($name) + { + if (false === ($identifier = $this->_getValidatorIdentifier($name))) { + return null; + } + return $this->_validators[$identifier]; + } + + /** + * Returns all set validators + * + * @param string|array $files (Optional) Returns the validator for this files + * @return null|array List of set validators + */ + public function getValidators($files = null) + { + if ($files == null) { + return $this->_validators; + } + + $files = $this->_getFiles($files, true, true); + $validators = array(); + foreach ($files as $file) { + if (!empty($this->_files[$file]['validators'])) { + $validators += $this->_files[$file]['validators']; + } + } + + $validators = array_unique($validators); + $result = array(); + foreach ($validators as $validator) { + $result[$validator] = $this->_validators[$validator]; + } + + return $result; + } + + /** + * Remove an individual validator + * + * @param string $name + * @return Zend_File_Transfer_Adapter_Abstract + */ + public function removeValidator($name) + { + if (false === ($key = $this->_getValidatorIdentifier($name))) { + return $this; + } + + unset($this->_validators[$key]); + foreach (array_keys($this->_files) as $file) { + if (empty($this->_files[$file]['validators'])) { + continue; + } + + $index = array_search($key, $this->_files[$file]['validators']); + if ($index === false) { + continue; + } + + unset($this->_files[$file]['validators'][$index]); + $this->_files[$file]['validated'] = false; + } + + return $this; + } + + /** + * Remove all validators + * + * @return Zend_File_Transfer_Adapter_Abstract + */ + public function clearValidators() + { + $this->_validators = array(); + foreach (array_keys($this->_files) as $file) { + $this->_files[$file]['validators'] = array(); + $this->_files[$file]['validated'] = false; + } + + return $this; + } + + /** + * Sets Options for adapters + * + * @param array $options Options to set + * @param array $files (Optional) Files to set the options for + * @return Zend_File_Transfer_Adapter_Abstract + */ + public function setOptions($options = array(), $files = null) { + $file = $this->_getFiles($files, false, true); + + if (is_array($options)) { + if (empty($file)) { + $this->_options = array_merge($this->_options, $options); + } + + foreach ($options as $name => $value) { + foreach ($file as $key => $content) { + switch ($name) { + case 'magicFile' : + $this->_files[$key]['options'][$name] = (string) $value; + break; + + case 'ignoreNoFile' : + case 'useByteString' : + case 'detectInfos' : + $this->_files[$key]['options'][$name] = (boolean) $value; + break; + + default: + throw new Zend_File_Transfer_Exception("Unknown option: $name = $value"); + } + } + } + } + + return $this; + } + + /** + * Returns set options for adapters or files + * + * @param array $files (Optional) Files to return the options for + * @return array Options for given files + */ + public function getOptions($files = null) { + $file = $this->_getFiles($files, false, true); + + foreach ($file as $key => $content) { + if (isset($this->_files[$key]['options'])) { + $options[$key] = $this->_files[$key]['options']; + } else { + $options[$key] = array(); + } + } + + return $options; + } + + /** + * Checks if the files are valid + * + * @param string|array $files (Optional) Files to check + * @return boolean True if all checks are valid + */ + public function isValid($files = null) + { + $check = $this->_getFiles($files, false, true); + if (empty($check)) { + return false; + } + + $translator = $this->getTranslator(); + $this->_messages = array(); + $break = false; + foreach($check as $key => $content) { + if (array_key_exists('validators', $content) && + in_array('Zend_Validate_File_Count', $content['validators'])) { + $validator = $this->_validators['Zend_Validate_File_Count']; + $count = $content; + if (empty($content['tmp_name'])) { + continue; + } + + if (array_key_exists('destination', $content)) { + $checkit = $content['destination']; + } else { + $checkit = dirname($content['tmp_name']); + } + + $checkit .= DIRECTORY_SEPARATOR . $content['name']; + $validator->addFile($checkit); + } + } + + if (isset($count)) { + if (!$validator->isValid($count['tmp_name'], $count)) { + $this->_messages += $validator->getMessages(); + } + } + + foreach ($check as $key => $content) { + $fileerrors = array(); + if (array_key_exists('validators', $content) && $content['validated']) { + continue; + } + + if (array_key_exists('validators', $content)) { + foreach ($content['validators'] as $class) { + $validator = $this->_validators[$class]; + if (method_exists($validator, 'setTranslator')) { + $validator->setTranslator($translator); + } + + if (($class === 'Zend_Validate_File_Upload') and (empty($content['tmp_name']))) { + $tocheck = $key; + } else { + $tocheck = $content['tmp_name']; + } + + if (!$validator->isValid($tocheck, $content)) { + $fileerrors += $validator->getMessages(); + } + + if (!empty($content['options']['ignoreNoFile']) and (isset($fileerrors['fileUploadErrorNoFile']))) { + unset($fileerrors['fileUploadErrorNoFile']); + break; + } + + if (($class === 'Zend_Validate_File_Upload') and (count($fileerrors) > 0)) { + break; + } + + if (($this->_break[$class]) and (count($fileerrors) > 0)) { + $break = true; + break; + } + } + } + + if (count($fileerrors) > 0) { + $this->_files[$key]['validated'] = false; + } else { + $this->_files[$key]['validated'] = true; + } + + $this->_messages += $fileerrors; + if ($break) { + break; + } + } + + if (count($this->_messages) > 0) { + return false; + } + + return true; + } + + /** + * Returns found validation messages + * + * @return array + */ + public function getMessages() + { + return $this->_messages; + } + + /** + * Retrieve error codes + * + * @return array + */ + public function getErrors() + { + return array_keys($this->_messages); + } + + /** + * Are there errors registered? + * + * @return boolean + */ + public function hasErrors() + { + return (!empty($this->_messages)); + } + + /** + * Adds a new filter for this class + * + * @param string|array $filter Type of filter to add + * @param string|array $options Options to set for the filter + * @param string|array $files Files to limit this filter to + * @return Zend_File_Transfer_Adapter + */ + public function addFilter($filter, $options = null, $files = null) + { + if ($filter instanceof Zend_Filter_Interface) { + $class = get_class($filter); + } elseif (is_string($filter)) { + $class = $this->getPluginLoader(self::FILTER)->load($filter); + $filter = new $class($options); + } else { + throw new Zend_File_Transfer_Exception('Invalid filter specified'); + } + + $this->_filters[$class] = $filter; + $files = $this->_getFiles($files, true, true); + foreach ($files as $file) { + $this->_files[$file]['filters'][] = $class; + } + + return $this; + } + + /** + * Add Multiple filters at once + * + * @param array $filters + * @param string|array $files + * @return Zend_File_Transfer_Adapter_Abstract + */ + public function addFilters(array $filters, $files = null) + { + foreach ($filters as $key => $spec) { + if ($spec instanceof Zend_Filter_Interface) { + $this->addFilter($spec, null, $files); + continue; + } + + if (is_string($key)) { + $this->addFilter($key, $spec, $files); + continue; + } + + if (is_int($key)) { + if (is_string($spec)) { + $this->addFilter($spec, null, $files); + continue; + } + + if (is_array($spec)) { + if (!array_key_exists('filter', $spec)) { + continue; + } + + $filter = $spec['filter']; + unset($spec['filter']); + $this->addFilter($filter, $spec, $files); + continue; + } + + continue; + } + } + + return $this; + } + + /** + * Sets a filter for the class, erasing all previous set + * + * @param string|array $filter Filter to set + * @param string|array $files Files to limit this filter to + * @return Zend_File_Transfer_Adapter + */ + public function setFilters(array $filters, $files = null) + { + $this->clearFilters(); + return $this->addFilters($filters, $files); + } + + /** + * Determine if a given filter has already been registered + * + * @param string $name + * @return bool + */ + public function hasFilter($name) + { + return (false !== $this->_getFilterIdentifier($name)); + } + + /** + * Retrieve individual filter + * + * @param string $name + * @return Zend_Filter_Interface|null + */ + public function getFilter($name) + { + if (false === ($identifier = $this->_getFilterIdentifier($name))) { + return null; + } + return $this->_filters[$identifier]; + } + + /** + * Returns all set filters + * + * @param string|array $files (Optional) Returns the filter for this files + * @return array List of set filters + * @throws Zend_File_Transfer_Exception When file not found + */ + public function getFilters($files = null) + { + if ($files === null) { + return $this->_filters; + } + + $files = $this->_getFiles($files, true, true); + $filters = array(); + foreach ($files as $file) { + if (!empty($this->_files[$file]['filters'])) { + $filters += $this->_files[$file]['filters']; + } + } + + $filters = array_unique($filters); + $result = array(); + foreach ($filters as $filter) { + $result[] = $this->_filters[$filter]; + } + + return $result; + } + + /** + * Remove an individual filter + * + * @param string $name + * @return Zend_File_Transfer_Adapter_Abstract + */ + public function removeFilter($name) + { + if (false === ($key = $this->_getFilterIdentifier($name))) { + return $this; + } + + unset($this->_filters[$key]); + foreach (array_keys($this->_files) as $file) { + if (empty($this->_files[$file]['filters'])) { + continue; + } + + $index = array_search($key, $this->_files[$file]['filters']); + if ($index === false) { + continue; + } + + unset($this->_files[$file]['filters'][$index]); + } + return $this; + } + + /** + * Remove all filters + * + * @return Zend_File_Transfer_Adapter_Abstract + */ + public function clearFilters() + { + $this->_filters = array(); + foreach (array_keys($this->_files) as $file) { + $this->_files[$file]['filters'] = array(); + } + return $this; + } + + /** + * Returns all set files + * + * @return array List of set files + * @throws Zend_File_Transfer_Exception Not implemented + */ + public function getFile() + { + throw new Zend_File_Transfer_Exception('Method not implemented'); + } + + /** + * Retrieves the filename of transferred files. + * + * @param string|null $file + * @param boolean $path (Optional) Should the path also be returned ? + * @return string|array + */ + public function getFileName($file = null, $path = true) + { + $files = $this->_getFiles($file, true, true); + $result = array(); + $directory = ""; + foreach($files as $file) { + if (empty($this->_files[$file]['name'])) { + continue; + } + + if ($path === true) { + $directory = $this->getDestination($file) . DIRECTORY_SEPARATOR; + } + + $result[$file] = $directory . $this->_files[$file]['name']; + } + + if (count($result) == 1) { + return current($result); + } + + return $result; + } + + /** + * Retrieve additional internal file informations for files + * + * @param string $file (Optional) File to get informations for + * @return array + */ + public function getFileInfo($file = null) + { + return $this->_getFiles($file); + } + + /** + * Adds one or more files + * + * @param string|array $file File to add + * @param string|array $validator Validators to use for this file, must be set before + * @param string|array $filter Filters to use for this file, must be set before + * @return Zend_File_Transfer_Adapter_Abstract + * @throws Zend_File_Transfer_Exception Not implemented + */ + public function addFile($file, $validator = null, $filter = null) + { + throw new Zend_File_Transfer_Exception('Method not implemented'); + } + + /** + * Returns all set types + * + * @return array List of set types + * @throws Zend_File_Transfer_Exception Not implemented + */ + public function getType() + { + throw new Zend_File_Transfer_Exception('Method not implemented'); + } + + /** + * Adds one or more type of files + * + * @param string|array $type Type of files to add + * @param string|array $validator Validators to use for this file, must be set before + * @param string|array $filter Filters to use for this file, must be set before + * @return Zend_File_Transfer_Adapter_Abstract + * @throws Zend_File_Transfer_Exception Not implemented + */ + public function addType($type, $validator = null, $filter = null) + { + throw new Zend_File_Transfer_Exception('Method not implemented'); + } + + /** + * Sets a new destination for the given files + * + * @deprecated Will be changed to be a filter!!! + * @param string $destination New destination directory + * @param string|array $files Files to set the new destination for + * @return Zend_File_Transfer_Abstract + * @throws Zend_File_Transfer_Exception when the given destination is not a directory or does not exist + */ + public function setDestination($destination, $files = null) + { + $orig = $files; + $destination = rtrim($destination, "/\\"); + if (!is_dir($destination)) { + throw new Zend_File_Transfer_Exception( + 'The given destination is not a directory or does not exist' + ); + } + + if (!$this->_isPathWriteable($destination)) { + throw new Zend_File_Transfer_Exception( + 'The given destination is not writable' + ); + } + + if ($files === null) { + foreach ($this->_files as $file => $content) { + $this->_files[$file]['destination'] = $destination; + } + } else { + $files = $this->_getFiles($files, true, true); + if (empty($files) and is_string($orig)) { + $this->_files[$orig]['destination'] = $destination; + } + + foreach ($files as $file) { + $this->_files[$file]['destination'] = $destination; + } + } + + return $this; + } + + /** + * Retrieve destination directory value + * + * @param null|string|array $files + * @return null|string|array + * @throws Zend_File_Transfer_Exception + */ + public function getDestination($files = null) + { + $orig = $files; + $files = $this->_getFiles($files, false, true); + $destinations = array(); + if (empty($files) and is_string($orig)) { + if (isset($this->_files[$orig]['destination'])) { + $destinations[$orig] = $this->_files[$orig]['destination']; + } else { + throw new Zend_File_Transfer_Exception(sprintf('The file transfer adapter can not find "%s"', $orig)); + } + } + + foreach ($files as $key => $content) { + if (isset($this->_files[$key]['destination'])) { + $destinations[$key] = $this->_files[$key]['destination']; + } else { + $tmpdir = $this->_getTmpDir(); + $this->setDestination($tmpdir, $key); + $destinations[$key] = $tmpdir; + } + } + + if (empty($destinations)) { + $destinations = $this->_getTmpDir(); + } else if (count($destinations) == 1) { + $destinations = current($destinations); + } + + return $destinations; + } + + /** + * Set translator object for localization + * + * @param Zend_Translate|null $translator + * @return Zend_File_Transfer_Abstract + * @throws Zend_File_Transfer_Exception + */ + public function setTranslator($translator = null) + { + if (null === $translator) { + $this->_translator = null; + } elseif ($translator instanceof Zend_Translate_Adapter) { + $this->_translator = $translator; + } elseif ($translator instanceof Zend_Translate) { + $this->_translator = $translator->getAdapter(); + } else { + throw new Zend_File_Transfer_Exception('Invalid translator specified'); + } + + return $this; + } + + /** + * Retrieve localization translator object + * + * @return Zend_Translate_Adapter|null + */ + public function getTranslator() + { + if ($this->translatorIsDisabled()) { + return null; + } + + return $this->_translator; + } + + /** + * Indicate whether or not translation should be disabled + * + * @param bool $flag + * @return Zend_File_Transfer_Abstract + */ + public function setDisableTranslator($flag) + { + $this->_translatorDisabled = (bool) $flag; + return $this; + } + + /** + * Is translation disabled? + * + * @return bool + */ + public function translatorIsDisabled() + { + return $this->_translatorDisabled; + } + + /** + * Returns the hash for a given file + * + * @param string $hash Hash algorithm to use + * @param string|array $files Files to return the hash for + * @return string|array Hashstring + * @throws Zend_File_Transfer_Exception On unknown hash algorithm + */ + public function getHash($hash = 'crc32', $files = null) + { + if (!in_array($hash, hash_algos())) { + throw new Zend_File_Transfer_Exception('Unknown hash algorithm'); + } + + $files = $this->_getFiles($files); + $result = array(); + foreach($files as $key => $value) { + if (file_exists($value['name'])) { + $result[$key] = hash_file($hash, $value['name']); + } else if (file_exists($value['tmp_name'])) { + $result[$key] = hash_file($hash, $value['tmp_name']); + } else if (empty($value['options']['ignoreNoFile'])) { + throw new Zend_File_Transfer_Exception("The file '{$value['name']}' does not exist"); + } + } + + if (count($result) == 1) { + return current($result); + } + + return $result; + } + + /** + * Returns the real filesize of the file + * + * @param string|array $files Files to get the filesize from + * @throws Zend_File_Transfer_Exception When the file does not exist + * @return string|array Filesize + */ + public function getFileSize($files = null) + { + $files = $this->_getFiles($files); + $result = array(); + foreach($files as $key => $value) { + if (file_exists($value['name']) || file_exists($value['tmp_name'])) { + if ($value['options']['useByteString']) { + $result[$key] = self::_toByteString($value['size']); + } else { + $result[$key] = $value['size']; + } + } else if (empty($value['options']['ignoreNoFile'])) { + throw new Zend_File_Transfer_Exception("The file '{$value['name']}' does not exist"); + } else { + continue; + } + } + + if (count($result) == 1) { + return current($result); + } + + return $result; + } + + /** + * Internal method to detect the size of a file + * + * @param array $value File infos + * @return string Filesize of given file + */ + protected function _detectFileSize($value) + { + if (file_exists($value['name'])) { + $result = sprintf("%u", @filesize($value['name'])); + } else if (file_exists($value['tmp_name'])) { + $result = sprintf("%u", @filesize($value['tmp_name'])); + } else { + return null; + } + + return $result; + } + + /** + * Returns the real mimetype of the file + * Uses fileinfo, when not available mime_magic and as last fallback a manual given mimetype + * + * @param string|array $files Files to get the mimetype from + * @throws Zend_File_Transfer_Exception When the file does not exist + * @return string|array MimeType + */ + public function getMimeType($files = null) + { + $files = $this->_getFiles($files); + $result = array(); + foreach($files as $key => $value) { + if (file_exists($value['name']) || file_exists($value['tmp_name'])) { + $result[$key] = $value['type']; + } else if (empty($value['options']['ignoreNoFile'])) { + throw new Zend_File_Transfer_Exception("The file '{$value['name']}' does not exist"); + } else { + continue; + } + } + + if (count($result) == 1) { + return current($result); + } + + return $result; + } + + /** + * Internal method to detect the mime type of a file + * + * @param array $value File infos + * @return string Mimetype of given file + */ + protected function _detectMimeType($value) + { + if (file_exists($value['name'])) { + $file = $value['name']; + } else if (file_exists($value['tmp_name'])) { + $file = $value['tmp_name']; + } else { + return null; + } + + if (class_exists('finfo', false)) { + $const = defined('FILEINFO_MIME_TYPE') ? FILEINFO_MIME_TYPE : FILEINFO_MIME; + if (!empty($value['options']['magicFile'])) { + $mime = @finfo_open($const, $value['options']['magicFile']); + } + + if (empty($mime)) { + $mime = @finfo_open($const); + } + + if (!empty($mime)) { + $result = finfo_file($mime, $file); + } + + unset($mime); + } + + if (empty($result) && (function_exists('mime_content_type') + && ini_get('mime_magic.magicfile'))) { + $result = mime_content_type($file); + } + + if (empty($result)) { + $result = 'application/octet-stream'; + } + + return $result; + } + + /** + * Returns the formatted size + * + * @param integer $size + * @return string + */ + protected static function _toByteString($size) + { + $sizes = array('B', 'kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'); + for ($i=0; $size >= 1024 && $i < 9; $i++) { + $size /= 1024; + } + + return round($size, 2) . $sizes[$i]; + } + + /** + * Internal function to filter all given files + * + * @param string|array $files (Optional) Files to check + * @return boolean False on error + */ + protected function _filter($files = null) + { + $check = $this->_getFiles($files); + foreach ($check as $name => $content) { + if (array_key_exists('filters', $content)) { + foreach ($content['filters'] as $class) { + $filter = $this->_filters[$class]; + try { + $result = $filter->filter($this->getFileName($name)); + + $this->_files[$name]['destination'] = dirname($result); + $this->_files[$name]['name'] = basename($result); + } catch (Zend_Filter_Exception $e) { + $this->_messages += array($e->getMessage()); + } + } + } + } + + if (count($this->_messages) > 0) { + return false; + } + + return true; + } + + /** + * Determine system TMP directory and detect if we have read access + * + * @return string + * @throws Zend_File_Transfer_Exception if unable to determine directory + */ + protected function _getTmpDir() + { + if (null === $this->_tmpDir) { + $tmpdir = array(); + if (function_exists('sys_get_temp_dir')) { + $tmpdir[] = sys_get_temp_dir(); + } + + if (!empty($_ENV['TMP'])) { + $tmpdir[] = realpath($_ENV['TMP']); + } + + if (!empty($_ENV['TMPDIR'])) { + $tmpdir[] = realpath($_ENV['TMPDIR']); + } + + if (!empty($_ENV['TEMP'])) { + $tmpdir[] = realpath($_ENV['TEMP']); + } + + $upload = ini_get('upload_tmp_dir'); + if ($upload) { + $tmpdir[] = realpath($upload); + } + + foreach($tmpdir as $directory) { + if ($this->_isPathWriteable($directory)) { + $this->_tmpDir = $directory; + } + } + + if (empty($this->_tmpDir)) { + // Attemp to detect by creating a temporary file + $tempFile = tempnam(md5(uniqid(rand(), TRUE)), ''); + if ($tempFile) { + $this->_tmpDir = realpath(dirname($tempFile)); + unlink($tempFile); + } else { + throw new Zend_File_Transfer_Exception('Could not determine a temporary directory'); + } + } + + $this->_tmpDir = rtrim($this->_tmpDir, "/\\"); + } + return $this->_tmpDir; + } + + /** + * Tries to detect if we can read and write to the given path + * + * @param string $path + * @return bool + */ + protected function _isPathWriteable($path) + { + $tempFile = rtrim($path, "/\\"); + $tempFile .= '/' . 'test.1'; + + $result = @file_put_contents($tempFile, 'TEST'); + + if ($result == false) { + return false; + } + + $result = @unlink($tempFile); + + if ($result == false) { + return false; + } + + return true; + } + + /** + * Returns found files based on internal file array and given files + * + * @param string|array $files (Optional) Files to return + * @param boolean $names (Optional) Returns only names on true, else complete info + * @param boolean $noexception (Optional) Allows throwing an exception, otherwise returns an empty array + * @return array Found files + * @throws Zend_File_Transfer_Exception On false filename + */ + protected function _getFiles($files, $names = false, $noexception = false) + { + $check = array(); + + if (is_string($files)) { + $files = array($files); + } + + if (is_array($files)) { + foreach ($files as $find) { + $found = array(); + foreach ($this->_files as $file => $content) { + if (!isset($content['name'])) { + continue; + } + + if (($content['name'] === $find) && isset($content['multifiles'])) { + foreach ($content['multifiles'] as $multifile) { + $found[] = $multifile; + } + break; + } + + if ($file === $find) { + $found[] = $file; + break; + } + + if ($content['name'] === $find) { + $found[] = $file; + break; + } + } + + if (empty($found)) { + if ($noexception !== false) { + return array(); + } + + throw new Zend_File_Transfer_Exception(sprintf('The file transfer adapter can not find "%s"', $find)); + } + + foreach ($found as $checked) { + $check[$checked] = $this->_files[$checked]; + } + } + } + + if ($files === null) { + $check = $this->_files; + $keys = array_keys($check); + foreach ($keys as $key) { + if (isset($check[$key]['multifiles'])) { + unset($check[$key]); + } + } + } + + if ($names) { + $check = array_keys($check); + } + + return $check; + } + + /** + * Retrieve internal identifier for a named validator + * + * @param string $name + * @return string + */ + protected function _getValidatorIdentifier($name) + { + if (array_key_exists($name, $this->_validators)) { + return $name; + } + + foreach (array_keys($this->_validators) as $test) { + if (preg_match('/' . preg_quote($name) . '$/i', $test)) { + return $test; + } + } + + return false; + } + + /** + * Retrieve internal identifier for a named filter + * + * @param string $name + * @return string + */ + protected function _getFilterIdentifier($name) + { + if (array_key_exists($name, $this->_filters)) { + return $name; + } + + foreach (array_keys($this->_filters) as $test) { + if (preg_match('/' . preg_quote($name) . '$/i', $test)) { + return $test; + } + } + + return false; + } +} diff --git a/library/vendor/Zend/File/Transfer/Adapter/Http.php b/library/vendor/Zend/File/Transfer/Adapter/Http.php new file mode 100644 index 0000000..08e56c0 --- /dev/null +++ b/library/vendor/Zend/File/Transfer/Adapter/Http.php @@ -0,0 +1,480 @@ +setOptions($options); + $this->_prepareFiles(); + $this->addValidator('Upload', false, $this->_files); + } + + /** + * Sets a validator for the class, erasing all previous set + * + * @param string|array $validator Validator to set + * @param string|array $files Files to limit this validator to + * @return Zend_File_Transfer_Adapter + */ + public function setValidators(array $validators, $files = null) + { + $this->clearValidators(); + return $this->addValidators($validators, $files); + } + + /** + * Remove an individual validator + * + * @param string $name + * @return Zend_File_Transfer_Adapter_Abstract + */ + public function removeValidator($name) + { + if ($name == 'Upload') { + return $this; + } + + return parent::removeValidator($name); + } + + /** + * Remove an individual validator + * + * @param string $name + * @return Zend_File_Transfer_Adapter_Abstract + */ + public function clearValidators() + { + parent::clearValidators(); + $this->addValidator('Upload', false, $this->_files); + + return $this; + } + + /** + * Send the file to the client (Download) + * + * @param string|array $options Options for the file(s) to send + * @return void + * @throws Zend_File_Transfer_Exception Not implemented + */ + public function send($options = null) + { + throw new Zend_File_Transfer_Exception('Method not implemented'); + } + + /** + * Checks if the files are valid + * + * @param string|array $files (Optional) Files to check + * @return boolean True if all checks are valid + */ + public function isValid($files = null) + { + // Workaround for WebServer not conforming HTTP and omitting CONTENT_LENGTH + $content = 0; + if (isset($_SERVER['CONTENT_LENGTH'])) { + $content = $_SERVER['CONTENT_LENGTH']; + } else if (!empty($_POST)) { + $content = serialize($_POST); + } + + // Workaround for a PHP error returning empty $_FILES when form data exceeds php settings + if (empty($this->_files) && ($content > 0)) { + if (is_array($files)) { + if (0 === count($files)) { + return false; + } + + $files = current($files); + } + + $temp = array($files => array( + 'name' => $files, + 'error' => 1)); + $validator = $this->_validators['Zend_Validate_File_Upload']; + $validator->setFiles($temp) + ->isValid($files, null); + $this->_messages += $validator->getMessages(); + return false; + } + + return parent::isValid($files); + } + + /** + * Receive the file from the client (Upload) + * + * @param string|array $files (Optional) Files to receive + * @return bool + */ + public function receive($files = null) + { + if (!$this->isValid($files)) { + return false; + } + + $check = $this->_getFiles($files); + foreach ($check as $file => $content) { + if (!$content['received']) { + $directory = ''; + $destination = $this->getDestination($file); + if ($destination !== null) { + $directory = $destination . DIRECTORY_SEPARATOR; + } + + $filename = $directory . $content['name']; + $rename = $this->getFilter('Rename'); + if ($rename !== null) { + $tmp = $rename->getNewName($content['tmp_name']); + if ($tmp != $content['tmp_name']) { + $filename = $tmp; + } + + if (dirname($filename) == '.') { + $filename = $directory . $filename; + } + + $key = array_search(get_class($rename), $this->_files[$file]['filters']); + unset($this->_files[$file]['filters'][$key]); + } + + // Should never return false when it's tested by the upload validator + if (!move_uploaded_file($content['tmp_name'], $filename)) { + if ($content['options']['ignoreNoFile']) { + $this->_files[$file]['received'] = true; + $this->_files[$file]['filtered'] = true; + continue; + } + + $this->_files[$file]['received'] = false; + return false; + } + + if ($rename !== null) { + $this->_files[$file]['destination'] = dirname($filename); + $this->_files[$file]['name'] = basename($filename); + } + + $this->_files[$file]['tmp_name'] = $filename; + $this->_files[$file]['received'] = true; + } + + if (!$content['filtered']) { + if (!$this->_filter($file)) { + $this->_files[$file]['filtered'] = false; + return false; + } + + $this->_files[$file]['filtered'] = true; + } + } + + return true; + } + + /** + * Checks if the file was already sent + * + * @param string|array $file Files to check + * @return bool + * @throws Zend_File_Transfer_Exception Not implemented + */ + public function isSent($files = null) + { + throw new Zend_File_Transfer_Exception('Method not implemented'); + } + + /** + * Checks if the file was already received + * + * @param string|array $files (Optional) Files to check + * @return bool + */ + public function isReceived($files = null) + { + $files = $this->_getFiles($files, false, true); + if (empty($files)) { + return false; + } + + foreach ($files as $content) { + if ($content['received'] !== true) { + return false; + } + } + + return true; + } + + /** + * Checks if the file was already filtered + * + * @param string|array $files (Optional) Files to check + * @return bool + */ + public function isFiltered($files = null) + { + $files = $this->_getFiles($files, false, true); + if (empty($files)) { + return false; + } + + foreach ($files as $content) { + if ($content['filtered'] !== true) { + return false; + } + } + + return true; + } + + /** + * Has a file been uploaded ? + * + * @param array|string|null $file + * @return bool + */ + public function isUploaded($files = null) + { + $files = $this->_getFiles($files, false, true); + if (empty($files)) { + return false; + } + + foreach ($files as $file) { + if (empty($file['name'])) { + return false; + } + } + + return true; + } + + /** + * Returns the actual progress of file up-/downloads + * + * @param string $id The upload to get the progress for + * @return array|null + */ + public static function getProgress($id = null) + { + if (!function_exists('apc_fetch') and !function_exists('uploadprogress_get_info')) { + throw new Zend_File_Transfer_Exception('Neither APC nor uploadprogress extension installed'); + } + + $session = 'Zend_File_Transfer_Adapter_Http_ProgressBar'; + $status = array( + 'total' => 0, + 'current' => 0, + 'rate' => 0, + 'message' => '', + 'done' => false + ); + + if (is_array($id)) { + if (isset($id['progress'])) { + $adapter = $id['progress']; + } + + if (isset($id['session'])) { + $session = $id['session']; + } + + if (isset($id['id'])) { + $id = $id['id']; + } else { + unset($id); + } + } + + if (!empty($id) && (($id instanceof Zend_ProgressBar_Adapter) || ($id instanceof Zend_ProgressBar))) { + $adapter = $id; + unset($id); + } + + if (empty($id)) { + if (!isset($_GET['progress_key'])) { + $status['message'] = 'No upload in progress'; + $status['done'] = true; + } else { + $id = $_GET['progress_key']; + } + } + + if (!empty($id)) { + if (self::isApcAvailable()) { + + $call = call_user_func(self::$_callbackApc, ini_get('apc.rfc1867_prefix') . $id); + if (is_array($call)) { + $status = $call + $status; + } + } else if (self::isUploadProgressAvailable()) { + $call = call_user_func(self::$_callbackUploadProgress, $id); + if (is_array($call)) { + $status = $call + $status; + $status['total'] = $status['bytes_total']; + $status['current'] = $status['bytes_uploaded']; + $status['rate'] = $status['speed_average']; + if ($status['total'] == $status['current']) { + $status['done'] = true; + } + } + } + + if (!is_array($call)) { + $status['done'] = true; + $status['message'] = 'Failure while retrieving the upload progress'; + } else if (!empty($status['cancel_upload'])) { + $status['done'] = true; + $status['message'] = 'The upload has been canceled'; + } else { + $status['message'] = self::_toByteString($status['current']) . " - " . self::_toByteString($status['total']); + } + + $status['id'] = $id; + } + + if (isset($adapter) && isset($status['id'])) { + if ($adapter instanceof Zend_ProgressBar_Adapter) { + $adapter = new Zend_ProgressBar($adapter, 0, $status['total'], $session); + } + + if (!($adapter instanceof Zend_ProgressBar)) { + throw new Zend_File_Transfer_Exception('Unknown Adapter given'); + } + + if ($status['done']) { + $adapter->finish(); + } else { + $adapter->update($status['current'], $status['message']); + } + + $status['progress'] = $adapter; + } + + return $status; + } + + /** + * Checks the APC extension for progress information + * + * @return boolean + */ + public static function isApcAvailable() + { + return (bool) ini_get('apc.enabled') && (bool) ini_get('apc.rfc1867') && is_callable(self::$_callbackApc); + } + + /** + * Checks the UploadProgress extension for progress information + * + * @return boolean + */ + public static function isUploadProgressAvailable() + { + return is_callable(self::$_callbackUploadProgress); + } + + /** + * Prepare the $_FILES array to match the internal syntax of one file per entry + * + * @param array $files + * @return array + */ + protected function _prepareFiles() + { + $this->_files = array(); + foreach ($_FILES as $form => $content) { + if (is_array($content['name'])) { + foreach ($content as $param => $file) { + foreach ($file as $number => $target) { + $this->_files[$form . '_' . $number . '_'][$param] = $target; + $this->_files[$form]['multifiles'][$number] = $form . '_' . $number . '_'; + } + } + + $this->_files[$form]['name'] = $form; + foreach($this->_files[$form]['multifiles'] as $key => $value) { + $this->_files[$value]['options'] = $this->_options; + $this->_files[$value]['validated'] = false; + $this->_files[$value]['received'] = false; + $this->_files[$value]['filtered'] = false; + + $mimetype = $this->_detectMimeType($this->_files[$value]); + $this->_files[$value]['type'] = $mimetype; + + $filesize = $this->_detectFileSize($this->_files[$value]); + $this->_files[$value]['size'] = $filesize; + + if ($this->_options['detectInfos']) { + $_FILES[$form]['type'][$key] = $mimetype; + $_FILES[$form]['size'][$key] = $filesize; + } + } + } else { + $this->_files[$form] = $content; + $this->_files[$form]['options'] = $this->_options; + $this->_files[$form]['validated'] = false; + $this->_files[$form]['received'] = false; + $this->_files[$form]['filtered'] = false; + + $mimetype = $this->_detectMimeType($this->_files[$form]); + $this->_files[$form]['type'] = $mimetype; + + $filesize = $this->_detectFileSize($this->_files[$form]); + $this->_files[$form]['size'] = $filesize; + + if ($this->_options['detectInfos']) { + $_FILES[$form]['type'] = $mimetype; + $_FILES[$form]['size'] = $filesize; + } + } + } + + return $this; + } +} diff --git a/library/vendor/Zend/File/Transfer/Exception.php b/library/vendor/Zend/File/Transfer/Exception.php new file mode 100644 index 0000000..27f030c --- /dev/null +++ b/library/vendor/Zend/File/Transfer/Exception.php @@ -0,0 +1,54 @@ +_fileerror = $fileerror; + parent::__construct($message); + } + + /** + * Returns the transfer error code for the exception + * This is not the exception code !!! + * + * @return integer + */ + public function getFileError() + { + return $this->_fileerror; + } +} diff --git a/library/vendor/Zend/Filter.php b/library/vendor/Zend/Filter.php new file mode 100644 index 0000000..d05bdf8 --- /dev/null +++ b/library/vendor/Zend/Filter.php @@ -0,0 +1,236 @@ +_filters, $filter); + } else { + $this->_filters[] = $filter; + } + return $this; + } + + /** + * Add a filter to the end of the chain + * + * @param Zend_Filter_Interface $filter + * @return Zend_Filter Provides a fluent interface + */ + public function appendFilter(Zend_Filter_Interface $filter) + { + return $this->addFilter($filter, self::CHAIN_APPEND); + } + + /** + * Add a filter to the start of the chain + * + * @param Zend_Filter_Interface $filter + * @return Zend_Filter Provides a fluent interface + */ + public function prependFilter(Zend_Filter_Interface $filter) + { + return $this->addFilter($filter, self::CHAIN_PREPEND); + } + + /** + * Get all the filters + * + * @return array + */ + public function getFilters() + { + return $this->_filters; + } + + /** + * Returns $value filtered through each filter in the chain + * + * Filters are run in the order in which they were added to the chain (FIFO) + * + * @param mixed $value + * @return mixed + */ + public function filter($value) + { + $valueFiltered = $value; + foreach ($this->_filters as $filter) { + $valueFiltered = $filter->filter($valueFiltered); + } + return $valueFiltered; + } + + /** + * Returns the set default namespaces + * + * @return array + */ + public static function getDefaultNamespaces() + { + return self::$_defaultNamespaces; + } + + /** + * Sets new default namespaces + * + * @param array|string $namespace + * @return null + */ + public static function setDefaultNamespaces($namespace) + { + if (!is_array($namespace)) { + $namespace = array((string) $namespace); + } + + self::$_defaultNamespaces = $namespace; + } + + /** + * Adds a new default namespace + * + * @param array|string $namespace + * @return null + */ + public static function addDefaultNamespaces($namespace) + { + if (!is_array($namespace)) { + $namespace = array((string) $namespace); + } + + self::$_defaultNamespaces = array_unique(array_merge(self::$_defaultNamespaces, $namespace)); + } + + /** + * Returns true when defaultNamespaces are set + * + * @return boolean + */ + public static function hasDefaultNamespaces() + { + return (!empty(self::$_defaultNamespaces)); + } + + /** + * @deprecated + * @see Zend_Filter::filterStatic() + * + * @param mixed $value + * @param string $classBaseName + * @param array $args OPTIONAL + * @param array|string $namespaces OPTIONAL + * @return mixed + * @throws Zend_Filter_Exception + */ + public static function get($value, $classBaseName, array $args = array(), $namespaces = array()) + { + trigger_error( + 'Zend_Filter::get() is deprecated as of 1.9.0; please update your code to utilize Zend_Filter::filterStatic()', + E_USER_NOTICE + ); + + return self::filterStatic($value, $classBaseName, $args, $namespaces); + } + + /** + * Returns a value filtered through a specified filter class, without requiring separate + * instantiation of the filter object. + * + * The first argument of this method is a data input value, that you would have filtered. + * The second argument is a string, which corresponds to the basename of the filter class, + * relative to the Zend_Filter namespace. This method automatically loads the class, + * creates an instance, and applies the filter() method to the data input. You can also pass + * an array of constructor arguments, if they are needed for the filter class. + * + * @param mixed $value + * @param string $classBaseName + * @param array $args OPTIONAL + * @param array|string $namespaces OPTIONAL + * @return mixed + * @throws Zend_Filter_Exception + */ + public static function filterStatic($value, $classBaseName, array $args = array(), $namespaces = array()) + { + $namespaces = array_merge((array) $namespaces, self::$_defaultNamespaces, array('Zend_Filter')); + foreach ($namespaces as $namespace) { + $className = $namespace . '_' . ucfirst($classBaseName); + if (!class_exists($className, false)) { + try { + $file = str_replace('_', DIRECTORY_SEPARATOR, $className) . '.php'; + if (Zend_Loader::isReadable($file)) { + Zend_Loader::loadClass($className); + } else { + continue; + } + } catch (Zend_Exception $ze) { + continue; + } + } + + $class = new ReflectionClass($className); + if ($class->implementsInterface('Zend_Filter_Interface')) { + if ($class->hasMethod('__construct')) { + $object = $class->newInstanceArgs(array_values($args)); + } else { + $object = $class->newInstance(); + } + return $object->filter($value); + } + } + throw new Zend_Filter_Exception("Filter class not found from basename '$classBaseName'"); + } +} diff --git a/library/vendor/Zend/Filter/Alnum.php b/library/vendor/Zend/Filter/Alnum.php new file mode 100644 index 0000000..c3928a0 --- /dev/null +++ b/library/vendor/Zend/Filter/Alnum.php @@ -0,0 +1,144 @@ +toArray(); + } else if (is_array($allowWhiteSpace)) { + if (array_key_exists('allowwhitespace', $allowWhiteSpace)) { + $allowWhiteSpace = $allowWhiteSpace['allowwhitespace']; + } else { + $allowWhiteSpace = false; + } + } + + $this->allowWhiteSpace = (boolean) $allowWhiteSpace; + if (null === self::$_unicodeEnabled) { + self::$_unicodeEnabled = (@preg_match('/\pL/u', 'a')) ? true : false; + } + + if (null === self::$_meansEnglishAlphabet) { + $this->_locale = new Zend_Locale('auto'); + self::$_meansEnglishAlphabet = in_array($this->_locale->getLanguage(), + array('ja', 'ko', 'zh') + ); + } + + } + + /** + * Returns the allowWhiteSpace option + * + * @return boolean + */ + public function getAllowWhiteSpace() + { + return $this->allowWhiteSpace; + } + + /** + * Sets the allowWhiteSpace option + * + * @param boolean $allowWhiteSpace + * @return Zend_Filter_Alnum Provides a fluent interface + */ + public function setAllowWhiteSpace($allowWhiteSpace) + { + $this->allowWhiteSpace = (boolean) $allowWhiteSpace; + return $this; + } + + /** + * Defined by Zend_Filter_Interface + * + * Returns the string $value, removing all but alphabetic and digit characters + * + * @param string $value + * @return string + */ + public function filter($value) + { + $whiteSpace = $this->allowWhiteSpace ? '\s' : ''; + if (!self::$_unicodeEnabled) { + // POSIX named classes are not supported, use alternative a-zA-Z0-9 match + $pattern = '/[^a-zA-Z0-9' . $whiteSpace . ']/'; + } else if (self::$_meansEnglishAlphabet) { + //The Alphabet means english alphabet. + $pattern = '/[^a-zA-Z0-9' . $whiteSpace . ']/u'; + } else { + //The Alphabet means each language's alphabet. + $pattern = '/[^\p{L}\p{N}' . $whiteSpace . ']/u'; + } + + return preg_replace($pattern, '', (string) $value); + } +} diff --git a/library/vendor/Zend/Filter/Alpha.php b/library/vendor/Zend/Filter/Alpha.php new file mode 100644 index 0000000..5c1a22c --- /dev/null +++ b/library/vendor/Zend/Filter/Alpha.php @@ -0,0 +1,144 @@ +toArray(); + } else if (is_array($allowWhiteSpace)) { + if (array_key_exists('allowwhitespace', $allowWhiteSpace)) { + $allowWhiteSpace = $allowWhiteSpace['allowwhitespace']; + } else { + $allowWhiteSpace = false; + } + } + + $this->allowWhiteSpace = (boolean) $allowWhiteSpace; + if (null === self::$_unicodeEnabled) { + self::$_unicodeEnabled = (@preg_match('/\pL/u', 'a')) ? true : false; + } + + if (null === self::$_meansEnglishAlphabet) { + $this->_locale = new Zend_Locale('auto'); + self::$_meansEnglishAlphabet = in_array($this->_locale->getLanguage(), + array('ja', 'ko', 'zh') + ); + } + + } + + /** + * Returns the allowWhiteSpace option + * + * @return boolean + */ + public function getAllowWhiteSpace() + { + return $this->allowWhiteSpace; + } + + /** + * Sets the allowWhiteSpace option + * + * @param boolean $allowWhiteSpace + * @return Zend_Filter_Alpha Provides a fluent interface + */ + public function setAllowWhiteSpace($allowWhiteSpace) + { + $this->allowWhiteSpace = (boolean) $allowWhiteSpace; + return $this; + } + + /** + * Defined by Zend_Filter_Interface + * + * Returns the string $value, removing all but alphabetic characters + * + * @param string $value + * @return string + */ + public function filter($value) + { + $whiteSpace = $this->allowWhiteSpace ? '\s' : ''; + if (!self::$_unicodeEnabled) { + // POSIX named classes are not supported, use alternative a-zA-Z match + $pattern = '/[^a-zA-Z' . $whiteSpace . ']/'; + } else if (self::$_meansEnglishAlphabet) { + //The Alphabet means english alphabet. + $pattern = '/[^a-zA-Z' . $whiteSpace . ']/u'; + } else { + //The Alphabet means each language's alphabet. + $pattern = '/[^\p{L}' . $whiteSpace . ']/u'; + } + + return preg_replace($pattern, '', (string) $value); + } +} diff --git a/library/vendor/Zend/Filter/BaseName.php b/library/vendor/Zend/Filter/BaseName.php new file mode 100644 index 0000000..41ab68a --- /dev/null +++ b/library/vendor/Zend/Filter/BaseName.php @@ -0,0 +1,49 @@ + 'boolean', + self::INTEGER => 'integer', + self::FLOAT => 'float', + self::STRING => 'string', + self::ZERO => 'zero', + self::EMPTY_ARRAY => 'array', + self::NULL => 'null', + self::PHP => 'php', + self::FALSE_STRING => 'false', + self::YES => 'yes', + self::ALL => 'all', + ); + + /** + * Internal type to detect + * + * @var integer + */ + protected $_type = self::PHP; + + /** + * Internal locale + * + * @var array + */ + protected $_locale = array('auto'); + + /** + * Internal mode + * + * @var boolean + */ + protected $_casting = true; + + /** + * Constructor + * + * @param string|array|Zend_Config $options OPTIONAL + */ + public function __construct($options = null) + { + if ($options instanceof Zend_Config) { + $options = $options->toArray(); + } elseif (!is_array($options)) { + $options = func_get_args(); + $temp = array(); + if (!empty($options)) { + $temp['type'] = array_shift($options); + } + + if (!empty($options)) { + $temp['casting'] = array_shift($options); + } + + if (!empty($options)) { + $temp['locale'] = array_shift($options); + } + + $options = $temp; + } + + if (array_key_exists('type', $options)) { + $this->setType($options['type']); + } + + if (array_key_exists('casting', $options)) { + $this->setCasting($options['casting']); + } + + if (array_key_exists('locale', $options)) { + $this->setLocale($options['locale']); + } + } + + /** + * Returns the set null types + * + * @return int + */ + public function getType() + { + return $this->_type; + } + + /** + * Set the null types + * + * @param integer|array $type + * @throws Zend_Filter_Exception + * @return Zend_Filter_Boolean + */ + public function setType($type = null) + { + if (is_array($type)) { + $detected = 0; + foreach($type as $value) { + if (is_int($value)) { + $detected += $value; + } elseif (in_array($value, $this->_constants)) { + $detected += array_search($value, $this->_constants); + } + } + + $type = $detected; + } elseif (is_string($type) && in_array($type, $this->_constants)) { + $type = array_search($type, $this->_constants); + } + + if (!is_int($type) || ($type < 0) || ($type > self::ALL)) { + throw new Zend_Filter_Exception('Unknown type'); + } + + $this->_type = $type; + return $this; + } + + /** + * Returns the set locale + * + * @return array + */ + public function getLocale() + { + return $this->_locale; + } + + /** + * Set the locales which are accepted + * + * @param string|array|Zend_Locale $locale + * @throws Zend_Filter_Exception + * @return Zend_Filter_Boolean + */ + public function setLocale($locale = null) + { + if (is_string($locale)) { + $locale = array($locale); + } elseif ($locale instanceof Zend_Locale) { + $locale = array($locale->toString()); + } elseif (!is_array($locale)) { + throw new Zend_Filter_Exception('Locale has to be string, array or an instance of Zend_Locale'); + } + + foreach ($locale as $single) { + if (!Zend_Locale::isLocale($single)) { + throw new Zend_Filter_Exception("Unknown locale '$single'"); + } + } + + $this->_locale = $locale; + return $this; + } + + /** + * Returns the casting option + * + * @return boolean + */ + public function getCasting() + { + return $this->_casting; + } + + /** + * Set the working mode + * + * @param boolean $locale When true this filter works like cast + * When false it recognises only true and false + * and all other values are returned as is + * @throws Zend_Filter_Exception + * @return Zend_Filter_Boolean + */ + public function setCasting($casting = true) + { + $this->_casting = (boolean) $casting; + return $this; + } + + /** + * Defined by Zend_Filter_Interface + * + * Returns a boolean representation of $value + * + * @param string $value + * @return string + */ + public function filter($value) + { + $type = $this->getType(); + $casting = $this->getCasting(); + + // STRING YES (Localized) + if ($type >= self::YES) { + $type -= self::YES; + if (is_string($value)) { + $locales = $this->getLocale(); + foreach ($locales as $locale) { + if ($this->_getLocalizedQuestion($value, false, $locale) === false) { + return false; + } + + if (!$casting && ($this->_getLocalizedQuestion($value, true, $locale) === true)) { + return true; + } + } + } + } + + // STRING FALSE ('false') + if ($type >= self::FALSE_STRING) { + $type -= self::FALSE_STRING; + if (is_string($value) && (strtolower($value) == 'false')) { + return false; + } + + if ((!$casting) && is_string($value) && (strtolower($value) == 'true')) { + return true; + } + } + + // NULL (null) + if ($type >= self::NULL) { + $type -= self::NULL; + if ($value === null) { + return false; + } + } + + // EMPTY_ARRAY (array()) + if ($type >= self::EMPTY_ARRAY) { + $type -= self::EMPTY_ARRAY; + if (is_array($value) && ($value == array())) { + return false; + } + } + + // ZERO ('0') + if ($type >= self::ZERO) { + $type -= self::ZERO; + if (is_string($value) && ($value == '0')) { + return false; + } + + if ((!$casting) && (is_string($value)) && ($value == '1')) { + return true; + } + } + + // STRING ('') + if ($type >= self::STRING) { + $type -= self::STRING; + if (is_string($value) && ($value == '')) { + return false; + } + } + + // FLOAT (0.0) + if ($type >= self::FLOAT) { + $type -= self::FLOAT; + if (is_float($value) && ($value == 0.0)) { + return false; + } + + if ((!$casting) && is_float($value) && ($value == 1.0)) { + return true; + } + } + + // INTEGER (0) + if ($type >= self::INTEGER) { + $type -= self::INTEGER; + if (is_int($value) && ($value == 0)) { + return false; + } + + if ((!$casting) && is_int($value) && ($value == 1)) { + return true; + } + } + + // BOOLEAN (false) + if ($type >= self::BOOLEAN) { + $type -= self::BOOLEAN; + if (is_bool($value)) { + return $value; + } + } + + if ($casting) { + return true; + } + + return $value; + } + + /** + * Determine the value of a localized string, and compare it to a given value + * + * @param string $value + * @param boolean $yes + * @param array $locale + * @return boolean + */ + protected function _getLocalizedQuestion($value, $yes, $locale) + { + if ($yes == true) { + $question = 'yes'; + $return = true; + } else { + $question = 'no'; + $return = false; + } + $str = Zend_Locale::getTranslation($question, 'question', $locale); + $str = explode(':', $str); + if (!empty($str)) { + foreach($str as $no) { + if (($no == $value) || (strtolower($no) == strtolower($value))) { + return $return; + } + } + } + } +} diff --git a/library/vendor/Zend/Filter/Callback.php b/library/vendor/Zend/Filter/Callback.php new file mode 100644 index 0000000..0553edc --- /dev/null +++ b/library/vendor/Zend/Filter/Callback.php @@ -0,0 +1,149 @@ +toArray(); + } else if (!is_array($options) || !array_key_exists('callback', $options)) { + $options = func_get_args(); + $temp['callback'] = array_shift($options); + if (!empty($options)) { + $temp['options'] = array_shift($options); + } + + $options = $temp; + } + + if (!array_key_exists('callback', $options)) { + throw new Zend_Filter_Exception('Missing callback to use'); + } + + $this->setCallback($options['callback']); + if (array_key_exists('options', $options)) { + $this->setOptions($options['options']); + } + } + + /** + * Returns the set callback + * + * @return string|array Set callback + */ + public function getCallback() + { + return $this->_callback; + } + + /** + * Sets a new callback for this filter + * + * @param unknown_type $callback + * @return unknown + */ + public function setCallback($callback, $options = null) + { + if (!is_callable($callback)) { + throw new Zend_Filter_Exception('Callback can not be accessed'); + } + + $this->_callback = $callback; + $this->setOptions($options); + return $this; + } + + /** + * Returns the set default options + * + * @return mixed + */ + public function getOptions() + { + return $this->_options; + } + + /** + * Sets new default options to the callback filter + * + * @param mixed $options Default options to set + * @return Zend_Filter_Callback + */ + public function setOptions($options) + { + $this->_options = $options; + return $this; + } + + /** + * Calls the filter per callback + * + * @param mixed $value Options for the set callback + * @return mixed Result from the filter which was callbacked + */ + public function filter($value) + { + $options = array(); + + if ($this->_options !== null) { + if (!is_array($this->_options)) { + $options = array($this->_options); + } else { + $options = $this->_options; + } + } + + array_unshift($options, $value); + + return call_user_func_array($this->_callback, $options); + } +} diff --git a/library/vendor/Zend/Filter/Compress.php b/library/vendor/Zend/Filter/Compress.php new file mode 100644 index 0000000..7502966 --- /dev/null +++ b/library/vendor/Zend/Filter/Compress.php @@ -0,0 +1,192 @@ +toArray(); + } + if (is_string($options)) { + $this->setAdapter($options); + } elseif ($options instanceof Zend_Filter_Compress_CompressInterface) { + $this->setAdapter($options); + } elseif (is_array($options)) { + $this->setOptions($options); + } + } + + /** + * Set filter setate + * + * @param array $options + * @return Zend_Filter_Compress + */ + public function setOptions(array $options) + { + foreach ($options as $key => $value) { + if ($key == 'options') { + $key = 'adapterOptions'; + } + $method = 'set' . ucfirst($key); + if (method_exists($this, $method)) { + $this->$method($value); + } + } + return $this; + } + + /** + * Returns the current adapter, instantiating it if necessary + * + * @return string + */ + public function getAdapter() + { + if ($this->_adapter instanceof Zend_Filter_Compress_CompressInterface) { + return $this->_adapter; + } + + $adapter = $this->_adapter; + $options = $this->getAdapterOptions(); + if (!class_exists($adapter)) { + if (Zend_Loader::isReadable('Zend/Filter/Compress/' . ucfirst($adapter) . '.php')) { + $adapter = 'Zend_Filter_Compress_' . ucfirst($adapter); + } + Zend_Loader::loadClass($adapter); + } + + $this->_adapter = new $adapter($options); + if (!$this->_adapter instanceof Zend_Filter_Compress_CompressInterface) { + throw new Zend_Filter_Exception("Compression adapter '" . $adapter . "' does not implement Zend_Filter_Compress_CompressInterface"); + } + return $this->_adapter; + } + + /** + * Retrieve adapter name + * + * @return string + */ + public function getAdapterName() + { + return $this->getAdapter()->toString(); + } + + /** + * Sets compression adapter + * + * @param string|Zend_Filter_Compress_CompressInterface $adapter Adapter to use + * @return Zend_Filter_Compress + */ + public function setAdapter($adapter) + { + if ($adapter instanceof Zend_Filter_Compress_CompressInterface) { + $this->_adapter = $adapter; + return $this; + } + if (!is_string($adapter)) { + throw new Zend_Filter_Exception('Invalid adapter provided; must be string or instance of Zend_Filter_Compress_CompressInterface'); + } + $this->_adapter = $adapter; + + return $this; + } + + /** + * Retrieve adapter options + * + * @return array + */ + public function getAdapterOptions() + { + return $this->_adapterOptions; + } + + /** + * Set adapter options + * + * @param array $options + * @return void + */ + public function setAdapterOptions(array $options) + { + $this->_adapterOptions = $options; + return $this; + } + + /** + * Calls adapter methods + * + * @param string $method Method to call + * @param string|array $options Options for this method + */ + public function __call($method, $options) + { + $adapter = $this->getAdapter(); + if (!method_exists($adapter, $method)) { + throw new Zend_Filter_Exception("Unknown method '{$method}'"); + } + + return call_user_func_array(array($adapter, $method), $options); + } + + /** + * Defined by Zend_Filter_Interface + * + * Compresses the content $value with the defined settings + * + * @param string $value Content to compress + * @return string The compressed content + */ + public function filter($value) + { + return $this->getAdapter()->compress($value); + } +} diff --git a/library/vendor/Zend/Filter/Compress/Bz2.php b/library/vendor/Zend/Filter/Compress/Bz2.php new file mode 100644 index 0000000..d1aab17 --- /dev/null +++ b/library/vendor/Zend/Filter/Compress/Bz2.php @@ -0,0 +1,181 @@ + Blocksize to use from 0-9 + * 'archive' => Archive to use + * ) + * + * @var array + */ + protected $_options = array( + 'blocksize' => 4, + 'archive' => null, + ); + + /** + * Class constructor + * + * @param array|Zend_Config $options (Optional) Options to set + */ + public function __construct($options = null) + { + if (!extension_loaded('bz2')) { + throw new Zend_Filter_Exception('This filter needs the bz2 extension'); + } + parent::__construct($options); + } + + /** + * Returns the set blocksize + * + * @return integer + */ + public function getBlocksize() + { + return $this->_options['blocksize']; + } + + /** + * Sets a new blocksize + * + * @param integer $level + * @return Zend_Filter_Compress_Bz2 + */ + public function setBlocksize($blocksize) + { + if (($blocksize < 0) || ($blocksize > 9)) { + throw new Zend_Filter_Exception('Blocksize must be between 0 and 9'); + } + + $this->_options['blocksize'] = (int) $blocksize; + return $this; + } + + /** + * Returns the set archive + * + * @return string + */ + public function getArchive() + { + return $this->_options['archive']; + } + + /** + * Sets the archive to use for de-/compression + * + * @param string $archive Archive to use + * @return Zend_Filter_Compress_Bz2 + */ + public function setArchive($archive) + { + $this->_options['archive'] = (string) $archive; + return $this; + } + + /** + * Compresses the given content + * + * @param string $content + * @return string + */ + public function compress($content) + { + $archive = $this->getArchive(); + if (!empty($archive)) { + $file = bzopen($archive, 'w'); + if (!$file) { + throw new Zend_Filter_Exception("Error opening the archive '" . $archive . "'"); + } + + bzwrite($file, $content); + bzclose($file); + $compressed = true; + } else { + $compressed = bzcompress($content, $this->getBlocksize()); + } + + if (is_int($compressed)) { + throw new Zend_Filter_Exception('Error during compression'); + } + + return $compressed; + } + + /** + * Decompresses the given content + * + * @param string $content + * @return string + */ + public function decompress($content) + { + $archive = $this->getArchive(); + if (@file_exists($content)) { + $archive = $content; + } + + if (@file_exists($archive)) { + $file = bzopen($archive, 'r'); + if (!$file) { + throw new Zend_Filter_Exception("Error opening the archive '" . $content . "'"); + } + + $compressed = bzread($file); + bzclose($file); + } else { + $compressed = bzdecompress($content); + } + + if (is_int($compressed)) { + throw new Zend_Filter_Exception('Error during decompression'); + } + + return $compressed; + } + + /** + * Returns the adapter name + * + * @return string + */ + public function toString() + { + return 'Bz2'; + } +} diff --git a/library/vendor/Zend/Filter/Compress/CompressAbstract.php b/library/vendor/Zend/Filter/Compress/CompressAbstract.php new file mode 100644 index 0000000..4b0813c --- /dev/null +++ b/library/vendor/Zend/Filter/Compress/CompressAbstract.php @@ -0,0 +1,88 @@ +toArray(); + } + + if (is_array($options)) { + $this->setOptions($options); + } + } + + /** + * Returns one or all set options + * + * @param string $option (Optional) Option to return + * @return mixed + */ + public function getOptions($option = null) + { + if ($option === null) { + return $this->_options; + } + + if (!array_key_exists($option, $this->_options)) { + return null; + } + + return $this->_options[$option]; + } + + /** + * Sets all or one option + * + * @param array $options + * @return Zend_Filter_Compress_Bz2 + */ + public function setOptions(array $options) + { + foreach ($options as $key => $option) { + $method = 'set' . $key; + if (method_exists($this, $method)) { + $this->$method($option); + } + } + + return $this; + } +} diff --git a/library/vendor/Zend/Filter/Compress/CompressInterface.php b/library/vendor/Zend/Filter/Compress/CompressInterface.php new file mode 100644 index 0000000..75f0a40 --- /dev/null +++ b/library/vendor/Zend/Filter/Compress/CompressInterface.php @@ -0,0 +1,54 @@ + Compression level 0-9 + * 'mode' => Compression mode, can be 'compress', 'deflate' + * 'archive' => Archive to use + * ) + * + * @var array + */ + protected $_options = array( + 'level' => 9, + 'mode' => 'compress', + 'archive' => null, + ); + + /** + * Class constructor + * + * @param array|Zend_Config|null $options (Optional) Options to set + */ + public function __construct($options = null) + { + if (!extension_loaded('zlib')) { + throw new Zend_Filter_Exception('This filter needs the zlib extension'); + } + parent::__construct($options); + } + + /** + * Returns the set compression level + * + * @return integer + */ + public function getLevel() + { + return $this->_options['level']; + } + + /** + * Sets a new compression level + * + * @param integer $level + * @return Zend_Filter_Compress_Gz + */ + public function setLevel($level) + { + if (($level < 0) || ($level > 9)) { + throw new Zend_Filter_Exception('Level must be between 0 and 9'); + } + + $this->_options['level'] = (int) $level; + return $this; + } + + /** + * Returns the set compression mode + * + * @return string + */ + public function getMode() + { + return $this->_options['mode']; + } + + /** + * Sets a new compression mode + * + * @param string $mode Supported are 'compress', 'deflate' and 'file' + */ + public function setMode($mode) + { + if (($mode != 'compress') && ($mode != 'deflate')) { + throw new Zend_Filter_Exception('Given compression mode not supported'); + } + + $this->_options['mode'] = $mode; + return $this; + } + + /** + * Returns the set archive + * + * @return string + */ + public function getArchive() + { + return $this->_options['archive']; + } + + /** + * Sets the archive to use for de-/compression + * + * @param string $archive Archive to use + * @return Zend_Filter_Compress_Gz + */ + public function setArchive($archive) + { + $this->_options['archive'] = (string) $archive; + return $this; + } + + /** + * Compresses the given content + * + * @param string $content + * @return string + */ + public function compress($content) + { + $archive = $this->getArchive(); + if (!empty($archive)) { + $file = gzopen($archive, 'w' . $this->getLevel()); + if (!$file) { + throw new Zend_Filter_Exception("Error opening the archive '" . $this->_options['archive'] . "'"); + } + + gzwrite($file, $content); + gzclose($file); + $compressed = true; + } else if ($this->_options['mode'] == 'deflate') { + $compressed = gzdeflate($content, $this->getLevel()); + } else { + $compressed = gzcompress($content, $this->getLevel()); + } + + if (!$compressed) { + throw new Zend_Filter_Exception('Error during compression'); + } + + return $compressed; + } + + /** + * Decompresses the given content + * + * @param string $content + * @return string + */ + public function decompress($content) + { + $archive = $this->getArchive(); + $mode = $this->getMode(); + if (@file_exists($content)) { + $archive = $content; + } + + if (@file_exists($archive)) { + $handler = fopen($archive, "rb"); + if (!$handler) { + throw new Zend_Filter_Exception("Error opening the archive '" . $archive . "'"); + } + + fseek($handler, -4, SEEK_END); + $packet = fread($handler, 4); + $bytes = unpack("V", $packet); + $size = end($bytes); + fclose($handler); + + $file = gzopen($archive, 'r'); + $compressed = gzread($file, $size); + gzclose($file); + } else if ($mode == 'deflate') { + $compressed = gzinflate($content); + } else { + $compressed = gzuncompress($content); + } + + if (!$compressed) { + throw new Zend_Filter_Exception('Error during compression'); + } + + return $compressed; + } + + /** + * Returns the adapter name + * + * @return string + */ + public function toString() + { + return 'Gz'; + } +} diff --git a/library/vendor/Zend/Filter/Compress/Lzf.php b/library/vendor/Zend/Filter/Compress/Lzf.php new file mode 100644 index 0000000..15ecb47 --- /dev/null +++ b/library/vendor/Zend/Filter/Compress/Lzf.php @@ -0,0 +1,87 @@ + Callback for compression + * 'archive' => Archive to use + * 'password' => Password to use + * 'target' => Target to write the files to + * ) + * + * @var array + */ + protected $_options = array( + 'callback' => null, + 'archive' => null, + 'password' => null, + 'target' => '.', + ); + + /** + * Class constructor + * + * @param array $options (Optional) Options to set + */ + public function __construct($options = null) + { + if (!extension_loaded('rar')) { + throw new Zend_Filter_Exception('This filter needs the rar extension'); + } + parent::__construct($options); + } + + /** + * Returns the set callback for compression + * + * @return string + */ + public function getCallback() + { + return $this->_options['callback']; + } + + /** + * Sets the callback to use + * + * @param string $callback + * @return Zend_Filter_Compress_Rar + */ + public function setCallback($callback) + { + if (!is_callable($callback)) { + throw new Zend_Filter_Exception('Callback can not be accessed'); + } + + $this->_options['callback'] = $callback; + return $this; + } + + /** + * Returns the set archive + * + * @return string + */ + public function getArchive() + { + return $this->_options['archive']; + } + + /** + * Sets the archive to use for de-/compression + * + * @param string $archive Archive to use + * @return Zend_Filter_Compress_Rar + */ + public function setArchive($archive) + { + $archive = str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $archive); + $this->_options['archive'] = (string) $archive; + + return $this; + } + + /** + * Returns the set password + * + * @return string + */ + public function getPassword() + { + return $this->_options['password']; + } + + /** + * Sets the password to use + * + * @param string $password + * @return Zend_Filter_Compress_Rar + */ + public function setPassword($password) + { + $this->_options['password'] = (string) $password; + return $this; + } + + /** + * Returns the set targetpath + * + * @return string + */ + public function getTarget() + { + return $this->_options['target']; + } + + /** + * Sets the targetpath to use + * + * @param string $target + * @return Zend_Filter_Compress_Rar + */ + public function setTarget($target) + { + if (!file_exists(dirname($target))) { + throw new Zend_Filter_Exception("The directory '$target' does not exist"); + } + + $target = str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $target); + $this->_options['target'] = (string) $target; + return $this; + } + + /** + * Compresses the given content + * + * @param string|array $content + * @return string + */ + public function compress($content) + { + $callback = $this->getCallback(); + if ($callback === null) { + throw new Zend_Filter_Exception('No compression callback available'); + } + + $options = $this->getOptions(); + unset($options['callback']); + + $result = call_user_func($callback, $options, $content); + if ($result !== true) { + throw new Zend_Filter_Exception('Error compressing the RAR Archive'); + } + + return $this->getArchive(); + } + + /** + * Decompresses the given content + * + * @param string $content + * @return boolean + */ + public function decompress($content) + { + $archive = $this->getArchive(); + if (file_exists($content)) { + $archive = str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, realpath($content)); + } elseif (empty($archive) || !file_exists($archive)) { + throw new Zend_Filter_Exception('RAR Archive not found'); + } + + $password = $this->getPassword(); + if ($password !== null) { + $archive = rar_open($archive, $password); + } else { + $archive = rar_open($archive); + } + + if (!$archive) { + throw new Zend_Filter_Exception("Error opening the RAR Archive"); + } + + $target = $this->getTarget(); + if (!is_dir($target)) { + $target = dirname($target); + } + + $filelist = rar_list($archive); + if (!$filelist) { + throw new Zend_Filter_Exception("Error reading the RAR Archive"); + } + + foreach($filelist as $file) { + $file->extract($target); + } + + rar_close($archive); + return true; + } + + /** + * Returns the adapter name + * + * @return string + */ + public function toString() + { + return 'Rar'; + } +} diff --git a/library/vendor/Zend/Filter/Compress/Tar.php b/library/vendor/Zend/Filter/Compress/Tar.php new file mode 100644 index 0000000..4359b64 --- /dev/null +++ b/library/vendor/Zend/Filter/Compress/Tar.php @@ -0,0 +1,234 @@ + Archive to use + * 'target' => Target to write the files to + * ) + * + * @var array + */ + protected $_options = array( + 'archive' => null, + 'target' => '.', + 'mode' => null, + ); + + /** + * Class constructor + * + * @param array $options (Optional) Options to set + */ + public function __construct($options = null) + { + if (!class_exists('Archive_Tar')) { + try { + Zend_Loader::loadClass('Archive_Tar'); + } catch (Zend_Exception $e) { + throw new Zend_Filter_Exception('This filter needs PEARs Archive_Tar', 0, $e); + } + } + + parent::__construct($options); + } + + /** + * Returns the set archive + * + * @return string + */ + public function getArchive() + { + return $this->_options['archive']; + } + + /** + * Sets the archive to use for de-/compression + * + * @param string $archive Archive to use + * @return Zend_Filter_Compress_Tar + */ + public function setArchive($archive) + { + $archive = str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $archive); + $this->_options['archive'] = (string) $archive; + + return $this; + } + + /** + * Returns the set targetpath + * + * @return string + */ + public function getTarget() + { + return $this->_options['target']; + } + + /** + * Sets the targetpath to use + * + * @param string $target + * @return Zend_Filter_Compress_Tar + */ + public function setTarget($target) + { + if (!file_exists(dirname($target))) { + throw new Zend_Filter_Exception("The directory '$target' does not exist"); + } + + $target = str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $target); + $this->_options['target'] = (string) $target; + return $this; + } + + /** + * Returns the set compression mode + */ + public function getMode() + { + return $this->_options['mode']; + } + + /** + * Compression mode to use + * Eighter Gz or Bz2 + * + * @param string $mode + */ + public function setMode($mode) + { + $mode = ucfirst(strtolower($mode)); + if (($mode != 'Bz2') && ($mode != 'Gz')) { + throw new Zend_Filter_Exception("The mode '$mode' is unknown"); + } + + if (($mode == 'Bz2') && (!extension_loaded('bz2'))) { + throw new Zend_Filter_Exception('This mode needs the bz2 extension'); + } + + if (($mode == 'Gz') && (!extension_loaded('zlib'))) { + throw new Zend_Filter_Exception('This mode needs the zlib extension'); + } + } + + /** + * Compresses the given content + * + * @param string $content + * @return string + */ + public function compress($content) + { + $archive = new Archive_Tar($this->getArchive(), $this->getMode()); + if (!file_exists($content)) { + $file = $this->getTarget(); + if (is_dir($file)) { + $file .= DIRECTORY_SEPARATOR . "tar.tmp"; + } + + $result = file_put_contents($file, $content); + if ($result === false) { + throw new Zend_Filter_Exception('Error creating the temporary file'); + } + + $content = $file; + } + + if (is_dir($content)) { + // collect all file infos + foreach (new RecursiveIteratorIterator( + new RecursiveDirectoryIterator($content, RecursiveDirectoryIterator::KEY_AS_PATHNAME), + RecursiveIteratorIterator::SELF_FIRST + ) as $directory => $info + ) { + if ($info->isFile()) { + $file[] = $directory; + } + } + + $content = $file; + } + + $result = $archive->create($content); + if ($result === false) { + throw new Zend_Filter_Exception('Error creating the Tar archive'); + } + + return $this->getArchive(); + } + + /** + * Decompresses the given content + * + * @param string $content + * @return boolean + */ + public function decompress($content) + { + $archive = $this->getArchive(); + if (file_exists($content)) { + $archive = str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, realpath($content)); + } elseif (empty($archive) || !file_exists($archive)) { + throw new Zend_Filter_Exception('Tar Archive not found'); + } + + $archive = new Archive_Tar($archive, $this->getMode()); + $target = $this->getTarget(); + if (!is_dir($target)) { + $target = dirname($target); + } + + $result = $archive->extract($target); + if ($result === false) { + throw new Zend_Filter_Exception('Error while extracting the Tar archive'); + } + + return true; + } + + /** + * Returns the adapter name + * + * @return string + */ + public function toString() + { + return 'Tar'; + } +} diff --git a/library/vendor/Zend/Filter/Compress/Zip.php b/library/vendor/Zend/Filter/Compress/Zip.php new file mode 100644 index 0000000..055645d --- /dev/null +++ b/library/vendor/Zend/Filter/Compress/Zip.php @@ -0,0 +1,343 @@ + Archive to use + * 'password' => Password to use + * 'target' => Target to write the files to + * ) + * + * @var array + */ + protected $_options = array( + 'archive' => null, + 'target' => null, + ); + + /** + * Class constructor + * + * @param string|array $options (Optional) Options to set + */ + public function __construct($options = null) + { + if (!extension_loaded('zip')) { + throw new Zend_Filter_Exception('This filter needs the zip extension'); + } + parent::__construct($options); + } + + /** + * Returns the set archive + * + * @return string + */ + public function getArchive() + { + return $this->_options['archive']; + } + + /** + * Sets the archive to use for de-/compression + * + * @param string $archive Archive to use + * @return Zend_Filter_Compress_Rar + */ + public function setArchive($archive) + { + $archive = str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $archive); + $this->_options['archive'] = (string) $archive; + + return $this; + } + + /** + * Returns the set targetpath + * + * @return string + */ + public function getTarget() + { + return $this->_options['target']; + } + + /** + * Sets the target to use + * + * @param string $target + * @return Zend_Filter_Compress_Rar + */ + public function setTarget($target) + { + if (!file_exists(dirname($target))) { + throw new Zend_Filter_Exception("The directory '$target' does not exist"); + } + + $target = str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $target); + $this->_options['target'] = (string) $target; + return $this; + } + + /** + * Compresses the given content + * + * @param string $content + * @return string Compressed archive + */ + public function compress($content) + { + $zip = new ZipArchive(); + $res = $zip->open($this->getArchive(), ZipArchive::CREATE | ZipArchive::OVERWRITE); + + if ($res !== true) { + throw new Zend_Filter_Exception($this->_errorString($res)); + } + + if (file_exists($content)) { + $content = str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, realpath($content)); + $basename = substr($content, strrpos($content, DIRECTORY_SEPARATOR) + 1); + if (is_dir($content)) { + $index = strrpos($content, DIRECTORY_SEPARATOR) + 1; + $content .= DIRECTORY_SEPARATOR; + $stack = array($content); + while (!empty($stack)) { + $current = array_pop($stack); + $files = array(); + + $dir = dir($current); + while (false !== ($node = $dir->read())) { + if (($node == '.') || ($node == '..')) { + continue; + } + + if (is_dir($current . $node)) { + array_push($stack, $current . $node . DIRECTORY_SEPARATOR); + } + + if (is_file($current . $node)) { + $files[] = $node; + } + } + + $local = substr($current, $index); + $zip->addEmptyDir(substr($local, 0, -1)); + + foreach ($files as $file) { + $zip->addFile($current . $file, $local . $file); + if ($res !== true) { + throw new Zend_Filter_Exception($this->_errorString($res)); + } + } + } + } else { + $res = $zip->addFile($content, $basename); + if ($res !== true) { + throw new Zend_Filter_Exception($this->_errorString($res)); + } + } + } else { + $file = $this->getTarget(); + if (!is_dir($file)) { + $file = basename($file); + } else { + $file = "zip.tmp"; + } + + $res = $zip->addFromString($file, $content); + if ($res !== true) { + throw new Zend_Filter_Exception($this->_errorString($res)); + } + } + + $zip->close(); + return $this->_options['archive']; + } + + /** + * Decompresses the given content + * + * @param string $content + * @return string + */ + public function decompress($content) + { + $archive = $this->getArchive(); + if (file_exists($content)) { + $archive = str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, realpath($content)); + } elseif (empty($archive) || !file_exists($archive)) { + throw new Zend_Filter_Exception('ZIP Archive not found'); + } + + $zip = new ZipArchive(); + $res = $zip->open($archive); + + $target = $this->getTarget(); + + if (!empty($target) && !is_dir($target)) { + $target = dirname($target); + } + + if (!empty($target)) { + $target = rtrim($target, '/\\') . DIRECTORY_SEPARATOR; + } + + if (empty($target) || !is_dir($target)) { + throw new Zend_Filter_Exception('No target for ZIP decompression set'); + } + + if ($res !== true) { + throw new Zend_Filter_Exception($this->_errorString($res)); + } + + if (version_compare(PHP_VERSION, '5.2.8', '<')) { + for ($i = 0; $i < $zip->numFiles; $i++) { + $statIndex = $zip->statIndex($i); + $currName = $statIndex['name']; + if (($currName[0] == '/') || + (substr($currName, 0, 2) == '..') || + (substr($currName, 0, 4) == './..') + ) + { + throw new Zend_Filter_Exception('Upward directory traversal was detected inside ' . $archive + . ' please use PHP 5.2.8 or greater to take advantage of path resolution features of ' + . 'the zip extension in this decompress() method.' + ); + } + } + } + + $res = @$zip->extractTo($target); + if ($res !== true) { + throw new Zend_Filter_Exception($this->_errorString($res)); + } + + $zip->close(); + return $target; + } + + /** + * Returns the proper string based on the given error constant + * + * @param string $error + */ + protected function _errorString($error) + { + switch($error) { + case ZipArchive::ER_MULTIDISK : + return 'Multidisk ZIP Archives not supported'; + + case ZipArchive::ER_RENAME : + return 'Failed to rename the temporary file for ZIP'; + + case ZipArchive::ER_CLOSE : + return 'Failed to close the ZIP Archive'; + + case ZipArchive::ER_SEEK : + return 'Failure while seeking the ZIP Archive'; + + case ZipArchive::ER_READ : + return 'Failure while reading the ZIP Archive'; + + case ZipArchive::ER_WRITE : + return 'Failure while writing the ZIP Archive'; + + case ZipArchive::ER_CRC : + return 'CRC failure within the ZIP Archive'; + + case ZipArchive::ER_ZIPCLOSED : + return 'ZIP Archive already closed'; + + case ZipArchive::ER_NOENT : + return 'No such file within the ZIP Archive'; + + case ZipArchive::ER_EXISTS : + return 'ZIP Archive already exists'; + + case ZipArchive::ER_OPEN : + return 'Can not open ZIP Archive'; + + case ZipArchive::ER_TMPOPEN : + return 'Failure creating temporary ZIP Archive'; + + case ZipArchive::ER_ZLIB : + return 'ZLib Problem'; + + case ZipArchive::ER_MEMORY : + return 'Memory allocation problem while working on a ZIP Archive'; + + case ZipArchive::ER_CHANGED : + return 'ZIP Entry has been changed'; + + case ZipArchive::ER_COMPNOTSUPP : + return 'Compression method not supported within ZLib'; + + case ZipArchive::ER_EOF : + return 'Premature EOF within ZIP Archive'; + + case ZipArchive::ER_INVAL : + return 'Invalid argument for ZLIB'; + + case ZipArchive::ER_NOZIP : + return 'Given file is no zip archive'; + + case ZipArchive::ER_INTERNAL : + return 'Internal error while working on a ZIP Archive'; + + case ZipArchive::ER_INCONS : + return 'Inconsistent ZIP archive'; + + case ZipArchive::ER_REMOVE : + return 'Can not remove ZIP Archive'; + + case ZipArchive::ER_DELETED : + return 'ZIP Entry has been deleted'; + + default : + return 'Unknown error within ZIP Archive'; + } + } + + /** + * Returns the adapter name + * + * @return string + */ + public function toString() + { + return 'Zip'; + } +} diff --git a/library/vendor/Zend/Filter/Decompress.php b/library/vendor/Zend/Filter/Decompress.php new file mode 100644 index 0000000..553c677 --- /dev/null +++ b/library/vendor/Zend/Filter/Decompress.php @@ -0,0 +1,48 @@ +getAdapter()->decompress($value); + } +} diff --git a/library/vendor/Zend/Filter/Decrypt.php b/library/vendor/Zend/Filter/Decrypt.php new file mode 100644 index 0000000..a17dc46 --- /dev/null +++ b/library/vendor/Zend/Filter/Decrypt.php @@ -0,0 +1,48 @@ +_adapter->decrypt($value); + } +} diff --git a/library/vendor/Zend/Filter/Digits.php b/library/vendor/Zend/Filter/Digits.php new file mode 100644 index 0000000..83881d7 --- /dev/null +++ b/library/vendor/Zend/Filter/Digits.php @@ -0,0 +1,81 @@ +toArray(); + } + + $this->setAdapter($options); + } + + /** + * Returns the name of the set adapter + * + * @return string + */ + public function getAdapter() + { + return $this->_adapter->toString(); + } + + /** + * Sets new encryption options + * + * @param string|array $options (Optional) Encryption options + * @return Zend_Filter_Encrypt + */ + public function setAdapter($options = null) + { + if (is_string($options)) { + $adapter = $options; + } else if (isset($options['adapter'])) { + $adapter = $options['adapter']; + unset($options['adapter']); + } else { + $adapter = 'Mcrypt'; + } + + if (!is_array($options)) { + $options = array(); + } + + if (Zend_Loader::isReadable('Zend/Filter/Encrypt/' . ucfirst($adapter). '.php')) { + $adapter = 'Zend_Filter_Encrypt_' . ucfirst($adapter); + } + + if (!class_exists($adapter)) { + Zend_Loader::loadClass($adapter); + } + + $this->_adapter = new $adapter($options); + if (!$this->_adapter instanceof Zend_Filter_Encrypt_Interface) { + throw new Zend_Filter_Exception("Encoding adapter '" . $adapter . "' does not implement Zend_Filter_Encrypt_Interface"); + } + + return $this; + } + + /** + * Calls adapter methods + * + * @param string $method Method to call + * @param string|array $options Options for this method + */ + public function __call($method, $options) + { + $part = substr($method, 0, 3); + if ((($part != 'get') and ($part != 'set')) or !method_exists($this->_adapter, $method)) { + throw new Zend_Filter_Exception("Unknown method '{$method}'"); + } + + return call_user_func_array(array($this->_adapter, $method), $options); + } + + /** + * Defined by Zend_Filter_Interface + * + * Encrypts the content $value with the defined settings + * + * @param string $value Content to encrypt + * @return string The encrypted content + */ + public function filter($value) + { + return $this->_adapter->encrypt($value); + } +} diff --git a/library/vendor/Zend/Filter/Encrypt/Interface.php b/library/vendor/Zend/Filter/Encrypt/Interface.php new file mode 100644 index 0000000..1510e7f --- /dev/null +++ b/library/vendor/Zend/Filter/Encrypt/Interface.php @@ -0,0 +1,47 @@ + encryption key string + * 'algorithm' => algorithm to use + * 'algorithm_directory' => directory where to find the algorithm + * 'mode' => encryption mode to use + * 'modedirectory' => directory where to find the mode + * ) + */ + protected $_encryption = array( + 'key' => 'ZendFramework', + 'algorithm' => 'blowfish', + 'algorithm_directory' => '', + 'mode' => 'cbc', + 'mode_directory' => '', + 'vector' => null, + 'salt' => false + ); + + /** + * Internal compression + * + * @var array + */ + protected $_compression; + + protected static $_srandCalled = false; + + /** + * Class constructor + * + * @param string|array|Zend_Config $options Cryption Options + */ + public function __construct($options) + { + if (!extension_loaded('mcrypt')) { + throw new Zend_Filter_Exception('This filter needs the mcrypt extension'); + } + + if ($options instanceof Zend_Config) { + $options = $options->toArray(); + } elseif (is_string($options)) { + $options = array('key' => $options); + } elseif (!is_array($options)) { + throw new Zend_Filter_Exception('Invalid options argument provided to filter'); + } + + if (array_key_exists('compression', $options)) { + $this->setCompression($options['compression']); + unset($options['compress']); + } + + $this->setEncryption($options); + } + + /** + * Returns the set encryption options + * + * @return array + */ + public function getEncryption() + { + return $this->_encryption; + } + + /** + * Sets new encryption options + * + * @param string|array $options Encryption options + * @return Zend_Filter_File_Encryption + */ + public function setEncryption($options) + { + if (is_string($options)) { + $options = array('key' => $options); + } + + if (!is_array($options)) { + throw new Zend_Filter_Exception('Invalid options argument provided to filter'); + } + + $options = $options + $this->getEncryption(); + $algorithms = mcrypt_list_algorithms($options['algorithm_directory']); + if (!in_array($options['algorithm'], $algorithms)) { + throw new Zend_Filter_Exception("The algorithm '{$options['algorithm']}' is not supported"); + } + + $modes = mcrypt_list_modes($options['mode_directory']); + if (!in_array($options['mode'], $modes)) { + throw new Zend_Filter_Exception("The mode '{$options['mode']}' is not supported"); + } + + if (!mcrypt_module_self_test($options['algorithm'], $options['algorithm_directory'])) { + throw new Zend_Filter_Exception('The given algorithm can not be used due an internal mcrypt problem'); + } + + if (!isset($options['vector'])) { + $options['vector'] = null; + } + + $this->_encryption = $options; + $this->setVector($options['vector']); + + return $this; + } + + /** + * Returns the set vector + * + * @return string + */ + public function getVector() + { + return $this->_encryption['vector']; + } + + /** + * Sets the initialization vector + * + * @param string $vector (Optional) Vector to set + * @return Zend_Filter_Encrypt_Mcrypt + */ + public function setVector($vector = null) + { + $cipher = $this->_openCipher(); + $size = mcrypt_enc_get_iv_size($cipher); + if (empty($vector)) { + $this->_srand(); + if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN' && version_compare(PHP_VERSION, '5.3.0', '<')) { + $method = MCRYPT_RAND; + } else { + if (file_exists('/dev/urandom') || (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN')) { + $method = MCRYPT_DEV_URANDOM; + } elseif (file_exists('/dev/random')) { + $method = MCRYPT_DEV_RANDOM; + } else { + $method = MCRYPT_RAND; + } + } + $vector = mcrypt_create_iv($size, $method); + } else if (strlen($vector) != $size) { + throw new Zend_Filter_Exception('The given vector has a wrong size for the set algorithm'); + } + + $this->_encryption['vector'] = $vector; + $this->_closeCipher($cipher); + + return $this; + } + + /** + * Returns the compression + * + * @return array + */ + public function getCompression() + { + return $this->_compression; + } + + /** + * Sets a internal compression for values to encrypt + * + * @param string|array $compression + * @return Zend_Filter_Encrypt_Mcrypt + */ + public function setCompression($compression) + { + if (is_string($this->_compression)) { + $compression = array('adapter' => $compression); + } + + $this->_compression = $compression; + return $this; + } + + /** + * Defined by Zend_Filter_Interface + * + * Encrypts $value with the defined settings + * + * @param string $value The content to encrypt + * @return string The encrypted content + */ + public function encrypt($value) + { + // compress prior to encryption + if (!empty($this->_compression)) { + $compress = new Zend_Filter_Compress($this->_compression); + $value = $compress->filter($value); + } + + $cipher = $this->_openCipher(); + $this->_initCipher($cipher); + $encrypted = mcrypt_generic($cipher, $value); + mcrypt_generic_deinit($cipher); + $this->_closeCipher($cipher); + + return $encrypted; + } + + /** + * Defined by Zend_Filter_Interface + * + * Decrypts $value with the defined settings + * + * @param string $value Content to decrypt + * @return string The decrypted content + */ + public function decrypt($value) + { + $cipher = $this->_openCipher(); + $this->_initCipher($cipher); + $decrypted = mdecrypt_generic($cipher, $value); + mcrypt_generic_deinit($cipher); + $this->_closeCipher($cipher); + + // decompress after decryption + if (!empty($this->_compression)) { + $decompress = new Zend_Filter_Decompress($this->_compression); + $decrypted = $decompress->filter($decrypted); + } + + return $decrypted; + } + + /** + * Returns the adapter name + * + * @return string + */ + public function toString() + { + return 'Mcrypt'; + } + + /** + * Open a cipher + * + * @throws Zend_Filter_Exception When the cipher can not be opened + * @return resource Returns the opened cipher + */ + protected function _openCipher() + { + $cipher = mcrypt_module_open( + $this->_encryption['algorithm'], + $this->_encryption['algorithm_directory'], + $this->_encryption['mode'], + $this->_encryption['mode_directory']); + + if ($cipher === false) { + throw new Zend_Filter_Exception('Mcrypt can not be opened with your settings'); + } + + return $cipher; + } + + /** + * Close a cipher + * + * @param resource $cipher Cipher to close + * @return Zend_Filter_Encrypt_Mcrypt + */ + protected function _closeCipher($cipher) + { + mcrypt_module_close($cipher); + + return $this; + } + + /** + * Initialises the cipher with the set key + * + * @param resource $cipher + * @throws + * @return resource + */ + protected function _initCipher($cipher) + { + $key = $this->_encryption['key']; + + $keysizes = mcrypt_enc_get_supported_key_sizes($cipher); + if (empty($keysizes) || ($this->_encryption['salt'] == true)) { + $this->_srand(); + $keysize = mcrypt_enc_get_key_size($cipher); + $key = substr(md5($key), 0, $keysize); + } else if (!in_array(strlen($key), $keysizes)) { + throw new Zend_Filter_Exception('The given key has a wrong size for the set algorithm'); + } + + $result = mcrypt_generic_init($cipher, $key, $this->_encryption['vector']); + if ($result < 0) { + throw new Zend_Filter_Exception('Mcrypt could not be initialize with the given setting'); + } + + return $this; + } + + /** + * _srand() interception + * + * @see ZF-8742 + */ + protected function _srand() + { + if (version_compare(PHP_VERSION, '5.3.0', '>=')) { + return; + } + if (!self::$_srandCalled) { + srand(Zend_Crypt_Math::randInteger(0, PHP_INT_MAX)); + self::$_srandCalled = true; + } + } +} diff --git a/library/vendor/Zend/Filter/Encrypt/Openssl.php b/library/vendor/Zend/Filter/Encrypt/Openssl.php new file mode 100644 index 0000000..7a46b8e --- /dev/null +++ b/library/vendor/Zend/Filter/Encrypt/Openssl.php @@ -0,0 +1,480 @@ + public keys + * 'private' => private keys + * 'envelope' => resulting envelope keys + * ) + */ + protected $_keys = array( + 'public' => array(), + 'private' => array(), + 'envelope' => array() + ); + + /** + * Internal passphrase + * + * @var string + */ + protected $_passphrase; + + /** + * Internal compression + * + * @var array + */ + protected $_compression; + + /** + * Internal create package + * + * @var boolean + */ + protected $_package = false; + + /** + * Class constructor + * Available options + * 'public' => public key + * 'private' => private key + * 'envelope' => envelope key + * 'passphrase' => passphrase + * 'compression' => compress value with this compression adapter + * 'package' => pack envelope keys into encrypted string, simplifies decryption + * + * @param string|array $options Options for this adapter + */ + public function __construct($options = array()) + { + if (!extension_loaded('openssl')) { + throw new Zend_Filter_Exception('This filter needs the openssl extension'); + } + + if ($options instanceof Zend_Config) { + $options = $options->toArray(); + } + + if (!is_array($options)) { + $options = array('public' => $options); + } + + if (array_key_exists('passphrase', $options)) { + $this->setPassphrase($options['passphrase']); + unset($options['passphrase']); + } + + if (array_key_exists('compression', $options)) { + $this->setCompression($options['compression']); + unset($options['compress']); + } + + if (array_key_exists('package', $options)) { + $this->setPackage($options['package']); + unset($options['package']); + } + + $this->_setKeys($options); + } + + /** + * Sets the encryption keys + * + * @param string|array $keys Key with type association + * @return Zend_Filter_Encrypt_Openssl + */ + protected function _setKeys($keys) + { + if (!is_array($keys)) { + throw new Zend_Filter_Exception('Invalid options argument provided to filter'); + } + + foreach ($keys as $type => $key) { + if (ctype_print($key) && is_file(realpath($key)) && is_readable($key)) { + $file = fopen($key, 'r'); + $cert = fread($file, 8192); + fclose($file); + } else { + $cert = $key; + $key = count($this->_keys[$type]); + } + + switch ($type) { + case 'public': + $test = openssl_pkey_get_public($cert); + if ($test === false) { + throw new Zend_Filter_Exception("Public key '{$cert}' not valid"); + } + + openssl_free_key($test); + $this->_keys['public'][$key] = $cert; + break; + case 'private': + $test = openssl_pkey_get_private($cert, $this->_passphrase); + if ($test === false) { + throw new Zend_Filter_Exception("Private key '{$cert}' not valid"); + } + + openssl_free_key($test); + $this->_keys['private'][$key] = $cert; + break; + case 'envelope': + $this->_keys['envelope'][$key] = $cert; + break; + default: + break; + } + } + + return $this; + } + + /** + * Returns all public keys + * + * @return array + */ + public function getPublicKey() + { + $key = $this->_keys['public']; + return $key; + } + + /** + * Sets public keys + * + * @param string|array $key Public keys + * @return Zend_Filter_Encrypt_Openssl + */ + public function setPublicKey($key) + { + if (is_array($key)) { + foreach($key as $type => $option) { + if ($type !== 'public') { + $key['public'] = $option; + unset($key[$type]); + } + } + } else { + $key = array('public' => $key); + } + + return $this->_setKeys($key); + } + + /** + * Returns all private keys + * + * @return array + */ + public function getPrivateKey() + { + $key = $this->_keys['private']; + return $key; + } + + /** + * Sets private keys + * + * @param string $key Private key + * @param string $passphrase + * @return Zend_Filter_Encrypt_Openssl + */ + public function setPrivateKey($key, $passphrase = null) + { + if (is_array($key)) { + foreach($key as $type => $option) { + if ($type !== 'private') { + $key['private'] = $option; + unset($key[$type]); + } + } + } else { + $key = array('private' => $key); + } + + if ($passphrase !== null) { + $this->setPassphrase($passphrase); + } + + return $this->_setKeys($key); + } + + /** + * Returns all envelope keys + * + * @return array + */ + public function getEnvelopeKey() + { + $key = $this->_keys['envelope']; + return $key; + } + + /** + * Sets envelope keys + * + * @param string|array $options Envelope keys + * @return Zend_Filter_Encrypt_Openssl + */ + public function setEnvelopeKey($key) + { + if (is_array($key)) { + foreach($key as $type => $option) { + if ($type !== 'envelope') { + $key['envelope'] = $option; + unset($key[$type]); + } + } + } else { + $key = array('envelope' => $key); + } + + return $this->_setKeys($key); + } + + /** + * Returns the passphrase + * + * @return string + */ + public function getPassphrase() + { + return $this->_passphrase; + } + + /** + * Sets a new passphrase + * + * @param string $passphrase + * @return Zend_Filter_Encrypt_Openssl + */ + public function setPassphrase($passphrase) + { + $this->_passphrase = $passphrase; + return $this; + } + + /** + * Returns the compression + * + * @return array + */ + public function getCompression() + { + return $this->_compression; + } + + /** + * Sets a internal compression for values to encrypt + * + * @param string|array $compression + * @return Zend_Filter_Encrypt_Openssl + */ + public function setCompression($compression) + { + if (is_string($this->_compression)) { + $compression = array('adapter' => $compression); + } + + $this->_compression = $compression; + return $this; + } + + /** + * Returns if header should be packaged + * + * @return boolean + */ + public function getPackage() + { + return $this->_package; + } + + /** + * Sets if the envelope keys should be included in the encrypted value + * + * @param boolean $package + * @return Zend_Filter_Encrypt_Openssl + */ + public function setPackage($package) + { + $this->_package = (boolean) $package; + return $this; + } + + /** + * Encrypts $value with the defined settings + * Note that you also need the "encrypted" keys to be able to decrypt + * + * @param string $value Content to encrypt + * @return string The encrypted content + * @throws Zend_Filter_Exception + */ + public function encrypt($value) + { + $encrypted = array(); + $encryptedkeys = array(); + + if (count($this->_keys['public']) == 0) { + throw new Zend_Filter_Exception('Openssl can not encrypt without public keys'); + } + + $keys = array(); + $fingerprints = array(); + $count = -1; + foreach($this->_keys['public'] as $key => $cert) { + $keys[$key] = openssl_pkey_get_public($cert); + if ($this->_package) { + $details = openssl_pkey_get_details($keys[$key]); + if ($details === false) { + $details = array('key' => 'ZendFramework'); + } + + ++$count; + $fingerprints[$count] = md5($details['key']); + } + } + + // compress prior to encryption + if (!empty($this->_compression)) { + $compress = new Zend_Filter_Compress($this->_compression); + $value = $compress->filter($value); + } + + $crypt = openssl_seal($value, $encrypted, $encryptedkeys, $keys); + foreach ($keys as $key) { + openssl_free_key($key); + } + + if ($crypt === false) { + throw new Zend_Filter_Exception('Openssl was not able to encrypt your content with the given options'); + } + + $this->_keys['envelope'] = $encryptedkeys; + + // Pack data and envelope keys into single string + if ($this->_package) { + $header = pack('n', count($this->_keys['envelope'])); + foreach($this->_keys['envelope'] as $key => $envKey) { + $header .= pack('H32n', $fingerprints[$key], strlen($envKey)) . $envKey; + } + + $encrypted = $header . $encrypted; + } + + return $encrypted; + } + + /** + * Defined by Zend_Filter_Interface + * + * Decrypts $value with the defined settings + * + * @param string $value Content to decrypt + * @return string The decrypted content + * @throws Zend_Filter_Exception + */ + public function decrypt($value) + { + $decrypted = ""; + $envelope = current($this->getEnvelopeKey()); + + if (count($this->_keys['private']) !== 1) { + throw new Zend_Filter_Exception('Please give a private key for decryption with Openssl'); + } + + if (!$this->_package && empty($envelope)) { + throw new Zend_Filter_Exception('Please give a envelope key for decryption with Openssl'); + } + + foreach($this->_keys['private'] as $key => $cert) { + $keys = openssl_pkey_get_private($cert, $this->getPassphrase()); + } + + if ($this->_package) { + $details = openssl_pkey_get_details($keys); + if ($details !== false) { + $fingerprint = md5($details['key']); + } else { + $fingerprint = md5("ZendFramework"); + } + + $count = unpack('ncount', $value); + $count = $count['count']; + $length = 2; + for($i = $count; $i > 0; --$i) { + $header = unpack('H32print/nsize', substr($value, $length, 18)); + $length += 18; + if ($header['print'] == $fingerprint) { + $envelope = substr($value, $length, $header['size']); + } + + $length += $header['size']; + } + + // remainder of string is the value to decrypt + $value = substr($value, $length); + } + + $crypt = openssl_open($value, $decrypted, $envelope, $keys); + openssl_free_key($keys); + + if ($crypt === false) { + throw new Zend_Filter_Exception('Openssl was not able to decrypt you content with the given options'); + } + + // decompress after decryption + if (!empty($this->_compression)) { + $decompress = new Zend_Filter_Decompress($this->_compression); + $decrypted = $decompress->filter($decrypted); + } + + return $decrypted; + } + + /** + * Returns the adapter name + * + * @return string + */ + public function toString() + { + return 'Openssl'; + } +} diff --git a/library/vendor/Zend/Filter/Exception.php b/library/vendor/Zend/Filter/Exception.php new file mode 100644 index 0000000..d56145a --- /dev/null +++ b/library/vendor/Zend/Filter/Exception.php @@ -0,0 +1,36 @@ +_filename; + } + + /** + * Sets the new filename where the content will be stored + * + * @param string $filename (Optional) New filename to set + * @return Zend_Filter_File_Encryt + */ + public function setFilename($filename = null) + { + $this->_filename = $filename; + return $this; + } + + /** + * Defined by Zend_Filter_Interface + * + * Decrypts the file $value with the defined settings + * + * @param string $value Full path of file to change + * @return string The filename which has been set, or false when there were errors + */ + public function filter($value) + { + if (!file_exists($value)) { + throw new Zend_Filter_Exception("File '$value' not found"); + } + + if (!isset($this->_filename)) { + $this->_filename = $value; + } + + if (file_exists($this->_filename) and !is_writable($this->_filename)) { + throw new Zend_Filter_Exception("File '{$this->_filename}' is not writable"); + } + + $content = file_get_contents($value); + if (!$content) { + throw new Zend_Filter_Exception("Problem while reading file '$value'"); + } + + $decrypted = parent::filter($content); + $result = file_put_contents($this->_filename, $decrypted); + + if (!$result) { + throw new Zend_Filter_Exception("Problem while writing file '{$this->_filename}'"); + } + + return $this->_filename; + } +} diff --git a/library/vendor/Zend/Filter/File/Encrypt.php b/library/vendor/Zend/Filter/File/Encrypt.php new file mode 100644 index 0000000..16be9df --- /dev/null +++ b/library/vendor/Zend/Filter/File/Encrypt.php @@ -0,0 +1,101 @@ +_filename; + } + + /** + * Sets the new filename where the content will be stored + * + * @param string $filename (Optional) New filename to set + * @return Zend_Filter_File_Encryt + */ + public function setFilename($filename = null) + { + $this->_filename = $filename; + return $this; + } + + /** + * Defined by Zend_Filter_Interface + * + * Encrypts the file $value with the defined settings + * + * @param string $value Full path of file to change + * @return string The filename which has been set, or false when there were errors + */ + public function filter($value) + { + if (!file_exists($value)) { + throw new Zend_Filter_Exception("File '$value' not found"); + } + + if (!isset($this->_filename)) { + $this->_filename = $value; + } + + if (file_exists($this->_filename) and !is_writable($this->_filename)) { + throw new Zend_Filter_Exception("File '{$this->_filename}' is not writable"); + } + + $content = file_get_contents($value); + if (!$content) { + throw new Zend_Filter_Exception("Problem while reading file '$value'"); + } + + $encrypted = parent::filter($content); + $result = file_put_contents($this->_filename, $encrypted); + + if (!$result) { + throw new Zend_Filter_Exception("Problem while writing file '{$this->_filename}'"); + } + + return $this->_filename; + } +} diff --git a/library/vendor/Zend/Filter/File/LowerCase.php b/library/vendor/Zend/Filter/File/LowerCase.php new file mode 100644 index 0000000..681332b --- /dev/null +++ b/library/vendor/Zend/Filter/File/LowerCase.php @@ -0,0 +1,79 @@ +setEncoding($options); + } + } + + /** + * Defined by Zend_Filter_Interface + * + * Does a lowercase on the content of the given file + * + * @param string $value Full path of file to change + * @return string The given $value + * @throws Zend_Filter_Exception + */ + public function filter($value) + { + if (!file_exists($value)) { + throw new Zend_Filter_Exception("File '$value' not found"); + } + + if (!is_writable($value)) { + throw new Zend_Filter_Exception("File '$value' is not writable"); + } + + $content = file_get_contents($value); + if (!$content) { + throw new Zend_Filter_Exception("Problem while reading file '$value'"); + } + + $content = parent::filter($content); + $result = file_put_contents($value, $content); + + if (!$result) { + throw new Zend_Filter_Exception("Problem while writing file '$value'"); + } + + return $value; + } +} diff --git a/library/vendor/Zend/Filter/File/Rename.php b/library/vendor/Zend/Filter/File/Rename.php new file mode 100644 index 0000000..1bf5650 --- /dev/null +++ b/library/vendor/Zend/Filter/File/Rename.php @@ -0,0 +1,304 @@ + Source filename or directory which will be renamed + * 'target' => Target filename or directory, the new name of the sourcefile + * 'overwrite' => Shall existing files be overwritten ? + * + * @param string|array $options Target file or directory to be renamed + * @param string $target Source filename or directory (deprecated) + * @param bool $overwrite Should existing files be overwritten (deprecated) + * @return void + */ + public function __construct($options) + { + if ($options instanceof Zend_Config) { + $options = $options->toArray(); + } elseif (is_string($options)) { + $options = array('target' => $options); + } elseif (!is_array($options)) { + throw new Zend_Filter_Exception('Invalid options argument provided to filter'); + } + + if (1 < func_num_args()) { + $argv = func_get_args(); + array_shift($argv); + $source = array_shift($argv); + $overwrite = false; + if (!empty($argv)) { + $overwrite = array_shift($argv); + } + $options['source'] = $source; + $options['overwrite'] = $overwrite; + } + + $this->setFile($options); + } + + /** + * Returns the files to rename and their new name and location + * + * @return array + */ + public function getFile() + { + return $this->_files; + } + + /** + * Sets a new file or directory as target, deleting existing ones + * + * Array accepts the following keys: + * 'source' => Source filename or directory which will be renamed + * 'target' => Target filename or directory, the new name of the sourcefile + * 'overwrite' => Shall existing files be overwritten ? + * + * @param string|array $options Old file or directory to be rewritten + * @return Zend_Filter_File_Rename + */ + public function setFile($options) + { + $this->_files = array(); + $this->addFile($options); + + return $this; + } + + /** + * Adds a new file or directory as target to the existing ones + * + * Array accepts the following keys: + * 'source' => Source filename or directory which will be renamed + * 'target' => Target filename or directory, the new name of the sourcefile + * 'overwrite' => Shall existing files be overwritten ? + * + * @param string|array $options Old file or directory to be rewritten + * @return Zend_Filter_File_Rename + */ + public function addFile($options) + { + if (is_string($options)) { + $options = array('target' => $options); + } elseif (!is_array($options)) { + throw new Zend_Filter_Exception ('Invalid options to rename filter provided'); + } + + $this->_convertOptions($options); + + return $this; + } + + /** + * Returns only the new filename without moving it + * But existing files will be erased when the overwrite option is true + * + * @param string $value Full path of file to change + * @param boolean $source Return internal informations + * @return string The new filename which has been set + */ + public function getNewName($value, $source = false) + { + $file = $this->_getFileName($value); + + if (!is_array($file) || !array_key_exists('source', $file) || !array_key_exists('target', $file)) { + return $value; + } + + if ($file['source'] == $file['target']) { + return $value; + } + + if (!file_exists($file['source'])) { + return $value; + } + + if (($file['overwrite'] == true) && (file_exists($file['target']))) { + unlink($file['target']); + } + + if (file_exists($file['target'])) { + throw new Zend_Filter_Exception(sprintf("File '%s' could not be renamed. It already exists.", $value)); + } + + if ($source) { + return $file; + } + + return $file['target']; + } + + /** + * Defined by Zend_Filter_Interface + * + * Renames the file $value to the new name set before + * Returns the file $value, removing all but digit characters + * + * @param string $value Full path of file to change + * @throws Zend_Filter_Exception + * @return string The new filename which has been set, or false when there were errors + */ + public function filter($value) + { + $file = $this->getNewName($value, true); + if (is_string($file)) { + return $file; + } + + $result = rename($file['source'], $file['target']); + + if ($result === true) { + return $file['target']; + } + + throw new Zend_Filter_Exception(sprintf("File '%s' could not be renamed. An error occured while processing the file.", $value)); + } + + /** + * Internal method for creating the file array + * Supports single and nested arrays + * + * @param array $options + * @return array + */ + protected function _convertOptions($options) { + $files = array(); + foreach ($options as $key => $value) { + if (is_array($value)) { + $this->_convertOptions($value); + continue; + } + + switch ($key) { + case "source": + $files['source'] = (string) $value; + break; + + case 'target' : + $files['target'] = (string) $value; + break; + + case 'overwrite' : + $files['overwrite'] = (boolean) $value; + break; + + default: + break; + } + } + + if (empty($files)) { + return $this; + } + + if (empty($files['source'])) { + $files['source'] = '*'; + } + + if (empty($files['target'])) { + $files['target'] = '*'; + } + + if (empty($files['overwrite'])) { + $files['overwrite'] = false; + } + + $found = false; + foreach ($this->_files as $key => $value) { + if ($value['source'] == $files['source']) { + $this->_files[$key] = $files; + $found = true; + } + } + + if (!$found) { + $count = count($this->_files); + $this->_files[$count] = $files; + } + + return $this; + } + + /** + * Internal method to resolve the requested source + * and return all other related parameters + * + * @param string $file Filename to get the informations for + * @return array + */ + protected function _getFileName($file) + { + $rename = array(); + foreach ($this->_files as $value) { + if ($value['source'] == '*') { + if (!isset($rename['source'])) { + $rename = $value; + $rename['source'] = $file; + } + } + + if ($value['source'] == $file) { + $rename = $value; + } + } + + if (!isset($rename['source'])) { + return $file; + } + + if (!isset($rename['target']) or ($rename['target'] == '*')) { + $rename['target'] = $rename['source']; + } + + if (is_dir($rename['target'])) { + $name = basename($rename['source']); + $last = $rename['target'][strlen($rename['target']) - 1]; + if (($last != '/') and ($last != '\\')) { + $rename['target'] .= DIRECTORY_SEPARATOR; + } + + $rename['target'] .= $name; + } + + return $rename; + } +} diff --git a/library/vendor/Zend/Filter/File/UpperCase.php b/library/vendor/Zend/Filter/File/UpperCase.php new file mode 100644 index 0000000..318e33e --- /dev/null +++ b/library/vendor/Zend/Filter/File/UpperCase.php @@ -0,0 +1,79 @@ +setEncoding($options); + } + } + + /** + * Defined by Zend_Filter_Interface + * + * Does a lowercase on the content of the given file + * + * @param string $value Full path of file to change + * @return string The given $value + * @throws Zend_Filter_Exception + */ + public function filter($value) + { + if (!file_exists($value)) { + throw new Zend_Filter_Exception("File '$value' not found"); + } + + if (!is_writable($value)) { + throw new Zend_Filter_Exception("File '$value' is not writable"); + } + + $content = file_get_contents($value); + if (!$content) { + throw new Zend_Filter_Exception("Problem while reading file '$value'"); + } + + $content = parent::filter($content); + $result = file_put_contents($value, $content); + + if (!$result) { + throw new Zend_Filter_Exception("Problem while writing file '$value'"); + } + + return $value; + } +} diff --git a/library/vendor/Zend/Filter/HtmlEntities.php b/library/vendor/Zend/Filter/HtmlEntities.php new file mode 100644 index 0000000..5ba7ad8 --- /dev/null +++ b/library/vendor/Zend/Filter/HtmlEntities.php @@ -0,0 +1,213 @@ +toArray(); + } else if (!is_array($options)) { + $options = func_get_args(); + $temp['quotestyle'] = array_shift($options); + if (!empty($options)) { + $temp['charset'] = array_shift($options); + } + + $options = $temp; + } + + if (!isset($options['quotestyle'])) { + $options['quotestyle'] = ENT_COMPAT; + } + + if (!isset($options['encoding'])) { + $options['encoding'] = 'UTF-8'; + } + if (isset($options['charset'])) { + $options['encoding'] = $options['charset']; + } + + if (!isset($options['doublequote'])) { + $options['doublequote'] = true; + } + + $this->setQuoteStyle($options['quotestyle']); + $this->setEncoding($options['encoding']); + $this->setDoubleQuote($options['doublequote']); + } + + /** + * Returns the quoteStyle option + * + * @return integer + */ + public function getQuoteStyle() + { + return $this->_quoteStyle; + } + + /** + * Sets the quoteStyle option + * + * @param integer $quoteStyle + * @return Zend_Filter_HtmlEntities Provides a fluent interface + */ + public function setQuoteStyle($quoteStyle) + { + $this->_quoteStyle = $quoteStyle; + return $this; + } + + + /** + * Get encoding + * + * @return string + */ + public function getEncoding() + { + return $this->_encoding; + } + + /** + * Set encoding + * + * @param string $value + * @return Zend_Filter_HtmlEntities + */ + public function setEncoding($value) + { + $this->_encoding = (string) $value; + return $this; + } + + /** + * Returns the charSet option + * + * Proxies to {@link getEncoding()} + * + * @return string + */ + public function getCharSet() + { + return $this->getEncoding(); + } + + /** + * Sets the charSet option + * + * Proxies to {@link setEncoding()} + * + * @param string $charSet + * @return Zend_Filter_HtmlEntities Provides a fluent interface + */ + public function setCharSet($charSet) + { + return $this->setEncoding($charSet); + } + + /** + * Returns the doubleQuote option + * + * @return boolean + */ + public function getDoubleQuote() + { + return $this->_doubleQuote; + } + + /** + * Sets the doubleQuote option + * + * @param boolean $doubleQuote + * @return Zend_Filter_HtmlEntities Provides a fluent interface + */ + public function setDoubleQuote($doubleQuote) + { + $this->_doubleQuote = (boolean) $doubleQuote; + return $this; + } + + /** + * Defined by Zend_Filter_Interface + * + * Returns the string $value, converting characters to their corresponding HTML entity + * equivalents where they exist + * + * @param string $value + * @return string + */ + public function filter($value) + { + $filtered = htmlentities((string) $value, $this->getQuoteStyle(), $this->getEncoding(), $this->getDoubleQuote()); + if (strlen((string) $value) && !strlen($filtered)) { + if (!function_exists('iconv')) { + throw new Zend_Filter_Exception('Encoding mismatch has resulted in htmlentities errors'); + } + $enc = $this->getEncoding(); + $value = iconv('', $enc . '//IGNORE', (string) $value); + $filtered = htmlentities($value, $this->getQuoteStyle(), $enc, $this->getDoubleQuote()); + if (!strlen($filtered)) { + throw new Zend_Filter_Exception('Encoding mismatch has resulted in htmlentities errors'); + } + } + return $filtered; + } +} diff --git a/library/vendor/Zend/Filter/Inflector.php b/library/vendor/Zend/Filter/Inflector.php new file mode 100644 index 0000000..2192f84 --- /dev/null +++ b/library/vendor/Zend/Filter/Inflector.php @@ -0,0 +1,523 @@ +toArray(); + } else if (!is_array($options)) { + $options = func_get_args(); + $temp = array(); + + if (!empty($options)) { + $temp['target'] = array_shift($options); + } + + if (!empty($options)) { + $temp['rules'] = array_shift($options); + } + + if (!empty($options)) { + $temp['throwTargetExceptionsOn'] = array_shift($options); + } + + if (!empty($options)) { + $temp['targetReplacementIdentifier'] = array_shift($options); + } + + $options = $temp; + } + + $this->setOptions($options); + } + + /** + * Retreive PluginLoader + * + * @return Zend_Loader_PluginLoader_Interface + */ + public function getPluginLoader() + { + if (!$this->_pluginLoader instanceof Zend_Loader_PluginLoader_Interface) { + $this->_pluginLoader = new Zend_Loader_PluginLoader(array('Zend_Filter_' => 'Zend/Filter/'), __CLASS__); + } + + return $this->_pluginLoader; + } + + /** + * Set PluginLoader + * + * @param Zend_Loader_PluginLoader_Interface $pluginLoader + * @return Zend_Filter_Inflector + */ + public function setPluginLoader(Zend_Loader_PluginLoader_Interface $pluginLoader) + { + $this->_pluginLoader = $pluginLoader; + return $this; + } + + /** + * Use Zend_Config object to set object state + * + * @deprecated Use setOptions() instead + * @param Zend_Config $config + * @return Zend_Filter_Inflector + */ + public function setConfig(Zend_Config $config) + { + return $this->setOptions($config); + } + + /** + * Set options + * + * @param array $options + * @return Zend_Filter_Inflector + */ + public function setOptions($options) { + if ($options instanceof Zend_Config) { + $options = $options->toArray(); + } + + // Set Präfix Path + if (array_key_exists('filterPrefixPath', $options)) { + if (!is_scalar($options['filterPrefixPath'])) { + foreach ($options['filterPrefixPath'] as $prefix => $path) { + $this->addFilterPrefixPath($prefix, $path); + } + } + } + + if (array_key_exists('throwTargetExceptionsOn', $options)) { + $this->setThrowTargetExceptionsOn($options['throwTargetExceptionsOn']); + } + + if (array_key_exists('targetReplacementIdentifier', $options)) { + $this->setTargetReplacementIdentifier($options['targetReplacementIdentifier']); + } + + if (array_key_exists('target', $options)) { + $this->setTarget($options['target']); + } + + if (array_key_exists('rules', $options)) { + $this->addRules($options['rules']); + } + + return $this; + } + + /** + * Convienence method to add prefix and path to PluginLoader + * + * @param string $prefix + * @param string $path + * @return Zend_Filter_Inflector + */ + public function addFilterPrefixPath($prefix, $path) + { + $this->getPluginLoader()->addPrefixPath($prefix, $path); + return $this; + } + + /** + * Set Whether or not the inflector should throw an exception when a replacement + * identifier is still found within an inflected target. + * + * @param bool $throwTargetExceptions + * @return Zend_Filter_Inflector + */ + public function setThrowTargetExceptionsOn($throwTargetExceptionsOn) + { + $this->_throwTargetExceptionsOn = ($throwTargetExceptionsOn == true) ? true : false; + return $this; + } + + /** + * Will exceptions be thrown? + * + * @return bool + */ + public function isThrowTargetExceptionsOn() + { + return $this->_throwTargetExceptionsOn; + } + + /** + * Set the Target Replacement Identifier, by default ':' + * + * @param string $targetReplacementIdentifier + * @return Zend_Filter_Inflector + */ + public function setTargetReplacementIdentifier($targetReplacementIdentifier) + { + if ($targetReplacementIdentifier) { + $this->_targetReplacementIdentifier = (string) $targetReplacementIdentifier; + } + + return $this; + } + + /** + * Get Target Replacement Identifier + * + * @return string + */ + public function getTargetReplacementIdentifier() + { + return $this->_targetReplacementIdentifier; + } + + /** + * Set a Target + * ex: 'scripts/:controller/:action.:suffix' + * + * @param string + * @return Zend_Filter_Inflector + */ + public function setTarget($target) + { + $this->_target = (string) $target; + return $this; + } + + /** + * Retrieve target + * + * @return string + */ + public function getTarget() + { + return $this->_target; + } + + /** + * Set Target Reference + * + * @param reference $target + * @return Zend_Filter_Inflector + */ + public function setTargetReference(&$target) + { + $this->_target =& $target; + return $this; + } + + /** + * SetRules() is the same as calling addRules() with the exception that it + * clears the rules before adding them. + * + * @param array $rules + * @return Zend_Filter_Inflector + */ + public function setRules(Array $rules) + { + $this->clearRules(); + $this->addRules($rules); + return $this; + } + + /** + * AddRules(): multi-call to setting filter rules. + * + * If prefixed with a ":" (colon), a filter rule will be added. If not + * prefixed, a static replacement will be added. + * + * ex: + * array( + * ':controller' => array('CamelCaseToUnderscore','StringToLower'), + * ':action' => array('CamelCaseToUnderscore','StringToLower'), + * 'suffix' => 'phtml' + * ); + * + * @param array + * @return Zend_Filter_Inflector + */ + public function addRules(Array $rules) + { + $keys = array_keys($rules); + foreach ($keys as $spec) { + if ($spec[0] == ':') { + $this->addFilterRule($spec, $rules[$spec]); + } else { + $this->setStaticRule($spec, $rules[$spec]); + } + } + + return $this; + } + + /** + * Get rules + * + * By default, returns all rules. If a $spec is provided, will return those + * rules if found, false otherwise. + * + * @param string $spec + * @return array|false + */ + public function getRules($spec = null) + { + if (null !== $spec) { + $spec = $this->_normalizeSpec($spec); + if (isset($this->_rules[$spec])) { + return $this->_rules[$spec]; + } + return false; + } + + return $this->_rules; + } + + /** + * getRule() returns a rule set by setFilterRule(), a numeric index must be provided + * + * @param string $spec + * @param int $index + * @return Zend_Filter_Interface|false + */ + public function getRule($spec, $index) + { + $spec = $this->_normalizeSpec($spec); + if (isset($this->_rules[$spec]) && is_array($this->_rules[$spec])) { + if (isset($this->_rules[$spec][$index])) { + return $this->_rules[$spec][$index]; + } + } + return false; + } + + /** + * ClearRules() clears the rules currently in the inflector + * + * @return Zend_Filter_Inflector + */ + public function clearRules() + { + $this->_rules = array(); + return $this; + } + + /** + * Set a filtering rule for a spec. $ruleSet can be a string, Filter object + * or an array of strings or filter objects. + * + * @param string $spec + * @param array|string|Zend_Filter_Interface $ruleSet + * @return Zend_Filter_Inflector + */ + public function setFilterRule($spec, $ruleSet) + { + $spec = $this->_normalizeSpec($spec); + $this->_rules[$spec] = array(); + return $this->addFilterRule($spec, $ruleSet); + } + + /** + * Add a filter rule for a spec + * + * @param mixed $spec + * @param mixed $ruleSet + * @return void + */ + public function addFilterRule($spec, $ruleSet) + { + $spec = $this->_normalizeSpec($spec); + if (!isset($this->_rules[$spec])) { + $this->_rules[$spec] = array(); + } + + if (!is_array($ruleSet)) { + $ruleSet = array($ruleSet); + } + + if (is_string($this->_rules[$spec])) { + $temp = $this->_rules[$spec]; + $this->_rules[$spec] = array(); + $this->_rules[$spec][] = $temp; + } + + foreach ($ruleSet as $rule) { + $this->_rules[$spec][] = $this->_getRule($rule); + } + + return $this; + } + + /** + * Set a static rule for a spec. This is a single string value + * + * @param string $name + * @param string $value + * @return Zend_Filter_Inflector + */ + public function setStaticRule($name, $value) + { + $name = $this->_normalizeSpec($name); + $this->_rules[$name] = (string) $value; + return $this; + } + + /** + * Set Static Rule Reference. + * + * This allows a consuming class to pass a property or variable + * in to be referenced when its time to build the output string from the + * target. + * + * @param string $name + * @param mixed $reference + * @return Zend_Filter_Inflector + */ + public function setStaticRuleReference($name, &$reference) + { + $name = $this->_normalizeSpec($name); + $this->_rules[$name] =& $reference; + return $this; + } + + /** + * Inflect + * + * @param string|array $source + * @return string + */ + public function filter($source) + { + // clean source + foreach ( (array) $source as $sourceName => $sourceValue) { + $source[ltrim($sourceName, ':')] = $sourceValue; + } + + $pregQuotedTargetReplacementIdentifier = preg_quote($this->_targetReplacementIdentifier, '#'); + $processedParts = array(); + + foreach ($this->_rules as $ruleName => $ruleValue) { + if (isset($source[$ruleName])) { + if (is_string($ruleValue)) { + // overriding the set rule + $processedParts['#'.$pregQuotedTargetReplacementIdentifier.$ruleName.'#'] = str_replace('\\', '\\\\', $source[$ruleName]); + } elseif (is_array($ruleValue)) { + $processedPart = $source[$ruleName]; + foreach ($ruleValue as $ruleFilter) { + $processedPart = $ruleFilter->filter($processedPart); + } + $processedParts['#'.$pregQuotedTargetReplacementIdentifier.$ruleName.'#'] = str_replace('\\', '\\\\', $processedPart); + } + } elseif (is_string($ruleValue)) { + $processedParts['#'.$pregQuotedTargetReplacementIdentifier.$ruleName.'#'] = str_replace('\\', '\\\\', $ruleValue); + } + } + + // all of the values of processedParts would have been str_replace('\\', '\\\\', ..)'d to disable preg_replace backreferences + $inflectedTarget = preg_replace(array_keys($processedParts), array_values($processedParts), $this->_target); + + if ($this->_throwTargetExceptionsOn && (preg_match('#(?='.$pregQuotedTargetReplacementIdentifier.'[A-Za-z]{1})#', $inflectedTarget) == true)) { + throw new Zend_Filter_Exception('A replacement identifier ' . $this->_targetReplacementIdentifier . ' was found inside the inflected target, perhaps a rule was not satisfied with a target source? Unsatisfied inflected target: ' . $inflectedTarget); + } + + return $inflectedTarget; + } + + /** + * Normalize spec string + * + * @param string $spec + * @return string + */ + protected function _normalizeSpec($spec) + { + return ltrim((string) $spec, ':&'); + } + + /** + * Resolve named filters and convert them to filter objects. + * + * @param string $rule + * @return Zend_Filter_Interface + */ + protected function _getRule($rule) + { + if ($rule instanceof Zend_Filter_Interface) { + return $rule; + } + + $rule = (string) $rule; + + $className = $this->getPluginLoader()->load($rule); + $ruleObject = new $className(); + if (!$ruleObject instanceof Zend_Filter_Interface) { + throw new Zend_Filter_Exception('No class named ' . $rule . ' implementing Zend_Filter_Interface could be found'); + } + + return $ruleObject; + } +} diff --git a/library/vendor/Zend/Filter/Input.php b/library/vendor/Zend/Filter/Input.php new file mode 100644 index 0000000..0c245a1 --- /dev/null +++ b/library/vendor/Zend/Filter/Input.php @@ -0,0 +1,1196 @@ + false, + self::BREAK_CHAIN => false, + self::ESCAPE_FILTER => 'HtmlEntities', + self::MISSING_MESSAGE => "Field '%field%' is required by rule '%rule%', but the field is missing", + self::NOT_EMPTY_MESSAGE => "You must give a non-empty value for field '%field%'", + self::PRESENCE => self::PRESENCE_OPTIONAL + ); + + /** + * @var boolean Set to False initially, this is set to True after the + * input data have been processed. Reset to False in setData() method. + */ + protected $_processed = false; + + /** + * Translation object + * @var Zend_Translate + */ + protected $_translator; + + /** + * Is translation disabled? + * @var Boolean + */ + protected $_translatorDisabled = false; + + /** + * @param array $filterRules + * @param array $validatorRules + * @param array $data OPTIONAL + * @param array $options OPTIONAL + */ + public function __construct($filterRules, $validatorRules, array $data = null, array $options = null) + { + if ($options) { + $this->setOptions($options); + } + + $this->_filterRules = (array) $filterRules; + $this->_validatorRules = (array) $validatorRules; + + if ($data) { + $this->setData($data); + } + } + + /** + * @param mixed $namespaces + * @return Zend_Filter_Input + * @deprecated since 1.5.0RC1 - use addFilterPrefixPath() or addValidatorPrefixPath instead. + */ + public function addNamespace($namespaces) + { + if (!is_array($namespaces)) { + $namespaces = array($namespaces); + } + + foreach ($namespaces as $namespace) { + $prefix = $namespace; + $path = str_replace('_', DIRECTORY_SEPARATOR, $prefix); + $this->addFilterPrefixPath($prefix, $path); + $this->addValidatorPrefixPath($prefix, $path); + } + + return $this; + } + + /** + * Add prefix path for all elements + * + * @param string $prefix + * @param string $path + * @return Zend_Filter_Input + */ + public function addFilterPrefixPath($prefix, $path) + { + $this->getPluginLoader(self::FILTER)->addPrefixPath($prefix, $path); + + return $this; + } + + /** + * Add prefix path for all elements + * + * @param string $prefix + * @param string $path + * @return Zend_Filter_Input + */ + public function addValidatorPrefixPath($prefix, $path) + { + $this->getPluginLoader(self::VALIDATE)->addPrefixPath($prefix, $path); + + return $this; + } + + /** + * Set plugin loaders for use with decorators and elements + * + * @param Zend_Loader_PluginLoader_Interface $loader + * @param string $type 'filter' or 'validate' + * @return Zend_Filter_Input + * @throws Zend_Filter_Exception on invalid type + */ + public function setPluginLoader(Zend_Loader_PluginLoader_Interface $loader, $type) + { + $type = strtolower($type); + switch ($type) { + case self::FILTER: + case self::VALIDATE: + $this->_loaders[$type] = $loader; + return $this; + default: + throw new Zend_Filter_Exception(sprintf('Invalid type "%s" provided to setPluginLoader()', $type)); + } + + return $this; + } + + /** + * Retrieve plugin loader for given type + * + * $type may be one of: + * - filter + * - validator + * + * If a plugin loader does not exist for the given type, defaults are + * created. + * + * @param string $type 'filter' or 'validate' + * @return Zend_Loader_PluginLoader_Interface + * @throws Zend_Filter_Exception on invalid type + */ + public function getPluginLoader($type) + { + $type = strtolower($type); + if (!isset($this->_loaders[$type])) { + switch ($type) { + case self::FILTER: + $prefixSegment = 'Zend_Filter_'; + $pathSegment = 'Zend/Filter/'; + break; + case self::VALIDATE: + $prefixSegment = 'Zend_Validate_'; + $pathSegment = 'Zend/Validate/'; + break; + default: + throw new Zend_Filter_Exception(sprintf('Invalid type "%s" provided to getPluginLoader()', $type)); + } + + $this->_loaders[$type] = new Zend_Loader_PluginLoader( + array($prefixSegment => $pathSegment) + ); + } + + return $this->_loaders[$type]; + } + + /** + * @return array + */ + public function getMessages() + { + $this->_process(); + return array_merge($this->_invalidMessages, $this->_missingFields); + } + + /** + * @return array + */ + public function getErrors() + { + $this->_process(); + return $this->_invalidErrors; + } + + /** + * @return array + */ + public function getInvalid() + { + $this->_process(); + return $this->_invalidMessages; + } + + /** + * @return array + */ + public function getMissing() + { + $this->_process(); + return $this->_missingFields; + } + + /** + * @return array + */ + public function getUnknown() + { + $this->_process(); + return $this->_unknownFields; + } + + /** + * @param string $fieldName OPTIONAL + * @return mixed + */ + public function getEscaped($fieldName = null) + { + $this->_process(); + $this->_getDefaultEscapeFilter(); + + if ($fieldName === null) { + return $this->_escapeRecursive($this->_validFields); + } + if (array_key_exists($fieldName, $this->_validFields)) { + return $this->_escapeRecursive($this->_validFields[$fieldName]); + } + return null; + } + + /** + * @param mixed $value + * @return mixed + */ + protected function _escapeRecursive($data) + { + if($data === null) { + return $data; + } + + if (!is_array($data)) { + return $this->_getDefaultEscapeFilter()->filter($data); + } + foreach ($data as &$element) { + $element = $this->_escapeRecursive($element); + } + return $data; + } + + /** + * @param string $fieldName OPTIONAL + * @return mixed + */ + public function getUnescaped($fieldName = null) + { + $this->_process(); + if ($fieldName === null) { + return $this->_validFields; + } + if (array_key_exists($fieldName, $this->_validFields)) { + return $this->_validFields[$fieldName]; + } + return null; + } + + /** + * @param string $fieldName + * @return mixed + */ + public function __get($fieldName) + { + return $this->getEscaped($fieldName); + } + + /** + * @return boolean + */ + public function hasInvalid() + { + $this->_process(); + return !(empty($this->_invalidMessages)); + } + + /** + * @return boolean + */ + public function hasMissing() + { + $this->_process(); + return !(empty($this->_missingFields)); + } + + /** + * @return boolean + */ + public function hasUnknown() + { + $this->_process(); + return !(empty($this->_unknownFields)); + } + + /** + * @return boolean + */ + public function hasValid() + { + $this->_process(); + return !(empty($this->_validFields)); + } + + /** + * @param string $fieldName + * @return boolean + */ + public function isValid($fieldName = null) + { + $this->_process(); + if ($fieldName === null) { + return !($this->hasMissing() || $this->hasInvalid()); + } + return array_key_exists($fieldName, $this->_validFields); + } + + /** + * @param string $fieldName + * @return boolean + */ + public function __isset($fieldName) + { + $this->_process(); + return isset($this->_validFields[$fieldName]); + } + + /** + * @return Zend_Filter_Input + * @throws Zend_Filter_Exception + */ + public function process() + { + $this->_process(); + if ($this->hasInvalid()) { + throw new Zend_Filter_Exception("Input has invalid fields"); + } + if ($this->hasMissing()) { + throw new Zend_Filter_Exception("Input has missing fields"); + } + + return $this; + } + + /** + * @param array $data + * @return Zend_Filter_Input + */ + public function setData(array $data) + { + $this->_data = $data; + + /** + * Reset to initial state + */ + $this->_validFields = array(); + $this->_invalidMessages = array(); + $this->_invalidErrors = array(); + $this->_missingFields = array(); + $this->_unknownFields = array(); + + $this->_processed = false; + + return $this; + } + + /** + * @param mixed $escapeFilter + * @return Zend_Filter_Interface + */ + public function setDefaultEscapeFilter($escapeFilter) + { + if (is_string($escapeFilter) || is_array($escapeFilter)) { + $escapeFilter = $this->_getFilter($escapeFilter); + } + if (!$escapeFilter instanceof Zend_Filter_Interface) { + throw new Zend_Filter_Exception('Escape filter specified does not implement Zend_Filter_Interface'); + } + $this->_defaultEscapeFilter = $escapeFilter; + return $escapeFilter; + } + + /** + * @param array $options + * @return Zend_Filter_Input + * @throws Zend_Filter_Exception if an unknown option is given + */ + public function setOptions(array $options) + { + foreach ($options as $option => $value) { + switch ($option) { + case self::ESCAPE_FILTER: + $this->setDefaultEscapeFilter($value); + break; + case self::INPUT_NAMESPACE: + $this->addNamespace($value); + break; + case self::VALIDATOR_NAMESPACE: + if(is_string($value)) { + $value = array($value); + } + + foreach($value AS $prefix) { + $this->addValidatorPrefixPath( + $prefix, + str_replace('_', DIRECTORY_SEPARATOR, $prefix) + ); + } + break; + case self::FILTER_NAMESPACE: + if(is_string($value)) { + $value = array($value); + } + + foreach($value AS $prefix) { + $this->addFilterPrefixPath( + $prefix, + str_replace('_', DIRECTORY_SEPARATOR, $prefix) + ); + } + break; + case self::ALLOW_EMPTY: + case self::BREAK_CHAIN: + case self::MISSING_MESSAGE: + case self::NOT_EMPTY_MESSAGE: + case self::PRESENCE: + $this->_defaults[$option] = $value; + break; + default: + throw new Zend_Filter_Exception("Unknown option '$option'"); + break; + } + } + + return $this; + } + + /** + * Set translation object + * + * @param Zend_Translate|Zend_Translate_Adapter|null $translator + * @return Zend_Filter_Input + */ + public function setTranslator($translator = null) + { + if ((null === $translator) || ($translator instanceof Zend_Translate_Adapter)) { + $this->_translator = $translator; + } elseif ($translator instanceof Zend_Translate) { + $this->_translator = $translator->getAdapter(); + } else { + throw new Zend_Validate_Exception('Invalid translator specified'); + } + + return $this; + } + + /** + * Return translation object + * + * @return Zend_Translate_Adapter|null + */ + public function getTranslator() + { + if ($this->translatorIsDisabled()) { + return null; + } + + if ($this->_translator === null) { + if (Zend_Registry::isRegistered('Zend_Translate')) { + $translator = Zend_Registry::get('Zend_Translate'); + if ($translator instanceof Zend_Translate_Adapter) { + return $translator; + } elseif ($translator instanceof Zend_Translate) { + return $translator->getAdapter(); + } + } + } + + return $this->_translator; + } + + /** + * Indicate whether or not translation should be disabled + * + * @param bool $flag + * @return Zend_Filter_Input + */ + public function setDisableTranslator($flag) + { + $this->_translatorDisabled = (bool) $flag; + return $this; + } + + /** + * Is translation disabled? + * + * @return bool + */ + public function translatorIsDisabled() + { + return $this->_translatorDisabled; + } + + /* + * Protected methods + */ + + /** + * @return void + */ + protected function _filter() + { + foreach ($this->_filterRules as $ruleName => &$filterRule) { + /** + * Make sure we have an array representing this filter chain. + * Don't typecast to (array) because it might be a Zend_Filter object + */ + if (!is_array($filterRule)) { + $filterRule = array($filterRule); + } + + /** + * Filters are indexed by integer, metacommands are indexed by string. + * Pick out the filters. + */ + $filterList = array(); + foreach ($filterRule as $key => $value) { + if (is_int($key)) { + $filterList[] = $value; + } + } + + /** + * Use defaults for filter metacommands. + */ + $filterRule[self::RULE] = $ruleName; + if (!isset($filterRule[self::FIELDS])) { + $filterRule[self::FIELDS] = $ruleName; + } + + /** + * Load all the filter classes and add them to the chain. + */ + if (!isset($filterRule[self::FILTER_CHAIN])) { + $filterRule[self::FILTER_CHAIN] = new Zend_Filter(); + foreach ($filterList as $filter) { + if (is_string($filter) || is_array($filter)) { + $filter = $this->_getFilter($filter); + } + $filterRule[self::FILTER_CHAIN]->addFilter($filter); + } + } + + /** + * If the ruleName is the special wildcard rule, + * then apply the filter chain to all input data. + * Else just process the field named by the rule. + */ + if ($ruleName == self::RULE_WILDCARD) { + foreach (array_keys($this->_data) as $field) { + $this->_filterRule(array_merge($filterRule, array(self::FIELDS => $field))); + } + } else { + $this->_filterRule($filterRule); + } + } + } + + /** + * @param array $filterRule + * @return void + */ + protected function _filterRule(array $filterRule) + { + $field = $filterRule[self::FIELDS]; + if (!array_key_exists($field, $this->_data)) { + return; + } + if (is_array($this->_data[$field])) { + foreach ($this->_data[$field] as $key => $value) { + $this->_data[$field][$key] = $filterRule[self::FILTER_CHAIN]->filter($value); + } + } else { + $this->_data[$field] = + $filterRule[self::FILTER_CHAIN]->filter($this->_data[$field]); + } + } + + /** + * @return Zend_Filter_Interface + */ + protected function _getDefaultEscapeFilter() + { + if ($this->_defaultEscapeFilter !== null) { + return $this->_defaultEscapeFilter; + } + return $this->setDefaultEscapeFilter($this->_defaults[self::ESCAPE_FILTER]); + } + + /** + * @param string $rule + * @param string $field + * @return string + */ + protected function _getMissingMessage($rule, $field) + { + $message = $this->_defaults[self::MISSING_MESSAGE]; + + if (null !== ($translator = $this->getTranslator())) { + if ($translator->isTranslated(self::MISSING_MESSAGE)) { + $message = $translator->translate(self::MISSING_MESSAGE); + } else { + $message = $translator->translate($message); + } + } + + $message = str_replace('%rule%', $rule, $message); + $message = str_replace('%field%', $field, $message); + return $message; + } + + /** + * @return string + */ + protected function _getNotEmptyMessage($rule, $field) + { + $message = $this->_defaults[self::NOT_EMPTY_MESSAGE]; + + if (null !== ($translator = $this->getTranslator())) { + if ($translator->isTranslated(self::NOT_EMPTY_MESSAGE)) { + $message = $translator->translate(self::NOT_EMPTY_MESSAGE); + } else { + $message = $translator->translate($message); + } + } + + $message = str_replace('%rule%', $rule, $message); + $message = str_replace('%field%', $field, $message); + return $message; + } + + /** + * @return void + */ + protected function _process() + { + if ($this->_processed === false) { + $this->_filter(); + $this->_validate(); + $this->_processed = true; + } + } + + /** + * @return void + */ + protected function _validate() + { + /** + * Special case: if there are no validators, treat all fields as valid. + */ + if (!$this->_validatorRules) { + $this->_validFields = $this->_data; + $this->_data = array(); + return; + } + + // remember the default not empty message in case we want to temporarily change it + $preserveDefaultNotEmptyMessage = $this->_defaults[self::NOT_EMPTY_MESSAGE]; + + foreach ($this->_validatorRules as $ruleName => &$validatorRule) { + /** + * Make sure we have an array representing this validator chain. + * Don't typecast to (array) because it might be a Zend_Validate object + */ + if (!is_array($validatorRule)) { + $validatorRule = array($validatorRule); + } + + /** + * Validators are indexed by integer, metacommands are indexed by string. + * Pick out the validators. + */ + $validatorList = array(); + foreach ($validatorRule as $key => $value) { + if (is_int($key)) { + $validatorList[$key] = $value; + } + } + + /** + * Use defaults for validation metacommands. + */ + $validatorRule[self::RULE] = $ruleName; + if (!isset($validatorRule[self::FIELDS])) { + $validatorRule[self::FIELDS] = $ruleName; + } + if (!isset($validatorRule[self::BREAK_CHAIN])) { + $validatorRule[self::BREAK_CHAIN] = $this->_defaults[self::BREAK_CHAIN]; + } + if (!isset($validatorRule[self::PRESENCE])) { + $validatorRule[self::PRESENCE] = $this->_defaults[self::PRESENCE]; + } + if (!isset($validatorRule[self::ALLOW_EMPTY])) { + $foundNotEmptyValidator = false; + + foreach ($validatorRule as $rule) { + if ($rule === 'NotEmpty') { + $foundNotEmptyValidator = true; + // field may not be empty, we are ready + break 1; + } + + if (is_array($rule)) { + $keys = array_keys($rule); + $classKey = array_shift($keys); + if (isset($rule[$classKey])) { + $ruleClass = $rule[$classKey]; + if ($ruleClass === 'NotEmpty') { + $foundNotEmptyValidator = true; + // field may not be empty, we are ready + break 1; + } + } + } + + // we must check if it is an object before using instanceof + if (!is_object($rule)) { + // it cannot be a NotEmpty validator, skip this one + continue; + } + + if($rule instanceof Zend_Validate_NotEmpty) { + $foundNotEmptyValidator = true; + // field may not be empty, we are ready + break 1; + } + } + + if (!$foundNotEmptyValidator) { + $validatorRule[self::ALLOW_EMPTY] = $this->_defaults[self::ALLOW_EMPTY]; + } else { + $validatorRule[self::ALLOW_EMPTY] = false; + } + } + + if (!isset($validatorRule[self::MESSAGES])) { + $validatorRule[self::MESSAGES] = array(); + } else if (!is_array($validatorRule[self::MESSAGES])) { + $validatorRule[self::MESSAGES] = array($validatorRule[self::MESSAGES]); + } else if (array_intersect_key($validatorList, $validatorRule[self::MESSAGES])) { + // this seems pointless... it just re-adds what it already has... + // I can disable all this and not a single unit test fails... + // There are now corresponding numeric keys in the validation rule messages array + // Treat it as a named messages list for all rule validators + $unifiedMessages = $validatorRule[self::MESSAGES]; + $validatorRule[self::MESSAGES] = array(); + + foreach ($validatorList as $key => $validator) { + if (array_key_exists($key, $unifiedMessages)) { + $validatorRule[self::MESSAGES][$key] = $unifiedMessages[$key]; + } + } + } + + /** + * Load all the validator classes and add them to the chain. + */ + if (!isset($validatorRule[self::VALIDATOR_CHAIN])) { + $validatorRule[self::VALIDATOR_CHAIN] = new Zend_Validate(); + + foreach ($validatorList as $key => $validator) { + if (is_string($validator) || is_array($validator)) { + $validator = $this->_getValidator($validator); + } + + if (isset($validatorRule[self::MESSAGES][$key])) { + $value = $validatorRule[self::MESSAGES][$key]; + if (is_array($value)) { + $validator->setMessages($value); + } else { + $validator->setMessage($value); + } + + if ($validator instanceof Zend_Validate_NotEmpty) { + /** we are changing the defaults here, this is alright if all subsequent validators are also a not empty + * validator, but it goes wrong if one of them is not AND is required!!! + * that is why we restore the default value at the end of this loop + */ + if (is_array($value)) { + $temp = $value; // keep the original value + $this->_defaults[self::NOT_EMPTY_MESSAGE] = array_pop($temp); + unset($temp); + } else { + $this->_defaults[self::NOT_EMPTY_MESSAGE] = $value; + } + } + } + + $validatorRule[self::VALIDATOR_CHAIN]->addValidator($validator, $validatorRule[self::BREAK_CHAIN]); + } + $validatorRule[self::VALIDATOR_CHAIN_COUNT] = count($validatorList); + } + + /** + * If the ruleName is the special wildcard rule, + * then apply the validator chain to all input data. + * Else just process the field named by the rule. + */ + if ($ruleName == self::RULE_WILDCARD) { + foreach (array_keys($this->_data) as $field) { + $this->_validateRule(array_merge($validatorRule, array(self::FIELDS => $field))); + } + } else { + $this->_validateRule($validatorRule); + } + + // reset the default not empty message + $this->_defaults[self::NOT_EMPTY_MESSAGE] = $preserveDefaultNotEmptyMessage; + } + + + + /** + * Unset fields in $_data that have been added to other arrays. + * We have to wait until all rules have been processed because + * a given field may be referenced by multiple rules. + */ + foreach (array_merge(array_keys($this->_missingFields), array_keys($this->_invalidMessages)) as $rule) { + foreach ((array) $this->_validatorRules[$rule][self::FIELDS] as $field) { + unset($this->_data[$field]); + } + } + foreach ($this->_validFields as $field => $value) { + unset($this->_data[$field]); + } + + /** + * Anything left over in $_data is an unknown field. + */ + $this->_unknownFields = $this->_data; + } + + /** + * @param array $validatorRule + * @return void + */ + protected function _validateRule(array $validatorRule) + { + /** + * Get one or more data values from input, and check for missing fields. + * Apply defaults if fields are missing. + */ + $data = array(); + foreach ((array) $validatorRule[self::FIELDS] as $key => $field) { + if (array_key_exists($field, $this->_data)) { + $data[$field] = $this->_data[$field]; + } else if (isset($validatorRule[self::DEFAULT_VALUE])) { + /** @todo according to this code default value can't be an array. It has to be reviewed */ + if (!is_array($validatorRule[self::DEFAULT_VALUE])) { + // Default value is a scalar + $data[$field] = $validatorRule[self::DEFAULT_VALUE]; + } else { + // Default value is an array. Search for corresponding key + if (isset($validatorRule[self::DEFAULT_VALUE][$key])) { + $data[$field] = $validatorRule[self::DEFAULT_VALUE][$key]; + } else if ($validatorRule[self::PRESENCE] == self::PRESENCE_REQUIRED) { + // Default value array is provided, but it doesn't have an entry for current field + // and presence is required + $this->_missingFields[$validatorRule[self::RULE]][] = + $this->_getMissingMessage($validatorRule[self::RULE], $field); + } + } + } else if ($validatorRule[self::PRESENCE] == self::PRESENCE_REQUIRED) { + $this->_missingFields[$validatorRule[self::RULE]][] = + $this->_getMissingMessage($validatorRule[self::RULE], $field); + } + } + + /** + * If any required fields are missing, break the loop. + */ + if (isset($this->_missingFields[$validatorRule[self::RULE]]) && count($this->_missingFields[$validatorRule[self::RULE]]) > 0) { + return; + } + + /** + * Evaluate the inputs against the validator chain. + */ + if (count((array) $validatorRule[self::FIELDS]) > 1) { + if (!$validatorRule[self::ALLOW_EMPTY]) { + $emptyFieldsFound = false; + $errorsList = array(); + $messages = array(); + + foreach ($data as $fieldKey => $field) { + // if there is no Zend_Validate_NotEmpty instance in the rules, we will use the default + if (!($notEmptyValidator = $this->_getNotEmptyValidatorInstance($validatorRule))) { + $notEmptyValidator = $this->_getValidator('NotEmpty'); + $notEmptyValidator->setMessage($this->_getNotEmptyMessage($validatorRule[self::RULE], $fieldKey)); + } + + if (!$notEmptyValidator->isValid($field)) { + foreach ($notEmptyValidator->getMessages() as $messageKey => $message) { + if (!isset($messages[$messageKey])) { + $messages[$messageKey] = $message; + } else { + $messages[] = $message; + } + } + $errorsList[] = $notEmptyValidator->getErrors(); + $emptyFieldsFound = true; + } + } + + if ($emptyFieldsFound) { + $this->_invalidMessages[$validatorRule[self::RULE]] = $messages; + $this->_invalidErrors[$validatorRule[self::RULE]] = array_unique(call_user_func_array('array_merge', $errorsList)); + return; + } + } + + if (!$validatorRule[self::VALIDATOR_CHAIN]->isValid($data)) { + $this->_invalidMessages[$validatorRule[self::RULE]] = $validatorRule[self::VALIDATOR_CHAIN]->getMessages(); + $this->_invalidErrors[$validatorRule[self::RULE]] = $validatorRule[self::VALIDATOR_CHAIN]->getErrors(); + return; + } + } else if (count($data) > 0) { + // $data is actually a one element array + $fieldNames = array_keys($data); + $fieldName = reset($fieldNames); + $field = reset($data); + + $failed = false; + if (!is_array($field)) { + $field = array($field); + } + + // if there is no Zend_Validate_NotEmpty instance in the rules, we will use the default + if (!($notEmptyValidator = $this->_getNotEmptyValidatorInstance($validatorRule))) { + $notEmptyValidator = $this->_getValidator('NotEmpty'); + $notEmptyValidator->setMessage($this->_getNotEmptyMessage($validatorRule[self::RULE], $fieldName)); + } + + if ($validatorRule[self::ALLOW_EMPTY]) { + $validatorChain = $validatorRule[self::VALIDATOR_CHAIN]; + } else { + $validatorChain = new Zend_Validate(); + $validatorChain->addValidator($notEmptyValidator, true /* Always break on failure */); + $validatorChain->addValidator($validatorRule[self::VALIDATOR_CHAIN]); + } + + foreach ($field as $key => $value) { + if ($validatorRule[self::ALLOW_EMPTY] && !$notEmptyValidator->isValid($value)) { + // Field is empty AND it's allowed. Do nothing. + continue; + } + + if (!$validatorChain->isValid($value)) { + if (isset($this->_invalidMessages[$validatorRule[self::RULE]])) { + $collectedMessages = $this->_invalidMessages[$validatorRule[self::RULE]]; + } else { + $collectedMessages = array(); + } + + foreach ($validatorChain->getMessages() as $messageKey => $message) { + if (!isset($collectedMessages[$messageKey])) { + $collectedMessages[$messageKey] = $message; + } else { + $collectedMessages[] = $message; + } + } + + $this->_invalidMessages[$validatorRule[self::RULE]] = $collectedMessages; + if (isset($this->_invalidErrors[$validatorRule[self::RULE]])) { + $this->_invalidErrors[$validatorRule[self::RULE]] = array_merge($this->_invalidErrors[$validatorRule[self::RULE]], + $validatorChain->getErrors()); + } else { + $this->_invalidErrors[$validatorRule[self::RULE]] = $validatorChain->getErrors(); + } + unset($this->_validFields[$fieldName]); + $failed = true; + if ($validatorRule[self::BREAK_CHAIN]) { + return; + } + } + } + if ($failed) { + return; + } + } + + /** + * If we got this far, the inputs for this rule pass validation. + */ + foreach ((array) $validatorRule[self::FIELDS] as $field) { + if (array_key_exists($field, $data)) { + $this->_validFields[$field] = $data[$field]; + } + } + } + + /** + * Check a validatorRule for the presence of a NotEmpty validator instance. + * The purpose is to preserve things like a custom message, that may have been + * set on the validator outside Zend_Filter_Input. + * @param array $validatorRule + * @return mixed false if none is found, Zend_Validate_NotEmpty instance if found + */ + protected function _getNotEmptyValidatorInstance($validatorRule) { + foreach ($validatorRule as $rule => $value) { + if (is_object($value) and $value instanceof Zend_Validate_NotEmpty) { + return $value; + } + } + + return false; + } + + /** + * @param mixed $classBaseName + * @return Zend_Filter_Interface + */ + protected function _getFilter($classBaseName) + { + return $this->_getFilterOrValidator(self::FILTER, $classBaseName); + } + + /** + * @param mixed $classBaseName + * @return Zend_Validate_Interface + */ + protected function _getValidator($classBaseName) + { + return $this->_getFilterOrValidator(self::VALIDATE, $classBaseName); + } + + /** + * @param string $type + * @param mixed $classBaseName + * @return Zend_Filter_Interface|Zend_Validate_Interface + * @throws Zend_Filter_Exception + */ + protected function _getFilterOrValidator($type, $classBaseName) + { + $args = array(); + + if (is_array($classBaseName)) { + $args = $classBaseName; + $classBaseName = array_shift($args); + } + + $interfaceName = 'Zend_' . ucfirst($type) . '_Interface'; + $className = $this->getPluginLoader($type)->load(ucfirst($classBaseName)); + + $class = new ReflectionClass($className); + + if (!$class->implementsInterface($interfaceName)) { + throw new Zend_Filter_Exception("Class '$className' based on basename '$classBaseName' must implement the '$interfaceName' interface"); + } + + if ($class->hasMethod('__construct')) { + $object = $class->newInstanceArgs(array_values($args)); + } else { + $object = $class->newInstance(); + } + + return $object; + } + +} diff --git a/library/vendor/Zend/Filter/Int.php b/library/vendor/Zend/Filter/Int.php new file mode 100644 index 0000000..ed7f9e8 --- /dev/null +++ b/library/vendor/Zend/Filter/Int.php @@ -0,0 +1,49 @@ + null, + 'date_format' => null, + 'precision' => null + ); + + /** + * Class constructor + * + * @param string|Zend_Locale $locale (Optional) Locale to set + */ + public function __construct($options = null) + { + if ($options instanceof Zend_Config) { + $options = $options->toArray(); + } + + if (null !== $options) { + $this->setOptions($options); + } + } + + /** + * Returns the set options + * + * @return array + */ + public function getOptions() + { + return $this->_options; + } + + /** + * Sets options to use + * + * @param array $options (Optional) Options to use + * @return Zend_Filter_LocalizedToNormalized + */ + public function setOptions(array $options = null) + { + $this->_options = $options + $this->_options; + return $this; + } + + /** + * Defined by Zend_Filter_Interface + * + * Normalizes the given input + * + * @param string $value Value to normalized + * @return string|array The normalized value + */ + public function filter($value) + { + if (Zend_Locale_Format::isNumber($value, $this->_options)) { + return Zend_Locale_Format::getNumber($value, $this->_options); + } else if (($this->_options['date_format'] === null) && (strpos($value, ':') !== false)) { + // Special case, no date format specified, detect time input + return Zend_Locale_Format::getTime($value, $this->_options); + } else if (Zend_Locale_Format::checkDateFormat($value, $this->_options)) { + // Detect date or time input + return Zend_Locale_Format::getDate($value, $this->_options); + } + + return $value; + } +} diff --git a/library/vendor/Zend/Filter/NormalizedToLocalized.php b/library/vendor/Zend/Filter/NormalizedToLocalized.php new file mode 100644 index 0000000..54224ca --- /dev/null +++ b/library/vendor/Zend/Filter/NormalizedToLocalized.php @@ -0,0 +1,108 @@ + null, + 'date_format' => null, + 'precision' => null + ); + + /** + * Class constructor + * + * @param string|Zend_Locale $locale (Optional) Locale to set + */ + public function __construct($options = null) + { + if ($options instanceof Zend_Config) { + $options = $options->toArray(); + } + + if (null !== $options) { + $this->setOptions($options); + } + } + + /** + * Returns the set options + * + * @return array + */ + public function getOptions() + { + return $this->_options; + } + + /** + * Sets options to use + * + * @param array $options (Optional) Options to use + * @return Zend_Filter_LocalizedToNormalized + */ + public function setOptions(array $options = null) + { + $this->_options = $options + $this->_options; + return $this; + } + + /** + * Defined by Zend_Filter_Interface + * + * Normalizes the given input + * + * @param string $value Value to normalized + * @return string|array The normalized value + */ + public function filter($value) + { + if (is_array($value)) { + $date = new Zend_Date($value, $this->_options['locale']); + return $date->toString($this->_options['date_format']); + } else if ($this->_options['precision'] === 0) { + return Zend_Locale_Format::toInteger($value, $this->_options); + } else if ($this->_options['precision'] === null) { + return Zend_Locale_Format::toFloat($value, $this->_options); + } + + return Zend_Locale_Format::toNumber($value, $this->_options); + } +} diff --git a/library/vendor/Zend/Filter/Null.php b/library/vendor/Zend/Filter/Null.php new file mode 100644 index 0000000..14a79f2 --- /dev/null +++ b/library/vendor/Zend/Filter/Null.php @@ -0,0 +1,181 @@ + 'boolean', + self::INTEGER => 'integer', + self::EMPTY_ARRAY => 'array', + self::STRING => 'string', + self::ZERO => 'zero', + self::ALL => 'all' + ); + + /** + * Internal type to detect + * + * @var integer + */ + protected $_type = self::ALL; + + /** + * Constructor + * + * @param string|array|Zend_Config $options OPTIONAL + */ + public function __construct($options = null) + { + if ($options instanceof Zend_Config) { + $options = $options->toArray(); + } else if (!is_array($options)) { + $options = func_get_args(); + $temp = array(); + if (!empty($options)) { + $temp = array_shift($options); + } + $options = $temp; + } else if (is_array($options) && array_key_exists('type', $options)) { + $options = $options['type']; + } + + if (!empty($options)) { + $this->setType($options); + } + } + + /** + * Returns the set null types + * + * @return array + */ + public function getType() + { + return $this->_type; + } + + /** + * Set the null types + * + * @param integer|array $type + * @throws Zend_Filter_Exception + * @return Zend_Filter_Null + */ + public function setType($type = null) + { + if (is_array($type)) { + $detected = 0; + foreach($type as $value) { + if (is_int($value)) { + $detected += $value; + } else if (in_array($value, $this->_constants)) { + $detected += array_search($value, $this->_constants); + } + } + + $type = $detected; + } else if (is_string($type)) { + if (in_array($type, $this->_constants)) { + $type = array_search($type, $this->_constants); + } + } + + if (!is_int($type) || ($type < 0) || ($type > self::ALL)) { + throw new Zend_Filter_Exception('Unknown type'); + } + + $this->_type = $type; + return $this; + } + + /** + * Defined by Zend_Filter_Interface + * + * Returns null representation of $value, if value is empty and matches + * types that should be considered null. + * + * @param string $value + * @return string + */ + public function filter($value) + { + $type = $this->getType(); + + // STRING ZERO ('0') + if ($type >= self::ZERO) { + $type -= self::ZERO; + if (is_string($value) && ($value == '0')) { + return null; + } + } + + // STRING ('') + if ($type >= self::STRING) { + $type -= self::STRING; + if (is_string($value) && ($value == '')) { + return null; + } + } + + // EMPTY_ARRAY (array()) + if ($type >= self::EMPTY_ARRAY) { + $type -= self::EMPTY_ARRAY; + if (is_array($value) && ($value == array())) { + return null; + } + } + + // INTEGER (0) + if ($type >= self::INTEGER) { + $type -= self::INTEGER; + if (is_int($value) && ($value == 0)) { + return null; + } + } + + // BOOLEAN (false) + if ($type >= self::BOOLEAN) { + $type -= self::BOOLEAN; + if (is_bool($value) && ($value == false)) { + return null; + } + } + + return $value; + } +} diff --git a/library/vendor/Zend/Filter/PregReplace.php b/library/vendor/Zend/Filter/PregReplace.php new file mode 100644 index 0000000..a4714d6 --- /dev/null +++ b/library/vendor/Zend/Filter/PregReplace.php @@ -0,0 +1,172 @@ + matching pattern + * 'replace' => replace with this + * + * @param string|array $options + * @return void + */ + public function __construct($options = null) + { + if ($options instanceof Zend_Config) { + $options = $options->toArray(); + } else if (!is_array($options)) { + $options = func_get_args(); + $temp = array(); + if (!empty($options)) { + $temp['match'] = array_shift($options); + } + + if (!empty($options)) { + $temp['replace'] = array_shift($options); + } + + $options = $temp; + } + + if (array_key_exists('match', $options)) { + $this->setMatchPattern($options['match']); + } + + if (array_key_exists('replace', $options)) { + $this->setReplacement($options['replace']); + } + } + + /** + * Set the match pattern for the regex being called within filter() + * + * @param mixed $match - same as the first argument of preg_replace + * @return Zend_Filter_PregReplace + */ + public function setMatchPattern($match) + { + $this->_matchPattern = $match; + return $this; + } + + /** + * Get currently set match pattern + * + * @return string + */ + public function getMatchPattern() + { + return $this->_matchPattern; + } + + /** + * Set the Replacement pattern/string for the preg_replace called in filter + * + * @param mixed $replacement - same as the second argument of preg_replace + * @return Zend_Filter_PregReplace + */ + public function setReplacement($replacement) + { + $this->_replacement = $replacement; + return $this; + } + + /** + * Get currently set replacement value + * + * @return string + */ + public function getReplacement() + { + return $this->_replacement; + } + + /** + * Perform regexp replacement as filter + * + * @param string $value + * @return string + */ + public function filter($value) + { + if ($this->_matchPattern == null) { + throw new Zend_Filter_Exception(get_class($this) . ' does not have a valid MatchPattern set.'); + } + + return preg_replace($this->_matchPattern, $this->_replacement, $value); + } + +} diff --git a/library/vendor/Zend/Filter/RealPath.php b/library/vendor/Zend/Filter/RealPath.php new file mode 100644 index 0000000..3cc3c99 --- /dev/null +++ b/library/vendor/Zend/Filter/RealPath.php @@ -0,0 +1,133 @@ +setExists($options); + } + + /** + * Returns true if the filtered path must exist + * + * @return boolean + */ + public function getExists() + { + return $this->_exists; + } + + /** + * Sets if the path has to exist + * TRUE when the path must exist + * FALSE when not existing paths can be given + * + * @param boolean|Zend_Config $exists Path must exist + * @return Zend_Filter_RealPath + */ + public function setExists($exists) + { + if ($exists instanceof Zend_Config) { + $exists = $exists->toArray(); + } + + if (is_array($exists)) { + if (isset($exists['exists'])) { + $exists = (boolean) $exists['exists']; + } + } + + $this->_exists = (boolean) $exists; + return $this; + } + + /** + * Defined by Zend_Filter_Interface + * + * Returns realpath($value) + * + * @param string $value + * @return string + */ + public function filter($value) + { + $path = (string) $value; + if ($this->_exists) { + return realpath($path); + } + + $realpath = @realpath($path); + if ($realpath) { + return $realpath; + } + + $drive = ''; + if (substr(PHP_OS, 0, 3) == 'WIN') { + $path = preg_replace('/[\\\\\/]/', DIRECTORY_SEPARATOR, $path); + if (preg_match('/([a-zA-Z]\:)(.*)/', $path, $matches)) { + list($fullMatch, $drive, $path) = $matches; + } else { + $cwd = getcwd(); + $drive = substr($cwd, 0, 2); + if (substr($path, 0, 1) != DIRECTORY_SEPARATOR) { + $path = substr($cwd, 3) . DIRECTORY_SEPARATOR . $path; + } + } + } elseif (substr($path, 0, 1) != DIRECTORY_SEPARATOR) { + $path = getcwd() . DIRECTORY_SEPARATOR . $path; + } + + $stack = array(); + $parts = explode(DIRECTORY_SEPARATOR, $path); + foreach ($parts as $dir) { + if (strlen($dir) && $dir !== '.') { + if ($dir == '..') { + array_pop($stack); + } else { + array_push($stack, $dir); + } + } + } + + return $drive . DIRECTORY_SEPARATOR . implode(DIRECTORY_SEPARATOR, $stack); + } +} diff --git a/library/vendor/Zend/Filter/StringToLower.php b/library/vendor/Zend/Filter/StringToLower.php new file mode 100644 index 0000000..c91072b --- /dev/null +++ b/library/vendor/Zend/Filter/StringToLower.php @@ -0,0 +1,118 @@ +toArray(); + } else if (!is_array($options)) { + $options = func_get_args(); + $temp = array(); + if (!empty($options)) { + $temp['encoding'] = array_shift($options); + } + $options = $temp; + } + + if (!array_key_exists('encoding', $options) && function_exists('mb_internal_encoding')) { + $options['encoding'] = mb_internal_encoding(); + } + + if (array_key_exists('encoding', $options)) { + $this->setEncoding($options['encoding']); + } + } + + /** + * Returns the set encoding + * + * @return string + */ + public function getEncoding() + { + return $this->_encoding; + } + + /** + * Set the input encoding for the given string + * + * @param string $encoding + * @return Zend_Filter_StringToLower Provides a fluent interface + * @throws Zend_Filter_Exception + */ + public function setEncoding($encoding = null) + { + if ($encoding !== null) { + if (!function_exists('mb_strtolower')) { + throw new Zend_Filter_Exception('mbstring is required for this feature'); + } + + $encoding = (string) $encoding; + if (!in_array(strtolower($encoding), array_map('strtolower', mb_list_encodings()))) { + throw new Zend_Filter_Exception("The given encoding '$encoding' is not supported by mbstring"); + } + } + + $this->_encoding = $encoding; + return $this; + } + + /** + * Defined by Zend_Filter_Interface + * + * Returns the string $value, converting characters to lowercase as necessary + * + * @param string $value + * @return string + */ + public function filter($value) + { + if ($this->_encoding !== null) { + return mb_strtolower((string) $value, $this->_encoding); + } + + return strtolower((string) $value); + } +} diff --git a/library/vendor/Zend/Filter/StringToUpper.php b/library/vendor/Zend/Filter/StringToUpper.php new file mode 100644 index 0000000..1276c8e --- /dev/null +++ b/library/vendor/Zend/Filter/StringToUpper.php @@ -0,0 +1,118 @@ +toArray(); + } else if (!is_array($options)) { + $options = func_get_args(); + $temp = array(); + if (!empty($options)) { + $temp['encoding'] = array_shift($options); + } + $options = $temp; + } + + if (!array_key_exists('encoding', $options) && function_exists('mb_internal_encoding')) { + $options['encoding'] = mb_internal_encoding(); + } + + if (array_key_exists('encoding', $options)) { + $this->setEncoding($options['encoding']); + } + } + + /** + * Returns the set encoding + * + * @return string + */ + public function getEncoding() + { + return $this->_encoding; + } + + /** + * Set the input encoding for the given string + * + * @param string $encoding + * @return Zend_Filter_StringToUpper Provides a fluent interface + * @throws Zend_Filter_Exception + */ + public function setEncoding($encoding = null) + { + if ($encoding !== null) { + if (!function_exists('mb_strtoupper')) { + throw new Zend_Filter_Exception('mbstring is required for this feature'); + } + + $encoding = (string) $encoding; + if (!in_array(strtolower($encoding), array_map('strtolower', mb_list_encodings()))) { + throw new Zend_Filter_Exception("The given encoding '$encoding' is not supported by mbstring"); + } + } + + $this->_encoding = $encoding; + return $this; + } + + /** + * Defined by Zend_Filter_Interface + * + * Returns the string $value, converting characters to uppercase as necessary + * + * @param string $value + * @return string + */ + public function filter($value) + { + if ($this->_encoding) { + return mb_strtoupper((string) $value, $this->_encoding); + } + + return strtoupper((string) $value); + } +} diff --git a/library/vendor/Zend/Filter/StringTrim.php b/library/vendor/Zend/Filter/StringTrim.php new file mode 100644 index 0000000..8006ec9 --- /dev/null +++ b/library/vendor/Zend/Filter/StringTrim.php @@ -0,0 +1,123 @@ +toArray(); + } else if (!is_array($options)) { + $options = func_get_args(); + $temp['charlist'] = array_shift($options); + $options = $temp; + } + + if (array_key_exists('charlist', $options)) { + $this->setCharList($options['charlist']); + } + } + + /** + * Returns the charList option + * + * @return string|null + */ + public function getCharList() + { + return $this->_charList; + } + + /** + * Sets the charList option + * + * @param string|null $charList + * @return Zend_Filter_StringTrim Provides a fluent interface + */ + public function setCharList($charList) + { + $this->_charList = $charList; + return $this; + } + + /** + * Defined by Zend_Filter_Interface + * + * Returns the string $value with characters stripped from the beginning and end + * + * @param string $value + * @return string + */ + public function filter($value) + { + if (null === $this->_charList) { + return $this->_unicodeTrim((string) $value); + } else { + return $this->_unicodeTrim((string) $value, $this->_charList); + } + } + + /** + * Unicode aware trim method + * Fixes a PHP problem + * + * @param string $value + * @param string $charlist + * @return string + */ + protected function _unicodeTrim($value, $charlist = '\\\\s') + { + $chars = preg_replace( + array( '/[\^\-\]\\\]/S', '/\\\{4}/S', '/\//'), + array( '\\\\\\0', '\\', '\/' ), + $charlist + ); + + $pattern = '^[' . $chars . ']*|[' . $chars . ']*$'; + return preg_replace("/$pattern/sSD", '', $value); + } +} diff --git a/library/vendor/Zend/Filter/StripNewlines.php b/library/vendor/Zend/Filter/StripNewlines.php new file mode 100644 index 0000000..91f6342 --- /dev/null +++ b/library/vendor/Zend/Filter/StripNewlines.php @@ -0,0 +1,47 @@ + Tags which are allowed + * 'allowAttribs' => Attributes which are allowed + * 'allowComments' => Are comments allowed ? + * + * @param string|array|Zend_Config $options + * @return void + */ + public function __construct($options = null) + { + if ($options instanceof Zend_Config) { + $options = $options->toArray(); + } else if ((!is_array($options)) || (is_array($options) && !array_key_exists('allowTags', $options) && + !array_key_exists('allowAttribs', $options) && !array_key_exists('allowComments', $options))) { + $options = func_get_args(); + $temp['allowTags'] = array_shift($options); + if (!empty($options)) { + $temp['allowAttribs'] = array_shift($options); + } + + if (!empty($options)) { + $temp['allowComments'] = array_shift($options); + } + + $options = $temp; + } + + if (array_key_exists('allowTags', $options)) { + $this->setTagsAllowed($options['allowTags']); + } + + if (array_key_exists('allowAttribs', $options)) { + $this->setAttributesAllowed($options['allowAttribs']); + } + + if (array_key_exists('allowComments', $options)) { + $this->setCommentsAllowed($options['allowComments']); + } + } + + /** + * Returns the commentsAllowed option + * + * This setting is now deprecated and ignored internally. + * + * @deprecated + * @return bool + */ + public function getCommentsAllowed() + { + return $this->commentsAllowed; + } + + /** + * Sets the commentsAllowed option + * + * This setting is now deprecated and ignored internally. + * + * @deprecated + * @param boolean $commentsAllowed + * @return Zend_Filter_StripTags Provides a fluent interface + */ + public function setCommentsAllowed($commentsAllowed) + { + $this->commentsAllowed = (boolean) $commentsAllowed; + return $this; + } + + /** + * Returns the tagsAllowed option + * + * @return array + */ + public function getTagsAllowed() + { + return $this->_tagsAllowed; + } + + /** + * Sets the tagsAllowed option + * + * @param array|string $tagsAllowed + * @return Zend_Filter_StripTags Provides a fluent interface + */ + public function setTagsAllowed($tagsAllowed) + { + if (!is_array($tagsAllowed)) { + $tagsAllowed = array($tagsAllowed); + } + + foreach ($tagsAllowed as $index => $element) { + // If the tag was provided without attributes + if (is_int($index) && is_string($element)) { + // Canonicalize the tag name + $tagName = strtolower($element); + // Store the tag as allowed with no attributes + $this->_tagsAllowed[$tagName] = array(); + } + // Otherwise, if a tag was provided with attributes + else if (is_string($index) && (is_array($element) || is_string($element))) { + // Canonicalize the tag name + $tagName = strtolower($index); + // Canonicalize the attributes + if (is_string($element)) { + $element = array($element); + } + // Store the tag as allowed with the provided attributes + $this->_tagsAllowed[$tagName] = array(); + foreach ($element as $attribute) { + if (is_string($attribute)) { + // Canonicalize the attribute name + $attributeName = strtolower($attribute); + $this->_tagsAllowed[$tagName][$attributeName] = null; + } + } + } + } + + return $this; + } + + /** + * Returns the attributesAllowed option + * + * @return array + */ + public function getAttributesAllowed() + { + return $this->_attributesAllowed; + } + + /** + * Sets the attributesAllowed option + * + * @param array|string $attributesAllowed + * @return Zend_Filter_StripTags Provides a fluent interface + */ + public function setAttributesAllowed($attributesAllowed) + { + if (!is_array($attributesAllowed)) { + $attributesAllowed = array($attributesAllowed); + } + + // Store each attribute as allowed + foreach ($attributesAllowed as $attribute) { + if (is_string($attribute)) { + // Canonicalize the attribute name + $attributeName = strtolower($attribute); + $this->_attributesAllowed[$attributeName] = null; + } + } + + return $this; + } + + /** + * Defined by Zend_Filter_Interface + * + * @todo improve docblock descriptions + * + * @param string $value + * @return string + */ + public function filter($value) + { + $value = (string) $value; + + // Strip HTML comments first + while (strpos($value, '' . $link . ''; + } + + return $link; + } + + /** + * Render link elements as string + * + * @param string|int $indent + * @return string + */ + public function toString($indent = null) + { + $indent = (null !== $indent) + ? $this->getWhitespace($indent) + : $this->getIndent(); + + $items = array(); + $this->getContainer()->ksort(); + foreach ($this as $item) { + $items[] = $this->itemToString($item); + } + + return $indent . implode($this->_escape($this->getSeparator()) . $indent, $items); + } + + /** + * Create data item for stack + * + * @param array $attributes + * @return stdClass + */ + public function createData(array $attributes) + { + $data = (object) $attributes; + return $data; + } + + /** + * Create item for stylesheet link item + * + * @param array $args + * @return stdClass|false Returns fals if stylesheet is a duplicate + */ + public function createDataStylesheet(array $args) + { + $rel = 'stylesheet'; + $type = 'text/css'; + $media = 'screen'; + $conditionalStylesheet = false; + $href = array_shift($args); + + if ($this->_isDuplicateStylesheet($href)) { + return false; + } + + if (0 < count($args)) { + $media = array_shift($args); + if(is_array($media)) { + $media = implode(',', $media); + } else { + $media = (string) $media; + } + } + if (0 < count($args)) { + $conditionalStylesheet = array_shift($args); + if(!empty($conditionalStylesheet) && is_string($conditionalStylesheet)) { + $conditionalStylesheet = (string) $conditionalStylesheet; + } else { + $conditionalStylesheet = null; + } + } + + if(0 < count($args) && is_array($args[0])) { + $extras = array_shift($args); + $extras = (array) $extras; + } + + $attributes = compact('rel', 'type', 'href', 'media', 'conditionalStylesheet', 'extras'); + return $this->createData($this->_applyExtras($attributes)); + } + + /** + * Is the linked stylesheet a duplicate? + * + * @param string $uri + * @return bool + */ + protected function _isDuplicateStylesheet($uri) + { + foreach ($this->getContainer() as $item) { + if (($item->rel == 'stylesheet') && ($item->href == $uri)) { + return true; + } + } + return false; + } + + /** + * Create item for alternate link item + * + * @param array $args + * @return stdClass + */ + public function createDataAlternate(array $args) + { + if (3 > count($args)) { + $e = new Zend_View_Exception(sprintf('Alternate tags require 3 arguments; %s provided', count($args))); + $e->setView($this->view); + throw $e; + } + + $rel = 'alternate'; + $href = array_shift($args); + $type = array_shift($args); + $title = array_shift($args); + + if(0 < count($args) && is_array($args[0])) { + $extras = array_shift($args); + $extras = (array) $extras; + + if(isset($extras['media']) && is_array($extras['media'])) { + $extras['media'] = implode(',', $extras['media']); + } + } + + $href = (string) $href; + $type = (string) $type; + $title = (string) $title; + + $attributes = compact('rel', 'href', 'type', 'title', 'extras'); + return $this->createData($this->_applyExtras($attributes)); + } + + /** + * Apply any overrides specified in the 'extras' array + * @param array $attributes + * @return array + */ + protected function _applyExtras($attributes) + { + if (isset($attributes['extras'])) { + foreach ($attributes['extras'] as $eKey=>$eVal) { + if (isset($attributes[$eKey])) { + $attributes[$eKey] = $eVal; + unset($attributes['extras'][$eKey]); + } + } + } + return $attributes; + } +} diff --git a/library/vendor/Zend/View/Helper/HeadMeta.php b/library/vendor/Zend/View/Helper/HeadMeta.php new file mode 100644 index 0000000..88cd3a7 --- /dev/null +++ b/library/vendor/Zend/View/Helper/HeadMeta.php @@ -0,0 +1,440 @@ +setSeparator(PHP_EOL); + } + + /** + * Retrieve object instance; optionally add meta tag + * + * @param string $content + * @param string $keyValue + * @param string $keyType + * @param array $modifiers + * @param string $placement + * @return Zend_View_Helper_HeadMeta + */ + public function headMeta($content = null, $keyValue = null, $keyType = 'name', $modifiers = array(), $placement = Zend_View_Helper_Placeholder_Container_Abstract::APPEND) + { + if ((null !== $content) && (null !== $keyValue)) { + $item = $this->createData($keyType, $keyValue, $content, $modifiers); + $action = strtolower($placement); + switch ($action) { + case 'append': + case 'prepend': + case 'set': + $this->$action($item); + break; + default: + $this->append($item); + break; + } + } + + return $this; + } + + protected function _normalizeType($type) + { + switch ($type) { + case 'Name': + return 'name'; + case 'HttpEquiv': + return 'http-equiv'; + case 'Property': + return 'property'; + default: + $e = new Zend_View_Exception(sprintf('Invalid type "%s" passed to _normalizeType', $type)); + $e->setView($this->view); + throw $e; + } + } + + /** + * Overload method access + * + * Allows the following 'virtual' methods: + * - appendName($keyValue, $content, $modifiers = array()) + * - offsetGetName($index, $keyValue, $content, $modifers = array()) + * - prependName($keyValue, $content, $modifiers = array()) + * - setName($keyValue, $content, $modifiers = array()) + * - appendHttpEquiv($keyValue, $content, $modifiers = array()) + * - offsetGetHttpEquiv($index, $keyValue, $content, $modifers = array()) + * - prependHttpEquiv($keyValue, $content, $modifiers = array()) + * - setHttpEquiv($keyValue, $content, $modifiers = array()) + * - appendProperty($keyValue, $content, $modifiers = array()) + * - offsetGetProperty($index, $keyValue, $content, $modifiers = array()) + * - prependProperty($keyValue, $content, $modifiers = array()) + * - setProperty($keyValue, $content, $modifiers = array()) + * + * @param string $method + * @param array $args + * @return Zend_View_Helper_HeadMeta + */ + public function __call($method, $args) + { + if (preg_match('/^(?Pset|(pre|ap)pend|offsetSet)(?PName|HttpEquiv|Property)$/', $method, $matches)) { + $action = $matches['action']; + $type = $this->_normalizeType($matches['type']); + $argc = count($args); + $index = null; + + if ('offsetSet' == $action) { + if (0 < $argc) { + $index = array_shift($args); + --$argc; + } + } + + if (2 > $argc) { + $e = new Zend_View_Exception('Too few arguments provided; requires key value, and content'); + $e->setView($this->view); + throw $e; + } + + if (3 > $argc) { + $args[] = array(); + } + + $item = $this->createData($type, $args[0], $args[1], $args[2]); + + if ('offsetSet' == $action) { + $this->offsetSet($index, $item); + return $this; + } + + $this->$action($item); + return $this; + } + + return parent::__call($method, $args); + } + + /** + * Create an HTML5-style meta charset tag. Something like + * + * Not valid in a non-HTML5 doctype + * + * @param string $charset + * @return Zend_View_Helper_HeadMeta Provides a fluent interface + */ + public function setCharset($charset) + { + $item = new stdClass; + $item->type = 'charset'; + $item->charset = $charset; + $item->content = null; + $item->modifiers = array(); + $this->set($item); + return $this; + } + + /** + * Determine if item is valid + * + * @param mixed $item + * @return boolean + */ + protected function _isValid($item) + { + if ((!$item instanceof stdClass) + || !isset($item->type) + || !isset($item->modifiers)) + { + return false; + } + + $isHtml5 = is_null($this->view) ? false : $this->view->doctype()->isHtml5(); + + if (!isset($item->content) + && (! $isHtml5 || (! $isHtml5 && $item->type !== 'charset'))) { + return false; + } + + // is only supported with doctype RDFa + if ( !is_null($this->view) && !$this->view->doctype()->isRdfa() + && $item->type === 'property') { + return false; + } + + return true; + } + + /** + * Append + * + * @param string $value + * @return void + * @throws Zend_View_Exception + */ + public function append($value) + { + if (!$this->_isValid($value)) { + $e = new Zend_View_Exception('Invalid value passed to append; please use appendMeta()'); + $e->setView($this->view); + throw $e; + } + + return $this->getContainer()->append($value); + } + + /** + * OffsetSet + * + * @param string|int $index + * @param string $value + * @return void + * @throws Zend_View_Exception + */ + public function offsetSet($index, $value): void + { + if (!$this->_isValid($value)) { + $e = new Zend_View_Exception('Invalid value passed to offsetSet; please use offsetSetName() or offsetSetHttpEquiv()'); + $e->setView($this->view); + throw $e; + } + + $this->getContainer()->offsetSet($index, $value); + } + + /** + * OffsetUnset + * + * @param string|int $index + * @return void + * @throws Zend_View_Exception + */ + public function offsetUnset($index): void + { + if (!in_array($index, $this->getContainer()->getKeys())) { + $e = new Zend_View_Exception('Invalid index passed to offsetUnset()'); + $e->setView($this->view); + throw $e; + } + + $this->getContainer()->offsetUnset($index); + } + + /** + * Prepend + * + * @param string $value + * @return void + * @throws Zend_View_Exception + */ + public function prepend($value) + { + if (!$this->_isValid($value)) { + $e = new Zend_View_Exception('Invalid value passed to prepend; please use prependMeta()'); + $e->setView($this->view); + throw $e; + } + + return $this->getContainer()->prepend($value); + } + + /** + * Set + * + * @param string $value + * @return void + * @throws Zend_View_Exception + */ + public function set($value) + { + if (!$this->_isValid($value)) { + $e = new Zend_View_Exception('Invalid value passed to set; please use setMeta()'); + $e->setView($this->view); + throw $e; + } + + $container = $this->getContainer(); + foreach ($container->getArrayCopy() as $index => $item) { + if ($item->type == $value->type && $item->{$item->type} == $value->{$value->type}) { + $this->offsetUnset($index); + } + } + + return $this->append($value); + } + + /** + * Build meta HTML string + * + * @param string $type + * @param string $typeValue + * @param string $content + * @param array $modifiers + * @return string + */ + public function itemToString(stdClass $item) + { + if (!in_array($item->type, $this->_typeKeys)) { + $e = new Zend_View_Exception(sprintf('Invalid type "%s" provided for meta', $item->type)); + $e->setView($this->view); + throw $e; + } + $type = $item->type; + + $modifiersString = ''; + foreach ($item->modifiers as $key => $value) { + if (!is_null($this->view) && $this->view->doctype()->isHtml5() + && $key == 'scheme') { + throw new Zend_View_Exception('Invalid modifier ' + . '"scheme" provided; not supported by HTML5'); + } + if (!in_array($key, $this->_modifierKeys)) { + continue; + } + $modifiersString .= $key . '="' . $this->_escape($value) . '" '; + } + + if ($this->view instanceof Zend_View_Abstract) { + if ($this->view->doctype()->isHtml5() + && $type == 'charset') { + $tpl = ($this->view->doctype()->isXhtml()) + ? '' + : ''; + } elseif ($this->view->doctype()->isXhtml()) { + $tpl = ''; + } else { + $tpl = ''; + } + } else { + $tpl = ''; + } + + $meta = sprintf( + $tpl, + $type, + $this->_escape($item->$type), + $this->_escape($item->content), + $modifiersString + ); + + if (isset($item->modifiers['conditional']) + && !empty($item->modifiers['conditional']) + && is_string($item->modifiers['conditional'])) + { + if (str_replace(' ', '', $item->modifiers['conditional']) === '!IE') { + $meta = '' . $meta . ''; + } + + return $meta; + } + + /** + * Render placeholder as string + * + * @param string|int $indent + * @return string + */ + public function toString($indent = null) + { + $indent = (null !== $indent) + ? $this->getWhitespace($indent) + : $this->getIndent(); + + $items = array(); + $this->getContainer()->ksort(); + try { + foreach ($this as $item) { + $items[] = $this->itemToString($item); + } + } catch (Zend_View_Exception $e) { + trigger_error($e->getMessage(), E_USER_WARNING); + return ''; + } + return $indent . implode($this->_escape($this->getSeparator()) . $indent, $items); + } + + /** + * Create data item for inserting into stack + * + * @param string $type + * @param string $typeValue + * @param string $content + * @param array $modifiers + * @return stdClass + */ + public function createData($type, $typeValue, $content, array $modifiers) + { + $data = new stdClass; + $data->type = $type; + $data->$type = $typeValue; + $data->content = $content; + $data->modifiers = $modifiers; + return $data; + } +} diff --git a/library/vendor/Zend/View/Helper/HeadScript.php b/library/vendor/Zend/View/Helper/HeadScript.php new file mode 100644 index 0000000..5b8461d --- /dev/null +++ b/library/vendor/Zend/View/Helper/HeadScript.php @@ -0,0 +1,512 @@ +setSeparator(PHP_EOL); + } + + /** + * Return headScript object + * + * Returns headScript helper object; optionally, allows specifying a script + * or script file to include. + * + * @param string $mode Script or file + * @param string $spec Script/url + * @param string $placement Append, prepend, or set + * @param array $attrs Array of script attributes + * @param string $type Script type and/or array of script attributes + * @return Zend_View_Helper_HeadScript + */ + public function headScript($mode = Zend_View_Helper_HeadScript::FILE, $spec = null, $placement = 'APPEND', array $attrs = array(), $type = 'text/javascript') + { + if ((null !== $spec) && is_string($spec)) { + $action = ucfirst(strtolower($mode)); + $placement = strtolower($placement); + switch ($placement) { + case 'set': + case 'prepend': + case 'append': + $action = $placement . $action; + break; + default: + $action = 'append' . $action; + break; + } + $this->$action($spec, $type, $attrs); + } + + return $this; + } + + /** + * Start capture action + * + * @param mixed $captureType + * @param string $typeOrAttrs + * @return void + */ + public function captureStart($captureType = Zend_View_Helper_Placeholder_Container_Abstract::APPEND, $type = 'text/javascript', $attrs = array()) + { + if ($this->_captureLock) { + $e = new Zend_View_Helper_Placeholder_Container_Exception('Cannot nest headScript captures'); + $e->setView($this->view); + throw $e; + } + + $this->_captureLock = true; + $this->_captureType = $captureType; + $this->_captureScriptType = $type; + $this->_captureScriptAttrs = $attrs; + ob_start(); + } + + /** + * End capture action and store + * + * @return void + */ + public function captureEnd() + { + $content = ob_get_clean(); + $type = $this->_captureScriptType; + $attrs = $this->_captureScriptAttrs; + $this->_captureScriptType = null; + $this->_captureScriptAttrs = null; + $this->_captureLock = false; + + switch ($this->_captureType) { + case Zend_View_Helper_Placeholder_Container_Abstract::SET: + case Zend_View_Helper_Placeholder_Container_Abstract::PREPEND: + case Zend_View_Helper_Placeholder_Container_Abstract::APPEND: + $action = strtolower($this->_captureType) . 'Script'; + break; + default: + $action = 'appendScript'; + break; + } + $this->$action($content, $type, $attrs); + } + + /** + * Overload method access + * + * Allows the following method calls: + * - appendFile($src, $type = 'text/javascript', $attrs = array()) + * - offsetSetFile($index, $src, $type = 'text/javascript', $attrs = array()) + * - prependFile($src, $type = 'text/javascript', $attrs = array()) + * - setFile($src, $type = 'text/javascript', $attrs = array()) + * - appendScript($script, $type = 'text/javascript', $attrs = array()) + * - offsetSetScript($index, $src, $type = 'text/javascript', $attrs = array()) + * - prependScript($script, $type = 'text/javascript', $attrs = array()) + * - setScript($script, $type = 'text/javascript', $attrs = array()) + * + * @param string $method + * @param array $args + * @return Zend_View_Helper_HeadScript + * @throws Zend_View_Exception if too few arguments or invalid method + */ + public function __call($method, $args) + { + if (preg_match('/^(?Pset|(ap|pre)pend|offsetSet)(?PFile|Script)$/', $method, $matches)) { + if (1 > count($args)) { + $e = new Zend_View_Exception(sprintf('Method "%s" requires at least one argument', $method)); + $e->setView($this->view); + throw $e; + } + + $action = $matches['action']; + $mode = strtolower($matches['mode']); + $type = 'text/javascript'; + $attrs = array(); + + if ('offsetSet' == $action) { + $index = array_shift($args); + if (1 > count($args)) { + $e = new Zend_View_Exception(sprintf('Method "%s" requires at least two arguments, an index and source', $method)); + $e->setView($this->view); + throw $e; + } + } + + $content = $args[0]; + + if (isset($args[1])) { + $type = (string) $args[1]; + } + if (isset($args[2])) { + $attrs = (array) $args[2]; + } + + switch ($mode) { + case 'script': + $item = $this->createData($type, $attrs, $content); + if ('offsetSet' == $action) { + $this->offsetSet($index, $item); + } else { + $this->$action($item); + } + break; + case 'file': + default: + if (!$this->_isDuplicate($content) || $action=='set') { + $attrs['src'] = $content; + $item = $this->createData($type, $attrs); + if ('offsetSet' == $action) { + $this->offsetSet($index, $item); + } else { + $this->$action($item); + } + } + break; + } + + return $this; + } + + return parent::__call($method, $args); + } + + /** + * Is the file specified a duplicate? + * + * @param string $file + * @return bool + */ + protected function _isDuplicate($file) + { + foreach ($this->getContainer() as $item) { + if (($item->source === null) + && array_key_exists('src', $item->attributes) + && ($file == $item->attributes['src'])) + { + return true; + } + } + return false; + } + + /** + * Is the script provided valid? + * + * @param mixed $value + * @param string $method + * @return bool + */ + protected function _isValid($value) + { + if ((!$value instanceof stdClass) + || !isset($value->type) + || (!isset($value->source) && !isset($value->attributes))) + { + return false; + } + + return true; + } + + /** + * Override append + * + * @param string $value + * @return void + */ + public function append($value) + { + if (!$this->_isValid($value)) { + $e = new Zend_View_Exception('Invalid argument passed to append(); please use one of the helper methods, appendScript() or appendFile()'); + $e->setView($this->view); + throw $e; + } + + return $this->getContainer()->append($value); + } + + /** + * Override prepend + * + * @param string $value + * @return void + */ + public function prepend($value) + { + if (!$this->_isValid($value)) { + $e = new Zend_View_Exception('Invalid argument passed to prepend(); please use one of the helper methods, prependScript() or prependFile()'); + $e->setView($this->view); + throw $e; + } + + return $this->getContainer()->prepend($value); + } + + /** + * Override set + * + * @param string $value + * @return void + */ + public function set($value) + { + if (!$this->_isValid($value)) { + $e = new Zend_View_Exception('Invalid argument passed to set(); please use one of the helper methods, setScript() or setFile()'); + $e->setView($this->view); + throw $e; + } + + return $this->getContainer()->set($value); + } + + /** + * Override offsetSet + * + * @param string|int $index + * @param mixed $value + * @return void + */ + public function offsetSet($index, $value): void + { + if (!$this->_isValid($value)) { + $e = new Zend_View_Exception('Invalid argument passed to offsetSet(); please use one of the helper methods, offsetSetScript() or offsetSetFile()'); + $e->setView($this->view); + throw $e; + } + + $this->getContainer()->offsetSet($index, $value); + } + + /** + * Set flag indicating if arbitrary attributes are allowed + * + * @param bool $flag + * @return Zend_View_Helper_HeadScript + */ + public function setAllowArbitraryAttributes($flag) + { + $this->_arbitraryAttributes = (bool) $flag; + return $this; + } + + /** + * Are arbitrary attributes allowed? + * + * @return bool + */ + public function arbitraryAttributesAllowed() + { + return $this->_arbitraryAttributes; + } + + /** + * Create script HTML + * + * @param string $type + * @param array $attributes + * @param string $content + * @param string|int $indent + * @return string + */ + public function itemToString($item, $indent, $escapeStart, $escapeEnd) + { + $attrString = ''; + if (!empty($item->attributes)) { + foreach ($item->attributes as $key => $value) { + if ((!$this->arbitraryAttributesAllowed() && !in_array($key, $this->_optionalAttributes)) + || in_array($key, array('conditional', 'noescape'))) + { + continue; + } + if ('defer' == $key) { + $value = 'defer'; + } + $attrString .= sprintf(' %s="%s"', $key, ($this->_autoEscape) ? $this->_escape($value) : $value); + } + } + + $addScriptEscape = !(isset($item->attributes['noescape']) && filter_var($item->attributes['noescape'], FILTER_VALIDATE_BOOLEAN)); + + $type = ($this->_autoEscape) ? $this->_escape($item->type) : $item->type; + $html = ''; + + if (isset($item->attributes['conditional']) + && !empty($item->attributes['conditional']) + && is_string($item->attributes['conditional'])) + { + // inner wrap with comment end and start if !IE + if (str_replace(' ', '', $item->attributes['conditional']) === '!IE') { + $html = '' . $html . ''; + } else { + $html = $indent . $html; + } + + return $html; + } + + /** + * Retrieve string representation + * + * @param string|int $indent + * @return string + */ + public function toString($indent = null) + { + $indent = (null !== $indent) + ? $this->getWhitespace($indent) + : $this->getIndent(); + + if ($this->view) { + $useCdata = $this->view->doctype()->isXhtml() ? true : false; + } else { + $useCdata = $this->useCdata ? true : false; + } + $escapeStart = ($useCdata) ? '//' : '//-->'; + + $items = array(); + $this->getContainer()->ksort(); + foreach ($this as $item) { + if (!$this->_isValid($item)) { + continue; + } + + $items[] = $this->itemToString($item, $indent, $escapeStart, $escapeEnd); + } + + $return = implode($this->getSeparator(), $items); + return $return; + } + + /** + * Create data item containing all necessary components of script + * + * @param string $type + * @param array $attributes + * @param string $content + * @return stdClass + */ + public function createData($type, array $attributes, $content = null) + { + $data = new stdClass(); + $data->type = $type; + $data->attributes = $attributes; + $data->source = $content; + return $data; + } +} diff --git a/library/vendor/Zend/View/Helper/HeadStyle.php b/library/vendor/Zend/View/Helper/HeadStyle.php new file mode 100644 index 0000000..c28f997 --- /dev/null +++ b/library/vendor/Zend/View/Helper/HeadStyle.php @@ -0,0 +1,426 @@ +setSeparator(PHP_EOL); + } + + /** + * Return headStyle object + * + * Returns headStyle helper object; optionally, allows specifying + * + * @param string $content Stylesheet contents + * @param string $placement Append, prepend, or set + * @param string|array $attributes Optional attributes to utilize + * @return Zend_View_Helper_HeadStyle + */ + public function headStyle($content = null, $placement = 'APPEND', $attributes = array()) + { + if ((null !== $content) && is_string($content)) { + switch (strtoupper($placement)) { + case 'SET': + $action = 'setStyle'; + break; + case 'PREPEND': + $action = 'prependStyle'; + break; + case 'APPEND': + default: + $action = 'appendStyle'; + break; + } + $this->$action($content, $attributes); + } + + return $this; + } + + /** + * Overload method calls + * + * Allows the following method calls: + * - appendStyle($content, $attributes = array()) + * - offsetSetStyle($index, $content, $attributes = array()) + * - prependStyle($content, $attributes = array()) + * - setStyle($content, $attributes = array()) + * + * @param string $method + * @param array $args + * @return void + * @throws Zend_View_Exception When no $content provided or invalid method + */ + public function __call($method, $args) + { + if (preg_match('/^(?Pset|(ap|pre)pend|offsetSet)(Style)$/', $method, $matches)) { + $index = null; + $argc = count($args); + $action = $matches['action']; + + if ('offsetSet' == $action) { + if (0 < $argc) { + $index = array_shift($args); + --$argc; + } + } + + if (1 > $argc) { + $e = new Zend_View_Exception(sprintf('Method "%s" requires minimally content for the stylesheet', $method)); + $e->setView($this->view); + throw $e; + } + + $content = $args[0]; + $attrs = array(); + if (isset($args[1])) { + $attrs = (array) $args[1]; + } + + $item = $this->createData($content, $attrs); + + if ('offsetSet' == $action) { + $this->offsetSet($index, $item); + } else { + $this->$action($item); + } + + return $this; + } + + return parent::__call($method, $args); + } + + /** + * Determine if a value is a valid style tag + * + * @param mixed $value + * @param string $method + * @return boolean + */ + protected function _isValid($value) + { + if ((!$value instanceof stdClass) + || !isset($value->content) + || !isset($value->attributes)) + { + return false; + } + + return true; + } + + /** + * Override append to enforce style creation + * + * @param mixed $value + * @return void + */ + public function append($value) + { + if (!$this->_isValid($value)) { + $e = new Zend_View_Exception('Invalid value passed to append; please use appendStyle()'); + $e->setView($this->view); + throw $e; + } + + return $this->getContainer()->append($value); + } + + /** + * Override offsetSet to enforce style creation + * + * @param string|int $index + * @param mixed $value + * @return void + */ + public function offsetSet($index, $value): void + { + if (!$this->_isValid($value)) { + $e = new Zend_View_Exception('Invalid value passed to offsetSet; please use offsetSetStyle()'); + $e->setView($this->view); + throw $e; + } + + $this->getContainer()->offsetSet($index, $value); + } + + /** + * Override prepend to enforce style creation + * + * @param mixed $value + * @return void + */ + public function prepend($value) + { + if (!$this->_isValid($value)) { + $e = new Zend_View_Exception('Invalid value passed to prepend; please use prependStyle()'); + $e->setView($this->view); + throw $e; + } + + return $this->getContainer()->prepend($value); + } + + /** + * Override set to enforce style creation + * + * @param mixed $value + * @return void + */ + public function set($value) + { + if (!$this->_isValid($value)) { + $e = new Zend_View_Exception('Invalid value passed to set; please use setStyle()'); + $e->setView($this->view); + throw $e; + } + + return $this->getContainer()->set($value); + } + + /** + * Start capture action + * + * @param mixed $captureType + * @param string $typeOrAttrs + * @return void + */ + public function captureStart($type = Zend_View_Helper_Placeholder_Container_Abstract::APPEND, $attrs = null) + { + if ($this->_captureLock) { + $e = new Zend_View_Helper_Placeholder_Container_Exception('Cannot nest headStyle captures'); + $e->setView($this->view); + throw $e; + } + + $this->_captureLock = true; + $this->_captureAttrs = $attrs; + $this->_captureType = $type; + ob_start(); + } + + /** + * End capture action and store + * + * @return void + */ + public function captureEnd() + { + $content = ob_get_clean(); + $attrs = $this->_captureAttrs; + $this->_captureAttrs = null; + $this->_captureLock = false; + + switch ($this->_captureType) { + case Zend_View_Helper_Placeholder_Container_Abstract::SET: + $this->setStyle($content, $attrs); + break; + case Zend_View_Helper_Placeholder_Container_Abstract::PREPEND: + $this->prependStyle($content, $attrs); + break; + case Zend_View_Helper_Placeholder_Container_Abstract::APPEND: + default: + $this->appendStyle($content, $attrs); + break; + } + } + + /** + * Convert content and attributes into valid style tag + * + * @param stdClass $item Item to render + * @param string $indent Indentation to use + * @return string + */ + public function itemToString(stdClass $item, $indent) + { + $attrString = ''; + if (!empty($item->attributes)) { + $enc = 'UTF-8'; + if ($this->view instanceof Zend_View_Interface + && method_exists($this->view, 'getEncoding') + ) { + $enc = $this->view->getEncoding(); + } + foreach ($item->attributes as $key => $value) { + if (!in_array($key, $this->_optionalAttributes)) { + continue; + } + if ('media' == $key) { + if(false === strpos($value, ',')) { + if (!in_array($value, $this->_mediaTypes)) { + continue; + } + } else { + $media_types = explode(',', $value); + $value = ''; + foreach($media_types as $type) { + $type = trim($type); + if (!in_array($type, $this->_mediaTypes)) { + continue; + } + $value .= $type .','; + } + $value = substr($value, 0, -1); + } + } + $attrString .= sprintf(' %s="%s"', $key, htmlspecialchars($value, ENT_COMPAT, $enc)); + } + } + + $escapeStart = $indent . ''. PHP_EOL; + if (isset($item->attributes['conditional']) + && !empty($item->attributes['conditional']) + && is_string($item->attributes['conditional']) + ) { + $escapeStart = null; + $escapeEnd = null; + } + + $html = ''; + + if (null == $escapeStart && null == $escapeEnd) { + if (str_replace(' ', '', $item->attributes['conditional']) === '!IE') { + $html = '' . $html . ''; + } + + return $html; + } + + /** + * Create string representation of placeholder + * + * @param string|int $indent + * @return string + */ + public function toString($indent = null) + { + $indent = (null !== $indent) + ? $this->getWhitespace($indent) + : $this->getIndent(); + + $items = array(); + $this->getContainer()->ksort(); + foreach ($this as $item) { + if (!$this->_isValid($item)) { + continue; + } + $items[] = $this->itemToString($item, $indent); + } + + $return = $indent . implode($this->getSeparator() . $indent, $items); + $return = preg_replace("/(\r\n?|\n)/", '$1' . $indent, $return); + return $return; + } + + /** + * Create data item for use in stack + * + * @param string $content + * @param array $attributes + * @return stdClass + */ + public function createData($content, array $attributes) + { + if (!isset($attributes['media'])) { + $attributes['media'] = 'screen'; + } else if(is_array($attributes['media'])) { + $attributes['media'] = implode(',', $attributes['media']); + } + + $data = new stdClass(); + $data->content = $content; + $data->attributes = $attributes; + + return $data; + } +} diff --git a/library/vendor/Zend/View/Helper/HeadTitle.php b/library/vendor/Zend/View/Helper/HeadTitle.php new file mode 100644 index 0000000..77aef26 --- /dev/null +++ b/library/vendor/Zend/View/Helper/HeadTitle.php @@ -0,0 +1,218 @@ +getDefaultAttachOrder()) + ? Zend_View_Helper_Placeholder_Container_Abstract::APPEND + : $this->getDefaultAttachOrder(); + } + $title = (string) $title; + if ($title !== '') { + if ($setType == Zend_View_Helper_Placeholder_Container_Abstract::SET) { + $this->set($title); + } elseif ($setType == Zend_View_Helper_Placeholder_Container_Abstract::PREPEND) { + $this->prepend($title); + } else { + $this->append($title); + } + } + + return $this; + } + + /** + * Set a default order to add titles + * + * @param string $setType + */ + public function setDefaultAttachOrder($setType) + { + if (!in_array($setType, array( + Zend_View_Helper_Placeholder_Container_Abstract::APPEND, + Zend_View_Helper_Placeholder_Container_Abstract::SET, + Zend_View_Helper_Placeholder_Container_Abstract::PREPEND + ))) { + throw new Zend_View_Exception("You must use a valid attach order: 'PREPEND', 'APPEND' or 'SET'"); + } + + $this->_defaultAttachOrder = $setType; + return $this; + } + + /** + * Get the default attach order, if any. + * + * @return mixed + */ + public function getDefaultAttachOrder() + { + return $this->_defaultAttachOrder; + } + + /** + * Sets a translation Adapter for translation + * + * @param Zend_Translate|Zend_Translate_Adapter $translate + * @return Zend_View_Helper_HeadTitle + */ + public function setTranslator($translate) + { + if ($translate instanceof Zend_Translate_Adapter) { + $this->_translator = $translate; + } elseif ($translate instanceof Zend_Translate) { + $this->_translator = $translate->getAdapter(); + } else { + $e = new Zend_View_Exception("You must set an instance of Zend_Translate or Zend_Translate_Adapter"); + $e->setView($this->view); + throw $e; + } + return $this; + } + + /** + * Retrieve translation object + * + * If none is currently registered, attempts to pull it from the registry + * using the key 'Zend_Translate'. + * + * @return Zend_Translate_Adapter|null + */ + public function getTranslator() + { + if (null === $this->_translator) { + if (Zend_Registry::isRegistered('Zend_Translate')) { + $this->setTranslator(Zend_Registry::get('Zend_Translate')); + } + } + return $this->_translator; + } + + /** + * Enables translation + * + * @return Zend_View_Helper_HeadTitle + */ + public function enableTranslation() + { + $this->_translate = true; + return $this; + } + + /** + * Disables translation + * + * @return Zend_View_Helper_HeadTitle + */ + public function disableTranslation() + { + $this->_translate = false; + return $this; + } + + /** + * Turn helper into string + * + * @param string|null $indent + * @param string|null $locale + * @return string + */ + public function toString($indent = null, $locale = null) + { + $indent = (null !== $indent) + ? $this->getWhitespace($indent) + : $this->getIndent(); + + $items = array(); + + if($this->_translate && $translator = $this->getTranslator()) { + foreach ($this as $item) { + $items[] = $translator->translate($item, $locale); + } + } else { + foreach ($this as $item) { + $items[] = $item; + } + } + + $separator = $this->getSeparator(); + $output = ''; + if(($prefix = $this->getPrefix())) { + $output .= $prefix; + } + $output .= implode($separator, $items); + if(($postfix = $this->getPostfix())) { + $output .= $postfix; + } + + $output = ($this->_autoEscape) ? $this->_escape($output) : $output; + + return $indent . '' . $output . ''; + } +} diff --git a/library/vendor/Zend/View/Helper/HtmlElement.php b/library/vendor/Zend/View/Helper/HtmlElement.php new file mode 100644 index 0000000..212afbd --- /dev/null +++ b/library/vendor/Zend/View/Helper/HtmlElement.php @@ -0,0 +1,165 @@ +_closingBracket) { + if ($this->_isXhtml()) { + $this->_closingBracket = ' />'; + } else { + $this->_closingBracket = '>'; + } + } + + return $this->_closingBracket; + } + + /** + * Is doctype XHTML? + * + * @return boolean + */ + protected function _isXhtml() + { + $doctype = $this->view->doctype(); + return $doctype->isXhtml(); + } + + /** + * Is doctype HTML5? + * + * @return boolean + */ + protected function _isHtml5() + { + $doctype = $this->view->doctype(); + return $doctype->isHtml5(); + } + + /** + * Is doctype strict? + * + * @return boolean + */ + protected function _isStrictDoctype() + { + $doctype = $this->view->doctype(); + return $doctype->isStrict(); + } + + /** + * Converts an associative array to a string of tag attributes. + * + * @access public + * + * @param array $attribs From this array, each key-value pair is + * converted to an attribute name and value. + * + * @return string The XHTML for the attributes. + */ + protected function _htmlAttribs($attribs) + { + $xhtml = ''; + foreach ((array) $attribs as $key => $val) { + $key = $this->view->escape($key); + + if (('on' == substr($key, 0, 2)) || ('constraints' == $key)) { + // Don't escape event attributes; _do_ substitute double quotes with singles + if (!is_scalar($val)) { + // non-scalar data should be cast to JSON first + $val = Zend_Json::encode($val); + } + // Escape single quotes inside event attribute values. + // This will create html, where the attribute value has + // single quotes around it, and escaped single quotes or + // non-escaped double quotes inside of it + $val = str_replace('\'', ''', $val); + } else { + if (is_array($val)) { + $val = implode(' ', $val); + } + $val = $this->view->escape($val); + } + + if ('id' == $key) { + $val = $this->_normalizeId($val); + } + + if (strpos($val, '"') !== false) { + $xhtml .= " $key='$val'"; + } else { + $xhtml .= " $key=\"$val\""; + } + + } + return $xhtml; + } + + /** + * Normalize an ID + * + * @param string $value + * @return string + */ + protected function _normalizeId($value) + { + if (strstr($value, '[')) { + if ('[]' == substr($value, -2)) { + $value = substr($value, 0, strlen($value) - 2); + } + $value = trim($value, ']'); + $value = str_replace('][', '-', $value); + $value = str_replace('[', '-', $value); + } + return $value; + } +} diff --git a/library/vendor/Zend/View/Helper/HtmlFlash.php b/library/vendor/Zend/View/Helper/HtmlFlash.php new file mode 100644 index 0000000..b33ad51 --- /dev/null +++ b/library/vendor/Zend/View/Helper/HtmlFlash.php @@ -0,0 +1,59 @@ + $data, + 'quality' => 'high'), $params); + + return $this->htmlObject($data, self::TYPE, $attribs, $params, $content); + } +} diff --git a/library/vendor/Zend/View/Helper/HtmlList.php b/library/vendor/Zend/View/Helper/HtmlList.php new file mode 100644 index 0000000..e080eb1 --- /dev/null +++ b/library/vendor/Zend/View/Helper/HtmlList.php @@ -0,0 +1,88 @@ +setView($this->view); + throw $e; + } + + $list = ''; + + foreach ($items as $item) { + if (!is_array($item)) { + if ($escape) { + $item = $this->view->escape($item); + } + $list .= '
  • ' . $item . '
  • ' . self::EOL; + } else { + if (6 < strlen($list)) { + $list = substr($list, 0, strlen($list) - 6) + . $this->htmlList($item, $ordered, $attribs, $escape) . '' . self::EOL; + } else { + $list .= '
  • ' . $this->htmlList($item, $ordered, $attribs, $escape) . '
  • ' . self::EOL; + } + } + } + + if ($attribs) { + $attribs = $this->_htmlAttribs($attribs); + } else { + $attribs = ''; + } + + $tag = 'ul'; + if ($ordered) { + $tag = 'ol'; + } + + return '<' . $tag . $attribs . '>' . self::EOL . $list . '' . self::EOL; + } +} diff --git a/library/vendor/Zend/View/Helper/HtmlObject.php b/library/vendor/Zend/View/Helper/HtmlObject.php new file mode 100644 index 0000000..a5a4e22 --- /dev/null +++ b/library/vendor/Zend/View/Helper/HtmlObject.php @@ -0,0 +1,79 @@ + $data, + 'type' => $type), $attribs); + + // Params + $paramHtml = array(); + $closingBracket = $this->getClosingBracket(); + + foreach ($params as $param => $options) { + if (is_string($options)) { + $options = array('value' => $options); + } + + $options = array_merge(array('name' => $param), $options); + + $paramHtml[] = '_htmlAttribs($options) . $closingBracket; + } + + // Content + if (is_array($content)) { + $content = implode(self::EOL, $content); + } + + // Object header + $xhtml = '_htmlAttribs($attribs) . '>' . self::EOL + . implode(self::EOL, $paramHtml) . self::EOL + . ($content ? $content . self::EOL : '') + . ''; + + return $xhtml; + } +} diff --git a/library/vendor/Zend/View/Helper/HtmlPage.php b/library/vendor/Zend/View/Helper/HtmlPage.php new file mode 100644 index 0000000..2a2265c --- /dev/null +++ b/library/vendor/Zend/View/Helper/HtmlPage.php @@ -0,0 +1,74 @@ + self::ATTRIB_CLASSID); + + /** + * Output a html object tag + * + * @param string $data The html url + * @param array $attribs Attribs for the object tag + * @param array $params Params for in the object tag + * @param string $content Alternative content + * @return string + */ + public function htmlPage($data, array $attribs = array(), array $params = array(), $content = null) + { + // Attrs + $attribs = array_merge($this->_attribs, $attribs); + + // Params + $params = array_merge(array('data' => $data), $params); + + return $this->htmlObject($data, self::TYPE, $attribs, $params, $content); + } +} diff --git a/library/vendor/Zend/View/Helper/HtmlQuicktime.php b/library/vendor/Zend/View/Helper/HtmlQuicktime.php new file mode 100644 index 0000000..f09452d --- /dev/null +++ b/library/vendor/Zend/View/Helper/HtmlQuicktime.php @@ -0,0 +1,81 @@ + self::ATTRIB_CLASSID, + 'codebase' => self::ATTRIB_CODEBASE); + + /** + * Output a quicktime movie object tag + * + * @param string $data The quicktime file + * @param array $attribs Attribs for the object tag + * @param array $params Params for in the object tag + * @param string $content Alternative content + * @return string + */ + public function htmlQuicktime($data, array $attribs = array(), array $params = array(), $content = null) + { + // Attrs + $attribs = array_merge($this->_attribs, $attribs); + + // Params + $params = array_merge(array('src' => $data), $params); + + return $this->htmlObject($data, self::TYPE, $attribs, $params, $content); + } +} diff --git a/library/vendor/Zend/View/Helper/InlineScript.php b/library/vendor/Zend/View/Helper/InlineScript.php new file mode 100644 index 0000000..555a2f4 --- /dev/null +++ b/library/vendor/Zend/View/Helper/InlineScript.php @@ -0,0 +1,60 @@ +headScript($mode, $spec, $placement, $attrs, $type); + } +} diff --git a/library/vendor/Zend/View/Helper/Interface.php b/library/vendor/Zend/View/Helper/Interface.php new file mode 100644 index 0000000..c7e761b --- /dev/null +++ b/library/vendor/Zend/View/Helper/Interface.php @@ -0,0 +1,46 @@ +true|false + * this array can contains a 'keepLayout'=>true|false and/or 'encodeData'=>true|false + * that will not be passed to Zend_Json::encode method but will be used here + * @param bool $encodeData + * @return string|void + */ + public function json($data, $keepLayouts = false, $encodeData = true) + { + $options = array(); + if (is_array($keepLayouts)) { + $options = $keepLayouts; + + $keepLayouts = false; + if (array_key_exists('keepLayouts', $options)) { + $keepLayouts = $options['keepLayouts']; + unset($options['keepLayouts']); + } + + if (array_key_exists('encodeData', $options)) { + $encodeData = $options['encodeData']; + unset($options['encodeData']); + } + } + + if ($encodeData) { + $data = Zend_Json::encode($data, null, $options); + } + if (!$keepLayouts) { + $layout = Zend_Layout::getMvcInstance(); + if ($layout instanceof Zend_Layout) { + $layout->disableLayout(); + } + } + + $response = Zend_Controller_Front::getInstance()->getResponse(); + $response->setHeader('Content-Type', 'application/json', true); + return $data; + } +} diff --git a/library/vendor/Zend/View/Helper/Layout.php b/library/vendor/Zend/View/Helper/Layout.php new file mode 100644 index 0000000..a83bf06 --- /dev/null +++ b/library/vendor/Zend/View/Helper/Layout.php @@ -0,0 +1,79 @@ +_layout) { + $this->_layout = Zend_Layout::getMvcInstance(); + if (null === $this->_layout) { + // Implicitly creates layout object + $this->_layout = new Zend_Layout(); + } + } + + return $this->_layout; + } + + /** + * Set layout object + * + * @param Zend_Layout $layout + * @return Zend_Layout_Controller_Action_Helper_Layout + */ + public function setLayout(Zend_Layout $layout) + { + $this->_layout = $layout; + return $this; + } + + /** + * Return layout object + * + * Usage: $this->layout()->setLayout('alternate'); + * + * @return Zend_Layout + */ + public function layout() + { + return $this->getLayout(); + } +} diff --git a/library/vendor/Zend/View/Helper/PaginationControl.php b/library/vendor/Zend/View/Helper/PaginationControl.php new file mode 100644 index 0000000..b474963 --- /dev/null +++ b/library/vendor/Zend/View/Helper/PaginationControl.php @@ -0,0 +1,142 @@ +view = $view; + return $this; + } + + /** + * Sets the default view partial. + * + * @param string|array $partial View partial + */ + public static function setDefaultViewPartial($partial) + { + self::$_defaultViewPartial = $partial; + } + + /** + * Gets the default view partial + * + * @return string|array + */ + public static function getDefaultViewPartial() + { + return self::$_defaultViewPartial; + } + + /** + * Render the provided pages. This checks if $view->paginator is set and, + * if so, uses that. Also, if no scrolling style or partial are specified, + * the defaults will be used (if set). + * + * @param Zend_Paginator (Optional) $paginator + * @param string $scrollingStyle (Optional) Scrolling style + * @param string $partial (Optional) View partial + * @param array|string $params (Optional) params to pass to the partial + * @return string + * @throws Zend_View_Exception + */ + public function paginationControl(Zend_Paginator $paginator = null, $scrollingStyle = null, $partial = null, $params = null) + { + if ($paginator === null) { + if (isset($this->view->paginator) and $this->view->paginator !== null and $this->view->paginator instanceof Zend_Paginator) { + $paginator = $this->view->paginator; + } else { + /** + * @see Zend_View_Exception + */ + + $e = new Zend_View_Exception('No paginator instance provided or incorrect type'); + $e->setView($this->view); + throw $e; + } + } + + if ($partial === null) { + if (self::$_defaultViewPartial === null) { + /** + * @see Zend_View_Exception + */ + $e = new Zend_View_Exception('No view partial provided and no default set'); + $e->setView($this->view); + throw $e; + } + + $partial = self::$_defaultViewPartial; + } + + $pages = get_object_vars($paginator->getPages($scrollingStyle)); + + if ($params !== null) { + $pages = array_merge($pages, (array) $params); + } + + if (is_array($partial)) { + if (count($partial) != 2) { + /** + * @see Zend_View_Exception + */ + $e = new Zend_View_Exception('A view partial supplied as an array must contain two values: the filename and its module'); + $e->setView($this->view); + throw $e; + } + + if ($partial[1] !== null) { + return $this->view->partial($partial[0], $partial[1], $pages); + } + + $partial = $partial[0]; + } + + return $this->view->partial($partial, $pages); + } +} diff --git a/library/vendor/Zend/View/Helper/Partial.php b/library/vendor/Zend/View/Helper/Partial.php new file mode 100644 index 0000000..787db9c --- /dev/null +++ b/library/vendor/Zend/View/Helper/Partial.php @@ -0,0 +1,150 @@ +cloneView(); + if (isset($this->partialCounter)) { + $view->partialCounter = $this->partialCounter; + } + if (isset($this->partialTotalCount)) { + $view->partialTotalCount = $this->partialTotalCount; + } + + if ((null !== $module) && is_string($module)) { + $moduleDir = Zend_Controller_Front::getInstance()->getControllerDirectory($module); + if (null === $moduleDir) { + $e = new Zend_View_Helper_Partial_Exception('Cannot render partial; module does not exist'); + $e->setView($this->view); + throw $e; + } + $viewsDir = dirname($moduleDir) . '/views'; + $view->addBasePath($viewsDir); + } elseif ((null == $model) && (null !== $module) + && (is_array($module) || is_object($module))) + { + $model = $module; + } + + if (!empty($model)) { + if (is_array($model)) { + $view->assign($model); + } elseif (is_object($model)) { + if (null !== ($objectKey = $this->getObjectKey())) { + $view->assign($objectKey, $model); + } elseif (method_exists($model, 'toArray')) { + $view->assign($model->toArray()); + } else { + $view->assign(get_object_vars($model)); + } + } + } + + return $view->render($name); + } + + /** + * Clone the current View + * + * @return Zend_View_Interface + */ + public function cloneView() + { + $view = clone $this->view; + $view->clearVars(); + return $view; + } + + /** + * Set object key + * + * @param string $key + * @return Zend_View_Helper_Partial + */ + public function setObjectKey($key) + { + if (null === $key) { + $this->_objectKey = null; + } else { + $this->_objectKey = (string) $key; + } + + return $this; + } + + /** + * Retrieve object key + * + * The objectKey is the variable to which an object in the iterator will be + * assigned. + * + * @return null|string + */ + public function getObjectKey() + { + return $this->_objectKey; + } +} diff --git a/library/vendor/Zend/View/Helper/Partial/Exception.php b/library/vendor/Zend/View/Helper/Partial/Exception.php new file mode 100644 index 0000000..5cd850a --- /dev/null +++ b/library/vendor/Zend/View/Helper/Partial/Exception.php @@ -0,0 +1,38 @@ +setView($this->view); + throw $e; + } + + if (is_object($model) + && (!$model instanceof Traversable) + && method_exists($model, 'toArray') + ) { + $model = $model->toArray(); + } + + $content = ''; + // reset the counter if it's call again + $this->partialCounter = 0; + $this->partialTotalCount = count($model); + + foreach ($model as $item) { + // increment the counter variable + $this->partialCounter++; + + $content .= $this->partial($name, $module, $item); + } + + return $content; + } +} diff --git a/library/vendor/Zend/View/Helper/Placeholder.php b/library/vendor/Zend/View/Helper/Placeholder.php new file mode 100644 index 0000000..3ca47ad --- /dev/null +++ b/library/vendor/Zend/View/Helper/Placeholder.php @@ -0,0 +1,85 @@ +_registry = Zend_View_Helper_Placeholder_Registry::getRegistry(); + } + + + /** + * Placeholder helper + * + * @param string $name + * @return Zend_View_Helper_Placeholder_Container_Abstract + */ + public function placeholder($name) + { + $name = (string) $name; + return $this->_registry->getContainer($name); + } + + /** + * Retrieve the registry + * + * @return Zend_View_Helper_Placeholder_Registry + */ + public function getRegistry() + { + return $this->_registry; + } +} diff --git a/library/vendor/Zend/View/Helper/Placeholder/Container.php b/library/vendor/Zend/View/Helper/Placeholder/Container.php new file mode 100644 index 0000000..c30025a --- /dev/null +++ b/library/vendor/Zend/View/Helper/Placeholder/Container.php @@ -0,0 +1,35 @@ +exchangeArray(array($value)); + } + + /** + * Prepend a value to the top of the container + * + * @param mixed $value + * @return void + */ + public function prepend($value) + { + $values = $this->getArrayCopy(); + array_unshift($values, $value); + $this->exchangeArray($values); + } + + /** + * Retrieve container value + * + * If single element registered, returns that element; otherwise, + * serializes to array. + * + * @return mixed + */ + public function getValue() + { + if (1 == count($this)) { + $keys = $this->getKeys(); + $key = array_shift($keys); + return $this[$key]; + } + + return $this->getArrayCopy(); + } + + /** + * Set prefix for __toString() serialization + * + * @param string $prefix + * @return Zend_View_Helper_Placeholder_Container + */ + public function setPrefix($prefix) + { + $this->_prefix = (string) $prefix; + return $this; + } + + /** + * Retrieve prefix + * + * @return string + */ + public function getPrefix() + { + return $this->_prefix; + } + + /** + * Set postfix for __toString() serialization + * + * @param string $postfix + * @return Zend_View_Helper_Placeholder_Container + */ + public function setPostfix($postfix) + { + $this->_postfix = (string) $postfix; + return $this; + } + + /** + * Retrieve postfix + * + * @return string + */ + public function getPostfix() + { + return $this->_postfix; + } + + /** + * Set separator for __toString() serialization + * + * Used to implode elements in container + * + * @param string $separator + * @return Zend_View_Helper_Placeholder_Container + */ + public function setSeparator($separator) + { + $this->_separator = (string) $separator; + return $this; + } + + /** + * Retrieve separator + * + * @return string + */ + public function getSeparator() + { + return $this->_separator; + } + + /** + * Set the indentation string for __toString() serialization, + * optionally, if a number is passed, it will be the number of spaces + * + * @param string|int $indent + * @return Zend_View_Helper_Placeholder_Container_Abstract + */ + public function setIndent($indent) + { + $this->_indent = $this->getWhitespace($indent); + return $this; + } + + /** + * Retrieve indentation + * + * @return string + */ + public function getIndent() + { + return $this->_indent; + } + + /** + * Retrieve whitespace representation of $indent + * + * @param int|string $indent + * @return string + */ + public function getWhitespace($indent) + { + if (is_int($indent)) { + $indent = str_repeat(' ', $indent); + } + + return (string) $indent; + } + + /** + * Start capturing content to push into placeholder + * + * @param int|string $type How to capture content into placeholder; append, prepend, or set + * @param null $key + * @throws Zend_View_Helper_Placeholder_Container_Exception + * @return void + */ + public function captureStart($type = Zend_View_Helper_Placeholder_Container_Abstract::APPEND, $key = null) + { + if ($this->_captureLock) { + $e = new Zend_View_Helper_Placeholder_Container_Exception('Cannot nest placeholder captures for the same placeholder'); + $e->setView($this->view); + throw $e; + } + + $this->_captureLock = true; + $this->_captureType = $type; + if ((null !== $key) && is_scalar($key)) { + $this->_captureKey = (string) $key; + } + ob_start(); + } + + /** + * End content capture + * + * @return void + */ + public function captureEnd() + { + $data = ob_get_clean(); + $key = null; + $this->_captureLock = false; + if (null !== $this->_captureKey) { + $key = $this->_captureKey; + } + switch ($this->_captureType) { + case self::SET: + if (null !== $key) { + $this[$key] = $data; + } else { + $this->exchangeArray(array($data)); + } + break; + case self::PREPEND: + if (null !== $key) { + $array = array($key => $data); + $values = $this->getArrayCopy(); + $final = $array + $values; + $this->exchangeArray($final); + } else { + $this->prepend($data); + } + break; + case self::APPEND: + default: + if (null !== $key) { + if (empty($this[$key])) { + $this[$key] = $data; + } else { + $this[$key] .= $data; + } + } else { + $this[$this->nextIndex()] = $data; + } + break; + } + } + + /** + * Get keys + * + * @return array + */ + public function getKeys() + { + $array = $this->getArrayCopy(); + return array_keys($array); + } + + /** + * Next Index + * + * as defined by the PHP manual + * @return int + */ + public function nextIndex() + { + $keys = $this->getKeys(); + if (0 == count($keys)) { + return 0; + } + + return $nextIndex = max($keys) + 1; + } + + /** + * Render the placeholder + * + * @param null $indent + * @return string + */ + public function toString($indent = null) + { + // Check items + if (0 === $this->count()) { + return ''; + } + + $indent = ($indent !== null) + ? $this->getWhitespace($indent) + : $this->getIndent(); + + $items = $this->getArrayCopy(); + $return = $indent + . $this->getPrefix() + . implode($this->getSeparator(), $items) + . $this->getPostfix(); + $return = preg_replace("/(\r\n?|\n)/", '$1' . $indent, $return); + return $return; + } + + /** + * Serialize object to string + * + * @return string + */ + public function __toString() + { + return $this->toString(); + } +} diff --git a/library/vendor/Zend/View/Helper/Placeholder/Container/Exception.php b/library/vendor/Zend/View/Helper/Placeholder/Container/Exception.php new file mode 100644 index 0000000..aceb769 --- /dev/null +++ b/library/vendor/Zend/View/Helper/Placeholder/Container/Exception.php @@ -0,0 +1,38 @@ +setRegistry(Zend_View_Helper_Placeholder_Registry::getRegistry()); + $this->setContainer($this->getRegistry()->getContainer($this->_regKey)); + } + + /** + * Retrieve registry + * + * @return Zend_View_Helper_Placeholder_Registry + */ + public function getRegistry() + { + return $this->_registry; + } + + /** + * Set registry object + * + * @param Zend_View_Helper_Placeholder_Registry $registry + * @return Zend_View_Helper_Placeholder_Container_Standalone + */ + public function setRegistry(Zend_View_Helper_Placeholder_Registry $registry) + { + $this->_registry = $registry; + return $this; + } + + /** + * Set whether or not auto escaping should be used + * + * @param bool $autoEscape whether or not to auto escape output + * @return Zend_View_Helper_Placeholder_Container_Standalone + */ + public function setAutoEscape($autoEscape = true) + { + $this->_autoEscape = ($autoEscape) ? true : false; + return $this; + } + + /** + * Return whether autoEscaping is enabled or disabled + * + * return bool + */ + public function getAutoEscape() + { + return $this->_autoEscape; + } + + /** + * Escape a string + * + * @param string $string + * @return string + */ + protected function _escape($string) + { + $enc = 'UTF-8'; + if ($this->view instanceof Zend_View_Interface + && method_exists($this->view, 'getEncoding') + ) { + $enc = $this->view->getEncoding(); + } + + return htmlspecialchars((string) $string, ENT_COMPAT, $enc); + } + + /** + * Set container on which to operate + * + * @param Zend_View_Helper_Placeholder_Container_Abstract $container + * @return Zend_View_Helper_Placeholder_Container_Standalone + */ + public function setContainer(Zend_View_Helper_Placeholder_Container_Abstract $container) + { + $this->_container = $container; + return $this; + } + + /** + * Retrieve placeholder container + * + * @return Zend_View_Helper_Placeholder_Container_Abstract + */ + public function getContainer() + { + return $this->_container; + } + + /** + * Overloading: set property value + * + * @param string $key + * @param mixed $value + * @return void + */ + public function __set($key, $value) + { + $container = $this->getContainer(); + $container[$key] = $value; + } + + /** + * Overloading: retrieve property + * + * @param string $key + * @return mixed + */ + public function __get($key) + { + $container = $this->getContainer(); + if (isset($container[$key])) { + return $container[$key]; + } + + return null; + } + + /** + * Overloading: check if property is set + * + * @param string $key + * @return bool + */ + public function __isset($key) + { + $container = $this->getContainer(); + return isset($container[$key]); + } + + /** + * Overloading: unset property + * + * @param string $key + * @return void + */ + public function __unset($key) + { + $container = $this->getContainer(); + if (isset($container[$key])) { + unset($container[$key]); + } + } + + /** + * Overload + * + * Proxy to container methods + * + * @param string $method + * @param array $args + * @return mixed + */ + public function __call($method, $args) + { + $container = $this->getContainer(); + if (method_exists($container, $method)) { + $return = call_user_func_array(array($container, $method), $args); + if ($return === $container) { + // If the container is returned, we really want the current object + return $this; + } + return $return; + } + + $e = new Zend_View_Exception('Method "' . $method . '" does not exist'); + $e->setView($this->view); + throw $e; + } + + /** + * String representation + * + * @return string + */ + public function toString() + { + return $this->getContainer()->toString(); + } + + /** + * Cast to string representation + * + * @return string + */ + public function __toString() + { + return $this->toString(); + } + + /** + * Countable + * + * @return int + */ + public function count(): int + { + $container = $this->getContainer(); + return count($container); + } + + /** + * ArrayAccess: offsetExists + * + * @param string|int $offset + * @return bool + */ + public function offsetExists($offset): bool + { + return $this->getContainer()->offsetExists($offset); + } + + /** + * ArrayAccess: offsetGet + * + * @param string|int $offset + * @return mixed + */ + #[\ReturnTypeWillChange] + public function offsetGet($offset) + { + return $this->getContainer()->offsetGet($offset); + } + + /** + * ArrayAccess: offsetSet + * + * @param string|int $offset + * @param mixed $value + * @return void + */ + public function offsetSet($offset, $value): void + { + $this->getContainer()->offsetSet($offset, $value); + } + + /** + * ArrayAccess: offsetUnset + * + * @param string|int $offset + * @return void + */ + public function offsetUnset($offset): void + { + $this->getContainer()->offsetUnset($offset); + } + + /** + * IteratorAggregate: get Iterator + * + * @return Iterator + */ + public function getIterator(): Traversable + { + return $this->getContainer()->getIterator(); + } +} diff --git a/library/vendor/Zend/View/Helper/Placeholder/Registry.php b/library/vendor/Zend/View/Helper/Placeholder/Registry.php new file mode 100644 index 0000000..111604c --- /dev/null +++ b/library/vendor/Zend/View/Helper/Placeholder/Registry.php @@ -0,0 +1,183 @@ +_items[$key] = new $this->_containerClass($value); + return $this->_items[$key]; + } + + /** + * Retrieve a placeholder container + * + * @param string $key + * @return Zend_View_Helper_Placeholder_Container_Abstract + */ + public function getContainer($key) + { + $key = (string) $key; + if (isset($this->_items[$key])) { + return $this->_items[$key]; + } + + $container = $this->createContainer($key); + + return $container; + } + + /** + * Does a particular container exist? + * + * @param string $key + * @return bool + */ + public function containerExists($key) + { + $key = (string) $key; + $return = array_key_exists($key, $this->_items); + return $return; + } + + /** + * Set the container for an item in the registry + * + * @param string $key + * @param Zend_View_Placeholder_Container_Abstract $container + * @return Zend_View_Placeholder_Registry + */ + public function setContainer($key, Zend_View_Helper_Placeholder_Container_Abstract $container) + { + $key = (string) $key; + $this->_items[$key] = $container; + return $this; + } + + /** + * Delete a container + * + * @param string $key + * @return bool + */ + public function deleteContainer($key) + { + $key = (string) $key; + if (isset($this->_items[$key])) { + unset($this->_items[$key]); + return true; + } + + return false; + } + + /** + * Set the container class to use + * + * @param string $name + * @return Zend_View_Helper_Placeholder_Registry + */ + public function setContainerClass($name) + { + if (!class_exists($name)) { + Zend_Loader::loadClass($name); + } + + $reflection = new ReflectionClass($name); + if (!$reflection->isSubclassOf(new ReflectionClass('Zend_View_Helper_Placeholder_Container_Abstract'))) { + $e = new Zend_View_Helper_Placeholder_Registry_Exception('Invalid Container class specified'); + $e->setView($this->view); + throw $e; + } + + $this->_containerClass = $name; + return $this; + } + + /** + * Retrieve the container class + * + * @return string + */ + public function getContainerClass() + { + return $this->_containerClass; + } +} diff --git a/library/vendor/Zend/View/Helper/Placeholder/Registry/Exception.php b/library/vendor/Zend/View/Helper/Placeholder/Registry/Exception.php new file mode 100644 index 0000000..42d7a28 --- /dev/null +++ b/library/vendor/Zend/View/Helper/Placeholder/Registry/Exception.php @@ -0,0 +1,38 @@ +view->placeholder($placeholder)->captureStart(); + echo $this->view->render($script); + $this->view->placeholder($placeholder)->captureEnd(); + } +} diff --git a/library/vendor/Zend/View/Helper/ServerUrl.php b/library/vendor/Zend/View/Helper/ServerUrl.php new file mode 100644 index 0000000..c38ec8b --- /dev/null +++ b/library/vendor/Zend/View/Helper/ServerUrl.php @@ -0,0 +1,148 @@ +setScheme($scheme); + + if (isset($_SERVER['HTTP_HOST']) && !empty($_SERVER['HTTP_HOST'])) { + $this->setHost($_SERVER['HTTP_HOST']); + } else if (isset($_SERVER['SERVER_NAME'], $_SERVER['SERVER_PORT'])) { + $name = $_SERVER['SERVER_NAME']; + $port = $_SERVER['SERVER_PORT']; + + if (($scheme == 'http' && $port == 80) || + ($scheme == 'https' && $port == 443)) { + $this->setHost($name); + } else { + $this->setHost($name . ':' . $port); + } + } + } + + /** + * View helper entry point: + * Returns the current host's URL like http://site.com + * + * @param string|boolean $requestUri [optional] if true, the request URI + * found in $_SERVER will be appended + * as a path. If a string is given, it + * will be appended as a path. Default + * is to not append any path. + * @return string server url + */ + public function serverUrl($requestUri = null) + { + if ($requestUri === true) { + $path = $_SERVER['REQUEST_URI']; + } else if (is_string($requestUri)) { + $path = $requestUri; + } else { + $path = ''; + } + + return $this->getScheme() . '://' . $this->getHost() . $path; + } + + /** + * Returns host + * + * @return string host + */ + public function getHost() + { + return $this->_host; + } + + /** + * Sets host + * + * @param string $host new host + * @return Zend_View_Helper_ServerUrl fluent interface, returns self + */ + public function setHost($host) + { + $this->_host = $host; + return $this; + } + + /** + * Returns scheme (typically http or https) + * + * @return string scheme (typically http or https) + */ + public function getScheme() + { + return $this->_scheme; + } + + /** + * Sets scheme (typically http or https) + * + * @param string $scheme new scheme (typically http or https) + * @return Zend_View_Helper_ServerUrl fluent interface, returns self + */ + public function setScheme($scheme) + { + $this->_scheme = $scheme; + return $this; + } +} diff --git a/library/vendor/Zend/View/Helper/Translate.php b/library/vendor/Zend/View/Helper/Translate.php new file mode 100644 index 0000000..8a7d916 --- /dev/null +++ b/library/vendor/Zend/View/Helper/Translate.php @@ -0,0 +1,174 @@ +setTranslator($translate); + } + } + + /** + * Translate a message + * You can give multiple params or an array of params. + * If you want to output another locale just set it as last single parameter + * Example 1: translate('%1\$s + %2\$s', $value1, $value2, $locale); + * Example 2: translate('%1\$s + %2\$s', array($value1, $value2), $locale); + * + * @param string $messageid Id of the message to be translated + * @return string|Zend_View_Helper_Translate Translated message + */ + public function translate($messageid = null) + { + if ($messageid === null) { + return $this; + } + + $translate = $this->getTranslator(); + $options = func_get_args(); + + array_shift($options); + $count = count($options); + $locale = null; + if ($count > 0) { + if (Zend_Locale::isLocale($options[($count - 1)], null, false) !== false) { + $locale = array_pop($options); + } + } + + if ((count($options) === 1) and (is_array($options[0]) === true)) { + $options = $options[0]; + } + + if ($translate !== null) { + $messageid = $translate->translate($messageid, $locale); + } + + if (count($options) === 0) { + return $messageid; + } + + return vsprintf($messageid, $options); + } + + /** + * Sets a translation Adapter for translation + * + * @param Zend_Translate|Zend_Translate_Adapter $translate Instance of Zend_Translate + * @throws Zend_View_Exception When no or a false instance was set + * @return Zend_View_Helper_Translate + */ + public function setTranslator($translate) + { + if ($translate instanceof Zend_Translate_Adapter) { + $this->_translator = $translate; + } else if ($translate instanceof Zend_Translate) { + $this->_translator = $translate->getAdapter(); + } else { + $e = new Zend_View_Exception('You must set an instance of Zend_Translate or Zend_Translate_Adapter'); + $e->setView($this->view); + throw $e; + } + + return $this; + } + + /** + * Retrieve translation object + * + * @return Zend_Translate_Adapter|null + */ + public function getTranslator() + { + if ($this->_translator === null) { + if (Zend_Registry::isRegistered('Zend_Translate')) { + $this->setTranslator(Zend_Registry::get('Zend_Translate')); + } + } + + return $this->_translator; + } + + /** + * Set's an new locale for all further translations + * + * @param string|Zend_Locale $locale New locale to set + * @throws Zend_View_Exception When no Zend_Translate instance was set + * @return Zend_View_Helper_Translate + */ + public function setLocale($locale = null) + { + $translate = $this->getTranslator(); + if ($translate === null) { + $e = new Zend_View_Exception('You must set an instance of Zend_Translate or Zend_Translate_Adapter'); + $e->setView($this->view); + throw $e; + } + + $translate->setLocale($locale); + return $this; + } + + /** + * Returns the set locale for translations + * + * @throws Zend_View_Exception When no Zend_Translate instance was set + * @return string|Zend_Locale + */ + public function getLocale() + { + $translate = $this->getTranslator(); + if ($translate === null) { + $e = new Zend_View_Exception('You must set an instance of Zend_Translate or Zend_Translate_Adapter'); + $e->setView($this->view); + throw $e; + } + + return $translate->getLocale(); + } +} diff --git a/library/vendor/Zend/View/Helper/Url.php b/library/vendor/Zend/View/Helper/Url.php new file mode 100644 index 0000000..3ed84ca --- /dev/null +++ b/library/vendor/Zend/View/Helper/Url.php @@ -0,0 +1,50 @@ +getRouter(); + return $router->assemble($urlOptions, $name, $reset, $encode); + } +} diff --git a/library/vendor/Zend/View/Interface.php b/library/vendor/Zend/View/Interface.php new file mode 100644 index 0000000..496ec71 --- /dev/null +++ b/library/vendor/Zend/View/Interface.php @@ -0,0 +1,137 @@ + value pairs to set en + * masse. + * + * @see __set() + * @param string|array $spec The assignment strategy to use (key or array of key + * => value pairs) + * @param mixed $value (Optional) If assigning a named variable, use this + * as the value. + * @return void + */ + public function assign($spec, $value = null); + + /** + * Clear all assigned variables + * + * Clears all variables assigned to Zend_View either via {@link assign()} or + * property overloading ({@link __get()}/{@link __set()}). + * + * @return void + */ + public function clearVars(); + + /** + * Processes a view script and returns the output. + * + * @param string $name The script name to process. + * @return string The script output. + */ + public function render($name); +} diff --git a/library/vendor/Zend/View/Stream.php b/library/vendor/Zend/View/Stream.php new file mode 100644 index 0000000..ae8d524 --- /dev/null +++ b/library/vendor/Zend/View/Stream.php @@ -0,0 +1,183 @@ +_data = file_get_contents($path); + + /** + * If reading the file failed, update our local stat store + * to reflect the real stat of the file, then return on failure + */ + if ($this->_data === false) { + $this->_stat = stat($path); + return false; + } + + /** + * Convert to long-form and to + * + */ + $this->_data = preg_replace('/\<\?\=/', "_data); + $this->_data = preg_replace('/<\?(?!xml|php)/s', '_data); + + /** + * file_get_contents() won't update PHP's stat cache, so we grab a stat + * of the file to prevent additional reads should the script be + * requested again, which will make include() happy. + */ + $this->_stat = stat($path); + + return true; + } + + /** + * Included so that __FILE__ returns the appropriate info + * + * @return array + */ + public function url_stat() + { + return $this->_stat; + } + + /** + * Reads from the stream. + */ + public function stream_read($count) + { + $ret = substr($this->_data, $this->_pos, $count); + $this->_pos += strlen($ret); + return $ret; + } + + + /** + * Tells the current position in the stream. + */ + public function stream_tell() + { + return $this->_pos; + } + + + /** + * Tells if we are at the end of the stream. + */ + public function stream_eof() + { + return $this->_pos >= strlen($this->_data); + } + + + /** + * Stream statistics. + */ + public function stream_stat() + { + return $this->_stat; + } + + + /** + * Seek to a specific point in the stream. + */ + public function stream_seek($offset, $whence) + { + switch ($whence) { + case SEEK_SET: + if ($offset < strlen($this->_data) && $offset >= 0) { + $this->_pos = $offset; + return true; + } else { + return false; + } + break; + + case SEEK_CUR: + if ($offset >= 0) { + $this->_pos += $offset; + return true; + } else { + return false; + } + break; + + case SEEK_END: + if (strlen($this->_data) + $offset >= 0) { + $this->_pos = strlen($this->_data) + $offset; + return true; + } else { + return false; + } + break; + + default: + return false; + } + } +} diff --git a/library/vendor/Zend/Xml/Exception.php b/library/vendor/Zend/Xml/Exception.php new file mode 100644 index 0000000..3d12d82 --- /dev/null +++ b/library/vendor/Zend/Xml/Exception.php @@ -0,0 +1,35 @@ + 0) { + return true; + } + return false; + } + + /** + * Scan XML string for potential XXE and XEE attacks + * + * @param string $xml + * @param DomDocument $dom + * @throws Zend_Xml_Exception + * @return SimpleXMLElement|DomDocument|boolean + */ + public static function scan($xml, DOMDocument $dom = null) + { + // If running with PHP-FPM we perform an heuristic scan + // We cannot use libxml_disable_entity_loader because of this bug + // @see https://bugs.php.net/bug.php?id=64938 + if (self::isPhpFpm()) { + self::heuristicScan($xml); + } + + if (null === $dom) { + $simpleXml = true; + $dom = new DOMDocument(); + } + + if (!self::isPhpFpm()) { + $loadEntities = libxml_disable_entity_loader(true); + $useInternalXmlErrors = libxml_use_internal_errors(true); + } + + // Load XML with network access disabled (LIBXML_NONET) + // error disabled with @ for PHP-FPM scenario + set_error_handler(array('Zend_Xml_Security', 'loadXmlErrorHandler'), E_WARNING); + + $result = $dom->loadXml($xml, LIBXML_NONET); + restore_error_handler(); + + if (!$result) { + // Entity load to previous setting + if (!self::isPhpFpm()) { + libxml_disable_entity_loader($loadEntities); + libxml_use_internal_errors($useInternalXmlErrors); + } + return false; + } + + // Scan for potential XEE attacks using ENTITY, if not PHP-FPM + if (!self::isPhpFpm()) { + foreach ($dom->childNodes as $child) { + if ($child->nodeType === XML_DOCUMENT_TYPE_NODE) { + if ($child->entities->length > 0) { + throw new Zend_Xml_Exception(self::ENTITY_DETECT); + } + } + } + } + + // Entity load to previous setting + if (!self::isPhpFpm()) { + libxml_disable_entity_loader($loadEntities); + libxml_use_internal_errors($useInternalXmlErrors); + } + + if (isset($simpleXml)) { + $result = simplexml_import_dom($dom); + if (!$result instanceof SimpleXMLElement) { + return false; + } + return $result; + } + return $dom; + } + + /** + * Scan XML file for potential XXE/XEE attacks + * + * @param string $file + * @param DOMDocument $dom + * @throws Zend_Xml_Exception + * @return SimpleXMLElement|DomDocument + */ + public static function scanFile($file, DOMDocument $dom = null) + { + if (!file_exists($file)) { + throw new Zend_Xml_Exception( + "The file $file specified doesn't exist" + ); + } + return self::scan(file_get_contents($file), $dom); + } + + /** + * Return true if PHP is running with PHP-FPM + * + * This method is mainly used to determine whether or not heuristic checks + * (vs libxml checks) should be made, due to threading issues in libxml; + * under php-fpm, threading becomes a concern. + * + * However, PHP versions 5.5.22+ and 5.6.6+ contain a patch to the + * libxml support in PHP that makes the libxml checks viable; in such + * versions, this method will return false to enforce those checks, which + * are more strict and accurate than the heuristic checks. + * + * @return boolean + */ + public static function isPhpFpm() + { + $isVulnerableVersion = ( + version_compare(PHP_VERSION, '5.5.22', 'lt') + || ( + version_compare(PHP_VERSION, '5.6', 'gte') + && version_compare(PHP_VERSION, '5.6.6', 'lt') + ) + ); + + if (substr(php_sapi_name(), 0, 3) === 'fpm' && $isVulnerableVersion) { + return true; + } + return false; + } + + /** + * Determine and return the string(s) to use for the $generator) { + $prefix = call_user_func($generator, '<' . '?xml'); + if (0 === strncmp($xml, $prefix, strlen($prefix))) { + return $encoding; + } + } + + // Fallback + return 'UTF-8'; + } + + /** + * Attempt to detect the specified XML encoding. + * + * Using the file's encoding, determines if an "encoding" attribute is + * present and well-formed in the XML declaration; if so, it returns a + * list with both the ASCII representation of that declaration and the + * original file encoding. + * + * If not, a list containing only the provided file encoding is returned. + * + * @param string $xml + * @param string $fileEncoding + * @return string[] Potential XML encodings + */ + protected static function detectXmlEncoding($xml, $fileEncoding) + { + $encodingMap = self::getAsciiEncodingMap(); + $generator = $encodingMap[$fileEncoding]; + $encAttr = call_user_func($generator, 'encoding="'); + $quote = call_user_func($generator, '"'); + $close = call_user_func($generator, '>'); + + $closePos = strpos($xml, $close); + if (false === $closePos) { + return array($fileEncoding); + } + + $encPos = strpos($xml, $encAttr); + if (false === $encPos + || $encPos > $closePos + ) { + return array($fileEncoding); + } + + $encPos += strlen($encAttr); + $quotePos = strpos($xml, $quote, $encPos); + if (false === $quotePos) { + return array($fileEncoding); + } + + $encoding = self::substr($xml, $encPos, $quotePos); + return array( + // Following line works because we're only supporting 8-bit safe encodings at this time. + str_replace('\0', '', $encoding), // detected encoding + $fileEncoding, // file encoding + ); + } + + /** + * Return a list of BOM maps. + * + * Returns a list of common encoding -> BOM maps, along with the character + * length to compare against. + * + * @link https://en.wikipedia.org/wiki/Byte_order_mark + * @return array + */ + protected static function getBomMap() + { + return array( + array( + 'encoding' => 'UTF-32BE', + 'bom' => pack('CCCC', 0x00, 0x00, 0xfe, 0xff), + 'length' => 4, + ), + array( + 'encoding' => 'UTF-32LE', + 'bom' => pack('CCCC', 0xff, 0xfe, 0x00, 0x00), + 'length' => 4, + ), + array( + 'encoding' => 'GB-18030', + 'bom' => pack('CCCC', 0x84, 0x31, 0x95, 0x33), + 'length' => 4, + ), + array( + 'encoding' => 'UTF-16BE', + 'bom' => pack('CC', 0xfe, 0xff), + 'length' => 2, + ), + array( + 'encoding' => 'UTF-16LE', + 'bom' => pack('CC', 0xff, 0xfe), + 'length' => 2, + ), + array( + 'encoding' => 'UTF-8', + 'bom' => pack('CCC', 0xef, 0xbb, 0xbf), + 'length' => 3, + ), + ); + } + + /** + * Return a map of encoding => generator pairs. + * + * Returns a map of encoding => generator pairs, where the generator is a + * callable that accepts a string and returns the appropriate byte order + * sequence of that string for the encoding. + * + * @return array + */ + protected static function getAsciiEncodingMap() + { + return array( + 'UTF-32BE' => array(__CLASS__, 'encodeToUTF32BE'), + 'UTF-32LE' => array(__CLASS__, 'encodeToUTF32LE'), + 'UTF-32odd1' => array(__CLASS__, 'encodeToUTF32odd1'), + 'UTF-32odd2' => array(__CLASS__, 'encodeToUTF32odd2'), + 'UTF-16BE' => array(__CLASS__, 'encodeToUTF16BE'), + 'UTF-16LE' => array(__CLASS__, 'encodeToUTF16LE'), + 'UTF-8' => array(__CLASS__, 'encodeToUTF8'), + 'GB-18030' => array(__CLASS__, 'encodeToUTF8'), + ); + } + + /** + * Binary-safe substr. + * + * substr() is not binary-safe; this method loops by character to ensure + * multi-byte characters are aggregated correctly. + * + * @param string $string + * @param int $start + * @param int $end + * @return string + */ + protected static function substr($string, $start, $end) + { + $substr = ''; + for ($i = $start; $i < $end; $i += 1) { + $substr .= $string[$i]; + } + return $substr; + } + + /** + * Generate an entity comparison based on the given encoding. + * + * This patch is internal only, and public only so it can be used as a + * callable to pass to array_map. + * + * @internal + * @param string $encoding + * @return string + */ + public static function generateEntityComparison($encoding) + { + $encodingMap = self::getAsciiEncodingMap(); + $generator = isset($encodingMap[$encoding]) ? $encodingMap[$encoding] : $encodingMap['UTF-8']; + return call_user_func($generator, '