aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorAndreas Gohr <gohr@cosmocode.de>2019-10-10 09:55:14 +0200
committerAndreas Gohr <gohr@cosmocode.de>2019-10-10 09:55:14 +0200
commit31a58aba4c24b34c34ad5764d1a35b7c398c3a2c (patch)
tree7f4d1546fbb69863a7d366fc1ff647f784853b68
parentaf7ba5aa0bd10fc0ad9ef983006305b4c5a8ed42 (diff)
parentc0c77cd20b23921c9e893bb70b99f38be153875a (diff)
downloaddokuwiki-31a58aba4c24b34c34ad5764d1a35b7c398c3a2c.tar.gz
dokuwiki-31a58aba4c24b34c34ad5764d1a35b7c398c3a2c.zip
Merge branch 'psr2'
* psr2: (160 commits) fixed merge error Moved parts of the Asian word handling to its own class ignore snake_case error of substr_replace fixed some line length errors ignore PSR2 in the old form class fix PSR2 error in switch statement replaced deprecated utf8 functions formatting cleanup mark old utf8 functions deprecated some more PSR2 cleanup Some cleanup for the UTF-8 stuff Moved all utf8 methods to their own namespaced classes Create separate table files for UTF-8 handling Ignore mixed concerns in loader Use type safe comparisons in loader Remove obsolete include adjust phpcs exclude patterns for new plugin classes 🚚 Move Subscription class to deprecated.php ♻️ Split up ChangesSubscriptionSender into multiple classes Minor optimizations in PluginController ...
-rw-r--r--_cs/DokuWiki/Sniffs/Functions/OpeningFunctionBraceSniff.php81
-rw-r--r--_cs/DokuWiki/Sniffs/NamingConventions/ConstructorNameSniff.php85
-rw-r--r--_cs/DokuWiki/Sniffs/PHP/DeprecatedFunctionsSniff.php62
-rw-r--r--_cs/DokuWiki/Sniffs/PHP/DiscouragedFunctionsSniff.php54
-rw-r--r--_cs/DokuWiki/Sniffs/WhiteSpace/ScopeIndentSniff.php319
-rw-r--r--_cs/DokuWiki/ruleset.xml69
-rw-r--r--_cs/README18
-rw-r--r--_test/core/DokuWikiTest.php50
-rw-r--r--_test/core/TestRequest.php2
-rw-r--r--_test/mock/AuthPlugin.php10
-rw-r--r--_test/mock/Doku_Renderer.php11
-rw-r--r--_test/mock/MailerMock.php16
-rw-r--r--_test/phpcs.xml98
-rw-r--r--_test/phpunit.xml7
-rw-r--r--_test/tests/inc/PageUtilsIsHiddenPage.test.php8
-rw-r--r--_test/tests/inc/PassHash.test.php2
-rw-r--r--_test/tests/inc/Subscriptions/BulkSubscriptionsSenderTest.php110
-rw-r--r--_test/tests/inc/Subscriptions/SubscriberManagerTest.php131
-rw-r--r--_test/tests/inc/Subscriptions/SubscriberRegexBuilderTest.php52
-rw-r--r--_test/tests/inc/auth_aclcheck.test.php4
-rw-r--r--_test/tests/inc/auth_aclcheck_caseinsensitive.test.php4
-rw-r--r--_test/tests/inc/auth_admincheck.test.php6
-rw-r--r--_test/tests/inc/auth_deleteprofile.test.php17
-rw-r--r--_test/tests/inc/cache_stalecheck.test.php4
-rw-r--r--_test/tests/inc/cache_use.test.php8
-rw-r--r--_test/tests/inc/changelog_getRevisionsAround.test.php5
-rw-r--r--_test/tests/inc/changelog_getlastrevisionat.test.php19
-rw-r--r--_test/tests/inc/changelog_getrelativerevision.test.php4
-rw-r--r--_test/tests/inc/changelog_getrevisioninfo.test.php4
-rw-r--r--_test/tests/inc/changelog_getrevisions.test.php5
-rw-r--r--_test/tests/inc/common_ml.test.php2
-rw-r--r--_test/tests/inc/common_saveWikiText.test.php4
-rw-r--r--_test/tests/inc/events_nested.test.php6
-rw-r--r--_test/tests/inc/httpclient_http.test.php11
-rw-r--r--_test/tests/inc/httpclient_mock.php3
-rw-r--r--_test/tests/inc/input.test.php4
-rw-r--r--_test/tests/inc/json.test.php420
-rwxr-xr-x_test/tests/inc/mailer.test.php2
-rw-r--r--_test/tests/inc/media_searchlist.test.php2
-rw-r--r--_test/tests/inc/pageutils_findnearest.test.php4
-rw-r--r--_test/tests/inc/parser/lexer.test.php73
-rw-r--r--_test/tests/inc/parser/parser.inc.php8
-rw-r--r--_test/tests/inc/parser/parser_code.test.php5
-rw-r--r--_test/tests/inc/parser/parser_eol.test.php18
-rw-r--r--_test/tests/inc/parser/parser_file.test.php5
-rw-r--r--_test/tests/inc/parser/parser_footnote.test.php45
-rw-r--r--_test/tests/inc/parser/parser_headers.test.php36
-rw-r--r--_test/tests/inc/parser/parser_i18n.test.php19
-rw-r--r--_test/tests/inc/parser/parser_links.test.php111
-rw-r--r--_test/tests/inc/parser/parser_lists.test.php83
-rw-r--r--_test/tests/inc/parser/parser_preformatted.test.php40
-rw-r--r--_test/tests/inc/parser/parser_quote.test.php14
-rw-r--r--_test/tests/inc/parser/parser_quotes.test.php58
-rw-r--r--_test/tests/inc/parser/parser_replacements.test.php50
-rw-r--r--_test/tests/inc/parser/parser_table.test.php64
-rw-r--r--_test/tests/inc/parser/parser_unformatted.test.php7
-rw-r--r--_test/tests/inc/parser/renderer_resolveinterwiki.test.php2
-rw-r--r--_test/tests/inc/parser/renderer_xhtml.test.php10
-rw-r--r--_test/tests/inc/remote.test.php48
-rw-r--r--_test/tests/inc/remoteapicore.test.php14
-rw-r--r--_test/tests/inc/remoteapicore_aclcheck.test.php6
-rw-r--r--_test/tests/inc/subscription.test.php246
-rw-r--r--_test/tests/inc/utf8_basename.test.php4
-rw-r--r--_test/tests/inc/utf8_correctidx.test.php8
-rw-r--r--_test/tests/inc/utf8_html.test.php20
-rw-r--r--_test/tests/inc/utf8_romanize.test.php4
-rw-r--r--_test/tests/inc/utf8_stripspecials.test.php2
-rw-r--r--_test/tests/inc/utf8_strtolower.test.php4
-rw-r--r--_test/tests/inc/utf8_substr.test.php4
-rw-r--r--_test/tests/inc/utf8_unicode.test.php16
-rw-r--r--_test/tests/inc/utf8_utf16be.test.php4
-rwxr-xr-xbin/dwpage.php2
-rwxr-xr-xbin/gittool.php16
-rwxr-xr-xbin/indexer.php8
-rwxr-xr-xbin/plugin.php8
-rwxr-xr-xbin/wantedpages.php14
-rw-r--r--doku.php6
-rw-r--r--feed.php20
-rw-r--r--inc/Action/Admin.php2
-rw-r--r--inc/Action/Export.php3
-rw-r--r--inc/Action/Logout.php2
-rw-r--r--inc/Action/Plugin.php2
-rw-r--r--inc/Action/Profile.php2
-rw-r--r--inc/Action/ProfileDelete.php2
-rw-r--r--inc/Action/Redirect.php3
-rw-r--r--inc/Action/Register.php2
-rw-r--r--inc/Action/Resendpwd.php4
-rw-r--r--inc/Action/Sitemap.php8
-rw-r--r--inc/Action/Subscribe.php28
-rw-r--r--inc/ActionRouter.php2
-rw-r--r--inc/Ajax.php33
-rw-r--r--inc/Cache/Cache.php237
-rw-r--r--inc/Cache/CacheInstructions.php46
-rw-r--r--inc/Cache/CacheParser.php64
-rw-r--r--inc/Cache/CacheRenderer.php94
-rw-r--r--inc/ChangeLog/ChangeLog.php666
-rw-r--r--inc/ChangeLog/MediaChangeLog.php30
-rw-r--r--inc/ChangeLog/PageChangeLog.php30
-rw-r--r--inc/Debug/DebugHelper.php121
-rw-r--r--inc/Debug/PropertyDeprecationHelper.php134
-rw-r--r--inc/Draft.php2
-rw-r--r--inc/Extension/ActionPlugin.php22
-rw-r--r--inc/Extension/AdminPlugin.php123
-rw-r--r--inc/Extension/AuthPlugin.php458
-rw-r--r--inc/Extension/CLIPlugin.php13
-rw-r--r--inc/Extension/Event.php202
-rw-r--r--inc/Extension/EventHandler.php108
-rw-r--r--inc/Extension/Plugin.php13
-rw-r--r--inc/Extension/PluginController.php393
-rw-r--r--inc/Extension/PluginInterface.php (renamed from inc/PluginInterface.php)10
-rw-r--r--inc/Extension/PluginTrait.php (renamed from inc/PluginTrait.php)134
-rw-r--r--inc/Extension/RemotePlugin.php122
-rw-r--r--inc/Extension/SyntaxPlugin.php132
-rw-r--r--inc/FeedParser.php65
-rw-r--r--inc/FeedParserFile.php62
-rw-r--r--inc/Form/ButtonElement.php2
-rw-r--r--inc/Form/DropdownElement.php12
-rw-r--r--inc/Form/Form.php12
-rw-r--r--inc/Form/OptGroup.php12
-rw-r--r--inc/HTTP/DokuHTTPClient.php77
-rw-r--r--inc/HTTP/HTTPClient.php (renamed from inc/HTTPClient.php)322
-rw-r--r--inc/HTTP/HTTPClientException.php10
-rw-r--r--inc/IXR_Library.php2
-rw-r--r--inc/Input.class.php335
-rw-r--r--inc/Input/Get.php29
-rw-r--r--inc/Input/Input.php287
-rw-r--r--inc/Input/Post.php30
-rw-r--r--inc/Input/Server.php19
-rw-r--r--inc/JSON.php827
-rw-r--r--inc/JpegMeta.php4
-rw-r--r--inc/Mailer.class.php54
-rw-r--r--inc/Manifest.php8
-rw-r--r--inc/Menu/AbstractMenu.php3
-rw-r--r--inc/Parsing/Handler/Block.php211
-rw-r--r--inc/Parsing/Handler/CallWriter.php40
-rw-r--r--inc/Parsing/Handler/CallWriterInterface.php30
-rw-r--r--inc/Parsing/Handler/Lists.php213
-rw-r--r--inc/Parsing/Handler/Nest.php83
-rw-r--r--inc/Parsing/Handler/Preformatted.php76
-rw-r--r--inc/Parsing/Handler/Quote.php110
-rw-r--r--inc/Parsing/Handler/ReWriterInterface.php29
-rw-r--r--inc/Parsing/Handler/Table.php345
-rw-r--r--inc/Parsing/Lexer/Lexer.php347
-rw-r--r--inc/Parsing/Lexer/ParallelRegex.php203
-rw-r--r--inc/Parsing/Lexer/StateStack.php60
-rw-r--r--inc/Parsing/Parser.php114
-rw-r--r--inc/Parsing/ParserMode/AbstractMode.php40
-rw-r--r--inc/Parsing/ParserMode/Acronym.php68
-rw-r--r--inc/Parsing/ParserMode/Base.php31
-rw-r--r--inc/Parsing/ParserMode/Camelcaselink.php23
-rw-r--r--inc/Parsing/ParserMode/Code.php25
-rw-r--r--inc/Parsing/ParserMode/Emaillink.php20
-rw-r--r--inc/Parsing/ParserMode/Entity.php50
-rw-r--r--inc/Parsing/ParserMode/Eol.php25
-rw-r--r--inc/Parsing/ParserMode/Externallink.php44
-rw-r--r--inc/Parsing/ParserMode/File.php25
-rw-r--r--inc/Parsing/ParserMode/Filelink.php39
-rw-r--r--inc/Parsing/ParserMode/Footnote.php50
-rw-r--r--inc/Parsing/ParserMode/Formatting.php115
-rw-r--r--inc/Parsing/ParserMode/Header.php24
-rw-r--r--inc/Parsing/ParserMode/Hr.php19
-rw-r--r--inc/Parsing/ParserMode/Html.php27
-rw-r--r--inc/Parsing/ParserMode/Internallink.php20
-rw-r--r--inc/Parsing/ParserMode/Linebreak.php19
-rw-r--r--inc/Parsing/ParserMode/Listblock.php44
-rw-r--r--inc/Parsing/ParserMode/Media.php20
-rw-r--r--inc/Parsing/ParserMode/ModeInterface.php46
-rw-r--r--inc/Parsing/ParserMode/Multiplyentity.php27
-rw-r--r--inc/Parsing/ParserMode/Nocache.php19
-rw-r--r--inc/Parsing/ParserMode/Notoc.php19
-rw-r--r--inc/Parsing/ParserMode/Php.php27
-rw-r--r--inc/Parsing/ParserMode/Plugin.php8
-rw-r--r--inc/Parsing/ParserMode/Preformatted.php31
-rw-r--r--inc/Parsing/ParserMode/Quote.php41
-rw-r--r--inc/Parsing/ParserMode/Quotes.php51
-rw-r--r--inc/Parsing/ParserMode/Rss.php19
-rw-r--r--inc/Parsing/ParserMode/Smiley.php48
-rw-r--r--inc/Parsing/ParserMode/Table.php47
-rw-r--r--inc/Parsing/ParserMode/Unformatted.php28
-rw-r--r--inc/Parsing/ParserMode/Windowssharelink.php31
-rw-r--r--inc/Parsing/ParserMode/Wordblock.php52
-rw-r--r--inc/PassHash.php (renamed from inc/PassHash.class.php)53
-rw-r--r--inc/Plugin.php11
-rw-r--r--inc/Remote/AccessDeniedException.php10
-rw-r--r--inc/Remote/Api.php (renamed from inc/remote.php)127
-rw-r--r--inc/Remote/ApiCore.php (renamed from inc/RemoteAPICore.php)396
-rw-r--r--inc/Remote/RemoteException.php10
-rw-r--r--inc/Remote/XmlRpcServer.php61
-rw-r--r--inc/SafeFN.class.php12
-rw-r--r--inc/Sitemap/Item.php66
-rw-r--r--inc/Sitemap/Mapper.php (renamed from inc/Sitemapper.php)76
-rw-r--r--inc/StyleUtils.php26
-rw-r--r--inc/Subscriptions/BulkSubscriptionSender.php261
-rw-r--r--inc/Subscriptions/MediaSubscriptionSender.php46
-rw-r--r--inc/Subscriptions/PageSubscriptionSender.php87
-rw-r--r--inc/Subscriptions/RegistrationSubscriptionSender.php40
-rw-r--r--inc/Subscriptions/SubscriberManager.php285
-rw-r--r--inc/Subscriptions/SubscriberRegexBuilder.php70
-rw-r--r--inc/Subscriptions/SubscriptionSender.php86
-rw-r--r--inc/TaskRunner.php28
-rw-r--r--inc/Ui/Admin.php12
-rw-r--r--inc/Ui/Search.php15
-rw-r--r--inc/Utf8/Asian.php99
-rw-r--r--inc/Utf8/Clean.php204
-rw-r--r--inc/Utf8/Conversion.php162
-rw-r--r--inc/Utf8/PhpString.php383
-rw-r--r--inc/Utf8/Table.php93
-rw-r--r--inc/Utf8/Unicode.php277
-rw-r--r--inc/Utf8/tables/case.php567
-rw-r--r--inc/Utf8/tables/loweraccents.php116
-rw-r--r--inc/Utf8/tables/romanization.php1458
-rw-r--r--inc/Utf8/tables/specials.php620
-rw-r--r--inc/Utf8/tables/upperaccents.php114
-rw-r--r--inc/actions.php4
-rw-r--r--inc/auth.php54
-rw-r--r--inc/cache.php346
-rw-r--r--inc/changelog.php715
-rw-r--r--inc/cli.php1
-rw-r--r--inc/common.php114
-rw-r--r--inc/confutils.php22
-rw-r--r--inc/deprecated.php565
-rw-r--r--inc/events.php275
-rw-r--r--inc/farm.php2
-rw-r--r--inc/fetch.functions.php18
-rw-r--r--inc/form.php37
-rw-r--r--inc/fulltext.php68
-rw-r--r--inc/html.php184
-rw-r--r--inc/indexer.php60
-rw-r--r--inc/infoutils.php65
-rw-r--r--inc/init.php28
-rw-r--r--inc/io.php16
-rw-r--r--inc/lang/az/wordblock.txt3
-rw-r--r--inc/lang/be/wordblock.txt3
-rw-r--r--inc/lang/gl/wordblock.txt3
-rw-r--r--inc/lang/ru/wordblock.txt3
-rw-r--r--inc/legacy.php18
-rw-r--r--inc/load.php57
-rw-r--r--inc/mail.php25
-rw-r--r--inc/media.php83
-rw-r--r--inc/pageutils.php18
-rw-r--r--inc/parser/code.php16
-rw-r--r--inc/parser/handler.php1853
-rw-r--r--inc/parser/lexer.php614
-rw-r--r--inc/parser/metadata.php310
-rw-r--r--inc/parser/parser.php1023
-rw-r--r--inc/parser/renderer.php218
-rw-r--r--inc/parser/xhtml.php306
-rw-r--r--inc/parser/xhtmlsummary.php43
-rw-r--r--inc/parserutils.php75
-rw-r--r--inc/plugincontroller.class.php347
-rw-r--r--inc/pluginutils.php29
-rw-r--r--inc/search.php12
-rw-r--r--inc/subscription.php693
-rw-r--r--inc/template.php36
-rw-r--r--inc/toolbar.php34
-rw-r--r--inc/utf8.php1838
-rw-r--r--install.php33
-rw-r--r--lib/exe/css.php84
-rw-r--r--lib/exe/detail.php21
-rw-r--r--lib/exe/fetch.php8
-rw-r--r--lib/exe/jquery.php4
-rw-r--r--lib/exe/js.php26
-rw-r--r--lib/exe/mediamanager.php5
-rw-r--r--lib/exe/xmlrpc.php66
-rw-r--r--lib/plugins/acl/action.php42
-rw-r--r--lib/plugins/acl/admin.php430
-rw-r--r--lib/plugins/acl/remote.php53
-rw-r--r--lib/plugins/action.php25
-rw-r--r--lib/plugins/admin.php119
-rw-r--r--lib/plugins/auth.php438
-rw-r--r--lib/plugins/authad/action.php45
-rw-r--r--lib/plugins/authad/auth.php347
-rw-r--r--lib/plugins/authldap/auth.php501
-rw-r--r--lib/plugins/authpdo/_test/sqlite.test.php8
-rw-r--r--lib/plugins/authpdo/auth.php461
-rw-r--r--lib/plugins/authpdo/conf/metadata.php2
-rw-r--r--lib/plugins/authplain/_test/escaping.test.php6
-rw-r--r--lib/plugins/authplain/auth.php183
-rw-r--r--lib/plugins/cli.php11
-rw-r--r--lib/plugins/config/_test/ConfigParserTest.php (renamed from lib/plugins/config/_test/configuration.test.php)32
-rw-r--r--lib/plugins/config/_test/LoaderTest.php79
-rw-r--r--lib/plugins/config/_test/Setting/AbstractSettingTest.php99
-rw-r--r--lib/plugins/config/_test/Setting/SettingArrayTest.php20
-rw-r--r--lib/plugins/config/_test/Setting/SettingNumericTest.php24
-rw-r--r--lib/plugins/config/_test/Setting/SettingNumericoptTest.php23
-rw-r--r--lib/plugins/config/_test/Setting/SettingOnoffTest.php72
-rw-r--r--lib/plugins/config/_test/Setting/SettingStringTest.php13
-rw-r--r--lib/plugins/config/_test/Setting/SettingTest.php70
-rw-r--r--lib/plugins/config/_test/WriterTest.php63
-rw-r--r--lib/plugins/config/admin.php430
-rw-r--r--lib/plugins/config/core/ConfigParser.php90
-rw-r--r--lib/plugins/config/core/Configuration.php219
-rw-r--r--lib/plugins/config/core/Loader.php269
-rw-r--r--lib/plugins/config/core/Setting/Setting.php294
-rw-r--r--lib/plugins/config/core/Setting/SettingArray.php105
-rw-r--r--lib/plugins/config/core/Setting/SettingAuthtype.php60
-rw-r--r--lib/plugins/config/core/Setting/SettingCompression.php21
-rw-r--r--lib/plugins/config/core/Setting/SettingDirchoice.php33
-rw-r--r--lib/plugins/config/core/Setting/SettingDisableactions.php23
-rw-r--r--lib/plugins/config/core/Setting/SettingEmail.php58
-rw-r--r--lib/plugins/config/core/Setting/SettingFieldset.php17
-rw-r--r--lib/plugins/config/core/Setting/SettingHidden.php10
-rw-r--r--lib/plugins/config/core/Setting/SettingImConvert.php28
-rw-r--r--lib/plugins/config/core/Setting/SettingLicense.php23
-rw-r--r--lib/plugins/config/core/Setting/SettingMulticheckbox.php163
-rw-r--r--lib/plugins/config/core/Setting/SettingMultichoice.php71
-rw-r--r--lib/plugins/config/core/Setting/SettingNoClass.php12
-rw-r--r--lib/plugins/config/core/Setting/SettingNoDefault.php13
-rw-r--r--lib/plugins/config/core/Setting/SettingNoKnownClass.php11
-rw-r--r--lib/plugins/config/core/Setting/SettingNumeric.php42
-rw-r--r--lib/plugins/config/core/Setting/SettingNumericopt.php25
-rw-r--r--lib/plugins/config/core/Setting/SettingOnoff.php57
-rw-r--r--lib/plugins/config/core/Setting/SettingPassword.php39
-rw-r--r--lib/plugins/config/core/Setting/SettingRegex.php34
-rw-r--r--lib/plugins/config/core/Setting/SettingRenderer.php56
-rw-r--r--lib/plugins/config/core/Setting/SettingSavedir.php26
-rw-r--r--lib/plugins/config/core/Setting/SettingSepchar.php18
-rw-r--r--lib/plugins/config/core/Setting/SettingString.php32
-rw-r--r--lib/plugins/config/core/Setting/SettingUndefined.php40
-rw-r--r--lib/plugins/config/core/Writer.php116
-rw-r--r--lib/plugins/config/lang/en/lang.php1
-rw-r--r--lib/plugins/config/settings/config.class.php1431
-rw-r--r--lib/plugins/config/settings/config.metadata.php58
-rw-r--r--lib/plugins/config/settings/extra.class.php309
-rw-r--r--lib/plugins/extension/_test/extension.test.php54
-rw-r--r--lib/plugins/extension/action.php28
-rw-r--r--lib/plugins/extension/admin.php81
-rw-r--r--lib/plugins/extension/helper/extension.php406
-rw-r--r--lib/plugins/extension/helper/gui.php82
-rw-r--r--lib/plugins/extension/helper/list.php279
-rw-r--r--lib/plugins/extension/helper/repository.php81
-rw-r--r--lib/plugins/info/syntax.php117
-rw-r--r--lib/plugins/popularity/action.php42
-rw-r--r--lib/plugins/popularity/admin.php73
-rw-r--r--lib/plugins/popularity/helper.php194
-rw-r--r--lib/plugins/remote.php104
-rw-r--r--lib/plugins/revert/admin.php89
-rw-r--r--lib/plugins/safefnrecode/action.php56
-rw-r--r--lib/plugins/styling/action.php33
-rw-r--r--lib/plugins/styling/admin.php87
-rw-r--r--lib/plugins/styling/popup.php5
-rw-r--r--lib/plugins/syntax.php134
-rw-r--r--lib/plugins/testing/action.php10
-rw-r--r--lib/plugins/testing/conf/default.php7
-rw-r--r--lib/plugins/testing/conf/metadata.php7
-rw-r--r--lib/plugins/testing/lang/en/settings.php5
-rw-r--r--lib/plugins/usermanager/_test/mocks.class.php12
-rw-r--r--lib/plugins/usermanager/admin.php726
-rw-r--r--lib/tpl/dokuwiki/images/pagetools-build.php2
-rw-r--r--lib/tpl/dokuwiki/tpl_footer.php3
-rw-r--r--lib/tpl/index.php3
351 files changed, 21379 insertions, 16420 deletions
diff --git a/_cs/DokuWiki/Sniffs/Functions/OpeningFunctionBraceSniff.php b/_cs/DokuWiki/Sniffs/Functions/OpeningFunctionBraceSniff.php
deleted file mode 100644
index 6c582b3af..000000000
--- a/_cs/DokuWiki/Sniffs/Functions/OpeningFunctionBraceSniff.php
+++ /dev/null
@@ -1,81 +0,0 @@
-<?php
-/**
- * Generic_Sniffs_Functions_OpeningFunctionBraceKernighanRitchieSniff.
- */
-
-class DokuWiki_Sniffs_Functions_OpeningFunctionBraceSniff implements PHP_CodeSniffer_Sniff {
-
-
- /**
- * Registers the tokens that this sniff wants to listen for.
- *
- * @return void
- */
- public function register()
- {
- return array(T_FUNCTION);
-
- }//end register()
-
-
- /**
- * Processes this test, when one of its tokens is encountered.
- *
- * @param PHP_CodeSniffer_File $phpcsFile The file being scanned.
- * @param int $stackPtr The position of the current token in the
- * stack passed in $tokens.
- *
- * @return void
- */
- public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr)
- {
- $tokens = $phpcsFile->getTokens();
-
- if (isset($tokens[$stackPtr]['scope_opener']) === false) {
- return;
- }
-
- $openingBrace = $tokens[$stackPtr]['scope_opener'];
-
- // The end of the function occurs at the end of the argument list. Its
- // like this because some people like to break long function declarations
- // over multiple lines.
- $functionLine = $tokens[$tokens[$stackPtr]['parenthesis_closer']]['line'];
- $braceLine = $tokens[$openingBrace]['line'];
-
- $lineDifference = ($braceLine - $functionLine);
-
- if ($lineDifference > 0) {
- $error = 'Opening brace should be on the same line as the declaration';
- $phpcsFile->addError($error, $openingBrace);
- return;
- }
-
- // Checks that the closing parenthesis and the opening brace are
- // separated by a whitespace character.
- $closerColumn = $tokens[$tokens[$stackPtr]['parenthesis_closer']]['column'];
- $braceColumn = $tokens[$openingBrace]['column'];
-
- $columnDifference = ($braceColumn - $closerColumn);
-
- if ($columnDifference > 2) {
- $error = 'Expected 0 or 1 space between the closing parenthesis and the opening brace; found '.($columnDifference - 1).'.';
- $phpcsFile->addError($error, $openingBrace);
- return;
- }
-
- // Check that a tab was not used instead of a space.
- $spaceTokenPtr = ($tokens[$stackPtr]['parenthesis_closer'] + 1);
- $spaceContent = $tokens[$spaceTokenPtr]['content'];
- if ($columnDifference == 2 && $spaceContent !== ' ') {
- $error = 'Expected a none or a single space character between closing parenthesis and opening brace; found "'.$spaceContent.'".';
- $phpcsFile->addError($error, $openingBrace);
- return;
- }
-
- }//end process()
-
-
-}//end class
-
-?>
diff --git a/_cs/DokuWiki/Sniffs/NamingConventions/ConstructorNameSniff.php b/_cs/DokuWiki/Sniffs/NamingConventions/ConstructorNameSniff.php
deleted file mode 100644
index 7dd6d9366..000000000
--- a/_cs/DokuWiki/Sniffs/NamingConventions/ConstructorNameSniff.php
+++ /dev/null
@@ -1,85 +0,0 @@
-<?php
-/**
- * Generic_Sniffs_NamingConventions_ConstructorNameSniff.
- *
- * PHP version 5
- *
- * @category PHP
- * @package PHP_CodeSniffer
- * @author Greg Sherwood <gsherwood@squiz.net>
- * @author Leif Wickland <lwickland@rightnow.com>
- * @copyright 2006-2011 Squiz Pty Ltd (ABN 77 084 670 600)
- * @license http://matrix.squiz.net/developer/tools/php_cs/licence BSD Licence
- * @link http://pear.php.net/package/PHP_CodeSniffer
- */
-
-if (class_exists('PHP_CodeSniffer_Standards_AbstractScopeSniff', true) === false) {
- $error = 'Class PHP_CodeSniffer_Standards_AbstractScopeSniff not found';
- throw new PHP_CodeSniffer_Exception($error);
-}
-
-/**
- * Generic_Sniffs_NamingConventions_ConstructorNameSniff.
- *
- * Favor PHP 5 constructor syntax, which uses "function __construct()".
- * Avoid PHP 4 constructor syntax, which uses "function ClassName()".
- *
- * @category PHP
- * @package PHP_CodeSniffer
- * @author Leif Wickland <lwickland@rightnow.com>
- * @license http://matrix.squiz.net/developer/tools/php_cs/licence BSD Licence
- * @version Release: 1.3.3
- * @link http://pear.php.net/package/PHP_CodeSniffer
- */
-class DokuWiki_Sniffs_NamingConventions_ConstructorNameSniff extends Generic_Sniffs_NamingConventions_ConstructorNameSniff
-{
- /**
- * Processes this test when one of its tokens is encountered.
- *
- * @param PHP_CodeSniffer_File $phpcsFile The current file being scanned.
- * @param int $stackPtr The position of the current token
- * in the stack passed in $tokens.
- * @param int $currScope A pointer to the start of the scope.
- *
- * @return void
- */
- protected function processTokenWithinScope(
- PHP_CodeSniffer_File $phpcsFile,
- $stackPtr,
- $currScope
- ) {
- $className = $phpcsFile->getDeclarationName($currScope);
- $methodName = $phpcsFile->getDeclarationName($stackPtr);
-
- if (strcasecmp($methodName, $className) === 0) {
- $error = 'PHP4 style constructors are discouraged; use "__construct()" instead';
- $phpcsFile->addWarning($error, $stackPtr, 'OldStyle');
- } else if (strcasecmp($methodName, '__construct') !== 0) {
- // Not a constructor.
- return;
- }
-
- $tokens = $phpcsFile->getTokens();
-
- $parentClassName = $phpcsFile->findExtendedClassName($currScope);
- if ($parentClassName === false) {
- return;
- }
-
- $endFunctionIndex = $tokens[$stackPtr]['scope_closer'];
- $startIndex = $stackPtr;
- while ($doubleColonIndex = $phpcsFile->findNext(array(T_DOUBLE_COLON), $startIndex, $endFunctionIndex)) {
- if ($tokens[($doubleColonIndex + 1)]['code'] === T_STRING
- && $tokens[($doubleColonIndex + 1)]['content'] === $parentClassName
- ) {
- $error = 'PHP4 style calls to parent constructors are discouraged; use "parent::__construct()" instead';
- $phpcsFile->addWarning($error, ($doubleColonIndex + 1), 'OldStyleCall');
- }
-
- $startIndex = ($doubleColonIndex + 1);
- }
-
- }//end processTokenWithinScope()
-
-
-}//end class
diff --git a/_cs/DokuWiki/Sniffs/PHP/DeprecatedFunctionsSniff.php b/_cs/DokuWiki/Sniffs/PHP/DeprecatedFunctionsSniff.php
deleted file mode 100644
index c15a5be02..000000000
--- a/_cs/DokuWiki/Sniffs/PHP/DeprecatedFunctionsSniff.php
+++ /dev/null
@@ -1,62 +0,0 @@
-<?php
-/**
- * DokuWiki_Sniffs_PHP_DiscouragedFunctionsSniff.
- *
- * PHP version 5
- *
- * @category PHP
- * @package PHP_CodeSniffer
- * @author Greg Sherwood <gsherwood@squiz.net>
- * @copyright 2006 Squiz Pty Ltd (ABN 77 084 670 600)
- * @license http://matrix.squiz.net/developer/tools/php_cs/licence BSD Licence
- * @version CVS: $Id: DiscouragedFunctionsSniff.php 265110 2008-08-19 06:36:11Z squiz $
- * @link http://pear.php.net/package/PHP_CodeSniffer
- */
-
-if (class_exists('Generic_Sniffs_PHP_ForbiddenFunctionsSniff', true) === false) {
- throw new PHP_CodeSniffer_Exception('Class Generic_Sniffs_PHP_ForbiddenFunctionsSniff not found');
-}
-
-/**
- * DokuWiki_Sniffs_PHP_DiscouragedFunctionsSniff.
- *
- * @category PHP
- * @package PHP_CodeSniffer
- * @author Greg Sherwood <gsherwood@squiz.net>
- * @copyright 2006 Squiz Pty Ltd (ABN 77 084 670 600)
- * @license http://matrix.squiz.net/developer/tools/php_cs/licence BSD Licence
- * @version Release: 1.2.2
- * @link http://pear.php.net/package/PHP_CodeSniffer
- */
-class DokuWiki_Sniffs_PHP_DeprecatedFunctionsSniff extends Generic_Sniffs_PHP_ForbiddenFunctionsSniff
-{
-
- /**
- * A list of forbidden functions with their alternatives.
- *
- * The value is NULL if no alternative exists. IE, the
- * function should just not be used.
- *
- * @var array(string => string|null)
- */
- public $forbiddenFunctions = array(
- 'setCorrectLocale' => null,
- 'html_attbuild' => 'buildAttributes',
- 'io_runcmd' => null,
- 'p_wiki_xhtml_summary' => 'p_cached_output',
- 'search_callback' => 'call_user_func_array',
- 'search_backlinks' => 'ft_backlinks',
- 'search_fulltext' => 'Fulltext Indexer',
- 'search_regex' => 'Fulltext Indexer',
- 'tpl_getFavicon' => 'tpl_getMediaFile',
- 'p_cached_xhtml' => 'p_cached_output',
- );
-
- /**
- * If true, an error will be thrown; otherwise a warning.
- *
- * @var bool
- */
- public $error = true;
-
-}//end class
diff --git a/_cs/DokuWiki/Sniffs/PHP/DiscouragedFunctionsSniff.php b/_cs/DokuWiki/Sniffs/PHP/DiscouragedFunctionsSniff.php
deleted file mode 100644
index bd51b1166..000000000
--- a/_cs/DokuWiki/Sniffs/PHP/DiscouragedFunctionsSniff.php
+++ /dev/null
@@ -1,54 +0,0 @@
-<?php
-/**
- * DokuWiki_Sniffs_PHP_DiscouragedFunctionsSniff.
- *
- * PHP version 5
- *
- * @category PHP
- * @package PHP_CodeSniffer
- * @author Greg Sherwood <gsherwood@squiz.net>
- * @copyright 2006 Squiz Pty Ltd (ABN 77 084 670 600)
- * @license http://matrix.squiz.net/developer/tools/php_cs/licence BSD Licence
- * @version CVS: $Id: DiscouragedFunctionsSniff.php 265110 2008-08-19 06:36:11Z squiz $
- * @link http://pear.php.net/package/PHP_CodeSniffer
- */
-
-if (class_exists('Generic_Sniffs_PHP_ForbiddenFunctionsSniff', true) === false) {
- throw new PHP_CodeSniffer_Exception('Class Generic_Sniffs_PHP_ForbiddenFunctionsSniff not found');
-}
-
-/**
- * DokuWiki_Sniffs_PHP_DiscouragedFunctionsSniff.
- *
- * @category PHP
- * @package PHP_CodeSniffer
- * @author Greg Sherwood <gsherwood@squiz.net>
- * @copyright 2006 Squiz Pty Ltd (ABN 77 084 670 600)
- * @license http://matrix.squiz.net/developer/tools/php_cs/licence BSD Licence
- * @version Release: 1.2.2
- * @link http://pear.php.net/package/PHP_CodeSniffer
- */
-class DokuWiki_Sniffs_PHP_DiscouragedFunctionsSniff extends Generic_Sniffs_PHP_ForbiddenFunctionsSniff
-{
-
- /**
- * A list of forbidden functions with their alternatives.
- *
- * The value is NULL if no alternative exists. IE, the
- * function should just not be used.
- *
- * @var array(string => string|null)
- */
- public $forbiddenFunctions = array(
- 'date' => 'dformat',
- 'strftime' => 'dformat',
- );
-
- /**
- * If true, an error will be thrown; otherwise a warning.
- *
- * @var bool
- */
- public $error = false;
-
-}//end class
diff --git a/_cs/DokuWiki/Sniffs/WhiteSpace/ScopeIndentSniff.php b/_cs/DokuWiki/Sniffs/WhiteSpace/ScopeIndentSniff.php
deleted file mode 100644
index 72064bda0..000000000
--- a/_cs/DokuWiki/Sniffs/WhiteSpace/ScopeIndentSniff.php
+++ /dev/null
@@ -1,319 +0,0 @@
-<?php
-/**
- * DokuWiki_Sniffs_Whitespace_ScopeIndentSniff based on
- * Generic_Sniffs_Whitespace_ScopeIndentSniff.
- *
- * PHP version 5
- *
- * @category PHP
- * @package PHP_CodeSniffer
- * @author Andreas Gohr <andi@splitbrain.org>
- * @author Greg Sherwood <gsherwood@squiz.net>
- * @author Marc McIntyre <mmcintyre@squiz.net>
- * @copyright 2006 Squiz Pty Ltd (ABN 77 084 670 600)
- * @license http://matrix.squiz.net/developer/tools/php_cs/licence BSD Licence
- * @version CVS: $Id: ScopeIndentSniff.php 270281 2008-12-02 02:38:34Z squiz $
- * @link http://pear.php.net/package/PHP_CodeSniffer
- */
-
-/**
- * Generic_Sniffs_Whitespace_ScopeIndentSniff.
- *
- * Checks that control structures are structured correctly, and their content
- * is indented correctly.
- *
- * @category PHP
- * @package PHP_CodeSniffer
- * @author Greg Sherwood <gsherwood@squiz.net>
- * @author Marc McIntyre <mmcintyre@squiz.net>
- * @copyright 2006 Squiz Pty Ltd (ABN 77 084 670 600)
- * @license http://matrix.squiz.net/developer/tools/php_cs/licence BSD Licence
- * @version Release: 1.2.0
- * @link http://pear.php.net/package/PHP_CodeSniffer
- */
-class DokuWiki_Sniffs_WhiteSpace_ScopeIndentSniff implements PHP_CodeSniffer_Sniff
-{
-
- /**
- * The number of spaces code should be indented.
- *
- * @var int
- */
- protected $indent = 4;
-
- /**
- * Does the indent need to be exactly right.
- *
- * If TRUE, indent needs to be exactly $ident spaces. If FALSE,
- * indent needs to be at least $ident spaces (but can be more).
- *
- * @var bool
- */
- protected $exact = false;
-
- /**
- * Any scope openers that should not cause an indent.
- *
- * @var array(int)
- */
- protected $nonIndentingScopes = array();
-
-
- /**
- * Returns an array of tokens this test wants to listen for.
- *
- * @return array
- */
- public function register()
- {
- return PHP_CodeSniffer_Tokens::$scopeOpeners;
-
- }//end register()
-
-
- /**
- * Processes this test, when one of its tokens is encountered.
- *
- * @param PHP_CodeSniffer_File $phpcsFile All the tokens found in the document.
- * @param int $stackPtr The position of the current token
- * in the stack passed in $tokens.
- *
- * @return void
- */
- public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr)
- {
- $tokens = $phpcsFile->getTokens();
-
- // If this is an inline condition (ie. there is no scope opener), then
- // return, as this is not a new scope.
- if (isset($tokens[$stackPtr]['scope_opener']) === false) {
- return;
- }
-
- if ($tokens[$stackPtr]['code'] === T_ELSE) {
- $next = $phpcsFile->findNext(
- PHP_CodeSniffer_Tokens::$emptyTokens,
- ($stackPtr + 1),
- null,
- true
- );
-
- // We will handle the T_IF token in another call to process.
- if ($tokens[$next]['code'] === T_IF) {
- return;
- }
- }
-
- // Find the first token on this line.
- $firstToken = $stackPtr;
- for ($i = $stackPtr; $i >= 0; $i--) {
- // Record the first code token on the line.
- if (in_array($tokens[$i]['code'], PHP_CodeSniffer_Tokens::$emptyTokens) === false) {
- $firstToken = $i;
- }
-
- // It's the start of the line, so we've found our first php token.
- if ($tokens[$i]['column'] === 1) {
- break;
- }
- }
-
- // Based on the conditions that surround this token, determine the
- // indent that we expect this current content to be.
- $expectedIndent = $this->calculateExpectedIndent($tokens, $firstToken);
-
- if ($tokens[$firstToken]['column'] !== $expectedIndent) {
- if($this->exact || $tokens[$firstToken]['column'] < $expectedIndent){
- $error = 'Line indented incorrectly; expected ';
- $error .= ($expectedIndent - 1).' spaces, found ';
- $error .= ($tokens[$firstToken]['column'] - 1);
- $phpcsFile->addError($error, $stackPtr);
- }elseif((($tokens[$firstToken]['column'] - 1) % $this->indent)){
- $error = 'Line indented not by multiple of '.$this->indent.'; expected ';
- $error .= ($expectedIndent - 1).' spaces, found ';
- $error .= ($tokens[$firstToken]['column'] - 1);
- $phpcsFile->addError($error, $stackPtr);
- }
- }
-
- $scopeOpener = $tokens[$stackPtr]['scope_opener'];
- $scopeCloser = $tokens[$stackPtr]['scope_closer'];
-
- // Some scopes are expected not to have indents.
- if (in_array($tokens[$firstToken]['code'], $this->nonIndentingScopes) === false) {
- $indent = ($expectedIndent + $this->indent);
- } else {
- $indent = $expectedIndent;
- }
-
- $newline = false;
- $commentOpen = false;
- $inHereDoc = false;
-
- // Only loop over the content beween the opening and closing brace, not
- // the braces themselves.
- for ($i = ($scopeOpener + 1); $i < $scopeCloser; $i++) {
-
- // If this token is another scope, skip it as it will be handled by
- // another call to this sniff.
- if (in_array($tokens[$i]['code'], PHP_CodeSniffer_Tokens::$scopeOpeners) === true) {
- if (isset($tokens[$i]['scope_opener']) === true) {
- $i = $tokens[$i]['scope_closer'];
- } else {
- // If this token does not have a scope_opener indice, then
- // it's probably an inline scope, so let's skip to the next
- // semicolon. Inline scopes include inline if's, abstract
- // methods etc.
- $nextToken = $phpcsFile->findNext(T_SEMICOLON, $i, $scopeCloser);
- if ($nextToken !== false) {
- $i = $nextToken;
- }
- }
-
- continue;
- }
-
- // If this is a HEREDOC then we need to ignore it as the
- // whitespace before the contents within the HEREDOC are
- // considered part of the content.
- if ($tokens[$i]['code'] === T_START_HEREDOC) {
- $inHereDoc = true;
- continue;
- } else if ($inHereDoc === true) {
- if ($tokens[$i]['code'] === T_END_HEREDOC) {
- $inHereDoc = false;
- }
-
- continue;
- }
-
- if ($tokens[$i]['column'] === 1) {
- // We started a newline.
- $newline = true;
- }
-
- if ($newline === true && $tokens[$i]['code'] !== T_WHITESPACE) {
- // If we started a newline and we find a token that is not
- // whitespace, then this must be the first token on the line that
- // must be indented.
- $newline = false;
- $firstToken = $i;
-
- $column = $tokens[$firstToken]['column'];
-
- // Special case for non-PHP code.
- if ($tokens[$firstToken]['code'] === T_INLINE_HTML) {
- $trimmedContentLength
- = strlen(ltrim($tokens[$firstToken]['content']));
- if ($trimmedContentLength === 0) {
- continue;
- }
-
- $contentLength = strlen($tokens[$firstToken]['content']);
- $column = ($contentLength - $trimmedContentLength + 1);
- }
-
- // Check to see if this constant string spans multiple lines.
- // If so, then make sure that the strings on lines other than the
- // first line are indented appropriately, based on their whitespace.
- if (in_array($tokens[$firstToken]['code'], PHP_CodeSniffer_Tokens::$stringTokens) === true) {
- if (in_array($tokens[($firstToken - 1)]['code'], PHP_CodeSniffer_Tokens::$stringTokens) === true) {
- // If we find a string that directly follows another string
- // then its just a string that spans multiple lines, so we
- // don't need to check for indenting.
- continue;
- }
- }
-
- // This is a special condition for T_DOC_COMMENT and C-style
- // comments, which contain whitespace between each line.
- $comments = array(
- T_COMMENT,
- T_DOC_COMMENT
- );
-
- if (in_array($tokens[$firstToken]['code'], $comments) === true) {
- $content = trim($tokens[$firstToken]['content']);
- if (preg_match('|^/\*|', $content) !== 0) {
- // Check to see if the end of the comment is on the same line
- // as the start of the comment. If it is, then we don't
- // have to worry about opening a comment.
- if (preg_match('|\*/$|', $content) === 0) {
- // We don't have to calculate the column for the
- // start of the comment as there is a whitespace
- // token before it.
- $commentOpen = true;
- }
- } else if ($commentOpen === true) {
- if ($content === '') {
- // We are in a comment, but this line has nothing on it
- // so let's skip it.
- continue;
- }
-
- $contentLength = strlen($tokens[$firstToken]['content']);
- $trimmedContentLength
- = strlen(ltrim($tokens[$firstToken]['content']));
-
- $column = ($contentLength - $trimmedContentLength + 1);
- if (preg_match('|\*/$|', $content) !== 0) {
- $commentOpen = false;
- }
- }//end if
- }//end if
-
- // The token at the start of the line, needs to have its' column
- // greater than the relative indent we set above. If it is less,
- // an error should be shown.
- if ($column !== $indent) {
- if ($this->exact === true || $column < $indent) {
- $error = 'Line indented incorrectly; expected ';
- if ($this->exact === false) {
- $error .= 'at least ';
- }
-
- $error .= ($indent - 1).' spaces, found ';
- $error .= ($column - 1);
- $phpcsFile->addError($error, $firstToken);
- }
- }
- }//end if
- }//end for
-
- }//end process()
-
-
- /**
- * Calculates the expected indent of a token.
- *
- * @param array $tokens The stack of tokens for this file.
- * @param int $stackPtr The position of the token to get indent for.
- *
- * @return int
- */
- protected function calculateExpectedIndent(array $tokens, $stackPtr)
- {
- $conditionStack = array();
-
- // Empty conditions array (top level structure).
- if (empty($tokens[$stackPtr]['conditions']) === true) {
- return 1;
- }
-
- $tokenConditions = $tokens[$stackPtr]['conditions'];
- foreach ($tokenConditions as $id => $condition) {
- // If it's an indenting scope ie. it's not in our array of
- // scopes that don't indent, add it to our condition stack.
- if (in_array($condition, $this->nonIndentingScopes) === false) {
- $conditionStack[$id] = $condition;
- }
- }
-
- return ((count($conditionStack) * $this->indent) + 1);
-
- }//end calculateExpectedIndent()
-
-
-}//end class
-
-?>
diff --git a/_cs/DokuWiki/ruleset.xml b/_cs/DokuWiki/ruleset.xml
deleted file mode 100644
index 3ee7fb667..000000000
--- a/_cs/DokuWiki/ruleset.xml
+++ /dev/null
@@ -1,69 +0,0 @@
-<?xml version="1.0"?>
-<ruleset name="DokuWiki">
- <description>DokuWiki Coding Standard</description>
-
- <!-- ignore 3rd party libraries (that we haven't adopted) -->
- <exclude-pattern>*/inc/blowfish.php</exclude-pattern>
- <exclude-pattern>*/inc/lessc.inc.php</exclude-pattern>
- <exclude-pattern>*/inc/phpseclib/*</exclude-pattern>
- <exclude-pattern>*/lib/plugins/authad/adLDAP/*</exclude-pattern>
- <exclude-pattern>*/lib/scripts/fileuploader.js</exclude-pattern>
- <exclude-pattern>*/lib/scripts/jquery/*</exclude-pattern>
- <exclude-pattern>*/EmailAddressValidator.php</exclude-pattern>
- <exclude-pattern>*/feedcreator.class.php</exclude-pattern>
- <exclude-pattern>*/SimplePie.php</exclude-pattern>
- <exclude-pattern>*/geshi.php</exclude-pattern>
- <exclude-pattern>*/geshi/*</exclude-pattern>
- <exclude-pattern>*/JSON.php</exclude-pattern>
-
- <!-- ignore devel only parts -->
- <exclude-pattern>*/_test/*</exclude-pattern>
- <exclude-pattern>*/_cs/*</exclude-pattern>
-
- <rule ref="Generic.Classes.DuplicateClassName" />
- <rule ref="Generic.CodeAnalysis.JumbledIncrementer" />
- <rule ref="Generic.CodeAnalysis.UnnecessaryFinalModifier" />
- <rule ref="Generic.CodeAnalysis.UnconditionalIfStatement" />
- <rule ref="Generic.CodeAnalysis.ForLoopShouldBeWhileLoop" />
- <rule ref="Generic.CodeAnalysis.ForLoopWithTestFunctionCall" />
- <rule ref="Generic.CodeAnalysis.UnusedFunctionParameter" />
- <rule ref="Generic.CodeAnalysis.EmptyStatement" />
- <rule ref="Generic.CodeAnalysis.UselessOverridingMethod" />
- <rule ref="Generic.Commenting.Todo" />
- <rule ref="Generic.Files.ByteOrderMark" />
- <rule ref="Generic.Files.LineEndings" />
- <rule ref="Generic.Formatting.DisallowMultipleStatements" />
- <rule ref="Generic.Metrics.NestingLevel">
- <properties>
- <property name="nestingLevel" value="6" />
- </properties>
- </rule>
- <rule ref="Generic.NamingConventions.UpperCaseConstantName" />
- <rule ref="Generic.PHP.LowerCaseConstant" />
- <rule ref="Generic.PHP.DeprecatedFunctions.php" />
- <rule ref="Generic.PHP.DisallowShortOpenTag" />
- <rule ref="Generic.PHP.ForbiddenFunctions" />
- <rule ref="Generic.WhiteSpace.DisallowTabIndent" />
- <rule ref="Generic.Classes.DuplicateClassName" />
- <rule ref="Generic.Functions.CallTimePassByReference" />
- <rule ref="Zend.Files.ClosingTag" />
- <rule ref="PEAR.Functions.ValidDefaultValue" />
- <rule ref="Squiz.PHP.Eval" />
- <rule ref="Squiz.WhiteSpace.SuperfluousWhitespace" />
- <rule ref="Squiz.CSS.LowercaseStyleDefinition" />
- <rule ref="Squiz.CSS.MissingColon" />
- <rule ref="Squiz.CSS.DisallowMultipleStyleDefinitions" />
- <rule ref="Squiz.CSS.ColonSpacing" />
- <rule ref="Squiz.CSS.ClassDefinitionClosingBraceSpace" />
- <rule ref="Squiz.CSS.SemicolonSpacing" />
- <rule ref="Squiz.CSS.Indentation" />
- <rule ref="Squiz.CSS.EmptyClassDefinition" />
- <rule ref="Squiz.CSS.ClassDefinitionNameSpacing" />
- <rule ref="Squiz.CSS.EmptyStyleDefinition" />
- <rule ref="Squiz.CSS.Opacity" />
- <rule ref="Squiz.CSS.ColourDefinition" />
- <rule ref="Squiz.CSS.DuplicateClassDefinition" />
- <rule ref="Squiz.CSS.ClassDefinitionOpeningBraceSpace" />
- <rule ref="Squiz.Commenting.DocCommentAlignment" />
-
-</ruleset>
diff --git a/_cs/README b/_cs/README
deleted file mode 100644
index 7aac73161..000000000
--- a/_cs/README
+++ /dev/null
@@ -1,18 +0,0 @@
-This directory contains the Coding Standard tests to be used with PHP
-CodeSniffer on DokuWiki's code.
-
-1. Install PHP CodeSniffer:
-
- #> pear install PHP_CodeSniffer
-
-2. Link the Coding Standard to the CodeSniffer directory:
-
- #> ln -s /path/to/dokuwiki/_cs/DokuWiki /usr/share/pear/PHP/CodeSniffer/Standards/DokuWiki
-
-3. Set DokuWiki to be the default standard:
-
- #> phpcs --config-set default_standard DokuWiki
-
-
-
-The coding standard is work in progress.
diff --git a/_test/core/DokuWikiTest.php b/_test/core/DokuWikiTest.php
index 80fdb4ac0..6e8049450 100644
--- a/_test/core/DokuWikiTest.php
+++ b/_test/core/DokuWikiTest.php
@@ -1,4 +1,9 @@
<?php
+
+use dokuwiki\Extension\PluginController;
+use dokuwiki\Extension\Event;
+use dokuwiki\Extension\EventHandler;
+
if(!class_exists('PHPUnit_Framework_TestCase')) {
/**
* phpunit 5/6 compatibility
@@ -103,7 +108,7 @@ abstract class DokuWikiTest extends PHPUnit_Framework_TestCase {
// reset loaded plugins
global $plugin_controller_class, $plugin_controller;
- /** @var Doku_Plugin_Controller $plugin_controller */
+ /** @var PluginController $plugin_controller */
$plugin_controller = new $plugin_controller_class();
// disable all non-default plugins
@@ -133,14 +138,14 @@ abstract class DokuWikiTest extends PHPUnit_Framework_TestCase {
// reset event handler
global $EVENT_HANDLER;
- $EVENT_HANDLER = new Doku_Event_Handler();
+ $EVENT_HANDLER = new EventHandler();
// reload language
$local = $conf['lang'];
- trigger_event('INIT_LANG_LOAD', $local, 'init_lang', true);
+ Event::createAndTrigger('INIT_LANG_LOAD', $local, 'init_lang', true);
global $INPUT;
- $INPUT = new Input();
+ $INPUT = new \dokuwiki\Input\Input();
}
/**
@@ -234,4 +239,41 @@ abstract class DokuWikiTest extends PHPUnit_Framework_TestCase {
$method->setAccessible(true);
return $method->invokeArgs($obj, $args);
}
+
+ /**
+ * Allow for reading inaccessible properties (private or protected)
+ *
+ * This makes it easier to check internals of tested objects. This should generally
+ * be avoided.
+ *
+ * @param object $obj Object on which to access the property
+ * @param string $prop name of the property to access
+ * @return mixed
+ * @throws ReflectionException when the given obj/prop does not exist
+ */
+ protected static function getInaccessibleProperty($obj, $prop) {
+ $class = new \ReflectionClass($obj);
+ $property = $class->getProperty($prop);
+ $property->setAccessible(true);
+ return $property->getValue($obj);
+ }
+
+ /**
+ * Allow for reading inaccessible properties (private or protected)
+ *
+ * This makes it easier to set internals of tested objects. This should generally
+ * be avoided.
+ *
+ * @param object $obj Object on which to access the property
+ * @param string $prop name of the property to access
+ * @param mixed $value new value to set the property to
+ * @return void
+ * @throws ReflectionException when the given obj/prop does not exist
+ */
+ protected static function setInaccessibleProperty($obj, $prop, $value) {
+ $class = new \ReflectionClass($obj);
+ $property = $class->getProperty($prop);
+ $property->setAccessible(true);
+ $property->setValue($obj, $value);
+ }
}
diff --git a/_test/core/TestRequest.php b/_test/core/TestRequest.php
index fcc80328c..23ca76eec 100644
--- a/_test/core/TestRequest.php
+++ b/_test/core/TestRequest.php
@@ -4,6 +4,8 @@
* runtime inspection.
*/
+use dokuwiki\Input\Input;
+
/**
* Helper class to execute a fake request
*/
diff --git a/_test/mock/AuthPlugin.php b/_test/mock/AuthPlugin.php
new file mode 100644
index 000000000..53edb2fe1
--- /dev/null
+++ b/_test/mock/AuthPlugin.php
@@ -0,0 +1,10 @@
+<?php
+
+namespace dokuwiki\test\mock;
+
+/**
+ * Class dokuwiki\Plugin\DokuWiki_Auth_Plugin
+ */
+class AuthPlugin extends \dokuwiki\Extension\AuthPlugin {
+
+}
diff --git a/_test/mock/Doku_Renderer.php b/_test/mock/Doku_Renderer.php
new file mode 100644
index 000000000..350346101
--- /dev/null
+++ b/_test/mock/Doku_Renderer.php
@@ -0,0 +1,11 @@
+<?php
+
+namespace dokuwiki\test\mock;
+
+class Doku_Renderer extends \Doku_Renderer {
+
+ /** @inheritdoc */
+ public function getFormat() {
+ return 'none';
+ }
+}
diff --git a/_test/mock/MailerMock.php b/_test/mock/MailerMock.php
new file mode 100644
index 000000000..9d93bc25a
--- /dev/null
+++ b/_test/mock/MailerMock.php
@@ -0,0 +1,16 @@
+<?php
+
+namespace dokuwiki\test\mock;
+
+class MailerMock extends \Mailer
+{
+
+ public $mails = [];
+
+ public function send()
+ {
+ $this->mails[] = $this->headers;
+ return true;
+ }
+
+}
diff --git a/_test/phpcs.xml b/_test/phpcs.xml
new file mode 100644
index 000000000..4f38195a3
--- /dev/null
+++ b/_test/phpcs.xml
@@ -0,0 +1,98 @@
+<?xml version="1.0"?>
+<ruleset name="DokuWiki Coding Standard Standard" namespace="DokuWiki\CS\Standard">
+ <description>Coding Standard used for DokuWiki</description>
+
+ <!-- default config -->
+ <arg name="colors"/>
+ <arg value="sp"/>
+ <arg name="extensions" value="php"/>
+
+ <ini name="memory_limit" value="-1"/>
+
+ <!-- where to look -->
+ <file>../inc</file>
+ <file>../lib</file>
+ <file>../bin</file>
+ <file>../doku.php</file>
+ <file>../index.php</file>
+ <file>../feed.php</file>
+ <file>../install.php</file>
+
+ <!-- skip these completely -->
+ <exclude-pattern>*/lang/*/lang.php</exclude-pattern>
+ <exclude-pattern>*/lang/*/settings.php</exclude-pattern>
+ <exclude-pattern>*/_test/*</exclude-pattern>
+
+ <!-- 3rd party libs, these should be moved to composer some day -->
+ <exclude-pattern>*/inc/DifferenceEngine.php</exclude-pattern>
+ <exclude-pattern>*/inc/IXR_Library.php</exclude-pattern>
+ <exclude-pattern>*/inc/JSON.php</exclude-pattern>
+ <exclude-pattern>*/inc/JpegMeta.php</exclude-pattern>
+ <exclude-pattern>*/lib/plugins/authad/adLDAP</exclude-pattern>
+
+ <!-- deprecated files to be removed soon -->
+ <exclude-pattern>*/inc/cli.php</exclude-pattern>
+ <exclude-pattern>*/inc/parser/*</exclude-pattern>
+
+ <!-- rules on top of PSR-2 -->
+ <rule ref="PSR2">
+ <!-- the following rule is not in PSR-2 and breaks the guardian pattern -->
+ <exclude name="Generic.ControlStructures.InlineControlStructure.NotAllowed"/>
+
+ <!-- we have lots of legacy classes without name spaces -->
+ <exclude name="PSR1.Classes.ClassDeclaration.MissingNamespace"/>
+ </rule>
+
+ <!-- disable some rules for certain paths, for legacy support -->
+ <rule ref="Squiz.Classes.ValidClassName.NotCamelCaps">
+ <exclude-pattern>*/inc/Plugin.php</exclude-pattern>
+ <exclude-pattern>*/inc/PluginInterface.php</exclude-pattern>
+ <exclude-pattern>*/inc/PluginTrait.php</exclude-pattern>
+
+ <exclude-pattern>*/lib/plugins/*.php</exclude-pattern>
+ <exclude-pattern>*/lib/plugins/*/action.php</exclude-pattern>
+ <exclude-pattern>*/lib/plugins/*/action/*.php</exclude-pattern>
+ <exclude-pattern>*/lib/plugins/*/admin.php</exclude-pattern>
+ <exclude-pattern>*/lib/plugins/*/admin/*.php</exclude-pattern>
+ <exclude-pattern>*/lib/plugins/*/auth.php</exclude-pattern>
+ <exclude-pattern>*/lib/plugins/*/auth/*.php</exclude-pattern>
+ <exclude-pattern>*/lib/plugins/*/cli.php</exclude-pattern>
+ <exclude-pattern>*/lib/plugins/*/cli/*.php</exclude-pattern>
+ <exclude-pattern>*/lib/plugins/*/helper.php</exclude-pattern>
+ <exclude-pattern>*/lib/plugins/*/helper/*.php</exclude-pattern>
+ <exclude-pattern>*/lib/plugins/*/remote.php</exclude-pattern>
+ <exclude-pattern>*/lib/plugins/*/remote/*.php</exclude-pattern>
+ <exclude-pattern>*/lib/plugins/*/syntax.php</exclude-pattern>
+ <exclude-pattern>*/lib/plugins/*/syntax/*.php</exclude-pattern>
+ </rule>
+
+ <!-- underscore skips exposing public methods to remote api -->
+ <rule ref="PSR2.Methods.MethodDeclaration.Underscore">
+ <exclude-pattern>*/inc/Extension/RemotePlugin.php</exclude-pattern>
+ <exclude-pattern>*/lib/plugins/*/remote.php</exclude-pattern>
+ <exclude-pattern>*/lib/plugins/*/remote/*.php</exclude-pattern>
+ </rule>
+
+ <rule ref="PSR1.Methods.CamelCapsMethodName.NotCamelCaps">
+ <exclude-pattern>*/inc/Extension/PluginInterface.php</exclude-pattern>
+ <exclude-pattern>*/inc/Extension/PluginTrait.php</exclude-pattern>
+ </rule>
+
+ <!-- for now we mix declarations and execution here (mostly for defines) -->
+ <rule ref="PSR1.Files.SideEffects">
+ <exclude-pattern>*/index.php</exclude-pattern>
+ <exclude-pattern>*/inc/parserutils.php</exclude-pattern>
+ <exclude-pattern>*/inc/mail.php</exclude-pattern>
+ <exclude-pattern>*/inc/init.php</exclude-pattern>
+ <exclude-pattern>*/inc/fulltext.php</exclude-pattern>
+ <exclude-pattern>*/inc/Mailer.class.php</exclude-pattern>
+ <exclude-pattern>*/doku.php</exclude-pattern>
+ <exclude-pattern>*/install.php</exclude-pattern>
+ <exclude-pattern>*/inc/utf8.php</exclude-pattern>
+ <exclude-pattern>*/feed.php</exclude-pattern>
+ <exclude-pattern>*/inc/load.php</exclude-pattern>
+ <exclude-pattern>*/bin/*.php</exclude-pattern>
+ <exclude-pattern>*/lib/exe/*.php</exclude-pattern>
+ </rule>
+
+</ruleset>
diff --git a/_test/phpunit.xml b/_test/phpunit.xml
index f4b88be9c..c450cea95 100644
--- a/_test/phpunit.xml
+++ b/_test/phpunit.xml
@@ -10,12 +10,15 @@
<testsuites>
<testsuite name="DokuWiki Tests">
<directory suffix=".test.php">tests/</directory>
+ <directory suffix="Test.php">tests/</directory>
</testsuite>
<testsuite name="Plugin Tests">
- <directory suffix=".test.php">../lib/plugins/*/_test</directory>
+ <directory suffix=".test.php">../lib/plugins/*/_test/</directory>
+ <directory suffix="Test.php">../lib/plugins/*/_test/</directory>
</testsuite>
<testsuite name="Template Tests">
- <directory suffix=".test.php">../lib/tpl/*/_test</directory>
+ <directory suffix=".test.php">../lib/tpl/*/_test/</directory>
+ <directory suffix="Test.php">../lib/tpl/*/_test/</directory>
</testsuite>
</testsuites>
diff --git a/_test/tests/inc/PageUtilsIsHiddenPage.test.php b/_test/tests/inc/PageUtilsIsHiddenPage.test.php
index a7077862e..09ab78e1b 100644
--- a/_test/tests/inc/PageUtilsIsHiddenPage.test.php
+++ b/_test/tests/inc/PageUtilsIsHiddenPage.test.php
@@ -41,7 +41,7 @@ class PageUtilsIsHiddenPageTest extends DokuWikiTest {
$this->assertTrue(isHiddenPage('another'));
}
- function alwaysHide(Doku_Event &$event, $params) {
+ function alwaysHide(Doku_Event $event, $params) {
$event->data['hidden'] = true;
}
@@ -53,7 +53,7 @@ class PageUtilsIsHiddenPageTest extends DokuWikiTest {
$this->assertFalse(isHiddenPage('test'));
}
- function showBefore(Doku_Event &$event, $params) {
+ function showBefore(Doku_Event $event, $params) {
$event->data['hidden'] = false;
$event->preventDefault();
$event->stopPropagation();
@@ -75,7 +75,7 @@ class PageUtilsIsHiddenPageTest extends DokuWikiTest {
$this->assertTrue(isHiddenPage('another'));
}
- function hideBeforeWithoutPrevent(Doku_Event &$event, $params) {
+ function hideBeforeWithoutPrevent(Doku_Event $event, $params) {
$event->data['hidden'] = true;
}
@@ -87,7 +87,7 @@ class PageUtilsIsHiddenPageTest extends DokuWikiTest {
$this->assertFalse(isHiddenPage('test'));
}
- function showAfter(Doku_Event &$event, $params) {
+ function showAfter(Doku_Event $event, $params) {
$event->data['hidden'] = false;
}
diff --git a/_test/tests/inc/PassHash.test.php b/_test/tests/inc/PassHash.test.php
index 1bc4b95bc..2c8dc1c39 100644
--- a/_test/tests/inc/PassHash.test.php
+++ b/_test/tests/inc/PassHash.test.php
@@ -1,5 +1,7 @@
<?php
+use dokuwiki\PassHash;
+
/**
* Class PassHash_test
*
diff --git a/_test/tests/inc/Subscriptions/BulkSubscriptionsSenderTest.php b/_test/tests/inc/Subscriptions/BulkSubscriptionsSenderTest.php
new file mode 100644
index 000000000..3bc6a9c2f
--- /dev/null
+++ b/_test/tests/inc/Subscriptions/BulkSubscriptionsSenderTest.php
@@ -0,0 +1,110 @@
+<?php
+
+namespace tests\inc\Subscriptions;
+
+use dokuwiki\Subscriptions\BulkSubscriptionSender;
+use dokuwiki\Subscriptions\SubscriberManager;
+use dokuwiki\test\mock\MailerMock;
+use DokuWikiTest;
+
+class BulkSubscriptionsSenderTest extends DokuWikiTest
+{
+
+ private $originalSubscriptionConfig;
+
+ public function setUp()
+ {
+ parent::setUp();
+ global $conf;
+ $this->originalSubscriptionConfig = $conf['subscribers'];
+ $conf['subscribers'] = true;
+ }
+
+ protected function tearDown()
+ {
+ global $conf;
+ $conf['subscribers'] = $this->originalSubscriptionConfig;
+ parent::tearDown();
+ }
+
+ public function testBulkdigest()
+ {
+ $mailerMock = new MailerMock();
+ $sub = new BulkSubscriptionSender($mailerMock);
+ $manager = new SubscriberManager();
+
+ // let's start with nothing
+ $this->assertEquals(0, $sub->sendBulk('sub1:test'));
+
+ // create a subscription
+ $manager->add('sub1:', 'testuser', 'digest', '978328800'); // last mod 2001-01-01
+
+ // now create change
+ $_SERVER['REMOTE_USER'] = 'someguy';
+ saveWikiText('sub1:test', 'foo bar', 'a subscription change', false);
+
+ // should trigger a mail
+ $this->assertEquals(1, $sub->sendBulk('sub1:test'));
+ $this->assertEquals(['arthur@example.com'], array_column($mailerMock->mails, 'Bcc'));
+
+ $mailerMock->mails = [];
+
+ // now create more changes
+ $_SERVER['REMOTE_USER'] = 'someguy';
+ saveWikiText('sub1:sub2:test', 'foo bar', 'a subscription change', false);
+ saveWikiText('sub1:another_test', 'foo bar', 'a subscription change', false);
+
+ // should not trigger a mail, because the subscription time has not been reached, yet
+ $this->assertEquals(0, $sub->sendBulk('sub1:test'));
+ $this->assertEquals([], array_column($mailerMock->mails, 'Bcc'));
+
+ // reset the subscription time
+ $manager->add('sub1:', 'testuser', 'digest', '978328800'); // last mod 2001-01-01
+
+ // we now should get mails for three changes
+ $this->assertEquals(3, $sub->sendBulk('sub1:test'));
+ $this->assertEquals(
+ ['arthur@example.com', 'arthur@example.com', 'arthur@example.com'],
+ array_column($mailerMock->mails, 'Bcc')
+ );
+ }
+
+ public function testBulklist()
+ {
+ $mailerMock = new MailerMock();
+ $sub = new BulkSubscriptionSender($mailerMock);
+ $manager = new SubscriberManager();
+
+ // let's start with nothing
+ $this->assertEquals(0, $sub->sendBulk('sub1:test'));
+
+ // create a subscription
+ $manager->add('sub1:', 'testuser', 'list', '978328800'); // last mod 2001-01-01
+
+ // now create change
+ $_SERVER['REMOTE_USER'] = 'someguy';
+ saveWikiText('sub1:test', 'foo bar', 'a subscription change', false);
+
+ // should trigger a mail
+ $this->assertEquals(1, $sub->sendBulk('sub1:test'));
+ $this->assertEquals(['arthur@example.com'], array_column($mailerMock->mails, 'Bcc'));
+
+ $mailerMock->mails = [];
+
+ // now create more changes
+ $_SERVER['REMOTE_USER'] = 'someguy';
+ saveWikiText('sub1:sub2:test', 'foo bar', 'a subscription change', false);
+ saveWikiText('sub1:another_test', 'foo bar', 'a subscription change', false);
+
+ // should not trigger a mail, because the subscription time has not been reached, yet
+ $this->assertEquals(0, $sub->sendBulk('sub1:test'));
+ $this->assertEquals([], array_column($mailerMock->mails, 'Bcc'));
+
+ // reset the subscription time
+ $manager->add('sub1:', 'testuser', 'list', '978328800'); // last mod 2001-01-01
+
+ // we now should get a single mail for all three changes
+ $this->assertEquals(1, $sub->sendBulk('sub1:test'));
+ $this->assertEquals(['arthur@example.com'], array_column($mailerMock->mails, 'Bcc'));
+ }
+}
diff --git a/_test/tests/inc/Subscriptions/SubscriberManagerTest.php b/_test/tests/inc/Subscriptions/SubscriberManagerTest.php
new file mode 100644
index 000000000..1fcd7c84b
--- /dev/null
+++ b/_test/tests/inc/Subscriptions/SubscriberManagerTest.php
@@ -0,0 +1,131 @@
+<?php
+
+namespace tests\inc\Subscriptions;
+
+use dokuwiki\Subscriptions\SubscriberManager;
+use DokuWikiTest;
+
+class SubscriberManagerTest extends DokuWikiTest
+{
+ private $originalSubscriptionConfig;
+
+ public function setUp()
+ {
+ parent::setUp();
+ global $conf;
+ $this->originalSubscriptionConfig = $conf['subscribers'];
+ $conf['subscribers'] = true;
+ }
+
+ protected function tearDown()
+ {
+ global $conf;
+ $conf['subscribers'] = $this->originalSubscriptionConfig;
+ parent::tearDown();
+ }
+
+ public function testAddremove()
+ {
+ $sub = new SubscriberManager();
+
+ // no subscriptions
+ $this->assertArrayNotHasKey(
+ 'wiki:dokuwiki',
+ $sub->subscribers('wiki:dokuwiki', null, ['every', 'list', 'digest'])
+ );
+
+ // add page subscription
+ $sub->add('wiki:dokuwiki', 'testuser', 'every');
+
+ // one subscription
+ $this->assertArrayHasKey(
+ 'wiki:dokuwiki',
+ $sub->subscribers('wiki:dokuwiki', null, ['every', 'list', 'digest'])
+ );
+
+ // remove page subscription
+ $sub->remove('wiki:dokuwiki', 'testuser');
+
+ // no subscription
+ $this->assertArrayNotHasKey(
+ 'wiki:dokuwiki',
+ $sub->subscribers('wiki:dokuwiki', null, ['every', 'list', 'digest'])
+ );
+
+ // add namespace subscription
+ $sub->add('wiki:', 'testuser', 'every');
+
+ // one subscription
+ $this->assertArrayHasKey(
+ 'wiki:',
+ $sub->subscribers('wiki:dokuwiki', null, ['every', 'list', 'digest'])
+ );
+
+ // remove (non existing) page subscription
+ $sub->remove('wiki:dokuwiki', 'testuser');
+
+ // still one subscription
+ $this->assertArrayHasKey(
+ 'wiki:',
+ $sub->subscribers('wiki:dokuwiki', null, ['every', 'list', 'digest'])
+ );
+
+ // change namespace subscription
+ $sub->add('wiki:', 'testuser', 'digest', '1234567');
+
+ // still one subscription
+ $this->assertArrayHasKey(
+ 'wiki:',
+ $sub->subscribers('wiki:dokuwiki', null, ['every', 'list', 'digest'])
+ );
+
+ // check contents
+ $this->assertEquals(
+ ['wiki:' => ['testuser' => ['digest', '1234567']]],
+ $sub->subscribers('wiki:dokuwiki', null, ['every', 'list', 'digest'])
+ );
+
+ // change subscription data
+ $sub->add('wiki:', 'testuser', 'digest', '7654321');
+
+ // still one subscription
+ $this->assertArrayHasKey(
+ 'wiki:',
+ $sub->subscribers('wiki:dokuwiki', null, ['every', 'list', 'digest'])
+ );
+
+ // check contents
+ $this->assertEquals(
+ ['wiki:' => ['testuser' => ['digest', '7654321']]],
+ $sub->subscribers('wiki:dokuwiki', null, ['every', 'list', 'digest'])
+ );
+ }
+
+ /**
+ * Tests, if overwriting subscriptions works even when subscriptions for the same
+ * user exist for two nested namespaces, this is a test for the bug described in FS#2580
+ */
+ public function testOverwrite()
+ {
+ $sub = new SubscriberManager();
+
+ $sub->add(':', 'admin', 'digest', '123456789');
+ $sub->add(':wiki:', 'admin', 'digest', '123456789');
+ $sub->add(':', 'admin', 'digest', '1234');
+ $sub->add(':wiki:', 'admin', 'digest', '1234');
+
+ $subscriptions = $sub->subscribers(':wiki:', 'admin');
+
+ $this->assertCount(
+ 1,
+ $subscriptions[':'],
+ 'More than one subscription saved for the root namespace even though the old one should have been overwritten.'
+ );
+ $this->assertCount(
+ 1,
+ $subscriptions[':wiki:'],
+ 'More than one subscription saved for the wiki namespace even though the old one should have been overwritten.'
+ );
+ $this->assertCount(2, $subscriptions, 'Didn\'t find the expected two subscriptions');
+ }
+}
diff --git a/_test/tests/inc/Subscriptions/SubscriberRegexBuilderTest.php b/_test/tests/inc/Subscriptions/SubscriberRegexBuilderTest.php
new file mode 100644
index 000000000..f9b22724d
--- /dev/null
+++ b/_test/tests/inc/Subscriptions/SubscriberRegexBuilderTest.php
@@ -0,0 +1,52 @@
+<?php
+
+namespace tests\inc\Subscriptions;
+
+use dokuwiki\Subscriptions\SubscriberRegexBuilder;
+use DokuWikiTest;
+
+class SubscriberRegexBuilderTest extends DokuWikiTest
+{
+
+ public function regexTestdataProvider()
+ {
+ return [
+ ['Cold Fusion', null, null, 1],
+ ['casper', null, null, 1],
+ ['nope', null, null, 0],
+ ['lights', null, null, 0],
+ [['Cold Fusion', 'casper', 'nope'], null, null, 2],
+ [null, 'list', null, 1],
+ [null, 'every', null, 2],
+ [null, 'digest', null, 3],
+ [null, ['list', 'every'], null, 3],
+ ['casper', 'digest', null, 0],
+ ['casper', ['digest', 'every'], null, 1],
+ ['zioth', 'list', '1344691369', 1],
+ ['zioth', null, '1344691369', 1],
+ ['zioth', 'digest', '1344691369', 0],
+ ];
+ }
+
+ /**
+ * @dataProvider regexTestdataProvider
+ */
+ public function testRegexp($user, $style, $inputData, $expectedNumResults)
+ {
+ // data to test against
+ $data = [
+ "casper every\n",
+ "Andreas digest 1344689733",
+ "Cold%20Fusion every",
+ "zioth list 1344691369\n",
+ "nlights digest",
+ "rikblok\tdigest \t 1344716803",
+ ];
+
+ $sub = new SubscriberRegexBuilder();
+ $re = $sub->buildRegex($user, $style, $inputData);
+ $this->assertFalse(empty($re));
+ $result = preg_grep($re, $data);
+ $this->assertEquals($expectedNumResults, count($result));
+ }
+}
diff --git a/_test/tests/inc/auth_aclcheck.test.php b/_test/tests/inc/auth_aclcheck.test.php
index 8c9b37536..2b5342e43 100644
--- a/_test/tests/inc/auth_aclcheck.test.php
+++ b/_test/tests/inc/auth_aclcheck.test.php
@@ -1,5 +1,7 @@
<?php
+use dokuwiki\test\mock\AuthPlugin;
+
class auth_acl_test extends DokuWikiTest {
protected $oldAuthAcl;
@@ -9,7 +11,7 @@ class auth_acl_test extends DokuWikiTest {
global $AUTH_ACL;
global $auth;
$this->oldAuthAcl = $AUTH_ACL;
- $auth = new DokuWiki_Auth_Plugin();
+ $auth = new AuthPlugin();
}
function tearDown() {
diff --git a/_test/tests/inc/auth_aclcheck_caseinsensitive.test.php b/_test/tests/inc/auth_aclcheck_caseinsensitive.test.php
index 21b2cfdb0..644675de4 100644
--- a/_test/tests/inc/auth_aclcheck_caseinsensitive.test.php
+++ b/_test/tests/inc/auth_aclcheck_caseinsensitive.test.php
@@ -1,6 +1,8 @@
<?php
-class auth_acl_caseinsensitive_auth extends DokuWiki_Auth_Plugin {
+use dokuwiki\Extension\AuthPlugin;
+
+class auth_acl_caseinsensitive_auth extends AuthPlugin {
function isCaseSensitive() {
return false;
}
diff --git a/_test/tests/inc/auth_admincheck.test.php b/_test/tests/inc/auth_admincheck.test.php
index 087be3810..82ddafcff 100644
--- a/_test/tests/inc/auth_admincheck.test.php
+++ b/_test/tests/inc/auth_admincheck.test.php
@@ -1,6 +1,8 @@
<?php
-class auth_admin_test_AuthInSensitive extends DokuWiki_Auth_Plugin {
+use dokuwiki\test\mock\AuthPlugin;
+
+class auth_admin_test_AuthInSensitive extends AuthPlugin {
function isCaseSensitive(){
return false;
}
@@ -18,7 +20,7 @@ class auth_admin_test extends DokuWikiTest {
function setSensitive() {
global $auth;
- $auth = new DokuWiki_Auth_Plugin();
+ $auth = new AuthPlugin();
}
function setInSensitive() {
diff --git a/_test/tests/inc/auth_deleteprofile.test.php b/_test/tests/inc/auth_deleteprofile.test.php
index dc38fcd16..2195ee97d 100644
--- a/_test/tests/inc/auth_deleteprofile.test.php
+++ b/_test/tests/inc/auth_deleteprofile.test.php
@@ -1,11 +1,14 @@
<?php
-class Mock_Auth_Plugin extends DokuWiki_Auth_Plugin {
+use dokuwiki\Input\Input;
+use dokuwiki\Extension\AuthPlugin;
- public $loggedOff = false;
+class Mock_Auth_Plugin extends AuthPlugin {
+
+ public $loggedOff = false;
public function __construct($canDeleteUser = true) {
- $this->cando['delUser'] = $canDeleteUser;
+ $this->cando['delUser'] = $canDeleteUser;
}
public function checkPass($user, $pass) {
@@ -13,11 +16,11 @@ class Mock_Auth_Plugin extends DokuWiki_Auth_Plugin {
}
public function deleteUsers($users) {
- return in_array($_SERVER['REMOTE_USER'], $users);
+ return in_array($_SERVER['REMOTE_USER'], $users);
}
public function logoff() {
- $this->loggedOff = true;
+ $this->loggedOff = true;
}
}
@@ -27,7 +30,7 @@ class auth_deleteprofile_test extends DokuWikiTest {
/*
* Tests:
*
- * 1. It works and the user is logged off
+ * 1. It works and the user is logged off
* 2. Password matches when config requires it
* 3,4. Auth plugin can prevent & wiki config can prevent
* 5. Any of invalid security token, missing/not set 'delete' flag, missing/unchecked 'confirm_delete'
@@ -176,4 +179,4 @@ class auth_deleteprofile_test extends DokuWikiTest {
$INPUT->remove('confirm_delete');
$this->assertFalse(auth_deleteprofile());
}
-} \ No newline at end of file
+}
diff --git a/_test/tests/inc/cache_stalecheck.test.php b/_test/tests/inc/cache_stalecheck.test.php
index 93f44a55c..2172d9930 100644
--- a/_test/tests/inc/cache_stalecheck.test.php
+++ b/_test/tests/inc/cache_stalecheck.test.php
@@ -1,5 +1,7 @@
<?php
+use dokuwiki\Cache\CacheRenderer;
+
class cache_stalecheck_test extends DokuWikiTest {
function test_staleness() {
global $ID;
@@ -11,7 +13,7 @@ class cache_stalecheck_test extends DokuWikiTest {
saveWikiText($ID, 'Fresh', 'Created');
# Create stale cache
- $cache = new cache_renderer($ID, $file, 'xhtml');
+ $cache = new CacheRenderer($ID, $file, 'xhtml');
$cache->storeCache('Stale');
$stale = $cache->retrieveCache();
diff --git a/_test/tests/inc/cache_use.test.php b/_test/tests/inc/cache_use.test.php
index c0c12580a..3a1028d13 100644
--- a/_test/tests/inc/cache_use.test.php
+++ b/_test/tests/inc/cache_use.test.php
@@ -1,5 +1,7 @@
<?php
+use dokuwiki\Cache\CacheRenderer;
+
/**
* Class cache_use_test
*
@@ -8,7 +10,7 @@
* @todo tests marked as flaky until Ticket #694 has been fixed
*/
class cache_use_test extends DokuWikiTest {
- /** @var cache_renderer $cache */
+ /** @var CacheRenderer $cache */
private $cache;
function setUp() {
@@ -21,7 +23,7 @@ class cache_use_test extends DokuWikiTest {
saveWikiText($ID, 'Content', 'Created');
- $this->cache = new cache_renderer($ID, $file, 'xhtml');
+ $this->cache = new CacheRenderer($ID, $file, 'xhtml');
$this->cache->storeCache('Test');
// set the modification times explicitly (overcome Issue #694)
@@ -76,6 +78,6 @@ class cache_use_test extends DokuWikiTest {
$conf['cachetime'] = -1; // disables renderer caching
$this->assertFalse($this->cache->useCache());
- $this->assertNotEmpty($this->cache->_nocache);
+ $this->assertNotEmpty($this->cache->isNoCache());
}
}
diff --git a/_test/tests/inc/changelog_getRevisionsAround.test.php b/_test/tests/inc/changelog_getRevisionsAround.test.php
index 2a5cb849e..ad6d3afcf 100644
--- a/_test/tests/inc/changelog_getRevisionsAround.test.php
+++ b/_test/tests/inc/changelog_getRevisionsAround.test.php
@@ -1,4 +1,7 @@
<?php
+
+use dokuwiki\ChangeLog\PageChangeLog;
+
/**
* Tests for requesting revisions of a page with getRevisions()
*
@@ -185,4 +188,4 @@ class changelog_getrevisionsaround_test extends DokuWikiTest {
$this->assertEquals($revsexpected, $revs);
}
-} \ No newline at end of file
+}
diff --git a/_test/tests/inc/changelog_getlastrevisionat.test.php b/_test/tests/inc/changelog_getlastrevisionat.test.php
index 4ab7900b6..cec54f6db 100644
--- a/_test/tests/inc/changelog_getlastrevisionat.test.php
+++ b/_test/tests/inc/changelog_getlastrevisionat.test.php
@@ -1,5 +1,8 @@
<?php
+use dokuwiki\ChangeLog\MediaChangeLog;
+use dokuwiki\ChangeLog\PageChangeLog;
+
/**
* Tests for requesting revisioninfo of a revision of a page with getRevisionInfo()
*
@@ -10,7 +13,7 @@
class changelog_getlastrevisionat_test extends DokuWikiTest {
private $pageid = 'mailinglist';
-
+
function setup() {
parent::setup();
global $cache_revinfo;
@@ -22,7 +25,7 @@ class changelog_getlastrevisionat_test extends DokuWikiTest {
unset($cache['mailinglist']);
}
}
-
+
/**
* no nonexist.changes meta file available
@@ -53,7 +56,7 @@ class changelog_getlastrevisionat_test extends DokuWikiTest {
$this->assertEquals($revsexpected, $revs);
}
-
+
/**
* test a future revision
*
@@ -64,7 +67,7 @@ class changelog_getlastrevisionat_test extends DokuWikiTest {
//set a known timestamp
touch(wikiFN($this->pageid), $rev);
-
+
$rev +=1;
$pagelog = new PageChangeLog($this->pageid, $chunk_size = 8192);
@@ -89,7 +92,7 @@ class changelog_getlastrevisionat_test extends DokuWikiTest {
/**
* Request not existing revision
- *
+ *
*/
function test_olderrev() {
$rev = 1;
@@ -124,7 +127,7 @@ class changelog_getlastrevisionat_test extends DokuWikiTest {
$current = $pagelog->getLastRevisionAt($rev);
$this->assertEquals($currentexpected, $current);
}
-
+
/**
* test get correct revision on deleted media
*
@@ -154,13 +157,13 @@ class changelog_getlastrevisionat_test extends DokuWikiTest {
$ret = media_delete($image, 0);
- $medialog = new MediaChangelog($image);
+ $medialog = new MediaChangeLog($image);
$current = $medialog->getLastRevisionAt($rev);
// as we wait for a tick, we should get something greater than the timestamp
$this->assertGreaterThan($revexpected, $current);
// however, it should be less than the current time or equal to it
$this->assertLessThanOrEqual(time(), $current);
-
+
//restore settings
$_SERVER['REMOTE_USER'] = $oldRemoteUser;
$conf['superuser'] = $oldSuperUser;
diff --git a/_test/tests/inc/changelog_getrelativerevision.test.php b/_test/tests/inc/changelog_getrelativerevision.test.php
index f9962066a..49d7a0915 100644
--- a/_test/tests/inc/changelog_getrelativerevision.test.php
+++ b/_test/tests/inc/changelog_getrelativerevision.test.php
@@ -1,5 +1,7 @@
<?php
+use dokuwiki\ChangeLog\PageChangeLog;
+
/**
* Tests for requesting revisioninfo of a revision of a page with getRevisionInfo()
*
@@ -415,4 +417,4 @@ class changelog_getrelativerevision_test extends DokuWikiTest {
$current = $pagelog->isCurrentRevision($rev);
$this->assertEquals($currentexpected, $current);
}
-} \ No newline at end of file
+}
diff --git a/_test/tests/inc/changelog_getrevisioninfo.test.php b/_test/tests/inc/changelog_getrevisioninfo.test.php
index 79b31d68e..2d7ad131a 100644
--- a/_test/tests/inc/changelog_getrevisioninfo.test.php
+++ b/_test/tests/inc/changelog_getrevisioninfo.test.php
@@ -1,5 +1,7 @@
<?php
+use dokuwiki\ChangeLog\PageChangeLog;
+
/**
* Tests for requesting revisioninfo of a revision of a page with getRevisionInfo()
*
@@ -137,4 +139,4 @@ class changelog_getrevisionsinfo_test extends DokuWikiTest {
$info = $pagelog->getRevisionInfo($rev);
$this->assertEquals($infoexpected, $info);
}
-} \ No newline at end of file
+}
diff --git a/_test/tests/inc/changelog_getrevisions.test.php b/_test/tests/inc/changelog_getrevisions.test.php
index b247ce3d6..e29b80997 100644
--- a/_test/tests/inc/changelog_getrevisions.test.php
+++ b/_test/tests/inc/changelog_getrevisions.test.php
@@ -1,4 +1,7 @@
<?php
+
+use dokuwiki\ChangeLog\PageChangeLog;
+
/**
* Tests for requesting revisions of a page with getRevisions()
*
@@ -227,4 +230,4 @@ class changelog_getrevisions_test extends DokuWikiTest {
$this->assertEquals($revsexpected, $revs);
}
-} \ No newline at end of file
+}
diff --git a/_test/tests/inc/common_ml.test.php b/_test/tests/inc/common_ml.test.php
index 027dcaef2..853c634b4 100644
--- a/_test/tests/inc/common_ml.test.php
+++ b/_test/tests/inc/common_ml.test.php
@@ -124,7 +124,7 @@ class common_ml_test extends DokuWikiTest {
foreach($ids as $id) {
$tok = media_get_token($id, $w, 0);
- $hash = substr(PassHash::hmac('md5', $id, auth_cookiesalt()), 0, 6);
+ $hash = substr(\dokuwiki\PassHash::hmac('md5', $id, auth_cookiesalt()), 0, 6);
$expect = DOKU_BASE.$this->script.'?w='.$w.'&amp;tok='.$tok.'&amp;media='.rawurlencode($id);
$this->assertEquals($expect, ml($id, $args));
diff --git a/_test/tests/inc/common_saveWikiText.test.php b/_test/tests/inc/common_saveWikiText.test.php
index fe83caabd..7ae12ca27 100644
--- a/_test/tests/inc/common_saveWikiText.test.php
+++ b/_test/tests/inc/common_saveWikiText.test.php
@@ -1,5 +1,7 @@
<?php
+use dokuwiki\ChangeLog\PageChangeLog;
+
class common_saveWikiText_test extends DokuWikiTest {
/** Delay writes of old revisions by a second. */
public function handle_write(Doku_Event $event, $param) {
@@ -166,7 +168,7 @@ class common_saveWikiText_test extends DokuWikiTest {
function test_savesequencedeleteexternalrevision() {
// add an additional delay when saving files to make sure
// nobody relies on the saving happening in the same second
- /** @var $EVENT_HANDLER Doku_Event_Handler */
+ /** @var $EVENT_HANDLER \dokuwiki\Extension\EventHandler */
global $EVENT_HANDLER;
$EVENT_HANDLER->register_hook('IO_WIKIPAGE_WRITE', 'BEFORE', $this, 'handle_write');
diff --git a/_test/tests/inc/events_nested.test.php b/_test/tests/inc/events_nested.test.php
index fe5e395bb..3ed2fcf34 100644
--- a/_test/tests/inc/events_nested.test.php
+++ b/_test/tests/inc/events_nested.test.php
@@ -1,5 +1,7 @@
<?php
+use dokuwiki\Extension\Event;
+
/**
* This tests if event handlers can trigger the same event again.
* This is used by plugins that modify cache handling and use metadata
@@ -16,7 +18,7 @@ class events_nested_test extends DokuWikiTest {
$firstcount++;
if ($firstcount == 1) {
$param = array();
- trigger_event('NESTED_EVENT', $param);
+ Event::createAndTrigger('NESTED_EVENT', $param);
}
}
);
@@ -28,7 +30,7 @@ class events_nested_test extends DokuWikiTest {
);
$param = array();
- trigger_event('NESTED_EVENT', $param);
+ Event::createAndTrigger('NESTED_EVENT', $param);
$this->assertEquals(2, $firstcount);
$this->assertEquals(2, $secondcount);
diff --git a/_test/tests/inc/httpclient_http.test.php b/_test/tests/inc/httpclient_http.test.php
index 3061f7e33..f3afdce66 100644
--- a/_test/tests/inc/httpclient_http.test.php
+++ b/_test/tests/inc/httpclient_http.test.php
@@ -301,6 +301,9 @@ class httpclient_http_test extends DokuWikiTest {
$this->assertTrue($data !== false, $http->errorInfo());
}
+ /**
+ * @throws ReflectionException
+ */
function test_postencode(){
$http = new HTTPMockClient();
@@ -312,7 +315,7 @@ class httpclient_http_test extends DokuWikiTest {
);
$this->assertEquals(
'%C3%B6%C3%A4%3F=%C3%B6%C3%A4%3F&foo=bang',
- $http->_postEncode($data),
+ $this->callInaccessibleMethod($http, 'postEncode', [$data]),
'simple'
);
@@ -323,7 +326,7 @@ class httpclient_http_test extends DokuWikiTest {
);
$this->assertEquals(
'foo=bang&%C3%A4rr%5B0%5D=%C3%B6&%C3%A4rr%5B1%5D=b&%C3%A4rr%5B2%5D=c',
- $http->_postEncode($data),
+ $this->callInaccessibleMethod($http, 'postEncode', [$data]),
'onelevelnum'
);
@@ -334,7 +337,7 @@ class httpclient_http_test extends DokuWikiTest {
);
$this->assertEquals(
'foo=bang&%C3%A4rr%5B%C3%B6%5D=%C3%A4&%C3%A4rr%5Bb%5D=c',
- $http->_postEncode($data),
+ $this->callInaccessibleMethod($http, 'postEncode', [$data]),
'onelevelassoc'
);
@@ -346,7 +349,7 @@ class httpclient_http_test extends DokuWikiTest {
);
$this->assertEquals(
'foo=bang&%C3%A4rr%5B%C3%B6%5D=%C3%A4&%C3%A4rr%5B%C3%A4%5D%5B%C3%B6%5D=%C3%A4',
- $http->_postEncode($data),
+ $this->callInaccessibleMethod($http, 'postEncode', [$data]),
'twolevelassoc'
);
}
diff --git a/_test/tests/inc/httpclient_mock.php b/_test/tests/inc/httpclient_mock.php
index b66b90775..56b99b7a2 100644
--- a/_test/tests/inc/httpclient_mock.php
+++ b/_test/tests/inc/httpclient_mock.php
@@ -1,4 +1,7 @@
<?php
+
+use dokuwiki\HTTP\HTTPClient;
+
/**
* Class HTTPMockClient
*
diff --git a/_test/tests/inc/input.test.php b/_test/tests/inc/input.test.php
index 4a8fb8d71..099a8eb81 100644
--- a/_test/tests/inc/input.test.php
+++ b/_test/tests/inc/input.test.php
@@ -1,7 +1,9 @@
<?php
+use dokuwiki\Input\Input;
+
/**
- * Tests for the Input class
+ * Tests for the dokuwiki\Input\Input class
*/
class input_test extends DokuWikiTest {
diff --git a/_test/tests/inc/json.test.php b/_test/tests/inc/json.test.php
deleted file mode 100644
index 03a76a260..000000000
--- a/_test/tests/inc/json.test.php
+++ /dev/null
@@ -1,420 +0,0 @@
-<?php
-/**
- * Unit tests for JSON.
- *
- * @author Michal Migurski <mike-json@teczno.com>
- * @author Matt Knapp <mdknapp[at]gmail[dot]com>
- * @author Brett Stimmerman <brettstimmerman[at]gmail[dot]com>
- * @copyright 2005 Michal Migurski
- * @version CVS: $Id: Test-JSON.php,v 1.28 2006/06/28 05:54:17 migurski Exp $
- * @license http://www.opensource.org/licenses/bsd-license.php
- * @link http://pear.php.net/pepr/pepr-proposal-show.php?id=198
- * @link http://mike.teczno.com/JSON/Test-JSON.phps
- */
-
-class JSON_EncDec_TestCase extends DokuWikiTest {
-
- protected $json;
-
- function setUp() {
- parent::setUp();
-
- $this->json = new JSON();
- $this->json->skipnative = true;
-
- $obj = new stdClass();
- $obj->a_string = '"he":llo}:{world';
- $obj->an_array = array(1, 2, 3);
- $obj->obj = new stdClass();
- $obj->obj->a_number = 123;
-
- $this->obj = $obj;
- $this->obj_j = '{"a_string":"\"he\":llo}:{world","an_array":[1,2,3],"obj":{"a_number":123}}';
- $this->obj_d = 'object with properties, nested object and arrays';
-
- $this->arr = array(null, true, array(1, 2, 3), "hello\"],[world!");
- $this->arr_j = '[null,true,[1,2,3],"hello\"],[world!"]';
- $this->arr_d = 'array with elements and nested arrays';
-
- $this->str1 = 'hello world';
- $this->str1_j = '"hello world"';
- $this->str1_j_ = "'hello world'";
- $this->str1_d = 'hello world';
- $this->str1_d_ = 'hello world, double quotes';
-
- $this->str2 = "hello\t\"world\"";
- $this->str2_j = '"hello\\t\\"world\\""';
- $this->str2_d = 'hello world, with tab, double-quotes';
-
- $this->str3 = "\\\r\n\t\"/";
- $this->str3_j = '"\\\\\\r\\n\\t\\"\\/"';
- $this->str3_d = 'backslash, return, newline, tab, double-quote';
-
- $this->str4 = 'héllö wørłd';
- $this->str4_j = '"h\u00e9ll\u00f6 w\u00f8r\u0142d"';
- $this->str4_j_ = '"héllö wørłd"';
- $this->str4_d = 'hello world, with unicode';
- }
-
- function test_to_JSON() {
- $this->assertEquals('null', $this->json->encode(null), 'type case: null');
- $this->assertEquals('true', $this->json->encode(true), 'type case: boolean true');
- $this->assertEquals('false', $this->json->encode(false), 'type case: boolean false');
-
- $this->assertEquals('1', $this->json->encode(1), 'numeric case: 1');
- $this->assertEquals('-1', $this->json->encode(-1), 'numeric case: -1');
- $this->assertEquals('1.000000', $this->json->encode(1.0), 'numeric case: 1.0');
- $this->assertEquals('1.100000', $this->json->encode(1.1), 'numeric case: 1.1');
-
- $this->assertEquals($this->str1_j, $this->json->encode($this->str1), "string case: {$this->str1_d}");
- $this->assertEquals($this->str2_j, $this->json->encode($this->str2), "string case: {$this->str2_d}");
- $this->assertEquals($this->str3_j, $this->json->encode($this->str3), "string case: {$this->str3_d}");
- $this->assertEquals($this->str4_j, $this->json->encode($this->str4), "string case: {$this->str4_d}");
-
- $this->assertEquals($this->arr_j, $this->json->encode($this->arr), "array case: {$this->arr_d}");
- $this->assertEquals($this->obj_j, $this->json->encode($this->obj), "object case: {$this->obj_d}");
- }
-
- function test_from_JSON() {
- $this->assertEquals(null, $this->json->decode('null'), 'type case: null');
- $this->assertEquals(true, $this->json->decode('true'), 'type case: boolean true');
- $this->assertEquals(false, $this->json->decode('false'), 'type case: boolean false');
-
- $this->assertEquals(1, $this->json->decode('1'), 'numeric case: 1');
- $this->assertEquals(-1, $this->json->decode('-1'), 'numeric case: -1');
- $this->assertEquals(1.0, $this->json->decode('1.0'), 'numeric case: 1.0');
- $this->assertEquals(1.1, $this->json->decode('1.1'), 'numeric case: 1.1');
-
- $this->assertEquals(11.0, $this->json->decode('1.1e1'), 'numeric case: 1.1e1');
- $this->assertEquals(11.0, $this->json->decode('1.10e+1'), 'numeric case: 1.10e+1');
- $this->assertEquals(0.11, $this->json->decode('1.1e-1'), 'numeric case: 1.1e-1');
- $this->assertEquals(-0.11, $this->json->decode('-1.1e-1'), 'numeric case: -1.1e-1');
-
- $this->assertEquals($this->str1, $this->json->decode($this->str1_j), "string case: {$this->str1_d}");
- $this->assertEquals($this->str1, $this->json->decode($this->str1_j_), "string case: {$this->str1_d_}");
- $this->assertEquals($this->str2, $this->json->decode($this->str2_j), "string case: {$this->str2_d}");
- $this->assertEquals($this->str3, $this->json->decode($this->str3_j), "string case: {$this->str3_d}");
- $this->assertEquals($this->str4, $this->json->decode($this->str4_j), "string case: {$this->str4_d}");
- $this->assertEquals($this->str4, $this->json->decode($this->str4_j_), "string case: {$this->str4_d}");
-
- $this->assertEquals($this->arr, $this->json->decode($this->arr_j), "array case: {$this->arr_d}");
- $this->assertEquals($this->obj, $this->json->decode($this->obj_j), "object case: {$this->obj_d}");
- }
-
- function test_to_then_from_JSON() {
- $this->assertEquals(null, $this->json->decode($this->json->encode(null)), 'type case: null');
- $this->assertEquals(true, $this->json->decode($this->json->encode(true)), 'type case: boolean true');
- $this->assertEquals(false, $this->json->decode($this->json->encode(false)), 'type case: boolean false');
-
- $this->assertEquals(1, $this->json->decode($this->json->encode(1)), 'numeric case: 1');
- $this->assertEquals(-1, $this->json->decode($this->json->encode(-1)), 'numeric case: -1');
- $this->assertEquals(1.0, $this->json->decode($this->json->encode(1.0)), 'numeric case: 1.0');
- $this->assertEquals(1.1, $this->json->decode($this->json->encode(1.1)), 'numeric case: 1.1');
-
- $this->assertEquals($this->str1, $this->json->decode($this->json->encode($this->str1)), "string case: {$this->str1_d}");
- $this->assertEquals($this->str2, $this->json->decode($this->json->encode($this->str2)), "string case: {$this->str2_d}");
- $this->assertEquals($this->str3, $this->json->decode($this->json->encode($this->str3)), "string case: {$this->str3_d}");
- $this->assertEquals($this->str4, $this->json->decode($this->json->encode($this->str4)), "string case: {$this->str4_d}");
-
- $this->assertEquals($this->arr, $this->json->decode($this->json->encode($this->arr)), "array case: {$this->arr_d}");
- $this->assertEquals($this->obj, $this->json->decode($this->json->encode($this->obj)), "object case: {$this->obj_d}");
- }
-
- function test_from_then_to_JSON() {
- $this->assertEquals('null', $this->json->encode($this->json->decode('null')), 'type case: null');
- $this->assertEquals('true', $this->json->encode($this->json->decode('true')), 'type case: boolean true');
- $this->assertEquals('false', $this->json->encode($this->json->decode('false')), 'type case: boolean false');
-
- $this->assertEquals('1', $this->json->encode($this->json->decode('1')), 'numeric case: 1');
- $this->assertEquals('-1', $this->json->encode($this->json->decode('-1')), 'numeric case: -1');
- $this->assertEquals('1.0', $this->json->encode($this->json->decode('1.0')), 'numeric case: 1.0');
- $this->assertEquals('1.1', $this->json->encode($this->json->decode('1.1')), 'numeric case: 1.1');
-
- $this->assertEquals($this->str1_j, $this->json->encode($this->json->decode($this->str1_j)), "string case: {$this->str1_d}");
- $this->assertEquals($this->str2_j, $this->json->encode($this->json->decode($this->str2_j)), "string case: {$this->str2_d}");
- $this->assertEquals($this->str3_j, $this->json->encode($this->json->decode($this->str3_j)), "string case: {$this->str3_d}");
- $this->assertEquals($this->str4_j, $this->json->encode($this->json->decode($this->str4_j)), "string case: {$this->str4_d}");
- $this->assertEquals($this->str4_j, $this->json->encode($this->json->decode($this->str4_j_)), "string case: {$this->str4_d}");
-
- $this->assertEquals($this->arr_j, $this->json->encode($this->json->decode($this->arr_j)), "array case: {$this->arr_d}");
- $this->assertEquals($this->obj_j, $this->json->encode($this->json->decode($this->obj_j)), "object case: {$this->obj_d}");
- }
-}
-
-class JSON_AssocArray_TestCase extends DokuWikiTest {
-
- function setUp() {
- parent::setUp();
-
- $this->json_l = new JSON(JSON_LOOSE_TYPE);
- $this->json_l->skipnative = true;
- $this->json_s = new JSON();
- $this->json_s->skipnative = true;
-
- $this->arr = array('car1'=> array('color'=> 'tan', 'model' => 'sedan'),
- 'car2' => array('color' => 'red', 'model' => 'sports'));
- $this->arr_jo = '{"car1":{"color":"tan","model":"sedan"},"car2":{"color":"red","model":"sports"}}';
- $this->arr_d = 'associative array with nested associative arrays';
-
- $this->arn = array(0=> array(0=> 'tan\\', 'model\\' => 'sedan'), 1 => array(0 => 'red', 'model' => 'sports'));
- $this->arn_ja = '[{"0":"tan\\\\","model\\\\":"sedan"},{"0":"red","model":"sports"}]';
- $this->arn_d = 'associative array with nested associative arrays, and some numeric keys thrown in';
-
- $this->arrs = array (1 => 'one', 2 => 'two', 5 => 'five');
- $this->arrs_jo = '{"1":"one","2":"two","5":"five"}';
- $this->arrs_d = 'associative array numeric keys which are not fully populated in a range of 0 to length-1';
- }
-
- function test_type() {
- $this->assertEquals('array', gettype($this->json_l->decode($this->arn_ja)), "loose type should be array");
- $this->assertEquals('array', gettype($this->json_s->decode($this->arn_ja)), "strict type should be array");
- }
-
- function test_to_JSON() {
- // both strict and loose JSON should result in an object
- $this->assertEquals($this->arr_jo, $this->json_l->encode($this->arr), "array case - loose: {$this->arr_d}");
- $this->assertEquals($this->arr_jo, $this->json_s->encode($this->arr), "array case - strict: {$this->arr_d}");
-
- // ...unless the input array has some numeric indeces, in which case the behavior is to degrade to a regular array
- $this->assertEquals($this->arn_ja, $this->json_s->encode($this->arn), "array case - strict: {$this->arn_d}");
-
- // Test a sparsely populated numerically indexed associative array
- $this->assertEquals($this->arrs_jo, $this->json_l->encode($this->arrs), "sparse numeric assoc array: {$this->arrs_d}");
- }
-
- function test_to_then_from_JSON() {
- // these tests motivated by a bug in which strings that end
- // with backslashes followed by quotes were incorrectly decoded.
-
- foreach(array('\\"', '\\\\"', '\\"\\"', '\\""\\""', '\\\\"\\\\"') as $v) {
- $this->assertEquals(array($v), $this->json_l->decode($this->json_l->encode(array($v))));
- $this->assertEquals(array('a' => $v), $this->json_l->decode($this->json_l->encode(array('a' => $v))));
- }
- }
-}
-
-class JSON_NestedArray_TestCase extends DokuWikiTest {
-
- function setUp() {
- parent::setUp();
-
- $this->json = new JSON(JSON_LOOSE_TYPE);
- $this->json->skipnative = true;
-
- $this->str1 = '[{"this":"that"}]';
- $this->arr1 = array(array('this' => 'that'));
-
- $this->str2 = '{"this":["that"]}';
- $this->arr2 = array('this' => array('that'));
-
- $this->str3 = '{"params":[{"foo":["1"],"bar":"1"}]}';
- $this->arr3 = array('params' => array(array('foo' => array('1'), 'bar' => '1')));
-
- $this->str4 = '{"0": {"foo": "bar", "baz": "winkle"}}';
- $this->arr4 = array('0' => array('foo' => 'bar', 'baz' => 'winkle'));
-
- $this->str5 = '{"params":[{"options": {"old": [ ], "new": {"0": {"elements": {"old": [], "new": {"0": {"elementName": "aa", "isDefault": false, "elementRank": "0", "priceAdjust": "0", "partNumber": ""}}}, "optionName": "aa", "isRequired": false, "optionDesc": null}}}}]}';
- $this->arr5 = array (
- 'params' => array (
- 0 => array (
- 'options' =>
- array (
- 'old' => array(),
- 'new' => array (
- 0 => array (
- 'elements' => array (
- 'old' => array(),
- 'new' => array (
- 0 => array (
- 'elementName' => 'aa',
- 'isDefault' => false,
- 'elementRank' => '0',
- 'priceAdjust' => '0',
- 'partNumber' => '',
- ),
- ),
- ),
- 'optionName' => 'aa',
- 'isRequired' => false,
- 'optionDesc' => NULL,
- ),
- ),
- ),
- ),
- ),
- );
- }
-
- function test_type() {
- $this->assertEquals('array', gettype($this->json->decode($this->str1)), "loose type should be array");
- $this->assertEquals('array', gettype($this->json->decode($this->str2)), "loose type should be array");
- $this->assertEquals('array', gettype($this->json->decode($this->str3)), "loose type should be array");
- }
-
- function test_from_JSON() {
- $this->assertEquals($this->arr1, $this->json->decode($this->str1), "simple compactly-nested array");
- $this->assertEquals($this->arr2, $this->json->decode($this->str2), "simple compactly-nested array");
- $this->assertEquals($this->arr3, $this->json->decode($this->str3), "complex compactly nested array");
- $this->assertEquals($this->arr4, $this->json->decode($this->str4), "complex compactly nested array");
- $this->assertEquals($this->arr5, $this->json->decode($this->str5), "super complex compactly nested array");
- }
-
- function _test_from_JSON() {
- $super = '{"params":[{"options": {"old": {}, "new": {"0": {"elements": {"old": {}, "new": {"0": {"elementName": "aa", "isDefault": false, "elementRank": "0", "priceAdjust": "0", "partNumber": ""}}}, "optionName": "aa", "isRequired": false, "optionDesc": ""}}}}]}';
- print("trying {$super}...\n");
- print var_export($this->json->decode($super));
- }
-}
-
-class JSON_Object_TestCase extends DokuWikiTest {
-
- function setUp() {
- parent::setUp();
-
- $this->json_l = new JSON(JSON_LOOSE_TYPE);
- $this->json_l->skipnative = true;
- $this->json_s = new JSON();
- $this->json_s->skipnative = true;
-
- $this->obj_j = '{"a_string":"\"he\":llo}:{world","an_array":[1,2,3],"obj":{"a_number":123}}';
-
- $this->obj1 = new stdClass();
- $this->obj1->car1 = new stdClass();
- $this->obj1->car1->color = 'tan';
- $this->obj1->car1->model = 'sedan';
- $this->obj1->car2 = new stdClass();
- $this->obj1->car2->color = 'red';
- $this->obj1->car2->model = 'sports';
- $this->obj1_j = '{"car1":{"color":"tan","model":"sedan"},"car2":{"color":"red","model":"sports"}}';
- $this->obj1_d = 'Object with nested objects';
- }
-
- function test_type() {
- $this->assertEquals('object', gettype($this->json_s->decode($this->obj_j)), "checking whether decoded type is object");
- $this->assertEquals('array', gettype($this->json_l->decode($this->obj_j)), "checking whether decoded type is array");
- }
-
- function test_to_JSON() {
- $this->assertEquals($this->obj1_j, $this->json_s->encode($this->obj1), "object - strict: {$this->obj1_d}");
- $this->assertEquals($this->obj1_j, $this->json_l->encode($this->obj1), "object - loose: {$this->obj1_d}");
- }
-
- function test_from_then_to_JSON() {
- $this->assertEquals($this->obj_j, $this->json_s->encode($this->json_s->decode($this->obj_j)), "object case");
- $this->assertEquals($this->obj_j, $this->json_l->encode($this->json_l->decode($this->obj_j)), "array case");
- }
-}
-
-class JSON_Spaces_Comments_TestCase extends DokuWikiTest {
-
- function setUp() {
- parent::setUp();
-
- $this->json = new JSON(JSON_LOOSE_TYPE);
- $this->json->skipnative = true;
-
- $this->obj_j = '{"a_string":"\"he\":llo}:{world","an_array":[1,2,3],"obj":{"a_number":123}}';
-
- $this->obj_js = '{"a_string": "\"he\":llo}:{world",
- "an_array":[1, 2, 3],
- "obj": {"a_number":123}}';
-
- $this->obj_jc1 = '{"a_string": "\"he\":llo}:{world",
- // here is a comment, hoorah
- "an_array":[1, 2, 3],
- "obj": {"a_number":123}}';
-
- $this->obj_jc2 = '/* this here is the sneetch */ "the sneetch"
- // this has been the sneetch.';
-
- $this->obj_jc3 = '{"a_string": "\"he\":llo}:{world",
- /* here is a comment, hoorah */
- "an_array":[1, 2, 3 /* and here is another */],
- "obj": {"a_number":123}}';
-
- $this->obj_jc4 = '{\'a_string\': "\"he\":llo}:{world",
- /* here is a comment, hoorah */
- \'an_array\':[1, 2, 3 /* and here is another */],
- "obj": {"a_number":123}}';
- }
-
- function test_spaces() {
- $this->assertEquals($this->json->decode($this->obj_j), $this->json->decode($this->obj_js), "checking whether notation with spaces works");
- }
-
- function test_comments() {
- $this->assertEquals($this->json->decode($this->obj_j), $this->json->decode($this->obj_jc1), "checking whether notation with single line comments works");
- $this->assertEquals('the sneetch', $this->json->decode($this->obj_jc2), "checking whether notation with multiline comments works");
- $this->assertEquals($this->json->decode($this->obj_j), $this->json->decode($this->obj_jc3), "checking whether notation with multiline comments works");
- $this->assertEquals($this->json->decode($this->obj_j), $this->json->decode($this->obj_jc4), "checking whether notation with single-quotes and multiline comments works");
- }
-}
-
-class JSON_Empties_TestCase extends DokuWikiTest {
-
- function setUp() {
- parent::setUp();
-
- $this->json_l = new JSON(JSON_LOOSE_TYPE);
- $this->json_l->skipnative = true;
- $this->json_l->skipnative = true;
- $this->json_s = new JSON();
- $this->json_s->skipnative = true;
-
- $this->obj0_j = '{}';
- $this->arr0_j = '[]';
-
- $this->obj1_j = '{ }';
- $this->arr1_j = '[ ]';
-
- $this->obj2_j = '{ /* comment inside */ }';
- $this->arr2_j = '[ /* comment inside */ ]';
- }
-
- function test_type() {
- $this->assertEquals('array', gettype($this->json_l->decode($this->arr0_j)), "should be array");
- $this->assertEquals('object', gettype($this->json_s->decode($this->obj0_j)), "should be object");
-
- $this->assertEquals(0, count($this->json_l->decode($this->arr0_j)), "should be empty array");
- $this->assertEquals(0, count(get_object_vars($this->json_s->decode($this->obj0_j))), "should be empty object");
-
- $this->assertEquals('array', gettype($this->json_l->decode($this->arr1_j)), "should be array, even with space");
- $this->assertEquals('object', gettype($this->json_s->decode($this->obj1_j)), "should be object, even with space");
-
- $this->assertEquals(0, count($this->json_l->decode($this->arr1_j)), "should be empty array, even with space");
- $this->assertEquals(0, count(get_object_vars($this->json_s->decode($this->obj1_j))), "should be empty object, even with space");
-
- $this->assertEquals('array', gettype($this->json_l->decode($this->arr2_j)), "should be array, despite comment");
- $this->assertEquals('object', gettype($this->json_s->decode($this->obj2_j)), "should be object, despite comment");
-
- $this->assertEquals(0, count($this->json_l->decode($this->arr2_j)), "should be empty array, despite comment");
- $this->assertEquals(0, count(get_object_vars($this->json_s->decode($this->obj2_j))), "should be empty object, despite commentt");
- }
-}
-
-class JSON_UnquotedKeys_TestCase extends DokuWikiTest {
-
- function setUp() {
- parent::setUp();
-
- $this->json = new JSON(JSON_LOOSE_TYPE);
- $this->json->skipnative = true;
-
- $this->arn = array(0=> array(0=> 'tan', 'model' => 'sedan'), 1 => array(0 => 'red', 'model' => 'sports'));
- $this->arn_ja = '[{0:"tan","model":"sedan"},{"0":"red",model:"sports"}]';
- $this->arn_d = 'associative array with unquoted keys, nested associative arrays, and some numeric keys thrown in';
-
- $this->arrs = array (1 => 'one', 2 => 'two', 5 => 'fi"ve');
- $this->arrs_jo = '{"1":"one",2:"two","5":\'fi"ve\'}';
- $this->arrs_d = 'associative array with unquoted keys, single-quoted values, numeric keys which are not fully populated in a range of 0 to length-1';
- }
-
- function test_from_JSON() {
- // ...unless the input array has some numeric indeces, in which case the behavior is to degrade to a regular array
- $this->assertEquals($this->arn, $this->json->decode($this->arn_ja), "array case - strict: {$this->arn_d}");
-
- // Test a sparsely populated numerically indexed associative array
- $this->assertEquals($this->arrs, $this->json->decode($this->arrs_jo), "sparse numeric assoc array: {$this->arrs_d}");
- }
-}
-
diff --git a/_test/tests/inc/mailer.test.php b/_test/tests/inc/mailer.test.php
index f1b579759..2c8f142d1 100755
--- a/_test/tests/inc/mailer.test.php
+++ b/_test/tests/inc/mailer.test.php
@@ -1,5 +1,7 @@
<?php
+use dokuwiki\HTTP\HTTPClient;
+
/**
* Extends the mailer class to expose internal variables for testing
*/
diff --git a/_test/tests/inc/media_searchlist.test.php b/_test/tests/inc/media_searchlist.test.php
index c038d3a20..b881ccc95 100644
--- a/_test/tests/inc/media_searchlist.test.php
+++ b/_test/tests/inc/media_searchlist.test.php
@@ -124,7 +124,7 @@ class media_searchlist_test extends DokuWikiTest {
$info = array();
$info['id'] = $this->upload_ns . ':' . $rel_id;
$info['perm'] = auth_quickaclcheck(getNS($info['id']).':*');
- $info['file'] = utf8_basename($file);
+ $info['file'] = \dokuwiki\Utf8\PhpString::basename($file);
$info['size'] = filesize($file);
$info['mtime'] = filemtime($file);
$info['writable'] = is_writable($file);
diff --git a/_test/tests/inc/pageutils_findnearest.test.php b/_test/tests/inc/pageutils_findnearest.test.php
index 1bed5bb04..55db44afa 100644
--- a/_test/tests/inc/pageutils_findnearest.test.php
+++ b/_test/tests/inc/pageutils_findnearest.test.php
@@ -1,5 +1,7 @@
<?php
+use dokuwiki\test\mock\AuthPlugin;
+
class pageutils_findnearest_test extends DokuWikiTest {
protected $oldAuthAcl;
@@ -13,7 +15,7 @@ class pageutils_findnearest_test extends DokuWikiTest {
$conf['useacl'] = 1;
$this->oldAuthAcl = $AUTH_ACL;
- $auth = new DokuWiki_Auth_Plugin();
+ $auth = new AuthPlugin();
$AUTH_ACL = array(
'* @ALL 1',
diff --git a/_test/tests/inc/parser/lexer.test.php b/_test/tests/inc/parser/lexer.test.php
index 50b6548a4..412bee75b 100644
--- a/_test/tests/inc/parser/lexer.test.php
+++ b/_test/tests/inc/parser/lexer.test.php
@@ -5,10 +5,9 @@
* @subpackage Tests
*/
-/**
-* Includes
-*/
-require_once DOKU_INC . 'inc/parser/lexer.php';
+use dokuwiki\Parsing\Lexer\Lexer;
+use dokuwiki\Parsing\Lexer\ParallelRegex;
+use dokuwiki\Parsing\Lexer\StateStack;
/**
* @package Doku
@@ -17,24 +16,24 @@ require_once DOKU_INC . 'inc/parser/lexer.php';
class TestOfLexerParallelRegex extends DokuWikiTest {
function testNoPatterns() {
- $regex = new Doku_LexerParallelRegex(false);
+ $regex = new ParallelRegex(false);
$this->assertFalse($regex->match("Hello", $match));
$this->assertEquals($match, "");
}
function testNoSubject() {
- $regex = new Doku_LexerParallelRegex(false);
+ $regex = new ParallelRegex(false);
$regex->addPattern(".*");
$this->assertTrue($regex->match("", $match));
$this->assertEquals($match, "");
}
function testMatchAll() {
- $regex = new Doku_LexerParallelRegex(false);
+ $regex = new ParallelRegex(false);
$regex->addPattern(".*");
$this->assertTrue($regex->match("Hello", $match));
$this->assertEquals($match, "Hello");
}
function testCaseSensitive() {
- $regex = new Doku_LexerParallelRegex(true);
+ $regex = new ParallelRegex(true);
$regex->addPattern("abc");
$this->assertTrue($regex->match("abcdef", $match));
$this->assertEquals($match, "abc");
@@ -42,7 +41,7 @@ class TestOfLexerParallelRegex extends DokuWikiTest {
$this->assertEquals($match, "abc");
}
function testCaseInsensitive() {
- $regex = new Doku_LexerParallelRegex(false);
+ $regex = new ParallelRegex(false);
$regex->addPattern("abc");
$this->assertTrue($regex->match("abcdef", $match));
$this->assertEquals($match, "abc");
@@ -50,7 +49,7 @@ class TestOfLexerParallelRegex extends DokuWikiTest {
$this->assertEquals($match, "ABC");
}
function testMatchMultiple() {
- $regex = new Doku_LexerParallelRegex(true);
+ $regex = new ParallelRegex(true);
$regex->addPattern("abc");
$regex->addPattern("ABC");
$this->assertTrue($regex->match("abcdef", $match));
@@ -60,7 +59,7 @@ class TestOfLexerParallelRegex extends DokuWikiTest {
$this->assertFalse($regex->match("Hello", $match));
}
function testPatternLabels() {
- $regex = new Doku_LexerParallelRegex(false);
+ $regex = new ParallelRegex(false);
$regex->addPattern("abc", "letter");
$regex->addPattern("123", "number");
$this->assertEquals($regex->match("abcdef", $match), "letter");
@@ -69,7 +68,7 @@ class TestOfLexerParallelRegex extends DokuWikiTest {
$this->assertEquals($match, "123");
}
function testMatchMultipleWithLookaheadNot() {
- $regex = new Doku_LexerParallelRegex(true);
+ $regex = new ParallelRegex(true);
$regex->addPattern("abc");
$regex->addPattern("ABC");
$regex->addPattern("a(?!\n).{1}");
@@ -82,37 +81,37 @@ class TestOfLexerParallelRegex extends DokuWikiTest {
$this->assertFalse($regex->match("Hello", $match));
}
function testMatchSetOptionCaseless() {
- $regex = new Doku_LexerParallelRegex(true);
+ $regex = new ParallelRegex(true);
$regex->addPattern("a(?i)b(?i)c");
$this->assertTrue($regex->match("aBc", $match));
$this->assertEquals($match, "aBc");
}
function testMatchSetOptionUngreedy() {
- $regex = new Doku_LexerParallelRegex(true);
+ $regex = new ParallelRegex(true);
$regex->addPattern("(?U)\w+");
$this->assertTrue($regex->match("aaaaaa", $match));
$this->assertEquals($match, "a");
}
function testMatchLookaheadEqual() {
- $regex = new Doku_LexerParallelRegex(true);
+ $regex = new ParallelRegex(true);
$regex->addPattern("\w(?=c)");
$this->assertTrue($regex->match("xbyczd", $match));
$this->assertEquals($match, "y");
}
function testMatchLookaheadNot() {
- $regex = new Doku_LexerParallelRegex(true);
+ $regex = new ParallelRegex(true);
$regex->addPattern("\w(?!b|c)");
$this->assertTrue($regex->match("xbyczd", $match));
$this->assertEquals($match, "b");
}
function testMatchLookbehindEqual() {
- $regex = new Doku_LexerParallelRegex(true);
+ $regex = new ParallelRegex(true);
$regex->addPattern("(?<=c)\w");
$this->assertTrue($regex->match("xbyczd", $match));
$this->assertEquals($match, "z");
}
function testMatchLookbehindNot() {
- $regex = new Doku_LexerParallelRegex(true);
+ $regex = new ParallelRegex(true);
$regex->addPattern("(?<!\A|x|b)\w");
$this->assertTrue($regex->match("xbyczd", $match));
$this->assertEquals($match, "c");
@@ -122,15 +121,15 @@ class TestOfLexerParallelRegex extends DokuWikiTest {
class TestOfLexerStateStack extends DokuWikiTest {
function testStartState() {
- $stack = new Doku_LexerStateStack("one");
+ $stack = new StateStack("one");
$this->assertEquals($stack->getCurrent(), "one");
}
function testExhaustion() {
- $stack = new Doku_LexerStateStack("one");
+ $stack = new StateStack("one");
$this->assertFalse($stack->leave());
}
function testStateMoves() {
- $stack = new Doku_LexerStateStack("one");
+ $stack = new StateStack("one");
$stack->enter("two");
$this->assertEquals($stack->getCurrent(), "two");
$stack->enter("three");
@@ -160,13 +159,13 @@ class TestOfLexer extends DokuWikiTest {
function testNoPatterns() {
$handler = $this->createMock('TestParser');
$handler->expects($this->never())->method('accept');
- $lexer = new Doku_Lexer($handler);
+ $lexer = new Lexer($handler);
$this->assertFalse($lexer->parse("abcdef"));
}
function testEmptyPage() {
$handler = $this->createMock('TestParser');
$handler->expects($this->never())->method('accept');
- $lexer = new Doku_Lexer($handler);
+ $lexer = new Lexer($handler);
$lexer->addPattern("a+");
$this->assertTrue($lexer->parse(""));
}
@@ -189,7 +188,7 @@ class TestOfLexer extends DokuWikiTest {
$handler->expects($this->at(7))->method('accept')
->with("z", DOKU_LEXER_UNMATCHED, 13)->will($this->returnValue(true));
- $lexer = new Doku_Lexer($handler);
+ $lexer = new Lexer($handler);
$lexer->addPattern("a+");
$this->assertTrue($lexer->parse("aaaxayyyaxaaaz"));
}
@@ -201,7 +200,7 @@ class TestOfLexer extends DokuWikiTest {
$handler->expects($this->at($i))->method('accept')
->with($target[$i], $this->anything(), $positions[$i])->will($this->returnValue(true));
}
- $lexer = new Doku_Lexer($handler);
+ $lexer = new Lexer($handler);
$lexer->addPattern("a+");
$lexer->addPattern("b+");
$this->assertTrue($lexer->parse("ababbxbaxxxxxxax"));
@@ -227,7 +226,7 @@ class TestOfLexerModes extends DokuWikiTest {
->with("aaaa", DOKU_LEXER_MATCHED,11)->will($this->returnValue(true));
$handler->expects($this->at(7))->method('a')
->with("x", DOKU_LEXER_UNMATCHED,15)->will($this->returnValue(true));
- $lexer = new Doku_Lexer($handler, "a");
+ $lexer = new Lexer($handler, "a");
$lexer->addPattern("a+", "a");
$lexer->addPattern("b+", "b");
$this->assertTrue($lexer->parse("abaabxbaaaxaaaax"));
@@ -261,7 +260,7 @@ class TestOfLexerModes extends DokuWikiTest {
$handler->expects($this->at(12))->method('b')
->with("a", DOKU_LEXER_UNMATCHED,18)->will($this->returnValue(true));
- $lexer = new Doku_Lexer($handler, "a");
+ $lexer = new Lexer($handler, "a");
$lexer->addPattern("a+", "a");
$lexer->addEntryPattern(":", "a", "b");
$lexer->addPattern("b+", "b");
@@ -293,7 +292,7 @@ class TestOfLexerModes extends DokuWikiTest {
->with("b", DOKU_LEXER_UNMATCHED,15)->will($this->returnValue(true));
- $lexer = new Doku_Lexer($handler, "a");
+ $lexer = new Lexer($handler, "a");
$lexer->addPattern("a+", "a");
$lexer->addEntryPattern("(", "a", "b");
$lexer->addPattern("b+", "b");
@@ -314,7 +313,7 @@ class TestOfLexerModes extends DokuWikiTest {
->with("bbb", DOKU_LEXER_SPECIAL,7)->will($this->returnValue(true));
$handler->expects($this->at(5))->method('a')
->with("xx", DOKU_LEXER_UNMATCHED,10)->will($this->returnValue(true));
- $lexer = new Doku_Lexer($handler, "a");
+ $lexer = new Lexer($handler, "a");
$lexer->addPattern("a+", "a");
$lexer->addSpecialPattern("b+", "a", "b");
$this->assertTrue($lexer->parse("aabaaxxbbbxx"));
@@ -326,7 +325,7 @@ class TestOfLexerModes extends DokuWikiTest {
$handler->expects($this->at(1))->method('a')
->with(")", DOKU_LEXER_EXIT,2)->will($this->returnValue(true));
- $lexer = new Doku_Lexer($handler, "a");
+ $lexer = new Lexer($handler, "a");
$lexer->addPattern("a+", "a");
$lexer->addExitPattern(")", "a");
$this->assertFalse($lexer->parse("aa)aa"));
@@ -351,7 +350,7 @@ class TestOfLexerHandlers extends DokuWikiTest {
$handler->expects($this->at(6))->method('a')
->with("b", DOKU_LEXER_UNMATCHED,9)->will($this->returnValue(true));
- $lexer = new Doku_Lexer($handler, "mode_a");
+ $lexer = new Lexer($handler, "mode_a");
$lexer->addPattern("a+", "mode_a");
$lexer->addEntryPattern("(", "mode_a", "mode_b");
$lexer->addPattern("b+", "mode_b");
@@ -389,7 +388,7 @@ class TestOfLexerByteIndices extends DokuWikiTest {
$handler->expects($this->at(5))->method('caught')
->with("</file>", DOKU_LEXER_EXIT, strpos($doc,'</file>'))->will($this->returnValue(true));
- $lexer = new Doku_Lexer($handler, "ignore");
+ $lexer = new Lexer($handler, "ignore");
$lexer->addEntryPattern("<file>", "ignore", "caught");
$lexer->addExitPattern("</file>", "caught");
$lexer->addSpecialPattern('b','caught','special');
@@ -415,7 +414,7 @@ class TestOfLexerByteIndices extends DokuWikiTest {
$handler->expects($this->at(5))->method('caught')
->with("</file>", DOKU_LEXER_EXIT, strpos($doc,'</file>'))->will($this->returnValue(true));
- $lexer = new Doku_Lexer($handler, "ignore");
+ $lexer = new Lexer($handler, "ignore");
$lexer->addEntryPattern('<file>(?=.*</file>)', "ignore", "caught");
$lexer->addExitPattern("</file>", "caught");
$lexer->addSpecialPattern('b','caught','special');
@@ -441,7 +440,7 @@ class TestOfLexerByteIndices extends DokuWikiTest {
$handler->expects($this->at(5))->method('caught')
->with("</file>", DOKU_LEXER_EXIT, strpos($doc,'</file>'))->will($this->returnValue(true));
- $lexer = new Doku_Lexer($handler, "ignore");
+ $lexer = new Lexer($handler, "ignore");
$lexer->addEntryPattern('<file>(?!foo)', "ignore", "caught");
$lexer->addExitPattern("</file>", "caught");
$lexer->addSpecialPattern('b','caught','special');
@@ -467,7 +466,7 @@ class TestOfLexerByteIndices extends DokuWikiTest {
$handler->expects($this->at(5))->method('caught')
->with("</file>", DOKU_LEXER_EXIT, strpos($doc,'</file>'))->will($this->returnValue(true));
- $lexer = new Doku_Lexer($handler, "ignore");
+ $lexer = new Lexer($handler, "ignore");
$lexer->addEntryPattern('<file>', "ignore", "caught");
$lexer->addExitPattern("(?<=d)</file>", "caught");
$lexer->addSpecialPattern('b','caught','special');
@@ -493,7 +492,7 @@ class TestOfLexerByteIndices extends DokuWikiTest {
$handler->expects($this->at(5))->method('caught')
->with("</file>", DOKU_LEXER_EXIT, strpos($doc,'</file>'))->will($this->returnValue(true));
- $lexer = new Doku_Lexer($handler, 'ignore');
+ $lexer = new Lexer($handler, 'ignore');
$lexer->addEntryPattern('<file>', 'ignore', 'caught');
$lexer->addExitPattern('(?<!c)</file>', 'caught');
$lexer->addSpecialPattern('b','caught','special');
@@ -520,7 +519,7 @@ class TestOfLexerByteIndices extends DokuWikiTest {
$handler->expects($this->once())->method('caught')
->with("FOO", DOKU_LEXER_SPECIAL, $matches[0][1])->will($this->returnValue(true));
- $lexer = new Doku_Lexer($handler, "ignore");
+ $lexer = new Lexer($handler, "ignore");
$lexer->addSpecialPattern($pattern,'ignore','caught');
$this->assertTrue($lexer->parse($doc));
diff --git a/_test/tests/inc/parser/parser.inc.php b/_test/tests/inc/parser/parser.inc.php
index c73f8d137..153f67b26 100644
--- a/_test/tests/inc/parser/parser.inc.php
+++ b/_test/tests/inc/parser/parser.inc.php
@@ -1,20 +1,22 @@
<?php
+use dokuwiki\Parsing\Parser;
+
require_once DOKU_INC . 'inc/parser/parser.php';
require_once DOKU_INC . 'inc/parser/handler.php';
+if (!defined('DOKU_PARSER_EOL')) define('DOKU_PARSER_EOL', "\n"); // add this to make handling test cases simpler
abstract class TestOfDoku_Parser extends DokuWikiTest {
- /** @var Doku_Parser */
+ /** @var Parser */
protected $P;
/** @var Doku_Handler */
protected $H;
function setUp() {
parent::setUp();
- $this->P = new Doku_Parser();
$this->H = new Doku_Handler();
- $this->P->Handler = $this->H;
+ $this->P = new Parser($this->H);
}
function tearDown() {
diff --git a/_test/tests/inc/parser/parser_code.test.php b/_test/tests/inc/parser/parser_code.test.php
index df8225f4e..961db7dd2 100644
--- a/_test/tests/inc/parser/parser_code.test.php
+++ b/_test/tests/inc/parser/parser_code.test.php
@@ -1,4 +1,7 @@
<?php
+
+use dokuwiki\Parsing\ParserMode\Code;
+
require_once 'parser.inc.php';
/**
@@ -10,7 +13,7 @@ class TestOfDoku_Parser_Code extends TestOfDoku_Parser {
function setUp() {
parent::setUp();
- $this->P->addMode('code',new Doku_Parser_Mode_Code());
+ $this->P->addMode('code',new Code());
}
function testCode() {
diff --git a/_test/tests/inc/parser/parser_eol.test.php b/_test/tests/inc/parser/parser_eol.test.php
index 6264f8b55..ae5e9cce5 100644
--- a/_test/tests/inc/parser/parser_eol.test.php
+++ b/_test/tests/inc/parser/parser_eol.test.php
@@ -1,10 +1,14 @@
<?php
+
+use dokuwiki\Parsing\ParserMode\Eol;
+use dokuwiki\Parsing\ParserMode\Linebreak;
+
require_once 'parser.inc.php';
class TestOfDoku_Parser_Eol extends TestOfDoku_Parser {
function testEol() {
- $this->P->addMode('eol',new Doku_Parser_Mode_Eol());
+ $this->P->addMode('eol',new Eol());
$this->P->parse("Foo\nBar");
$calls = array (
array('document_start',array()),
@@ -17,7 +21,7 @@ class TestOfDoku_Parser_Eol extends TestOfDoku_Parser {
}
function testEolMultiple() {
- $this->P->addMode('eol',new Doku_Parser_Mode_Eol());
+ $this->P->addMode('eol',new Eol());
$this->P->parse("Foo\n\nbar\nFoo");
$calls = array (
array('document_start',array()),
@@ -33,7 +37,7 @@ class TestOfDoku_Parser_Eol extends TestOfDoku_Parser {
}
function testWinEol() {
- $this->P->addMode('eol',new Doku_Parser_Mode_Eol());
+ $this->P->addMode('eol',new Eol());
$this->P->parse("Foo\r\nBar");
$calls = array (
array('document_start',array()),
@@ -46,7 +50,7 @@ class TestOfDoku_Parser_Eol extends TestOfDoku_Parser {
}
function testLinebreak() {
- $this->P->addMode('linebreak',new Doku_Parser_Mode_Linebreak());
+ $this->P->addMode('linebreak',new Linebreak());
$this->P->parse('Foo\\\\ Bar');
$calls = array (
array('document_start',array()),
@@ -61,8 +65,8 @@ class TestOfDoku_Parser_Eol extends TestOfDoku_Parser {
}
function testLinebreakPlusEol() {
- $this->P->addMode('linebreak',new Doku_Parser_Mode_Linebreak());
- $this->P->addMode('eol',new Doku_Parser_Mode_Eol());
+ $this->P->addMode('linebreak',new Linebreak());
+ $this->P->addMode('eol',new Eol());
$this->P->parse('Foo\\\\'."\n\n".'Bar');
$calls = array (
@@ -80,7 +84,7 @@ class TestOfDoku_Parser_Eol extends TestOfDoku_Parser {
}
function testLinebreakInvalid() {
- $this->P->addMode('linebreak',new Doku_Parser_Mode_Linebreak());
+ $this->P->addMode('linebreak',new Linebreak());
$this->P->parse('Foo\\\\Bar');
$calls = array (
array('document_start',array()),
diff --git a/_test/tests/inc/parser/parser_file.test.php b/_test/tests/inc/parser/parser_file.test.php
index 39bda8a58..407b04a48 100644
--- a/_test/tests/inc/parser/parser_file.test.php
+++ b/_test/tests/inc/parser/parser_file.test.php
@@ -1,11 +1,14 @@
<?php
+
+use dokuwiki\Parsing\ParserMode\File;
+
require_once 'parser.inc.php';
class TestOfDoku_Parser_File extends TestOfDoku_Parser {
function setUp() {
parent::setUp();
- $this->P->addMode('file',new Doku_Parser_Mode_File());
+ $this->P->addMode('file',new File());
}
function testFile() {
diff --git a/_test/tests/inc/parser/parser_footnote.test.php b/_test/tests/inc/parser/parser_footnote.test.php
index 2457fb031..96d7a8407 100644
--- a/_test/tests/inc/parser/parser_footnote.test.php
+++ b/_test/tests/inc/parser/parser_footnote.test.php
@@ -1,11 +1,24 @@
<?php
+
+use dokuwiki\Parsing\Handler\Lists;
+use dokuwiki\Parsing\ParserMode\Code;
+use dokuwiki\Parsing\ParserMode\Eol;
+use dokuwiki\Parsing\ParserMode\Footnote;
+use dokuwiki\Parsing\ParserMode\Formatting;
+use dokuwiki\Parsing\ParserMode\Hr;
+use dokuwiki\Parsing\ParserMode\Listblock;
+use dokuwiki\Parsing\ParserMode\Preformatted;
+use dokuwiki\Parsing\ParserMode\Quote;
+use dokuwiki\Parsing\ParserMode\Table;
+use dokuwiki\Parsing\ParserMode\Unformatted;
+
require_once 'parser.inc.php';
class TestOfDoku_Parser_Footnote extends TestOfDoku_Parser {
function setUp() {
parent::setUp();
- $this->P->addMode('footnote',new Doku_Parser_Mode_Footnote());
+ $this->P->addMode('footnote',new Footnote());
}
function testFootnote() {
@@ -39,7 +52,7 @@ class TestOfDoku_Parser_Footnote extends TestOfDoku_Parser {
}
function testFootnoteLinefeed() {
- $this->P->addMode('eol',new Doku_Parser_Mode_Eol());
+ $this->P->addMode('eol',new Eol());
$this->P->parse("Foo (( testing\ntesting )) Bar");
$calls = array (
array('document_start',array()),
@@ -76,7 +89,7 @@ class TestOfDoku_Parser_Footnote extends TestOfDoku_Parser {
}
function testFootnoteEol() {
- $this->P->addMode('eol',new Doku_Parser_Mode_Eol());
+ $this->P->addMode('eol',new Eol());
$this->P->parse("Foo \nX(( test\ning ))Y\n Bar");
$calls = array (
array('document_start',array()),
@@ -95,7 +108,7 @@ class TestOfDoku_Parser_Footnote extends TestOfDoku_Parser {
}
function testFootnoteStrong() {
- $this->P->addMode('strong',new Doku_Parser_Mode_Formatting('strong'));
+ $this->P->addMode('strong',new Formatting('strong'));
$this->P->parse('Foo (( **testing** )) Bar');
$calls = array (
array('document_start',array()),
@@ -118,7 +131,7 @@ class TestOfDoku_Parser_Footnote extends TestOfDoku_Parser {
}
function testFootnoteHr() {
- $this->P->addMode('hr',new Doku_Parser_Mode_HR());
+ $this->P->addMode('hr',new Hr());
$this->P->parse("Foo (( \n ---- \n )) Bar");
$calls = array (
array('document_start',array()),
@@ -139,7 +152,7 @@ class TestOfDoku_Parser_Footnote extends TestOfDoku_Parser {
}
function testFootnoteCode() {
- $this->P->addMode('code',new Doku_Parser_Mode_Code());
+ $this->P->addMode('code',new Code());
$this->P->parse("Foo (( <code>Test</code> )) Bar");
$calls = array (
array('document_start',array()),
@@ -160,7 +173,7 @@ class TestOfDoku_Parser_Footnote extends TestOfDoku_Parser {
}
function testFootnotePreformatted() {
- $this->P->addMode('preformatted',new Doku_Parser_Mode_Preformatted());
+ $this->P->addMode('preformatted',new Preformatted());
$this->P->parse("Foo (( \n Test\n )) Bar");
$calls = array (
array('document_start',array()),
@@ -181,8 +194,8 @@ class TestOfDoku_Parser_Footnote extends TestOfDoku_Parser {
}
function testFootnotePreformattedEol() {
- $this->P->addMode('preformatted',new Doku_Parser_Mode_Preformatted());
- $this->P->addMode('eol',new Doku_Parser_Mode_Eol());
+ $this->P->addMode('preformatted',new Preformatted());
+ $this->P->addMode('eol',new Eol());
$this->P->parse("Foo (( \n Test\n )) Bar");
$calls = array (
array('document_start',array()),
@@ -204,7 +217,7 @@ class TestOfDoku_Parser_Footnote extends TestOfDoku_Parser {
}
function testFootnoteUnformatted() {
- $this->P->addMode('unformatted',new Doku_Parser_Mode_Unformatted());
+ $this->P->addMode('unformatted',new Unformatted());
$this->P->parse("Foo (( <nowiki>Test</nowiki> )) Bar");
$calls = array (
array('document_start',array()),
@@ -225,7 +238,7 @@ class TestOfDoku_Parser_Footnote extends TestOfDoku_Parser {
}
function testFootnoteNotHeader() {
- $this->P->addMode('unformatted',new Doku_Parser_Mode_Unformatted());
+ $this->P->addMode('unformatted',new Unformatted());
$this->P->parse("Foo (( \n====Test====\n )) Bar");
$calls = array (
array('document_start',array()),
@@ -244,7 +257,7 @@ class TestOfDoku_Parser_Footnote extends TestOfDoku_Parser {
}
function testFootnoteTable() {
- $this->P->addMode('table',new Doku_Parser_Mode_Table());
+ $this->P->addMode('table',new Table());
$this->P->parse("Foo ((
| Row 0 Col 1 | Row 0 Col 2 | Row 0 Col 3 |
| Row 1 Col 1 | Row 1 Col 2 | Row 1 Col 3 |
@@ -290,7 +303,7 @@ class TestOfDoku_Parser_Footnote extends TestOfDoku_Parser {
}
function testFootnoteList() {
- $this->P->addMode('listblock',new Doku_Parser_Mode_ListBlock());
+ $this->P->addMode('listblock',new ListBlock());
$this->P->parse("Foo ((
*A
* B
@@ -303,7 +316,7 @@ class TestOfDoku_Parser_Footnote extends TestOfDoku_Parser {
array('nest', array ( array (
array('footnote_open',array()),
array('listu_open',array()),
- array('listitem_open',array(1,Doku_Handler_List::NODE)),
+ array('listitem_open',array(1,Lists::NODE)),
array('listcontent_open',array()),
array('cdata',array("A")),
array('listcontent_close',array()),
@@ -332,7 +345,7 @@ class TestOfDoku_Parser_Footnote extends TestOfDoku_Parser {
}
function testFootnoteQuote() {
- $this->P->addMode('quote',new Doku_Parser_Mode_Quote());
+ $this->P->addMode('quote',new Quote());
$this->P->parse("Foo ((
> def
>>ghi
@@ -361,7 +374,7 @@ class TestOfDoku_Parser_Footnote extends TestOfDoku_Parser {
}
function testFootnoteNesting() {
- $this->P->addMode('strong',new Doku_Parser_Mode_Formatting('strong'));
+ $this->P->addMode('strong',new Formatting('strong'));
$this->P->parse("(( a ** (( b )) ** c ))");
$calls = array(
diff --git a/_test/tests/inc/parser/parser_headers.test.php b/_test/tests/inc/parser/parser_headers.test.php
index a1bf7d2ba..d061899dd 100644
--- a/_test/tests/inc/parser/parser_headers.test.php
+++ b/_test/tests/inc/parser/parser_headers.test.php
@@ -1,10 +1,14 @@
<?php
+
+use dokuwiki\Parsing\ParserMode\Eol;
+use dokuwiki\Parsing\ParserMode\Header;
+
require_once 'parser.inc.php';
class TestOfDoku_Parser_Headers extends TestOfDoku_Parser {
function testHeader1() {
- $this->P->addMode('header',new Doku_Parser_Mode_Header());
+ $this->P->addMode('header',new Header());
$this->P->parse("abc \n ====== Header ====== \n def");
$calls = array (
array('document_start',array()),
@@ -23,7 +27,7 @@ class TestOfDoku_Parser_Headers extends TestOfDoku_Parser {
}
function testHeader2() {
- $this->P->addMode('header',new Doku_Parser_Mode_Header());
+ $this->P->addMode('header',new Header());
$this->P->parse("abc \n ===== Header ===== \n def");
$calls = array (
array('document_start',array()),
@@ -42,7 +46,7 @@ class TestOfDoku_Parser_Headers extends TestOfDoku_Parser {
}
function testHeader3() {
- $this->P->addMode('header',new Doku_Parser_Mode_Header());
+ $this->P->addMode('header',new Header());
$this->P->parse("abc \n ==== Header ==== \n def");
$calls = array (
array('document_start',array()),
@@ -61,7 +65,7 @@ class TestOfDoku_Parser_Headers extends TestOfDoku_Parser {
}
function testHeader4() {
- $this->P->addMode('header',new Doku_Parser_Mode_Header());
+ $this->P->addMode('header',new Header());
$this->P->parse("abc \n === Header === \n def");
$calls = array (
array('document_start',array()),
@@ -80,7 +84,7 @@ class TestOfDoku_Parser_Headers extends TestOfDoku_Parser {
}
function testHeader5() {
- $this->P->addMode('header',new Doku_Parser_Mode_Header());
+ $this->P->addMode('header',new Header());
$this->P->parse("abc \n == Header == \n def");
$calls = array (
array('document_start',array()),
@@ -99,7 +103,7 @@ class TestOfDoku_Parser_Headers extends TestOfDoku_Parser {
}
function testHeader2UnevenSmaller() {
- $this->P->addMode('header',new Doku_Parser_Mode_Header());
+ $this->P->addMode('header',new Header());
$this->P->parse("abc \n ===== Header == \n def");
$calls = array (
array('document_start',array()),
@@ -118,7 +122,7 @@ class TestOfDoku_Parser_Headers extends TestOfDoku_Parser {
}
function testHeader2UnevenBigger() {
- $this->P->addMode('header',new Doku_Parser_Mode_Header());
+ $this->P->addMode('header',new Header());
$this->P->parse("abc \n ===== Header =========== \n def");
$calls = array (
array('document_start',array()),
@@ -137,7 +141,7 @@ class TestOfDoku_Parser_Headers extends TestOfDoku_Parser {
}
function testHeaderLarge() {
- $this->P->addMode('header',new Doku_Parser_Mode_Header());
+ $this->P->addMode('header',new Header());
$this->P->parse("abc \n ======= Header ======= \n def");
$calls = array (
array('document_start',array()),
@@ -156,7 +160,7 @@ class TestOfDoku_Parser_Headers extends TestOfDoku_Parser {
}
function testHeaderSmall() {
- $this->P->addMode('header',new Doku_Parser_Mode_Header());
+ $this->P->addMode('header',new Header());
$this->P->parse("abc \n= Header =\n def");
$calls = array (
array('document_start',array()),
@@ -170,7 +174,7 @@ class TestOfDoku_Parser_Headers extends TestOfDoku_Parser {
function testHeader1Mixed() {
- $this->P->addMode('header',new Doku_Parser_Mode_Header());
+ $this->P->addMode('header',new Header());
$this->P->parse("abc \n====== == Header == ======\n def");
$calls = array (
array('document_start',array()),
@@ -189,7 +193,7 @@ class TestOfDoku_Parser_Headers extends TestOfDoku_Parser {
}
function testHeader5Mixed() {
- $this->P->addMode('header',new Doku_Parser_Mode_Header());
+ $this->P->addMode('header',new Header());
$this->P->parse("abc \n== ====== Header ====== ==\n def");
$calls = array (
array('document_start',array()),
@@ -208,7 +212,7 @@ class TestOfDoku_Parser_Headers extends TestOfDoku_Parser {
}
function testHeaderMultiline() {
- $this->P->addMode('header',new Doku_Parser_Mode_Header());
+ $this->P->addMode('header',new Header());
$this->P->parse("abc \n== ====== Header\n ====== ==\n def");
$calls = array (
array('document_start',array()),
@@ -227,14 +231,14 @@ class TestOfDoku_Parser_Headers extends TestOfDoku_Parser {
}
# function testNoToc() {
-# $this->P->addMode('notoc',new Doku_Parser_Mode_NoToc());
+# $this->P->addMode('notoc',new NoToc());
# $this->P->parse('abc ~~NOTOC~~ def');
# $this->assertFalse($this->H->meta['toc']);
# }
function testHeader1Eol() {
- $this->P->addMode('header',new Doku_Parser_Mode_Header());
- $this->P->addMode('eol',new Doku_Parser_Mode_Eol());
+ $this->P->addMode('header',new Header());
+ $this->P->addMode('eol',new Eol());
$this->P->parse("abc \n ====== Header ====== \n def");
$calls = array (
array('document_start',array()),
@@ -254,7 +258,7 @@ class TestOfDoku_Parser_Headers extends TestOfDoku_Parser {
}
function testHeaderMulti2() {
- $this->P->addMode('header',new Doku_Parser_Mode_Header());
+ $this->P->addMode('header',new Header());
$this->P->parse("abc \n ====== Header ====== \n def abc \n ===== Header2 ===== \n def");
$calls = array (
array('document_start',array()),
diff --git a/_test/tests/inc/parser/parser_i18n.test.php b/_test/tests/inc/parser/parser_i18n.test.php
index 096f2e227..b10bd9f3e 100644
--- a/_test/tests/inc/parser/parser_i18n.test.php
+++ b/_test/tests/inc/parser/parser_i18n.test.php
@@ -1,4 +1,11 @@
<?php
+
+use dokuwiki\Parsing\ParserMode\Acronym;
+use dokuwiki\Parsing\ParserMode\Formatting;
+use dokuwiki\Parsing\ParserMode\Header;
+use dokuwiki\Parsing\ParserMode\Internallink;
+use dokuwiki\Parsing\ParserMode\Table;
+
require_once 'parser.inc.php';
class TestOfDoku_Parser_i18n extends TestOfDoku_Parser {
@@ -9,7 +16,7 @@ class TestOfDoku_Parser_i18n extends TestOfDoku_Parser {
'subscript', 'superscript', 'deleted',
);
foreach ( $formats as $format ) {
- $this->P->addMode($format,new Doku_Parser_Mode_Formatting($format));
+ $this->P->addMode($format,new Formatting($format));
}
$this->P->parse("I**ñ**t__ë__r//n//â<sup>t</sup>i<sub>ô</sub>n''à''liz<del>æ</del>tiøn");
$calls = array (
@@ -51,7 +58,7 @@ class TestOfDoku_Parser_i18n extends TestOfDoku_Parser {
}
function testHeader() {
- $this->P->addMode('header',new Doku_Parser_Mode_Header());
+ $this->P->addMode('header',new Header());
$this->P->parse("Foo\n ==== Iñtërnâtiônàlizætiøn ==== \n Bar");
$calls = array (
array('document_start',array()),
@@ -70,7 +77,7 @@ class TestOfDoku_Parser_i18n extends TestOfDoku_Parser {
}
function testTable() {
- $this->P->addMode('table',new Doku_Parser_Mode_Table());
+ $this->P->addMode('table',new Table());
$this->P->parse('
abc
| Row 0 Col 1 | Iñtërnâtiônàlizætiøn | Row 0 Col 3 |
@@ -115,7 +122,7 @@ def');
function testAcronym() {
$t = array('Iñtërnâtiônàlizætiøn');
- $this->P->addMode('acronym',new Doku_Parser_Mode_Acronym($t));
+ $this->P->addMode('acronym',new Acronym($t));
$this->P->parse("Foo Iñtërnâtiônàlizætiøn Bar");
$calls = array (
array('document_start',array()),
@@ -130,7 +137,7 @@ def');
}
function testInterwiki() {
- $this->P->addMode('internallink',new Doku_Parser_Mode_InternalLink());
+ $this->P->addMode('internallink',new InternalLink());
$this->P->parse("Foo [[wp>Iñtërnâtiônàlizætiøn|Iñtërnâtiônàlizætiøn]] Bar");
$calls = array (
array('document_start',array()),
@@ -145,7 +152,7 @@ def');
}
function testInternalLink() {
- $this->P->addMode('internallink',new Doku_Parser_Mode_InternalLink());
+ $this->P->addMode('internallink',new InternalLink());
$this->P->parse("Foo [[x:Iñtërnâtiônàlizætiøn:y:foo_bar:z|Iñtërnâtiônàlizætiøn]] Bar");
$calls = array (
array('document_start',array()),
diff --git a/_test/tests/inc/parser/parser_links.test.php b/_test/tests/inc/parser/parser_links.test.php
index ee001e73a..cbcfcb87b 100644
--- a/_test/tests/inc/parser/parser_links.test.php
+++ b/_test/tests/inc/parser/parser_links.test.php
@@ -1,4 +1,13 @@
<?php
+
+use dokuwiki\Parsing\ParserMode\Camelcaselink;
+use dokuwiki\Parsing\ParserMode\Emaillink;
+use dokuwiki\Parsing\ParserMode\Externallink;
+use dokuwiki\Parsing\ParserMode\Filelink;
+use dokuwiki\Parsing\ParserMode\Internallink;
+use dokuwiki\Parsing\ParserMode\Media;
+use dokuwiki\Parsing\ParserMode\Windowssharelink;
+
require_once 'parser.inc.php';
/**
@@ -9,7 +18,7 @@ require_once 'parser.inc.php';
class TestOfDoku_Parser_Links extends TestOfDoku_Parser {
function testExternalLinkSimple() {
- $this->P->addMode('externallink',new Doku_Parser_Mode_ExternalLink());
+ $this->P->addMode('externallink',new Externallink());
$this->P->parse("Foo http://www.google.com Bar");
$calls = array (
array('document_start',array()),
@@ -24,7 +33,7 @@ class TestOfDoku_Parser_Links extends TestOfDoku_Parser {
}
function testExternalLinkCase() {
- $this->P->addMode('externallink',new Doku_Parser_Mode_ExternalLink());
+ $this->P->addMode('externallink',new Externallink());
$this->P->parse("Foo HTTP://WWW.GOOGLE.COM Bar");
$calls = array (
array('document_start',array()),
@@ -39,7 +48,7 @@ class TestOfDoku_Parser_Links extends TestOfDoku_Parser {
}
function testExternalIPv4() {
- $this->P->addMode('externallink',new Doku_Parser_Mode_ExternalLink());
+ $this->P->addMode('externallink',new Externallink());
$this->P->parse("Foo http://123.123.3.21/foo Bar");
$calls = array (
array('document_start',array()),
@@ -54,7 +63,7 @@ class TestOfDoku_Parser_Links extends TestOfDoku_Parser {
}
function testExternalIPv6() {
- $this->P->addMode('externallink',new Doku_Parser_Mode_ExternalLink());
+ $this->P->addMode('externallink',new Externallink());
$this->P->parse("Foo http://[3ffe:2a00:100:7031::1]/foo Bar");
$calls = array (
array('document_start',array()),
@@ -96,8 +105,8 @@ class TestOfDoku_Parser_Links extends TestOfDoku_Parser {
$name = $title;
}
$this->setup();
- $this->P->addMode('internallink',new Doku_Parser_Mode_InternalLink());
- $this->P->addMode('externallink',new Doku_Parser_Mode_ExternalLink());
+ $this->P->addMode('internallink',new Internallink());
+ $this->P->addMode('externallink',new Externallink());
$this->P->parse("Foo $source Bar");
$calls = array (
array('document_start',array()),
@@ -117,7 +126,7 @@ class TestOfDoku_Parser_Links extends TestOfDoku_Parser {
}
function testExternalLinkJavascript() {
- $this->P->addMode('externallink',new Doku_Parser_Mode_ExternalLink());
+ $this->P->addMode('externallink',new Externallink());
$this->P->parse("Foo javascript:alert('XSS'); Bar");
$calls = array (
array('document_start',array()),
@@ -130,7 +139,7 @@ class TestOfDoku_Parser_Links extends TestOfDoku_Parser {
}
function testExternalWWWLink() {
- $this->P->addMode('externallink',new Doku_Parser_Mode_ExternalLink());
+ $this->P->addMode('externallink',new Externallink());
$this->P->parse("Foo www.google.com Bar");
$calls = array (
array('document_start',array()),
@@ -145,7 +154,7 @@ class TestOfDoku_Parser_Links extends TestOfDoku_Parser {
}
function testExternalWWWLinkInPath() {
- $this->P->addMode('externallink',new Doku_Parser_Mode_ExternalLink());
+ $this->P->addMode('externallink',new Externallink());
// See issue #936. Should NOT generate a link!
$this->P->parse("Foo /home/subdir/www/www.something.de/somedir/ Bar");
$calls = array (
@@ -159,7 +168,7 @@ class TestOfDoku_Parser_Links extends TestOfDoku_Parser {
}
function testExternalWWWLinkFollowingPath() {
- $this->P->addMode('externallink',new Doku_Parser_Mode_ExternalLink());
+ $this->P->addMode('externallink',new Externallink());
$this->P->parse("Foo /home/subdir/www/ www.something.de/somedir/ Bar");
$calls = array (
array('document_start',array()),
@@ -174,7 +183,7 @@ class TestOfDoku_Parser_Links extends TestOfDoku_Parser {
}
function testExternalFTPLink() {
- $this->P->addMode('externallink',new Doku_Parser_Mode_ExternalLink());
+ $this->P->addMode('externallink',new Externallink());
$this->P->parse("Foo ftp.sunsite.com Bar");
$calls = array (
array('document_start',array()),
@@ -189,7 +198,7 @@ class TestOfDoku_Parser_Links extends TestOfDoku_Parser {
}
function testExternalFTPLinkInPath() {
- $this->P->addMode('externallink',new Doku_Parser_Mode_ExternalLink());
+ $this->P->addMode('externallink',new Externallink());
// See issue #936. Should NOT generate a link!
$this->P->parse("Foo /home/subdir/www/ftp.something.de/somedir/ Bar");
$calls = array (
@@ -203,7 +212,7 @@ class TestOfDoku_Parser_Links extends TestOfDoku_Parser {
}
function testExternalFTPLinkFollowingPath() {
- $this->P->addMode('externallink',new Doku_Parser_Mode_ExternalLink());
+ $this->P->addMode('externallink',new Externallink());
$this->P->parse("Foo /home/subdir/www/ ftp.something.de/somedir/ Bar");
$calls = array (
array('document_start',array()),
@@ -218,7 +227,7 @@ class TestOfDoku_Parser_Links extends TestOfDoku_Parser {
}
function testEmail() {
- $this->P->addMode('emaillink',new Doku_Parser_Mode_Emaillink());
+ $this->P->addMode('emaillink',new Emaillink());
$this->P->parse("Foo <bugs@php.net> Bar");
$calls = array (
array('document_start',array()),
@@ -233,7 +242,7 @@ class TestOfDoku_Parser_Links extends TestOfDoku_Parser {
}
function testEmailRFC2822() {
- $this->P->addMode('emaillink',new Doku_Parser_Mode_Emaillink());
+ $this->P->addMode('emaillink',new Emaillink());
$this->P->parse("Foo <~fix+bug's.for/ev{e}r@php.net> Bar");
$calls = array (
array('document_start',array()),
@@ -248,7 +257,7 @@ class TestOfDoku_Parser_Links extends TestOfDoku_Parser {
}
function testEmailCase() {
- $this->P->addMode('emaillink',new Doku_Parser_Mode_Emaillink());
+ $this->P->addMode('emaillink',new Emaillink());
$this->P->parse("Foo <bugs@pHp.net> Bar");
$calls = array (
array('document_start',array()),
@@ -264,7 +273,7 @@ class TestOfDoku_Parser_Links extends TestOfDoku_Parser {
function testInternalLinkOneChar() {
- $this->P->addMode('internallink',new Doku_Parser_Mode_InternalLink());
+ $this->P->addMode('internallink',new Internallink());
$this->P->parse("Foo [[l]] Bar");
$calls = array (
array('document_start',array()),
@@ -279,7 +288,7 @@ class TestOfDoku_Parser_Links extends TestOfDoku_Parser {
}
function testInternalLinkNoChar() {
- $this->P->addMode('internallink',new Doku_Parser_Mode_InternalLink());
+ $this->P->addMode('internallink',new Internallink());
$this->P->parse("Foo [[]] Bar");
$calls = array (
array('document_start',array()),
@@ -294,7 +303,7 @@ class TestOfDoku_Parser_Links extends TestOfDoku_Parser {
}
function testInternalLinkNamespaceNoTitle() {
- $this->P->addMode('internallink',new Doku_Parser_Mode_InternalLink());
+ $this->P->addMode('internallink',new Internallink());
$this->P->parse("Foo [[foo:bar]] Bar");
$calls = array (
array('document_start',array()),
@@ -309,7 +318,7 @@ class TestOfDoku_Parser_Links extends TestOfDoku_Parser {
}
function testInternalLinkNamespace() {
- $this->P->addMode('internallink',new Doku_Parser_Mode_InternalLink());
+ $this->P->addMode('internallink',new Internallink());
$this->P->parse("Foo [[x:1:y:foo_bar:z|Test]] Bar");
$calls = array (
array('document_start',array()),
@@ -324,7 +333,7 @@ class TestOfDoku_Parser_Links extends TestOfDoku_Parser {
}
function testInternalLinkSectionRef() {
- $this->P->addMode('internallink',new Doku_Parser_Mode_InternalLink());
+ $this->P->addMode('internallink',new Internallink());
$this->P->parse("Foo [[wiki:syntax#internal|Syntax]] Bar");
$calls = array (
array('document_start',array()),
@@ -339,7 +348,7 @@ class TestOfDoku_Parser_Links extends TestOfDoku_Parser {
}
function testInternalLinkCodeFollows() {
- $this->P->addMode('internallink',new Doku_Parser_Mode_InternalLink());
+ $this->P->addMode('internallink',new Internallink());
$this->P->parse("Foo [[wiki:internal:link|Test]] Bar <code>command [arg1 [arg2 [arg3]]]</code>");
$calls = array (
array('document_start',array()),
@@ -354,7 +363,7 @@ class TestOfDoku_Parser_Links extends TestOfDoku_Parser {
}
function testInternalLinkCodeFollows2() {
- $this->P->addMode('internallink',new Doku_Parser_Mode_InternalLink());
+ $this->P->addMode('internallink',new Internallink());
$this->P->parse("Foo [[wiki:internal:link|[Square brackets in title] Test]] Bar <code>command [arg1 [arg2 [arg3]]]</code>");
$calls = array (
array('document_start',array()),
@@ -369,7 +378,7 @@ class TestOfDoku_Parser_Links extends TestOfDoku_Parser {
}
function testExternalInInternalLink() {
- $this->P->addMode('internallink',new Doku_Parser_Mode_InternalLink());
+ $this->P->addMode('internallink',new Internallink());
$this->P->parse("Foo [[http://www.google.com|Google]] Bar");
$calls = array (
array('document_start',array()),
@@ -384,7 +393,7 @@ class TestOfDoku_Parser_Links extends TestOfDoku_Parser {
}
function testExternalInInternalLink2() {
- $this->P->addMode('internallink',new Doku_Parser_Mode_InternalLink());
+ $this->P->addMode('internallink',new Internallink());
$this->P->parse("Foo [[http://www.google.com?test[]=squarebracketsinurl|Google]] Bar");
$calls = array (
array('document_start',array()),
@@ -399,7 +408,7 @@ class TestOfDoku_Parser_Links extends TestOfDoku_Parser {
}
function testExternalInInternalLink2CodeFollows() {
- $this->P->addMode('internallink',new Doku_Parser_Mode_InternalLink());
+ $this->P->addMode('internallink',new Internallink());
$this->P->parse("Foo [[http://www.google.com?test[]=squarebracketsinurl|Google]] Bar <code>command [arg1 [arg2 [arg3]]]</code>");
$calls = array (
array('document_start',array()),
@@ -414,7 +423,7 @@ class TestOfDoku_Parser_Links extends TestOfDoku_Parser {
}
function testTwoInternalLinks() {
- $this->P->addMode('internallink',new Doku_Parser_Mode_InternalLink());
+ $this->P->addMode('internallink',new Internallink());
$this->P->parse("Foo [[foo:bar|one]] and [[bar:foo|two]] Bar");
$calls = array (
array('document_start',array()),
@@ -432,7 +441,7 @@ class TestOfDoku_Parser_Links extends TestOfDoku_Parser {
function testInterwikiLink() {
- $this->P->addMode('internallink',new Doku_Parser_Mode_InternalLink());
+ $this->P->addMode('internallink',new Internallink());
$this->P->parse("Foo [[iw>somepage|Some Page]] Bar");
$calls = array (
array('document_start',array()),
@@ -447,7 +456,7 @@ class TestOfDoku_Parser_Links extends TestOfDoku_Parser {
}
function testInterwikiLinkCase() {
- $this->P->addMode('internallink',new Doku_Parser_Mode_InternalLink());
+ $this->P->addMode('internallink',new Internallink());
$this->P->parse("Foo [[IW>somepage|Some Page]] Bar");
$calls = array (
array('document_start',array()),
@@ -462,7 +471,7 @@ class TestOfDoku_Parser_Links extends TestOfDoku_Parser {
}
function testInterwikiPedia() {
- $this->P->addMode('internallink',new Doku_Parser_Mode_InternalLink());
+ $this->P->addMode('internallink',new Internallink());
$this->P->parse("Foo [[wp>Callback_(computer_science)|callbacks]] Bar");
$calls = array (
array('document_start',array()),
@@ -477,7 +486,7 @@ class TestOfDoku_Parser_Links extends TestOfDoku_Parser {
}
function testCamelCase() {
- $this->P->addMode('camelcaselink',new Doku_Parser_Mode_CamelCaseLink());
+ $this->P->addMode('camelcaselink',new Camelcaselink());
$this->P->parse("Foo FooBar Bar");
$calls = array (
array('document_start',array()),
@@ -492,7 +501,7 @@ class TestOfDoku_Parser_Links extends TestOfDoku_Parser {
}
function testFileLink() {
- $this->P->addMode('filelink',new Doku_Parser_Mode_FileLink());
+ $this->P->addMode('filelink',new FileLink());
$this->P->parse('Foo file://temp/file.txt Bar');
$calls = array (
array('document_start',array()),
@@ -507,7 +516,7 @@ class TestOfDoku_Parser_Links extends TestOfDoku_Parser {
}
function testFileLinkInternal() {
- $this->P->addMode('internallink',new Doku_Parser_Mode_InternalLink());
+ $this->P->addMode('internallink',new Internallink());
$this->P->parse('Foo [[file://temp/file.txt|Some File]] Bar');
$calls = array (
array('document_start',array()),
@@ -522,7 +531,7 @@ class TestOfDoku_Parser_Links extends TestOfDoku_Parser {
}
function testWindowsShareLink() {
- $this->P->addMode('windowssharelink',new Doku_Parser_Mode_WindowsShareLink());
+ $this->P->addMode('windowssharelink',new Windowssharelink());
$this->P->parse('Foo \\\server\share Bar');
$calls = array (
array('document_start',array()),
@@ -537,7 +546,7 @@ class TestOfDoku_Parser_Links extends TestOfDoku_Parser {
}
function testWindowsShareLinkHyphen() {
- $this->P->addMode('windowssharelink',new Doku_Parser_Mode_WindowsShareLink());
+ $this->P->addMode('windowssharelink',new Windowssharelink());
$this->P->parse('Foo \\\server\share-hyphen Bar');
$calls = array (
array('document_start',array()),
@@ -552,7 +561,7 @@ class TestOfDoku_Parser_Links extends TestOfDoku_Parser {
}
function testWindowsShareLinkInternal() {
- $this->P->addMode('internallink',new Doku_Parser_Mode_InternalLink());
+ $this->P->addMode('internallink',new Internallink());
$this->P->parse('Foo [[\\\server\share|My Documents]] Bar');
$calls = array (
array('document_start',array()),
@@ -567,7 +576,7 @@ class TestOfDoku_Parser_Links extends TestOfDoku_Parser {
}
function testMediaInternal() {
- $this->P->addMode('media',new Doku_Parser_Mode_Media());
+ $this->P->addMode('media',new Media());
$this->P->parse('Foo {{img.gif}} Bar');
$calls = array (
array('document_start',array()),
@@ -582,7 +591,7 @@ class TestOfDoku_Parser_Links extends TestOfDoku_Parser {
}
function testMediaInternalLinkOnly() {
- $this->P->addMode('media',new Doku_Parser_Mode_Media());
+ $this->P->addMode('media',new Media());
$this->P->parse('Foo {{img.gif?linkonly}} Bar');
$calls = array (
array('document_start',array()),
@@ -597,7 +606,7 @@ class TestOfDoku_Parser_Links extends TestOfDoku_Parser {
}
function testMediaNotImage() {
- $this->P->addMode('media',new Doku_Parser_Mode_Media());
+ $this->P->addMode('media',new Media());
$this->P->parse('Foo {{foo.txt?10x10|Some File}} Bar');
$calls = array (
array('document_start',array()),
@@ -612,7 +621,7 @@ class TestOfDoku_Parser_Links extends TestOfDoku_Parser {
}
function testMediaInternalLAlign() {
- $this->P->addMode('media',new Doku_Parser_Mode_Media());
+ $this->P->addMode('media',new Media());
$this->P->parse('Foo {{img.gif }} Bar');
$calls = array (
array('document_start',array()),
@@ -627,7 +636,7 @@ class TestOfDoku_Parser_Links extends TestOfDoku_Parser {
}
function testMediaInternalRAlign() {
- $this->P->addMode('media',new Doku_Parser_Mode_Media());
+ $this->P->addMode('media',new Media());
$this->P->parse('Foo {{ img.gif}} Bar');
$calls = array (
array('document_start',array()),
@@ -642,7 +651,7 @@ class TestOfDoku_Parser_Links extends TestOfDoku_Parser {
}
function testMediaInternalCenter() {
- $this->P->addMode('media',new Doku_Parser_Mode_Media());
+ $this->P->addMode('media',new Media());
$this->P->parse('Foo {{ img.gif }} Bar');
$calls = array (
array('document_start',array()),
@@ -657,7 +666,7 @@ class TestOfDoku_Parser_Links extends TestOfDoku_Parser {
}
function testMediaInternalParams() {
- $this->P->addMode('media',new Doku_Parser_Mode_Media());
+ $this->P->addMode('media',new Media());
$this->P->parse('Foo {{img.gif?50x100nocache}} Bar');
$calls = array (
array('document_start',array()),
@@ -672,7 +681,7 @@ class TestOfDoku_Parser_Links extends TestOfDoku_Parser {
}
function testMediaInternalTitle() {
- $this->P->addMode('media',new Doku_Parser_Mode_Media());
+ $this->P->addMode('media',new Media());
$this->P->parse('Foo {{img.gif?50x100|Some Image}} Bar');
$calls = array (
array('document_start',array()),
@@ -687,7 +696,7 @@ class TestOfDoku_Parser_Links extends TestOfDoku_Parser {
}
function testMediaExternal() {
- $this->P->addMode('media',new Doku_Parser_Mode_Media());
+ $this->P->addMode('media',new Media());
$this->P->parse('Foo {{http://www.google.com/img.gif}} Bar');
$calls = array (
array('document_start',array()),
@@ -702,7 +711,7 @@ class TestOfDoku_Parser_Links extends TestOfDoku_Parser {
}
function testMediaExternalParams() {
- $this->P->addMode('media',new Doku_Parser_Mode_Media());
+ $this->P->addMode('media',new Media());
$this->P->parse('Foo {{http://www.google.com/img.gif?50x100nocache}} Bar');
$calls = array (
array('document_start',array()),
@@ -717,7 +726,7 @@ class TestOfDoku_Parser_Links extends TestOfDoku_Parser {
}
function testMediaExternalTitle() {
- $this->P->addMode('media',new Doku_Parser_Mode_Media());
+ $this->P->addMode('media',new Media());
$this->P->parse('Foo {{http://www.google.com/img.gif?50x100|Some Image}} Bar');
$calls = array (
array('document_start',array()),
@@ -733,7 +742,7 @@ class TestOfDoku_Parser_Links extends TestOfDoku_Parser {
}
function testMediaInInternalLink() {
- $this->P->addMode('internallink',new Doku_Parser_Mode_InternalLink());
+ $this->P->addMode('internallink',new Internallink());
$this->P->parse("Foo [[x:1:y:foo_bar:z|{{img.gif?10x20nocache|Some Image}}]] Bar");
$image = array(
@@ -760,7 +769,7 @@ class TestOfDoku_Parser_Links extends TestOfDoku_Parser {
}
function testMediaNoImageInInternalLink() {
- $this->P->addMode('internallink',new Doku_Parser_Mode_InternalLink());
+ $this->P->addMode('internallink',new Internallink());
$this->P->parse("Foo [[x:1:y:foo_bar:z|{{foo.txt?10x20nocache|Some Image}}]] Bar");
$image = array(
@@ -787,7 +796,7 @@ class TestOfDoku_Parser_Links extends TestOfDoku_Parser {
}
function testMediaInEmailLink() {
- $this->P->addMode('internallink',new Doku_Parser_Mode_InternalLink());
+ $this->P->addMode('internallink',new Internallink());
$this->P->parse("Foo [[foo@example.com|{{img.gif?10x20nocache|Some Image}}]] Bar");
$image = array(
@@ -814,7 +823,7 @@ class TestOfDoku_Parser_Links extends TestOfDoku_Parser {
}
function testNestedMedia() {
- $this->P->addMode('media',new Doku_Parser_Mode_Media());
+ $this->P->addMode('media',new Media());
$this->P->parse('Foo {{img.gif|{{foo.gif|{{bar.gif|Bar}}}}}} Bar');
$calls = array (
array('document_start',array()),
diff --git a/_test/tests/inc/parser/parser_lists.test.php b/_test/tests/inc/parser/parser_lists.test.php
index 6acaff637..2176af76d 100644
--- a/_test/tests/inc/parser/parser_lists.test.php
+++ b/_test/tests/inc/parser/parser_lists.test.php
@@ -1,10 +1,19 @@
<?php
+
+use dokuwiki\Parsing\Handler\Lists;
+use dokuwiki\Parsing\ParserMode\Eol;
+use dokuwiki\Parsing\ParserMode\Footnote;
+use dokuwiki\Parsing\ParserMode\Formatting;
+use dokuwiki\Parsing\ParserMode\Linebreak;
+use dokuwiki\Parsing\ParserMode\Listblock;
+use dokuwiki\Parsing\ParserMode\Unformatted;
+
require_once 'parser.inc.php';
class TestOfDoku_Parser_Lists extends TestOfDoku_Parser {
function testUnorderedList() {
- $this->P->addMode('listblock',new Doku_Parser_Mode_ListBlock());
+ $this->P->addMode('listblock',new Listblock());
$this->P->parse('
*A
* B
@@ -13,7 +22,7 @@ class TestOfDoku_Parser_Lists extends TestOfDoku_Parser {
$calls = array (
array('document_start',array()),
array('listu_open',array()),
- array('listitem_open',array(1,Doku_Handler_List::NODE)),
+ array('listitem_open',array(1,Lists::NODE)),
array('listcontent_open',array()),
array('cdata',array("A")),
array('listcontent_close',array()),
@@ -37,7 +46,7 @@ class TestOfDoku_Parser_Lists extends TestOfDoku_Parser {
}
function testOrderedList() {
- $this->P->addMode('listblock',new Doku_Parser_Mode_ListBlock());
+ $this->P->addMode('listblock',new Listblock());
$this->P->parse('
-A
- B
@@ -46,7 +55,7 @@ class TestOfDoku_Parser_Lists extends TestOfDoku_Parser {
$calls = array (
array('document_start',array()),
array('listo_open',array()),
- array('listitem_open',array(1,Doku_Handler_List::NODE)),
+ array('listitem_open',array(1,Lists::NODE)),
array('listcontent_open',array()),
array('cdata',array("A")),
array('listcontent_close',array()),
@@ -71,7 +80,7 @@ class TestOfDoku_Parser_Lists extends TestOfDoku_Parser {
function testMixedList() {
- $this->P->addMode('listblock',new Doku_Parser_Mode_ListBlock());
+ $this->P->addMode('listblock',new Listblock());
$this->P->parse('
-A
* B
@@ -80,7 +89,7 @@ class TestOfDoku_Parser_Lists extends TestOfDoku_Parser {
$calls = array (
array('document_start',array()),
array('listo_open',array()),
- array('listitem_open',array(1,Doku_Handler_List::NODE)),
+ array('listitem_open',array(1,Lists::NODE)),
array('listcontent_open',array()),
array('cdata',array("A")),
array('listcontent_close',array()),
@@ -102,14 +111,14 @@ class TestOfDoku_Parser_Lists extends TestOfDoku_Parser {
);
$this->assertEquals(array_map('stripbyteindex',$this->H->calls),$calls);
}
-
+
function testUnorderedListWinEOL() {
- $this->P->addMode('listblock',new Doku_Parser_Mode_ListBlock());
+ $this->P->addMode('listblock',new Listblock());
$this->P->parse("\r\n *A\r\n * B\r\n * C\r\n");
$calls = array (
array('document_start',array()),
array('listu_open',array()),
- array('listitem_open',array(1,Doku_Handler_List::NODE)),
+ array('listitem_open',array(1,Lists::NODE)),
array('listcontent_open',array()),
array('cdata',array("A")),
array('listcontent_close',array()),
@@ -131,14 +140,14 @@ class TestOfDoku_Parser_Lists extends TestOfDoku_Parser {
);
$this->assertEquals(array_map('stripbyteindex',$this->H->calls),$calls);
}
-
+
function testOrderedListWinEOL() {
- $this->P->addMode('listblock',new Doku_Parser_Mode_ListBlock());
+ $this->P->addMode('listblock',new Listblock());
$this->P->parse("\r\n -A\r\n - B\r\n - C\r\n");
$calls = array (
array('document_start',array()),
array('listo_open',array()),
- array('listitem_open',array(1,Doku_Handler_List::NODE)),
+ array('listitem_open',array(1,Lists::NODE)),
array('listcontent_open',array()),
array('cdata',array("A")),
array('listcontent_close',array()),
@@ -160,9 +169,9 @@ class TestOfDoku_Parser_Lists extends TestOfDoku_Parser {
);
$this->assertEquals(array_map('stripbyteindex',$this->H->calls),$calls);
}
-
+
function testNotAList() {
- $this->P->addMode('listblock',new Doku_Parser_Mode_ListBlock());
+ $this->P->addMode('listblock',new Listblock());
$this->P->parse("Foo -bar *foo Bar");
$calls = array (
array('document_start',array()),
@@ -173,10 +182,10 @@ class TestOfDoku_Parser_Lists extends TestOfDoku_Parser {
);
$this->assertEquals(array_map('stripbyteindex',$this->H->calls),$calls);
}
-
+
function testUnorderedListParagraph() {
- $this->P->addMode('listblock',new Doku_Parser_Mode_ListBlock());
- $this->P->addMode('eol',new Doku_Parser_Mode_Eol());
+ $this->P->addMode('listblock',new Listblock());
+ $this->P->addMode('eol',new Eol());
$this->P->parse('Foo
*A
* B
@@ -188,7 +197,7 @@ Bar');
array('cdata',array("Foo")),
array('p_close',array()),
array('listu_open',array()),
- array('listitem_open',array(1,Doku_Handler_List::NODE)),
+ array('listitem_open',array(1,Lists::NODE)),
array('listcontent_open',array()),
array('cdata',array("A")),
array('listcontent_close',array()),
@@ -213,12 +222,12 @@ Bar');
);
$this->assertEquals(array_map('stripbyteindex',$this->H->calls),$calls);
}
-
+
// This is really a failing test - formatting able to spread across list items
// Problem is fixing it would mean a major rewrite of lists
function testUnorderedListStrong() {
- $this->P->addMode('listblock',new Doku_Parser_Mode_ListBlock());
- $this->P->addMode('strong',new Doku_Parser_Mode_Formatting('strong'));
+ $this->P->addMode('listblock',new Listblock());
+ $this->P->addMode('strong',new Formatting('strong'));
$this->P->parse('
***A**
*** B
@@ -227,7 +236,7 @@ Bar');
$calls = array (
array('document_start',array()),
array('listu_open',array()),
- array('listitem_open',array(1,Doku_Handler_List::NODE)),
+ array('listitem_open',array(1,Lists::NODE)),
array('listcontent_open',array()),
array('strong_open',array()),
array('cdata',array("A")),
@@ -248,12 +257,12 @@ Bar');
);
$this->assertEquals(array_map('stripbyteindex',$this->H->calls),$calls);
}
-
+
// This is really a failing test - unformatted able to spread across list items
// Problem is fixing it would mean a major rewrite of lists
function testUnorderedListUnformatted() {
- $this->P->addMode('listblock',new Doku_Parser_Mode_ListBlock());
- $this->P->addMode('unformatted',new Doku_Parser_Mode_Unformatted());
+ $this->P->addMode('listblock',new Listblock());
+ $this->P->addMode('unformatted',new Unformatted());
$this->P->parse('
*%%A%%
*%% B
@@ -262,7 +271,7 @@ Bar');
$calls = array (
array('document_start',array()),
array('listu_open',array()),
- array('listitem_open',array(1,Doku_Handler_List::NODE)),
+ array('listitem_open',array(1,Lists::NODE)),
array('listcontent_open',array()),
array('unformatted',array("A")),
array('listcontent_close',array()),
@@ -279,10 +288,10 @@ Bar');
);
$this->assertEquals(array_map('stripbyteindex',$this->H->calls),$calls);
}
-
+
function testUnorderedListLinebreak() {
- $this->P->addMode('listblock',new Doku_Parser_Mode_ListBlock());
- $this->P->addMode('linebreak',new Doku_Parser_Mode_Linebreak());
+ $this->P->addMode('listblock',new Listblock());
+ $this->P->addMode('linebreak',new Linebreak());
$this->P->parse('
*A\\\\ D
* B
@@ -291,7 +300,7 @@ Bar');
$calls = array (
array('document_start',array()),
array('listu_open',array()),
- array('listitem_open',array(1,Doku_Handler_List::NODE)),
+ array('listitem_open',array(1,Lists::NODE)),
array('listcontent_open',array()),
array('cdata',array("A")),
array('linebreak',array()),
@@ -315,10 +324,10 @@ Bar');
);
$this->assertEquals(array_map('stripbyteindex',$this->H->calls),$calls);
}
-
+
function testUnorderedListLinebreak2() {
- $this->P->addMode('listblock',new Doku_Parser_Mode_ListBlock());
- $this->P->addMode('linebreak',new Doku_Parser_Mode_Linebreak());
+ $this->P->addMode('listblock',new Listblock());
+ $this->P->addMode('linebreak',new Linebreak());
$this->P->parse('
*A\\\\
* B
@@ -342,10 +351,10 @@ Bar');
);
$this->assertEquals(array_map('stripbyteindex',$this->H->calls),$calls);
}
-
+
function testUnorderedListFootnote() {
- $this->P->addMode('listblock',new Doku_Parser_Mode_ListBlock());
- $this->P->addMode('footnote',new Doku_Parser_Mode_Footnote());
+ $this->P->addMode('listblock',new Listblock());
+ $this->P->addMode('footnote',new Footnote());
$this->P->parse('
*((A))
*(( B
@@ -355,7 +364,7 @@ Bar');
$calls = array (
array('document_start',array()),
array('listu_open',array()),
- array('listitem_open',array(1,Doku_Handler_List::NODE)),
+ array('listitem_open',array(1,Lists::NODE)),
array('listcontent_open',array()),
array('nest', array( array(
array('footnote_open',array()),
diff --git a/_test/tests/inc/parser/parser_preformatted.test.php b/_test/tests/inc/parser/parser_preformatted.test.php
index f7a01a7e5..ad99f2916 100644
--- a/_test/tests/inc/parser/parser_preformatted.test.php
+++ b/_test/tests/inc/parser/parser_preformatted.test.php
@@ -1,10 +1,20 @@
<?php
+
+use dokuwiki\Parsing\ParserMode\Code;
+use dokuwiki\Parsing\ParserMode\Eol;
+use dokuwiki\Parsing\ParserMode\File;
+use dokuwiki\Parsing\ParserMode\Header;
+use dokuwiki\Parsing\ParserMode\Html;
+use dokuwiki\Parsing\ParserMode\Listblock;
+use dokuwiki\Parsing\ParserMode\Php;
+use dokuwiki\Parsing\ParserMode\Preformatted;
+
require_once 'parser.inc.php';
class TestOfDoku_Parser_Preformatted extends TestOfDoku_Parser {
function testFile() {
- $this->P->addMode('file',new Doku_Parser_Mode_File());
+ $this->P->addMode('file',new File());
$this->P->parse('Foo <file>testing</file> Bar');
$calls = array (
array('document_start',array()),
@@ -22,7 +32,7 @@ class TestOfDoku_Parser_Preformatted extends TestOfDoku_Parser {
}
function testCode() {
- $this->P->addMode('code',new Doku_Parser_Mode_Code());
+ $this->P->addMode('code',new Code());
$this->P->parse('Foo <code>testing</code> Bar');
$calls = array (
array('document_start',array()),
@@ -39,7 +49,7 @@ class TestOfDoku_Parser_Preformatted extends TestOfDoku_Parser {
}
function testCodeWhitespace() {
- $this->P->addMode('code',new Doku_Parser_Mode_Code());
+ $this->P->addMode('code',new Code());
$this->P->parse("Foo <code \n>testing</code> Bar");
$calls = array (
array('document_start',array()),
@@ -56,7 +66,7 @@ class TestOfDoku_Parser_Preformatted extends TestOfDoku_Parser {
}
function testCodeLang() {
- $this->P->addMode('code',new Doku_Parser_Mode_Code());
+ $this->P->addMode('code',new Code());
$this->P->parse("Foo <code php>testing</code> Bar");
$calls = array (
array('document_start',array()),
@@ -73,7 +83,7 @@ class TestOfDoku_Parser_Preformatted extends TestOfDoku_Parser {
}
function testPreformatted() {
- $this->P->addMode('preformatted',new Doku_Parser_Mode_Preformatted());
+ $this->P->addMode('preformatted',new Preformatted());
$this->P->parse("F oo\n x \n y \nBar\n");
$calls = array (
array('document_start',array()),
@@ -90,7 +100,7 @@ class TestOfDoku_Parser_Preformatted extends TestOfDoku_Parser {
}
function testPreformattedWinEOL() {
- $this->P->addMode('preformatted',new Doku_Parser_Mode_Preformatted());
+ $this->P->addMode('preformatted',new Preformatted());
$this->P->parse("F oo\r\n x \r\n y \r\nBar\r\n");
$calls = array (
array('document_start',array()),
@@ -107,7 +117,7 @@ class TestOfDoku_Parser_Preformatted extends TestOfDoku_Parser {
}
function testPreformattedTab() {
- $this->P->addMode('preformatted',new Doku_Parser_Mode_Preformatted());
+ $this->P->addMode('preformatted',new Preformatted());
$this->P->parse("F oo\n\tx\t\n\t\ty\t\nBar\n");
$calls = array (
array('document_start',array()),
@@ -124,7 +134,7 @@ class TestOfDoku_Parser_Preformatted extends TestOfDoku_Parser {
}
function testPreformattedTabWinEOL() {
- $this->P->addMode('preformatted',new Doku_Parser_Mode_Preformatted());
+ $this->P->addMode('preformatted',new Preformatted());
$this->P->parse("F oo\r\n\tx\t\r\n\t\ty\t\r\nBar\r\n");
$calls = array (
array('document_start',array()),
@@ -141,8 +151,8 @@ class TestOfDoku_Parser_Preformatted extends TestOfDoku_Parser {
}
function testPreformattedList() {
- $this->P->addMode('preformatted',new Doku_Parser_Mode_Preformatted());
- $this->P->addMode('listblock',new Doku_Parser_Mode_ListBlock());
+ $this->P->addMode('preformatted',new Preformatted());
+ $this->P->addMode('listblock',new Listblock());
$this->P->parse(" - x \n * y \nF oo\n x \n y \n -X\n *Y\nBar\n");
$calls = array (
array('document_start',array()),
@@ -175,7 +185,7 @@ class TestOfDoku_Parser_Preformatted extends TestOfDoku_Parser {
// test for php
function testPHP() {
- $this->P->addMode('php',new Doku_Parser_Mode_PHP());
+ $this->P->addMode('php',new Php());
$this->P->parse('Foo <php>testing</php> Bar');
$calls = array (
array('document_start',array()),
@@ -192,7 +202,7 @@ class TestOfDoku_Parser_Preformatted extends TestOfDoku_Parser {
// test with for HTML
function testHTML() {
- $this->P->addMode('html',new Doku_Parser_Mode_HTML());
+ $this->P->addMode('html',new Html());
$this->P->parse('Foo <html>testing</html> Bar');
$calls = array (
array('document_start',array()),
@@ -210,9 +220,9 @@ class TestOfDoku_Parser_Preformatted extends TestOfDoku_Parser {
function testPreformattedPlusHeaderAndEol() {
// Note that EOL must come after preformatted!
- $this->P->addMode('preformatted',new Doku_Parser_Mode_Preformatted());
- $this->P->addMode('header',new Doku_Parser_Mode_Header());
- $this->P->addMode('eol',new Doku_Parser_Mode_Eol());
+ $this->P->addMode('preformatted',new Preformatted());
+ $this->P->addMode('header',new Header());
+ $this->P->addMode('eol',new Eol());
$this->P->parse("F oo\n ==Test==\n y \nBar\n");
$calls = array (
array('document_start',array()),
diff --git a/_test/tests/inc/parser/parser_quote.test.php b/_test/tests/inc/parser/parser_quote.test.php
index ae14671c1..190f18cc1 100644
--- a/_test/tests/inc/parser/parser_quote.test.php
+++ b/_test/tests/inc/parser/parser_quote.test.php
@@ -1,10 +1,14 @@
<?php
+
+use dokuwiki\Parsing\ParserMode\Eol;
+use dokuwiki\Parsing\ParserMode\Quote;
+
require_once 'parser.inc.php';
class TestOfDoku_Parser_Quote extends TestOfDoku_Parser {
function testQuote() {
- $this->P->addMode('quote',new Doku_Parser_Mode_Quote());
+ $this->P->addMode('quote',new Quote());
$this->P->parse("abc\n> def\n>>ghi\nklm");
$calls = array (
array('document_start',array()),
@@ -27,7 +31,7 @@ class TestOfDoku_Parser_Quote extends TestOfDoku_Parser {
}
function testQuoteWinCr() {
- $this->P->addMode('quote',new Doku_Parser_Mode_Quote());
+ $this->P->addMode('quote',new Quote());
$this->P->parse("abc\r\n> def\r\n>>ghi\r\nklm");
$calls = array (
array('document_start',array()),
@@ -50,7 +54,7 @@ class TestOfDoku_Parser_Quote extends TestOfDoku_Parser {
}
function testQuoteMinumumContext() {
- $this->P->addMode('quote',new Doku_Parser_Mode_Quote());
+ $this->P->addMode('quote',new Quote());
$this->P->parse("\n> def\n>>ghi\n ");
$calls = array (
array('document_start',array()),
@@ -67,8 +71,8 @@ class TestOfDoku_Parser_Quote extends TestOfDoku_Parser {
}
function testQuoteEol() {
- $this->P->addMode('quote',new Doku_Parser_Mode_Quote());
- $this->P->addMode('eol',new Doku_Parser_Mode_Eol());
+ $this->P->addMode('quote',new Quote());
+ $this->P->addMode('eol',new Eol());
$this->P->parse("abc\n> def\n>>ghi\nklm");
$calls = array (
array('document_start',array()),
diff --git a/_test/tests/inc/parser/parser_quotes.test.php b/_test/tests/inc/parser/parser_quotes.test.php
index 6f174ddae..fb192d21f 100644
--- a/_test/tests/inc/parser/parser_quotes.test.php
+++ b/_test/tests/inc/parser/parser_quotes.test.php
@@ -1,4 +1,7 @@
<?php
+
+use dokuwiki\Parsing\ParserMode\Quotes;
+
require_once 'parser.inc.php';
class TestOfDoku_Parser_Quotes extends TestOfDoku_Parser {
@@ -11,7 +14,7 @@ class TestOfDoku_Parser_Quotes extends TestOfDoku_Parser {
function testSingleQuoteOpening() {
$raw = "Foo 'hello Bar";
- $this->P->addMode('quotes',new Doku_Parser_Mode_Quotes());
+ $this->P->addMode('quotes',new Quotes());
$this->P->parse($raw);
$calls = array (
@@ -29,7 +32,7 @@ class TestOfDoku_Parser_Quotes extends TestOfDoku_Parser {
function testSingleQuoteOpeningSpecial() {
$raw = "Foo said:'hello Bar";
- $this->P->addMode('quotes',new Doku_Parser_Mode_Quotes());
+ $this->P->addMode('quotes',new Quotes());
$this->P->parse($raw);
$calls = array (
@@ -47,7 +50,7 @@ class TestOfDoku_Parser_Quotes extends TestOfDoku_Parser {
function testSingleQuoteClosing() {
$raw = "Foo hello' Bar";
- $this->P->addMode('quotes',new Doku_Parser_Mode_Quotes());
+ $this->P->addMode('quotes',new Quotes());
$this->P->parse($raw);
$calls = array (
@@ -65,7 +68,7 @@ class TestOfDoku_Parser_Quotes extends TestOfDoku_Parser {
function testSingleQuoteClosingSpecial() {
$raw = "Foo hello') Bar";
- $this->P->addMode('quotes',new Doku_Parser_Mode_Quotes());
+ $this->P->addMode('quotes',new Quotes());
$this->P->parse($raw);
$calls = array (
@@ -83,7 +86,7 @@ class TestOfDoku_Parser_Quotes extends TestOfDoku_Parser {
function testSingleQuotes() {
$raw = "Foo 'hello' Bar";
- $this->P->addMode('quotes',new Doku_Parser_Mode_Quotes());
+ $this->P->addMode('quotes',new Quotes());
$this->P->parse($raw);
$calls = array (
@@ -103,7 +106,7 @@ class TestOfDoku_Parser_Quotes extends TestOfDoku_Parser {
function testApostrophe() {
$raw = "hey it's fine weather today";
- $this->P->addMode('quotes',new Doku_Parser_Mode_Quotes());
+ $this->P->addMode('quotes',new Quotes());
$this->P->parse($raw);
$calls = array (
@@ -122,7 +125,7 @@ class TestOfDoku_Parser_Quotes extends TestOfDoku_Parser {
function testSingleQuotesSpecial() {
$raw = "Foo ('hello') Bar";
- $this->P->addMode('quotes',new Doku_Parser_Mode_Quotes());
+ $this->P->addMode('quotes',new Quotes());
$this->P->parse($raw);
$calls = array (
@@ -142,7 +145,7 @@ class TestOfDoku_Parser_Quotes extends TestOfDoku_Parser {
function testDoubleQuoteOpening() {
$raw = 'Foo "hello Bar';
- $this->P->addMode('quotes',new Doku_Parser_Mode_Quotes());
+ $this->P->addMode('quotes',new Quotes());
$this->P->parse($raw);
$calls = array (
@@ -160,7 +163,7 @@ class TestOfDoku_Parser_Quotes extends TestOfDoku_Parser {
function testDoubleQuoteOpeningSpecial() {
$raw = 'Foo said:"hello Bar';
- $this->P->addMode('quotes',new Doku_Parser_Mode_Quotes());
+ $this->P->addMode('quotes',new Quotes());
$this->P->parse($raw);
$calls = array (
@@ -178,8 +181,13 @@ class TestOfDoku_Parser_Quotes extends TestOfDoku_Parser {
function testDoubleQuoteClosing() {
$raw = 'Foo hello" Bar';
- $this->P->addMode('quotes',new Doku_Parser_Mode_Quotes());
- $this->H->status['doublequote'] = 1;
+ $this->P->addMode('quotes',new Quotes());
+
+ /** @noinspection PhpUnhandledExceptionInspection */
+ $status = $this->getInaccessibleProperty($this->H, 'status');
+ $status['doublequote'] = 1;
+ /** @noinspection PhpUnhandledExceptionInspection */
+ $this->setInaccessibleProperty($this->H, 'status', $status);
$this->P->parse($raw);
$calls = array (
@@ -197,8 +205,13 @@ class TestOfDoku_Parser_Quotes extends TestOfDoku_Parser {
function testDoubleQuoteClosingSpecial() {
$raw = 'Foo hello") Bar';
- $this->P->addMode('quotes',new Doku_Parser_Mode_Quotes());
- $this->H->status['doublequote'] = 1;
+ $this->P->addMode('quotes',new Quotes());
+ /** @noinspection PhpUnhandledExceptionInspection */
+ $status = $this->getInaccessibleProperty($this->H, 'status');
+ $status['doublequote'] = 1;
+ /** @noinspection PhpUnhandledExceptionInspection */
+ $this->setInaccessibleProperty($this->H, 'status', $status);
+
$this->P->parse($raw);
$calls = array (
@@ -215,8 +228,13 @@ class TestOfDoku_Parser_Quotes extends TestOfDoku_Parser {
}
function testDoubleQuoteClosingSpecial2() {
$raw = 'Foo hello") Bar';
- $this->P->addMode('quotes',new Doku_Parser_Mode_Quotes());
- $this->H->status['doublequote'] = 0;
+ $this->P->addMode('quotes',new Quotes());
+ /** @noinspection PhpUnhandledExceptionInspection */
+ $status = $this->getInaccessibleProperty($this->H, 'status');
+ $status['doublequote'] = 0;
+ /** @noinspection PhpUnhandledExceptionInspection */
+ $this->setInaccessibleProperty($this->H, 'status', $status);
+
$this->P->parse($raw);
$calls = array (
@@ -234,7 +252,7 @@ class TestOfDoku_Parser_Quotes extends TestOfDoku_Parser {
function testDoubleQuotes() {
$raw = 'Foo "hello" Bar';
- $this->P->addMode('quotes',new Doku_Parser_Mode_Quotes());
+ $this->P->addMode('quotes',new Quotes());
$this->P->parse($raw);
$calls = array (
@@ -254,7 +272,7 @@ class TestOfDoku_Parser_Quotes extends TestOfDoku_Parser {
function testDoubleQuotesSpecial() {
$raw = 'Foo ("hello") Bar';
- $this->P->addMode('quotes',new Doku_Parser_Mode_Quotes());
+ $this->P->addMode('quotes',new Quotes());
$this->P->parse($raw);
$calls = array (
@@ -274,7 +292,7 @@ class TestOfDoku_Parser_Quotes extends TestOfDoku_Parser {
function testDoubleQuotesEnclosingBrackets() {
$raw = 'Foo "{hello}" Bar';
- $this->P->addMode('quotes',new Doku_Parser_Mode_Quotes());
+ $this->P->addMode('quotes',new Quotes());
$this->P->parse($raw);
$calls = array (
@@ -294,7 +312,7 @@ class TestOfDoku_Parser_Quotes extends TestOfDoku_Parser {
function testDoubleQuotesEnclosingLink() {
$raw = 'Foo "[[www.domain.com]]" Bar';
- $this->P->addMode('quotes',new Doku_Parser_Mode_Quotes());
+ $this->P->addMode('quotes',new Quotes());
$this->P->parse($raw);
$calls = array (
@@ -315,7 +333,7 @@ class TestOfDoku_Parser_Quotes extends TestOfDoku_Parser {
function testAllQuotes() {
$raw = 'There was written "He thought \'It\'s a man\'s world\'".';
- $this->P->addMode('quotes',new Doku_Parser_Mode_Quotes());
+ $this->P->addMode('quotes',new Quotes());
$this->P->parse($raw);
$calls = array (
diff --git a/_test/tests/inc/parser/parser_replacements.test.php b/_test/tests/inc/parser/parser_replacements.test.php
index f0367dac0..d910dba9e 100644
--- a/_test/tests/inc/parser/parser_replacements.test.php
+++ b/_test/tests/inc/parser/parser_replacements.test.php
@@ -1,10 +1,18 @@
<?php
+
+use dokuwiki\Parsing\ParserMode\Acronym;
+use dokuwiki\Parsing\ParserMode\Entity;
+use dokuwiki\Parsing\ParserMode\Hr;
+use dokuwiki\Parsing\ParserMode\Multiplyentity;
+use dokuwiki\Parsing\ParserMode\Smiley;
+use dokuwiki\Parsing\ParserMode\Wordblock;
+
require_once 'parser.inc.php';
class TestOfDoku_Parser_Replacements extends TestOfDoku_Parser {
function testSingleAcronym() {
- $this->P->addMode('acronym',new Doku_Parser_Mode_Acronym(array('FOOBAR')));
+ $this->P->addMode('acronym',new Acronym(array('FOOBAR')));
$this->P->parse('abc FOOBAR xyz');
$calls = array (
@@ -21,7 +29,7 @@ class TestOfDoku_Parser_Replacements extends TestOfDoku_Parser {
}
function testAlmostAnAcronym() {
- $this->P->addMode('acronym',new Doku_Parser_Mode_Acronym(array('FOOBAR')));
+ $this->P->addMode('acronym',new Acronym(array('FOOBAR')));
$this->P->parse('abcFOOBARxyz');
$calls = array (
@@ -36,7 +44,7 @@ class TestOfDoku_Parser_Replacements extends TestOfDoku_Parser {
}
function testPickAcronymCorrectly() {
- $this->P->addMode('acronym',new Doku_Parser_Mode_Acronym(array('FOO')));
+ $this->P->addMode('acronym',new Acronym(array('FOO')));
$this->P->parse('FOOBAR FOO');
$calls = array (
@@ -53,7 +61,7 @@ class TestOfDoku_Parser_Replacements extends TestOfDoku_Parser {
}
function testMultipleAcronyms() {
- $this->P->addMode('acronym',new Doku_Parser_Mode_Acronym(array('FOO','BAR')));
+ $this->P->addMode('acronym',new Acronym(array('FOO','BAR')));
$this->P->parse('abc FOO def BAR xyz');
$calls = array (
@@ -73,7 +81,7 @@ class TestOfDoku_Parser_Replacements extends TestOfDoku_Parser {
}
function testMultipleAcronymsWithSubset1() {
- $this->P->addMode('acronym',new Doku_Parser_Mode_Acronym(array('FOO','A.FOO','FOO.1','A.FOO.1')));
+ $this->P->addMode('acronym',new Acronym(array('FOO','A.FOO','FOO.1','A.FOO.1')));
$this->P->parse('FOO A.FOO FOO.1 A.FOO.1');
$calls = array (
@@ -96,7 +104,7 @@ class TestOfDoku_Parser_Replacements extends TestOfDoku_Parser {
}
function testMultipleAcronymsWithSubset2() {
- $this->P->addMode('acronym',new Doku_Parser_Mode_Acronym(array('A.FOO.1','FOO.1','A.FOO','FOO')));
+ $this->P->addMode('acronym',new Acronym(array('A.FOO.1','FOO.1','A.FOO','FOO')));
$this->P->parse('FOO A.FOO FOO.1 A.FOO.1');
$calls = array (
@@ -119,7 +127,7 @@ class TestOfDoku_Parser_Replacements extends TestOfDoku_Parser {
}
function testSingleSmileyFail() {
- $this->P->addMode('smiley',new Doku_Parser_Mode_Smiley(array(':-)')));
+ $this->P->addMode('smiley',new Smiley(array(':-)')));
$this->P->parse('abc:-)xyz');
$calls = array (
@@ -134,7 +142,7 @@ class TestOfDoku_Parser_Replacements extends TestOfDoku_Parser {
}
function testSingleSmiley() {
- $this->P->addMode('smiley',new Doku_Parser_Mode_Smiley(array(':-)')));
+ $this->P->addMode('smiley',new Smiley(array(':-)')));
$this->P->parse('abc :-) xyz');
$calls = array (
@@ -151,7 +159,7 @@ class TestOfDoku_Parser_Replacements extends TestOfDoku_Parser {
}
function testMultipleSmileysFail() {
- $this->P->addMode('smiley',new Doku_Parser_Mode_Smiley(array(':-)','^_^')));
+ $this->P->addMode('smiley',new Smiley(array(':-)','^_^')));
$this->P->parse('abc:-)x^_^yz');
$calls = array (
@@ -166,7 +174,7 @@ class TestOfDoku_Parser_Replacements extends TestOfDoku_Parser {
}
function testMultipleSmileys() {
- $this->P->addMode('smiley',new Doku_Parser_Mode_Smiley(array(':-)','^_^')));
+ $this->P->addMode('smiley',new Smiley(array(':-)','^_^')));
$this->P->parse('abc :-) x ^_^ yz');
$calls = array (
@@ -186,7 +194,7 @@ class TestOfDoku_Parser_Replacements extends TestOfDoku_Parser {
function testBackslashSmileyFail() {
// This smiley is really :-\\ but escaping makes like interesting
- $this->P->addMode('smiley',new Doku_Parser_Mode_Smiley(array(':-\\\\')));
+ $this->P->addMode('smiley',new Smiley(array(':-\\\\')));
$this->P->parse('abc:-\\\xyz');
$calls = array (
@@ -202,7 +210,7 @@ class TestOfDoku_Parser_Replacements extends TestOfDoku_Parser {
function testBackslashSmiley() {
// This smiley is really :-\\ but escaping makes like interesting
- $this->P->addMode('smiley',new Doku_Parser_Mode_Smiley(array(':-\\\\')));
+ $this->P->addMode('smiley',new Smiley(array(':-\\\\')));
$this->P->parse('abc :-\\\ xyz');
$calls = array (
@@ -219,7 +227,7 @@ class TestOfDoku_Parser_Replacements extends TestOfDoku_Parser {
}
function testSingleWordblock() {
- $this->P->addMode('wordblock',new Doku_Parser_Mode_Wordblock(array('CAT')));
+ $this->P->addMode('wordblock',new Wordblock(array('CAT')));
$this->P->parse('abc CAT xyz');
$calls = array (
@@ -236,7 +244,7 @@ class TestOfDoku_Parser_Replacements extends TestOfDoku_Parser {
}
function testWordblockCase() {
- $this->P->addMode('wordblock',new Doku_Parser_Mode_Wordblock(array('CAT')));
+ $this->P->addMode('wordblock',new Wordblock(array('CAT')));
$this->P->parse('abc cat xyz');
$calls = array (
@@ -253,7 +261,7 @@ class TestOfDoku_Parser_Replacements extends TestOfDoku_Parser {
}
function testMultipleWordblock() {
- $this->P->addMode('wordblock',new Doku_Parser_Mode_Wordblock(array('CAT','dog')));
+ $this->P->addMode('wordblock',new Wordblock(array('CAT','dog')));
$this->P->parse('abc cat x DOG yz');
$calls = array (
@@ -272,7 +280,7 @@ class TestOfDoku_Parser_Replacements extends TestOfDoku_Parser {
}
function testSingleEntity() {
- $this->P->addMode('entity',new Doku_Parser_Mode_Entity(array('->')));
+ $this->P->addMode('entity',new Entity(array('->')));
$this->P->parse('x -> y');
$calls = array (
@@ -289,7 +297,7 @@ class TestOfDoku_Parser_Replacements extends TestOfDoku_Parser {
}
function testMultipleEntities() {
- $this->P->addMode('entity',new Doku_Parser_Mode_Entity(array('->','<-')));
+ $this->P->addMode('entity',new Entity(array('->','<-')));
$this->P->parse('x -> y <- z');
$calls = array (
@@ -308,7 +316,7 @@ class TestOfDoku_Parser_Replacements extends TestOfDoku_Parser {
}
function testMultiplyEntity() {
- $this->P->addMode('multiplyentity',new Doku_Parser_Mode_MultiplyEntity());
+ $this->P->addMode('multiplyentity',new Multiplyentity());
$this->P->parse('Foo 10x20 Bar');
$calls = array (
@@ -326,7 +334,7 @@ class TestOfDoku_Parser_Replacements extends TestOfDoku_Parser {
function testMultiplyEntityHex() {
// the multiply entity pattern should not match hex numbers, eg. 0x123
- $this->P->addMode('multiplyentity',new Doku_Parser_Mode_MultiplyEntity());
+ $this->P->addMode('multiplyentity',new Multiplyentity());
$this->P->parse('Foo 0x123 Bar');
$calls = array (
@@ -341,7 +349,7 @@ class TestOfDoku_Parser_Replacements extends TestOfDoku_Parser {
}
function testHR() {
- $this->P->addMode('hr',new Doku_Parser_Mode_HR());
+ $this->P->addMode('hr',new Hr());
$this->P->parse("Foo \n ---- \n Bar");
$calls = array (
@@ -359,7 +367,7 @@ class TestOfDoku_Parser_Replacements extends TestOfDoku_Parser {
}
function testHREol() {
- $this->P->addMode('hr',new Doku_Parser_Mode_HR());
+ $this->P->addMode('hr',new Hr());
$this->P->parse("Foo \n----\n Bar");
$calls = array (
diff --git a/_test/tests/inc/parser/parser_table.test.php b/_test/tests/inc/parser/parser_table.test.php
index f05dd29aa..c233a4072 100644
--- a/_test/tests/inc/parser/parser_table.test.php
+++ b/_test/tests/inc/parser/parser_table.test.php
@@ -1,10 +1,18 @@
<?php
+
+use dokuwiki\Parsing\ParserMode\Eol;
+use dokuwiki\Parsing\ParserMode\Footnote;
+use dokuwiki\Parsing\ParserMode\Formatting;
+use dokuwiki\Parsing\ParserMode\Linebreak;
+use dokuwiki\Parsing\ParserMode\Table;
+use dokuwiki\Parsing\ParserMode\Unformatted;
+
require_once 'parser.inc.php';
class TestOfDoku_Parser_Table extends TestOfDoku_Parser {
function testTable() {
- $this->P->addMode('table',new Doku_Parser_Mode_Table());
+ $this->P->addMode('table',new Table());
$this->P->parse('
abc
| Row 0 Col 1 | Row 0 Col 2 | Row 0 Col 3 |
@@ -48,7 +56,7 @@ def');
}
function testTableWinEOL() {
- $this->P->addMode('table',new Doku_Parser_Mode_Table());
+ $this->P->addMode('table',new Table());
$this->P->parse("\r\nabc\r\n| Row 0 Col 1 | Row 0 Col 2 | Row 0 Col 3 |\r\n| Row 1 Col 1 | Row 1 Col 2 | Row 1 Col 3 |\r\ndef");
$calls = array (
array('document_start',array()),
@@ -88,7 +96,7 @@ def');
}
function testEmptyTable() {
- $this->P->addMode('table',new Doku_Parser_Mode_Table());
+ $this->P->addMode('table',new Table());
$this->P->parse('
abc
|
@@ -113,7 +121,7 @@ def');
}
function testTableHeaders() {
- $this->P->addMode('table',new Doku_Parser_Mode_Table());
+ $this->P->addMode('table',new Table());
$this->P->parse('
abc
^ X | Y ^ Z |
@@ -148,7 +156,7 @@ def');
}
function testTableHead() {
- $this->P->addMode('table',new Doku_Parser_Mode_Table());
+ $this->P->addMode('table',new Table());
$this->P->parse('
abc
^ X ^ Y ^ Z ^
@@ -197,7 +205,7 @@ def');
}
function testTableHeadOneRowTable() {
- $this->P->addMode('table',new Doku_Parser_Mode_Table());
+ $this->P->addMode('table',new Table());
$this->P->parse('
abc
^ X ^ Y ^ Z ^
@@ -232,7 +240,7 @@ def');
}
function testTableHeadMultiline() {
- $this->P->addMode('table',new Doku_Parser_Mode_Table());
+ $this->P->addMode('table',new Table());
$this->P->parse('
abc
^ X1 ^ Y1 ^ Z1 ^
@@ -293,7 +301,7 @@ def');
}
function testCellAlignment() {
- $this->P->addMode('table',new Doku_Parser_Mode_Table());
+ $this->P->addMode('table',new Table());
$this->P->parse('
abc
| X | Y ^ Z |
@@ -327,7 +335,7 @@ def');
}
function testCellSpan() {
- $this->P->addMode('table',new Doku_Parser_Mode_Table());
+ $this->P->addMode('table',new Table());
$this->P->parse('
abc
| d || e |
@@ -369,7 +377,7 @@ def');
}
function testCellRowSpan() {
- $this->P->addMode('table',new Doku_Parser_Mode_Table());
+ $this->P->addMode('table',new Table());
$this->P->parse('
abc
| a | c:::||
@@ -417,7 +425,7 @@ def');
}
function testCellRowSpanFirstRow() {
- $this->P->addMode('table',new Doku_Parser_Mode_Table());
+ $this->P->addMode('table',new Table());
$this->P->parse('
abc
|::: ^ d:::^:::| ::: |
@@ -475,7 +483,7 @@ def');
}
function testRowSpanTableHead() {
- $this->P->addMode('table',new Doku_Parser_Mode_Table());
+ $this->P->addMode('table',new Table());
$this->P->parse('
abc
^ X1 ^ Y1 ^ Z1 ^
@@ -533,7 +541,7 @@ def');
}
function testRowSpanAcrossTableHeadBoundary() {
- $this->P->addMode('table',new Doku_Parser_Mode_Table());
+ $this->P->addMode('table',new Table());
$this->P->parse('
abc
^ X1 ^ Y1 ^ Z1 ^
@@ -600,8 +608,8 @@ def');
}
function testCellAlignmentFormatting() {
- $this->P->addMode('table',new Doku_Parser_Mode_Table());
- $this->P->addMode('strong',new Doku_Parser_Mode_Formatting('strong'));
+ $this->P->addMode('table',new Table());
+ $this->P->addMode('strong',new Formatting('strong'));
$this->P->parse('
abc
| **X** | Y ^ Z |
@@ -640,8 +648,8 @@ def');
}
function testTableEol() {
- $this->P->addMode('table',new Doku_Parser_Mode_Table());
- $this->P->addMode('eol',new Doku_Parser_Mode_Eol());
+ $this->P->addMode('table',new Table());
+ $this->P->addMode('eol',new Eol());
$this->P->parse('
abc
| Row 0 Col 1 | Row 0 Col 2 | Row 0 Col 3 |
@@ -687,8 +695,8 @@ def');
// This is really a failing test - formatting able to spread across cols
// Problem is fixing it would mean a major rewrite of table handling
function testTableStrong() {
- $this->P->addMode('table',new Doku_Parser_Mode_Table());
- $this->P->addMode('strong',new Doku_Parser_Mode_Formatting('strong'));
+ $this->P->addMode('table',new Table());
+ $this->P->addMode('strong',new Formatting('strong'));
$this->P->parse('
abc
| **Row 0 Col 1** | **Row 0 Col 2 | Row 0 Col 3** |
@@ -742,8 +750,8 @@ def');
// This is really a failing test - unformatted able to spread across cols
// Problem is fixing it would mean a major rewrite of table handling
function testTableUnformatted() {
- $this->P->addMode('table',new Doku_Parser_Mode_Table());
- $this->P->addMode('unformatted',new Doku_Parser_Mode_Unformatted());
+ $this->P->addMode('table',new Table());
+ $this->P->addMode('unformatted',new Unformatted());
$this->P->parse('
abc
| <nowiki>Row 0 Col 1</nowiki> | <nowiki>Row 0 Col 2 | Row 0 Col 3</nowiki> |
@@ -791,8 +799,8 @@ def');
}
function testTableLinebreak() {
- $this->P->addMode('table',new Doku_Parser_Mode_Table());
- $this->P->addMode('linebreak',new Doku_Parser_Mode_Linebreak());
+ $this->P->addMode('table',new Table());
+ $this->P->addMode('linebreak',new Linebreak());
$this->P->parse('
abc
| Row 0\\\\ Col 1 | Row 0 Col 2 | Row 0 Col 3 |
@@ -841,8 +849,8 @@ def');
// This is really a failing test - footnote able to spread across cols
// Problem is fixing it would mean a major rewrite of table handling
function testTableFootnote() {
- $this->P->addMode('table',new Doku_Parser_Mode_Table());
- $this->P->addMode('footnote',new Doku_Parser_Mode_Footnote());
+ $this->P->addMode('table',new Table());
+ $this->P->addMode('footnote',new Footnote());
$this->P->parse('
abc
| ((Row 0 Col 1)) | ((Row 0 Col 2 | Row 0 Col 3)) |
@@ -899,7 +907,7 @@ def');
function testTable_FS1833() {
$syntax = " \n| Row 0 Col 1 |\n";
- $this->P->addMode('table',new Doku_Parser_Mode_Table());
+ $this->P->addMode('table',new Table());
$this->P->parse($syntax);
$calls = array (
array('document_start',array()),
@@ -920,7 +928,7 @@ def');
*/
function testTable_CellFix() {
$syntax = "\n| r1c1 | r1c2 | r1c3 |\n| r2c1 |\n";
- $this->P->addMode('table',new Doku_Parser_Mode_Table());
+ $this->P->addMode('table',new Table());
$this->P->parse($syntax);
$calls = array (
array('document_start',array()),
@@ -961,7 +969,7 @@ def');
*/
function testTable_CellFix2() {
$syntax = "\n| r1c1 |\n| r2c1 | r2c2 | r2c3 |\n";
- $this->P->addMode('table',new Doku_Parser_Mode_Table());
+ $this->P->addMode('table',new Table());
$this->P->parse($syntax);
$calls = array (
array('document_start',array()),
diff --git a/_test/tests/inc/parser/parser_unformatted.test.php b/_test/tests/inc/parser/parser_unformatted.test.php
index f20ba5e8b..32c83fcce 100644
--- a/_test/tests/inc/parser/parser_unformatted.test.php
+++ b/_test/tests/inc/parser/parser_unformatted.test.php
@@ -1,10 +1,13 @@
<?php
+
+use dokuwiki\Parsing\ParserMode\Unformatted;
+
require_once 'parser.inc.php';
class TestOfDoku_Parser_Unformatted extends TestOfDoku_Parser {
function testNowiki() {
- $this->P->addMode('unformatted',new Doku_Parser_Mode_Unformatted());
+ $this->P->addMode('unformatted',new Unformatted());
$this->P->parse("Foo <nowiki>testing</nowiki> Bar");
$calls = array (
array('document_start',array()),
@@ -21,7 +24,7 @@ class TestOfDoku_Parser_Unformatted extends TestOfDoku_Parser {
}
function testDoublePercent() {
- $this->P->addMode('unformatted',new Doku_Parser_Mode_Unformatted());
+ $this->P->addMode('unformatted',new Unformatted());
$this->P->parse("Foo %%testing%% Bar");
$calls = array (
array('document_start',array()),
diff --git a/_test/tests/inc/parser/renderer_resolveinterwiki.test.php b/_test/tests/inc/parser/renderer_resolveinterwiki.test.php
index 822c41af8..2cd23dfaa 100644
--- a/_test/tests/inc/parser/renderer_resolveinterwiki.test.php
+++ b/_test/tests/inc/parser/renderer_resolveinterwiki.test.php
@@ -1,6 +1,6 @@
<?php
-require_once DOKU_INC . 'inc/parser/renderer.php';
+use dokuwiki\test\mock\Doku_Renderer;
/**
* Tests for Doku_Renderer::_resolveInterWiki()
diff --git a/_test/tests/inc/parser/renderer_xhtml.test.php b/_test/tests/inc/parser/renderer_xhtml.test.php
index f7be39a1b..828c6dff6 100644
--- a/_test/tests/inc/parser/renderer_xhtml.test.php
+++ b/_test/tests/inc/parser/renderer_xhtml.test.php
@@ -1,5 +1,7 @@
<?php
+use dokuwiki\Parsing\Handler\Lists;
+
/**
* Class renderer_xhtml_test
*/
@@ -123,7 +125,7 @@ class renderer_xhtml_test extends DokuWikiTest {
$this->R->document_start();
$this->R->listo_open();
- $this->R->listitem_open(1, Doku_Handler_List::NODE);
+ $this->R->listitem_open(1, Lists::NODE);
$this->R->listcontent_open();
$this->R->cdata('item1');
$this->R->listcontent_close();
@@ -145,7 +147,7 @@ class renderer_xhtml_test extends DokuWikiTest {
$this->R->listcontent_close();
$this->R->listitem_close();
- $this->R->listitem_open(1, Doku_Handler_List::NODE);
+ $this->R->listitem_open(1, Lists::NODE);
$this->R->listcontent_open();
$this->R->cdata('item3');
$this->R->listcontent_close();
@@ -188,7 +190,7 @@ class renderer_xhtml_test extends DokuWikiTest {
$this->R->document_start();
$this->R->listu_open();
- $this->R->listitem_open(1, Doku_Handler_List::NODE);
+ $this->R->listitem_open(1, Lists::NODE);
$this->R->listcontent_open();
$this->R->cdata('item1');
$this->R->listcontent_close();
@@ -210,7 +212,7 @@ class renderer_xhtml_test extends DokuWikiTest {
$this->R->listcontent_close();
$this->R->listitem_close();
- $this->R->listitem_open(1, Doku_Handler_List::NODE);
+ $this->R->listitem_open(1, Lists::NODE);
$this->R->listcontent_open();
$this->R->cdata('item3');
$this->R->listcontent_close();
diff --git a/_test/tests/inc/remote.test.php b/_test/tests/inc/remote.test.php
index ee040f09a..6a9686b07 100644
--- a/_test/tests/inc/remote.test.php
+++ b/_test/tests/inc/remote.test.php
@@ -1,6 +1,10 @@
<?php
-class MockAuth extends DokuWiki_Auth_Plugin {
+use dokuwiki\Extension\AuthPlugin;
+use dokuwiki\Extension\RemotePlugin;
+use dokuwiki\Remote\Api;
+
+class MockAuth extends AuthPlugin {
function isCaseSensitive() { return true; }
}
@@ -75,7 +79,7 @@ class RemoteAPICoreTest {
}
-class remote_plugin_testplugin extends DokuWiki_Remote_Plugin {
+class remote_plugin_testplugin extends RemotePlugin {
function _getMethods() {
return array(
'method1' => array(
@@ -108,7 +112,7 @@ class remote_plugin_testplugin extends DokuWiki_Remote_Plugin {
function publicCall() {return true;}
}
-class remote_plugin_testplugin2 extends DokuWiki_Remote_Plugin {
+class remote_plugin_testplugin2 extends RemotePlugin {
/**
* This is a dummy method
*
@@ -131,7 +135,7 @@ class remote_test extends DokuWikiTest {
protected $userinfo;
- /** @var RemoteAPI */
+ /** @var Api */
protected $remote;
function setUp() {
@@ -144,7 +148,7 @@ class remote_test extends DokuWikiTest {
parent::setUp();
// mock plugin controller to return our test plugins
- $pluginManager = $this->createMock('Doku_Plugin_Controller');
+ $pluginManager = $this->createMock('dokuwiki\Extension\PluginController');
$pluginManager->method('getList')->willReturn(array('testplugin', 'testplugin2'));
$pluginManager->method('load')->willReturnCallback(
function($type, $plugin) {
@@ -162,7 +166,7 @@ class remote_test extends DokuWikiTest {
$conf['useacl'] = 0;
$this->userinfo = $USERINFO;
- $this->remote = new RemoteAPI();
+ $this->remote = new Api();
$auth = new MockAuth();
}
@@ -206,7 +210,7 @@ class remote_test extends DokuWikiTest {
}
/**
- * @expectedException RemoteAccessDeniedException
+ * @expectedException dokuwiki\Remote\AccessDeniedException
*/
function test_hasAccessFail() {
global $conf;
@@ -260,7 +264,7 @@ class remote_test extends DokuWikiTest {
}
/**
- * @expectedException RemoteException
+ * @expectedException dokuwiki\Remote\RemoteException
*/
function test_forceAccessFail() {
global $conf;
@@ -275,7 +279,7 @@ class remote_test extends DokuWikiTest {
$conf['remoteuser'] = '';
$conf['useacl'] = 1;
$USERINFO['grps'] = array('grp');
- $remoteApi = new RemoteApi();
+ $remoteApi = new Api();
$remoteApi->getCoreMethods(new RemoteAPICoreTest());
$this->assertEquals($remoteApi->call('wiki.stringTestMethod'), 'success');
@@ -287,12 +291,12 @@ class remote_test extends DokuWikiTest {
}
/**
- * @expectedException RemoteException
+ * @expectedException dokuwiki\Remote\RemoteException
*/
function test_generalCoreFunctionOnArgumentMismatch() {
global $conf;
$conf['remote'] = 1;
- $remoteApi = new RemoteApi();
+ $remoteApi = new Api();
$remoteApi->getCoreMethods(new RemoteAPICoreTest());
$remoteApi->call('wiki.voidTestMethod', array('something'));
@@ -305,7 +309,7 @@ class remote_test extends DokuWikiTest {
$conf['remoteuser'] = '';
$conf['useacl'] = 1;
- $remoteApi = new RemoteApi();
+ $remoteApi = new Api();
$remoteApi->getCoreMethods(new RemoteAPICoreTest());
$this->assertEquals($remoteApi->call('wiki.oneStringArgMethod', array('string')), 'string');
@@ -321,7 +325,7 @@ class remote_test extends DokuWikiTest {
$conf['remoteuser'] = '';
$conf['useacl'] = 1;
- $remoteApi = new RemoteApi();
+ $remoteApi = new Api();
$this->assertEquals($remoteApi->call('plugin.testplugin.method1'), null);
$this->assertEquals($remoteApi->call('plugin.testplugin.method2', array('string', 7)), array('string', 7, false));
$this->assertEquals($remoteApi->call('plugin.testplugin.method2ext', array('string', 7, true)), array('string', 7, true));
@@ -329,20 +333,20 @@ class remote_test extends DokuWikiTest {
}
/**
- * @expectedException RemoteException
+ * @expectedException dokuwiki\Remote\RemoteException
*/
function test_notExistingCall() {
global $conf;
$conf['remote'] = 1;
- $remoteApi = new RemoteApi();
+ $remoteApi = new Api();
$remoteApi->call('dose not exist');
}
function test_publicCallCore() {
global $conf;
$conf['useacl'] = 1;
- $remoteApi = new RemoteApi();
+ $remoteApi = new Api();
$remoteApi->getCoreMethods(new RemoteAPICoreTest());
$this->assertTrue($remoteApi->call('wiki.publicCall'));
}
@@ -350,28 +354,28 @@ class remote_test extends DokuWikiTest {
function test_publicCallPlugin() {
global $conf;
$conf['useacl'] = 1;
- $remoteApi = new RemoteApi();
+ $remoteApi = new Api();
$this->assertTrue($remoteApi->call('plugin.testplugin.publicCall'));
}
/**
- * @expectedException RemoteAccessDeniedException
+ * @expectedException dokuwiki\Remote\AccessDeniedException
*/
function test_publicCallCoreDeny() {
global $conf;
$conf['useacl'] = 1;
- $remoteApi = new RemoteApi();
+ $remoteApi = new Api();
$remoteApi->getCoreMethods(new RemoteAPICoreTest());
$remoteApi->call('wiki.stringTestMethod');
}
/**
- * @expectedException RemoteAccessDeniedException
+ * @expectedException dokuwiki\Remote\AccessDeniedException
*/
function test_publicCallPluginDeny() {
global $conf;
$conf['useacl'] = 1;
- $remoteApi = new RemoteApi();
+ $remoteApi = new Api();
$remoteApi->call('plugin.testplugin.methodString');
}
@@ -384,7 +388,7 @@ class remote_test extends DokuWikiTest {
global $EVENT_HANDLER;
$EVENT_HANDLER->register_hook('RPC_CALL_ADD', 'BEFORE', $this, 'pluginCallCustomPathRegister');
- $remoteApi = new RemoteAPI();
+ $remoteApi = new Api();
$result = $remoteApi->call('custom.path');
$this->assertEquals($result, 'success');
}
diff --git a/_test/tests/inc/remoteapicore.test.php b/_test/tests/inc/remoteapicore.test.php
index 66d0e9669..70b7710e8 100644
--- a/_test/tests/inc/remoteapicore.test.php
+++ b/_test/tests/inc/remoteapicore.test.php
@@ -1,5 +1,9 @@
<?php
+use dokuwiki\Remote\Api;
+use dokuwiki\Remote\ApiCore;
+use dokuwiki\test\mock\AuthPlugin;
+
/**
* Class remoteapicore_test
*/
@@ -7,7 +11,7 @@ class remoteapicore_test extends DokuWikiTest {
protected $userinfo;
protected $oldAuthAcl;
- /** @var RemoteAPI */
+ /** @var Api */
protected $remote;
public function setUp() {
@@ -21,13 +25,13 @@ class remoteapicore_test extends DokuWikiTest {
global $auth;
$this->oldAuthAcl = $AUTH_ACL;
$this->userinfo = $USERINFO;
- $auth = new DokuWiki_Auth_Plugin();
+ $auth = new AuthPlugin();
$conf['remote'] = 1;
$conf['remoteuser'] = '@user';
$conf['useacl'] = 0;
- $this->remote = new RemoteAPI();
+ $this->remote = new Api();
}
public function tearDown() {
@@ -389,7 +393,7 @@ You can use up to five different levels of',
}
public function test_getPageVersions() {
- /** @var $EVENT_HANDLER Doku_Event_Handler */
+ /** @var $EVENT_HANDLER \dokuwiki\Extension\EventHandler */
global $EVENT_HANDLER;
$EVENT_HANDLER->register_hook('IO_WIKIPAGE_WRITE', 'BEFORE', $this, 'handle_write');
global $conf;
@@ -480,7 +484,7 @@ You can use up to five different levels of',
}
public function test_getXMLRPCAPIVersion() {
- $this->assertEquals(DOKU_API_VERSION, $this->remote->call('dokuwiki.getXMLRPCAPIVersion'));
+ $this->assertEquals(ApiCore::API_VERSION, $this->remote->call('dokuwiki.getXMLRPCAPIVersion'));
}
public function test_getRPCVersionSupported() {
diff --git a/_test/tests/inc/remoteapicore_aclcheck.test.php b/_test/tests/inc/remoteapicore_aclcheck.test.php
index 25aff331f..6ba7f1dcf 100644
--- a/_test/tests/inc/remoteapicore_aclcheck.test.php
+++ b/_test/tests/inc/remoteapicore_aclcheck.test.php
@@ -1,5 +1,7 @@
<?php
+use dokuwiki\Remote\Api;
+
/**
* Class remoteapicore_test
*/
@@ -7,7 +9,7 @@ class remoteapicore_aclcheck_test extends DokuWikiTest {
protected $userinfo;
protected $oldAuthAcl;
- /** @var RemoteAPI */
+ /** @var Api */
protected $remote;
protected $pluginsEnabled = array('auth_plugin_authplain');
@@ -38,7 +40,7 @@ class remoteapicore_aclcheck_test extends DokuWikiTest {
$conf['remoteuser'] = '@user';
$conf['useacl'] = 0;
- $this->remote = new RemoteAPI();
+ $this->remote = new Api();
}
diff --git a/_test/tests/inc/subscription.test.php b/_test/tests/inc/subscription.test.php
deleted file mode 100644
index 34a7b9e4b..000000000
--- a/_test/tests/inc/subscription.test.php
+++ /dev/null
@@ -1,246 +0,0 @@
-<?php
-
-class subscription_test extends DokuWikiTest {
-
- function test_regexp() {
- // data to test against
- $data = array(
- "casper every\n",
- "Andreas digest 1344689733",
- "Cold%20Fusion every",
- "zioth list 1344691369\n",
- "nlights digest",
- "rikblok\tdigest \t 1344716803",
- );
-
- // user, style, data, expected number of results
- $tests = array(
- array('Cold Fusion', null, null, 1),
- array('casper', null, null, 1),
- array('nope', null, null, 0),
- array('lights', null, null, 0),
- array(array('Cold Fusion', 'casper', 'nope'), null, null, 2),
- array(null, 'list', null, 1),
- array(null, 'every', null, 2),
- array(null, 'digest', null, 3),
- array(null, array('list', 'every'), null, 3),
- array('casper', 'digest', null, 0),
- array('casper', array('digest', 'every'), null, 1),
- array('zioth', 'list', '1344691369', 1),
- array('zioth', null, '1344691369', 1),
- array('zioth', 'digest', '1344691369', 0),
- );
-
- $sub = new MockupSubscription();
-
- $row = 0;
- foreach($tests as $test) {
- $re = $sub->buildregex($test[0], $test[1], $test[2]);
- $this->assertFalse(empty($re), "test line $row");
- $result = preg_grep($re, $data);
- $this->assertEquals($test[3], count($result), "test line $row. $re got\n".print_r($result, true));
-
- $row++;
- }
- }
-
- function test_addremove() {
- $sub = new MockupSubscription();
-
- // no subscriptions
- $this->assertArrayNotHasKey(
- 'wiki:dokuwiki',
- $sub->subscribers('wiki:dokuwiki', null, array('every', 'list', 'digest'))
- );
-
- // add page subscription
- $sub->add('wiki:dokuwiki', 'testuser', 'every');
-
- // one subscription
- $this->assertArrayHasKey(
- 'wiki:dokuwiki',
- $sub->subscribers('wiki:dokuwiki', null, array('every', 'list', 'digest'))
- );
-
- // remove page subscription
- $sub->remove('wiki:dokuwiki', 'testuser');
-
- // no subscription
- $this->assertArrayNotHasKey(
- 'wiki:dokuwiki',
- $sub->subscribers('wiki:dokuwiki', null, array('every', 'list', 'digest'))
- );
-
- // add namespace subscription
- $sub->add('wiki:', 'testuser', 'every');
-
- // one subscription
- $this->assertArrayHasKey(
- 'wiki:',
- $sub->subscribers('wiki:dokuwiki', null, array('every', 'list', 'digest'))
- );
-
- // remove (non existing) page subscription
- $sub->remove('wiki:dokuwiki', 'testuser');
-
- // still one subscription
- $this->assertArrayHasKey(
- 'wiki:',
- $sub->subscribers('wiki:dokuwiki', null, array('every', 'list', 'digest'))
- );
-
- // change namespace subscription
- $sub->add('wiki:', 'testuser', 'digest', '1234567');
-
- // still one subscription
- $this->assertArrayHasKey(
- 'wiki:',
- $sub->subscribers('wiki:dokuwiki', null, array('every', 'list', 'digest'))
- );
-
- // check contents
- $this->assertEquals(
- array('wiki:' => array('testuser' => array('digest', '1234567'))),
- $sub->subscribers('wiki:dokuwiki', null, array('every', 'list', 'digest'))
- );
-
- // change subscription data
- $sub->add('wiki:', 'testuser', 'digest', '7654321');
-
- // still one subscription
- $this->assertArrayHasKey(
- 'wiki:',
- $sub->subscribers('wiki:dokuwiki', null, array('every', 'list', 'digest'))
- );
-
- // check contents
- $this->assertEquals(
- array('wiki:' => array('testuser' => array('digest', '7654321'))),
- $sub->subscribers('wiki:dokuwiki', null, array('every', 'list', 'digest'))
- );
- }
-
- function test_bulkdigest() {
- $sub = new MockupSubscription();
-
- // let's start with nothing
- $this->assertEquals(0, $sub->send_bulk('sub1:test'));
-
- // create a subscription
- $sub->add('sub1:', 'testuser', 'digest', '978328800'); // last mod 2001-01-01
-
- // now create change
- $_SERVER['REMOTE_USER'] = 'someguy';
- saveWikiText('sub1:test', 'foo bar', 'a subscription change', false);
-
- // should trigger a mail
- $this->assertEquals(1, $sub->send_bulk('sub1:test'));
- $this->assertEquals(array('arthur@example.com'), $sub->mails);
-
- $sub->reset();
-
- // now create more changes
- $_SERVER['REMOTE_USER'] = 'someguy';
- saveWikiText('sub1:sub2:test', 'foo bar', 'a subscription change', false);
- saveWikiText('sub1:another_test', 'foo bar', 'a subscription change', false);
-
- // should not trigger a mail, because the subscription time has not been reached, yet
- $this->assertEquals(0, $sub->send_bulk('sub1:test'));
- $this->assertEquals(array(), $sub->mails);
-
- // reset the subscription time
- $sub->add('sub1:', 'testuser', 'digest', '978328800'); // last mod 2001-01-01
-
- // we now should get mails for three changes
- $this->assertEquals(3, $sub->send_bulk('sub1:test'));
- $this->assertEquals(array('arthur@example.com', 'arthur@example.com', 'arthur@example.com'), $sub->mails);
- }
-
- function test_bulklist() {
- $sub = new MockupSubscription();
-
- // let's start with nothing
- $this->assertEquals(0, $sub->send_bulk('sub1:test'));
-
- // create a subscription
- $sub->add('sub1:', 'testuser', 'list', '978328800'); // last mod 2001-01-01
-
- // now create change
- $_SERVER['REMOTE_USER'] = 'someguy';
- saveWikiText('sub1:test', 'foo bar', 'a subscription change', false);
-
- // should trigger a mail
- $this->assertEquals(1, $sub->send_bulk('sub1:test'));
- $this->assertEquals(array('arthur@example.com'), $sub->mails);
-
- $sub->reset();
-
- // now create more changes
- $_SERVER['REMOTE_USER'] = 'someguy';
- saveWikiText('sub1:sub2:test', 'foo bar', 'a subscription change', false);
- saveWikiText('sub1:another_test', 'foo bar', 'a subscription change', false);
-
- // should not trigger a mail, because the subscription time has not been reached, yet
- $this->assertEquals(0, $sub->send_bulk('sub1:test'));
- $this->assertEquals(array(), $sub->mails);
-
- // reset the subscription time
- $sub->add('sub1:', 'testuser', 'list', '978328800'); // last mod 2001-01-01
-
- // we now should get a single mail for all three changes
- $this->assertEquals(1, $sub->send_bulk('sub1:test'));
- $this->assertEquals(array('arthur@example.com'), $sub->mails);
- }
-
- /**
- * Tests, if overwriting subscriptions works even when subscriptions for the same
- * user exist for two nested namespaces, this is a test for the bug described in FS#2580
- */
- function test_overwrite() {
- $sub = new MockupSubscription();
-
- $sub->add(':', 'admin', 'digest', '123456789');
- $sub->add(':wiki:', 'admin', 'digest', '123456789');
- $sub->add(':', 'admin', 'digest', '1234');
- $sub->add(':wiki:', 'admin', 'digest', '1234');
-
- $subscriptions = $sub->subscribers(':wiki:', 'admin');
-
- $this->assertCount(1, $subscriptions[':'], 'More than one subscription saved for the root namespace even though the old one should have been overwritten.');
- $this->assertCount(1, $subscriptions[':wiki:'], 'More than one subscription saved for the wiki namespace even though the old one should have been overwritten.');
- $this->assertCount(2, $subscriptions, 'Didn\'t find the expected two subscriptions');
- }
-}
-
-/**
- * makes protected methods visible for testing
- */
-class MockupSubscription extends Subscription {
- public $mails; // we keep sent mails here
-
- public function __construct() {
- $this->reset();
- }
-
- /**
- * resets the mail array
- */
- public function reset() {
- $this->mails = array();
- }
-
- public function isenabled() {
- return true;
- }
-
- public function buildregex($user = null, $style = null, $data = null) {
- return parent::buildregex($user, $style, $data);
- }
-
- protected function send($subscriber_mail, $subject, $id, $template, $trep, $hrep = null, $headers = array()) {
- $this->mails[] = $subscriber_mail;
- return true;
- }
-}
-
-//Setup VIM: ex: et ts=4 :
diff --git a/_test/tests/inc/utf8_basename.test.php b/_test/tests/inc/utf8_basename.test.php
index 1544e9915..c946e39f3 100644
--- a/_test/tests/inc/utf8_basename.test.php
+++ b/_test/tests/inc/utf8_basename.test.php
@@ -84,8 +84,8 @@ class utf8_basename_test extends DokuWikiTest {
);
foreach($data as $test){
- $this->assertEquals($test[2], utf8_basename($test[0], $test[1]), "input: ('".$test[0]."', '".$test[1]."')");
+ $this->assertEquals($test[2], \dokuwiki\Utf8\PhpString::basename($test[0], $test[1]), "input: ('".$test[0]."', '".$test[1]."')");
}
}
-} \ No newline at end of file
+}
diff --git a/_test/tests/inc/utf8_correctidx.test.php b/_test/tests/inc/utf8_correctidx.test.php
index a704fd0e8..5a24af737 100644
--- a/_test/tests/inc/utf8_correctidx.test.php
+++ b/_test/tests/inc/utf8_correctidx.test.php
@@ -15,7 +15,7 @@ class utf8_correctidx_test extends DokuWikiTest {
$tests[] = array('aaживπά우리をあöä',1,true,1);
foreach($tests as $test){
- $this->assertEquals(utf8_correctIdx($test[0],$test[1],$test[2]),$test[3]);
+ $this->assertEquals(\dokuwiki\Utf8\Clean::correctIdx($test[0],$test[1],$test[2]),$test[3]);
}
}
@@ -33,7 +33,7 @@ class utf8_correctidx_test extends DokuWikiTest {
$tests[] = array('aaживπά우리をあöä',4,true,4);
foreach($tests as $test){
- $this->assertEquals(utf8_correctIdx($test[0],$test[1],$test[2]),$test[3]);
+ $this->assertEquals(\dokuwiki\Utf8\Clean::correctIdx($test[0],$test[1],$test[2]),$test[3]);
}
}
@@ -53,7 +53,7 @@ class utf8_correctidx_test extends DokuWikiTest {
$tests[] = array('aaживπά우리をあöä',13,true,13);
foreach($tests as $test){
- $this->assertEquals(utf8_correctIdx($test[0],$test[1],$test[2]),$test[3]);
+ $this->assertEquals(\dokuwiki\Utf8\Clean::correctIdx($test[0],$test[1],$test[2]),$test[3]);
}
}
@@ -69,7 +69,7 @@ class utf8_correctidx_test extends DokuWikiTest {
$tests[] = array('aaживπά우리をあöä',128,true,29);
foreach($tests as $test){
- $this->assertEquals(utf8_correctIdx($test[0],$test[1],$test[2]),$test[3]);
+ $this->assertEquals(\dokuwiki\Utf8\Clean::correctIdx($test[0],$test[1],$test[2]),$test[3]);
}
}
diff --git a/_test/tests/inc/utf8_html.test.php b/_test/tests/inc/utf8_html.test.php
index 4a70c3c4c..d65004fc2 100644
--- a/_test/tests/inc/utf8_html.test.php
+++ b/_test/tests/inc/utf8_html.test.php
@@ -8,7 +8,7 @@ class utf8_html_test extends DokuWikiTest {
function test_from_1byte(){
$in = 'a';
$out = 'a';
- $this->assertEquals(utf8_tohtml($in),$out);
+ $this->assertEquals(\dokuwiki\Utf8\Conversion::toHtml($in),$out);
}
function test_from_1byte_all(){
@@ -20,55 +20,55 @@ class utf8_html_test extends DokuWikiTest {
function test_from_2byte(){
$in = "\xc3\xbc";
$out = '&#252;';
- $this->assertEquals(utf8_tohtml($in),$out);
+ $this->assertEquals(\dokuwiki\Utf8\Conversion::toHtml($in),$out);
}
function test_from_3byte(){
$in = "\xe2\x99\x8a";
$out = '&#x264a;';
- $this->assertEquals(utf8_tohtml($in),$out);
+ $this->assertEquals(\dokuwiki\Utf8\Conversion::toHtml($in),$out);
}
function test_from_4byte(){
$in = "\xf4\x80\x80\x81";
$out = '&#x100001;';
- $this->assertEquals(utf8_tohtml($in),$out);
+ $this->assertEquals(\dokuwiki\Utf8\Conversion::toHtml($in),$out);
}
function test_to_1byte(){
$out = 'a';
$in = 'a';
- $this->assertEquals(utf8_unhtml($in),$out);
+ $this->assertEquals(\dokuwiki\Utf8\Conversion::fromHtml($in),$out);
}
function test_to_2byte(){
$out = "\xc3\xbc";
$in = '&#252;';
- $this->assertEquals(utf8_unhtml($in),$out);
+ $this->assertEquals(\dokuwiki\Utf8\Conversion::fromHtml($in),$out);
}
function test_to_3byte(){
$out = "\xe2\x99\x8a";
$in = '&#x264a;';
- $this->assertEquals(utf8_unhtml($in),$out);
+ $this->assertEquals(\dokuwiki\Utf8\Conversion::fromHtml($in),$out);
}
function test_to_4byte(){
$out = "\xf4\x80\x80\x81";
$in = '&#x100001;';
- $this->assertEquals(utf8_unhtml($in),$out);
+ $this->assertEquals(\dokuwiki\Utf8\Conversion::fromHtml($in),$out);
}
function test_without_entities(){
$out = '&amp;#38;&amp;#38;';
$in = '&amp;#38;&#38;amp;#38;';
- $this->assertEquals(utf8_unhtml($in),$out);
+ $this->assertEquals(\dokuwiki\Utf8\Conversion::fromHtml($in),$out);
}
function test_with_entities(){
$out = '&#38;&amp;#38;';
$in = '&amp;#38;&#38;amp;#38;';
- $this->assertEquals(utf8_unhtml($in,HTML_ENTITIES),$out);
+ $this->assertEquals(\dokuwiki\Utf8\Conversion::fromHtml($in,HTML_ENTITIES),$out);
}
}
diff --git a/_test/tests/inc/utf8_romanize.test.php b/_test/tests/inc/utf8_romanize.test.php
index 353d48c00..5ffa38872 100644
--- a/_test/tests/inc/utf8_romanize.test.php
+++ b/_test/tests/inc/utf8_romanize.test.php
@@ -18,7 +18,7 @@ class utf8_romanize_test extends DokuWikiTest {
foreach($tests as $test){
list($jap,$rom) = explode(';',trim($test));
- $chk = utf8_romanize($jap);
+ $chk = \dokuwiki\Utf8\Clean::romanize($jap);
$this->assertEquals($rom,$chk,"$jap\t->\t$chk\t!=\t$rom\t($line)");
$line++;
}
@@ -31,7 +31,7 @@ class utf8_romanize_test extends DokuWikiTest {
* @author Andreas Gohr <andi@splitbrain.org>
*/
function test_deaccented(){
- $this->assertEquals("a A a A a o O",utf8_romanize("å Å ä Ä ä ö Ö"));
+ $this->assertEquals("a A a A a o O",\dokuwiki\Utf8\Clean::romanize("å Å ä Ä ä ö Ö"));
}
}
//Setup VIM: ex: et ts=4 :
diff --git a/_test/tests/inc/utf8_stripspecials.test.php b/_test/tests/inc/utf8_stripspecials.test.php
index c9dc3205f..723b36281 100644
--- a/_test/tests/inc/utf8_stripspecials.test.php
+++ b/_test/tests/inc/utf8_stripspecials.test.php
@@ -19,7 +19,7 @@ class utf8_stripspecials extends DokuWikiTest {
$tests[] = array('string with nbsps','_','\*','string_with_nbsps');
foreach($tests as $test){
- $this->assertEquals(utf8_stripspecials($test[0],$test[1],$test[2]),$test[3]);
+ $this->assertEquals(\dokuwiki\Utf8\Clean::stripspecials($test[0],$test[1],$test[2]),$test[3]);
}
}
diff --git a/_test/tests/inc/utf8_strtolower.test.php b/_test/tests/inc/utf8_strtolower.test.php
index 85f5b270b..2654c72cc 100644
--- a/_test/tests/inc/utf8_strtolower.test.php
+++ b/_test/tests/inc/utf8_strtolower.test.php
@@ -10,7 +10,7 @@ class utf8_strtolower_test extends DokuWikiTest {
);
foreach($data as $input => $expected) {
- $this->assertEquals($expected, utf8_strtolower($input));
+ $this->assertEquals($expected, \dokuwiki\Utf8\PhpString::strtolower($input));
}
// just make sure our data was correct
@@ -20,4 +20,4 @@ class utf8_strtolower_test extends DokuWikiTest {
}
}
}
-} \ No newline at end of file
+}
diff --git a/_test/tests/inc/utf8_substr.test.php b/_test/tests/inc/utf8_substr.test.php
index 758e8c9d4..e7d3fb555 100644
--- a/_test/tests/inc/utf8_substr.test.php
+++ b/_test/tests/inc/utf8_substr.test.php
@@ -21,7 +21,7 @@ class utf8_substr_test extends DokuWikiTest {
$tests[] = array('живπά우리をあöä',-6,-2,'우리をあ');
foreach($tests as $test){
- $this->assertEquals(utf8_substr($test[0],$test[1],$test[2]),$test[3]);
+ $this->assertEquals(\dokuwiki\Utf8\PhpString::substr($test[0],$test[1],$test[2]),$test[3]);
}
}
@@ -34,7 +34,7 @@ class utf8_substr_test extends DokuWikiTest {
$tests[] = array($str,0,66002,$str);
foreach($tests as $test){
- $this->assertEquals(utf8_substr($test[0],$test[1],$test[2]),$test[3]);
+ $this->assertEquals(\dokuwiki\Utf8\PhpString::substr($test[0],$test[1],$test[2]),$test[3]);
}
}
diff --git a/_test/tests/inc/utf8_unicode.test.php b/_test/tests/inc/utf8_unicode.test.php
index fde8c5d02..94ef9f23e 100644
--- a/_test/tests/inc/utf8_unicode.test.php
+++ b/_test/tests/inc/utf8_unicode.test.php
@@ -8,49 +8,49 @@ class utf8_unicode_test extends DokuWikiTest {
function test_from_1byte(){
$in = 'a';
$out = array(97);
- $this->assertEquals(utf8_to_unicode($in),$out);
+ $this->assertEquals(\dokuwiki\Utf8\Unicode::fromUtf8($in),$out);
}
function test_from_2byte(){
$in = "\xc3\xbc";
$out = array(252);
- $this->assertEquals(utf8_to_unicode($in),$out);
+ $this->assertEquals(\dokuwiki\Utf8\Unicode::fromUtf8($in),$out);
}
function test_from_3byte(){
$in = "\xe2\x99\x8a";
$out = array(9802);
- $this->assertEquals(utf8_to_unicode($in),$out);
+ $this->assertEquals(\dokuwiki\Utf8\Unicode::fromUtf8($in),$out);
}
function test_from_4byte(){
$in = "\xf4\x80\x80\x81";
$out = array(1048577);
- $this->assertEquals(utf8_to_unicode($in),$out);
+ $this->assertEquals(\dokuwiki\Utf8\Unicode::fromUtf8($in),$out);
}
function test_to_1byte(){
$out = 'a';
$in = array(97);
- $this->assertEquals(unicode_to_utf8($in),$out);
+ $this->assertEquals(\dokuwiki\Utf8\Unicode::toUtf8($in),$out);
}
function test_to_2byte(){
$out = "\xc3\xbc";
$in = array(252);
- $this->assertEquals(unicode_to_utf8($in),$out);
+ $this->assertEquals(\dokuwiki\Utf8\Unicode::toUtf8($in),$out);
}
function test_to_3byte(){
$out = "\xe2\x99\x8a";
$in = array(9802);
- $this->assertEquals(unicode_to_utf8($in),$out);
+ $this->assertEquals(\dokuwiki\Utf8\Unicode::toUtf8($in),$out);
}
function test_to_4byte(){
$out = "\xf4\x80\x80\x81";
$in = array(1048577);
- $this->assertEquals(unicode_to_utf8($in),$out);
+ $this->assertEquals(\dokuwiki\Utf8\Unicode::toUtf8($in),$out);
}
}
diff --git a/_test/tests/inc/utf8_utf16be.test.php b/_test/tests/inc/utf8_utf16be.test.php
index 943ebeffc..6ac879f68 100644
--- a/_test/tests/inc/utf8_utf16be.test.php
+++ b/_test/tests/inc/utf8_utf16be.test.php
@@ -12,14 +12,14 @@ class utf8_utf16be_test extends DokuWikiTest {
* Convert from UTF-8 to UTF-16BE
*/
function test_to16be(){
- $this->assertEquals(utf8_to_utf16be($this->utf8), $this->utf16);
+ $this->assertEquals(\dokuwiki\Utf8\Conversion::toUtf16Be($this->utf8), $this->utf16);
}
/**
* Convert from UTF-16BE to UTF-8
*/
function test_from16be(){
- $this->assertEquals(utf16be_to_utf8($this->utf16),$this->utf8);
+ $this->assertEquals(\dokuwiki\Utf8\Conversion::fromUtf16Be($this->utf16),$this->utf8);
}
}
diff --git a/bin/dwpage.php b/bin/dwpage.php
index 3124563fc..967183434 100755
--- a/bin/dwpage.php
+++ b/bin/dwpage.php
@@ -182,7 +182,7 @@ class PageCLI extends CLI {
}
if(empty($localfile)) {
- $localfile = getcwd() . '/' . utf8_basename($wiki_fn);
+ $localfile = getcwd() . '/' . \dokuwiki\Utf8\PhpString::basename($wiki_fn);
}
if(!file_exists(dirname($localfile))) {
diff --git a/bin/gittool.php b/bin/gittool.php
index 63d5b4426..990281bf6 100755
--- a/bin/gittool.php
+++ b/bin/gittool.php
@@ -89,17 +89,17 @@ class GitToolCLI extends CLI {
echo $options->help();
break;
case 'clone':
- $this->cmd_clone($args);
+ $this->cmdClone($args);
break;
case 'install':
- $this->cmd_install($args);
+ $this->cmdInstall($args);
break;
case 'repo':
case 'repos':
- $this->cmd_repos();
+ $this->cmdRepos();
break;
default:
- $this->cmd_git($command, $args);
+ $this->cmdGit($command, $args);
}
}
@@ -108,7 +108,7 @@ class GitToolCLI extends CLI {
*
* @param array $extensions
*/
- public function cmd_clone($extensions) {
+ public function cmdClone($extensions) {
$errors = array();
$succeeded = array();
@@ -137,7 +137,7 @@ class GitToolCLI extends CLI {
*
* @param array $extensions
*/
- public function cmd_install($extensions) {
+ public function cmdInstall($extensions) {
$errors = array();
$succeeded = array();
@@ -171,7 +171,7 @@ class GitToolCLI extends CLI {
* @param $cmd
* @param $arg
*/
- public function cmd_git($cmd, $arg) {
+ public function cmdGit($cmd, $arg) {
$repos = $this->findRepos();
$shell = array_merge(array('git', $cmd), $arg);
@@ -199,7 +199,7 @@ class GitToolCLI extends CLI {
/**
* Simply lists the repositories
*/
- public function cmd_repos() {
+ public function cmdRepos() {
$repos = $this->findRepos();
foreach($repos as $repo) {
echo "$repo\n";
diff --git a/bin/indexer.php b/bin/indexer.php
index 4d19a9515..9ccdaa448 100755
--- a/bin/indexer.php
+++ b/bin/indexer.php
@@ -60,7 +60,7 @@ class IndexerCLI extends CLI {
/**
* Update the index
*/
- function update() {
+ protected function update() {
global $conf;
$data = array();
$this->quietecho("Searching pages... ");
@@ -77,7 +77,7 @@ class IndexerCLI extends CLI {
*
* @param string $id
*/
- function index($id) {
+ protected function index($id) {
$this->quietecho("$id... ");
idx_addPage($id, !$this->quiet, $this->clear);
$this->quietecho("done.\n");
@@ -86,7 +86,7 @@ class IndexerCLI extends CLI {
/**
* Clear all index files
*/
- function clearindex() {
+ protected function clearindex() {
$this->quietecho("Clearing index... ");
idx_get_indexer()->clear();
$this->quietecho("done.\n");
@@ -97,7 +97,7 @@ class IndexerCLI extends CLI {
*
* @param string $msg
*/
- function quietecho($msg) {
+ protected function quietecho($msg) {
if(!$this->quiet) echo $msg;
}
}
diff --git a/bin/plugin.php b/bin/plugin.php
index cbe0b1fe7..a3ee78dd0 100755
--- a/bin/plugin.php
+++ b/bin/plugin.php
@@ -1,6 +1,7 @@
#!/usr/bin/php
<?php
+use dokuwiki\Extension\PluginController;
use splitbrain\phpcli\CLI;
use splitbrain\phpcli\Colors;
use splitbrain\phpcli\Options;
@@ -51,7 +52,7 @@ class PluginCLI extends CLI {
* List available plugins
*/
protected function listPlugins() {
- /** @var Doku_Plugin_Controller $plugin_controller */
+ /** @var PluginController $plugin_controller */
global $plugin_controller;
echo "\n";
@@ -85,10 +86,9 @@ class PluginCLI extends CLI {
* Instantiate a CLI plugin
*
* @param string $name
- * @return DokuWiki_CLI_Plugin|null
+ * @return \dokuwiki\Extension\CLIPlugin|null
*/
- protected
- function loadPlugin($name) {
+ protected function loadPlugin($name) {
// execute the plugin CLI
$class = "cli_plugin_$name";
if(class_exists($class)) {
diff --git a/bin/wantedpages.php b/bin/wantedpages.php
index 0240eb958..f2efa0950 100755
--- a/bin/wantedpages.php
+++ b/bin/wantedpages.php
@@ -74,8 +74,8 @@ class WantedPagesCLI extends CLI {
$this->info("searching $startdir");
- foreach($this->get_pages($startdir) as $page) {
- $this->internal_links($page);
+ foreach($this->getPages($startdir) as $page) {
+ $this->internalLinks($page);
}
ksort($this->result);
foreach($this->result as $main => $subs) {
@@ -98,7 +98,7 @@ class WantedPagesCLI extends CLI {
* @param string $basepath
* @return int
*/
- protected function dir_filter($entry, $basepath) {
+ protected function dirFilter($entry, $basepath) {
if($entry == '.' || $entry == '..') {
return WantedPagesCLI::DIR_CONTINUE;
}
@@ -121,7 +121,7 @@ class WantedPagesCLI extends CLI {
* @return array
* @throws DokuCLI_Exception
*/
- protected function get_pages($dir) {
+ protected function getPages($dir) {
static $trunclen = null;
if(!$trunclen) {
global $conf;
@@ -135,11 +135,11 @@ class WantedPagesCLI extends CLI {
$pages = array();
$dh = opendir($dir);
while(false !== ($entry = readdir($dh))) {
- $status = $this->dir_filter($entry, $dir);
+ $status = $this->dirFilter($entry, $dir);
if($status == WantedPagesCLI::DIR_CONTINUE) {
continue;
} else if($status == WantedPagesCLI::DIR_NS) {
- $pages = array_merge($pages, $this->get_pages($dir . '/' . $entry));
+ $pages = array_merge($pages, $this->getPages($dir . '/' . $entry));
} else {
$page = array(
'id' => pathID(substr($dir . '/' . $entry, $trunclen)),
@@ -157,7 +157,7 @@ class WantedPagesCLI extends CLI {
*
* @param array $page array with page id and file path
*/
- function internal_links($page) {
+ protected function internalLinks($page) {
global $conf;
$instructions = p_get_instructions(file_get_contents($page['file']));
$cns = getNS($page['id']);
diff --git a/doku.php b/doku.php
index 7c66eda52..4d203464a 100644
--- a/doku.php
+++ b/doku.php
@@ -9,6 +9,8 @@
*/
// update message version - always use a string to avoid localized floats!
+use dokuwiki\Extension\Event;
+
$updateVersion = "51";
// xdebug_start_profiling();
@@ -111,7 +113,7 @@ if($conf['breadcrumbs']) breadcrumbs();
checkUpdateMessages();
$tmp = array(); // No event data
-trigger_event('DOKUWIKI_STARTED', $tmp);
+Event::createAndTrigger('DOKUWIKI_STARTED', $tmp);
//close session
session_write_close();
@@ -120,6 +122,6 @@ session_write_close();
act_dispatch();
$tmp = array(); // No event data
-trigger_event('DOKUWIKI_DONE', $tmp);
+Event::createAndTrigger('DOKUWIKI_DONE', $tmp);
// xdebug_dump_function_profile(1);
diff --git a/feed.php b/feed.php
index 65d751b3e..de5887e6d 100644
--- a/feed.php
+++ b/feed.php
@@ -9,6 +9,12 @@
* @global Input $INPUT
*/
+use dokuwiki\Cache\Cache;
+use dokuwiki\ChangeLog\MediaChangeLog;
+use dokuwiki\ChangeLog\PageChangeLog;
+use dokuwiki\Extension\AuthPlugin;
+use dokuwiki\Extension\Event;
+
if(!defined('DOKU_INC')) define('DOKU_INC', dirname(__FILE__).'/');
require_once(DOKU_INC.'inc/init.php');
@@ -28,7 +34,7 @@ $opt = rss_parseOptions();
// the feed is dynamic - we need a cache for each combo
// (but most people just use the default feed so it's still effective)
$key = join('', array_values($opt)).'$'.$_SERVER['REMOTE_USER'].'$'.$_SERVER['HTTP_HOST'].$_SERVER['SERVER_PORT'];
-$cache = new cache($key, '.feed');
+$cache = new Cache($key, '.feed');
// prepare cache depends
$depends['files'] = getConfigFiles('main');
@@ -42,7 +48,7 @@ header('Pragma: public');
header('Content-Type: application/xml; charset=utf-8');
header('X-Robots-Tag: noindex');
if($cache->useCache($depends)) {
- http_conditionalRequest($cache->_time);
+ http_conditionalRequest($cache->getTime());
if($conf['allowdebug']) header("X-CacheUsed: $cache->cache");
print $cache->retrieveCache();
exit;
@@ -76,7 +82,7 @@ if(isset($modes[$opt['feed_mode']])) {
'opt' => &$opt,
'data' => &$data,
);
- $event = new Doku_Event('FEED_MODE_UNKNOWN', $eventData);
+ $event = new Event('FEED_MODE_UNKNOWN', $eventData);
if($event->advise_before(true)) {
echo sprintf('<error>Unknown feed mode %s</error>', hsc($opt['feed_mode']));
exit;
@@ -174,7 +180,7 @@ function rss_parseOptions() {
$eventData = array(
'opt' => &$opt,
);
- trigger_event('FEED_OPTS_POSTPROCESS', $eventData);
+ Event::createAndTrigger('FEED_OPTS_POSTPROCESS', $eventData);
return $opt;
}
@@ -189,7 +195,7 @@ function rss_parseOptions() {
function rss_buildItems(&$rss, &$data, $opt) {
global $conf;
global $lang;
- /* @var DokuWiki_Auth_Plugin $auth */
+ /* @var AuthPlugin $auth */
global $auth;
$eventData = array(
@@ -197,7 +203,7 @@ function rss_buildItems(&$rss, &$data, $opt) {
'data' => &$data,
'opt' => &$opt,
);
- $event = new Doku_Event('FEED_DATA_PROCESS', $eventData);
+ $event = new Event('FEED_DATA_PROCESS', $eventData);
if($event->advise_before(false)) {
foreach($data as $ditem) {
if(!is_array($ditem)) {
@@ -443,7 +449,7 @@ function rss_buildItems(&$rss, &$data, $opt) {
'ditem' => &$ditem,
'rss' => &$rss
);
- $evt = new Doku_Event('FEED_ITEM_ADD', $evdata);
+ $evt = new Event('FEED_ITEM_ADD', $evdata);
if($evt->advise_before()) {
$rss->addItem($item);
}
diff --git a/inc/Action/Admin.php b/inc/Action/Admin.php
index cc6dfd74f..1c9afd6b9 100644
--- a/inc/Action/Admin.php
+++ b/inc/Action/Admin.php
@@ -28,7 +28,7 @@ class Admin extends AbstractUserAction {
// retrieve admin plugin name from $_REQUEST['page']
if(($page = $INPUT->str('page', '', true)) != '') {
- /** @var $plugin \DokuWiki_Admin_Plugin */
+ /** @var $plugin \dokuwiki\Extension\AdminPlugin */
if($plugin = plugin_getRequestAdminPlugin()) { // FIXME this method does also permission checking
if(!$plugin->isAccessibleByCurrentUser()) {
throw new ActionException('denied');
diff --git a/inc/Action/Export.php b/inc/Action/Export.php
index 1eec27ec3..6b46b276e 100644
--- a/inc/Action/Export.php
+++ b/inc/Action/Export.php
@@ -3,6 +3,7 @@
namespace dokuwiki\Action;
use dokuwiki\Action\Exception\ActionAbort;
+use dokuwiki\Extension\Event;
/**
* Class Export
@@ -96,7 +97,7 @@ class Export extends AbstractAction {
$data['headers'] = $headers;
$data['output'] =& $output;
- trigger_event('ACTION_EXPORT_POSTPROCESS', $data);
+ Event::createAndTrigger('ACTION_EXPORT_POSTPROCESS', $data);
if(!empty($data['output'])) {
if(is_array($data['headers'])) foreach($data['headers'] as $key => $val) {
diff --git a/inc/Action/Logout.php b/inc/Action/Logout.php
index 8b464e85d..28e8fee58 100644
--- a/inc/Action/Logout.php
+++ b/inc/Action/Logout.php
@@ -23,7 +23,7 @@ class Logout extends AbstractUserAction {
public function checkPreconditions() {
parent::checkPreconditions();
- /** @var \DokuWiki_Auth_Plugin $auth */
+ /** @var \dokuwiki\Extension\AuthPlugin $auth */
global $auth;
if(!$auth->canDo('logout')) throw new ActionDisabledException();
}
diff --git a/inc/Action/Plugin.php b/inc/Action/Plugin.php
index c3e16bf87..43964cf39 100644
--- a/inc/Action/Plugin.php
+++ b/inc/Action/Plugin.php
@@ -23,7 +23,7 @@ class Plugin extends AbstractAction {
* @triggers TPL_ACT_UNKNOWN
*/
public function tplContent() {
- $evt = new \Doku_Event('TPL_ACT_UNKNOWN', $this->actionname);
+ $evt = new \dokuwiki\Extension\Event('TPL_ACT_UNKNOWN', $this->actionname);
if($evt->advise_before()) {
msg('Failed to handle action: ' . hsc($this->actionname), -1);
}
diff --git a/inc/Action/Profile.php b/inc/Action/Profile.php
index 53d8d2ff3..654a23818 100644
--- a/inc/Action/Profile.php
+++ b/inc/Action/Profile.php
@@ -23,7 +23,7 @@ class Profile extends AbstractUserAction {
public function checkPreconditions() {
parent::checkPreconditions();
- /** @var \DokuWiki_Auth_Plugin $auth */
+ /** @var \dokuwiki\Extension\AuthPlugin $auth */
global $auth;
if(!$auth->canDo('Profile')) throw new ActionDisabledException();
}
diff --git a/inc/Action/ProfileDelete.php b/inc/Action/ProfileDelete.php
index 995f81394..89c58edb5 100644
--- a/inc/Action/ProfileDelete.php
+++ b/inc/Action/ProfileDelete.php
@@ -23,7 +23,7 @@ class ProfileDelete extends AbstractUserAction {
public function checkPreconditions() {
parent::checkPreconditions();
- /** @var \DokuWiki_Auth_Plugin $auth */
+ /** @var \dokuwiki\Extension\AuthPlugin $auth */
global $auth;
if(!$auth->canDo('delUser')) throw new ActionDisabledException();
}
diff --git a/inc/Action/Redirect.php b/inc/Action/Redirect.php
index ed67d66d7..dca911a22 100644
--- a/inc/Action/Redirect.php
+++ b/inc/Action/Redirect.php
@@ -3,6 +3,7 @@
namespace dokuwiki\Action;
use dokuwiki\Action\Exception\ActionAbort;
+use dokuwiki\Extension\Event;
/**
* Class Redirect
@@ -41,7 +42,7 @@ class Redirect extends AbstractAliasAction {
}
// execute the redirect
- trigger_event('ACTION_SHOW_REDIRECT', $opts, array($this, 'redirect'));
+ Event::createAndTrigger('ACTION_SHOW_REDIRECT', $opts, array($this, 'redirect'));
// should never be reached
throw new ActionAbort('show');
diff --git a/inc/Action/Register.php b/inc/Action/Register.php
index 0d5415868..7d21bff4a 100644
--- a/inc/Action/Register.php
+++ b/inc/Action/Register.php
@@ -23,7 +23,7 @@ class Register extends AbstractAclAction {
public function checkPreconditions() {
parent::checkPreconditions();
- /** @var \DokuWiki_Auth_Plugin $auth */
+ /** @var \dokuwiki\Extension\AuthPlugin $auth */
global $auth;
global $conf;
if(isset($conf['openregister']) && !$conf['openregister']) throw new ActionDisabledException();
diff --git a/inc/Action/Resendpwd.php b/inc/Action/Resendpwd.php
index 5b5e38194..f3f8d3bad 100644
--- a/inc/Action/Resendpwd.php
+++ b/inc/Action/Resendpwd.php
@@ -23,7 +23,7 @@ class Resendpwd extends AbstractAclAction {
public function checkPreconditions() {
parent::checkPreconditions();
- /** @var \DokuWiki_Auth_Plugin $auth */
+ /** @var \dokuwiki\Extension\AuthPlugin $auth */
global $auth;
global $conf;
if(isset($conf['resendpasswd']) && !$conf['resendpasswd']) throw new ActionDisabledException(); //legacy option
@@ -59,7 +59,7 @@ class Resendpwd extends AbstractAclAction {
protected function resendpwd() {
global $lang;
global $conf;
- /* @var \DokuWiki_Auth_Plugin $auth */
+ /* @var \dokuwiki\Extension\AuthPlugin $auth */
global $auth;
global $INPUT;
diff --git a/inc/Action/Sitemap.php b/inc/Action/Sitemap.php
index 10b1377a0..f0a925cc3 100644
--- a/inc/Action/Sitemap.php
+++ b/inc/Action/Sitemap.php
@@ -32,8 +32,8 @@ class Sitemap extends AbstractAction {
throw new FatalException('Sitemap generation is disabled', 404);
}
- $sitemap = \Sitemapper::getFilePath();
- if(\Sitemapper::sitemapIsCompressed()) {
+ $sitemap = Sitemap::getFilePath();
+ if(Sitemap::sitemapIsCompressed()) {
$mime = 'application/x-gzip';
} else {
$mime = 'application/xml; charset=utf-8';
@@ -41,13 +41,13 @@ class Sitemap extends AbstractAction {
// Check if sitemap file exists, otherwise create it
if(!is_readable($sitemap)) {
- \Sitemapper::generate();
+ Sitemap::generate();
}
if(is_readable($sitemap)) {
// Send headers
header('Content-Type: ' . $mime);
- header('Content-Disposition: attachment; filename=' . utf8_basename($sitemap));
+ header('Content-Disposition: attachment; filename=' . \dokuwiki\Utf8\PhpString::basename($sitemap));
http_conditionalRequest(filemtime($sitemap));
diff --git a/inc/Action/Subscribe.php b/inc/Action/Subscribe.php
index c16571022..a129a8698 100644
--- a/inc/Action/Subscribe.php
+++ b/inc/Action/Subscribe.php
@@ -4,6 +4,8 @@ namespace dokuwiki\Action;
use dokuwiki\Action\Exception\ActionAbort;
use dokuwiki\Action\Exception\ActionDisabledException;
+use dokuwiki\Subscriptions\SubscriberManager;
+use dokuwiki\Extension\Event;
/**
* Class Subscribe
@@ -67,18 +69,18 @@ class Subscribe extends AbstractUserAction {
if(empty($params['action']) || !checkSecurityToken()) return;
// Handle POST data, may throw exception.
- trigger_event('ACTION_HANDLE_SUBSCRIBE', $params, array($this, 'handlePostData'));
+ Event::createAndTrigger('ACTION_HANDLE_SUBSCRIBE', $params, array($this, 'handlePostData'));
$target = $params['target'];
$style = $params['style'];
$action = $params['action'];
// Perform action.
- $sub = new \Subscription();
- if($action == 'unsubscribe') {
- $ok = $sub->remove($target, $INPUT->server->str('REMOTE_USER'), $style);
+ $subManager = new SubscriberManager();
+ if($action === 'unsubscribe') {
+ $ok = $subManager->remove($target, $INPUT->server->str('REMOTE_USER'), $style);
} else {
- $ok = $sub->add($target, $INPUT->server->str('REMOTE_USER'), $style);
+ $ok = $subManager->add($target, $INPUT->server->str('REMOTE_USER'), $style);
}
if($ok) {
@@ -89,15 +91,15 @@ class Subscribe extends AbstractUserAction {
), 1
);
throw new ActionAbort('redirect');
- } else {
- throw new \Exception(
- sprintf(
- $lang["subscr_{$action}_error"],
- hsc($INFO['userinfo']['name']),
- prettyprint_id($target)
- )
- );
}
+
+ throw new \Exception(
+ sprintf(
+ $lang["subscr_{$action}_error"],
+ hsc($INFO['userinfo']['name']),
+ prettyprint_id($target)
+ )
+ );
}
/**
diff --git a/inc/ActionRouter.php b/inc/ActionRouter.php
index edc45cfc4..dfcce3aff 100644
--- a/inc/ActionRouter.php
+++ b/inc/ActionRouter.php
@@ -76,7 +76,7 @@ class ActionRouter {
try {
// give plugins an opportunity to process the actionname
- $evt = new \Doku_Event('ACTION_ACT_PREPROCESS', $actionname);
+ $evt = new Extension\Event('ACTION_ACT_PREPROCESS', $actionname);
if ($evt->advise_before()) {
$this->action = $this->loadAction($actionname);
$this->checkAction($this->action);
diff --git a/inc/Ajax.php b/inc/Ajax.php
index d6a686445..e8cbc84d5 100644
--- a/inc/Ajax.php
+++ b/inc/Ajax.php
@@ -16,11 +16,11 @@ class Ajax {
* @param string $call name of the ajax call
*/
public function __construct($call) {
- $callfn = 'call_' . $call;
+ $callfn = 'call' . ucfirst($call);
if(method_exists($this, $callfn)) {
$this->$callfn();
} else {
- $evt = new \Doku_Event('AJAX_CALL_UNKNOWN', $call);
+ $evt = new Extension\Event('AJAX_CALL_UNKNOWN', $call);
if($evt->advise_before()) {
print "AJAX call '" . hsc($call) . "' unknown!\n";
} else {
@@ -35,7 +35,7 @@ class Ajax {
*
* @author Andreas Gohr <andi@splitbrain.org>
*/
- protected function call_qsearch() {
+ protected function callQsearch() {
global $lang;
global $INPUT;
@@ -82,7 +82,7 @@ class Ajax {
* @link http://www.opensearch.org/Specifications/OpenSearch/Extensions/Suggestions/1.0
* @author Mike Frysinger <vapier@gentoo.org>
*/
- protected function call_suggestions() {
+ protected function callSuggestions() {
global $INPUT;
$query = cleanID($INPUT->post->str('q'));
@@ -107,10 +107,9 @@ class Ajax {
array(), // no description
array() // no urls
);
- $json = new \JSON();
header('Content-Type: application/x-suggestions+json');
- print $json->encode($suggestions);
+ print json_encode($suggestions);
}
/**
@@ -118,7 +117,7 @@ class Ajax {
*
* Andreas Gohr <andi@splitbrain.org>
*/
- protected function call_lock() {
+ protected function callLock() {
global $ID;
global $INFO;
global $INPUT;
@@ -158,7 +157,7 @@ class Ajax {
*
* @author Andreas Gohr <andi@splitbrain.org>
*/
- protected function call_draftdel() {
+ protected function callDraftdel() {
global $INPUT;
$id = cleanID($INPUT->str('id'));
if(empty($id)) return;
@@ -175,7 +174,7 @@ class Ajax {
*
* @author Andreas Gohr <andi@splitbrain.org>
*/
- protected function call_medians() {
+ protected function callMedians() {
global $conf;
global $INPUT;
@@ -198,7 +197,7 @@ class Ajax {
*
* @author Andreas Gohr <andi@splitbrain.org>
*/
- protected function call_medialist() {
+ protected function callMedialist() {
global $NS;
global $INPUT;
@@ -217,7 +216,7 @@ class Ajax {
*
* @author Kate Arzamastseva <pshns@ukr.net>
*/
- protected function call_mediadetails() {
+ protected function callMediadetails() {
global $IMG, $JUMPTO, $REV, $fullscreen, $INPUT;
$fullscreen = true;
require_once(DOKU_INC . 'lib/exe/mediamanager.php');
@@ -238,7 +237,7 @@ class Ajax {
*
* @author Kate Arzamastseva <pshns@ukr.net>
*/
- protected function call_mediadiff() {
+ protected function callMediadiff() {
global $NS;
global $INPUT;
@@ -254,7 +253,7 @@ class Ajax {
*
* @author Kate Arzamastseva <pshns@ukr.net>
*/
- protected function call_mediaupload() {
+ protected function callMediaupload() {
global $NS, $MSG, $INPUT;
$id = '';
@@ -299,9 +298,9 @@ class Ajax {
'ns' => $NS
);
}
- $json = new \JSON;
+
header('Content-Type: application/json');
- echo $json->encode($result);
+ echo json_encode($result);
}
/**
@@ -309,7 +308,7 @@ class Ajax {
*
* @author Andreas Gohr <andi@splitbrain.org>
*/
- protected function call_index() {
+ protected function callIndex() {
global $conf;
global $INPUT;
@@ -332,7 +331,7 @@ class Ajax {
*
* @author Andreas Gohr <gohr@cosmocode.de>
*/
- protected function call_linkwiz() {
+ protected function callLinkwiz() {
global $conf;
global $lang;
global $INPUT;
diff --git a/inc/Cache/Cache.php b/inc/Cache/Cache.php
new file mode 100644
index 000000000..599dc5f59
--- /dev/null
+++ b/inc/Cache/Cache.php
@@ -0,0 +1,237 @@
+<?php
+
+namespace dokuwiki\Cache;
+
+use \dokuwiki\Debug\PropertyDeprecationHelper;
+use dokuwiki\Extension\Event;
+
+/**
+ * Generic handling of caching
+ */
+class Cache
+{
+ use PropertyDeprecationHelper;
+
+ public $key = ''; // primary identifier for this item
+ public $ext = ''; // file ext for cache data, secondary identifier for this item
+ public $cache = ''; // cache file name
+ public $depends = array(); // array containing cache dependency information,
+ // used by makeDefaultCacheDecision to determine cache validity
+
+ // phpcs:disable
+ /**
+ * @deprecated since 2019-02-02 use the respective getters instead!
+ */
+ protected $_event = ''; // event to be triggered during useCache
+ protected $_time;
+ protected $_nocache = false; // if set to true, cache will not be used or stored
+ // phpcs:enable
+
+ /**
+ * @param string $key primary identifier
+ * @param string $ext file extension
+ */
+ public function __construct($key, $ext)
+ {
+ $this->key = $key;
+ $this->ext = $ext;
+ $this->cache = getCacheName($key, $ext);
+
+ /**
+ * @deprecated since 2019-02-02 use the respective getters instead!
+ */
+ $this->deprecatePublicProperty('_event');
+ $this->deprecatePublicProperty('_time');
+ $this->deprecatePublicProperty('_nocache');
+ }
+
+ public function getTime()
+ {
+ return $this->_time;
+ }
+
+ public function getEvent()
+ {
+ return $this->_event;
+ }
+
+ public function setEvent($event)
+ {
+ $this->_event = $event;
+ }
+
+ /**
+ * public method to determine whether the cache can be used
+ *
+ * to assist in centralisation of event triggering and calculation of cache statistics,
+ * don't override this function override makeDefaultCacheDecision()
+ *
+ * @param array $depends array of cache dependencies, support dependecies:
+ * 'age' => max age of the cache in seconds
+ * 'files' => cache must be younger than mtime of each file
+ * (nb. dependency passes if file doesn't exist)
+ *
+ * @return bool true if cache can be used, false otherwise
+ */
+ public function useCache($depends = array())
+ {
+ $this->depends = $depends;
+ $this->addDependencies();
+
+ if ($this->_event) {
+ return $this->stats(Event::createAndTrigger(
+ $this->_event, $this, array($this, 'makeDefaultCacheDecision'))
+ );
+ }
+
+ return $this->stats($this->makeDefaultCacheDecision());
+ }
+
+ /**
+ * internal method containing cache use decision logic
+ *
+ * this function processes the following keys in the depends array
+ * purge - force a purge on any non empty value
+ * age - expire cache if older than age (seconds)
+ * files - expire cache if any file in this array was updated more recently than the cache
+ *
+ * Note that this function needs to be public as it is used as callback for the event handler
+ *
+ * can be overridden
+ *
+ * @internal This method may only be called by the event handler! Call \dokuwiki\Cache\Cache::useCache instead!
+ *
+ * @return bool see useCache()
+ */
+ public function makeDefaultCacheDecision()
+ {
+
+ if ($this->_nocache) {
+ return false;
+ } // caching turned off
+ if (!empty($this->depends['purge'])) {
+ return false;
+ } // purge requested?
+ if (!($this->_time = @filemtime($this->cache))) {
+ return false;
+ } // cache exists?
+
+ // cache too old?
+ if (!empty($this->depends['age']) && ((time() - $this->_time) > $this->depends['age'])) {
+ return false;
+ }
+
+ if (!empty($this->depends['files'])) {
+ foreach ($this->depends['files'] as $file) {
+ if ($this->_time <= @filemtime($file)) {
+ return false;
+ } // cache older than files it depends on?
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * add dependencies to the depends array
+ *
+ * this method should only add dependencies,
+ * it should not remove any existing dependencies and
+ * it should only overwrite a dependency when the new value is more stringent than the old
+ */
+ protected function addDependencies()
+ {
+ global $INPUT;
+ if ($INPUT->has('purge')) {
+ $this->depends['purge'] = true;
+ } // purge requested
+ }
+
+ /**
+ * retrieve the cached data
+ *
+ * @param bool $clean true to clean line endings, false to leave line endings alone
+ * @return string cache contents
+ */
+ public function retrieveCache($clean = true)
+ {
+ return io_readFile($this->cache, $clean);
+ }
+
+ /**
+ * cache $data
+ *
+ * @param string $data the data to be cached
+ * @return bool true on success, false otherwise
+ */
+ public function storeCache($data)
+ {
+ if ($this->_nocache) {
+ return false;
+ }
+
+ return io_savefile($this->cache, $data);
+ }
+
+ /**
+ * remove any cached data associated with this cache instance
+ */
+ public function removeCache()
+ {
+ @unlink($this->cache);
+ }
+
+ /**
+ * Record cache hits statistics.
+ * (Only when debugging allowed, to reduce overhead.)
+ *
+ * @param bool $success result of this cache use attempt
+ * @return bool pass-thru $success value
+ */
+ protected function stats($success)
+ {
+ global $conf;
+ static $stats = null;
+ static $file;
+
+ if (!$conf['allowdebug']) {
+ return $success;
+ }
+
+ if (is_null($stats)) {
+ $file = $conf['cachedir'] . '/cache_stats.txt';
+ $lines = explode("\n", io_readFile($file));
+
+ foreach ($lines as $line) {
+ $i = strpos($line, ',');
+ $stats[substr($line, 0, $i)] = $line;
+ }
+ }
+
+ if (isset($stats[$this->ext])) {
+ list($ext, $count, $hits) = explode(',', $stats[$this->ext]);
+ } else {
+ $ext = $this->ext;
+ $count = 0;
+ $hits = 0;
+ }
+
+ $count++;
+ if ($success) {
+ $hits++;
+ }
+ $stats[$this->ext] = "$ext,$count,$hits";
+
+ io_saveFile($file, join("\n", $stats));
+
+ return $success;
+ }
+
+ /**
+ * @return bool
+ */
+ public function isNoCache()
+ {
+ return $this->_nocache;
+ }
+}
diff --git a/inc/Cache/CacheInstructions.php b/inc/Cache/CacheInstructions.php
new file mode 100644
index 000000000..3c4786105
--- /dev/null
+++ b/inc/Cache/CacheInstructions.php
@@ -0,0 +1,46 @@
+<?php
+
+namespace dokuwiki\Cache;
+
+/**
+ * Caching of parser instructions
+ */
+class CacheInstructions extends \dokuwiki\Cache\CacheParser
+{
+
+ /**
+ * @param string $id page id
+ * @param string $file source file for cache
+ */
+ public function __construct($id, $file)
+ {
+ parent::__construct($id, $file, 'i');
+ }
+
+ /**
+ * retrieve the cached data
+ *
+ * @param bool $clean true to clean line endings, false to leave line endings alone
+ * @return array cache contents
+ */
+ public function retrieveCache($clean = true)
+ {
+ $contents = io_readFile($this->cache, false);
+ return !empty($contents) ? unserialize($contents) : array();
+ }
+
+ /**
+ * cache $instructions
+ *
+ * @param array $instructions the instruction to be cached
+ * @return bool true on success, false otherwise
+ */
+ public function storeCache($instructions)
+ {
+ if ($this->_nocache) {
+ return false;
+ }
+
+ return io_savefile($this->cache, serialize($instructions));
+ }
+}
diff --git a/inc/Cache/CacheParser.php b/inc/Cache/CacheParser.php
new file mode 100644
index 000000000..86453bed5
--- /dev/null
+++ b/inc/Cache/CacheParser.php
@@ -0,0 +1,64 @@
+<?php
+
+namespace dokuwiki\Cache;
+
+/**
+ * Parser caching
+ */
+class CacheParser extends Cache
+{
+
+ public $file = ''; // source file for cache
+ public $mode = ''; // input mode (represents the processing the input file will undergo)
+ public $page = '';
+
+ /**
+ *
+ * @param string $id page id
+ * @param string $file source file for cache
+ * @param string $mode input mode
+ */
+ public function __construct($id, $file, $mode)
+ {
+ if ($id) {
+ $this->page = $id;
+ }
+ $this->file = $file;
+ $this->mode = $mode;
+
+ $this->_event = 'PARSER_CACHE_USE';
+ parent::__construct($file . $_SERVER['HTTP_HOST'] . $_SERVER['SERVER_PORT'], '.' . $mode);
+ }
+
+ /**
+ * method contains cache use decision logic
+ *
+ * @return bool see useCache()
+ */
+ public function makeDefaultCacheDecision()
+ {
+
+ if (!file_exists($this->file)) {
+ return false;
+ } // source exists?
+ return parent::makeDefaultCacheDecision();
+ }
+
+ protected function addDependencies()
+ {
+
+ // parser cache file dependencies ...
+ $files = array(
+ $this->file, // ... source
+ DOKU_INC . 'inc/parser/Parser.php', // ... parser
+ DOKU_INC . 'inc/parser/handler.php', // ... handler
+ );
+ $files = array_merge($files, getConfigFiles('main')); // ... wiki settings
+
+ $this->depends['files'] = !empty($this->depends['files']) ?
+ array_merge($files, $this->depends['files']) :
+ $files;
+ parent::addDependencies();
+ }
+
+}
diff --git a/inc/Cache/CacheRenderer.php b/inc/Cache/CacheRenderer.php
new file mode 100644
index 000000000..e8a28c309
--- /dev/null
+++ b/inc/Cache/CacheRenderer.php
@@ -0,0 +1,94 @@
+<?php
+
+namespace dokuwiki\Cache;
+
+/**
+ * Caching of data of renderer
+ */
+class CacheRenderer extends CacheParser
+{
+
+ /**
+ * method contains cache use decision logic
+ *
+ * @return bool see useCache()
+ */
+ public function makeDefaultCacheDecision()
+ {
+ global $conf;
+
+ if (!parent::makeDefaultCacheDecision()) {
+ return false;
+ }
+
+ if (!isset($this->page)) {
+ return true;
+ }
+
+ // meta cache older than file it depends on?
+ if ($this->_time < @filemtime(metaFN($this->page, '.meta'))) {
+ return false;
+ }
+
+ // check current link existence is consistent with cache version
+ // first check the purgefile
+ // - if the cache is more recent than the purgefile we know no links can have been updated
+ if ($this->_time >= @filemtime($conf['cachedir'] . '/purgefile')) {
+ return true;
+ }
+
+ // for wiki pages, check metadata dependencies
+ $metadata = p_get_metadata($this->page);
+
+ if (!isset($metadata['relation']['references']) ||
+ empty($metadata['relation']['references'])) {
+ return true;
+ }
+
+ foreach ($metadata['relation']['references'] as $id => $exists) {
+ if ($exists != page_exists($id, '', false)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ protected function addDependencies()
+ {
+ global $conf;
+
+ // default renderer cache file 'age' is dependent on 'cachetime' setting, two special values:
+ // -1 : do not cache (should not be overridden)
+ // 0 : cache never expires (can be overridden) - no need to set depends['age']
+ if ($conf['cachetime'] == -1) {
+ $this->_nocache = true;
+ return;
+ } elseif ($conf['cachetime'] > 0) {
+ $this->depends['age'] = isset($this->depends['age']) ?
+ min($this->depends['age'], $conf['cachetime']) : $conf['cachetime'];
+ }
+
+ // renderer cache file dependencies ...
+ $files = array(
+ DOKU_INC . 'inc/parser/' . $this->mode . '.php', // ... the renderer
+ );
+
+ // page implies metadata and possibly some other dependencies
+ if (isset($this->page)) {
+
+ // for xhtml this will render the metadata if needed
+ $valid = p_get_metadata($this->page, 'date valid');
+ if (!empty($valid['age'])) {
+ $this->depends['age'] = isset($this->depends['age']) ?
+ min($this->depends['age'], $valid['age']) : $valid['age'];
+ }
+ }
+
+ $this->depends['files'] = !empty($this->depends['files']) ?
+ array_merge($files, $this->depends['files']) :
+ $files;
+
+ parent::addDependencies();
+ }
+}
diff --git a/inc/ChangeLog/ChangeLog.php b/inc/ChangeLog/ChangeLog.php
new file mode 100644
index 000000000..16b5cc285
--- /dev/null
+++ b/inc/ChangeLog/ChangeLog.php
@@ -0,0 +1,666 @@
+<?php
+
+namespace dokuwiki\ChangeLog;
+
+/**
+ * methods for handling of changelog of pages or media files
+ */
+abstract class ChangeLog
+{
+
+ /** @var string */
+ protected $id;
+ /** @var int */
+ protected $chunk_size;
+ /** @var array */
+ protected $cache;
+
+ /**
+ * Constructor
+ *
+ * @param string $id page id
+ * @param int $chunk_size maximum block size read from file
+ */
+ public function __construct($id, $chunk_size = 8192)
+ {
+ global $cache_revinfo;
+
+ $this->cache =& $cache_revinfo;
+ if (!isset($this->cache[$id])) {
+ $this->cache[$id] = array();
+ }
+
+ $this->id = $id;
+ $this->setChunkSize($chunk_size);
+
+ }
+
+ /**
+ * Set chunk size for file reading
+ * Chunk size zero let read whole file at once
+ *
+ * @param int $chunk_size maximum block size read from file
+ */
+ public function setChunkSize($chunk_size)
+ {
+ if (!is_numeric($chunk_size)) $chunk_size = 0;
+
+ $this->chunk_size = (int)max($chunk_size, 0);
+ }
+
+ /**
+ * Returns path to changelog
+ *
+ * @return string path to file
+ */
+ abstract protected function getChangelogFilename();
+
+ /**
+ * Returns path to current page/media
+ *
+ * @return string path to file
+ */
+ abstract protected function getFilename();
+
+ /**
+ * Get the changelog information for a specific page id and revision (timestamp)
+ *
+ * Adjacent changelog lines are optimistically parsed and cached to speed up
+ * consecutive calls to getRevisionInfo. For large changelog files, only the chunk
+ * containing the requested changelog line is read.
+ *
+ * @param int $rev revision timestamp
+ * @return bool|array false or array with entries:
+ * - date: unix timestamp
+ * - ip: IPv4 address (127.0.0.1)
+ * - type: log line type
+ * - id: page id
+ * - user: user name
+ * - sum: edit summary (or action reason)
+ * - extra: extra data (varies by line type)
+ *
+ * @author Ben Coburn <btcoburn@silicodon.net>
+ * @author Kate Arzamastseva <pshns@ukr.net>
+ */
+ public function getRevisionInfo($rev)
+ {
+ $rev = max($rev, 0);
+
+ // check if it's already in the memory cache
+ if (isset($this->cache[$this->id]) && isset($this->cache[$this->id][$rev])) {
+ return $this->cache[$this->id][$rev];
+ }
+
+ //read lines from changelog
+ list($fp, $lines) = $this->readloglines($rev);
+ if ($fp) {
+ fclose($fp);
+ }
+ if (empty($lines)) return false;
+
+ // parse and cache changelog lines
+ foreach ($lines as $value) {
+ $tmp = parseChangelogLine($value);
+ if ($tmp !== false) {
+ $this->cache[$this->id][$tmp['date']] = $tmp;
+ }
+ }
+ if (!isset($this->cache[$this->id][$rev])) {
+ return false;
+ }
+ return $this->cache[$this->id][$rev];
+ }
+
+ /**
+ * Return a list of page revisions numbers
+ *
+ * Does not guarantee that the revision exists in the attic,
+ * only that a line with the date exists in the changelog.
+ * By default the current revision is skipped.
+ *
+ * The current revision is automatically skipped when the page exists.
+ * See $INFO['meta']['last_change'] for the current revision.
+ * A negative $first let read the current revision too.
+ *
+ * For efficiency, the log lines are parsed and cached for later
+ * calls to getRevisionInfo. Large changelog files are read
+ * backwards in chunks until the requested number of changelog
+ * lines are recieved.
+ *
+ * @param int $first skip the first n changelog lines
+ * @param int $num number of revisions to return
+ * @return array with the revision timestamps
+ *
+ * @author Ben Coburn <btcoburn@silicodon.net>
+ * @author Kate Arzamastseva <pshns@ukr.net>
+ */
+ public function getRevisions($first, $num)
+ {
+ $revs = array();
+ $lines = array();
+ $count = 0;
+
+ $num = max($num, 0);
+ if ($num == 0) {
+ return $revs;
+ }
+
+ if ($first < 0) {
+ $first = 0;
+ } else {
+ if (file_exists($this->getFilename())) {
+ // skip current revision if the page exists
+ $first = max($first + 1, 0);
+ }
+ }
+
+ $file = $this->getChangelogFilename();
+
+ if (!file_exists($file)) {
+ return $revs;
+ }
+ if (filesize($file) < $this->chunk_size || $this->chunk_size == 0) {
+ // read whole file
+ $lines = file($file);
+ if ($lines === false) {
+ return $revs;
+ }
+ } else {
+ // read chunks backwards
+ $fp = fopen($file, 'rb'); // "file pointer"
+ if ($fp === false) {
+ return $revs;
+ }
+ fseek($fp, 0, SEEK_END);
+ $tail = ftell($fp);
+
+ // chunk backwards
+ $finger = max($tail - $this->chunk_size, 0);
+ while ($count < $num + $first) {
+ $nl = $this->getNewlinepointer($fp, $finger);
+
+ // was the chunk big enough? if not, take another bite
+ if ($nl > 0 && $tail <= $nl) {
+ $finger = max($finger - $this->chunk_size, 0);
+ continue;
+ } else {
+ $finger = $nl;
+ }
+
+ // read chunk
+ $chunk = '';
+ $read_size = max($tail - $finger, 0); // found chunk size
+ $got = 0;
+ while ($got < $read_size && !feof($fp)) {
+ $tmp = @fread($fp, max(min($this->chunk_size, $read_size - $got), 0));
+ if ($tmp === false) {
+ break;
+ } //error state
+ $got += strlen($tmp);
+ $chunk .= $tmp;
+ }
+ $tmp = explode("\n", $chunk);
+ array_pop($tmp); // remove trailing newline
+
+ // combine with previous chunk
+ $count += count($tmp);
+ $lines = array_merge($tmp, $lines);
+
+ // next chunk
+ if ($finger == 0) {
+ break;
+ } else { // already read all the lines
+ $tail = $finger;
+ $finger = max($tail - $this->chunk_size, 0);
+ }
+ }
+ fclose($fp);
+ }
+
+ // skip parsing extra lines
+ $num = max(min(count($lines) - $first, $num), 0);
+ if ($first > 0 && $num > 0) {
+ $lines = array_slice($lines, max(count($lines) - $first - $num, 0), $num);
+ } else {
+ if ($first > 0 && $num == 0) {
+ $lines = array_slice($lines, 0, max(count($lines) - $first, 0));
+ } elseif ($first == 0 && $num > 0) {
+ $lines = array_slice($lines, max(count($lines) - $num, 0));
+ }
+ }
+
+ // handle lines in reverse order
+ for ($i = count($lines) - 1; $i >= 0; $i--) {
+ $tmp = parseChangelogLine($lines[$i]);
+ if ($tmp !== false) {
+ $this->cache[$this->id][$tmp['date']] = $tmp;
+ $revs[] = $tmp['date'];
+ }
+ }
+
+ return $revs;
+ }
+
+ /**
+ * Get the nth revision left or right handside for a specific page id and revision (timestamp)
+ *
+ * For large changelog files, only the chunk containing the
+ * reference revision $rev is read and sometimes a next chunck.
+ *
+ * Adjacent changelog lines are optimistically parsed and cached to speed up
+ * consecutive calls to getRevisionInfo.
+ *
+ * @param int $rev revision timestamp used as startdate (doesn't need to be revisionnumber)
+ * @param int $direction give position of returned revision with respect to $rev; positive=next, negative=prev
+ * @return bool|int
+ * timestamp of the requested revision
+ * otherwise false
+ */
+ public function getRelativeRevision($rev, $direction)
+ {
+ $rev = max($rev, 0);
+ $direction = (int)$direction;
+
+ //no direction given or last rev, so no follow-up
+ if (!$direction || ($direction > 0 && $this->isCurrentRevision($rev))) {
+ return false;
+ }
+
+ //get lines from changelog
+ list($fp, $lines, $head, $tail, $eof) = $this->readloglines($rev);
+ if (empty($lines)) return false;
+
+ // look for revisions later/earlier then $rev, when founded count till the wanted revision is reached
+ // also parse and cache changelog lines for getRevisionInfo().
+ $revcounter = 0;
+ $relativerev = false;
+ $checkotherchunck = true; //always runs once
+ while (!$relativerev && $checkotherchunck) {
+ $tmp = array();
+ //parse in normal or reverse order
+ $count = count($lines);
+ if ($direction > 0) {
+ $start = 0;
+ $step = 1;
+ } else {
+ $start = $count - 1;
+ $step = -1;
+ }
+ for ($i = $start; $i >= 0 && $i < $count; $i = $i + $step) {
+ $tmp = parseChangelogLine($lines[$i]);
+ if ($tmp !== false) {
+ $this->cache[$this->id][$tmp['date']] = $tmp;
+ //look for revs older/earlier then reference $rev and select $direction-th one
+ if (($direction > 0 && $tmp['date'] > $rev) || ($direction < 0 && $tmp['date'] < $rev)) {
+ $revcounter++;
+ if ($revcounter == abs($direction)) {
+ $relativerev = $tmp['date'];
+ }
+ }
+ }
+ }
+
+ //true when $rev is found, but not the wanted follow-up.
+ $checkotherchunck = $fp
+ && ($tmp['date'] == $rev || ($revcounter > 0 && !$relativerev))
+ && !(($tail == $eof && $direction > 0) || ($head == 0 && $direction < 0));
+
+ if ($checkotherchunck) {
+ list($lines, $head, $tail) = $this->readAdjacentChunk($fp, $head, $tail, $direction);
+
+ if (empty($lines)) break;
+ }
+ }
+ if ($fp) {
+ fclose($fp);
+ }
+
+ return $relativerev;
+ }
+
+ /**
+ * Returns revisions around rev1 and rev2
+ * When available it returns $max entries for each revision
+ *
+ * @param int $rev1 oldest revision timestamp
+ * @param int $rev2 newest revision timestamp (0 looks up last revision)
+ * @param int $max maximum number of revisions returned
+ * @return array with two arrays with revisions surrounding rev1 respectively rev2
+ */
+ public function getRevisionsAround($rev1, $rev2, $max = 50)
+ {
+ $max = floor(abs($max) / 2) * 2 + 1;
+ $rev1 = max($rev1, 0);
+ $rev2 = max($rev2, 0);
+
+ if ($rev2) {
+ if ($rev2 < $rev1) {
+ $rev = $rev2;
+ $rev2 = $rev1;
+ $rev1 = $rev;
+ }
+ } else {
+ //empty right side means a removed page. Look up last revision.
+ $revs = $this->getRevisions(-1, 1);
+ $rev2 = $revs[0];
+ }
+ //collect revisions around rev2
+ list($revs2, $allrevs, $fp, $lines, $head, $tail) = $this->retrieveRevisionsAround($rev2, $max);
+
+ if (empty($revs2)) return array(array(), array());
+
+ //collect revisions around rev1
+ $index = array_search($rev1, $allrevs);
+ if ($index === false) {
+ //no overlapping revisions
+ list($revs1, , , , ,) = $this->retrieveRevisionsAround($rev1, $max);
+ if (empty($revs1)) $revs1 = array();
+ } else {
+ //revisions overlaps, reuse revisions around rev2
+ $revs1 = $allrevs;
+ while ($head > 0) {
+ for ($i = count($lines) - 1; $i >= 0; $i--) {
+ $tmp = parseChangelogLine($lines[$i]);
+ if ($tmp !== false) {
+ $this->cache[$this->id][$tmp['date']] = $tmp;
+ $revs1[] = $tmp['date'];
+ $index++;
+
+ if ($index > floor($max / 2)) break 2;
+ }
+ }
+
+ list($lines, $head, $tail) = $this->readAdjacentChunk($fp, $head, $tail, -1);
+ }
+ sort($revs1);
+ //return wanted selection
+ $revs1 = array_slice($revs1, max($index - floor($max / 2), 0), $max);
+ }
+
+ return array(array_reverse($revs1), array_reverse($revs2));
+ }
+
+
+ /**
+ * Checks if the ID has old revisons
+ * @return boolean
+ */
+ public function hasRevisions() {
+ $file = $this->getChangelogFilename();
+ return file_exists($file);
+ }
+
+ /**
+ * Returns lines from changelog.
+ * If file larger than $chuncksize, only chunck is read that could contain $rev.
+ *
+ * @param int $rev revision timestamp
+ * @return array|false
+ * if success returns array(fp, array(changeloglines), $head, $tail, $eof)
+ * where fp only defined for chuck reading, needs closing.
+ * otherwise false
+ */
+ protected function readloglines($rev)
+ {
+ $file = $this->getChangelogFilename();
+
+ if (!file_exists($file)) {
+ return false;
+ }
+
+ $fp = null;
+ $head = 0;
+ $tail = 0;
+ $eof = 0;
+
+ if (filesize($file) < $this->chunk_size || $this->chunk_size == 0) {
+ // read whole file
+ $lines = file($file);
+ if ($lines === false) {
+ return false;
+ }
+ } else {
+ // read by chunk
+ $fp = fopen($file, 'rb'); // "file pointer"
+ if ($fp === false) {
+ return false;
+ }
+ $head = 0;
+ fseek($fp, 0, SEEK_END);
+ $eof = ftell($fp);
+ $tail = $eof;
+
+ // find chunk
+ while ($tail - $head > $this->chunk_size) {
+ $finger = $head + floor(($tail - $head) / 2.0);
+ $finger = $this->getNewlinepointer($fp, $finger);
+ $tmp = fgets($fp);
+ if ($finger == $head || $finger == $tail) {
+ break;
+ }
+ $tmp = parseChangelogLine($tmp);
+ $finger_rev = $tmp['date'];
+
+ if ($finger_rev > $rev) {
+ $tail = $finger;
+ } else {
+ $head = $finger;
+ }
+ }
+
+ if ($tail - $head < 1) {
+ // cound not find chunk, assume requested rev is missing
+ fclose($fp);
+ return false;
+ }
+
+ $lines = $this->readChunk($fp, $head, $tail);
+ }
+ return array(
+ $fp,
+ $lines,
+ $head,
+ $tail,
+ $eof,
+ );
+ }
+
+ /**
+ * Read chunk and return array with lines of given chunck.
+ * Has no check if $head and $tail are really at a new line
+ *
+ * @param resource $fp resource filepointer
+ * @param int $head start point chunck
+ * @param int $tail end point chunck
+ * @return array lines read from chunck
+ */
+ protected function readChunk($fp, $head, $tail)
+ {
+ $chunk = '';
+ $chunk_size = max($tail - $head, 0); // found chunk size
+ $got = 0;
+ fseek($fp, $head);
+ while ($got < $chunk_size && !feof($fp)) {
+ $tmp = @fread($fp, max(min($this->chunk_size, $chunk_size - $got), 0));
+ if ($tmp === false) { //error state
+ break;
+ }
+ $got += strlen($tmp);
+ $chunk .= $tmp;
+ }
+ $lines = explode("\n", $chunk);
+ array_pop($lines); // remove trailing newline
+ return $lines;
+ }
+
+ /**
+ * Set pointer to first new line after $finger and return its position
+ *
+ * @param resource $fp filepointer
+ * @param int $finger a pointer
+ * @return int pointer
+ */
+ protected function getNewlinepointer($fp, $finger)
+ {
+ fseek($fp, $finger);
+ $nl = $finger;
+ if ($finger > 0) {
+ fgets($fp); // slip the finger forward to a new line
+ $nl = ftell($fp);
+ }
+ return $nl;
+ }
+
+ /**
+ * Check whether given revision is the current page
+ *
+ * @param int $rev timestamp of current page
+ * @return bool true if $rev is current revision, otherwise false
+ */
+ public function isCurrentRevision($rev)
+ {
+ return $rev == @filemtime($this->getFilename());
+ }
+
+ /**
+ * Return an existing revision for a specific date which is
+ * the current one or younger or equal then the date
+ *
+ * @param number $date_at timestamp
+ * @return string revision ('' for current)
+ */
+ public function getLastRevisionAt($date_at)
+ {
+ //requested date_at(timestamp) younger or equal then modified_time($this->id) => load current
+ if (file_exists($this->getFilename()) && $date_at >= @filemtime($this->getFilename())) {
+ return '';
+ } else {
+ if ($rev = $this->getRelativeRevision($date_at + 1, -1)) { //+1 to get also the requested date revision
+ return $rev;
+ } else {
+ return false;
+ }
+ }
+ }
+
+ /**
+ * Returns the next lines of the changelog of the chunck before head or after tail
+ *
+ * @param resource $fp filepointer
+ * @param int $head position head of last chunk
+ * @param int $tail position tail of last chunk
+ * @param int $direction positive forward, negative backward
+ * @return array with entries:
+ * - $lines: changelog lines of readed chunk
+ * - $head: head of chunk
+ * - $tail: tail of chunk
+ */
+ protected function readAdjacentChunk($fp, $head, $tail, $direction)
+ {
+ if (!$fp) return array(array(), $head, $tail);
+
+ if ($direction > 0) {
+ //read forward
+ $head = $tail;
+ $tail = $head + floor($this->chunk_size * (2 / 3));
+ $tail = $this->getNewlinepointer($fp, $tail);
+ } else {
+ //read backward
+ $tail = $head;
+ $head = max($tail - $this->chunk_size, 0);
+ while (true) {
+ $nl = $this->getNewlinepointer($fp, $head);
+ // was the chunk big enough? if not, take another bite
+ if ($nl > 0 && $tail <= $nl) {
+ $head = max($head - $this->chunk_size, 0);
+ } else {
+ $head = $nl;
+ break;
+ }
+ }
+ }
+
+ //load next chunck
+ $lines = $this->readChunk($fp, $head, $tail);
+ return array($lines, $head, $tail);
+ }
+
+ /**
+ * Collect the $max revisions near to the timestamp $rev
+ *
+ * @param int $rev revision timestamp
+ * @param int $max maximum number of revisions to be returned
+ * @return bool|array
+ * return array with entries:
+ * - $requestedrevs: array of with $max revision timestamps
+ * - $revs: all parsed revision timestamps
+ * - $fp: filepointer only defined for chuck reading, needs closing.
+ * - $lines: non-parsed changelog lines before the parsed revisions
+ * - $head: position of first readed changelogline
+ * - $lasttail: position of end of last readed changelogline
+ * otherwise false
+ */
+ protected function retrieveRevisionsAround($rev, $max)
+ {
+ //get lines from changelog
+ list($fp, $lines, $starthead, $starttail, /* $eof */) = $this->readloglines($rev);
+ if (empty($lines)) return false;
+
+ //parse chunk containing $rev, and read forward more chunks until $max/2 is reached
+ $head = $starthead;
+ $tail = $starttail;
+ $revs = array();
+ $aftercount = $beforecount = 0;
+ while (count($lines) > 0) {
+ foreach ($lines as $line) {
+ $tmp = parseChangelogLine($line);
+ if ($tmp !== false) {
+ $this->cache[$this->id][$tmp['date']] = $tmp;
+ $revs[] = $tmp['date'];
+ if ($tmp['date'] >= $rev) {
+ //count revs after reference $rev
+ $aftercount++;
+ if ($aftercount == 1) $beforecount = count($revs);
+ }
+ //enough revs after reference $rev?
+ if ($aftercount > floor($max / 2)) break 2;
+ }
+ }
+ //retrieve next chunk
+ list($lines, $head, $tail) = $this->readAdjacentChunk($fp, $head, $tail, 1);
+ }
+ if ($aftercount == 0) return false;
+
+ $lasttail = $tail;
+
+ //read additional chuncks backward until $max/2 is reached and total number of revs is equal to $max
+ $lines = array();
+ $i = 0;
+ if ($aftercount > 0) {
+ $head = $starthead;
+ $tail = $starttail;
+ while ($head > 0) {
+ list($lines, $head, $tail) = $this->readAdjacentChunk($fp, $head, $tail, -1);
+
+ for ($i = count($lines) - 1; $i >= 0; $i--) {
+ $tmp = parseChangelogLine($lines[$i]);
+ if ($tmp !== false) {
+ $this->cache[$this->id][$tmp['date']] = $tmp;
+ $revs[] = $tmp['date'];
+ $beforecount++;
+ //enough revs before reference $rev?
+ if ($beforecount > max(floor($max / 2), $max - $aftercount)) break 2;
+ }
+ }
+ }
+ }
+ sort($revs);
+
+ //keep only non-parsed lines
+ $lines = array_slice($lines, 0, $i);
+ //trunk desired selection
+ $requestedrevs = array_slice($revs, -$max, $max);
+
+ return array($requestedrevs, $revs, $fp, $lines, $head, $lasttail);
+ }
+}
diff --git a/inc/ChangeLog/MediaChangeLog.php b/inc/ChangeLog/MediaChangeLog.php
new file mode 100644
index 000000000..0d7d8d390
--- /dev/null
+++ b/inc/ChangeLog/MediaChangeLog.php
@@ -0,0 +1,30 @@
+<?php
+
+namespace dokuwiki\ChangeLog;
+
+/**
+ * handles changelog of a media file
+ */
+class MediaChangeLog extends ChangeLog
+{
+
+ /**
+ * Returns path to changelog
+ *
+ * @return string path to file
+ */
+ protected function getChangelogFilename()
+ {
+ return mediaMetaFN($this->id, '.changes');
+ }
+
+ /**
+ * Returns path to current page/media
+ *
+ * @return string path to file
+ */
+ protected function getFilename()
+ {
+ return mediaFN($this->id);
+ }
+}
diff --git a/inc/ChangeLog/PageChangeLog.php b/inc/ChangeLog/PageChangeLog.php
new file mode 100644
index 000000000..f1b91dee6
--- /dev/null
+++ b/inc/ChangeLog/PageChangeLog.php
@@ -0,0 +1,30 @@
+<?php
+
+namespace dokuwiki\ChangeLog;
+
+/**
+ * handles changelog of a wiki page
+ */
+class PageChangeLog extends ChangeLog
+{
+
+ /**
+ * Returns path to changelog
+ *
+ * @return string path to file
+ */
+ protected function getChangelogFilename()
+ {
+ return metaFN($this->id, '.changes');
+ }
+
+ /**
+ * Returns path to current page/media
+ *
+ * @return string path to file
+ */
+ protected function getFilename()
+ {
+ return wikiFN($this->id);
+ }
+}
diff --git a/inc/Debug/DebugHelper.php b/inc/Debug/DebugHelper.php
new file mode 100644
index 000000000..3d4b20d62
--- /dev/null
+++ b/inc/Debug/DebugHelper.php
@@ -0,0 +1,121 @@
+<?php
+
+
+namespace dokuwiki\Debug;
+
+use Doku_Event;
+use dokuwiki\Extension\EventHandler;
+
+class DebugHelper
+{
+ const INFO_DEPRECATION_LOG_EVENT = 'INFO_DEPRECATION_LOG';
+
+ /**
+ * Log accesses to deprecated fucntions to the debug log
+ *
+ * @param string $alternative (optional) The function or method that should be used instead
+ * @param int $callerOffset (optional) How far the deprecated method is removed from this one
+ *
+ * @triggers \dokuwiki\Debug::INFO_DEPRECATION_LOG_EVENT
+ */
+ public static function dbgDeprecatedFunction($alternative = '', $callerOffset = 1)
+ {
+ global $conf;
+ /** @var EventHandler $EVENT_HANDLER */
+ global $EVENT_HANDLER;
+ if (
+ !$conf['allowdebug'] &&
+ ($EVENT_HANDLER === null || !$EVENT_HANDLER->hasHandlerForEvent('INFO_DEPRECATION_LOG'))
+ ){
+ // avoid any work if no one cares
+ return;
+ }
+
+ $backtrace = debug_backtrace();
+ for ($i = 0; $i < $callerOffset; $i += 1) {
+ array_shift($backtrace);
+ }
+
+ list($self, $call) = $backtrace;
+
+ self::triggerDeprecationEvent(
+ $backtrace,
+ $alternative,
+ trim($self['class'] . '::' . $self['function'] . '()', ':'),
+ trim($call['class'] . '::' . $call['function'] . '()', ':'),
+ $call['file'],
+ $call['line']
+ );
+ }
+
+ /**
+ * This marks logs a deprecation warning for a property that should no longer be used
+ *
+ * This is usually called withing a magic getter or setter.
+ * For logging deprecated functions or methods see dbgDeprecatedFunction()
+ *
+ * @param string $class The class with the deprecated property
+ * @param string $propertyName The name of the deprecated property
+ *
+ * @triggers \dokuwiki\Debug::INFO_DEPRECATION_LOG_EVENT
+ */
+ public static function dbgDeprecatedProperty($class, $propertyName)
+ {
+ global $conf;
+ global $EVENT_HANDLER;
+ if (!$conf['allowdebug'] && !$EVENT_HANDLER->hasHandlerForEvent(self::INFO_DEPRECATION_LOG_EVENT)) {
+ // avoid any work if no one cares
+ return;
+ }
+
+ $backtrace = debug_backtrace();
+ array_shift($backtrace);
+ $call = $backtrace[1];
+ $caller = trim($call['class'] . '::' . $call['function'] . '()', ':');
+ $qualifiedName = $class . '::$' . $propertyName;
+ self::triggerDeprecationEvent(
+ $backtrace,
+ '',
+ $qualifiedName,
+ $caller,
+ $backtrace[0]['file'],
+ $backtrace[0]['line']
+ );
+ }
+
+ /**
+ * @param array $backtrace
+ * @param string $alternative
+ * @param string $deprecatedThing
+ * @param string $caller
+ * @param string $file
+ * @param int $line
+ */
+ private static function triggerDeprecationEvent(
+ array $backtrace,
+ $alternative,
+ $deprecatedThing,
+ $caller,
+ $file,
+ $line
+ ) {
+ $data = [
+ 'trace' => $backtrace,
+ 'alternative' => $alternative,
+ 'called' => $deprecatedThing,
+ 'caller' => $caller,
+ 'file' => $file,
+ 'line' => $line,
+ ];
+ $event = new Doku_Event(self::INFO_DEPRECATION_LOG_EVENT, $data);
+ if ($event->advise_before()) {
+ $msg = $event->data['called'] . ' is deprecated. It was called from ';
+ $msg .= $event->data['caller'] . ' in ' . $event->data['file'] . ':' . $event->data['line'];
+ if ($event->data['alternative']) {
+ $msg .= ' ' . $event->data['alternative'] . ' should be used instead!';
+ }
+ dbglog($msg);
+ }
+ $event->advise_after();
+ }
+}
diff --git a/inc/Debug/PropertyDeprecationHelper.php b/inc/Debug/PropertyDeprecationHelper.php
new file mode 100644
index 000000000..6289d5ba8
--- /dev/null
+++ b/inc/Debug/PropertyDeprecationHelper.php
@@ -0,0 +1,134 @@
+<?php
+/**
+ * Trait for issuing warnings on deprecated access.
+ *
+ * Adapted from https://github.com/wikimedia/mediawiki/blob/4aedefdbfd193f323097354bf581de1c93f02715/includes/debug/DeprecationHelper.php
+ *
+ */
+
+
+namespace dokuwiki\Debug;
+
+/**
+ * Use this trait in classes which have properties for which public access
+ * is deprecated. Set the list of properties in $deprecatedPublicProperties
+ * and make the properties non-public. The trait will preserve public access
+ * but issue deprecation warnings when it is needed.
+ *
+ * Example usage:
+ * class Foo {
+ * use DeprecationHelper;
+ * protected $bar;
+ * public function __construct() {
+ * $this->deprecatePublicProperty( 'bar', '1.21', __CLASS__ );
+ * }
+ * }
+ *
+ * $foo = new Foo;
+ * $foo->bar; // works but logs a warning
+ *
+ * Cannot be used with classes that have their own __get/__set methods.
+ *
+ */
+trait PropertyDeprecationHelper
+{
+
+ /**
+ * List of deprecated properties, in <property name> => <class> format
+ * where <class> is the the name of the class defining the property
+ *
+ * E.g. [ '_event' => '\dokuwiki\Cache\Cache' ]
+ * @var string[]
+ */
+ protected $deprecatedPublicProperties = [];
+
+ /**
+ * Mark a property as deprecated. Only use this for properties that used to be public and only
+ * call it in the constructor.
+ *
+ * @param string $property The name of the property.
+ * @param null $class name of the class defining the property
+ * @see DebugHelper::dbgDeprecatedProperty
+ */
+ protected function deprecatePublicProperty(
+ $property,
+ $class = null
+ ) {
+ $this->deprecatedPublicProperties[$property] = $class ?: get_class();
+ }
+
+ public function __get($name)
+ {
+ if (isset($this->deprecatedPublicProperties[$name])) {
+ $class = $this->deprecatedPublicProperties[$name];
+ DebugHelper::dbgDeprecatedProperty($class, $name);
+ return $this->$name;
+ }
+
+ $qualifiedName = get_class() . '::$' . $name;
+ if ($this->deprecationHelperGetPropertyOwner($name)) {
+ // Someone tried to access a normal non-public property. Try to behave like PHP would.
+ trigger_error("Cannot access non-public property $qualifiedName", E_USER_ERROR);
+ } else {
+ // Non-existing property. Try to behave like PHP would.
+ trigger_error("Undefined property: $qualifiedName", E_USER_NOTICE);
+ }
+ return null;
+ }
+
+ public function __set($name, $value)
+ {
+ if (isset($this->deprecatedPublicProperties[$name])) {
+ $class = $this->deprecatedPublicProperties[$name];
+ DebugHelper::dbgDeprecatedProperty($class, $name);
+ $this->$name = $value;
+ return;
+ }
+
+ $qualifiedName = get_class() . '::$' . $name;
+ if ($this->deprecationHelperGetPropertyOwner($name)) {
+ // Someone tried to access a normal non-public property. Try to behave like PHP would.
+ trigger_error("Cannot access non-public property $qualifiedName", E_USER_ERROR);
+ } else {
+ // Non-existing property. Try to behave like PHP would.
+ $this->$name = $value;
+ }
+ }
+
+ /**
+ * Like property_exists but also check for non-visible private properties and returns which
+ * class in the inheritance chain declared the property.
+ * @param string $property
+ * @return string|bool Best guess for the class in which the property is defined.
+ */
+ private function deprecationHelperGetPropertyOwner($property)
+ {
+ // Easy branch: check for protected property / private property of the current class.
+ if (property_exists($this, $property)) {
+ // The class name is not necessarily correct here but getting the correct class
+ // name would be expensive, this will work most of the time and getting it
+ // wrong is not a big deal.
+ return __CLASS__;
+ }
+ // property_exists() returns false when the property does exist but is private (and not
+ // defined by the current class, for some value of "current" that differs slightly
+ // between engines).
+ // Since PHP triggers an error on public access of non-public properties but happily
+ // allows public access to undefined properties, we need to detect this case as well.
+ // Reflection is slow so use array cast hack to check for that:
+ $obfuscatedProps = array_keys((array)$this);
+ $obfuscatedPropTail = "\0$property";
+ foreach ($obfuscatedProps as $obfuscatedProp) {
+ // private props are in the form \0<classname>\0<propname>
+ if (strpos($obfuscatedProp, $obfuscatedPropTail, 1) !== false) {
+ $classname = substr($obfuscatedProp, 1, -strlen($obfuscatedPropTail));
+ if ($classname === '*') {
+ // sanity; this shouldn't be possible as protected properties were handled earlier
+ $classname = __CLASS__;
+ }
+ return $classname;
+ }
+ }
+ return false;
+ }
+}
diff --git a/inc/Draft.php b/inc/Draft.php
index 7c3109bab..f80016c8d 100644
--- a/inc/Draft.php
+++ b/inc/Draft.php
@@ -86,7 +86,7 @@ class Draft
'cname' => $this->cname,
'errors' => [],
];
- $event = new \Doku_Event('DRAFT_SAVE', $draft);
+ $event = new Extension\Event('DRAFT_SAVE', $draft);
if ($event->advise_before()) {
$draft['hasBeenSaved'] = io_saveFile($draft['cname'], serialize($draft));
if ($draft['hasBeenSaved']) {
diff --git a/inc/Extension/ActionPlugin.php b/inc/Extension/ActionPlugin.php
new file mode 100644
index 000000000..ed6d82038
--- /dev/null
+++ b/inc/Extension/ActionPlugin.php
@@ -0,0 +1,22 @@
+<?php
+
+namespace dokuwiki\Extension;
+
+/**
+ * Action Plugin Prototype
+ *
+ * Handles action hooks within a plugin
+ *
+ * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ * @author Christopher Smith <chris@jalakai.co.uk>
+ */
+abstract class ActionPlugin extends Plugin
+{
+
+ /**
+ * Registers a callback function for a given event
+ *
+ * @param \Doku_Event_Handler $controller
+ */
+ abstract public function register(\Doku_Event_Handler $controller);
+}
diff --git a/inc/Extension/AdminPlugin.php b/inc/Extension/AdminPlugin.php
new file mode 100644
index 000000000..7900a1ec4
--- /dev/null
+++ b/inc/Extension/AdminPlugin.php
@@ -0,0 +1,123 @@
+<?php
+
+namespace dokuwiki\Extension;
+
+/**
+ * Admin Plugin Prototype
+ *
+ * Implements an admin interface in a plugin
+ *
+ * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ * @author Christopher Smith <chris@jalakai.co.uk>
+ */
+abstract class AdminPlugin extends Plugin
+{
+
+ /**
+ * Return the text that is displayed at the main admin menu
+ * (Default localized language string 'menu' is returned, override this function for setting another name)
+ *
+ * @param string $language language code
+ * @return string menu string
+ */
+ public function getMenuText($language)
+ {
+ $menutext = $this->getLang('menu');
+ if (!$menutext) {
+ $info = $this->getInfo();
+ $menutext = $info['name'] . ' ...';
+ }
+ return $menutext;
+ }
+
+ /**
+ * Return the path to the icon being displayed in the main admin menu.
+ * By default it tries to find an 'admin.svg' file in the plugin directory.
+ * (Override this function for setting another image)
+ *
+ * Important: you have to return a single path, monochrome SVG icon! It has to be
+ * under 2 Kilobytes!
+ *
+ * We recommend icons from https://materialdesignicons.com/ or to use a matching
+ * style.
+ *
+ * @return string full path to the icon file
+ */
+ public function getMenuIcon()
+ {
+ $plugin = $this->getPluginName();
+ return DOKU_PLUGIN . $plugin . '/admin.svg';
+ }
+
+ /**
+ * Determine position in list in admin window
+ * Lower values are sorted up
+ *
+ * @return int
+ */
+ public function getMenuSort()
+ {
+ return 1000;
+ }
+
+ /**
+ * Carry out required processing
+ */
+ public function handle()
+ {
+ // some plugins might not need this
+ }
+
+ /**
+ * Output html of the admin page
+ */
+ abstract public function html();
+
+ /**
+ * Checks if access should be granted to this admin plugin
+ *
+ * @return bool true if the current user may access this admin plugin
+ */
+ public function isAccessibleByCurrentUser() {
+ $data = [];
+ $data['instance'] = $this;
+ $data['hasAccess'] = false;
+
+ $event = new Event('ADMINPLUGIN_ACCESS_CHECK', $data);
+ if($event->advise_before()) {
+ if ($this->forAdminOnly()) {
+ $data['hasAccess'] = auth_isadmin();
+ } else {
+ $data['hasAccess'] = auth_ismanager();
+ }
+ }
+ $event->advise_after();
+
+ return $data['hasAccess'];
+ }
+
+ /**
+ * Return true for access only by admins (config:superuser) or false if managers are allowed as well
+ *
+ * @return bool
+ */
+ public function forAdminOnly()
+ {
+ return true;
+ }
+
+ /**
+ * Return array with ToC items. Items can be created with the html_mktocitem()
+ *
+ * @see html_mktocitem()
+ * @see tpl_toc()
+ *
+ * @return array
+ */
+ public function getTOC()
+ {
+ return array();
+ }
+
+}
+
diff --git a/inc/Extension/AuthPlugin.php b/inc/Extension/AuthPlugin.php
new file mode 100644
index 000000000..2123e1320
--- /dev/null
+++ b/inc/Extension/AuthPlugin.php
@@ -0,0 +1,458 @@
+<?php
+
+namespace dokuwiki\Extension;
+
+/**
+ * Auth Plugin Prototype
+ *
+ * allows to authenticate users in a plugin
+ *
+ * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ * @author Chris Smith <chris@jalakai.co.uk>
+ * @author Jan Schumann <js@jschumann-it.com>
+ */
+abstract class AuthPlugin extends Plugin
+{
+ public $success = true;
+
+ /**
+ * Possible things an auth backend module may be able to
+ * do. The things a backend can do need to be set to true
+ * in the constructor.
+ */
+ protected $cando = array(
+ 'addUser' => false, // can Users be created?
+ 'delUser' => false, // can Users be deleted?
+ 'modLogin' => false, // can login names be changed?
+ 'modPass' => false, // can passwords be changed?
+ 'modName' => false, // can real names be changed?
+ 'modMail' => false, // can emails be changed?
+ 'modGroups' => false, // can groups be changed?
+ 'getUsers' => false, // can a (filtered) list of users be retrieved?
+ 'getUserCount' => false, // can the number of users be retrieved?
+ 'getGroups' => false, // can a list of available groups be retrieved?
+ 'external' => false, // does the module do external auth checking?
+ 'logout' => true, // can the user logout again? (eg. not possible with HTTP auth)
+ );
+
+ /**
+ * Constructor.
+ *
+ * Carry out sanity checks to ensure the object is
+ * able to operate. Set capabilities in $this->cando
+ * array here
+ *
+ * For future compatibility, sub classes should always include a call
+ * to parent::__constructor() in their constructors!
+ *
+ * Set $this->success to false if checks fail
+ *
+ * @author Christopher Smith <chris@jalakai.co.uk>
+ */
+ public function __construct()
+ {
+ // the base class constructor does nothing, derived class
+ // constructors do the real work
+ }
+
+ /**
+ * Available Capabilities. [ DO NOT OVERRIDE ]
+ *
+ * For introspection/debugging
+ *
+ * @author Christopher Smith <chris@jalakai.co.uk>
+ * @return array
+ */
+ public function getCapabilities()
+ {
+ return array_keys($this->cando);
+ }
+
+ /**
+ * Capability check. [ DO NOT OVERRIDE ]
+ *
+ * Checks the capabilities set in the $this->cando array and
+ * some pseudo capabilities (shortcutting access to multiple
+ * ones)
+ *
+ * ususal capabilities start with lowercase letter
+ * shortcut capabilities start with uppercase letter
+ *
+ * @author Andreas Gohr <andi@splitbrain.org>
+ * @param string $cap the capability to check
+ * @return bool
+ */
+ public function canDo($cap)
+ {
+ switch ($cap) {
+ case 'Profile':
+ // can at least one of the user's properties be changed?
+ return ($this->cando['modPass'] ||
+ $this->cando['modName'] ||
+ $this->cando['modMail']);
+ break;
+ case 'UserMod':
+ // can at least anything be changed?
+ return ($this->cando['modPass'] ||
+ $this->cando['modName'] ||
+ $this->cando['modMail'] ||
+ $this->cando['modLogin'] ||
+ $this->cando['modGroups'] ||
+ $this->cando['modMail']);
+ break;
+ default:
+ // print a helping message for developers
+ if (!isset($this->cando[$cap])) {
+ msg("Check for unknown capability '$cap' - Do you use an outdated Plugin?", -1);
+ }
+ return $this->cando[$cap];
+ }
+ }
+
+ /**
+ * Trigger the AUTH_USERDATA_CHANGE event and call the modification function. [ DO NOT OVERRIDE ]
+ *
+ * You should use this function instead of calling createUser, modifyUser or
+ * deleteUsers directly. The event handlers can prevent the modification, for
+ * example for enforcing a user name schema.
+ *
+ * @author Gabriel Birke <birke@d-scribe.de>
+ * @param string $type Modification type ('create', 'modify', 'delete')
+ * @param array $params Parameters for the createUser, modifyUser or deleteUsers method.
+ * The content of this array depends on the modification type
+ * @return bool|null|int Result from the modification function or false if an event handler has canceled the action
+ */
+ public function triggerUserMod($type, $params)
+ {
+ $validTypes = array(
+ 'create' => 'createUser',
+ 'modify' => 'modifyUser',
+ 'delete' => 'deleteUsers',
+ );
+ if (empty($validTypes[$type])) {
+ return false;
+ }
+
+ $result = false;
+ $eventdata = array('type' => $type, 'params' => $params, 'modification_result' => null);
+ $evt = new Event('AUTH_USER_CHANGE', $eventdata);
+ if ($evt->advise_before(true)) {
+ $result = call_user_func_array(array($this, $validTypes[$type]), $evt->data['params']);
+ $evt->data['modification_result'] = $result;
+ }
+ $evt->advise_after();
+ unset($evt);
+ return $result;
+ }
+
+ /**
+ * Log off the current user [ OPTIONAL ]
+ *
+ * Is run in addition to the ususal logoff method. Should
+ * only be needed when trustExternal is implemented.
+ *
+ * @see auth_logoff()
+ * @author Andreas Gohr <andi@splitbrain.org>
+ */
+ public function logOff()
+ {
+ }
+
+ /**
+ * Do all authentication [ OPTIONAL ]
+ *
+ * Set $this->cando['external'] = true when implemented
+ *
+ * If this function is implemented it will be used to
+ * authenticate a user - all other DokuWiki internals
+ * will not be used for authenticating, thus
+ * implementing the checkPass() function is not needed
+ * anymore.
+ *
+ * The function can be used to authenticate against third
+ * party cookies or Apache auth mechanisms and replaces
+ * the auth_login() function
+ *
+ * The function will be called with or without a set
+ * username. If the Username is given it was called
+ * from the login form and the given credentials might
+ * need to be checked. If no username was given it
+ * the function needs to check if the user is logged in
+ * by other means (cookie, environment).
+ *
+ * The function needs to set some globals needed by
+ * DokuWiki like auth_login() does.
+ *
+ * @see auth_login()
+ * @author Andreas Gohr <andi@splitbrain.org>
+ *
+ * @param string $user Username
+ * @param string $pass Cleartext Password
+ * @param bool $sticky Cookie should not expire
+ * @return bool true on successful auth
+ */
+ public function trustExternal($user, $pass, $sticky = false)
+ {
+ /* some example:
+
+ global $USERINFO;
+ global $conf;
+ $sticky ? $sticky = true : $sticky = false; //sanity check
+
+ // do the checking here
+
+ // set the globals if authed
+ $USERINFO['name'] = 'FIXME';
+ $USERINFO['mail'] = 'FIXME';
+ $USERINFO['grps'] = array('FIXME');
+ $_SERVER['REMOTE_USER'] = $user;
+ $_SESSION[DOKU_COOKIE]['auth']['user'] = $user;
+ $_SESSION[DOKU_COOKIE]['auth']['pass'] = $pass;
+ $_SESSION[DOKU_COOKIE]['auth']['info'] = $USERINFO;
+ return true;
+
+ */
+ }
+
+ /**
+ * Check user+password [ MUST BE OVERRIDDEN ]
+ *
+ * Checks if the given user exists and the given
+ * plaintext password is correct
+ *
+ * May be ommited if trustExternal is used.
+ *
+ * @author Andreas Gohr <andi@splitbrain.org>
+ * @param string $user the user name
+ * @param string $pass the clear text password
+ * @return bool
+ */
+ public function checkPass($user, $pass)
+ {
+ msg("no valid authorisation system in use", -1);
+ return false;
+ }
+
+ /**
+ * Return user info [ MUST BE OVERRIDDEN ]
+ *
+ * Returns info about the given user needs to contain
+ * at least these fields:
+ *
+ * name string full name of the user
+ * mail string email address of the user
+ * grps array list of groups the user is in
+ *
+ * @author Andreas Gohr <andi@splitbrain.org>
+ * @param string $user the user name
+ * @param bool $requireGroups whether or not the returned data must include groups
+ * @return false|array containing user data or false
+ */
+ public function getUserData($user, $requireGroups = true)
+ {
+ if (!$this->cando['external']) msg("no valid authorisation system in use", -1);
+ return false;
+ }
+
+ /**
+ * Create a new User [implement only where required/possible]
+ *
+ * Returns false if the user already exists, null when an error
+ * occurred and true if everything went well.
+ *
+ * The new user HAS TO be added to the default group by this
+ * function!
+ *
+ * Set addUser capability when implemented
+ *
+ * @author Andreas Gohr <andi@splitbrain.org>
+ * @param string $user
+ * @param string $pass
+ * @param string $name
+ * @param string $mail
+ * @param null|array $grps
+ * @return bool|null
+ */
+ public function createUser($user, $pass, $name, $mail, $grps = null)
+ {
+ msg("authorisation method does not allow creation of new users", -1);
+ return null;
+ }
+
+ /**
+ * Modify user data [implement only where required/possible]
+ *
+ * Set the mod* capabilities according to the implemented features
+ *
+ * @author Chris Smith <chris@jalakai.co.uk>
+ * @param string $user nick of the user to be changed
+ * @param array $changes array of field/value pairs to be changed (password will be clear text)
+ * @return bool
+ */
+ public function modifyUser($user, $changes)
+ {
+ msg("authorisation method does not allow modifying of user data", -1);
+ return false;
+ }
+
+ /**
+ * Delete one or more users [implement only where required/possible]
+ *
+ * Set delUser capability when implemented
+ *
+ * @author Chris Smith <chris@jalakai.co.uk>
+ * @param array $users
+ * @return int number of users deleted
+ */
+ public function deleteUsers($users)
+ {
+ msg("authorisation method does not allow deleting of users", -1);
+ return 0;
+ }
+
+ /**
+ * Return a count of the number of user which meet $filter criteria
+ * [should be implemented whenever retrieveUsers is implemented]
+ *
+ * Set getUserCount capability when implemented
+ *
+ * @author Chris Smith <chris@jalakai.co.uk>
+ * @param array $filter array of field/pattern pairs, empty array for no filter
+ * @return int
+ */
+ public function getUserCount($filter = array())
+ {
+ msg("authorisation method does not provide user counts", -1);
+ return 0;
+ }
+
+ /**
+ * Bulk retrieval of user data [implement only where required/possible]
+ *
+ * Set getUsers capability when implemented
+ *
+ * @author Chris Smith <chris@jalakai.co.uk>
+ * @param int $start index of first user to be returned
+ * @param int $limit max number of users to be returned, 0 for unlimited
+ * @param array $filter array of field/pattern pairs, null for no filter
+ * @return array list of userinfo (refer getUserData for internal userinfo details)
+ */
+ public function retrieveUsers($start = 0, $limit = 0, $filter = null)
+ {
+ msg("authorisation method does not support mass retrieval of user data", -1);
+ return array();
+ }
+
+ /**
+ * Define a group [implement only where required/possible]
+ *
+ * Set addGroup capability when implemented
+ *
+ * @author Chris Smith <chris@jalakai.co.uk>
+ * @param string $group
+ * @return bool
+ */
+ public function addGroup($group)
+ {
+ msg("authorisation method does not support independent group creation", -1);
+ return false;
+ }
+
+ /**
+ * Retrieve groups [implement only where required/possible]
+ *
+ * Set getGroups capability when implemented
+ *
+ * @author Chris Smith <chris@jalakai.co.uk>
+ * @param int $start
+ * @param int $limit
+ * @return array
+ */
+ public function retrieveGroups($start = 0, $limit = 0)
+ {
+ msg("authorisation method does not support group list retrieval", -1);
+ return array();
+ }
+
+ /**
+ * Return case sensitivity of the backend [OPTIONAL]
+ *
+ * When your backend is caseinsensitive (eg. you can login with USER and
+ * user) then you need to overwrite this method and return false
+ *
+ * @return bool
+ */
+ public function isCaseSensitive()
+ {
+ return true;
+ }
+
+ /**
+ * Sanitize a given username [OPTIONAL]
+ *
+ * This function is applied to any user name that is given to
+ * the backend and should also be applied to any user name within
+ * the backend before returning it somewhere.
+ *
+ * This should be used to enforce username restrictions.
+ *
+ * @author Andreas Gohr <andi@splitbrain.org>
+ * @param string $user username
+ * @return string the cleaned username
+ */
+ public function cleanUser($user)
+ {
+ return $user;
+ }
+
+ /**
+ * Sanitize a given groupname [OPTIONAL]
+ *
+ * This function is applied to any groupname that is given to
+ * the backend and should also be applied to any groupname within
+ * the backend before returning it somewhere.
+ *
+ * This should be used to enforce groupname restrictions.
+ *
+ * Groupnames are to be passed without a leading '@' here.
+ *
+ * @author Andreas Gohr <andi@splitbrain.org>
+ * @param string $group groupname
+ * @return string the cleaned groupname
+ */
+ public function cleanGroup($group)
+ {
+ return $group;
+ }
+
+ /**
+ * Check Session Cache validity [implement only where required/possible]
+ *
+ * DokuWiki caches user info in the user's session for the timespan defined
+ * in $conf['auth_security_timeout'].
+ *
+ * This makes sure slow authentication backends do not slow down DokuWiki.
+ * This also means that changes to the user database will not be reflected
+ * on currently logged in users.
+ *
+ * To accommodate for this, the user manager plugin will touch a reference
+ * file whenever a change is submitted. This function compares the filetime
+ * of this reference file with the time stored in the session.
+ *
+ * This reference file mechanism does not reflect changes done directly in
+ * the backend's database through other means than the user manager plugin.
+ *
+ * Fast backends might want to return always false, to force rechecks on
+ * each page load. Others might want to use their own checking here. If
+ * unsure, do not override.
+ *
+ * @param string $user - The username
+ * @author Andreas Gohr <andi@splitbrain.org>
+ * @return bool
+ */
+ public function useSessionCache($user)
+ {
+ global $conf;
+ return ($_SESSION[DOKU_COOKIE]['auth']['time'] >= @filemtime($conf['cachedir'] . '/sessionpurge'));
+ }
+}
diff --git a/inc/Extension/CLIPlugin.php b/inc/Extension/CLIPlugin.php
new file mode 100644
index 000000000..8637ccf8c
--- /dev/null
+++ b/inc/Extension/CLIPlugin.php
@@ -0,0 +1,13 @@
+<?php
+
+namespace dokuwiki\Extension;
+
+/**
+ * CLI plugin prototype
+ *
+ * Provides DokuWiki plugin functionality on top of php-cli
+ */
+abstract class CLIPlugin extends \splitbrain\phpcli\CLI implements PluginInterface
+{
+ use PluginTrait;
+}
diff --git a/inc/Extension/Event.php b/inc/Extension/Event.php
new file mode 100644
index 000000000..bbaa52e55
--- /dev/null
+++ b/inc/Extension/Event.php
@@ -0,0 +1,202 @@
+<?php
+// phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
+
+namespace dokuwiki\Extension;
+
+/**
+ * The Action plugin event
+ */
+class Event
+{
+ /** @var string READONLY event name, objects must register against this name to see the event */
+ public $name = '';
+ /** @var mixed|null READWRITE data relevant to the event, no standardised format, refer to event docs */
+ public $data = null;
+ /**
+ * @var mixed|null READWRITE the results of the event action, only relevant in "_AFTER" advise
+ * event handlers may modify this if they are preventing the default action
+ * to provide the after event handlers with event results
+ */
+ public $result = null;
+ /** @var bool READONLY if true, event handlers can prevent the events default action */
+ public $canPreventDefault = true;
+
+ /** @var bool whether or not to carry out the default action associated with the event */
+ protected $runDefault = true;
+ /** @var bool whether or not to continue propagating the event to other handlers */
+ protected $mayContinue = true;
+
+ /**
+ * event constructor
+ *
+ * @param string $name
+ * @param mixed $data
+ */
+ public function __construct($name, &$data)
+ {
+
+ $this->name = $name;
+ $this->data =& $data;
+ }
+
+ /**
+ * @return string
+ */
+ public function __toString()
+ {
+ return $this->name;
+ }
+
+ /**
+ * advise all registered BEFORE handlers of this event
+ *
+ * if these methods are used by functions outside of this object, they must
+ * properly handle correct processing of any default action and issue an
+ * advise_after() signal. e.g.
+ * $evt = new dokuwiki\Plugin\Doku_Event(name, data);
+ * if ($evt->advise_before(canPreventDefault) {
+ * // default action code block
+ * }
+ * $evt->advise_after();
+ * unset($evt);
+ *
+ * @param bool $enablePreventDefault
+ * @return bool results of processing the event, usually $this->runDefault
+ */
+ public function advise_before($enablePreventDefault = true)
+ {
+ global $EVENT_HANDLER;
+
+ $this->canPreventDefault = $enablePreventDefault;
+ if ($EVENT_HANDLER !== null) {
+ $EVENT_HANDLER->process_event($this, 'BEFORE');
+ } else {
+ dbglog($this->name . ':BEFORE event triggered before event system was initialized');
+ }
+
+ return (!$enablePreventDefault || $this->runDefault);
+ }
+
+ /**
+ * advise all registered AFTER handlers of this event
+ *
+ * @param bool $enablePreventDefault
+ * @see advise_before() for details
+ */
+ public function advise_after()
+ {
+ global $EVENT_HANDLER;
+
+ $this->mayContinue = true;
+
+ if ($EVENT_HANDLER !== null) {
+ $EVENT_HANDLER->process_event($this, 'AFTER');
+ } else {
+ dbglog($this->name . ':AFTER event triggered before event system was initialized');
+ }
+ }
+
+ /**
+ * trigger
+ *
+ * - advise all registered (<event>_BEFORE) handlers that this event is about to take place
+ * - carry out the default action using $this->data based on $enablePrevent and
+ * $this->_default, all of which may have been modified by the event handlers.
+ * - advise all registered (<event>_AFTER) handlers that the event has taken place
+ *
+ * @param null|callable $action
+ * @param bool $enablePrevent
+ * @return mixed $event->results
+ * the value set by any <event>_before or <event> handlers if the default action is prevented
+ * or the results of the default action (as modified by <event>_after handlers)
+ * or NULL no action took place and no handler modified the value
+ */
+ public function trigger($action = null, $enablePrevent = true)
+ {
+
+ if (!is_callable($action)) {
+ $enablePrevent = false;
+ if ($action !== null) {
+ trigger_error(
+ 'The default action of ' . $this .
+ ' is not null but also not callable. Maybe the method is not public?',
+ E_USER_WARNING
+ );
+ }
+ }
+
+ if ($this->advise_before($enablePrevent) && is_callable($action)) {
+ if (is_array($action)) {
+ list($obj, $method) = $action;
+ $this->result = $obj->$method($this->data);
+ } else {
+ $this->result = $action($this->data);
+ }
+ }
+
+ $this->advise_after();
+
+ return $this->result;
+ }
+
+ /**
+ * stopPropagation
+ *
+ * stop any further processing of the event by event handlers
+ * this function does not prevent the default action taking place
+ */
+ public function stopPropagation()
+ {
+ $this->mayContinue = false;
+ }
+
+ /**
+ * may the event propagate to the next handler?
+ *
+ * @return bool
+ */
+ public function mayPropagate()
+ {
+ return $this->mayContinue;
+ }
+
+ /**
+ * preventDefault
+ *
+ * prevent the default action taking place
+ */
+ public function preventDefault()
+ {
+ $this->runDefault = false;
+ }
+
+ /**
+ * should the default action be executed?
+ *
+ * @return bool
+ */
+ public function mayRunDefault()
+ {
+ return $this->runDefault;
+ }
+
+ /**
+ * Convenience method to trigger an event
+ *
+ * Creates, triggers and destroys an event in one go
+ *
+ * @param string $name name for the event
+ * @param mixed $data event data
+ * @param callable $action (optional, default=NULL) default action, a php callback function
+ * @param bool $canPreventDefault (optional, default=true) can hooks prevent the default action
+ *
+ * @return mixed the event results value after all event processing is complete
+ * by default this is the return value of the default action however
+ * it can be set or modified by event handler hooks
+ */
+ static public function createAndTrigger($name, &$data, $action = null, $canPreventDefault = true)
+ {
+ $evt = new Event($name, $data);
+ return $evt->trigger($action, $canPreventDefault);
+ }
+}
diff --git a/inc/Extension/EventHandler.php b/inc/Extension/EventHandler.php
new file mode 100644
index 000000000..7bed0fe6f
--- /dev/null
+++ b/inc/Extension/EventHandler.php
@@ -0,0 +1,108 @@
+<?php
+// phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
+
+namespace dokuwiki\Extension;
+
+/**
+ * Controls the registration and execution of all events,
+ */
+class EventHandler
+{
+
+ // public properties: none
+
+ // private properties
+ protected $hooks = array(); // array of events and their registered handlers
+
+ /**
+ * event_handler
+ *
+ * constructor, loads all action plugins and calls their register() method giving them
+ * an opportunity to register any hooks they require
+ */
+ public function __construct()
+ {
+
+ // load action plugins
+ /** @var ActionPlugin $plugin */
+ $plugin = null;
+ $pluginlist = plugin_list('action');
+
+ foreach ($pluginlist as $plugin_name) {
+ $plugin = plugin_load('action', $plugin_name);
+
+ if ($plugin !== null) $plugin->register($this);
+ }
+ }
+
+ /**
+ * register_hook
+ *
+ * register a hook for an event
+ *
+ * @param string $event string name used by the event, (incl '_before' or '_after' for triggers)
+ * @param string $advise
+ * @param object $obj object in whose scope method is to be executed,
+ * if NULL, method is assumed to be a globally available function
+ * @param string $method event handler function
+ * @param mixed $param data passed to the event handler
+ * @param int $seq sequence number for ordering hook execution (ascending)
+ */
+ public function register_hook($event, $advise, $obj, $method, $param = null, $seq = 0)
+ {
+ $seq = (int)$seq;
+ $doSort = !isset($this->hooks[$event . '_' . $advise][$seq]);
+ $this->hooks[$event . '_' . $advise][$seq][] = array($obj, $method, $param);
+
+ if ($doSort) {
+ ksort($this->hooks[$event . '_' . $advise]);
+ }
+ }
+
+ /**
+ * process the before/after event
+ *
+ * @param Event $event
+ * @param string $advise BEFORE or AFTER
+ */
+ public function process_event($event, $advise = '')
+ {
+
+ $evt_name = $event->name . ($advise ? '_' . $advise : '_BEFORE');
+
+ if (!empty($this->hooks[$evt_name])) {
+ foreach ($this->hooks[$evt_name] as $sequenced_hooks) {
+ foreach ($sequenced_hooks as $hook) {
+ list($obj, $method, $param) = $hook;
+
+ if ($obj === null) {
+ $method($event, $param);
+ } else {
+ $obj->$method($event, $param);
+ }
+
+ if (!$event->mayPropagate()) return;
+ }
+ }
+ }
+ }
+
+ /**
+ * Check if an event has any registered handlers
+ *
+ * When $advise is empty, both BEFORE and AFTER events will be considered,
+ * otherwise only the given advisory is checked
+ *
+ * @param string $name Name of the event
+ * @param string $advise BEFORE, AFTER or empty
+ * @return bool
+ */
+ public function hasHandlerForEvent($name, $advise = '')
+ {
+ if ($advise) {
+ return isset($this->hooks[$name . '_' . $advise]);
+ }
+
+ return isset($this->hooks[$name . '_BEFORE']) || isset($this->hooks[$name . '_AFTER']);
+ }
+}
diff --git a/inc/Extension/Plugin.php b/inc/Extension/Plugin.php
new file mode 100644
index 000000000..03637fe4d
--- /dev/null
+++ b/inc/Extension/Plugin.php
@@ -0,0 +1,13 @@
+<?php
+
+namespace dokuwiki\Extension;
+
+/**
+ * DokuWiki Base Plugin
+ *
+ * Most plugin types inherit from this class
+ */
+abstract class Plugin implements PluginInterface
+{
+ use PluginTrait;
+}
diff --git a/inc/Extension/PluginController.php b/inc/Extension/PluginController.php
new file mode 100644
index 000000000..638fd3946
--- /dev/null
+++ b/inc/Extension/PluginController.php
@@ -0,0 +1,393 @@
+<?php
+
+namespace dokuwiki\Extension;
+
+/**
+ * Class to encapsulate access to dokuwiki plugins
+ *
+ * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ * @author Christopher Smith <chris@jalakai.co.uk>
+ */
+class PluginController
+{
+ /** @var array the types of plugins DokuWiki supports */
+ const PLUGIN_TYPES = ['auth', 'admin', 'syntax', 'action', 'renderer', 'helper', 'remote', 'cli'];
+
+ protected $listByType = [];
+ /** @var array all installed plugins and their enabled state [plugin=>enabled] */
+ protected $masterList = [];
+ protected $pluginCascade = ['default' => [], 'local' => [], 'protected' => []];
+ protected $lastLocalConfigFile = '';
+
+ /**
+ * Populates the master list of plugins
+ */
+ public function __construct()
+ {
+ $this->loadConfig();
+ $this->populateMasterList();
+ }
+
+ /**
+ * Returns a list of available plugins of given type
+ *
+ * @param $type string, plugin_type name;
+ * the type of plugin to return,
+ * use empty string for all types
+ * @param $all bool;
+ * false to only return enabled plugins,
+ * true to return both enabled and disabled plugins
+ *
+ * @return array of
+ * - plugin names when $type = ''
+ * - or plugin component names when a $type is given
+ *
+ * @author Andreas Gohr <andi@splitbrain.org>
+ */
+ public function getList($type = '', $all = false)
+ {
+
+ // request the complete list
+ if (!$type) {
+ return $all ? array_keys($this->masterList) : array_keys(array_filter($this->masterList));
+ }
+
+ if (!isset($this->listByType[$type]['enabled'])) {
+ $this->listByType[$type]['enabled'] = $this->getListByType($type, true);
+ }
+ if ($all && !isset($this->listByType[$type]['disabled'])) {
+ $this->listByType[$type]['disabled'] = $this->getListByType($type, false);
+ }
+
+ return $all
+ ? array_merge($this->listByType[$type]['enabled'], $this->listByType[$type]['disabled'])
+ : $this->listByType[$type]['enabled'];
+ }
+
+ /**
+ * Loads the given plugin and creates an object of it
+ *
+ * @param $type string type of plugin to load
+ * @param $name string name of the plugin to load
+ * @param $new bool true to return a new instance of the plugin, false to use an already loaded instance
+ * @param $disabled bool true to load even disabled plugins
+ * @return PluginInterface|null the plugin object or null on failure
+ * @author Andreas Gohr <andi@splitbrain.org>
+ *
+ */
+ public function load($type, $name, $new = false, $disabled = false)
+ {
+
+ //we keep all loaded plugins available in global scope for reuse
+ global $DOKU_PLUGINS;
+
+ list($plugin, /* $component */) = $this->splitName($name);
+
+ // check if disabled
+ if (!$disabled && !$this->isEnabled($plugin)) {
+ return null;
+ }
+
+ $class = $type . '_plugin_' . $name;
+
+ //plugin already loaded?
+ if (!empty($DOKU_PLUGINS[$type][$name])) {
+ if ($new || !$DOKU_PLUGINS[$type][$name]->isSingleton()) {
+ return class_exists($class, true) ? new $class : null;
+ }
+
+ return $DOKU_PLUGINS[$type][$name];
+ }
+
+ //construct class and instantiate
+ if (!class_exists($class, true)) {
+
+ # the plugin might be in the wrong directory
+ $inf = confToHash(DOKU_PLUGIN . "$plugin/plugin.info.txt");
+ if ($inf['base'] && $inf['base'] != $plugin) {
+ msg(
+ sprintf(
+ "Plugin installed incorrectly. Rename plugin directory '%s' to '%s'.",
+ hsc($plugin),
+ hsc(
+ $inf['base']
+ )
+ ), -1
+ );
+ } elseif (preg_match('/^' . DOKU_PLUGIN_NAME_REGEX . '$/', $plugin) !== 1) {
+ msg(
+ sprintf(
+ "Plugin name '%s' is not a valid plugin name, only the characters a-z and 0-9 are allowed. " .
+ 'Maybe the plugin has been installed in the wrong directory?', hsc($plugin)
+ ), -1
+ );
+ }
+ return null;
+ }
+
+ $DOKU_PLUGINS[$type][$name] = new $class;
+ return $DOKU_PLUGINS[$type][$name];
+ }
+
+ /**
+ * Whether plugin is disabled
+ *
+ * @param string $plugin name of plugin
+ * @return bool true disabled, false enabled
+ * @deprecated in favor of the more sensible isEnabled where the return value matches the enabled state
+ */
+ public function isDisabled($plugin)
+ {
+ dbg_deprecated('isEnabled()');
+ return !$this->isEnabled($plugin);
+ }
+
+ /**
+ * Check whether plugin is disabled
+ *
+ * @param string $plugin name of plugin
+ * @return bool true enabled, false disabled
+ */
+ public function isEnabled($plugin)
+ {
+ return !empty($this->masterList[$plugin]);
+ }
+
+ /**
+ * Disable the plugin
+ *
+ * @param string $plugin name of plugin
+ * @return bool true saving succeed, false saving failed
+ */
+ public function disable($plugin)
+ {
+ if (array_key_exists($plugin, $this->pluginCascade['protected'])) return false;
+ $this->masterList[$plugin] = 0;
+ return $this->saveList();
+ }
+
+ /**
+ * Enable the plugin
+ *
+ * @param string $plugin name of plugin
+ * @return bool true saving succeed, false saving failed
+ */
+ public function enable($plugin)
+ {
+ if (array_key_exists($plugin, $this->pluginCascade['protected'])) return false;
+ $this->masterList[$plugin] = 1;
+ return $this->saveList();
+ }
+
+ /**
+ * Returns cascade of the config files
+ *
+ * @return array with arrays of plugin configs
+ */
+ public function getCascade()
+ {
+ return $this->pluginCascade;
+ }
+
+ /**
+ * Read all installed plugins and their current enabled state
+ */
+ protected function populateMasterList()
+ {
+ if ($dh = @opendir(DOKU_PLUGIN)) {
+ $all_plugins = array();
+ while (false !== ($plugin = readdir($dh))) {
+ if ($plugin[0] === '.') continue; // skip hidden entries
+ if (is_file(DOKU_PLUGIN . $plugin)) continue; // skip files, we're only interested in directories
+
+ if (array_key_exists($plugin, $this->masterList) && $this->masterList[$plugin] == 0) {
+ $all_plugins[$plugin] = 0;
+
+ } elseif (array_key_exists($plugin, $this->masterList) && $this->masterList[$plugin] == 1) {
+ $all_plugins[$plugin] = 1;
+ } else {
+ $all_plugins[$plugin] = 1;
+ }
+ }
+ $this->masterList = $all_plugins;
+ if (!file_exists($this->lastLocalConfigFile)) {
+ $this->saveList(true);
+ }
+ }
+ }
+
+ /**
+ * Includes the plugin config $files
+ * and returns the entries of the $plugins array set in these files
+ *
+ * @param array $files list of files to include, latter overrides previous
+ * @return array with entries of the $plugins arrays of the included files
+ */
+ protected function checkRequire($files)
+ {
+ $plugins = array();
+ foreach ($files as $file) {
+ if (file_exists($file)) {
+ include_once($file);
+ }
+ }
+ return $plugins;
+ }
+
+ /**
+ * Save the current list of plugins
+ *
+ * @param bool $forceSave ;
+ * false to save only when config changed
+ * true to always save
+ * @return bool true saving succeed, false saving failed
+ */
+ protected function saveList($forceSave = false)
+ {
+ global $conf;
+
+ if (empty($this->masterList)) return false;
+
+ // Rebuild list of local settings
+ $local_plugins = $this->rebuildLocal();
+ if ($local_plugins != $this->pluginCascade['local'] || $forceSave) {
+ $file = $this->lastLocalConfigFile;
+ $out = "<?php\n/*\n * Local plugin enable/disable settings\n" .
+ " * Auto-generated through plugin/extension manager\n *\n" .
+ " * NOTE: Plugins will not be added to this file unless there " .
+ "is a need to override a default setting. Plugins are\n" .
+ " * enabled by default.\n */\n";
+ foreach ($local_plugins as $plugin => $value) {
+ $out .= "\$plugins['$plugin'] = $value;\n";
+ }
+ // backup current file (remove any existing backup)
+ if (file_exists($file)) {
+ $backup = $file . '.bak';
+ if (file_exists($backup)) @unlink($backup);
+ if (!@copy($file, $backup)) return false;
+ if (!empty($conf['fperm'])) chmod($backup, $conf['fperm']);
+ }
+ //check if can open for writing, else restore
+ return io_saveFile($file, $out);
+ }
+ return false;
+ }
+
+ /**
+ * Rebuild the set of local plugins
+ *
+ * @return array array of plugins to be saved in end($config_cascade['plugins']['local'])
+ */
+ protected function rebuildLocal()
+ {
+ //assign to local variable to avoid overwriting
+ $backup = $this->masterList;
+ //Can't do anything about protected one so rule them out completely
+ $local_default = array_diff_key($backup, $this->pluginCascade['protected']);
+ //Diff between local+default and default
+ //gives us the ones we need to check and save
+ $diffed_ones = array_diff_key($local_default, $this->pluginCascade['default']);
+ //The ones which we are sure of (list of 0s not in default)
+ $sure_plugins = array_filter($diffed_ones, array($this, 'negate'));
+ //the ones in need of diff
+ $conflicts = array_diff_key($local_default, $diffed_ones);
+ //The final list
+ return array_merge($sure_plugins, array_diff_assoc($conflicts, $this->pluginCascade['default']));
+ }
+
+ /**
+ * Build the list of plugins and cascade
+ *
+ */
+ protected function loadConfig()
+ {
+ global $config_cascade;
+ foreach (array('default', 'protected') as $type) {
+ if (array_key_exists($type, $config_cascade['plugins'])) {
+ $this->pluginCascade[$type] = $this->checkRequire($config_cascade['plugins'][$type]);
+ }
+ }
+ $local = $config_cascade['plugins']['local'];
+ $this->lastLocalConfigFile = array_pop($local);
+ $this->pluginCascade['local'] = $this->checkRequire(array($this->lastLocalConfigFile));
+ if (is_array($local)) {
+ $this->pluginCascade['default'] = array_merge(
+ $this->pluginCascade['default'],
+ $this->checkRequire($local)
+ );
+ }
+ $this->masterList = array_merge(
+ $this->pluginCascade['default'],
+ $this->pluginCascade['local'],
+ $this->pluginCascade['protected']
+ );
+ }
+
+ /**
+ * Returns a list of available plugin components of given type
+ *
+ * @param string $type plugin_type name; the type of plugin to return,
+ * @param bool $enabled true to return enabled plugins,
+ * false to return disabled plugins
+ * @return array of plugin components of requested type
+ */
+ protected function getListByType($type, $enabled)
+ {
+ $master_list = $enabled
+ ? array_keys(array_filter($this->masterList))
+ : array_keys(array_filter($this->masterList, array($this, 'negate')));
+ $plugins = array();
+
+ foreach ($master_list as $plugin) {
+
+ if (file_exists(DOKU_PLUGIN . "$plugin/$type.php")) {
+ $plugins[] = $plugin;
+ continue;
+ }
+
+ $typedir = DOKU_PLUGIN . "$plugin/$type/";
+ if (is_dir($typedir)) {
+ if ($dp = opendir($typedir)) {
+ while (false !== ($component = readdir($dp))) {
+ if (strpos($component, '.') === 0 || strtolower(substr($component, -4)) !== '.php') continue;
+ if (is_file($typedir . $component)) {
+ $plugins[] = $plugin . '_' . substr($component, 0, -4);
+ }
+ }
+ closedir($dp);
+ }
+ }
+
+ }//foreach
+
+ return $plugins;
+ }
+
+ /**
+ * Split name in a plugin name and a component name
+ *
+ * @param string $name
+ * @return array with
+ * - plugin name
+ * - and component name when available, otherwise empty string
+ */
+ protected function splitName($name)
+ {
+ if (!isset($this->masterList[$name])) {
+ return explode('_', $name, 2);
+ }
+
+ return array($name, '');
+ }
+
+ /**
+ * Returns inverse boolean value of the input
+ *
+ * @param mixed $input
+ * @return bool inversed boolean value of input
+ */
+ protected function negate($input)
+ {
+ return !(bool)$input;
+ }
+}
diff --git a/inc/PluginInterface.php b/inc/Extension/PluginInterface.php
index 608989096..f2dbe8626 100644
--- a/inc/PluginInterface.php
+++ b/inc/Extension/PluginInterface.php
@@ -1,14 +1,18 @@
<?php
+
+namespace dokuwiki\Extension;
+
/**
* DokuWiki Plugin Interface
*
* Defines the public contract all DokuWiki plugins will adhere to. The actual code
- * to do so is defined in DokuWiki_PluginTrait
+ * to do so is defined in dokuwiki\Extension\PluginTrait
*
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
* @author Christopher Smith <chris@jalakai.co.uk>
*/
-interface DokuWiki_PluginInterface {
+interface PluginInterface
+{
/**
* General Info
*
@@ -107,7 +111,7 @@ interface DokuWiki_PluginInterface {
*
* @param string $name name of plugin to load
* @param bool $msg if a message should be displayed in case the plugin is not available
- * @return DokuWiki_PluginInterface|null helper plugin object
+ * @return PluginInterface|null helper plugin object
*/
public function loadHelper($name, $msg = true);
diff --git a/inc/PluginTrait.php b/inc/Extension/PluginTrait.php
index 57b735e85..f1db0f598 100644
--- a/inc/PluginTrait.php
+++ b/inc/Extension/PluginTrait.php
@@ -1,10 +1,12 @@
<?php
+namespace dokuwiki\Extension;
+
/**
- * Do not inherit directly from this class, instead inherit from the specialized
- * ones in lib/plugin
+ * Provides standard DokuWiki plugin behaviour
*/
-trait DokuWiki_PluginTrait {
+trait PluginTrait
+{
protected $localised = false; // set to true by setupLocale() after loading language dependent strings
protected $lang = array(); // array to hold language dependent strings, best accessed via ->getLang()
@@ -12,12 +14,13 @@ trait DokuWiki_PluginTrait {
protected $conf = array(); // array to hold plugin settings, best accessed via ->getConf()
/**
- * @see DokuWiki_PluginInterface::getInfo()
+ * @see PluginInterface::getInfo()
*/
- public function getInfo() {
+ public function getInfo()
+ {
$parts = explode('_', get_class($this));
$info = DOKU_PLUGIN . '/' . $parts[2] . '/plugin.info.txt';
- if(file_exists($info)) return confToHash($info);
+ if (file_exists($info)) return confToHash($info);
msg(
'getInfo() not implemented in ' . get_class($this) . ' and ' . $info . ' not found.<br />' .
@@ -31,43 +34,48 @@ trait DokuWiki_PluginTrait {
}
/**
- * @see DokuWiki_PluginInterface::isSingleton()
+ * @see PluginInterface::isSingleton()
*/
- public function isSingleton() {
+ public function isSingleton()
+ {
return true;
}
/**
- * @see DokuWiki_PluginInterface::loadHelper()
+ * @see PluginInterface::loadHelper()
*/
- public function loadHelper($name, $msg = true) {
+ public function loadHelper($name, $msg = true)
+ {
$obj = plugin_load('helper', $name);
- if(is_null($obj) && $msg) msg("Helper plugin $name is not available or invalid.", -1);
+ if (is_null($obj) && $msg) msg("Helper plugin $name is not available or invalid.", -1);
return $obj;
}
// region introspection methods
/**
- * @see DokuWiki_PluginInterface::getPluginType()
+ * @see PluginInterface::getPluginType()
*/
- public function getPluginType() {
+ public function getPluginType()
+ {
list($t) = explode('_', get_class($this), 2);
return $t;
}
/**
- * @see DokuWiki_PluginInterface::getPluginName()
+ * @see PluginInterface::getPluginName()
*/
- public function getPluginName() {
+ public function getPluginName()
+ {
list(/* $t */, /* $p */, $n) = explode('_', get_class($this), 4);
return $n;
}
/**
- * @see DokuWiki_PluginInterface::getPluginComponent()
+ * @see PluginInterface::getPluginComponent()
*/
- public function getPluginComponent() {
+ public function getPluginComponent()
+ {
list(/* $t */, /* $p */, /* $n */, $c) = explode('_', get_class($this), 4);
return (isset($c) ? $c : '');
}
@@ -76,31 +84,34 @@ trait DokuWiki_PluginTrait {
// region localization methods
/**
- * @see DokuWiki_PluginInterface::getLang()
+ * @see PluginInterface::getLang()
*/
- public function getLang($id) {
- if(!$this->localised) $this->setupLocale();
+ public function getLang($id)
+ {
+ if (!$this->localised) $this->setupLocale();
return (isset($this->lang[$id]) ? $this->lang[$id] : '');
}
/**
- * @see DokuWiki_PluginInterface::locale_xhtml()
+ * @see PluginInterface::locale_xhtml()
*/
- public function locale_xhtml($id) {
+ public function locale_xhtml($id)
+ {
return p_cached_output($this->localFN($id));
}
/**
- * @see DokuWiki_PluginInterface::localFN()
+ * @see PluginInterface::localFN()
*/
- public function localFN($id, $ext = 'txt') {
+ public function localFN($id, $ext = 'txt')
+ {
global $conf;
$plugin = $this->getPluginName();
$file = DOKU_CONF . 'plugin_lang/' . $plugin . '/' . $conf['lang'] . '/' . $id . '.' . $ext;
- if(!file_exists($file)) {
+ if (!file_exists($file)) {
$file = DOKU_PLUGIN . $plugin . '/lang/' . $conf['lang'] . '/' . $id . '.' . $ext;
- if(!file_exists($file)) {
+ if (!file_exists($file)) {
//fall back to english
$file = DOKU_PLUGIN . $plugin . '/lang/en/' . $id . '.' . $ext;
}
@@ -109,10 +120,11 @@ trait DokuWiki_PluginTrait {
}
/**
- * @see DokuWiki_PluginInterface::setupLocale()
+ * @see PluginInterface::setupLocale()
*/
- public function setupLocale() {
- if($this->localised) return;
+ public function setupLocale()
+ {
+ if ($this->localised) return;
global $conf, $config_cascade; // definitely don't invoke "global $lang"
$path = DOKU_PLUGIN . $this->getPluginName() . '/lang/';
@@ -121,16 +133,16 @@ trait DokuWiki_PluginTrait {
// don't include once, in case several plugin components require the same language file
@include($path . 'en/lang.php');
- foreach($config_cascade['lang']['plugin'] as $config_file) {
- if(file_exists($config_file . $this->getPluginName() . '/en/lang.php')) {
+ foreach ($config_cascade['lang']['plugin'] as $config_file) {
+ if (file_exists($config_file . $this->getPluginName() . '/en/lang.php')) {
include($config_file . $this->getPluginName() . '/en/lang.php');
}
}
- if($conf['lang'] != 'en') {
+ if ($conf['lang'] != 'en') {
@include($path . $conf['lang'] . '/lang.php');
- foreach($config_cascade['lang']['plugin'] as $config_file) {
- if(file_exists($config_file . $this->getPluginName() . '/' . $conf['lang'] . '/lang.php')) {
+ foreach ($config_cascade['lang']['plugin'] as $config_file) {
+ if (file_exists($config_file . $this->getPluginName() . '/' . $conf['lang'] . '/lang.php')) {
include($config_file . $this->getPluginName() . '/' . $conf['lang'] . '/lang.php');
}
}
@@ -144,15 +156,16 @@ trait DokuWiki_PluginTrait {
// region configuration methods
/**
- * @see DokuWiki_PluginInterface::getConf()
+ * @see PluginInterface::getConf()
*/
- public function getConf($setting, $notset = false) {
+ public function getConf($setting, $notset = false)
+ {
- if(!$this->configloaded) {
+ if (!$this->configloaded) {
$this->loadConfig();
}
- if(isset($this->conf[$setting])) {
+ if (isset($this->conf[$setting])) {
return $this->conf[$setting];
} else {
return $notset;
@@ -160,16 +173,17 @@ trait DokuWiki_PluginTrait {
}
/**
- * @see DokuWiki_PluginInterface::loadConfig()
+ * @see PluginInterface::loadConfig()
*/
- public function loadConfig() {
+ public function loadConfig()
+ {
global $conf;
$defaults = $this->readDefaultSettings();
$plugin = $this->getPluginName();
- foreach($defaults as $key => $value) {
- if(isset($conf['plugin'][$plugin][$key])) continue;
+ foreach ($defaults as $key => $value) {
+ if (isset($conf['plugin'][$plugin][$key])) continue;
$conf['plugin'][$plugin][$key] = $value;
}
@@ -183,12 +197,13 @@ trait DokuWiki_PluginTrait {
*
* @return array setting => value
*/
- protected function readDefaultSettings() {
+ protected function readDefaultSettings()
+ {
$path = DOKU_PLUGIN . $this->getPluginName() . '/conf/';
$conf = array();
- if(file_exists($path . 'default.php')) {
+ if (file_exists($path . 'default.php')) {
include($path . 'default.php');
}
@@ -199,38 +214,41 @@ trait DokuWiki_PluginTrait {
// region output methods
/**
- * @see DokuWiki_PluginInterface::email()
+ * @see PluginInterface::email()
*/
- public function email($email, $name = '', $class = '', $more = '') {
- if(!$email) return $name;
+ public function email($email, $name = '', $class = '', $more = '')
+ {
+ if (!$email) return $name;
$email = obfuscate($email);
- if(!$name) $name = $email;
+ if (!$name) $name = $email;
$class = "class='" . ($class ? $class : 'mail') . "'";
return "<a href='mailto:$email' $class title='$email' $more>$name</a>";
}
/**
- * @see DokuWiki_PluginInterface::external_link()
+ * @see PluginInterface::external_link()
*/
- public function external_link($link, $title = '', $class = '', $target = '', $more = '') {
+ public function external_link($link, $title = '', $class = '', $target = '', $more = '')
+ {
global $conf;
$link = htmlentities($link);
- if(!$title) $title = $link;
- if(!$target) $target = $conf['target']['extern'];
- if($conf['relnofollow']) $more .= ' rel="nofollow"';
+ if (!$title) $title = $link;
+ if (!$target) $target = $conf['target']['extern'];
+ if ($conf['relnofollow']) $more .= ' rel="nofollow"';
- if($class) $class = " class='$class'";
- if($target) $target = " target='$target'";
- if($more) $more = " " . trim($more);
+ if ($class) $class = " class='$class'";
+ if ($target) $target = " target='$target'";
+ if ($more) $more = " " . trim($more);
return "<a href='$link'$class$target$more>$title</a>";
}
/**
- * @see DokuWiki_PluginInterface::render_text()
+ * @see PluginInterface::render_text()
*/
- public function render_text($text, $format = 'xhtml') {
+ public function render_text($text, $format = 'xhtml')
+ {
return p_render($format, p_get_instructions($text), $info);
}
diff --git a/inc/Extension/RemotePlugin.php b/inc/Extension/RemotePlugin.php
new file mode 100644
index 000000000..33bca980a
--- /dev/null
+++ b/inc/Extension/RemotePlugin.php
@@ -0,0 +1,122 @@
+<?php
+
+namespace dokuwiki\Extension;
+
+use dokuwiki\Remote\Api;
+use ReflectionException;
+use ReflectionMethod;
+
+/**
+ * Remote Plugin prototype
+ *
+ * Add functionality to the remote API in a plugin
+ */
+abstract class RemotePlugin extends Plugin
+{
+
+ private $api;
+
+ /**
+ * Constructor
+ */
+ public function __construct()
+ {
+ $this->api = new Api();
+ }
+
+ /**
+ * Get all available methods with remote access.
+ *
+ * By default it exports all public methods of a remote plugin. Methods beginning
+ * with an underscore are skipped.
+ *
+ * @return array Information about all provided methods. {@see dokuwiki\Remote\RemoteAPI}.
+ * @throws ReflectionException
+ */
+ public function _getMethods()
+ {
+ $result = array();
+
+ $reflection = new \ReflectionClass($this);
+ foreach ($reflection->getMethods(ReflectionMethod::IS_PUBLIC) as $method) {
+ // skip parent methods, only methods further down are exported
+ $declaredin = $method->getDeclaringClass()->name;
+ if ($declaredin === 'dokuwiki\Extension\Plugin' || $declaredin === 'dokuwiki\Extension\RemotePlugin') {
+ continue;
+ }
+ $method_name = $method->name;
+ if (strpos($method_name, '_') === 0) {
+ continue;
+ }
+
+ // strip asterisks
+ $doc = $method->getDocComment();
+ $doc = preg_replace(
+ array('/^[ \t]*\/\*+[ \t]*/m', '/[ \t]*\*+[ \t]*/m', '/\*+\/\s*$/m', '/\s*\/\s*$/m'),
+ array('', '', '', ''),
+ $doc
+ );
+
+ // prepare data
+ $data = array();
+ $data['name'] = $method_name;
+ $data['public'] = 0;
+ $data['doc'] = $doc;
+ $data['args'] = array();
+
+ // get parameter type from doc block type hint
+ foreach ($method->getParameters() as $parameter) {
+ $name = $parameter->name;
+ $type = 'string'; // we default to string
+ if (preg_match('/^@param[ \t]+([\w|\[\]]+)[ \t]\$' . $name . '/m', $doc, $m)) {
+ $type = $this->cleanTypeHint($m[1]);
+ }
+ $data['args'][] = $type;
+ }
+
+ // get return type from doc block type hint
+ if (preg_match('/^@return[ \t]+([\w|\[\]]+)/m', $doc, $m)) {
+ $data['return'] = $this->cleanTypeHint($m[1]);
+ } else {
+ $data['return'] = 'string';
+ }
+
+ // add to result
+ $result[$method_name] = $data;
+ }
+
+ return $result;
+ }
+
+ /**
+ * Matches the given type hint against the valid options for the remote API
+ *
+ * @param string $hint
+ * @return string
+ */
+ protected function cleanTypeHint($hint)
+ {
+ $types = explode('|', $hint);
+ foreach ($types as $t) {
+ if (substr($t, -2) === '[]') {
+ return 'array';
+ }
+ if ($t === 'boolean') {
+ return 'bool';
+ }
+ if (in_array($t, array('array', 'string', 'int', 'double', 'bool', 'null', 'date', 'file'))) {
+ return $t;
+ }
+ }
+ return 'string';
+ }
+
+ /**
+ * @return Api
+ */
+ protected function getApi()
+ {
+ return $this->api;
+ }
+
+}
diff --git a/inc/Extension/SyntaxPlugin.php b/inc/Extension/SyntaxPlugin.php
new file mode 100644
index 000000000..e5dda9bdc
--- /dev/null
+++ b/inc/Extension/SyntaxPlugin.php
@@ -0,0 +1,132 @@
+<?php
+
+namespace dokuwiki\Extension;
+
+use \Doku_Handler;
+use \Doku_Renderer;
+
+/**
+ * Syntax Plugin Prototype
+ *
+ * All DokuWiki plugins to extend the parser/rendering mechanism
+ * need to inherit from this class
+ *
+ * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ * @author Andreas Gohr <andi@splitbrain.org>
+ */
+abstract class SyntaxPlugin extends \dokuwiki\Parsing\ParserMode\Plugin
+{
+ use PluginTrait;
+
+ protected $allowedModesSetup = false;
+
+ /**
+ * Syntax Type
+ *
+ * Needs to return one of the mode types defined in $PARSER_MODES in Parser.php
+ *
+ * @return string
+ */
+ abstract public function getType();
+
+ /**
+ * Allowed Mode Types
+ *
+ * Defines the mode types for other dokuwiki markup that maybe nested within the
+ * plugin's own markup. Needs to return an array of one or more of the mode types
+ * defined in $PARSER_MODES in Parser.php
+ *
+ * @return array
+ */
+ public function getAllowedTypes()
+ {
+ return array();
+ }
+
+ /**
+ * Paragraph Type
+ *
+ * Defines how this syntax is handled regarding paragraphs. This is important
+ * for correct XHTML nesting. Should return one of the following:
+ *
+ * 'normal' - The plugin can be used inside paragraphs
+ * 'block' - Open paragraphs need to be closed before plugin output
+ * 'stack' - Special case. Plugin wraps other paragraphs.
+ *
+ * @see Doku_Handler_Block
+ *
+ * @return string
+ */
+ public function getPType()
+ {
+ return 'normal';
+ }
+
+ /**
+ * Handler to prepare matched data for the rendering process
+ *
+ * This function can only pass data to render() via its return value - render()
+ * may be not be run during the object's current life.
+ *
+ * Usually you should only need the $match param.
+ *
+ * @param string $match The text matched by the patterns
+ * @param int $state The lexer state for the match
+ * @param int $pos The character position of the matched text
+ * @param Doku_Handler $handler The Doku_Handler object
+ * @return bool|array Return an array with all data you want to use in render, false don't add an instruction
+ */
+ abstract public function handle($match, $state, $pos, Doku_Handler $handler);
+
+ /**
+ * Handles the actual output creation.
+ *
+ * The function must not assume any other of the classes methods have been run
+ * during the object's current life. The only reliable data it receives are its
+ * parameters.
+ *
+ * The function should always check for the given output format and return false
+ * when a format isn't supported.
+ *
+ * $renderer contains a reference to the renderer object which is
+ * currently handling the rendering. You need to use it for writing
+ * the output. How this is done depends on the renderer used (specified
+ * by $format
+ *
+ * The contents of the $data array depends on what the handler() function above
+ * created
+ *
+ * @param string $format output format being rendered
+ * @param Doku_Renderer $renderer the current renderer object
+ * @param array $data data created by handler()
+ * @return boolean rendered correctly? (however, returned value is not used at the moment)
+ */
+ abstract public function render($format, Doku_Renderer $renderer, $data);
+
+ /**
+ * There should be no need to override this function
+ *
+ * @param string $mode
+ * @return bool
+ */
+ public function accepts($mode)
+ {
+
+ if (!$this->allowedModesSetup) {
+ global $PARSER_MODES;
+
+ $allowedModeTypes = $this->getAllowedTypes();
+ foreach ($allowedModeTypes as $mt) {
+ $this->allowedModes = array_merge($this->allowedModes, $PARSER_MODES[$mt]);
+ }
+
+ $idx = array_search(substr(get_class($this), 7), (array)$this->allowedModes);
+ if ($idx !== false) {
+ unset($this->allowedModes[$idx]);
+ }
+ $this->allowedModesSetup = true;
+ }
+
+ return parent::accepts($mode);
+ }
+}
diff --git a/inc/FeedParser.php b/inc/FeedParser.php
index 39434dcaf..8f71b96bc 100644
--- a/inc/FeedParser.php
+++ b/inc/FeedParser.php
@@ -1,13 +1,5 @@
<?php
/**
- * Class used to parse RSS and ATOM feeds
- *
- * @author Andreas Gohr <andi@splitbrain.org>
- */
-
-if(!defined('DOKU_INC')) die('meh.');
-
-/**
* We override some methods of the original SimplePie class here
*/
class FeedParser extends SimplePie {
@@ -15,70 +7,21 @@ class FeedParser extends SimplePie {
/**
* Constructor. Set some defaults
*/
- function __construct(){
+ public function __construct(){
parent::__construct();
$this->enable_cache(false);
- $this->set_file_class('FeedParser_File');
+ $this->set_file_class(\dokuwiki\FeedParserFile::class);
}
/**
* Backward compatibility for older plugins
*
+ * phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
* @param string $url
*/
- function feed_url($url){
+ public function feed_url($url){
$this->set_feed_url($url);
}
}
-/**
- * Fetch an URL using our own HTTPClient
- *
- * Replaces SimplePie's own class
- */
-class FeedParser_File extends SimplePie_File {
- var $http;
- var $useragent;
- var $success = true;
- var $headers = array();
- var $body;
- var $error;
- /** @noinspection PhpMissingParentConstructorInspection */
-
- /**
- * Inititializes the HTTPClient
- *
- * We ignore all given parameters - they are set in DokuHTTPClient
- *
- * @inheritdoc
- */
- function __construct($url, $timeout=10, $redirects=5,
- $headers=null, $useragent=null, $force_fsockopen=false, $curl_options = array()) {
- $this->http = new DokuHTTPClient();
- $this->success = $this->http->sendRequest($url);
-
- $this->headers = $this->http->resp_headers;
- $this->body = $this->http->resp_body;
- $this->error = $this->http->error;
-
- $this->method = SIMPLEPIE_FILE_SOURCE_REMOTE | SIMPLEPIE_FILE_SOURCE_FSOCKOPEN;
-
- return $this->success;
- }
-
- /** @inheritdoc */
- function headers(){
- return $this->headers;
- }
- /** @inheritdoc */
- function body(){
- return $this->body;
- }
-
- /** @inheritdoc */
- function close(){
- return true;
- }
-
-}
diff --git a/inc/FeedParserFile.php b/inc/FeedParserFile.php
new file mode 100644
index 000000000..be3417e9b
--- /dev/null
+++ b/inc/FeedParserFile.php
@@ -0,0 +1,62 @@
+<?php
+
+namespace dokuwiki;
+
+use dokuwiki\HTTP\DokuHTTPClient;
+
+/**
+ * Fetch an URL using our own HTTPClient
+ *
+ * Replaces SimplePie's own class
+ */
+class FeedParserFile extends \SimplePie_File
+{
+ protected $http;
+ /** @noinspection PhpMissingParentConstructorInspection */
+
+ /**
+ * Inititializes the HTTPClient
+ *
+ * We ignore all given parameters - they are set in DokuHTTPClient
+ *
+ * @inheritdoc
+ */
+ public function __construct(
+ $url,
+ $timeout = 10,
+ $redirects = 5,
+ $headers = null,
+ $useragent = null,
+ $force_fsockopen = false,
+ $curl_options = array()
+ ) {
+ $this->http = new DokuHTTPClient();
+ $this->success = $this->http->sendRequest($url);
+
+ $this->headers = $this->http->resp_headers;
+ $this->body = $this->http->resp_body;
+ $this->error = $this->http->error;
+
+ $this->method = SIMPLEPIE_FILE_SOURCE_REMOTE | SIMPLEPIE_FILE_SOURCE_FSOCKOPEN;
+
+ return $this->success;
+ }
+
+ /** @inheritdoc */
+ public function headers()
+ {
+ return $this->headers;
+ }
+
+ /** @inheritdoc */
+ public function body()
+ {
+ return $this->body;
+ }
+
+ /** @inheritdoc */
+ public function close()
+ {
+ return true;
+ }
+}
diff --git a/inc/Form/ButtonElement.php b/inc/Form/ButtonElement.php
index e2afe9c97..4f585f0c1 100644
--- a/inc/Form/ButtonElement.php
+++ b/inc/Form/ButtonElement.php
@@ -17,7 +17,7 @@ class ButtonElement extends Element {
* @param string $name
* @param string $content HTML content of the button. You have to escape it yourself.
*/
- function __construct($name, $content = '') {
+ public function __construct($name, $content = '') {
parent::__construct('button', array('name' => $name, 'value' => 1));
$this->content = $content;
}
diff --git a/inc/Form/DropdownElement.php b/inc/Form/DropdownElement.php
index 023b67dd3..51f475196 100644
--- a/inc/Form/DropdownElement.php
+++ b/inc/Form/DropdownElement.php
@@ -104,7 +104,9 @@ class DropdownElement extends InputElement {
*/
public function attr($name, $value = null) {
if(strtolower($name) == 'multiple') {
- throw new \InvalidArgumentException('Sorry, the dropdown element does not support the "multiple" attribute');
+ throw new \InvalidArgumentException(
+ 'Sorry, the dropdown element does not support the "multiple" attribute'
+ );
}
return parent::attr($name, $value);
}
@@ -181,7 +183,13 @@ class DropdownElement extends InputElement {
if($this->useInput) $this->prefillInput();
$html = '<select ' . buildAttributes($this->attrs()) . '>';
- $html = array_reduce($this->optGroups, function($html, OptGroup $optGroup) {return $html . $optGroup->toHTML();}, $html);
+ $html = array_reduce(
+ $this->optGroups,
+ function ($html, OptGroup $optGroup) {
+ return $html . $optGroup->toHTML();
+ },
+ $html
+ );
$html .= '</select>';
return $html;
diff --git a/inc/Form/Form.php b/inc/Form/Form.php
index 92bbd30f4..c741a698f 100644
--- a/inc/Form/Form.php
+++ b/inc/Form/Form.php
@@ -84,7 +84,9 @@ class Form extends Element {
/**
* Get the position of the element in the form or false if it is not in the form
*
- * Warning: This function may return Boolean FALSE, but may also return a non-Boolean value which evaluates to FALSE. Please read the section on Booleans for more information. Use the === operator for testing the return value of this function.
+ * Warning: This function may return Boolean FALSE, but may also return a non-Boolean value which evaluates
+ * to FALSE. Please read the section on Booleans for more information. Use the === operator for testing the
+ * return value of this function.
*
* @param Element $element
*
@@ -157,7 +159,9 @@ class Form extends Element {
* @return Element
*/
public function addElement(Element $element, $pos = -1) {
- if(is_a($element, '\dokuwiki\Form\Form')) throw new \InvalidArgumentException('You can\'t add a form to a form');
+ if(is_a($element, '\dokuwiki\Form\Form')) throw new \InvalidArgumentException(
+ 'You can\'t add a form to a form'
+ );
if($pos < 0) {
$this->elements[] = $element;
} else {
@@ -173,7 +177,9 @@ class Form extends Element {
* @param int $pos 0-based position of the element to replace
*/
public function replaceElement(Element $element, $pos) {
- if(is_a($element, '\dokuwiki\Form\Form')) throw new \InvalidArgumentException('You can\'t add a form to a form');
+ if(is_a($element, '\dokuwiki\Form\Form')) throw new \InvalidArgumentException(
+ 'You can\'t add a form to a form'
+ );
array_splice($this->elements, $pos, 1, array($element));
}
diff --git a/inc/Form/OptGroup.php b/inc/Form/OptGroup.php
index 791f0b3f6..40149b171 100644
--- a/inc/Form/OptGroup.php
+++ b/inc/Form/OptGroup.php
@@ -51,9 +51,13 @@ class OptGroup extends Element {
$this->options = array();
foreach($options as $key => $val) {
if (is_array($val)) {
- if (!key_exists('label', $val)) throw new \InvalidArgumentException('If option is given as array, it has to have a "label"-key!');
+ if (!key_exists('label', $val)) throw new \InvalidArgumentException(
+ 'If option is given as array, it has to have a "label"-key!'
+ );
if (key_exists('attrs', $val) && is_array($val['attrs']) && key_exists('selected', $val['attrs'])) {
- throw new \InvalidArgumentException('Please use function "DropdownElement::val()" to set the selected option');
+ throw new \InvalidArgumentException(
+ 'Please use function "DropdownElement::val()" to set the selected option'
+ );
}
$this->options[$key] = $val;
} elseif(is_int($key)) {
@@ -93,7 +97,9 @@ class OptGroup extends Element {
if (!empty($val['attrs']) && is_array($val['attrs'])) {
$attrs = buildAttributes($val['attrs']);
}
- $html .= '<option' . $selected . ' value="' . hsc($key) . '" '.$attrs.'>' . hsc($val['label']) . '</option>';
+ $html .= '<option' . $selected . ' value="' . hsc($key) . '" '.$attrs.'>';
+ $html .= hsc($val['label']);
+ $html .= '</option>';
}
return $html;
}
diff --git a/inc/HTTP/DokuHTTPClient.php b/inc/HTTP/DokuHTTPClient.php
new file mode 100644
index 000000000..b1db7e3c5
--- /dev/null
+++ b/inc/HTTP/DokuHTTPClient.php
@@ -0,0 +1,77 @@
+<?php
+
+
+namespace dokuwiki\HTTP;
+
+
+
+/**
+ * Adds DokuWiki specific configs to the HTTP client
+ *
+ * @author Andreas Goetz <cpuidle@gmx.de>
+ */
+class DokuHTTPClient extends HTTPClient {
+
+ /**
+ * Constructor.
+ *
+ * @author Andreas Gohr <andi@splitbrain.org>
+ */
+ public function __construct(){
+ global $conf;
+
+ // call parent constructor
+ parent::__construct();
+
+ // set some values from the config
+ $this->proxy_host = $conf['proxy']['host'];
+ $this->proxy_port = $conf['proxy']['port'];
+ $this->proxy_user = $conf['proxy']['user'];
+ $this->proxy_pass = conf_decodeString($conf['proxy']['pass']);
+ $this->proxy_ssl = $conf['proxy']['ssl'];
+ $this->proxy_except = $conf['proxy']['except'];
+
+ // allow enabling debugging via URL parameter (if debugging allowed)
+ if($conf['allowdebug']) {
+ if(
+ isset($_REQUEST['httpdebug']) ||
+ (
+ isset($_SERVER['HTTP_REFERER']) &&
+ strpos($_SERVER['HTTP_REFERER'], 'httpdebug') !== false
+ )
+ ) {
+ $this->debug = true;
+ }
+ }
+ }
+
+
+ /**
+ * Wraps an event around the parent function
+ *
+ * @triggers HTTPCLIENT_REQUEST_SEND
+ * @author Andreas Gohr <andi@splitbrain.org>
+ */
+ /**
+ * @param string $url
+ * @param string|array $data the post data either as array or raw data
+ * @param string $method
+ * @return bool
+ */
+ public function sendRequest($url,$data='',$method='GET'){
+ $httpdata = array('url' => $url,
+ 'data' => $data,
+ 'method' => $method);
+ $evt = new \Doku_Event('HTTPCLIENT_REQUEST_SEND',$httpdata);
+ if($evt->advise_before()){
+ $url = $httpdata['url'];
+ $data = $httpdata['data'];
+ $method = $httpdata['method'];
+ }
+ $evt->advise_after();
+ unset($evt);
+ return parent::sendRequest($url,$data,$method);
+ }
+
+}
+
diff --git a/inc/HTTPClient.php b/inc/HTTP/HTTPClient.php
index 9a20dc598..90c22b7f1 100644
--- a/inc/HTTPClient.php
+++ b/inc/HTTP/HTTPClient.php
@@ -1,18 +1,9 @@
<?php
-/**
- * HTTP Client
- *
- * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
- * @author Andreas Goetz <cpuidle@gmx.de>
- */
+namespace dokuwiki\HTTP;
define('HTTP_NL',"\r\n");
-/**
- * Class HTTPClientException
- */
-class HTTPClientException extends Exception { }
/**
* This class implements a basic HTTP client
@@ -28,53 +19,53 @@ class HTTPClientException extends Exception { }
*/
class HTTPClient {
//set these if you like
- var $agent; // User agent
- var $http; // HTTP version defaults to 1.0
- var $timeout; // read timeout (seconds)
- var $cookies;
- var $referer;
- var $max_redirect;
- var $max_bodysize;
- var $max_bodysize_abort = true; // if set, abort if the response body is bigger than max_bodysize
- var $header_regexp; // if set this RE must match against the headers, else abort
- var $headers;
- var $debug;
- var $start = 0.0; // for timings
- var $keep_alive = true; // keep alive rocks
+ public $agent; // User agent
+ public $http; // HTTP version defaults to 1.0
+ public $timeout; // read timeout (seconds)
+ public $cookies;
+ public $referer;
+ public $max_redirect;
+ public $max_bodysize;
+ public $max_bodysize_abort = true; // if set, abort if the response body is bigger than max_bodysize
+ public $header_regexp; // if set this RE must match against the headers, else abort
+ public $headers;
+ public $debug;
+ public $start = 0.0; // for timings
+ public $keep_alive = true; // keep alive rocks
// don't set these, read on error
- var $error;
- var $redirect_count;
+ public $error;
+ public $redirect_count;
// read these after a successful request
- var $status;
- var $resp_body;
- var $resp_headers;
+ public $status;
+ public $resp_body;
+ public $resp_headers;
// set these to do basic authentication
- var $user;
- var $pass;
+ public $user;
+ public $pass;
// set these if you need to use a proxy
- var $proxy_host;
- var $proxy_port;
- var $proxy_user;
- var $proxy_pass;
- var $proxy_ssl; //boolean set to true if your proxy needs SSL
- var $proxy_except; // regexp of URLs to exclude from proxy
+ public $proxy_host;
+ public $proxy_port;
+ public $proxy_user;
+ public $proxy_pass;
+ public $proxy_ssl; //boolean set to true if your proxy needs SSL
+ public $proxy_except; // regexp of URLs to exclude from proxy
// list of kept alive connections
- static $connections = array();
+ protected static $connections = array();
// what we use as boundary on multipart/form-data posts
- var $boundary = '---DokuWikiHTTPClient--4523452351';
+ protected $boundary = '---DokuWikiHTTPClient--4523452351';
/**
* Constructor.
*
* @author Andreas Gohr <andi@splitbrain.org>
*/
- function __construct(){
+ public function __construct(){
$this->agent = 'Mozilla/4.0 (compatible; DokuWiki HTTP Client; '.PHP_OS.')';
$this->timeout = 15;
$this->cookies = array();
@@ -89,7 +80,7 @@ class HTTPClient {
$this->header_regexp= '';
if(extension_loaded('zlib')) $this->headers['Accept-encoding'] = 'gzip';
$this->headers['Accept'] = 'text/xml,application/xml,application/xhtml+xml,'.
- 'text/html,text/plain,image/png,image/jpeg,image/gif,*/*';
+ 'text/html,text/plain,image/png,image/jpeg,image/gif,*/*';
$this->headers['Accept-Language'] = 'en-us';
}
@@ -105,7 +96,7 @@ class HTTPClient {
*
* @author Andreas Gohr <andi@splitbrain.org>
*/
- function get($url,$sloppy304=false){
+ public function get($url,$sloppy304=false){
if(!$this->sendRequest($url)) return false;
if($this->status == 304 && $sloppy304) return $this->resp_body;
if($this->status < 200 || $this->status > 206) return false;
@@ -127,13 +118,13 @@ class HTTPClient {
*
* @author Andreas Gohr <andi@splitbrain.org>
*/
- function dget($url,$data,$sloppy304=false){
+ public function dget($url,$data,$sloppy304=false){
if(strpos($url,'?')){
$url .= '&';
}else{
$url .= '?';
}
- $url .= $this->_postEncode($data);
+ $url .= $this->postEncode($data);
return $this->get($url,$sloppy304);
}
@@ -147,7 +138,7 @@ class HTTPClient {
* @return false|string response body, false on error
* @author Andreas Gohr <andi@splitbrain.org>
*/
- function post($url,$data){
+ public function post($url,$data){
if(!$this->sendRequest($url,$data,'POST')) return false;
if($this->status < 200 || $this->status > 206) return false;
return $this->resp_body;
@@ -170,18 +161,17 @@ class HTTPClient {
* @author Andreas Goetz <cpuidle@gmx.de>
* @author Andreas Gohr <andi@splitbrain.org>
*/
- function sendRequest($url,$data='',$method='GET'){
- $this->start = $this->_time();
+ public function sendRequest($url,$data='',$method='GET'){
+ $this->start = $this->time();
$this->error = '';
$this->status = 0;
- $this->status = 0;
$this->resp_body = '';
$this->resp_headers = array();
// don't accept gzip if truncated bodies might occur
if($this->max_bodysize &&
- !$this->max_bodysize_abort &&
- $this->headers['Accept-encoding'] == 'gzip'){
+ !$this->max_bodysize_abort &&
+ $this->headers['Accept-encoding'] == 'gzip'){
unset($this->headers['Accept-encoding']);
}
@@ -230,13 +220,13 @@ class HTTPClient {
$headers['Content-Type'] = null;
}
switch ($headers['Content-Type']) {
- case 'multipart/form-data':
- $headers['Content-Type'] = 'multipart/form-data; boundary=' . $this->boundary;
- $data = $this->_postMultipartEncode($data);
- break;
- default:
- $headers['Content-Type'] = 'application/x-www-form-urlencoded';
- $data = $this->_postEncode($data);
+ case 'multipart/form-data':
+ $headers['Content-Type'] = 'multipart/form-data; boundary=' . $this->boundary;
+ $data = $this->postMultipartEncode($data);
+ break;
+ default:
+ $headers['Content-Type'] = 'application/x-www-form-urlencoded';
+ $data = $this->postEncode($data);
}
}
}elseif($method == 'GET'){
@@ -256,15 +246,15 @@ class HTTPClient {
}
// already connected?
- $connectionId = $this->_uniqueConnectionId($server,$port);
- $this->_debug('connection pool', self::$connections);
+ $connectionId = $this->uniqueConnectionId($server,$port);
+ $this->debug('connection pool', self::$connections);
$socket = null;
if (isset(self::$connections[$connectionId])) {
- $this->_debug('reusing connection', $connectionId);
+ $this->debug('reusing connection', $connectionId);
$socket = self::$connections[$connectionId];
}
if (is_null($socket) || feof($socket)) {
- $this->_debug('opening connection', $connectionId);
+ $this->debug('opening connection', $connectionId);
// open socket
$socket = @fsockopen($server,$port,$errno, $errstr, $this->timeout);
if (!$socket){
@@ -275,7 +265,7 @@ class HTTPClient {
// try establish a CONNECT tunnel for SSL
try {
- if($this->_ssltunnel($socket, $request_url)){
+ if($this->ssltunnel($socket, $request_url)){
// no keep alive for tunnels
$this->keep_alive = false;
// tunnel is authed already
@@ -311,22 +301,22 @@ class HTTPClient {
// build request
$request = "$method $request_url HTTP/".$this->http.HTTP_NL;
- $request .= $this->_buildHeaders($headers);
- $request .= $this->_getCookies();
+ $request .= $this->buildHeaders($headers);
+ $request .= $this->getCookies();
$request .= HTTP_NL;
$request .= $data;
- $this->_debug('request',$request);
- $this->_sendData($socket, $request, 'request');
+ $this->debug('request',$request);
+ $this->sendData($socket, $request, 'request');
// read headers from socket
$r_headers = '';
do{
- $r_line = $this->_readLine($socket, 'headers');
+ $r_line = $this->readLine($socket, 'headers');
$r_headers .= $r_line;
}while($r_line != "\r\n" && $r_line != "\n");
- $this->_debug('response headers',$r_headers);
+ $this->debug('response headers',$r_headers);
// check if expected body size exceeds allowance
if($this->max_bodysize && preg_match('/\r?\nContent-Length:\s*(\d+)\r?\n/i',$r_headers,$match)){
@@ -345,7 +335,7 @@ class HTTPClient {
$this->status = $m[2];
// handle headers and cookies
- $this->resp_headers = $this->_parseHeaders($r_headers);
+ $this->resp_headers = $this->parseHeaders($r_headers);
if(isset($this->resp_headers['set-cookie'])){
foreach ((array) $this->resp_headers['set-cookie'] as $cookie){
list($cookie) = explode(';',$cookie,2);
@@ -361,7 +351,7 @@ class HTTPClient {
}
}
- $this->_debug('Object headers',$this->resp_headers);
+ $this->debug('Object headers',$this->resp_headers);
// check server status code to follow redirect
if($this->status == 301 || $this->status == 302 ){
@@ -381,10 +371,10 @@ class HTTPClient {
if (!preg_match('/^http/i', $this->resp_headers['location'])){
if($this->resp_headers['location'][0] != '/'){
$this->resp_headers['location'] = $uri['scheme'].'://'.$uri['host'].':'.$uri['port'].
- dirname($uri['path']).'/'.$this->resp_headers['location'];
+ dirname($uri['path']).'/'.$this->resp_headers['location'];
}else{
$this->resp_headers['location'] = $uri['scheme'].'://'.$uri['host'].':'.$uri['port'].
- $this->resp_headers['location'];
+ $this->resp_headers['location'];
}
}
// perform redirected request, always via GET (required by RFC)
@@ -398,18 +388,25 @@ class HTTPClient {
//read body (with chunked encoding if needed)
$r_body = '';
- if((isset($this->resp_headers['transfer-encoding']) && $this->resp_headers['transfer-encoding'] == 'chunked')
- || (isset($this->resp_headers['transfer-coding']) && $this->resp_headers['transfer-coding'] == 'chunked')){
+ if(
+ (
+ isset($this->resp_headers['transfer-encoding']) &&
+ $this->resp_headers['transfer-encoding'] == 'chunked'
+ ) || (
+ isset($this->resp_headers['transfer-coding']) &&
+ $this->resp_headers['transfer-coding'] == 'chunked'
+ )
+ ) {
$abort = false;
do {
$chunk_size = '';
- while (preg_match('/^[a-zA-Z0-9]?$/',$byte=$this->_readData($socket,1,'chunk'))){
+ while (preg_match('/^[a-zA-Z0-9]?$/',$byte=$this->readData($socket,1,'chunk'))){
// read chunksize until \r
$chunk_size .= $byte;
if (strlen($chunk_size) > 128) // set an abritrary limit on the size of chunks
throw new HTTPClientException('Allowed response size exceeded');
}
- $this->_readLine($socket, 'chunk'); // readtrailing \n
+ $this->readLine($socket, 'chunk'); // readtrailing \n
$chunk_size = hexdec($chunk_size);
if($this->max_bodysize && $chunk_size+strlen($r_body) > $this->max_bodysize){
@@ -421,8 +418,8 @@ class HTTPClient {
}
if ($chunk_size > 0) {
- $r_body .= $this->_readData($socket, $chunk_size, 'chunk');
- $this->_readData($socket, 2, 'chunk'); // read trailing \r\n
+ $r_body .= $this->readData($socket, $chunk_size, 'chunk');
+ $this->readData($socket, 2, 'chunk'); // read trailing \r\n
}
} while ($chunk_size && !$abort);
}elseif(isset($this->resp_headers['content-length']) && !isset($this->resp_headers['transfer-encoding'])){
@@ -433,21 +430,25 @@ class HTTPClient {
// read up to the content-length or max_bodysize
// for keep alive we need to read the whole message to clean up the socket for the next read
- if(!$this->keep_alive && $this->max_bodysize && $this->max_bodysize < $this->resp_headers['content-length']){
- $length = $this->max_bodysize+1;
+ if(
+ !$this->keep_alive &&
+ $this->max_bodysize &&
+ $this->max_bodysize < $this->resp_headers['content-length']
+ ) {
+ $length = $this->max_bodysize + 1;
}else{
$length = $this->resp_headers['content-length'];
}
- $r_body = $this->_readData($socket, $length, 'response (content-length limited)', true);
+ $r_body = $this->readData($socket, $length, 'response (content-length limited)', true);
}elseif( !isset($this->resp_headers['transfer-encoding']) && $this->max_bodysize && !$this->keep_alive){
- $r_body = $this->_readData($socket, $this->max_bodysize+1, 'response (content-length limited)', true);
+ $r_body = $this->readData($socket, $this->max_bodysize+1, 'response (content-length limited)', true);
} elseif ((int)$this->status === 204) {
// request has no content
} else{
// read entire socket
while (!feof($socket)) {
- $r_body .= $this->_readData($socket, 4096, 'response (unlimited)', true);
+ $r_body .= $this->readData($socket, 4096, 'response (unlimited)', true);
}
}
@@ -472,7 +473,7 @@ class HTTPClient {
}
if (!$this->keep_alive ||
- (isset($this->resp_headers['connection']) && $this->resp_headers['connection'] == 'Close')) {
+ (isset($this->resp_headers['connection']) && $this->resp_headers['connection'] == 'Close')) {
// close socket
fclose($socket);
unset(self::$connections[$connectionId]);
@@ -480,8 +481,8 @@ class HTTPClient {
// decode gzip if needed
if(isset($this->resp_headers['content-encoding']) &&
- $this->resp_headers['content-encoding'] == 'gzip' &&
- strlen($r_body) > 10 && substr($r_body,0,3)=="\x1f\x8b\x08"){
+ $this->resp_headers['content-encoding'] == 'gzip' &&
+ strlen($r_body) > 10 && substr($r_body,0,3)=="\x1f\x8b\x08"){
$this->resp_body = @gzinflate(substr($r_body, 10));
if($this->resp_body === false){
$this->error = 'Failed to decompress gzip encoded content';
@@ -491,7 +492,7 @@ class HTTPClient {
$this->resp_body = $r_body;
}
- $this->_debug('response body',$this->resp_body);
+ $this->debug('response body',$this->resp_body);
$this->redirect_count = 0;
return true;
}
@@ -506,7 +507,7 @@ class HTTPClient {
* @throws HTTPClientException when a tunnel is needed but could not be established
* @return bool true if a tunnel was established
*/
- function _ssltunnel(&$socket, &$requesturl){
+ protected function ssltunnel(&$socket, &$requesturl){
if(!$this->proxy_host) return false;
$requestinfo = parse_url($requesturl);
if($requestinfo['scheme'] != 'https') return false;
@@ -520,17 +521,17 @@ class HTTPClient {
}
$request .= HTTP_NL;
- $this->_debug('SSL Tunnel CONNECT',$request);
- $this->_sendData($socket, $request, 'SSL Tunnel CONNECT');
+ $this->debug('SSL Tunnel CONNECT',$request);
+ $this->sendData($socket, $request, 'SSL Tunnel CONNECT');
// read headers from socket
$r_headers = '';
do{
- $r_line = $this->_readLine($socket, 'headers');
+ $r_line = $this->readLine($socket, 'headers');
$r_headers .= $r_line;
}while($r_line != "\r\n" && $r_line != "\n");
- $this->_debug('SSL Tunnel Response',$r_headers);
+ $this->debug('SSL Tunnel Response',$r_headers);
if(preg_match('/^HTTP\/1\.[01] 200/i',$r_headers)){
// set correct peer name for verification (enabled since PHP 5.6)
stream_context_set_option($socket, 'ssl', 'peer_name', $requestinfo['host']);
@@ -546,11 +547,13 @@ class HTTPClient {
if (@stream_socket_enable_crypto($socket, true, $cryptoMethod)) {
$requesturl = $requestinfo['path'].
- (!empty($requestinfo['query'])?'?'.$requestinfo['query']:'');
+ (!empty($requestinfo['query'])?'?'.$requestinfo['query']:'');
return true;
}
- throw new HTTPClientException('Failed to set up crypto for secure connection to '.$requestinfo['host'], -151);
+ throw new HTTPClientException(
+ 'Failed to set up crypto for secure connection to '.$requestinfo['host'], -151
+ );
}
throw new HTTPClientException('Failed to establish secure proxy connection', -150);
@@ -566,13 +569,13 @@ class HTTPClient {
*
* @author Tom N Harris <tnharris@whoopdedo.org>
*/
- function _sendData($socket, $data, $message) {
+ protected function sendData($socket, $data, $message) {
// send request
$towrite = strlen($data);
$written = 0;
while($written < $towrite){
// check timeout
- $time_used = $this->_time() - $this->start;
+ $time_used = $this->time() - $this->start;
if($time_used > $this->timeout)
throw new HTTPClientException(sprintf('Timeout while sending %s (%.3fs)',$message, $time_used), -100);
if(feof($socket))
@@ -584,8 +587,8 @@ class HTTPClient {
$sel_e = null;
// wait for stream ready or timeout (1sec)
if(@stream_select($sel_r,$sel_w,$sel_e,1) === false){
- usleep(1000);
- continue;
+ usleep(1000);
+ continue;
}
// write to stream
@@ -611,17 +614,17 @@ class HTTPClient {
*
* @author Tom N Harris <tnharris@whoopdedo.org>
*/
- function _readData($socket, $nbytes, $message, $ignore_eof = false) {
+ protected function readData($socket, $nbytes, $message, $ignore_eof = false) {
$r_data = '';
// Does not return immediately so timeout and eof can be checked
if ($nbytes < 0) $nbytes = 0;
$to_read = $nbytes;
do {
- $time_used = $this->_time() - $this->start;
+ $time_used = $this->time() - $this->start;
if ($time_used > $this->timeout)
throw new HTTPClientException(
- sprintf('Timeout while reading %s after %d bytes (%.3fs)', $message,
- strlen($r_data), $time_used), -100);
+ sprintf('Timeout while reading %s after %d bytes (%.3fs)', $message,
+ strlen($r_data), $time_used), -100);
if(feof($socket)) {
if(!$ignore_eof)
throw new HTTPClientException("Premature End of File (socket) while reading $message");
@@ -635,8 +638,8 @@ class HTTPClient {
$sel_e = null;
// wait for stream ready or timeout (1sec)
if(@stream_select($sel_r,$sel_w,$sel_e,1) === false){
- usleep(1000);
- continue;
+ usleep(1000);
+ continue;
}
$bytes = fread($socket, $to_read);
@@ -661,14 +664,14 @@ class HTTPClient {
*
* @author Tom N Harris <tnharris@whoopdedo.org>
*/
- function _readLine($socket, $message) {
+ protected function readLine($socket, $message) {
$r_data = '';
do {
- $time_used = $this->_time() - $this->start;
+ $time_used = $this->time() - $this->start;
if ($time_used > $this->timeout)
throw new HTTPClientException(
- sprintf('Timeout while reading %s (%.3fs) >%s<', $message, $time_used, $r_data),
- -100);
+ sprintf('Timeout while reading %s (%.3fs) >%s<', $message, $time_used, $r_data),
+ -100);
if(feof($socket))
throw new HTTPClientException("Premature End of File (socket) while reading $message");
@@ -678,8 +681,8 @@ class HTTPClient {
$sel_e = null;
// wait for stream ready or timeout (1sec)
if(@stream_select($sel_r,$sel_w,$sel_e,1) === false){
- usleep(1000);
- continue;
+ usleep(1000);
+ continue;
}
$r_data = fgets($socket, 1024);
@@ -697,12 +700,12 @@ class HTTPClient {
* @param string $info
* @param mixed $var
*/
- function _debug($info,$var=null){
+ protected function debug($info,$var=null){
if(!$this->debug) return;
if(php_sapi_name() == 'cli'){
- $this->_debug_text($info, $var);
+ $this->debugText($info, $var);
}else{
- $this->_debug_html($info, $var);
+ $this->debugHtml($info, $var);
}
}
@@ -712,8 +715,8 @@ class HTTPClient {
* @param string $info
* @param mixed $var
*/
- function _debug_html($info, $var=null){
- print '<b>'.$info.'</b> '.($this->_time() - $this->start).'s<br />';
+ protected function debugHtml($info, $var=null){
+ print '<b>'.$info.'</b> '.($this->time() - $this->start).'s<br />';
if(!is_null($var)){
ob_start();
print_r($var);
@@ -729,8 +732,8 @@ class HTTPClient {
* @param string $info
* @param mixed $var
*/
- function _debug_text($info, $var=null){
- print '*'.$info.'* '.($this->_time() - $this->start)."s\n";
+ protected function debugText($info, $var=null){
+ print '*'.$info.'* '.($this->time() - $this->start)."s\n";
if(!is_null($var)) print_r($var);
print "\n-----------------------------------------------\n";
}
@@ -740,7 +743,7 @@ class HTTPClient {
*
* @return float
*/
- static function _time(){
+ protected static function time(){
list($usec, $sec) = explode(" ", microtime());
return ((float)$usec + (float)$sec);
}
@@ -755,7 +758,7 @@ class HTTPClient {
* @param string $string
* @return array
*/
- function _parseHeaders($string){
+ protected function parseHeaders($string){
$headers = array();
$lines = explode("\n",$string);
array_shift($lines); //skip first line (status)
@@ -786,7 +789,7 @@ class HTTPClient {
* @param array $headers
* @return string
*/
- function _buildHeaders($headers){
+ protected function buildHeaders($headers){
$string = '';
foreach($headers as $key => $value){
if($value === '') continue;
@@ -802,7 +805,7 @@ class HTTPClient {
*
* @return string
*/
- function _getCookies(){
+ protected function getCookies(){
$headers = '';
foreach ($this->cookies as $key => $val){
$headers .= "$key=$val; ";
@@ -820,7 +823,7 @@ class HTTPClient {
* @param array $data
* @return string
*/
- function _postEncode($data){
+ protected function postEncode($data){
return http_build_query($data,'','&');
}
@@ -833,7 +836,7 @@ class HTTPClient {
* @param array $data
* @return string
*/
- function _postMultipartEncode($data){
+ protected function postMultipartEncode($data){
$boundary = '--'.$this->boundary;
$out = '';
foreach($data as $key => $val){
@@ -864,80 +867,7 @@ class HTTPClient {
* @param string $port
* @return string unique identifier
*/
- function _uniqueConnectionId($server, $port) {
+ protected function uniqueConnectionId($server, $port) {
return "$server:$port";
}
}
-
-
-/**
- * Adds DokuWiki specific configs to the HTTP client
- *
- * @author Andreas Goetz <cpuidle@gmx.de>
- */
-class DokuHTTPClient extends HTTPClient {
-
- /**
- * Constructor.
- *
- * @author Andreas Gohr <andi@splitbrain.org>
- */
- function __construct(){
- global $conf;
-
- // call parent constructor
- parent::__construct();
-
- // set some values from the config
- $this->proxy_host = $conf['proxy']['host'];
- $this->proxy_port = $conf['proxy']['port'];
- $this->proxy_user = $conf['proxy']['user'];
- $this->proxy_pass = conf_decodeString($conf['proxy']['pass']);
- $this->proxy_ssl = $conf['proxy']['ssl'];
- $this->proxy_except = $conf['proxy']['except'];
-
- // allow enabling debugging via URL parameter (if debugging allowed)
- if($conf['allowdebug']) {
- if(
- isset($_REQUEST['httpdebug']) ||
- (
- isset($_SERVER['HTTP_REFERER']) &&
- strpos($_SERVER['HTTP_REFERER'], 'httpdebug') !== false
- )
- ) {
- $this->debug = true;
- }
- }
- }
-
-
- /**
- * Wraps an event around the parent function
- *
- * @triggers HTTPCLIENT_REQUEST_SEND
- * @author Andreas Gohr <andi@splitbrain.org>
- */
- /**
- * @param string $url
- * @param string|array $data the post data either as array or raw data
- * @param string $method
- * @return bool
- */
- function sendRequest($url,$data='',$method='GET'){
- $httpdata = array('url' => $url,
- 'data' => $data,
- 'method' => $method);
- $evt = new Doku_Event('HTTPCLIENT_REQUEST_SEND',$httpdata);
- if($evt->advise_before()){
- $url = $httpdata['url'];
- $data = $httpdata['data'];
- $method = $httpdata['method'];
- }
- $evt->advise_after();
- unset($evt);
- return parent::sendRequest($url,$data,$method);
- }
-
-}
-
-//Setup VIM: ex: et ts=4 :
diff --git a/inc/HTTP/HTTPClientException.php b/inc/HTTP/HTTPClientException.php
new file mode 100644
index 000000000..5b8f4eeca
--- /dev/null
+++ b/inc/HTTP/HTTPClientException.php
@@ -0,0 +1,10 @@
+<?php
+
+namespace dokuwiki\HTTP;
+
+use Exception;
+
+class HTTPClientException extends Exception
+{
+
+}
diff --git a/inc/IXR_Library.php b/inc/IXR_Library.php
index 5ae1402b9..e671b6880 100644
--- a/inc/IXR_Library.php
+++ b/inc/IXR_Library.php
@@ -1,5 +1,7 @@
<?php
+use dokuwiki\HTTP\DokuHTTPClient;
+
/**
* IXR - The Incutio XML-RPC Library
*
diff --git a/inc/Input.class.php b/inc/Input.class.php
deleted file mode 100644
index 199994d8d..000000000
--- a/inc/Input.class.php
+++ /dev/null
@@ -1,335 +0,0 @@
-<?php
-
-/**
- * Encapsulates access to the $_REQUEST array, making sure used parameters are initialized and
- * have the correct type.
- *
- * All function access the $_REQUEST array by default, if you want to access $_POST or $_GET
- * explicitly use the $post and $get members.
- *
- * @author Andreas Gohr <andi@splitbrain.org>
- */
-class Input {
-
- /** @var PostInput Access $_POST parameters */
- public $post;
- /** @var GetInput Access $_GET parameters */
- public $get;
- /** @var ServerInput Access $_SERVER parameters */
- public $server;
-
- protected $access;
-
- /**
- * @var Callable
- */
- protected $filter;
-
- /**
- * Intilizes the Input class and it subcomponents
- */
- function __construct() {
- $this->access = &$_REQUEST;
- $this->post = new PostInput();
- $this->get = new GetInput();
- $this->server = new ServerInput();
- }
-
- /**
- * Apply the set filter to the given value
- *
- * @param string $data
- * @return string
- */
- protected function applyfilter($data){
- if(!$this->filter) return $data;
- return call_user_func($this->filter, $data);
- }
-
- /**
- * Return a filtered copy of the input object
- *
- * Expects a callable that accepts one string parameter and returns a filtered string
- *
- * @param Callable|string $filter
- * @return Input
- */
- public function filter($filter='stripctl'){
- $this->filter = $filter;
- $clone = clone $this;
- $this->filter = '';
- return $clone;
- }
-
- /**
- * Check if a parameter was set
- *
- * Basically a wrapper around isset. When called on the $post and $get subclasses,
- * the parameter is set to $_POST or $_GET and to $_REQUEST
- *
- * @see isset
- * @param string $name Parameter name
- * @return bool
- */
- public function has($name) {
- return isset($this->access[$name]);
- }
-
- /**
- * Remove a parameter from the superglobals
- *
- * Basically a wrapper around unset. When NOT called on the $post and $get subclasses,
- * the parameter will also be removed from $_POST or $_GET
- *
- * @see isset
- * @param string $name Parameter name
- */
- public function remove($name) {
- if(isset($this->access[$name])) {
- unset($this->access[$name]);
- }
- // also remove from sub classes
- if(isset($this->post) && isset($_POST[$name])) {
- unset($_POST[$name]);
- }
- if(isset($this->get) && isset($_GET[$name])) {
- unset($_GET[$name]);
- }
- }
-
- /**
- * Access a request parameter without any type conversion
- *
- * @param string $name Parameter name
- * @param mixed $default Default to return if parameter isn't set
- * @param bool $nonempty Return $default if parameter is set but empty()
- * @return mixed
- */
- public function param($name, $default = null, $nonempty = false) {
- if(!isset($this->access[$name])) return $default;
- $value = $this->applyfilter($this->access[$name]);
- if($nonempty && empty($value)) return $default;
- return $value;
- }
-
- /**
- * Sets a parameter
- *
- * @param string $name Parameter name
- * @param mixed $value Value to set
- */
- public function set($name, $value) {
- $this->access[$name] = $value;
- }
-
- /**
- * Get a reference to a request parameter
- *
- * This avoids copying data in memory, when the parameter is not set it will be created
- * and intialized with the given $default value before a reference is returned
- *
- * @param string $name Parameter name
- * @param mixed $default If parameter is not set, initialize with this value
- * @param bool $nonempty Init with $default if parameter is set but empty()
- * @return mixed (reference)
- */
- public function &ref($name, $default = '', $nonempty = false) {
- if(!isset($this->access[$name]) || ($nonempty && empty($this->access[$name]))) {
- $this->set($name, $default);
- }
-
- return $this->access[$name];
- }
-
- /**
- * Access a request parameter as int
- *
- * @param string $name Parameter name
- * @param int $default Default to return if parameter isn't set or is an array
- * @param bool $nonempty Return $default if parameter is set but empty()
- * @return int
- */
- public function int($name, $default = 0, $nonempty = false) {
- if(!isset($this->access[$name])) return $default;
- if(is_array($this->access[$name])) return $default;
- $value = $this->applyfilter($this->access[$name]);
- if($value === '') return $default;
- if($nonempty && empty($value)) return $default;
-
- return (int) $value;
- }
-
- /**
- * Access a request parameter as string
- *
- * @param string $name Parameter name
- * @param string $default Default to return if parameter isn't set or is an array
- * @param bool $nonempty Return $default if parameter is set but empty()
- * @return string
- */
- public function str($name, $default = '', $nonempty = false) {
- if(!isset($this->access[$name])) return $default;
- if(is_array($this->access[$name])) return $default;
- $value = $this->applyfilter($this->access[$name]);
- if($nonempty && empty($value)) return $default;
-
- return (string) $value;
- }
-
- /**
- * Access a request parameter and make sure it is has a valid value
- *
- * Please note that comparisons to the valid values are not done typesafe (request vars
- * are always strings) however the function will return the correct type from the $valids
- * array when an match was found.
- *
- * @param string $name Parameter name
- * @param array $valids Array of valid values
- * @param mixed $default Default to return if parameter isn't set or not valid
- * @return null|mixed
- */
- public function valid($name, $valids, $default = null) {
- if(!isset($this->access[$name])) return $default;
- if(is_array($this->access[$name])) return $default; // we don't allow arrays
- $value = $this->applyfilter($this->access[$name]);
- $found = array_search($value, $valids);
- if($found !== false) return $valids[$found]; // return the valid value for type safety
- return $default;
- }
-
- /**
- * Access a request parameter as bool
- *
- * Note: $nonempty is here for interface consistency and makes not much sense for booleans
- *
- * @param string $name Parameter name
- * @param mixed $default Default to return if parameter isn't set
- * @param bool $nonempty Return $default if parameter is set but empty()
- * @return bool
- */
- public function bool($name, $default = false, $nonempty = false) {
- if(!isset($this->access[$name])) return $default;
- if(is_array($this->access[$name])) return $default;
- $value = $this->applyfilter($this->access[$name]);
- if($value === '') return $default;
- if($nonempty && empty($value)) return $default;
-
- return (bool) $value;
- }
-
- /**
- * Access a request parameter as array
- *
- * @param string $name Parameter name
- * @param mixed $default Default to return if parameter isn't set
- * @param bool $nonempty Return $default if parameter is set but empty()
- * @return array
- */
- public function arr($name, $default = array(), $nonempty = false) {
- if(!isset($this->access[$name])) return $default;
- if(!is_array($this->access[$name])) return $default;
- if($nonempty && empty($this->access[$name])) return $default;
-
- return (array) $this->access[$name];
- }
-
- /**
- * Create a simple key from an array key
- *
- * This is useful to access keys where the information is given as an array key or as a single array value.
- * For example when the information was submitted as the name of a submit button.
- *
- * This function directly changes the access array.
- *
- * Eg. $_REQUEST['do']['save']='Speichern' becomes $_REQUEST['do'] = 'save'
- *
- * This function returns the $INPUT object itself for easy chaining
- *
- * @param string $name
- * @return Input
- */
- public function extract($name){
- if(!isset($this->access[$name])) return $this;
- if(!is_array($this->access[$name])) return $this;
- $keys = array_keys($this->access[$name]);
- if(!$keys){
- // this was an empty array
- $this->remove($name);
- return $this;
- }
- // get the first key
- $value = array_shift($keys);
- if($value === 0){
- // we had a numeric array, assume the value is not in the key
- $value = array_shift($this->access[$name]);
- }
-
- $this->set($name, $value);
- return $this;
- }
-}
-
-/**
- * Internal class used for $_POST access in Input class
- */
-class PostInput extends Input {
- protected $access;
-
- /**
- * Initialize the $access array, remove subclass members
- */
- function __construct() {
- $this->access = &$_POST;
- }
-
- /**
- * Sets a parameter in $_POST and $_REQUEST
- *
- * @param string $name Parameter name
- * @param mixed $value Value to set
- */
- public function set($name, $value) {
- parent::set($name, $value);
- $_REQUEST[$name] = $value;
- }
-}
-
-/**
- * Internal class used for $_GET access in Input class
- */
-class GetInput extends Input {
- protected $access;
-
- /**
- * Initialize the $access array, remove subclass members
- */
- function __construct() {
- $this->access = &$_GET;
- }
-
- /**
- * Sets a parameter in $_GET and $_REQUEST
- *
- * @param string $name Parameter name
- * @param mixed $value Value to set
- */
- public function set($name, $value) {
- parent::set($name, $value);
- $_REQUEST[$name] = $value;
- }
-}
-
-/**
- * Internal class used for $_SERVER access in Input class
- */
-class ServerInput extends Input {
- protected $access;
-
- /**
- * Initialize the $access array, remove subclass members
- */
- function __construct() {
- $this->access = &$_SERVER;
- }
-
-}
diff --git a/inc/Input/Get.php b/inc/Input/Get.php
new file mode 100644
index 000000000..99ab2655d
--- /dev/null
+++ b/inc/Input/Get.php
@@ -0,0 +1,29 @@
+<?php
+
+namespace dokuwiki\Input;
+
+/**
+ * Internal class used for $_GET access in dokuwiki\Input\Input class
+ */
+class Get extends Input
+{
+ /** @noinspection PhpMissingParentConstructorInspection
+ * Initialize the $access array, remove subclass members
+ */
+ public function __construct()
+ {
+ $this->access = &$_GET;
+ }
+
+ /**
+ * Sets a parameter in $_GET and $_REQUEST
+ *
+ * @param string $name Parameter name
+ * @param mixed $value Value to set
+ */
+ public function set($name, $value)
+ {
+ parent::set($name, $value);
+ $_REQUEST[$name] = $value;
+ }
+}
diff --git a/inc/Input/Input.php b/inc/Input/Input.php
new file mode 100644
index 000000000..3d2426bcc
--- /dev/null
+++ b/inc/Input/Input.php
@@ -0,0 +1,287 @@
+<?php
+
+namespace dokuwiki\Input;
+
+/**
+ * Encapsulates access to the $_REQUEST array, making sure used parameters are initialized and
+ * have the correct type.
+ *
+ * All function access the $_REQUEST array by default, if you want to access $_POST or $_GET
+ * explicitly use the $post and $get members.
+ *
+ * @author Andreas Gohr <andi@splitbrain.org>
+ */
+class Input
+{
+
+ /** @var Post Access $_POST parameters */
+ public $post;
+ /** @var Get Access $_GET parameters */
+ public $get;
+ /** @var Server Access $_SERVER parameters */
+ public $server;
+
+ protected $access;
+
+ /**
+ * @var Callable
+ */
+ protected $filter;
+
+ /**
+ * Intilizes the dokuwiki\Input\Input class and it subcomponents
+ */
+ public function __construct()
+ {
+ $this->access = &$_REQUEST;
+ $this->post = new Post();
+ $this->get = new Get();
+ $this->server = new Server();
+ }
+
+ /**
+ * Apply the set filter to the given value
+ *
+ * @param string $data
+ * @return string
+ */
+ protected function applyfilter($data)
+ {
+ if (!$this->filter) return $data;
+ return call_user_func($this->filter, $data);
+ }
+
+ /**
+ * Return a filtered copy of the input object
+ *
+ * Expects a callable that accepts one string parameter and returns a filtered string
+ *
+ * @param Callable|string $filter
+ * @return Input
+ */
+ public function filter($filter = 'stripctl')
+ {
+ $this->filter = $filter;
+ $clone = clone $this;
+ $this->filter = '';
+ return $clone;
+ }
+
+ /**
+ * Check if a parameter was set
+ *
+ * Basically a wrapper around isset. When called on the $post and $get subclasses,
+ * the parameter is set to $_POST or $_GET and to $_REQUEST
+ *
+ * @see isset
+ * @param string $name Parameter name
+ * @return bool
+ */
+ public function has($name)
+ {
+ return isset($this->access[$name]);
+ }
+
+ /**
+ * Remove a parameter from the superglobals
+ *
+ * Basically a wrapper around unset. When NOT called on the $post and $get subclasses,
+ * the parameter will also be removed from $_POST or $_GET
+ *
+ * @see isset
+ * @param string $name Parameter name
+ */
+ public function remove($name)
+ {
+ if (isset($this->access[$name])) {
+ unset($this->access[$name]);
+ }
+ // also remove from sub classes
+ if (isset($this->post) && isset($_POST[$name])) {
+ unset($_POST[$name]);
+ }
+ if (isset($this->get) && isset($_GET[$name])) {
+ unset($_GET[$name]);
+ }
+ }
+
+ /**
+ * Access a request parameter without any type conversion
+ *
+ * @param string $name Parameter name
+ * @param mixed $default Default to return if parameter isn't set
+ * @param bool $nonempty Return $default if parameter is set but empty()
+ * @return mixed
+ */
+ public function param($name, $default = null, $nonempty = false)
+ {
+ if (!isset($this->access[$name])) return $default;
+ $value = $this->applyfilter($this->access[$name]);
+ if ($nonempty && empty($value)) return $default;
+ return $value;
+ }
+
+ /**
+ * Sets a parameter
+ *
+ * @param string $name Parameter name
+ * @param mixed $value Value to set
+ */
+ public function set($name, $value)
+ {
+ $this->access[$name] = $value;
+ }
+
+ /**
+ * Get a reference to a request parameter
+ *
+ * This avoids copying data in memory, when the parameter is not set it will be created
+ * and intialized with the given $default value before a reference is returned
+ *
+ * @param string $name Parameter name
+ * @param mixed $default If parameter is not set, initialize with this value
+ * @param bool $nonempty Init with $default if parameter is set but empty()
+ * @return mixed (reference)
+ */
+ public function &ref($name, $default = '', $nonempty = false)
+ {
+ if (!isset($this->access[$name]) || ($nonempty && empty($this->access[$name]))) {
+ $this->set($name, $default);
+ }
+
+ return $this->access[$name];
+ }
+
+ /**
+ * Access a request parameter as int
+ *
+ * @param string $name Parameter name
+ * @param int $default Default to return if parameter isn't set or is an array
+ * @param bool $nonempty Return $default if parameter is set but empty()
+ * @return int
+ */
+ public function int($name, $default = 0, $nonempty = false)
+ {
+ if (!isset($this->access[$name])) return $default;
+ if (is_array($this->access[$name])) return $default;
+ $value = $this->applyfilter($this->access[$name]);
+ if ($value === '') return $default;
+ if ($nonempty && empty($value)) return $default;
+
+ return (int)$value;
+ }
+
+ /**
+ * Access a request parameter as string
+ *
+ * @param string $name Parameter name
+ * @param string $default Default to return if parameter isn't set or is an array
+ * @param bool $nonempty Return $default if parameter is set but empty()
+ * @return string
+ */
+ public function str($name, $default = '', $nonempty = false)
+ {
+ if (!isset($this->access[$name])) return $default;
+ if (is_array($this->access[$name])) return $default;
+ $value = $this->applyfilter($this->access[$name]);
+ if ($nonempty && empty($value)) return $default;
+
+ return (string)$value;
+ }
+
+ /**
+ * Access a request parameter and make sure it is has a valid value
+ *
+ * Please note that comparisons to the valid values are not done typesafe (request vars
+ * are always strings) however the function will return the correct type from the $valids
+ * array when an match was found.
+ *
+ * @param string $name Parameter name
+ * @param array $valids Array of valid values
+ * @param mixed $default Default to return if parameter isn't set or not valid
+ * @return null|mixed
+ */
+ public function valid($name, $valids, $default = null)
+ {
+ if (!isset($this->access[$name])) return $default;
+ if (is_array($this->access[$name])) return $default; // we don't allow arrays
+ $value = $this->applyfilter($this->access[$name]);
+ $found = array_search($value, $valids);
+ if ($found !== false) return $valids[$found]; // return the valid value for type safety
+ return $default;
+ }
+
+ /**
+ * Access a request parameter as bool
+ *
+ * Note: $nonempty is here for interface consistency and makes not much sense for booleans
+ *
+ * @param string $name Parameter name
+ * @param mixed $default Default to return if parameter isn't set
+ * @param bool $nonempty Return $default if parameter is set but empty()
+ * @return bool
+ */
+ public function bool($name, $default = false, $nonempty = false)
+ {
+ if (!isset($this->access[$name])) return $default;
+ if (is_array($this->access[$name])) return $default;
+ $value = $this->applyfilter($this->access[$name]);
+ if ($value === '') return $default;
+ if ($nonempty && empty($value)) return $default;
+
+ return (bool)$value;
+ }
+
+ /**
+ * Access a request parameter as array
+ *
+ * @param string $name Parameter name
+ * @param mixed $default Default to return if parameter isn't set
+ * @param bool $nonempty Return $default if parameter is set but empty()
+ * @return array
+ */
+ public function arr($name, $default = array(), $nonempty = false)
+ {
+ if (!isset($this->access[$name])) return $default;
+ if (!is_array($this->access[$name])) return $default;
+ if ($nonempty && empty($this->access[$name])) return $default;
+
+ return (array)$this->access[$name];
+ }
+
+ /**
+ * Create a simple key from an array key
+ *
+ * This is useful to access keys where the information is given as an array key or as a single array value.
+ * For example when the information was submitted as the name of a submit button.
+ *
+ * This function directly changes the access array.
+ *
+ * Eg. $_REQUEST['do']['save']='Speichern' becomes $_REQUEST['do'] = 'save'
+ *
+ * This function returns the $INPUT object itself for easy chaining
+ *
+ * @param string $name
+ * @return Input
+ */
+ public function extract($name)
+ {
+ if (!isset($this->access[$name])) return $this;
+ if (!is_array($this->access[$name])) return $this;
+ $keys = array_keys($this->access[$name]);
+ if (!$keys) {
+ // this was an empty array
+ $this->remove($name);
+ return $this;
+ }
+ // get the first key
+ $value = array_shift($keys);
+ if ($value === 0) {
+ // we had a numeric array, assume the value is not in the key
+ $value = array_shift($this->access[$name]);
+ }
+
+ $this->set($name, $value);
+ return $this;
+ }
+}
diff --git a/inc/Input/Post.php b/inc/Input/Post.php
new file mode 100644
index 000000000..137cd72f4
--- /dev/null
+++ b/inc/Input/Post.php
@@ -0,0 +1,30 @@
+<?php
+
+namespace dokuwiki\Input;
+
+/**
+ * Internal class used for $_POST access in dokuwiki\Input\Input class
+ */
+class Post extends Input
+{
+
+ /** @noinspection PhpMissingParentConstructorInspection
+ * Initialize the $access array, remove subclass members
+ */
+ public function __construct()
+ {
+ $this->access = &$_POST;
+ }
+
+ /**
+ * Sets a parameter in $_POST and $_REQUEST
+ *
+ * @param string $name Parameter name
+ * @param mixed $value Value to set
+ */
+ public function set($name, $value)
+ {
+ parent::set($name, $value);
+ $_REQUEST[$name] = $value;
+ }
+}
diff --git a/inc/Input/Server.php b/inc/Input/Server.php
new file mode 100644
index 000000000..60964fd8f
--- /dev/null
+++ b/inc/Input/Server.php
@@ -0,0 +1,19 @@
+<?php
+
+namespace dokuwiki\Input;
+
+/**
+ * Internal class used for $_SERVER access in dokuwiki\Input\Input class
+ */
+class Server extends Input
+{
+
+ /** @noinspection PhpMissingParentConstructorInspection
+ * Initialize the $access array, remove subclass members
+ */
+ public function __construct()
+ {
+ $this->access = &$_SERVER;
+ }
+
+}
diff --git a/inc/JSON.php b/inc/JSON.php
deleted file mode 100644
index ad2272d09..000000000
--- a/inc/JSON.php
+++ /dev/null
@@ -1,827 +0,0 @@
-<?php
-/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
-
-/**
- * Converts to and from JSON format.
- *
- * JSON (JavaScript Object Notation) is a lightweight data-interchange
- * format. It is easy for humans to read and write. It is easy for machines
- * to parse and generate. It is based on a subset of the JavaScript
- * Programming Language, Standard ECMA-262 3rd Edition - December 1999.
- * This feature can also be found in Python. JSON is a text format that is
- * completely language independent but uses conventions that are familiar
- * to programmers of the C-family of languages, including C, C++, C#, Java,
- * JavaScript, Perl, TCL, and many others. These properties make JSON an
- * ideal data-interchange language.
- *
- * This package provides a simple encoder and decoder for JSON notation. It
- * is intended for use with client-side Javascript applications that make
- * use of HTTPRequest to perform server communication functions - data can
- * be encoded into JSON notation for use in a client-side javascript, or
- * decoded from incoming Javascript requests. JSON format is native to
- * Javascript, and can be directly eval()'ed with no further parsing
- * overhead
- *
- * All strings should be in ASCII or UTF-8 format!
- *
- * LICENSE: Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met: Redistributions of source code must retain the
- * above copyright notice, this list of conditions and the following
- * disclaimer. Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
- * NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
- * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
- * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
- * DAMAGE.
- *
- * @author Michal Migurski <mike-json@teczno.com>
- * @author Matt Knapp <mdknapp[at]gmail[dot]com>
- * @author Brett Stimmerman <brettstimmerman[at]gmail[dot]com>
- * @copyright 2005 Michal Migurski
- * @version CVS: $Id: JSON.php,v 1.31 2006/06/28 05:54:17 migurski Exp $
- * @license http://www.opensource.org/licenses/bsd-license.php
- * @link http://pear.php.net/pepr/pepr-proposal-show.php?id=198
- */
-
-// for DokuWiki
-if(!defined('DOKU_INC')) die('meh.');
-
-/**
- * Default decoding
- */
-define('JSON_STRICT_TYPE', 0);
-
-/**
- * Marker constant for JSON::decode(), used to flag stack state
- */
-define('JSON_SLICE', 1);
-
-/**
- * Marker constant for JSON::decode(), used to flag stack state
- */
-define('JSON_IN_STR', 2);
-
-/**
- * Marker constant for JSON::decode(), used to flag stack state
- */
-define('JSON_IN_ARR', 3);
-
-/**
- * Marker constant for JSON::decode(), used to flag stack state
- */
-define('JSON_IN_OBJ', 4);
-
-/**
- * Marker constant for JSON::decode(), used to flag stack state
- */
-define('JSON_IN_CMT', 5);
-
-/**
- * Behavior switch for JSON::decode()
- */
-define('JSON_LOOSE_TYPE', 16);
-
-/**
- * Behavior switch for JSON::decode()
- */
-define('JSON_SUPPRESS_ERRORS', 32);
-
-/**
- * Converts to and from JSON format.
- *
- * Brief example of use:
- *
- * <code>
- * // create a new instance of JSON
- * $json = new JSON();
- *
- * // convert a complexe value to JSON notation, and send it to the browser
- * $value = array('foo', 'bar', array(1, 2, 'baz'), array(3, array(4)));
- * $output = $json->encode($value);
- *
- * print($output);
- * // prints: ["foo","bar",[1,2,"baz"],[3,[4]]]
- *
- * // accept incoming POST data, assumed to be in JSON notation
- * $input = file_get_contents('php://input', 1000000);
- * $value = $json->decode($input);
- * </code>
- */
-class JSON
-{
- /**
- * Disables the use of PHP5's native json_decode()
- *
- * You shouldn't change this usually because the native function is much
- * faster. However, this non-native will also parse slightly broken JSON
- * which might be handy when talking to a non-conform endpoint
- */
- public $skipnative = false;
-
- /**
- * constructs a new JSON instance
- *
- * @param int $use object behavior flags; combine with boolean-OR
- *
- * possible values:
- * - JSON_LOOSE_TYPE: loose typing.
- * "{...}" syntax creates associative arrays
- * instead of objects in decode().
- * - JSON_SUPPRESS_ERRORS: error suppression.
- * Values which can't be encoded (e.g. resources)
- * appear as NULL instead of throwing errors.
- * By default, a deeply-nested resource will
- * bubble up with an error, so all return values
- * from encode() should be checked with isError()
- */
- function __construct($use = 0)
- {
- $this->use = $use;
- }
-
- /**
- * convert a string from one UTF-16 char to one UTF-8 char
- *
- * Normally should be handled by mb_convert_encoding, but
- * provides a slower PHP-only method for installations
- * that lack the multibye string extension.
- *
- * @param string $utf16 UTF-16 character
- * @return string UTF-8 character
- * @access private
- */
- function utf162utf8($utf16)
- {
- // oh please oh please oh please oh please oh please
- if(function_exists('mb_convert_encoding')) {
- return mb_convert_encoding($utf16, 'UTF-8', 'UTF-16');
- }
-
- $bytes = (ord($utf16{0}) << 8) | ord($utf16{1});
-
- switch(true) {
- case ((0x7F & $bytes) == $bytes):
- // this case should never be reached, because we are in ASCII range
- // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
- return chr(0x7F & $bytes);
-
- case (0x07FF & $bytes) == $bytes:
- // return a 2-byte UTF-8 character
- // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
- return chr(0xC0 | (($bytes >> 6) & 0x1F))
- . chr(0x80 | ($bytes & 0x3F));
-
- case (0xFFFF & $bytes) == $bytes:
- // return a 3-byte UTF-8 character
- // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
- return chr(0xE0 | (($bytes >> 12) & 0x0F))
- . chr(0x80 | (($bytes >> 6) & 0x3F))
- . chr(0x80 | ($bytes & 0x3F));
- }
-
- // ignoring UTF-32 for now, sorry
- return '';
- }
-
- /**
- * convert a string from one UTF-8 char to one UTF-16 char
- *
- * Normally should be handled by mb_convert_encoding, but
- * provides a slower PHP-only method for installations
- * that lack the multibye string extension.
- *
- * @param string $utf8 UTF-8 character
- * @return string UTF-16 character
- * @access private
- */
- function utf82utf16($utf8)
- {
- // oh please oh please oh please oh please oh please
- if(function_exists('mb_convert_encoding')) {
- return mb_convert_encoding($utf8, 'UTF-16', 'UTF-8');
- }
-
- switch(strlen($utf8)) {
- case 1:
- // this case should never be reached, because we are in ASCII range
- // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
- return $utf8;
-
- case 2:
- // return a UTF-16 character from a 2-byte UTF-8 char
- // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
- return chr(0x07 & (ord($utf8{0}) >> 2))
- . chr((0xC0 & (ord($utf8{0}) << 6))
- | (0x3F & ord($utf8{1})));
-
- case 3:
- // return a UTF-16 character from a 3-byte UTF-8 char
- // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
- return chr((0xF0 & (ord($utf8{0}) << 4))
- | (0x0F & (ord($utf8{1}) >> 2)))
- . chr((0xC0 & (ord($utf8{1}) << 6))
- | (0x7F & ord($utf8{2})));
- }
-
- // ignoring UTF-32 for now, sorry
- return '';
- }
-
- /**
- * encodes an arbitrary variable into JSON format
- *
- * @param mixed $var any number, boolean, string, array, or object to be encoded.
- * see argument 1 to JSON() above for array-parsing behavior.
- * if var is a strng, note that encode() always expects it
- * to be in ASCII or UTF-8 format!
- *
- * @return mixed JSON string representation of input var or an error if a problem occurs
- * @access public
- */
- function encode($var)
- {
- if (!$this->skipnative && function_exists('json_encode')){
- return json_encode($var);
- }
-
- switch (gettype($var)) {
- case 'boolean':
- return $var ? 'true' : 'false';
-
- case 'NULL':
- return 'null';
-
- case 'integer':
- return (int) $var;
-
- case 'double':
- case 'float':
- return (float) $var;
-
- case 'string':
- // STRINGS ARE EXPECTED TO BE IN ASCII OR UTF-8 FORMAT
- $ascii = '';
- $strlen_var = strlen($var);
-
- /*
- * Iterate over every character in the string,
- * escaping with a slash or encoding to UTF-8 where necessary
- */
- for ($c = 0; $c < $strlen_var; ++$c) {
-
- $ord_var_c = ord($var{$c});
-
- switch (true) {
- case $ord_var_c == 0x08:
- $ascii .= '\b';
- break;
- case $ord_var_c == 0x09:
- $ascii .= '\t';
- break;
- case $ord_var_c == 0x0A:
- $ascii .= '\n';
- break;
- case $ord_var_c == 0x0C:
- $ascii .= '\f';
- break;
- case $ord_var_c == 0x0D:
- $ascii .= '\r';
- break;
-
- case $ord_var_c == 0x22:
- case $ord_var_c == 0x2F:
- case $ord_var_c == 0x5C:
- // double quote, slash, slosh
- $ascii .= '\\'.$var{$c};
- break;
-
- case (($ord_var_c >= 0x20) && ($ord_var_c <= 0x7F)):
- // characters U-00000000 - U-0000007F (same as ASCII)
- $ascii .= $var{$c};
- break;
-
- case (($ord_var_c & 0xE0) == 0xC0):
- // characters U-00000080 - U-000007FF, mask 110XXXXX
- // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
- $char = pack('C*', $ord_var_c, ord($var{$c + 1}));
- $c += 1;
- $utf16 = $this->utf82utf16($char);
- $ascii .= sprintf('\u%04s', bin2hex($utf16));
- break;
-
- case (($ord_var_c & 0xF0) == 0xE0):
- // characters U-00000800 - U-0000FFFF, mask 1110XXXX
- // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
- $char = pack('C*', $ord_var_c,
- ord($var{$c + 1}),
- ord($var{$c + 2}));
- $c += 2;
- $utf16 = $this->utf82utf16($char);
- $ascii .= sprintf('\u%04s', bin2hex($utf16));
- break;
-
- case (($ord_var_c & 0xF8) == 0xF0):
- // characters U-00010000 - U-001FFFFF, mask 11110XXX
- // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
- $char = pack('C*', $ord_var_c,
- ord($var{$c + 1}),
- ord($var{$c + 2}),
- ord($var{$c + 3}));
- $c += 3;
- $utf16 = $this->utf82utf16($char);
- $ascii .= sprintf('\u%04s', bin2hex($utf16));
- break;
-
- case (($ord_var_c & 0xFC) == 0xF8):
- // characters U-00200000 - U-03FFFFFF, mask 111110XX
- // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
- $char = pack('C*', $ord_var_c,
- ord($var{$c + 1}),
- ord($var{$c + 2}),
- ord($var{$c + 3}),
- ord($var{$c + 4}));
- $c += 4;
- $utf16 = $this->utf82utf16($char);
- $ascii .= sprintf('\u%04s', bin2hex($utf16));
- break;
-
- case (($ord_var_c & 0xFE) == 0xFC):
- // characters U-04000000 - U-7FFFFFFF, mask 1111110X
- // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
- $char = pack('C*', $ord_var_c,
- ord($var{$c + 1}),
- ord($var{$c + 2}),
- ord($var{$c + 3}),
- ord($var{$c + 4}),
- ord($var{$c + 5}));
- $c += 5;
- $utf16 = $this->utf82utf16($char);
- $ascii .= sprintf('\u%04s', bin2hex($utf16));
- break;
- }
- }
-
- return '"'.$ascii.'"';
-
- case 'array':
- /*
- * As per JSON spec if any array key is not an integer
- * we must treat the the whole array as an object. We
- * also try to catch a sparsely populated associative
- * array with numeric keys here because some JS engines
- * will create an array with empty indexes up to
- * max_index which can cause memory issues and because
- * the keys, which may be relevant, will be remapped
- * otherwise.
- *
- * As per the ECMA and JSON specification an object may
- * have any string as a property. Unfortunately due to
- * a hole in the ECMA specification if the key is a
- * ECMA reserved word or starts with a digit the
- * parameter is only accessible using ECMAScript's
- * bracket notation.
- */
-
- // treat as a JSON object
- if (is_array($var) && count($var) && (array_keys($var) !== range(0, sizeof($var) - 1))) {
- $properties = array_map(array($this, 'name_value'),
- array_keys($var),
- array_values($var));
-
- foreach($properties as $property) {
- if(JSON::isError($property)) {
- return $property;
- }
- }
-
- return '{' . join(',', $properties) . '}';
- }
-
- // treat it like a regular array
- $elements = array_map(array($this, 'encode'), $var);
-
- foreach($elements as $element) {
- if(JSON::isError($element)) {
- return $element;
- }
- }
-
- return '[' . join(',', $elements) . ']';
-
- case 'object':
- $vars = get_object_vars($var);
-
- $properties = array_map(array($this, 'name_value'),
- array_keys($vars),
- array_values($vars));
-
- foreach($properties as $property) {
- if(JSON::isError($property)) {
- return $property;
- }
- }
-
- return '{' . join(',', $properties) . '}';
-
- default:
- return ($this->use & JSON_SUPPRESS_ERRORS)
- ? 'null'
- : new JSON_Error(gettype($var)." can not be encoded as JSON string");
- }
- }
-
- /**
- * array-walking function for use in generating JSON-formatted name-value pairs
- *
- * @param string $name name of key to use
- * @param mixed $value reference to an array element to be encoded
- *
- * @return string JSON-formatted name-value pair, like '"name":value'
- * @access private
- */
- function name_value($name, $value)
- {
- $encoded_value = $this->encode($value);
-
- if(JSON::isError($encoded_value)) {
- return $encoded_value;
- }
-
- return $this->encode(strval($name)) . ':' . $encoded_value;
- }
-
- /**
- * reduce a string by removing leading and trailing comments and whitespace
- *
- * @param $str string string value to strip of comments and whitespace
- *
- * @return string string value stripped of comments and whitespace
- * @access private
- */
- function reduce_string($str)
- {
- $str = preg_replace(array(
-
- // eliminate single line comments in '// ...' form
- '#^\s*//(.+)$#m',
-
- // eliminate multi-line comments in '/* ... */' form, at start of string
- '#^\s*/\*(.+)\*/#Us',
-
- // eliminate multi-line comments in '/* ... */' form, at end of string
- '#/\*(.+)\*/\s*$#Us'
-
- ), '', $str);
-
- // eliminate extraneous space
- return trim($str);
- }
-
- /**
- * decodes a JSON string into appropriate variable
- *
- * @param string $str JSON-formatted string
- *
- * @return mixed number, boolean, string, array, or object
- * corresponding to given JSON input string.
- * See argument 1 to JSON() above for object-output behavior.
- * Note that decode() always returns strings
- * in ASCII or UTF-8 format!
- * @access public
- */
- function decode($str)
- {
- if (!$this->skipnative && function_exists('json_decode')){
- return json_decode($str,($this->use == JSON_LOOSE_TYPE));
- }
-
- $str = $this->reduce_string($str);
-
- switch (strtolower($str)) {
- case 'true':
- return true;
-
- case 'false':
- return false;
-
- case 'null':
- return null;
-
- default:
- $m = array();
-
- if (is_numeric($str)) {
- // Lookie-loo, it's a number
-
- // This would work on its own, but I'm trying to be
- // good about returning integers where appropriate:
- // return (float)$str;
-
- // Return float or int, as appropriate
- return ((float)$str == (integer)$str)
- ? (integer)$str
- : (float)$str;
-
- } elseif (preg_match('/^("|\').*(\1)$/s', $str, $m) && $m[1] == $m[2]) {
- // STRINGS RETURNED IN UTF-8 FORMAT
- $delim = substr($str, 0, 1);
- $chrs = substr($str, 1, -1);
- $utf8 = '';
- $strlen_chrs = strlen($chrs);
-
- for ($c = 0; $c < $strlen_chrs; ++$c) {
-
- $substr_chrs_c_2 = substr($chrs, $c, 2);
- $ord_chrs_c = ord($chrs{$c});
-
- switch (true) {
- case $substr_chrs_c_2 == '\b':
- $utf8 .= chr(0x08);
- ++$c;
- break;
- case $substr_chrs_c_2 == '\t':
- $utf8 .= chr(0x09);
- ++$c;
- break;
- case $substr_chrs_c_2 == '\n':
- $utf8 .= chr(0x0A);
- ++$c;
- break;
- case $substr_chrs_c_2 == '\f':
- $utf8 .= chr(0x0C);
- ++$c;
- break;
- case $substr_chrs_c_2 == '\r':
- $utf8 .= chr(0x0D);
- ++$c;
- break;
-
- case $substr_chrs_c_2 == '\\"':
- case $substr_chrs_c_2 == '\\\'':
- case $substr_chrs_c_2 == '\\\\':
- case $substr_chrs_c_2 == '\\/':
- if (($delim == '"' && $substr_chrs_c_2 != '\\\'') ||
- ($delim == "'" && $substr_chrs_c_2 != '\\"')) {
- $utf8 .= $chrs{++$c};
- }
- break;
-
- case preg_match('/\\\u[0-9A-F]{4}/i', substr($chrs, $c, 6)):
- // single, escaped unicode character
- $utf16 = chr(hexdec(substr($chrs, ($c + 2), 2)))
- . chr(hexdec(substr($chrs, ($c + 4), 2)));
- $utf8 .= $this->utf162utf8($utf16);
- $c += 5;
- break;
-
- case ($ord_chrs_c >= 0x20) && ($ord_chrs_c <= 0x7F):
- $utf8 .= $chrs{$c};
- break;
-
- case ($ord_chrs_c & 0xE0) == 0xC0:
- // characters U-00000080 - U-000007FF, mask 110XXXXX
- //see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
- $utf8 .= substr($chrs, $c, 2);
- ++$c;
- break;
-
- case ($ord_chrs_c & 0xF0) == 0xE0:
- // characters U-00000800 - U-0000FFFF, mask 1110XXXX
- // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
- $utf8 .= substr($chrs, $c, 3);
- $c += 2;
- break;
-
- case ($ord_chrs_c & 0xF8) == 0xF0:
- // characters U-00010000 - U-001FFFFF, mask 11110XXX
- // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
- $utf8 .= substr($chrs, $c, 4);
- $c += 3;
- break;
-
- case ($ord_chrs_c & 0xFC) == 0xF8:
- // characters U-00200000 - U-03FFFFFF, mask 111110XX
- // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
- $utf8 .= substr($chrs, $c, 5);
- $c += 4;
- break;
-
- case ($ord_chrs_c & 0xFE) == 0xFC:
- // characters U-04000000 - U-7FFFFFFF, mask 1111110X
- // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
- $utf8 .= substr($chrs, $c, 6);
- $c += 5;
- break;
-
- }
-
- }
-
- return $utf8;
-
- } elseif (preg_match('/^\[.*\]$/s', $str) || preg_match('/^\{.*\}$/s', $str)) {
- // array, or object notation
-
- if ($str{0} == '[') {
- $stk = array(JSON_IN_ARR);
- $arr = array();
- } else {
- if ($this->use & JSON_LOOSE_TYPE) {
- $stk = array(JSON_IN_OBJ);
- $obj = array();
- } else {
- $stk = array(JSON_IN_OBJ);
- $obj = new stdClass();
- }
- }
-
- array_push($stk, array('what' => JSON_SLICE,
- 'where' => 0,
- 'delim' => false));
-
- $chrs = substr($str, 1, -1);
- $chrs = $this->reduce_string($chrs);
-
- if ($chrs == '') {
- if (reset($stk) == JSON_IN_ARR) {
- return $arr;
-
- } else {
- return $obj;
-
- }
- }
-
- //print("\nparsing {$chrs}\n");
-
- $strlen_chrs = strlen($chrs);
-
- for ($c = 0; $c <= $strlen_chrs; ++$c) {
-
- $top = end($stk);
- $substr_chrs_c_2 = substr($chrs, $c, 2);
-
- if (($c == $strlen_chrs) || (($chrs{$c} == ',') && ($top['what'] == JSON_SLICE))) {
- // found a comma that is not inside a string, array, etc.,
- // OR we've reached the end of the character list
- $slice = substr($chrs, $top['where'], ($c - $top['where']));
- array_push($stk, array('what' => JSON_SLICE, 'where' => ($c + 1), 'delim' => false));
- //print("Found split at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
-
- if (reset($stk) == JSON_IN_ARR) {
- // we are in an array, so just push an element onto the stack
- array_push($arr, $this->decode($slice));
-
- } elseif (reset($stk) == JSON_IN_OBJ) {
- // we are in an object, so figure
- // out the property name and set an
- // element in an associative array,
- // for now
- $parts = array();
-
- if (preg_match('/^\s*(["\'].*[^\\\]["\'])\s*:\s*(\S.*),?$/Uis', $slice, $parts)) {
- // "name":value pair
- $key = $this->decode($parts[1]);
- $val = $this->decode($parts[2]);
-
- if ($this->use & JSON_LOOSE_TYPE) {
- $obj[$key] = $val;
- } else {
- $obj->$key = $val;
- }
- } elseif (preg_match('/^\s*(\w+)\s*:\s*(\S.*),?$/Uis', $slice, $parts)) {
- // name:value pair, where name is unquoted
- $key = $parts[1];
- $val = $this->decode($parts[2]);
-
- if ($this->use & JSON_LOOSE_TYPE) {
- $obj[$key] = $val;
- } else {
- $obj->$key = $val;
- }
- }
-
- }
-
- } elseif ((($chrs{$c} == '"') || ($chrs{$c} == "'")) && ($top['what'] != JSON_IN_STR)) {
- // found a quote, and we are not inside a string
- array_push($stk, array('what' => JSON_IN_STR, 'where' => $c, 'delim' => $chrs{$c}));
- //print("Found start of string at {$c}\n");
-
- } elseif (($chrs{$c} == $top['delim']) &&
- ($top['what'] == JSON_IN_STR) &&
- ((strlen(substr($chrs, 0, $c)) - strlen(rtrim(substr($chrs, 0, $c), '\\'))) % 2 != 1)) {
- // found a quote, we're in a string, and it's not escaped
- // we know that it's not escaped becase there is _not_ an
- // odd number of backslashes at the end of the string so far
- array_pop($stk);
- //print("Found end of string at {$c}: ".substr($chrs, $top['where'], (1 + 1 + $c - $top['where']))."\n");
-
- } elseif (($chrs{$c} == '[') &&
- in_array($top['what'], array(JSON_SLICE, JSON_IN_ARR, JSON_IN_OBJ))) {
- // found a left-bracket, and we are in an array, object, or slice
- array_push($stk, array('what' => JSON_IN_ARR, 'where' => $c, 'delim' => false));
- //print("Found start of array at {$c}\n");
-
- } elseif (($chrs{$c} == ']') && ($top['what'] == JSON_IN_ARR)) {
- // found a right-bracket, and we're in an array
- array_pop($stk);
- //print("Found end of array at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
-
- } elseif (($chrs{$c} == '{') &&
- in_array($top['what'], array(JSON_SLICE, JSON_IN_ARR, JSON_IN_OBJ))) {
- // found a left-brace, and we are in an array, object, or slice
- array_push($stk, array('what' => JSON_IN_OBJ, 'where' => $c, 'delim' => false));
- //print("Found start of object at {$c}\n");
-
- } elseif (($chrs{$c} == '}') && ($top['what'] == JSON_IN_OBJ)) {
- // found a right-brace, and we're in an object
- array_pop($stk);
- //print("Found end of object at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
-
- } elseif (($substr_chrs_c_2 == '/*') &&
- in_array($top['what'], array(JSON_SLICE, JSON_IN_ARR, JSON_IN_OBJ))) {
- // found a comment start, and we are in an array, object, or slice
- array_push($stk, array('what' => JSON_IN_CMT, 'where' => $c, 'delim' => false));
- $c++;
- //print("Found start of comment at {$c}\n");
-
- } elseif (($substr_chrs_c_2 == '*/') && ($top['what'] == JSON_IN_CMT)) {
- // found a comment end, and we're in one now
- array_pop($stk);
- $c++;
-
- for ($i = $top['where']; $i <= $c; ++$i)
- $chrs = substr_replace($chrs, ' ', $i, 1);
-
- //print("Found end of comment at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
-
- }
-
- }
-
- if (reset($stk) == JSON_IN_ARR) {
- return $arr;
-
- } elseif (reset($stk) == JSON_IN_OBJ) {
- return $obj;
-
- }
-
- }
- }
- }
-
- /**
- * @todo Ultimately, this should just call PEAR::isError()
- */
- function isError($data, $code = null)
- {
- if (class_exists('pear')) {
- return PEAR::isError($data, $code);
- } elseif (is_object($data) && (get_class($data) == 'JSON_error' ||
- is_subclass_of($data, 'JSON_error'))) {
- return true;
- }
-
- return false;
- }
-}
-
-if (class_exists('PEAR_Error')) {
-
- class JSON_Error extends PEAR_Error
- {
- function __construct($message = 'unknown error', $code = null,
- $mode = null, $options = null, $userinfo = null)
- {
- parent::__construct($message, $code, $mode, $options, $userinfo);
- }
- }
-
-} else {
-
- /**
- * @todo Ultimately, this class shall be descended from PEAR_Error
- */
- class JSON_Error
- {
- function __construct($message = 'unknown error', $code = null,
- $mode = null, $options = null, $userinfo = null)
- {
-
- }
- }
-
-}
diff --git a/inc/JpegMeta.php b/inc/JpegMeta.php
index afc89e49e..b11f07145 100644
--- a/inc/JpegMeta.php
+++ b/inc/JpegMeta.php
@@ -1302,7 +1302,7 @@ class JpegMeta {
function _parseFileInfo() {
if (file_exists($this->_fileName) && is_file($this->_fileName)) {
$this->_info['file'] = array();
- $this->_info['file']['Name'] = utf8_decodeFN(utf8_basename($this->_fileName));
+ $this->_info['file']['Name'] = utf8_decodeFN(\dokuwiki\Utf8\PhpString::basename($this->_fileName));
$this->_info['file']['Path'] = fullpath($this->_fileName);
$this->_info['file']['Size'] = filesize($this->_fileName);
if ($this->_info['file']['Size'] < 1024) {
@@ -1393,7 +1393,7 @@ class JpegMeta {
}
} else {
$this->_info['file'] = array();
- $this->_info['file']['Name'] = utf8_basename($this->_fileName);
+ $this->_info['file']['Name'] = \dokuwiki\Utf8\PhpString::basename($this->_fileName);
$this->_info['file']['Url'] = $this->_fileName;
}
diff --git a/inc/Mailer.class.php b/inc/Mailer.class.php
index 0fdb45a0a..328073bc1 100644
--- a/inc/Mailer.class.php
+++ b/inc/Mailer.class.php
@@ -9,6 +9,8 @@
* @author Andreas Gohr <andi@splitbrain.org>
*/
+use dokuwiki\Extension\Event;
+
// end of line for mail lines - RFC822 says CRLF but postfix (and other MTAs?)
// think different
if(!defined('MAILHEADER_EOL')) define('MAILHEADER_EOL', "\n");
@@ -43,12 +45,12 @@ class Mailer {
global $INPUT;
$server = parse_url(DOKU_URL, PHP_URL_HOST);
- if(strpos($server,'.') === false) $server = $server.'.localhost';
+ if(strpos($server,'.') === false) $server .= '.localhost';
- $this->partid = substr(md5(uniqid(rand(), true)),0, 8).'@'.$server;
- $this->boundary = '__________'.md5(uniqid(rand(), true));
+ $this->partid = substr(md5(uniqid(mt_rand(), true)),0, 8).'@'.$server;
+ $this->boundary = '__________'.md5(uniqid(mt_rand(), true));
- $listid = join('.', array_reverse(explode('/', DOKU_BASE))).$server;
+ $listid = implode('.', array_reverse(explode('/', DOKU_BASE))).$server;
$listid = strtolower(trim($listid, '.'));
$this->allowhtml = (bool)$conf['htmlmail'];
@@ -78,7 +80,7 @@ class Mailer {
*/
public function attachFile($path, $mime, $name = '', $embed = '') {
if(!$name) {
- $name = utf8_basename($path);
+ $name = \dokuwiki\Utf8\PhpString::basename($path);
}
$this->attach[] = array(
@@ -117,7 +119,7 @@ class Mailer {
* @param array $matches
* @return string placeholder
*/
- protected function autoembed_cb($matches) {
+ protected function autoEmbedCallBack($matches) {
static $embeds = 0;
$embeds++;
@@ -186,7 +188,7 @@ class Mailer {
*
* @param string $text plain text body
* @param array $textrep replacements to apply on the text part
- * @param array $htmlrep replacements to apply on the HTML part, null to use $textrep (with urls wrapped in <a> tags)
+ * @param array $htmlrep replacements to apply on the HTML part, null to use $textrep (urls wrapped in <a> tags)
* @param string $html the HTML body, leave null to create it from $text
* @param bool $wrap wrap the HTML in the default header/Footer
*/
@@ -196,17 +198,17 @@ class Mailer {
$textrep = (array)$textrep;
// create HTML from text if not given
- if(is_null($html)) {
+ if($html === null) {
$html = $text;
$html = hsc($html);
$html = preg_replace('/^----+$/m', '<hr >', $html);
$html = nl2br($html);
}
if($wrap) {
- $wrap = rawLocale('mailwrap', 'html');
+ $wrapper = rawLocale('mailwrap', 'html');
$html = preg_replace('/\n-- <br \/>.*$/s', '', $html); //strip signature
$html = str_replace('@EMAILSIGNATURE@', '', $html); //strip @EMAILSIGNATURE@
- $html = str_replace('@HTMLBODY@', $html, $wrap);
+ $html = str_replace('@HTMLBODY@', $html, $wrapper);
}
if(strpos($text, '@EMAILSIGNATURE@') === false) {
@@ -226,7 +228,7 @@ class Mailer {
// embed media from templates
$html = preg_replace_callback(
'/@MEDIA\(([^\)]+)\)@/',
- array($this, 'autoembed_cb'), $html
+ array($this, 'autoEmbedCallBack'), $html
);
// add default token replacements
@@ -385,7 +387,7 @@ class Mailer {
}
// FIXME: is there a way to encode the localpart of a emailaddress?
- if(!utf8_isASCII($addr)) {
+ if(!\dokuwiki\Utf8\Clean::isASCII($addr)) {
msg(hsc("E-Mail address <$addr> is not ASCII"), -1);
continue;
}
@@ -401,11 +403,11 @@ class Mailer {
$addr = "<$addr>";
if(defined('MAILHEADER_ASCIIONLY')) {
- $text = utf8_deaccent($text);
- $text = utf8_strip($text);
+ $text = \dokuwiki\Utf8\Clean::deaccent($text);
+ $text = \dokuwiki\Utf8\Clean::strip($text);
}
- if(strpos($text, ',') !== false || !utf8_isASCII($text)) {
+ if(strpos($text, ',') !== false || !\dokuwiki\Utf8\Clean::isASCII($text)) {
$text = '=?UTF-8?B?'.base64_encode($text).'?=';
}
} else {
@@ -551,10 +553,10 @@ class Mailer {
if(isset($this->headers['Subject'])) {
// add prefix to subject
if(empty($conf['mailprefix'])) {
- if(utf8_strlen($conf['title']) < 20) {
+ if(\dokuwiki\Utf8\PhpString::strlen($conf['title']) < 20) {
$prefix = '['.$conf['title'].']';
} else {
- $prefix = '['.utf8_substr($conf['title'], 0, 20).'...]';
+ $prefix = '['.\dokuwiki\Utf8\PhpString::substr($conf['title'], 0, 20).'...]';
}
} else {
$prefix = '['.$conf['mailprefix'].']';
@@ -566,10 +568,10 @@ class Mailer {
// encode subject
if(defined('MAILHEADER_ASCIIONLY')) {
- $this->headers['Subject'] = utf8_deaccent($this->headers['Subject']);
- $this->headers['Subject'] = utf8_strip($this->headers['Subject']);
+ $this->headers['Subject'] = \dokuwiki\Utf8\Clean::deaccent($this->headers['Subject']);
+ $this->headers['Subject'] = \dokuwiki\Utf8\Clean::strip($this->headers['Subject']);
}
- if(!utf8_isASCII($this->headers['Subject'])) {
+ if(!\dokuwiki\Utf8\Clean::isASCII($this->headers['Subject'])) {
$this->headers['Subject'] = '=?UTF-8?B?'.base64_encode($this->headers['Subject']).'?=';
}
}
@@ -595,7 +597,7 @@ class Mailer {
protected function prepareHeaders() {
$headers = '';
foreach($this->headers as $key => $val) {
- if ($val === '' || is_null($val)) continue;
+ if ($val === '' || $val === null) continue;
$headers .= $this->wrappedHeaderLine($key, $val);
}
return $headers;
@@ -645,7 +647,11 @@ class Mailer {
'NAME' => $INFO['userinfo']['name'],
'MAIL' => $INFO['userinfo']['mail']
);
- $signature = str_replace('@DOKUWIKIURL@', $this->replacements['text']['DOKUWIKIURL'], $lang['email_signature_text']);
+ $signature = str_replace(
+ '@DOKUWIKIURL@',
+ $this->replacements['text']['DOKUWIKIURL'],
+ $lang['email_signature_text']
+ );
$this->replacements['text']['EMAILSIGNATURE'] = "\n-- \n" . $signature . "\n";
$this->replacements['html'] = array(
@@ -707,7 +713,7 @@ class Mailer {
);
// do our thing if BEFORE hook approves
- $evt = new Doku_Event('MAIL_MESSAGE_SEND', $data);
+ $evt = new Event('MAIL_MESSAGE_SEND', $data);
if($evt->advise_before(true)) {
// clean up before using the headers
$this->cleanHeaders();
@@ -746,7 +752,7 @@ class Mailer {
}
// send the thing
- if(is_null($this->sendparam)) {
+ if($this->sendparam === null) {
$success = @mail($to, $subject, $body, $headers);
} else {
$success = @mail($to, $subject, $body, $headers, $this->sendparam);
diff --git a/inc/Manifest.php b/inc/Manifest.php
index 843c67265..29e7f263f 100644
--- a/inc/Manifest.php
+++ b/inc/Manifest.php
@@ -2,6 +2,8 @@
namespace dokuwiki;
+use dokuwiki\Extension\Event;
+
class Manifest
{
public function sendManifest()
@@ -37,7 +39,9 @@ class Manifest
}
if (empty($manifest['theme_color'])) {
- $manifest['theme_color'] = !empty($replacements['__theme_color__']) ? $replacements['__theme_color__'] : $replacements['__background_alt__'];
+ $manifest['theme_color'] = !empty($replacements['__theme_color__'])
+ ? $replacements['__theme_color__']
+ : $replacements['__background_alt__'];
}
if (empty($manifest['icons'])) {
@@ -72,7 +76,7 @@ class Manifest
}
}
- trigger_event('MANIFEST_SEND', $manifest);
+ Event::createAndTrigger('MANIFEST_SEND', $manifest);
header('Content-Type: application/manifest+json');
echo json_encode($manifest);
diff --git a/inc/Menu/AbstractMenu.php b/inc/Menu/AbstractMenu.php
index ce021ab64..37e5d2cc3 100644
--- a/inc/Menu/AbstractMenu.php
+++ b/inc/Menu/AbstractMenu.php
@@ -2,6 +2,7 @@
namespace dokuwiki\Menu;
+use dokuwiki\Extension\Event;
use dokuwiki\Menu\Item\AbstractItem;
/**
@@ -42,7 +43,7 @@ abstract class AbstractMenu implements MenuInterface {
'view' => $this->view,
'items' => array(),
);
- trigger_event('MENU_ITEMS_ASSEMBLY', $data, array($this, 'loadItems'));
+ Event::createAndTrigger('MENU_ITEMS_ASSEMBLY', $data, array($this, 'loadItems'));
return $data['items'];
}
diff --git a/inc/Parsing/Handler/Block.php b/inc/Parsing/Handler/Block.php
new file mode 100644
index 000000000..4cfa686d4
--- /dev/null
+++ b/inc/Parsing/Handler/Block.php
@@ -0,0 +1,211 @@
+<?php
+
+namespace dokuwiki\Parsing\Handler;
+
+/**
+ * Handler for paragraphs
+ *
+ * @author Harry Fuecks <hfuecks@gmail.com>
+ */
+class Block
+{
+ protected $calls = array();
+ protected $skipEol = false;
+ protected $inParagraph = false;
+
+ // Blocks these should not be inside paragraphs
+ protected $blockOpen = array(
+ 'header',
+ 'listu_open','listo_open','listitem_open','listcontent_open',
+ 'table_open','tablerow_open','tablecell_open','tableheader_open','tablethead_open',
+ 'quote_open',
+ 'code','file','hr','preformatted','rss',
+ 'htmlblock','phpblock',
+ 'footnote_open',
+ );
+
+ protected $blockClose = array(
+ 'header',
+ 'listu_close','listo_close','listitem_close','listcontent_close',
+ 'table_close','tablerow_close','tablecell_close','tableheader_close','tablethead_close',
+ 'quote_close',
+ 'code','file','hr','preformatted','rss',
+ 'htmlblock','phpblock',
+ 'footnote_close',
+ );
+
+ // Stacks can contain paragraphs
+ protected $stackOpen = array(
+ 'section_open',
+ );
+
+ protected $stackClose = array(
+ 'section_close',
+ );
+
+
+ /**
+ * Constructor. Adds loaded syntax plugins to the block and stack
+ * arrays
+ *
+ * @author Andreas Gohr <andi@splitbrain.org>
+ */
+ public function __construct()
+ {
+ global $DOKU_PLUGINS;
+ //check if syntax plugins were loaded
+ if (empty($DOKU_PLUGINS['syntax'])) return;
+ foreach ($DOKU_PLUGINS['syntax'] as $n => $p) {
+ $ptype = $p->getPType();
+ if ($ptype == 'block') {
+ $this->blockOpen[] = 'plugin_'.$n;
+ $this->blockClose[] = 'plugin_'.$n;
+ } elseif ($ptype == 'stack') {
+ $this->stackOpen[] = 'plugin_'.$n;
+ $this->stackClose[] = 'plugin_'.$n;
+ }
+ }
+ }
+
+ protected function openParagraph($pos)
+ {
+ if ($this->inParagraph) return;
+ $this->calls[] = array('p_open',array(), $pos);
+ $this->inParagraph = true;
+ $this->skipEol = true;
+ }
+
+ /**
+ * Close a paragraph if needed
+ *
+ * This function makes sure there are no empty paragraphs on the stack
+ *
+ * @author Andreas Gohr <andi@splitbrain.org>
+ *
+ * @param string|integer $pos
+ */
+ protected function closeParagraph($pos)
+ {
+ if (!$this->inParagraph) return;
+ // look back if there was any content - we don't want empty paragraphs
+ $content = '';
+ $ccount = count($this->calls);
+ for ($i=$ccount-1; $i>=0; $i--) {
+ if ($this->calls[$i][0] == 'p_open') {
+ break;
+ } elseif ($this->calls[$i][0] == 'cdata') {
+ $content .= $this->calls[$i][1][0];
+ } else {
+ $content = 'found markup';
+ break;
+ }
+ }
+
+ if (trim($content)=='') {
+ //remove the whole paragraph
+ //array_splice($this->calls,$i); // <- this is much slower than the loop below
+ for ($x=$ccount; $x>$i;
+ $x--) array_pop($this->calls);
+ } else {
+ // remove ending linebreaks in the paragraph
+ $i=count($this->calls)-1;
+ if ($this->calls[$i][0] == 'cdata') $this->calls[$i][1][0] = rtrim($this->calls[$i][1][0], "\n");
+ $this->calls[] = array('p_close',array(), $pos);
+ }
+
+ $this->inParagraph = false;
+ $this->skipEol = true;
+ }
+
+ protected function addCall($call)
+ {
+ $key = count($this->calls);
+ if ($key and ($call[0] == 'cdata') and ($this->calls[$key-1][0] == 'cdata')) {
+ $this->calls[$key-1][1][0] .= $call[1][0];
+ } else {
+ $this->calls[] = $call;
+ }
+ }
+
+ // simple version of addCall, without checking cdata
+ protected function storeCall($call)
+ {
+ $this->calls[] = $call;
+ }
+
+ /**
+ * Processes the whole instruction stack to open and close paragraphs
+ *
+ * @author Harry Fuecks <hfuecks@gmail.com>
+ * @author Andreas Gohr <andi@splitbrain.org>
+ *
+ * @param array $calls
+ *
+ * @return array
+ */
+ public function process($calls)
+ {
+ // open first paragraph
+ $this->openParagraph(0);
+ foreach ($calls as $key => $call) {
+ $cname = $call[0];
+ if ($cname == 'plugin') {
+ $cname='plugin_'.$call[1][0];
+ $plugin = true;
+ $plugin_open = (($call[1][2] == DOKU_LEXER_ENTER) || ($call[1][2] == DOKU_LEXER_SPECIAL));
+ $plugin_close = (($call[1][2] == DOKU_LEXER_EXIT) || ($call[1][2] == DOKU_LEXER_SPECIAL));
+ } else {
+ $plugin = false;
+ }
+ /* stack */
+ if (in_array($cname, $this->stackClose) && (!$plugin || $plugin_close)) {
+ $this->closeParagraph($call[2]);
+ $this->storeCall($call);
+ $this->openParagraph($call[2]);
+ continue;
+ }
+ if (in_array($cname, $this->stackOpen) && (!$plugin || $plugin_open)) {
+ $this->closeParagraph($call[2]);
+ $this->storeCall($call);
+ $this->openParagraph($call[2]);
+ continue;
+ }
+ /* block */
+ // If it's a substition it opens and closes at the same call.
+ // To make sure next paragraph is correctly started, let close go first.
+ if (in_array($cname, $this->blockClose) && (!$plugin || $plugin_close)) {
+ $this->closeParagraph($call[2]);
+ $this->storeCall($call);
+ $this->openParagraph($call[2]);
+ continue;
+ }
+ if (in_array($cname, $this->blockOpen) && (!$plugin || $plugin_open)) {
+ $this->closeParagraph($call[2]);
+ $this->storeCall($call);
+ continue;
+ }
+ /* eol */
+ if ($cname == 'eol') {
+ // Check this isn't an eol instruction to skip...
+ if (!$this->skipEol) {
+ // Next is EOL => double eol => mark as paragraph
+ if (isset($calls[$key+1]) && $calls[$key+1][0] == 'eol') {
+ $this->closeParagraph($call[2]);
+ $this->openParagraph($call[2]);
+ } else {
+ //if this is just a single eol make a space from it
+ $this->addCall(array('cdata',array("\n"), $call[2]));
+ }
+ }
+ continue;
+ }
+ /* normal */
+ $this->addCall($call);
+ $this->skipEol = false;
+ }
+ // close last paragraph
+ $call = end($this->calls);
+ $this->closeParagraph($call[2]);
+ return $this->calls;
+ }
+}
diff --git a/inc/Parsing/Handler/CallWriter.php b/inc/Parsing/Handler/CallWriter.php
new file mode 100644
index 000000000..2457143ed
--- /dev/null
+++ b/inc/Parsing/Handler/CallWriter.php
@@ -0,0 +1,40 @@
+<?php
+
+namespace dokuwiki\Parsing\Handler;
+
+class CallWriter implements CallWriterInterface
+{
+
+ /** @var \Doku_Handler $Handler */
+ protected $Handler;
+
+ /**
+ * @param \Doku_Handler $Handler
+ */
+ public function __construct(\Doku_Handler $Handler)
+ {
+ $this->Handler = $Handler;
+ }
+
+ /** @inheritdoc */
+ public function writeCall($call)
+ {
+ $this->Handler->calls[] = $call;
+ }
+
+ /** @inheritdoc */
+ public function writeCalls($calls)
+ {
+ $this->Handler->calls = array_merge($this->Handler->calls, $calls);
+ }
+
+ /**
+ * @inheritdoc
+ * function is required, but since this call writer is first/highest in
+ * the chain it is not required to do anything
+ */
+ public function finalise()
+ {
+ unset($this->Handler);
+ }
+}
diff --git a/inc/Parsing/Handler/CallWriterInterface.php b/inc/Parsing/Handler/CallWriterInterface.php
new file mode 100644
index 000000000..1ade7c060
--- /dev/null
+++ b/inc/Parsing/Handler/CallWriterInterface.php
@@ -0,0 +1,30 @@
+<?php
+
+namespace dokuwiki\Parsing\Handler;
+
+interface CallWriterInterface
+{
+ /**
+ * Add a call to our call list
+ *
+ * @param $call the call to be added
+ */
+ public function writeCall($call);
+
+ /**
+ * Append a list of calls to our call list
+ *
+ * @param $calls list of calls to be appended
+ */
+ public function writeCalls($calls);
+
+ /**
+ * Explicit request to finish up and clean up NOW!
+ * (probably because document end has been reached)
+ *
+ * If part of a CallWriter chain, call finalise on
+ * the original call writer
+ *
+ */
+ public function finalise();
+}
diff --git a/inc/Parsing/Handler/Lists.php b/inc/Parsing/Handler/Lists.php
new file mode 100644
index 000000000..c4428fe46
--- /dev/null
+++ b/inc/Parsing/Handler/Lists.php
@@ -0,0 +1,213 @@
+<?php
+
+namespace dokuwiki\Parsing\Handler;
+
+class Lists implements ReWriterInterface
+{
+
+ /** @var CallWriterInterface original call writer */
+ protected $callWriter;
+
+ protected $calls = array();
+ protected $listCalls = array();
+ protected $listStack = array();
+
+ protected $initialDepth = 0;
+
+ const NODE = 1;
+
+
+ /** @inheritdoc */
+ public function __construct(CallWriterInterface $CallWriter)
+ {
+ $this->callWriter = $CallWriter;
+ }
+
+ /** @inheritdoc */
+ public function writeCall($call)
+ {
+ $this->calls[] = $call;
+ }
+
+ /**
+ * @inheritdoc
+ * Probably not needed but just in case...
+ */
+ public function writeCalls($calls)
+ {
+ $this->calls = array_merge($this->calls, $calls);
+ }
+
+ /** @inheritdoc */
+ public function finalise()
+ {
+ $last_call = end($this->calls);
+ $this->writeCall(array('list_close',array(), $last_call[2]));
+
+ $this->process();
+ $this->callWriter->finalise();
+ unset($this->callWriter);
+ }
+
+ /** @inheritdoc */
+ public function process()
+ {
+
+ foreach ($this->calls as $call) {
+ switch ($call[0]) {
+ case 'list_item':
+ $this->listOpen($call);
+ break;
+ case 'list_open':
+ $this->listStart($call);
+ break;
+ case 'list_close':
+ $this->listEnd($call);
+ break;
+ default:
+ $this->listContent($call);
+ break;
+ }
+ }
+
+ $this->callWriter->writeCalls($this->listCalls);
+ return $this->callWriter;
+ }
+
+ protected function listStart($call)
+ {
+ $depth = $this->interpretSyntax($call[1][0], $listType);
+
+ $this->initialDepth = $depth;
+ // array(list type, current depth, index of current listitem_open)
+ $this->listStack[] = array($listType, $depth, 1);
+
+ $this->listCalls[] = array('list'.$listType.'_open',array(),$call[2]);
+ $this->listCalls[] = array('listitem_open',array(1),$call[2]);
+ $this->listCalls[] = array('listcontent_open',array(),$call[2]);
+ }
+
+
+ protected function listEnd($call)
+ {
+ $closeContent = true;
+
+ while ($list = array_pop($this->listStack)) {
+ if ($closeContent) {
+ $this->listCalls[] = array('listcontent_close',array(),$call[2]);
+ $closeContent = false;
+ }
+ $this->listCalls[] = array('listitem_close',array(),$call[2]);
+ $this->listCalls[] = array('list'.$list[0].'_close', array(), $call[2]);
+ }
+ }
+
+ protected function listOpen($call)
+ {
+ $depth = $this->interpretSyntax($call[1][0], $listType);
+ $end = end($this->listStack);
+ $key = key($this->listStack);
+
+ // Not allowed to be shallower than initialDepth
+ if ($depth < $this->initialDepth) {
+ $depth = $this->initialDepth;
+ }
+
+ if ($depth == $end[1]) {
+ // Just another item in the list...
+ if ($listType == $end[0]) {
+ $this->listCalls[] = array('listcontent_close',array(),$call[2]);
+ $this->listCalls[] = array('listitem_close',array(),$call[2]);
+ $this->listCalls[] = array('listitem_open',array($depth-1),$call[2]);
+ $this->listCalls[] = array('listcontent_open',array(),$call[2]);
+
+ // new list item, update list stack's index into current listitem_open
+ $this->listStack[$key][2] = count($this->listCalls) - 2;
+
+ // Switched list type...
+ } else {
+ $this->listCalls[] = array('listcontent_close',array(),$call[2]);
+ $this->listCalls[] = array('listitem_close',array(),$call[2]);
+ $this->listCalls[] = array('list'.$end[0].'_close', array(), $call[2]);
+ $this->listCalls[] = array('list'.$listType.'_open', array(), $call[2]);
+ $this->listCalls[] = array('listitem_open', array($depth-1), $call[2]);
+ $this->listCalls[] = array('listcontent_open',array(),$call[2]);
+
+ array_pop($this->listStack);
+ $this->listStack[] = array($listType, $depth, count($this->listCalls) - 2);
+ }
+ } elseif ($depth > $end[1]) { // Getting deeper...
+ $this->listCalls[] = array('listcontent_close',array(),$call[2]);
+ $this->listCalls[] = array('list'.$listType.'_open', array(), $call[2]);
+ $this->listCalls[] = array('listitem_open', array($depth-1), $call[2]);
+ $this->listCalls[] = array('listcontent_open',array(),$call[2]);
+
+ // set the node/leaf state of this item's parent listitem_open to NODE
+ $this->listCalls[$this->listStack[$key][2]][1][1] = self::NODE;
+
+ $this->listStack[] = array($listType, $depth, count($this->listCalls) - 2);
+ } else { // Getting shallower ( $depth < $end[1] )
+ $this->listCalls[] = array('listcontent_close',array(),$call[2]);
+ $this->listCalls[] = array('listitem_close',array(),$call[2]);
+ $this->listCalls[] = array('list'.$end[0].'_close',array(),$call[2]);
+
+ // Throw away the end - done
+ array_pop($this->listStack);
+
+ while (1) {
+ $end = end($this->listStack);
+ $key = key($this->listStack);
+
+ if ($end[1] <= $depth) {
+ // Normalize depths
+ $depth = $end[1];
+
+ $this->listCalls[] = array('listitem_close',array(),$call[2]);
+
+ if ($end[0] == $listType) {
+ $this->listCalls[] = array('listitem_open',array($depth-1),$call[2]);
+ $this->listCalls[] = array('listcontent_open',array(),$call[2]);
+
+ // new list item, update list stack's index into current listitem_open
+ $this->listStack[$key][2] = count($this->listCalls) - 2;
+ } else {
+ // Switching list type...
+ $this->listCalls[] = array('list'.$end[0].'_close', array(), $call[2]);
+ $this->listCalls[] = array('list'.$listType.'_open', array(), $call[2]);
+ $this->listCalls[] = array('listitem_open', array($depth-1), $call[2]);
+ $this->listCalls[] = array('listcontent_open',array(),$call[2]);
+
+ array_pop($this->listStack);
+ $this->listStack[] = array($listType, $depth, count($this->listCalls) - 2);
+ }
+
+ break;
+
+ // Haven't dropped down far enough yet.... ( $end[1] > $depth )
+ } else {
+ $this->listCalls[] = array('listitem_close',array(),$call[2]);
+ $this->listCalls[] = array('list'.$end[0].'_close',array(),$call[2]);
+
+ array_pop($this->listStack);
+ }
+ }
+ }
+ }
+
+ protected function listContent($call)
+ {
+ $this->listCalls[] = $call;
+ }
+
+ protected function interpretSyntax($match, & $type)
+ {
+ if (substr($match, -1) == '*') {
+ $type = 'u';
+ } else {
+ $type = 'o';
+ }
+ // Is the +1 needed? It used to be count(explode(...))
+ // but I don't think the number is seen outside this handler
+ return substr_count(str_replace("\t", ' ', $match), ' ') + 1;
+ }
+}
diff --git a/inc/Parsing/Handler/Nest.php b/inc/Parsing/Handler/Nest.php
new file mode 100644
index 000000000..b0044a3cb
--- /dev/null
+++ b/inc/Parsing/Handler/Nest.php
@@ -0,0 +1,83 @@
+<?php
+
+namespace dokuwiki\Parsing\Handler;
+
+/**
+ * Generic call writer class to handle nesting of rendering instructions
+ * within a render instruction. Also see nest() method of renderer base class
+ *
+ * @author Chris Smith <chris@jalakai.co.uk>
+ */
+class Nest implements ReWriterInterface
+{
+
+ /** @var CallWriterInterface original CallWriter */
+ protected $callWriter;
+
+ protected $calls = array();
+ protected $closingInstruction;
+
+ /**
+ * @inheritdoc
+ *
+ * @param CallWriterInterface $CallWriter the parser's current call writer, i.e. the one above us in the chain
+ * @param string $close closing instruction name, this is required to properly terminate the
+ * syntax mode if the document ends without a closing pattern
+ */
+ public function __construct(CallWriterInterface $CallWriter, $close = "nest_close")
+ {
+ $this->callWriter = $CallWriter;
+
+ $this->closingInstruction = $close;
+ }
+
+ /** @inheritdoc */
+ public function writeCall($call)
+ {
+ $this->calls[] = $call;
+ }
+
+ /** @inheritdoc */
+ public function writeCalls($calls)
+ {
+ $this->calls = array_merge($this->calls, $calls);
+ }
+
+ /** @inheritdoc */
+ public function finalise()
+ {
+ $last_call = end($this->calls);
+ $this->writeCall(array($this->closingInstruction,array(), $last_call[2]));
+
+ $this->process();
+ $this->callWriter->finalise();
+ unset($this->callWriter);
+ }
+
+ /** @inheritdoc */
+ public function process()
+ {
+ // merge consecutive cdata
+ $unmerged_calls = $this->calls;
+ $this->calls = array();
+
+ foreach ($unmerged_calls as $call) $this->addCall($call);
+
+ $first_call = reset($this->calls);
+ $this->callWriter->writeCall(array("nest", array($this->calls), $first_call[2]));
+
+ return $this->callWriter;
+ }
+
+ protected function addCall($call)
+ {
+ $key = count($this->calls);
+ if ($key and ($call[0] == 'cdata') and ($this->calls[$key-1][0] == 'cdata')) {
+ $this->calls[$key-1][1][0] .= $call[1][0];
+ } elseif ($call[0] == 'eol') {
+ // do nothing (eol shouldn't be allowed, to counter preformatted fix in #1652 & #1699)
+ } else {
+ $this->calls[] = $call;
+ }
+ }
+}
diff --git a/inc/Parsing/Handler/Preformatted.php b/inc/Parsing/Handler/Preformatted.php
new file mode 100644
index 000000000..a668771a7
--- /dev/null
+++ b/inc/Parsing/Handler/Preformatted.php
@@ -0,0 +1,76 @@
+<?php
+
+namespace dokuwiki\Parsing\Handler;
+
+class Preformatted implements ReWriterInterface
+{
+
+ /** @var CallWriterInterface original call writer */
+ protected $callWriter;
+
+ protected $calls = array();
+ protected $pos;
+ protected $text ='';
+
+ /**
+ * @inheritdoc
+ */
+ public function __construct(CallWriterInterface $CallWriter)
+ {
+ $this->callWriter = $CallWriter;
+ }
+
+ /** @inheritdoc */
+ public function writeCall($call)
+ {
+ $this->calls[] = $call;
+ }
+
+ /**
+ * @inheritdoc
+ * Probably not needed but just in case...
+ */
+ public function writeCalls($calls)
+ {
+ $this->calls = array_merge($this->calls, $calls);
+ }
+
+ /** @inheritdoc */
+ public function finalise()
+ {
+ $last_call = end($this->calls);
+ $this->writeCall(array('preformatted_end',array(), $last_call[2]));
+
+ $this->process();
+ $this->callWriter->finalise();
+ unset($this->callWriter);
+ }
+
+ /** @inheritdoc */
+ public function process()
+ {
+ foreach ($this->calls as $call) {
+ switch ($call[0]) {
+ case 'preformatted_start':
+ $this->pos = $call[2];
+ break;
+ case 'preformatted_newline':
+ $this->text .= "\n";
+ break;
+ case 'preformatted_content':
+ $this->text .= $call[1][0];
+ break;
+ case 'preformatted_end':
+ if (trim($this->text)) {
+ $this->callWriter->writeCall(array('preformatted', array($this->text), $this->pos));
+ }
+ // see FS#1699 & FS#1652, add 'eol' instructions to ensure proper triggering of following p_open
+ $this->callWriter->writeCall(array('eol', array(), $this->pos));
+ $this->callWriter->writeCall(array('eol', array(), $this->pos));
+ break;
+ }
+ }
+
+ return $this->callWriter;
+ }
+}
diff --git a/inc/Parsing/Handler/Quote.php b/inc/Parsing/Handler/Quote.php
new file mode 100644
index 000000000..a786d10c0
--- /dev/null
+++ b/inc/Parsing/Handler/Quote.php
@@ -0,0 +1,110 @@
+<?php
+
+namespace dokuwiki\Parsing\Handler;
+
+class Quote implements ReWriterInterface
+{
+
+ /** @var CallWriterInterface original CallWriter */
+ protected $callWriter;
+
+ protected $calls = array();
+
+ protected $quoteCalls = array();
+
+ /** @inheritdoc */
+ public function __construct(CallWriterInterface $CallWriter)
+ {
+ $this->callWriter = $CallWriter;
+ }
+
+ /** @inheritdoc */
+ public function writeCall($call)
+ {
+ $this->calls[] = $call;
+ }
+
+ /**
+ * @inheritdoc
+ *
+ * Probably not needed but just in case...
+ */
+ public function writeCalls($calls)
+ {
+ $this->calls = array_merge($this->calls, $calls);
+ }
+
+ /** @inheritdoc */
+ public function finalise()
+ {
+ $last_call = end($this->calls);
+ $this->writeCall(array('quote_end',array(), $last_call[2]));
+
+ $this->process();
+ $this->callWriter->finalise();
+ unset($this->callWriter);
+ }
+
+ /** @inheritdoc */
+ public function process()
+ {
+
+ $quoteDepth = 1;
+
+ foreach ($this->calls as $call) {
+ switch ($call[0]) {
+
+ /** @noinspection PhpMissingBreakStatementInspection */
+ case 'quote_start':
+ $this->quoteCalls[] = array('quote_open',array(),$call[2]);
+ // fallthrough
+ case 'quote_newline':
+ $quoteLength = $this->getDepth($call[1][0]);
+
+ if ($quoteLength > $quoteDepth) {
+ $quoteDiff = $quoteLength - $quoteDepth;
+ for ($i = 1; $i <= $quoteDiff; $i++) {
+ $this->quoteCalls[] = array('quote_open',array(),$call[2]);
+ }
+ } elseif ($quoteLength < $quoteDepth) {
+ $quoteDiff = $quoteDepth - $quoteLength;
+ for ($i = 1; $i <= $quoteDiff; $i++) {
+ $this->quoteCalls[] = array('quote_close',array(),$call[2]);
+ }
+ } else {
+ if ($call[0] != 'quote_start') $this->quoteCalls[] = array('linebreak',array(),$call[2]);
+ }
+
+ $quoteDepth = $quoteLength;
+
+ break;
+
+ case 'quote_end':
+ if ($quoteDepth > 1) {
+ $quoteDiff = $quoteDepth - 1;
+ for ($i = 1; $i <= $quoteDiff; $i++) {
+ $this->quoteCalls[] = array('quote_close',array(),$call[2]);
+ }
+ }
+
+ $this->quoteCalls[] = array('quote_close',array(),$call[2]);
+
+ $this->callWriter->writeCalls($this->quoteCalls);
+ break;
+
+ default:
+ $this->quoteCalls[] = $call;
+ break;
+ }
+ }
+
+ return $this->callWriter;
+ }
+
+ protected function getDepth($marker)
+ {
+ preg_match('/>{1,}/', $marker, $matches);
+ $quoteLength = strlen($matches[0]);
+ return $quoteLength;
+ }
+}
diff --git a/inc/Parsing/Handler/ReWriterInterface.php b/inc/Parsing/Handler/ReWriterInterface.php
new file mode 100644
index 000000000..13f7b48e3
--- /dev/null
+++ b/inc/Parsing/Handler/ReWriterInterface.php
@@ -0,0 +1,29 @@
+<?php
+
+namespace dokuwiki\Parsing\Handler;
+
+/**
+ * A ReWriter takes over from the orignal call writer and handles all new calls itself until
+ * the process method is called and control is given back to the original writer.
+ */
+interface ReWriterInterface extends CallWriterInterface
+{
+
+ /**
+ * ReWriterInterface constructor.
+ *
+ * This rewriter will be registered as the new call writer in the Handler.
+ * The original is passed as parameter
+ *
+ * @param CallWriterInterface $callWriter the original callwriter
+ */
+ public function __construct(CallWriterInterface $callWriter);
+
+ /**
+ * Process any calls that have been added and add them to the
+ * original call writer
+ *
+ * @return CallWriterInterface the orignal call writer
+ */
+ public function process();
+}
diff --git a/inc/Parsing/Handler/Table.php b/inc/Parsing/Handler/Table.php
new file mode 100644
index 000000000..6759ea798
--- /dev/null
+++ b/inc/Parsing/Handler/Table.php
@@ -0,0 +1,345 @@
+<?php
+
+namespace dokuwiki\Parsing\Handler;
+
+class Table implements ReWriterInterface
+{
+
+ /** @var CallWriterInterface original CallWriter */
+ protected $callWriter;
+
+ protected $calls = array();
+ protected $tableCalls = array();
+ protected $maxCols = 0;
+ protected $maxRows = 1;
+ protected $currentCols = 0;
+ protected $firstCell = false;
+ protected $lastCellType = 'tablecell';
+ protected $inTableHead = true;
+ protected $currentRow = array('tableheader' => 0, 'tablecell' => 0);
+ protected $countTableHeadRows = 0;
+
+ /** @inheritdoc */
+ public function __construct(CallWriterInterface $CallWriter)
+ {
+ $this->callWriter = $CallWriter;
+ }
+
+ /** @inheritdoc */
+ public function writeCall($call)
+ {
+ $this->calls[] = $call;
+ }
+
+ /**
+ * @inheritdoc
+ * Probably not needed but just in case...
+ */
+ public function writeCalls($calls)
+ {
+ $this->calls = array_merge($this->calls, $calls);
+ }
+
+ /** @inheritdoc */
+ public function finalise()
+ {
+ $last_call = end($this->calls);
+ $this->writeCall(array('table_end',array(), $last_call[2]));
+
+ $this->process();
+ $this->callWriter->finalise();
+ unset($this->callWriter);
+ }
+
+ /** @inheritdoc */
+ public function process()
+ {
+ foreach ($this->calls as $call) {
+ switch ($call[0]) {
+ case 'table_start':
+ $this->tableStart($call);
+ break;
+ case 'table_row':
+ $this->tableRowClose($call);
+ $this->tableRowOpen(array('tablerow_open',$call[1],$call[2]));
+ break;
+ case 'tableheader':
+ case 'tablecell':
+ $this->tableCell($call);
+ break;
+ case 'table_end':
+ $this->tableRowClose($call);
+ $this->tableEnd($call);
+ break;
+ default:
+ $this->tableDefault($call);
+ break;
+ }
+ }
+ $this->callWriter->writeCalls($this->tableCalls);
+
+ return $this->callWriter;
+ }
+
+ protected function tableStart($call)
+ {
+ $this->tableCalls[] = array('table_open',$call[1],$call[2]);
+ $this->tableCalls[] = array('tablerow_open',array(),$call[2]);
+ $this->firstCell = true;
+ }
+
+ protected function tableEnd($call)
+ {
+ $this->tableCalls[] = array('table_close',$call[1],$call[2]);
+ $this->finalizeTable();
+ }
+
+ protected function tableRowOpen($call)
+ {
+ $this->tableCalls[] = $call;
+ $this->currentCols = 0;
+ $this->firstCell = true;
+ $this->lastCellType = 'tablecell';
+ $this->maxRows++;
+ if ($this->inTableHead) {
+ $this->currentRow = array('tablecell' => 0, 'tableheader' => 0);
+ }
+ }
+
+ protected function tableRowClose($call)
+ {
+ if ($this->inTableHead && ($this->inTableHead = $this->isTableHeadRow())) {
+ $this->countTableHeadRows++;
+ }
+ // Strip off final cell opening and anything after it
+ while ($discard = array_pop($this->tableCalls)) {
+ if ($discard[0] == 'tablecell_open' || $discard[0] == 'tableheader_open') {
+ break;
+ }
+ if (!empty($this->currentRow[$discard[0]])) {
+ $this->currentRow[$discard[0]]--;
+ }
+ }
+ $this->tableCalls[] = array('tablerow_close', array(), $call[2]);
+
+ if ($this->currentCols > $this->maxCols) {
+ $this->maxCols = $this->currentCols;
+ }
+ }
+
+ protected function isTableHeadRow()
+ {
+ $td = $this->currentRow['tablecell'];
+ $th = $this->currentRow['tableheader'];
+
+ if (!$th || $td > 2) return false;
+ if (2*$td > $th) return false;
+
+ return true;
+ }
+
+ protected function tableCell($call)
+ {
+ if ($this->inTableHead) {
+ $this->currentRow[$call[0]]++;
+ }
+ if (!$this->firstCell) {
+ // Increase the span
+ $lastCall = end($this->tableCalls);
+
+ // A cell call which follows an open cell means an empty cell so span
+ if ($lastCall[0] == 'tablecell_open' || $lastCall[0] == 'tableheader_open') {
+ $this->tableCalls[] = array('colspan',array(),$call[2]);
+ }
+
+ $this->tableCalls[] = array($this->lastCellType.'_close',array(),$call[2]);
+ $this->tableCalls[] = array($call[0].'_open',array(1,null,1),$call[2]);
+ $this->lastCellType = $call[0];
+ } else {
+ $this->tableCalls[] = array($call[0].'_open',array(1,null,1),$call[2]);
+ $this->lastCellType = $call[0];
+ $this->firstCell = false;
+ }
+
+ $this->currentCols++;
+ }
+
+ protected function tableDefault($call)
+ {
+ $this->tableCalls[] = $call;
+ }
+
+ protected function finalizeTable()
+ {
+
+ // Add the max cols and rows to the table opening
+ if ($this->tableCalls[0][0] == 'table_open') {
+ // Adjust to num cols not num col delimeters
+ $this->tableCalls[0][1][] = $this->maxCols - 1;
+ $this->tableCalls[0][1][] = $this->maxRows;
+ $this->tableCalls[0][1][] = array_shift($this->tableCalls[0][1]);
+ } else {
+ trigger_error('First element in table call list is not table_open');
+ }
+
+ $lastRow = 0;
+ $lastCell = 0;
+ $cellKey = array();
+ $toDelete = array();
+
+ // if still in tableheader, then there can be no table header
+ // as all rows can't be within <THEAD>
+ if ($this->inTableHead) {
+ $this->inTableHead = false;
+ $this->countTableHeadRows = 0;
+ }
+
+ // Look for the colspan elements and increment the colspan on the
+ // previous non-empty opening cell. Once done, delete all the cells
+ // that contain colspans
+ for ($key = 0; $key < count($this->tableCalls); ++$key) {
+ $call = $this->tableCalls[$key];
+
+ switch ($call[0]) {
+ case 'table_open':
+ if ($this->countTableHeadRows) {
+ array_splice($this->tableCalls, $key+1, 0, array(
+ array('tablethead_open', array(), $call[2])));
+ }
+ break;
+
+ case 'tablerow_open':
+ $lastRow++;
+ $lastCell = 0;
+ break;
+
+ case 'tablecell_open':
+ case 'tableheader_open':
+ $lastCell++;
+ $cellKey[$lastRow][$lastCell] = $key;
+ break;
+
+ case 'table_align':
+ $prev = in_array($this->tableCalls[$key-1][0], array('tablecell_open', 'tableheader_open'));
+ $next = in_array($this->tableCalls[$key+1][0], array('tablecell_close', 'tableheader_close'));
+ // If the cell is empty, align left
+ if ($prev && $next) {
+ $this->tableCalls[$key-1][1][1] = 'left';
+
+ // If the previous element was a cell open, align right
+ } elseif ($prev) {
+ $this->tableCalls[$key-1][1][1] = 'right';
+
+ // If the next element is the close of an element, align either center or left
+ } elseif ($next) {
+ if ($this->tableCalls[$cellKey[$lastRow][$lastCell]][1][1] == 'right') {
+ $this->tableCalls[$cellKey[$lastRow][$lastCell]][1][1] = 'center';
+ } else {
+ $this->tableCalls[$cellKey[$lastRow][$lastCell]][1][1] = 'left';
+ }
+ }
+
+ // Now convert the whitespace back to cdata
+ $this->tableCalls[$key][0] = 'cdata';
+ break;
+
+ case 'colspan':
+ $this->tableCalls[$key-1][1][0] = false;
+
+ for ($i = $key-2; $i >= $cellKey[$lastRow][1]; $i--) {
+ if ($this->tableCalls[$i][0] == 'tablecell_open' ||
+ $this->tableCalls[$i][0] == 'tableheader_open'
+ ) {
+ if (false !== $this->tableCalls[$i][1][0]) {
+ $this->tableCalls[$i][1][0]++;
+ break;
+ }
+ }
+ }
+
+ $toDelete[] = $key-1;
+ $toDelete[] = $key;
+ $toDelete[] = $key+1;
+ break;
+
+ case 'rowspan':
+ if ($this->tableCalls[$key-1][0] == 'cdata') {
+ // ignore rowspan if previous call was cdata (text mixed with :::)
+ // we don't have to check next call as that wont match regex
+ $this->tableCalls[$key][0] = 'cdata';
+ } else {
+ $spanning_cell = null;
+
+ // can't cross thead/tbody boundary
+ if (!$this->countTableHeadRows || ($lastRow-1 != $this->countTableHeadRows)) {
+ for ($i = $lastRow-1; $i > 0; $i--) {
+ if ($this->tableCalls[$cellKey[$i][$lastCell]][0] == 'tablecell_open' ||
+ $this->tableCalls[$cellKey[$i][$lastCell]][0] == 'tableheader_open'
+ ) {
+ if ($this->tableCalls[$cellKey[$i][$lastCell]][1][2] >= $lastRow - $i) {
+ $spanning_cell = $i;
+ break;
+ }
+ }
+ }
+ }
+ if (is_null($spanning_cell)) {
+ // No spanning cell found, so convert this cell to
+ // an empty one to avoid broken tables
+ $this->tableCalls[$key][0] = 'cdata';
+ $this->tableCalls[$key][1][0] = '';
+ break;
+ }
+ $this->tableCalls[$cellKey[$spanning_cell][$lastCell]][1][2]++;
+
+ $this->tableCalls[$key-1][1][2] = false;
+
+ $toDelete[] = $key-1;
+ $toDelete[] = $key;
+ $toDelete[] = $key+1;
+ }
+ break;
+
+ case 'tablerow_close':
+ // Fix broken tables by adding missing cells
+ $moreCalls = array();
+ while (++$lastCell < $this->maxCols) {
+ $moreCalls[] = array('tablecell_open', array(1, null, 1), $call[2]);
+ $moreCalls[] = array('cdata', array(''), $call[2]);
+ $moreCalls[] = array('tablecell_close', array(), $call[2]);
+ }
+ $moreCallsLength = count($moreCalls);
+ if ($moreCallsLength) {
+ array_splice($this->tableCalls, $key, 0, $moreCalls);
+ $key += $moreCallsLength;
+ }
+
+ if ($this->countTableHeadRows == $lastRow) {
+ array_splice($this->tableCalls, $key+1, 0, array(
+ array('tablethead_close', array(), $call[2])));
+ }
+ break;
+ }
+ }
+
+ // condense cdata
+ $cnt = count($this->tableCalls);
+ for ($key = 0; $key < $cnt; $key++) {
+ if ($this->tableCalls[$key][0] == 'cdata') {
+ $ckey = $key;
+ $key++;
+ while ($this->tableCalls[$key][0] == 'cdata') {
+ $this->tableCalls[$ckey][1][0] .= $this->tableCalls[$key][1][0];
+ $toDelete[] = $key;
+ $key++;
+ }
+ continue;
+ }
+ }
+
+ foreach ($toDelete as $delete) {
+ unset($this->tableCalls[$delete]);
+ }
+ $this->tableCalls = array_values($this->tableCalls);
+ }
+}
diff --git a/inc/Parsing/Lexer/Lexer.php b/inc/Parsing/Lexer/Lexer.php
new file mode 100644
index 000000000..c164f4ffe
--- /dev/null
+++ b/inc/Parsing/Lexer/Lexer.php
@@ -0,0 +1,347 @@
+<?php
+/**
+ * Lexer adapted from Simple Test: http://sourceforge.net/projects/simpletest/
+ * For an intro to the Lexer see:
+ * https://web.archive.org/web/20120125041816/http://www.phppatterns.com/docs/develop/simple_test_lexer_notes
+ *
+ * @author Marcus Baker http://www.lastcraft.com
+ */
+
+namespace dokuwiki\Parsing\Lexer;
+
+// FIXME move elsewhere
+
+define("DOKU_LEXER_ENTER", 1);
+define("DOKU_LEXER_MATCHED", 2);
+define("DOKU_LEXER_UNMATCHED", 3);
+define("DOKU_LEXER_EXIT", 4);
+define("DOKU_LEXER_SPECIAL", 5);
+
+/**
+ * Accepts text and breaks it into tokens.
+ *
+ * Some optimisation to make the sure the content is only scanned by the PHP regex
+ * parser once. Lexer modes must not start with leading underscores.
+ */
+class Lexer
+{
+ /** @var ParallelRegex[] */
+ protected $regexes;
+ /** @var \Doku_Handler */
+ protected $handler;
+ /** @var StateStack */
+ protected $modeStack;
+ /** @var array mode "rewrites" */
+ protected $mode_handlers;
+ /** @var bool case sensitive? */
+ protected $case;
+
+ /**
+ * Sets up the lexer in case insensitive matching by default.
+ *
+ * @param \Doku_Handler $handler Handling strategy by reference.
+ * @param string $start Starting handler.
+ * @param boolean $case True for case sensitive.
+ */
+ public function __construct($handler, $start = "accept", $case = false)
+ {
+ $this->case = $case;
+ $this->regexes = array();
+ $this->handler = $handler;
+ $this->modeStack = new StateStack($start);
+ $this->mode_handlers = array();
+ }
+
+ /**
+ * Adds a token search pattern for a particular parsing mode.
+ *
+ * The pattern does not change the current mode.
+ *
+ * @param string $pattern Perl style regex, but ( and )
+ * lose the usual meaning.
+ * @param string $mode Should only apply this
+ * pattern when dealing with
+ * this type of input.
+ */
+ public function addPattern($pattern, $mode = "accept")
+ {
+ if (! isset($this->regexes[$mode])) {
+ $this->regexes[$mode] = new ParallelRegex($this->case);
+ }
+ $this->regexes[$mode]->addPattern($pattern);
+ }
+
+ /**
+ * Adds a pattern that will enter a new parsing mode.
+ *
+ * Useful for entering parenthesis, strings, tags, etc.
+ *
+ * @param string $pattern Perl style regex, but ( and ) lose the usual meaning.
+ * @param string $mode Should only apply this pattern when dealing with this type of input.
+ * @param string $new_mode Change parsing to this new nested mode.
+ */
+ public function addEntryPattern($pattern, $mode, $new_mode)
+ {
+ if (! isset($this->regexes[$mode])) {
+ $this->regexes[$mode] = new ParallelRegex($this->case);
+ }
+ $this->regexes[$mode]->addPattern($pattern, $new_mode);
+ }
+
+ /**
+ * Adds a pattern that will exit the current mode and re-enter the previous one.
+ *
+ * @param string $pattern Perl style regex, but ( and ) lose the usual meaning.
+ * @param string $mode Mode to leave.
+ */
+ public function addExitPattern($pattern, $mode)
+ {
+ if (! isset($this->regexes[$mode])) {
+ $this->regexes[$mode] = new ParallelRegex($this->case);
+ }
+ $this->regexes[$mode]->addPattern($pattern, "__exit");
+ }
+
+ /**
+ * Adds a pattern that has a special mode.
+ *
+ * Acts as an entry and exit pattern in one go, effectively calling a special
+ * parser handler for this token only.
+ *
+ * @param string $pattern Perl style regex, but ( and ) lose the usual meaning.
+ * @param string $mode Should only apply this pattern when dealing with this type of input.
+ * @param string $special Use this mode for this one token.
+ */
+ public function addSpecialPattern($pattern, $mode, $special)
+ {
+ if (! isset($this->regexes[$mode])) {
+ $this->regexes[$mode] = new ParallelRegex($this->case);
+ }
+ $this->regexes[$mode]->addPattern($pattern, "_$special");
+ }
+
+ /**
+ * Adds a mapping from a mode to another handler.
+ *
+ * @param string $mode Mode to be remapped.
+ * @param string $handler New target handler.
+ */
+ public function mapHandler($mode, $handler)
+ {
+ $this->mode_handlers[$mode] = $handler;
+ }
+
+ /**
+ * Splits the page text into tokens.
+ *
+ * Will fail if the handlers report an error or if no content is consumed. If successful then each
+ * unparsed and parsed token invokes a call to the held listener.
+ *
+ * @param string $raw Raw HTML text.
+ * @return boolean True on success, else false.
+ */
+ public function parse($raw)
+ {
+ if (! isset($this->handler)) {
+ return false;
+ }
+ $initialLength = strlen($raw);
+ $length = $initialLength;
+ $pos = 0;
+ while (is_array($parsed = $this->reduce($raw))) {
+ list($unmatched, $matched, $mode) = $parsed;
+ $currentLength = strlen($raw);
+ $matchPos = $initialLength - $currentLength - strlen($matched);
+ if (! $this->dispatchTokens($unmatched, $matched, $mode, $pos, $matchPos)) {
+ return false;
+ }
+ if ($currentLength == $length) {
+ return false;
+ }
+ $length = $currentLength;
+ $pos = $initialLength - $currentLength;
+ }
+ if (!$parsed) {
+ return false;
+ }
+ return $this->invokeHandler($raw, DOKU_LEXER_UNMATCHED, $pos);
+ }
+
+ /**
+ * Sends the matched token and any leading unmatched
+ * text to the parser changing the lexer to a new
+ * mode if one is listed.
+ *
+ * @param string $unmatched Unmatched leading portion.
+ * @param string $matched Actual token match.
+ * @param bool|string $mode Mode after match. A boolean false mode causes no change.
+ * @param int $initialPos
+ * @param int $matchPos Current byte index location in raw doc thats being parsed
+ * @return boolean False if there was any error from the parser.
+ */
+ protected function dispatchTokens($unmatched, $matched, $mode, $initialPos, $matchPos)
+ {
+ if (! $this->invokeHandler($unmatched, DOKU_LEXER_UNMATCHED, $initialPos)) {
+ return false;
+ }
+ if ($this->isModeEnd($mode)) {
+ if (! $this->invokeHandler($matched, DOKU_LEXER_EXIT, $matchPos)) {
+ return false;
+ }
+ return $this->modeStack->leave();
+ }
+ if ($this->isSpecialMode($mode)) {
+ $this->modeStack->enter($this->decodeSpecial($mode));
+ if (! $this->invokeHandler($matched, DOKU_LEXER_SPECIAL, $matchPos)) {
+ return false;
+ }
+ return $this->modeStack->leave();
+ }
+ if (is_string($mode)) {
+ $this->modeStack->enter($mode);
+ return $this->invokeHandler($matched, DOKU_LEXER_ENTER, $matchPos);
+ }
+ return $this->invokeHandler($matched, DOKU_LEXER_MATCHED, $matchPos);
+ }
+
+ /**
+ * Tests to see if the new mode is actually to leave the current mode and pop an item from the matching
+ * mode stack.
+ *
+ * @param string $mode Mode to test.
+ * @return boolean True if this is the exit mode.
+ */
+ protected function isModeEnd($mode)
+ {
+ return ($mode === "__exit");
+ }
+
+ /**
+ * Test to see if the mode is one where this mode is entered for this token only and automatically
+ * leaves immediately afterwoods.
+ *
+ * @param string $mode Mode to test.
+ * @return boolean True if this is the exit mode.
+ */
+ protected function isSpecialMode($mode)
+ {
+ return (strncmp($mode, "_", 1) == 0);
+ }
+
+ /**
+ * Strips the magic underscore marking single token modes.
+ *
+ * @param string $mode Mode to decode.
+ * @return string Underlying mode name.
+ */
+ protected function decodeSpecial($mode)
+ {
+ return substr($mode, 1);
+ }
+
+ /**
+ * Calls the parser method named after the current mode.
+ *
+ * Empty content will be ignored. The lexer has a parser handler for each mode in the lexer.
+ *
+ * @param string $content Text parsed.
+ * @param boolean $is_match Token is recognised rather
+ * than unparsed data.
+ * @param int $pos Current byte index location in raw doc
+ * thats being parsed
+ * @return bool
+ */
+ protected function invokeHandler($content, $is_match, $pos)
+ {
+ if (($content === "") || ($content === false)) {
+ return true;
+ }
+ $handler = $this->modeStack->getCurrent();
+ if (isset($this->mode_handlers[$handler])) {
+ $handler = $this->mode_handlers[$handler];
+ }
+
+ // modes starting with plugin_ are all handled by the same
+ // handler but with an additional parameter
+ if (substr($handler, 0, 7)=='plugin_') {
+ list($handler,$plugin) = explode('_', $handler, 2);
+ return $this->handler->$handler($content, $is_match, $pos, $plugin);
+ }
+
+ return $this->handler->$handler($content, $is_match, $pos);
+ }
+
+ /**
+ * Tries to match a chunk of text and if successful removes the recognised chunk and any leading
+ * unparsed data. Empty strings will not be matched.
+ *
+ * @param string $raw The subject to parse. This is the content that will be eaten.
+ * @return array|bool Three item list of unparsed content followed by the
+ * recognised token and finally the action the parser is to take.
+ * True if no match, false if there is a parsing error.
+ */
+ protected function reduce(&$raw)
+ {
+ if (! isset($this->regexes[$this->modeStack->getCurrent()])) {
+ return false;
+ }
+ if ($raw === "") {
+ return true;
+ }
+ if ($action = $this->regexes[$this->modeStack->getCurrent()]->split($raw, $split)) {
+ list($unparsed, $match, $raw) = $split;
+ return array($unparsed, $match, $action);
+ }
+ return true;
+ }
+
+ /**
+ * Escapes regex characters other than (, ) and /
+ *
+ * @param string $str
+ * @return string
+ */
+ public static function escape($str)
+ {
+ $chars = array(
+ '/\\\\/',
+ '/\./',
+ '/\+/',
+ '/\*/',
+ '/\?/',
+ '/\[/',
+ '/\^/',
+ '/\]/',
+ '/\$/',
+ '/\{/',
+ '/\}/',
+ '/\=/',
+ '/\!/',
+ '/\</',
+ '/\>/',
+ '/\|/',
+ '/\:/'
+ );
+
+ $escaped = array(
+ '\\\\\\\\',
+ '\.',
+ '\+',
+ '\*',
+ '\?',
+ '\[',
+ '\^',
+ '\]',
+ '\$',
+ '\{',
+ '\}',
+ '\=',
+ '\!',
+ '\<',
+ '\>',
+ '\|',
+ '\:'
+ );
+ return preg_replace($chars, $escaped, $str);
+ }
+}
diff --git a/inc/Parsing/Lexer/ParallelRegex.php b/inc/Parsing/Lexer/ParallelRegex.php
new file mode 100644
index 000000000..96f61a10f
--- /dev/null
+++ b/inc/Parsing/Lexer/ParallelRegex.php
@@ -0,0 +1,203 @@
+<?php
+/**
+ * Lexer adapted from Simple Test: http://sourceforge.net/projects/simpletest/
+ * For an intro to the Lexer see:
+ * https://web.archive.org/web/20120125041816/http://www.phppatterns.com/docs/develop/simple_test_lexer_notes
+ *
+ * @author Marcus Baker http://www.lastcraft.com
+ */
+
+namespace dokuwiki\Parsing\Lexer;
+
+/**
+ * Compounded regular expression.
+ *
+ * Any of the contained patterns could match and when one does it's label is returned.
+ */
+class ParallelRegex
+{
+ /** @var string[] patterns to match */
+ protected $patterns;
+ /** @var string[] labels for above patterns */
+ protected $labels;
+ /** @var string the compound regex matching all patterns */
+ protected $regex;
+ /** @var bool case sensitive matching? */
+ protected $case;
+
+ /**
+ * Constructor. Starts with no patterns.
+ *
+ * @param boolean $case True for case sensitive, false
+ * for insensitive.
+ */
+ public function __construct($case)
+ {
+ $this->case = $case;
+ $this->patterns = array();
+ $this->labels = array();
+ $this->regex = null;
+ }
+
+ /**
+ * Adds a pattern with an optional label.
+ *
+ * @param mixed $pattern Perl style regex. Must be UTF-8
+ * encoded. If its a string, the (, )
+ * lose their meaning unless they
+ * form part of a lookahead or
+ * lookbehind assertation.
+ * @param bool|string $label Label of regex to be returned
+ * on a match. Label must be ASCII
+ */
+ public function addPattern($pattern, $label = true)
+ {
+ $count = count($this->patterns);
+ $this->patterns[$count] = $pattern;
+ $this->labels[$count] = $label;
+ $this->regex = null;
+ }
+
+ /**
+ * Attempts to match all patterns at once against a string.
+ *
+ * @param string $subject String to match against.
+ * @param string $match First matched portion of
+ * subject.
+ * @return bool|string False if no match found, label if label exists, true if not
+ */
+ public function match($subject, &$match)
+ {
+ if (count($this->patterns) == 0) {
+ return false;
+ }
+ if (! preg_match($this->getCompoundedRegex(), $subject, $matches)) {
+ $match = "";
+ return false;
+ }
+
+ $match = $matches[0];
+ $size = count($matches);
+ // FIXME this could be made faster by storing the labels as keys in a hashmap
+ for ($i = 1; $i < $size; $i++) {
+ if ($matches[$i] && isset($this->labels[$i - 1])) {
+ return $this->labels[$i - 1];
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Attempts to split the string against all patterns at once
+ *
+ * @param string $subject String to match against.
+ * @param array $split The split result: array containing, pre-match, match & post-match strings
+ * @return boolean True on success.
+ *
+ * @author Christopher Smith <chris@jalakai.co.uk>
+ */
+ public function split($subject, &$split)
+ {
+ if (count($this->patterns) == 0) {
+ return false;
+ }
+
+ if (! preg_match($this->getCompoundedRegex(), $subject, $matches)) {
+ if (function_exists('preg_last_error')) {
+ $err = preg_last_error();
+ switch ($err) {
+ case PREG_BACKTRACK_LIMIT_ERROR:
+ msg('A PCRE backtrack error occured. Try to increase the pcre.backtrack_limit in php.ini', -1);
+ break;
+ case PREG_RECURSION_LIMIT_ERROR:
+ msg('A PCRE recursion error occured. Try to increase the pcre.recursion_limit in php.ini', -1);
+ break;
+ case PREG_BAD_UTF8_ERROR:
+ msg('A PCRE UTF-8 error occured. This might be caused by a faulty plugin', -1);
+ break;
+ case PREG_INTERNAL_ERROR:
+ msg('A PCRE internal error occured. This might be caused by a faulty plugin', -1);
+ break;
+ }
+ }
+
+ $split = array($subject, "", "");
+ return false;
+ }
+
+ $idx = count($matches)-2;
+ list($pre, $post) = preg_split($this->patterns[$idx].$this->getPerlMatchingFlags(), $subject, 2);
+ $split = array($pre, $matches[0], $post);
+
+ return isset($this->labels[$idx]) ? $this->labels[$idx] : true;
+ }
+
+ /**
+ * Compounds the patterns into a single
+ * regular expression separated with the
+ * "or" operator. Caches the regex.
+ * Will automatically escape (, ) and / tokens.
+ *
+ * @return null|string
+ */
+ protected function getCompoundedRegex()
+ {
+ if ($this->regex == null) {
+ $cnt = count($this->patterns);
+ for ($i = 0; $i < $cnt; $i++) {
+ /*
+ * decompose the input pattern into "(", "(?", ")",
+ * "[...]", "[]..]", "[^]..]", "[...[:...:]..]", "\x"...
+ * elements.
+ */
+ preg_match_all('/\\\\.|' .
+ '\(\?|' .
+ '[()]|' .
+ '\[\^?\]?(?:\\\\.|\[:[^]]*:\]|[^]\\\\])*\]|' .
+ '[^[()\\\\]+/', $this->patterns[$i], $elts);
+
+ $pattern = "";
+ $level = 0;
+
+ foreach ($elts[0] as $elt) {
+ /*
+ * for "(", ")" remember the nesting level, add "\"
+ * only to the non-"(?" ones.
+ */
+
+ switch ($elt) {
+ case '(':
+ $pattern .= '\(';
+ break;
+ case ')':
+ if ($level > 0)
+ $level--; /* closing (? */
+ else $pattern .= '\\';
+ $pattern .= ')';
+ break;
+ case '(?':
+ $level++;
+ $pattern .= '(?';
+ break;
+ default:
+ if (substr($elt, 0, 1) == '\\')
+ $pattern .= $elt;
+ else $pattern .= str_replace('/', '\/', $elt);
+ }
+ }
+ $this->patterns[$i] = "($pattern)";
+ }
+ $this->regex = "/" . implode("|", $this->patterns) . "/" . $this->getPerlMatchingFlags();
+ }
+ return $this->regex;
+ }
+
+ /**
+ * Accessor for perl regex mode flags to use.
+ * @return string Perl regex flags.
+ */
+ protected function getPerlMatchingFlags()
+ {
+ return ($this->case ? "msS" : "msSi");
+ }
+}
diff --git a/inc/Parsing/Lexer/StateStack.php b/inc/Parsing/Lexer/StateStack.php
new file mode 100644
index 000000000..325412bb4
--- /dev/null
+++ b/inc/Parsing/Lexer/StateStack.php
@@ -0,0 +1,60 @@
+<?php
+/**
+ * Lexer adapted from Simple Test: http://sourceforge.net/projects/simpletest/
+ * For an intro to the Lexer see:
+ * https://web.archive.org/web/20120125041816/http://www.phppatterns.com/docs/develop/simple_test_lexer_notes
+ *
+ * @author Marcus Baker http://www.lastcraft.com
+ */
+
+namespace dokuwiki\Parsing\Lexer;
+
+/**
+ * States for a stack machine.
+ */
+class StateStack
+{
+ protected $stack;
+
+ /**
+ * Constructor. Starts in named state.
+ * @param string $start Starting state name.
+ */
+ public function __construct($start)
+ {
+ $this->stack = array($start);
+ }
+
+ /**
+ * Accessor for current state.
+ * @return string State.
+ */
+ public function getCurrent()
+ {
+ return $this->stack[count($this->stack) - 1];
+ }
+
+ /**
+ * Adds a state to the stack and sets it to be the current state.
+ *
+ * @param string $state New state.
+ */
+ public function enter($state)
+ {
+ array_push($this->stack, $state);
+ }
+
+ /**
+ * Leaves the current state and reverts
+ * to the previous one.
+ * @return boolean false if we attempt to drop off the bottom of the list.
+ */
+ public function leave()
+ {
+ if (count($this->stack) == 1) {
+ return false;
+ }
+ array_pop($this->stack);
+ return true;
+ }
+}
diff --git a/inc/Parsing/Parser.php b/inc/Parsing/Parser.php
new file mode 100644
index 000000000..b2070569f
--- /dev/null
+++ b/inc/Parsing/Parser.php
@@ -0,0 +1,114 @@
+<?php
+
+namespace dokuwiki\Parsing;
+
+use Doku_Handler;
+use dokuwiki\Parsing\Lexer\Lexer;
+use dokuwiki\Parsing\ParserMode\Base;
+use dokuwiki\Parsing\ParserMode\ModeInterface;
+
+/**
+ * Sets up the Lexer with modes and points it to the Handler
+ * For an intro to the Lexer see: wiki:parser
+ */
+class Parser {
+
+ /** @var Doku_Handler */
+ protected $handler;
+
+ /** @var Lexer $lexer */
+ protected $lexer;
+
+ /** @var ModeInterface[] $modes */
+ protected $modes = array();
+
+ /** @var bool mode connections may only be set up once */
+ protected $connected = false;
+
+ /**
+ * dokuwiki\Parsing\Doku_Parser constructor.
+ *
+ * @param Doku_Handler $handler
+ */
+ public function __construct(Doku_Handler $handler) {
+ $this->handler = $handler;
+ }
+
+ /**
+ * Adds the base mode and initialized the lexer
+ *
+ * @param Base $BaseMode
+ */
+ protected function addBaseMode($BaseMode) {
+ $this->modes['base'] = $BaseMode;
+ if(!$this->lexer) {
+ $this->lexer = new Lexer($this->handler, 'base', true);
+ }
+ $this->modes['base']->Lexer = $this->lexer;
+ }
+
+ /**
+ * Add a new syntax element (mode) to the parser
+ *
+ * PHP preserves order of associative elements
+ * Mode sequence is important
+ *
+ * @param string $name
+ * @param ModeInterface $Mode
+ */
+ public function addMode($name, ModeInterface $Mode) {
+ if(!isset($this->modes['base'])) {
+ $this->addBaseMode(new Base());
+ }
+ $Mode->Lexer = $this->lexer; // FIXME should be done by setter
+ $this->modes[$name] = $Mode;
+ }
+
+ /**
+ * Connect all modes with each other
+ *
+ * This is the last step before actually parsing.
+ */
+ protected function connectModes() {
+
+ if($this->connected) {
+ return;
+ }
+
+ foreach(array_keys($this->modes) as $mode) {
+ // Base isn't connected to anything
+ if($mode == 'base') {
+ continue;
+ }
+ $this->modes[$mode]->preConnect();
+
+ foreach(array_keys($this->modes) as $cm) {
+
+ if($this->modes[$cm]->accepts($mode)) {
+ $this->modes[$mode]->connectTo($cm);
+ }
+
+ }
+
+ $this->modes[$mode]->postConnect();
+ }
+
+ $this->connected = true;
+ }
+
+ /**
+ * Parses wiki syntax to instructions
+ *
+ * @param string $doc the wiki syntax text
+ * @return array instructions
+ */
+ public function parse($doc) {
+ $this->connectModes();
+ // Normalize CRs and pad doc
+ $doc = "\n" . str_replace("\r\n", "\n", $doc) . "\n";
+ $this->lexer->parse($doc);
+ $this->handler->finalize();
+ return $this->handler->calls;
+ }
+
+}
diff --git a/inc/Parsing/ParserMode/AbstractMode.php b/inc/Parsing/ParserMode/AbstractMode.php
new file mode 100644
index 000000000..15fc9fe04
--- /dev/null
+++ b/inc/Parsing/ParserMode/AbstractMode.php
@@ -0,0 +1,40 @@
+<?php
+
+namespace dokuwiki\Parsing\ParserMode;
+
+/**
+ * This class and all the subclasses below are used to reduce the effort required to register
+ * modes with the Lexer.
+ *
+ * @author Harry Fuecks <hfuecks@gmail.com>
+ */
+abstract class AbstractMode implements ModeInterface
+{
+ /** @var \dokuwiki\Parsing\Lexer\Lexer $Lexer will be injected on loading FIXME this should be done by setter */
+ public $Lexer;
+ protected $allowedModes = array();
+
+ /** @inheritdoc */
+ abstract public function getSort();
+
+ /** @inheritdoc */
+ public function preConnect()
+ {
+ }
+
+ /** @inheritdoc */
+ public function connectTo($mode)
+ {
+ }
+
+ /** @inheritdoc */
+ public function postConnect()
+ {
+ }
+
+ /** @inheritdoc */
+ public function accepts($mode)
+ {
+ return in_array($mode, (array) $this->allowedModes);
+ }
+}
diff --git a/inc/Parsing/ParserMode/Acronym.php b/inc/Parsing/ParserMode/Acronym.php
new file mode 100644
index 000000000..b42a7b573
--- /dev/null
+++ b/inc/Parsing/ParserMode/Acronym.php
@@ -0,0 +1,68 @@
+<?php
+
+namespace dokuwiki\Parsing\ParserMode;
+
+class Acronym extends AbstractMode
+{
+ // A list
+ protected $acronyms = array();
+ protected $pattern = '';
+
+ /**
+ * Acronym constructor.
+ *
+ * @param string[] $acronyms
+ */
+ public function __construct($acronyms)
+ {
+ usort($acronyms, array($this,'compare'));
+ $this->acronyms = $acronyms;
+ }
+
+ /** @inheritdoc */
+ public function preConnect()
+ {
+ if (!count($this->acronyms)) return;
+
+ $bound = '[\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f]';
+ $acronyms = array_map(['\\dokuwiki\\Parsing\\Lexer\\Lexer', 'escape'], $this->acronyms);
+ $this->pattern = '(?<=^|'.$bound.')(?:'.join('|', $acronyms).')(?='.$bound.')';
+ }
+
+ /** @inheritdoc */
+ public function connectTo($mode)
+ {
+ if (!count($this->acronyms)) return;
+
+ if (strlen($this->pattern) > 0) {
+ $this->Lexer->addSpecialPattern($this->pattern, $mode, 'acronym');
+ }
+ }
+
+ /** @inheritdoc */
+ public function getSort()
+ {
+ return 240;
+ }
+
+ /**
+ * sort callback to order by string length descending
+ *
+ * @param string $a
+ * @param string $b
+ *
+ * @return int
+ */
+ protected function compare($a, $b)
+ {
+ $a_len = strlen($a);
+ $b_len = strlen($b);
+ if ($a_len > $b_len) {
+ return -1;
+ } elseif ($a_len < $b_len) {
+ return 1;
+ }
+
+ return 0;
+ }
+}
diff --git a/inc/Parsing/ParserMode/Base.php b/inc/Parsing/ParserMode/Base.php
new file mode 100644
index 000000000..562275600
--- /dev/null
+++ b/inc/Parsing/ParserMode/Base.php
@@ -0,0 +1,31 @@
+<?php
+
+namespace dokuwiki\Parsing\ParserMode;
+
+class Base extends AbstractMode
+{
+
+ /**
+ * Base constructor.
+ */
+ public function __construct()
+ {
+ global $PARSER_MODES;
+
+ $this->allowedModes = array_merge(
+ $PARSER_MODES['container'],
+ $PARSER_MODES['baseonly'],
+ $PARSER_MODES['paragraphs'],
+ $PARSER_MODES['formatting'],
+ $PARSER_MODES['substition'],
+ $PARSER_MODES['protected'],
+ $PARSER_MODES['disabled']
+ );
+ }
+
+ /** @inheritdoc */
+ public function getSort()
+ {
+ return 0;
+ }
+}
diff --git a/inc/Parsing/ParserMode/Camelcaselink.php b/inc/Parsing/ParserMode/Camelcaselink.php
new file mode 100644
index 000000000..ef0b32531
--- /dev/null
+++ b/inc/Parsing/ParserMode/Camelcaselink.php
@@ -0,0 +1,23 @@
+<?php
+
+namespace dokuwiki\Parsing\ParserMode;
+
+class Camelcaselink extends AbstractMode
+{
+
+ /** @inheritdoc */
+ public function connectTo($mode)
+ {
+ $this->Lexer->addSpecialPattern(
+ '\b[A-Z]+[a-z]+[A-Z][A-Za-z]*\b',
+ $mode,
+ 'camelcaselink'
+ );
+ }
+
+ /** @inheritdoc */
+ public function getSort()
+ {
+ return 290;
+ }
+}
diff --git a/inc/Parsing/ParserMode/Code.php b/inc/Parsing/ParserMode/Code.php
new file mode 100644
index 000000000..aa494377d
--- /dev/null
+++ b/inc/Parsing/ParserMode/Code.php
@@ -0,0 +1,25 @@
+<?php
+
+namespace dokuwiki\Parsing\ParserMode;
+
+class Code extends AbstractMode
+{
+
+ /** @inheritdoc */
+ public function connectTo($mode)
+ {
+ $this->Lexer->addEntryPattern('<code\b(?=.*</code>)', $mode, 'code');
+ }
+
+ /** @inheritdoc */
+ public function postConnect()
+ {
+ $this->Lexer->addExitPattern('</code>', 'code');
+ }
+
+ /** @inheritdoc */
+ public function getSort()
+ {
+ return 200;
+ }
+}
diff --git a/inc/Parsing/ParserMode/Emaillink.php b/inc/Parsing/ParserMode/Emaillink.php
new file mode 100644
index 000000000..f9af28c66
--- /dev/null
+++ b/inc/Parsing/ParserMode/Emaillink.php
@@ -0,0 +1,20 @@
+<?php
+
+namespace dokuwiki\Parsing\ParserMode;
+
+class Emaillink extends AbstractMode
+{
+
+ /** @inheritdoc */
+ public function connectTo($mode)
+ {
+ // pattern below is defined in inc/mail.php
+ $this->Lexer->addSpecialPattern('<'.PREG_PATTERN_VALID_EMAIL.'>', $mode, 'emaillink');
+ }
+
+ /** @inheritdoc */
+ public function getSort()
+ {
+ return 340;
+ }
+}
diff --git a/inc/Parsing/ParserMode/Entity.php b/inc/Parsing/ParserMode/Entity.php
new file mode 100644
index 000000000..b670124b2
--- /dev/null
+++ b/inc/Parsing/ParserMode/Entity.php
@@ -0,0 +1,50 @@
+<?php
+
+namespace dokuwiki\Parsing\ParserMode;
+
+use dokuwiki\Parsing\Lexer\Lexer;
+
+class Entity extends AbstractMode
+{
+
+ protected $entities = array();
+ protected $pattern = '';
+
+ /**
+ * Entity constructor.
+ * @param string[] $entities
+ */
+ public function __construct($entities)
+ {
+ $this->entities = $entities;
+ }
+
+
+ /** @inheritdoc */
+ public function preConnect()
+ {
+ if (!count($this->entities) || $this->pattern != '') return;
+
+ $sep = '';
+ foreach ($this->entities as $entity) {
+ $this->pattern .= $sep. Lexer::escape($entity);
+ $sep = '|';
+ }
+ }
+
+ /** @inheritdoc */
+ public function connectTo($mode)
+ {
+ if (!count($this->entities)) return;
+
+ if (strlen($this->pattern) > 0) {
+ $this->Lexer->addSpecialPattern($this->pattern, $mode, 'entity');
+ }
+ }
+
+ /** @inheritdoc */
+ public function getSort()
+ {
+ return 260;
+ }
+}
diff --git a/inc/Parsing/ParserMode/Eol.php b/inc/Parsing/ParserMode/Eol.php
new file mode 100644
index 000000000..a5886b51f
--- /dev/null
+++ b/inc/Parsing/ParserMode/Eol.php
@@ -0,0 +1,25 @@
+<?php
+
+namespace dokuwiki\Parsing\ParserMode;
+
+class Eol extends AbstractMode
+{
+
+ /** @inheritdoc */
+ public function connectTo($mode)
+ {
+ $badModes = array('listblock','table');
+ if (in_array($mode, $badModes)) {
+ return;
+ }
+ // see FS#1652, pattern extended to swallow preceding whitespace to avoid
+ // issues with lines that only contain whitespace
+ $this->Lexer->addSpecialPattern('(?:^[ \t]*)?\n', $mode, 'eol');
+ }
+
+ /** @inheritdoc */
+ public function getSort()
+ {
+ return 370;
+ }
+}
diff --git a/inc/Parsing/ParserMode/Externallink.php b/inc/Parsing/ParserMode/Externallink.php
new file mode 100644
index 000000000..747574595
--- /dev/null
+++ b/inc/Parsing/ParserMode/Externallink.php
@@ -0,0 +1,44 @@
+<?php
+
+namespace dokuwiki\Parsing\ParserMode;
+
+class Externallink extends AbstractMode
+{
+ protected $schemes = array();
+ protected $patterns = array();
+
+ /** @inheritdoc */
+ public function preConnect()
+ {
+ if (count($this->patterns)) return;
+
+ $ltrs = '\w';
+ $gunk = '/\#~:.?+=&%@!\-\[\]';
+ $punc = '.:?\-;,';
+ $host = $ltrs.$punc;
+ $any = $ltrs.$gunk.$punc;
+
+ $this->schemes = getSchemes();
+ foreach ($this->schemes as $scheme) {
+ $this->patterns[] = '\b(?i)'.$scheme.'(?-i)://['.$any.']+?(?=['.$punc.']*[^'.$any.'])';
+ }
+
+ $this->patterns[] = '(?<=\s)(?i)www?(?-i)\.['.$host.']+?\.['.$host.']+?['.$any.']+?(?=['.$punc.']*[^'.$any.'])';
+ $this->patterns[] = '(?<=\s)(?i)ftp?(?-i)\.['.$host.']+?\.['.$host.']+?['.$any.']+?(?=['.$punc.']*[^'.$any.'])';
+ }
+
+ /** @inheritdoc */
+ public function connectTo($mode)
+ {
+
+ foreach ($this->patterns as $pattern) {
+ $this->Lexer->addSpecialPattern($pattern, $mode, 'externallink');
+ }
+ }
+
+ /** @inheritdoc */
+ public function getSort()
+ {
+ return 330;
+ }
+}
diff --git a/inc/Parsing/ParserMode/File.php b/inc/Parsing/ParserMode/File.php
new file mode 100644
index 000000000..149134135
--- /dev/null
+++ b/inc/Parsing/ParserMode/File.php
@@ -0,0 +1,25 @@
+<?php
+
+namespace dokuwiki\Parsing\ParserMode;
+
+class File extends AbstractMode
+{
+
+ /** @inheritdoc */
+ public function connectTo($mode)
+ {
+ $this->Lexer->addEntryPattern('<file\b(?=.*</file>)', $mode, 'file');
+ }
+
+ /** @inheritdoc */
+ public function postConnect()
+ {
+ $this->Lexer->addExitPattern('</file>', 'file');
+ }
+
+ /** @inheritdoc */
+ public function getSort()
+ {
+ return 210;
+ }
+}
diff --git a/inc/Parsing/ParserMode/Filelink.php b/inc/Parsing/ParserMode/Filelink.php
new file mode 100644
index 000000000..3cd86cb8b
--- /dev/null
+++ b/inc/Parsing/ParserMode/Filelink.php
@@ -0,0 +1,39 @@
+<?php
+
+namespace dokuwiki\Parsing\ParserMode;
+
+class Filelink extends AbstractMode
+{
+
+ protected $pattern;
+
+ /** @inheritdoc */
+ public function preConnect()
+ {
+
+ $ltrs = '\w';
+ $gunk = '/\#~:.?+=&%@!\-';
+ $punc = '.:?\-;,';
+ $host = $ltrs.$punc;
+ $any = $ltrs.$gunk.$punc;
+
+ $this->pattern = '\b(?i)file(?-i)://['.$any.']+?['.
+ $punc.']*[^'.$any.']';
+ }
+
+ /** @inheritdoc */
+ public function connectTo($mode)
+ {
+ $this->Lexer->addSpecialPattern(
+ $this->pattern,
+ $mode,
+ 'filelink'
+ );
+ }
+
+ /** @inheritdoc */
+ public function getSort()
+ {
+ return 360;
+ }
+}
diff --git a/inc/Parsing/ParserMode/Footnote.php b/inc/Parsing/ParserMode/Footnote.php
new file mode 100644
index 000000000..c399f9849
--- /dev/null
+++ b/inc/Parsing/ParserMode/Footnote.php
@@ -0,0 +1,50 @@
+<?php
+
+namespace dokuwiki\Parsing\ParserMode;
+
+class Footnote extends AbstractMode
+{
+
+ /**
+ * Footnote constructor.
+ */
+ public function __construct()
+ {
+ global $PARSER_MODES;
+
+ $this->allowedModes = array_merge(
+ $PARSER_MODES['container'],
+ $PARSER_MODES['formatting'],
+ $PARSER_MODES['substition'],
+ $PARSER_MODES['protected'],
+ $PARSER_MODES['disabled']
+ );
+
+ unset($this->allowedModes[array_search('footnote', $this->allowedModes)]);
+ }
+
+ /** @inheritdoc */
+ public function connectTo($mode)
+ {
+ $this->Lexer->addEntryPattern(
+ '\x28\x28(?=.*\x29\x29)',
+ $mode,
+ 'footnote'
+ );
+ }
+
+ /** @inheritdoc */
+ public function postConnect()
+ {
+ $this->Lexer->addExitPattern(
+ '\x29\x29',
+ 'footnote'
+ );
+ }
+
+ /** @inheritdoc */
+ public function getSort()
+ {
+ return 150;
+ }
+}
diff --git a/inc/Parsing/ParserMode/Formatting.php b/inc/Parsing/ParserMode/Formatting.php
new file mode 100644
index 000000000..a3c465cc0
--- /dev/null
+++ b/inc/Parsing/ParserMode/Formatting.php
@@ -0,0 +1,115 @@
+<?php
+
+namespace dokuwiki\Parsing\ParserMode;
+
+/**
+ * This class sets the markup for bold (=strong),
+ * italic (=emphasis), underline etc.
+ */
+class Formatting extends AbstractMode
+{
+ protected $type;
+
+ protected $formatting = array(
+ 'strong' => array(
+ 'entry' => '\*\*(?=.*\*\*)',
+ 'exit' => '\*\*',
+ 'sort' => 70
+ ),
+
+ 'emphasis' => array(
+ 'entry' => '//(?=[^\x00]*[^:])', //hack for bugs #384 #763 #1468
+ 'exit' => '//',
+ 'sort' => 80
+ ),
+
+ 'underline' => array(
+ 'entry' => '__(?=.*__)',
+ 'exit' => '__',
+ 'sort' => 90
+ ),
+
+ 'monospace' => array(
+ 'entry' => '\x27\x27(?=.*\x27\x27)',
+ 'exit' => '\x27\x27',
+ 'sort' => 100
+ ),
+
+ 'subscript' => array(
+ 'entry' => '<sub>(?=.*</sub>)',
+ 'exit' => '</sub>',
+ 'sort' => 110
+ ),
+
+ 'superscript' => array(
+ 'entry' => '<sup>(?=.*</sup>)',
+ 'exit' => '</sup>',
+ 'sort' => 120
+ ),
+
+ 'deleted' => array(
+ 'entry' => '<del>(?=.*</del>)',
+ 'exit' => '</del>',
+ 'sort' => 130
+ ),
+ );
+
+ /**
+ * @param string $type
+ */
+ public function __construct($type)
+ {
+ global $PARSER_MODES;
+
+ if (!array_key_exists($type, $this->formatting)) {
+ trigger_error('Invalid formatting type ' . $type, E_USER_WARNING);
+ }
+
+ $this->type = $type;
+
+ // formatting may contain other formatting but not it self
+ $modes = $PARSER_MODES['formatting'];
+ $key = array_search($type, $modes);
+ if (is_int($key)) {
+ unset($modes[$key]);
+ }
+
+ $this->allowedModes = array_merge(
+ $modes,
+ $PARSER_MODES['substition'],
+ $PARSER_MODES['disabled']
+ );
+ }
+
+ /** @inheritdoc */
+ public function connectTo($mode)
+ {
+
+ // Can't nest formatting in itself
+ if ($mode == $this->type) {
+ return;
+ }
+
+ $this->Lexer->addEntryPattern(
+ $this->formatting[$this->type]['entry'],
+ $mode,
+ $this->type
+ );
+ }
+
+ /** @inheritdoc */
+ public function postConnect()
+ {
+
+ $this->Lexer->addExitPattern(
+ $this->formatting[$this->type]['exit'],
+ $this->type
+ );
+ }
+
+ /** @inheritdoc */
+ public function getSort()
+ {
+ return $this->formatting[$this->type]['sort'];
+ }
+}
diff --git a/inc/Parsing/ParserMode/Header.php b/inc/Parsing/ParserMode/Header.php
new file mode 100644
index 000000000..854b3178c
--- /dev/null
+++ b/inc/Parsing/ParserMode/Header.php
@@ -0,0 +1,24 @@
+<?php
+
+namespace dokuwiki\Parsing\ParserMode;
+
+class Header extends AbstractMode
+{
+
+ /** @inheritdoc */
+ public function connectTo($mode)
+ {
+ //we're not picky about the closing ones, two are enough
+ $this->Lexer->addSpecialPattern(
+ '[ \t]*={2,}[^\n]+={2,}[ \t]*(?=\n)',
+ $mode,
+ 'header'
+ );
+ }
+
+ /** @inheritdoc */
+ public function getSort()
+ {
+ return 50;
+ }
+}
diff --git a/inc/Parsing/ParserMode/Hr.php b/inc/Parsing/ParserMode/Hr.php
new file mode 100644
index 000000000..e4f0b444b
--- /dev/null
+++ b/inc/Parsing/ParserMode/Hr.php
@@ -0,0 +1,19 @@
+<?php
+
+namespace dokuwiki\Parsing\ParserMode;
+
+class Hr extends AbstractMode
+{
+
+ /** @inheritdoc */
+ public function connectTo($mode)
+ {
+ $this->Lexer->addSpecialPattern('\n[ \t]*-{4,}[ \t]*(?=\n)', $mode, 'hr');
+ }
+
+ /** @inheritdoc */
+ public function getSort()
+ {
+ return 160;
+ }
+}
diff --git a/inc/Parsing/ParserMode/Html.php b/inc/Parsing/ParserMode/Html.php
new file mode 100644
index 000000000..f5b63ef09
--- /dev/null
+++ b/inc/Parsing/ParserMode/Html.php
@@ -0,0 +1,27 @@
+<?php
+
+namespace dokuwiki\Parsing\ParserMode;
+
+class Html extends AbstractMode
+{
+
+ /** @inheritdoc */
+ public function connectTo($mode)
+ {
+ $this->Lexer->addEntryPattern('<html>(?=.*</html>)', $mode, 'html');
+ $this->Lexer->addEntryPattern('<HTML>(?=.*</HTML>)', $mode, 'htmlblock');
+ }
+
+ /** @inheritdoc */
+ public function postConnect()
+ {
+ $this->Lexer->addExitPattern('</html>', 'html');
+ $this->Lexer->addExitPattern('</HTML>', 'htmlblock');
+ }
+
+ /** @inheritdoc */
+ public function getSort()
+ {
+ return 190;
+ }
+}
diff --git a/inc/Parsing/ParserMode/Internallink.php b/inc/Parsing/ParserMode/Internallink.php
new file mode 100644
index 000000000..6def0d9a3
--- /dev/null
+++ b/inc/Parsing/ParserMode/Internallink.php
@@ -0,0 +1,20 @@
+<?php
+
+namespace dokuwiki\Parsing\ParserMode;
+
+class Internallink extends AbstractMode
+{
+
+ /** @inheritdoc */
+ public function connectTo($mode)
+ {
+ // Word boundaries?
+ $this->Lexer->addSpecialPattern("\[\[.*?\]\](?!\])", $mode, 'internallink');
+ }
+
+ /** @inheritdoc */
+ public function getSort()
+ {
+ return 300;
+ }
+}
diff --git a/inc/Parsing/ParserMode/Linebreak.php b/inc/Parsing/ParserMode/Linebreak.php
new file mode 100644
index 000000000..dd95cc383
--- /dev/null
+++ b/inc/Parsing/ParserMode/Linebreak.php
@@ -0,0 +1,19 @@
+<?php
+
+namespace dokuwiki\Parsing\ParserMode;
+
+class Linebreak extends AbstractMode
+{
+
+ /** @inheritdoc */
+ public function connectTo($mode)
+ {
+ $this->Lexer->addSpecialPattern('\x5C{2}(?:[ \t]|(?=\n))', $mode, 'linebreak');
+ }
+
+ /** @inheritdoc */
+ public function getSort()
+ {
+ return 140;
+ }
+}
diff --git a/inc/Parsing/ParserMode/Listblock.php b/inc/Parsing/ParserMode/Listblock.php
new file mode 100644
index 000000000..eef762777
--- /dev/null
+++ b/inc/Parsing/ParserMode/Listblock.php
@@ -0,0 +1,44 @@
+<?php
+
+namespace dokuwiki\Parsing\ParserMode;
+
+class Listblock extends AbstractMode
+{
+
+ /**
+ * Listblock constructor.
+ */
+ public function __construct()
+ {
+ global $PARSER_MODES;
+
+ $this->allowedModes = array_merge(
+ $PARSER_MODES['formatting'],
+ $PARSER_MODES['substition'],
+ $PARSER_MODES['disabled'],
+ $PARSER_MODES['protected']
+ );
+ }
+
+ /** @inheritdoc */
+ public function connectTo($mode)
+ {
+ $this->Lexer->addEntryPattern('[ \t]*\n {2,}[\-\*]', $mode, 'listblock');
+ $this->Lexer->addEntryPattern('[ \t]*\n\t{1,}[\-\*]', $mode, 'listblock');
+
+ $this->Lexer->addPattern('\n {2,}[\-\*]', 'listblock');
+ $this->Lexer->addPattern('\n\t{1,}[\-\*]', 'listblock');
+ }
+
+ /** @inheritdoc */
+ public function postConnect()
+ {
+ $this->Lexer->addExitPattern('\n', 'listblock');
+ }
+
+ /** @inheritdoc */
+ public function getSort()
+ {
+ return 10;
+ }
+}
diff --git a/inc/Parsing/ParserMode/Media.php b/inc/Parsing/ParserMode/Media.php
new file mode 100644
index 000000000..f93f94773
--- /dev/null
+++ b/inc/Parsing/ParserMode/Media.php
@@ -0,0 +1,20 @@
+<?php
+
+namespace dokuwiki\Parsing\ParserMode;
+
+class Media extends AbstractMode
+{
+
+ /** @inheritdoc */
+ public function connectTo($mode)
+ {
+ // Word boundaries?
+ $this->Lexer->addSpecialPattern("\{\{(?:[^\}]|(?:\}[^\}]))+\}\}", $mode, 'media');
+ }
+
+ /** @inheritdoc */
+ public function getSort()
+ {
+ return 320;
+ }
+}
diff --git a/inc/Parsing/ParserMode/ModeInterface.php b/inc/Parsing/ParserMode/ModeInterface.php
new file mode 100644
index 000000000..7cca0385f
--- /dev/null
+++ b/inc/Parsing/ParserMode/ModeInterface.php
@@ -0,0 +1,46 @@
+<?php
+
+namespace dokuwiki\Parsing\ParserMode;
+
+/**
+ * Defines a mode (syntax component) in the Parser
+ */
+interface ModeInterface
+{
+ /**
+ * returns a number used to determine in which order modes are added
+ *
+ * @return int;
+ */
+ public function getSort();
+
+ /**
+ * Called before any calls to connectTo
+ *
+ * @return void
+ */
+ public function preConnect();
+
+ /**
+ * Connects the mode
+ *
+ * @param string $mode
+ * @return void
+ */
+ public function connectTo($mode);
+
+ /**
+ * Called after all calls to connectTo
+ *
+ * @return void
+ */
+ public function postConnect();
+
+ /**
+ * Check if given mode is accepted inside this mode
+ *
+ * @param string $mode
+ * @return bool
+ */
+ public function accepts($mode);
+}
diff --git a/inc/Parsing/ParserMode/Multiplyentity.php b/inc/Parsing/ParserMode/Multiplyentity.php
new file mode 100644
index 000000000..89df136df
--- /dev/null
+++ b/inc/Parsing/ParserMode/Multiplyentity.php
@@ -0,0 +1,27 @@
+<?php
+
+namespace dokuwiki\Parsing\ParserMode;
+
+/**
+ * Implements the 640x480 replacement
+ */
+class Multiplyentity extends AbstractMode
+{
+
+ /** @inheritdoc */
+ public function connectTo($mode)
+ {
+
+ $this->Lexer->addSpecialPattern(
+ '(?<=\b)(?:[1-9]|\d{2,})[xX]\d+(?=\b)',
+ $mode,
+ 'multiplyentity'
+ );
+ }
+
+ /** @inheritdoc */
+ public function getSort()
+ {
+ return 270;
+ }
+}
diff --git a/inc/Parsing/ParserMode/Nocache.php b/inc/Parsing/ParserMode/Nocache.php
new file mode 100644
index 000000000..fa6db8305
--- /dev/null
+++ b/inc/Parsing/ParserMode/Nocache.php
@@ -0,0 +1,19 @@
+<?php
+
+namespace dokuwiki\Parsing\ParserMode;
+
+class Nocache extends AbstractMode
+{
+
+ /** @inheritdoc */
+ public function connectTo($mode)
+ {
+ $this->Lexer->addSpecialPattern('~~NOCACHE~~', $mode, 'nocache');
+ }
+
+ /** @inheritdoc */
+ public function getSort()
+ {
+ return 40;
+ }
+}
diff --git a/inc/Parsing/ParserMode/Notoc.php b/inc/Parsing/ParserMode/Notoc.php
new file mode 100644
index 000000000..5956207c1
--- /dev/null
+++ b/inc/Parsing/ParserMode/Notoc.php
@@ -0,0 +1,19 @@
+<?php
+
+namespace dokuwiki\Parsing\ParserMode;
+
+class Notoc extends AbstractMode
+{
+
+ /** @inheritdoc */
+ public function connectTo($mode)
+ {
+ $this->Lexer->addSpecialPattern('~~NOTOC~~', $mode, 'notoc');
+ }
+
+ /** @inheritdoc */
+ public function getSort()
+ {
+ return 30;
+ }
+}
diff --git a/inc/Parsing/ParserMode/Php.php b/inc/Parsing/ParserMode/Php.php
new file mode 100644
index 000000000..914648b51
--- /dev/null
+++ b/inc/Parsing/ParserMode/Php.php
@@ -0,0 +1,27 @@
+<?php
+
+namespace dokuwiki\Parsing\ParserMode;
+
+class Php extends AbstractMode
+{
+
+ /** @inheritdoc */
+ public function connectTo($mode)
+ {
+ $this->Lexer->addEntryPattern('<php>(?=.*</php>)', $mode, 'php');
+ $this->Lexer->addEntryPattern('<PHP>(?=.*</PHP>)', $mode, 'phpblock');
+ }
+
+ /** @inheritdoc */
+ public function postConnect()
+ {
+ $this->Lexer->addExitPattern('</php>', 'php');
+ $this->Lexer->addExitPattern('</PHP>', 'phpblock');
+ }
+
+ /** @inheritdoc */
+ public function getSort()
+ {
+ return 180;
+ }
+}
diff --git a/inc/Parsing/ParserMode/Plugin.php b/inc/Parsing/ParserMode/Plugin.php
new file mode 100644
index 000000000..c885c6037
--- /dev/null
+++ b/inc/Parsing/ParserMode/Plugin.php
@@ -0,0 +1,8 @@
+<?php
+
+namespace dokuwiki\Parsing\ParserMode;
+
+/**
+ * @fixme do we need this anymore or could the syntax plugin inherit directly from abstract mode?
+ */
+abstract class Plugin extends AbstractMode {}
diff --git a/inc/Parsing/ParserMode/Preformatted.php b/inc/Parsing/ParserMode/Preformatted.php
new file mode 100644
index 000000000..7dfc47489
--- /dev/null
+++ b/inc/Parsing/ParserMode/Preformatted.php
@@ -0,0 +1,31 @@
+<?php
+
+namespace dokuwiki\Parsing\ParserMode;
+
+class Preformatted extends AbstractMode
+{
+
+ /** @inheritdoc */
+ public function connectTo($mode)
+ {
+ // Has hard coded awareness of lists...
+ $this->Lexer->addEntryPattern('\n (?![\*\-])', $mode, 'preformatted');
+ $this->Lexer->addEntryPattern('\n\t(?![\*\-])', $mode, 'preformatted');
+
+ // How to effect a sub pattern with the Lexer!
+ $this->Lexer->addPattern('\n ', 'preformatted');
+ $this->Lexer->addPattern('\n\t', 'preformatted');
+ }
+
+ /** @inheritdoc */
+ public function postConnect()
+ {
+ $this->Lexer->addExitPattern('\n', 'preformatted');
+ }
+
+ /** @inheritdoc */
+ public function getSort()
+ {
+ return 20;
+ }
+}
diff --git a/inc/Parsing/ParserMode/Quote.php b/inc/Parsing/ParserMode/Quote.php
new file mode 100644
index 000000000..65525b241
--- /dev/null
+++ b/inc/Parsing/ParserMode/Quote.php
@@ -0,0 +1,41 @@
+<?php
+
+namespace dokuwiki\Parsing\ParserMode;
+
+class Quote extends AbstractMode
+{
+
+ /**
+ * Quote constructor.
+ */
+ public function __construct()
+ {
+ global $PARSER_MODES;
+
+ $this->allowedModes = array_merge(
+ $PARSER_MODES['formatting'],
+ $PARSER_MODES['substition'],
+ $PARSER_MODES['disabled'],
+ $PARSER_MODES['protected']
+ );
+ }
+
+ /** @inheritdoc */
+ public function connectTo($mode)
+ {
+ $this->Lexer->addEntryPattern('\n>{1,}', $mode, 'quote');
+ }
+
+ /** @inheritdoc */
+ public function postConnect()
+ {
+ $this->Lexer->addPattern('\n>{1,}', 'quote');
+ $this->Lexer->addExitPattern('\n', 'quote');
+ }
+
+ /** @inheritdoc */
+ public function getSort()
+ {
+ return 220;
+ }
+}
diff --git a/inc/Parsing/ParserMode/Quotes.php b/inc/Parsing/ParserMode/Quotes.php
new file mode 100644
index 000000000..13db2e679
--- /dev/null
+++ b/inc/Parsing/ParserMode/Quotes.php
@@ -0,0 +1,51 @@
+<?php
+
+namespace dokuwiki\Parsing\ParserMode;
+
+class Quotes extends AbstractMode
+{
+
+ /** @inheritdoc */
+ public function connectTo($mode)
+ {
+ global $conf;
+
+ $ws = '\s/\#~:+=&%@\-\x28\x29\]\[{}><"\''; // whitespace
+ $punc = ';,\.?!';
+
+ if ($conf['typography'] == 2) {
+ $this->Lexer->addSpecialPattern(
+ "(?<=^|[$ws])'(?=[^$ws$punc])",
+ $mode,
+ 'singlequoteopening'
+ );
+ $this->Lexer->addSpecialPattern(
+ "(?<=^|[^$ws]|[$punc])'(?=$|[$ws$punc])",
+ $mode,
+ 'singlequoteclosing'
+ );
+ $this->Lexer->addSpecialPattern(
+ "(?<=^|[^$ws$punc])'(?=$|[^$ws$punc])",
+ $mode,
+ 'apostrophe'
+ );
+ }
+
+ $this->Lexer->addSpecialPattern(
+ "(?<=^|[$ws])\"(?=[^$ws$punc])",
+ $mode,
+ 'doublequoteopening'
+ );
+ $this->Lexer->addSpecialPattern(
+ "\"",
+ $mode,
+ 'doublequoteclosing'
+ );
+ }
+
+ /** @inheritdoc */
+ public function getSort()
+ {
+ return 280;
+ }
+}
diff --git a/inc/Parsing/ParserMode/Rss.php b/inc/Parsing/ParserMode/Rss.php
new file mode 100644
index 000000000..a62d9b807
--- /dev/null
+++ b/inc/Parsing/ParserMode/Rss.php
@@ -0,0 +1,19 @@
+<?php
+
+namespace dokuwiki\Parsing\ParserMode;
+
+class Rss extends AbstractMode
+{
+
+ /** @inheritdoc */
+ public function connectTo($mode)
+ {
+ $this->Lexer->addSpecialPattern("\{\{rss>[^\}]+\}\}", $mode, 'rss');
+ }
+
+ /** @inheritdoc */
+ public function getSort()
+ {
+ return 310;
+ }
+}
diff --git a/inc/Parsing/ParserMode/Smiley.php b/inc/Parsing/ParserMode/Smiley.php
new file mode 100644
index 000000000..084ccc9ed
--- /dev/null
+++ b/inc/Parsing/ParserMode/Smiley.php
@@ -0,0 +1,48 @@
+<?php
+
+namespace dokuwiki\Parsing\ParserMode;
+
+use dokuwiki\Parsing\Lexer\Lexer;
+
+class Smiley extends AbstractMode
+{
+ protected $smileys = array();
+ protected $pattern = '';
+
+ /**
+ * Smiley constructor.
+ * @param string[] $smileys
+ */
+ public function __construct($smileys)
+ {
+ $this->smileys = $smileys;
+ }
+
+ /** @inheritdoc */
+ public function preConnect()
+ {
+ if (!count($this->smileys) || $this->pattern != '') return;
+
+ $sep = '';
+ foreach ($this->smileys as $smiley) {
+ $this->pattern .= $sep.'(?<=\W|^)'. Lexer::escape($smiley).'(?=\W|$)';
+ $sep = '|';
+ }
+ }
+
+ /** @inheritdoc */
+ public function connectTo($mode)
+ {
+ if (!count($this->smileys)) return;
+
+ if (strlen($this->pattern) > 0) {
+ $this->Lexer->addSpecialPattern($this->pattern, $mode, 'smiley');
+ }
+ }
+
+ /** @inheritdoc */
+ public function getSort()
+ {
+ return 230;
+ }
+}
diff --git a/inc/Parsing/ParserMode/Table.php b/inc/Parsing/ParserMode/Table.php
new file mode 100644
index 000000000..b4b512380
--- /dev/null
+++ b/inc/Parsing/ParserMode/Table.php
@@ -0,0 +1,47 @@
+<?php
+
+namespace dokuwiki\Parsing\ParserMode;
+
+class Table extends AbstractMode
+{
+
+ /**
+ * Table constructor.
+ */
+ public function __construct()
+ {
+ global $PARSER_MODES;
+
+ $this->allowedModes = array_merge(
+ $PARSER_MODES['formatting'],
+ $PARSER_MODES['substition'],
+ $PARSER_MODES['disabled'],
+ $PARSER_MODES['protected']
+ );
+ }
+
+ /** @inheritdoc */
+ public function connectTo($mode)
+ {
+ $this->Lexer->addEntryPattern('[\t ]*\n\^', $mode, 'table');
+ $this->Lexer->addEntryPattern('[\t ]*\n\|', $mode, 'table');
+ }
+
+ /** @inheritdoc */
+ public function postConnect()
+ {
+ $this->Lexer->addPattern('\n\^', 'table');
+ $this->Lexer->addPattern('\n\|', 'table');
+ $this->Lexer->addPattern('[\t ]*:::[\t ]*(?=[\|\^])', 'table');
+ $this->Lexer->addPattern('[\t ]+', 'table');
+ $this->Lexer->addPattern('\^', 'table');
+ $this->Lexer->addPattern('\|', 'table');
+ $this->Lexer->addExitPattern('\n', 'table');
+ }
+
+ /** @inheritdoc */
+ public function getSort()
+ {
+ return 60;
+ }
+}
diff --git a/inc/Parsing/ParserMode/Unformatted.php b/inc/Parsing/ParserMode/Unformatted.php
new file mode 100644
index 000000000..1bc2826e6
--- /dev/null
+++ b/inc/Parsing/ParserMode/Unformatted.php
@@ -0,0 +1,28 @@
+<?php
+
+namespace dokuwiki\Parsing\ParserMode;
+
+class Unformatted extends AbstractMode
+{
+
+ /** @inheritdoc */
+ public function connectTo($mode)
+ {
+ $this->Lexer->addEntryPattern('<nowiki>(?=.*</nowiki>)', $mode, 'unformatted');
+ $this->Lexer->addEntryPattern('%%(?=.*%%)', $mode, 'unformattedalt');
+ }
+
+ /** @inheritdoc */
+ public function postConnect()
+ {
+ $this->Lexer->addExitPattern('</nowiki>', 'unformatted');
+ $this->Lexer->addExitPattern('%%', 'unformattedalt');
+ $this->Lexer->mapHandler('unformattedalt', 'unformatted');
+ }
+
+ /** @inheritdoc */
+ public function getSort()
+ {
+ return 170;
+ }
+}
diff --git a/inc/Parsing/ParserMode/Windowssharelink.php b/inc/Parsing/ParserMode/Windowssharelink.php
new file mode 100644
index 000000000..747d4d8a9
--- /dev/null
+++ b/inc/Parsing/ParserMode/Windowssharelink.php
@@ -0,0 +1,31 @@
+<?php
+
+namespace dokuwiki\Parsing\ParserMode;
+
+class Windowssharelink extends AbstractMode
+{
+
+ protected $pattern;
+
+ /** @inheritdoc */
+ public function preConnect()
+ {
+ $this->pattern = "\\\\\\\\\w+?(?:\\\\[\w\-$]+)+";
+ }
+
+ /** @inheritdoc */
+ public function connectTo($mode)
+ {
+ $this->Lexer->addSpecialPattern(
+ $this->pattern,
+ $mode,
+ 'windowssharelink'
+ );
+ }
+
+ /** @inheritdoc */
+ public function getSort()
+ {
+ return 350;
+ }
+}
diff --git a/inc/Parsing/ParserMode/Wordblock.php b/inc/Parsing/ParserMode/Wordblock.php
new file mode 100644
index 000000000..50b24b2db
--- /dev/null
+++ b/inc/Parsing/ParserMode/Wordblock.php
@@ -0,0 +1,52 @@
+<?php
+
+namespace dokuwiki\Parsing\ParserMode;
+
+use dokuwiki\Parsing\Lexer\Lexer;
+
+/**
+ * @fixme is this actually used?
+ */
+class Wordblock extends AbstractMode
+{
+ protected $badwords = array();
+ protected $pattern = '';
+
+ /**
+ * Wordblock constructor.
+ * @param $badwords
+ */
+ public function __construct($badwords)
+ {
+ $this->badwords = $badwords;
+ }
+
+ /** @inheritdoc */
+ public function preConnect()
+ {
+
+ if (count($this->badwords) == 0 || $this->pattern != '') {
+ return;
+ }
+
+ $sep = '';
+ foreach ($this->badwords as $badword) {
+ $this->pattern .= $sep.'(?<=\b)(?i)'. Lexer::escape($badword).'(?-i)(?=\b)';
+ $sep = '|';
+ }
+ }
+
+ /** @inheritdoc */
+ public function connectTo($mode)
+ {
+ if (strlen($this->pattern) > 0) {
+ $this->Lexer->addSpecialPattern($this->pattern, $mode, 'wordblock');
+ }
+ }
+
+ /** @inheritdoc */
+ public function getSort()
+ {
+ return 250;
+ }
+}
diff --git a/inc/PassHash.class.php b/inc/PassHash.php
index 56c7cfd79..8ac623cd1 100644
--- a/inc/PassHash.class.php
+++ b/inc/PassHash.php
@@ -1,4 +1,8 @@
<?php
+// phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
+
+namespace dokuwiki;
+
/**
* Password Hashing Class
*
@@ -21,7 +25,7 @@ class PassHash {
* @param string $hash Hash to compare against
* @return bool
*/
- function verify_hash($clear, $hash) {
+ public function verify_hash($clear, $hash) {
$method = '';
$salt = '';
$magic = '';
@@ -72,7 +76,7 @@ class PassHash {
} elseif(preg_match('/^\$6\$(rounds=\d+)?\$?(.+?)\$/', $hash, $m)) {
$method = 'sha512';
$salt = $m[2];
- $magic = $m[1];
+ $magic = $m[1];
} elseif($len == 32) {
$method = 'md5';
} elseif($len == 40) {
@@ -354,7 +358,7 @@ class PassHash {
* @param string $salt The salt to use, null for random
* @param string $magic The hash identifier (P or H)
* @param int $compute The iteration count for new passwords
- * @throws Exception
+ * @throws \Exception
* @return string Hashed password
*/
public function hash_pmd5($clear, $salt = null, $magic = 'P', $compute = 8) {
@@ -367,7 +371,7 @@ class PassHash {
$iter = strpos($itoa64, $iterc);
if($iter > 30) {
- throw new Exception("Too high iteration count ($iter) in ".
+ throw new \Exception("Too high iteration count ($iter) in ".
__CLASS__.'::'.__FUNCTION__);
}
@@ -412,6 +416,7 @@ class PassHash {
* @param int $compute
*
* @return string
+ * @throws \Exception
*/
public function hash_hmd5($clear, $salt = null, $magic = 'H', $compute = 8) {
return $this->hash_pmd5($clear, $salt, $magic, $compute);
@@ -461,7 +466,7 @@ class PassHash {
* @param string $salt The salt to use, null for random
* @param array $opts ('algo' => hash algorithm, 'iter' => iterations)
* @return string Hashed password
- * @throws Exception when PHP is missing support for the method/algo
+ * @throws \Exception when PHP is missing support for the method/algo
*/
public function hash_djangopbkdf2($clear, $salt=null, $opts=array()) {
$this->init_salt($salt, 12);
@@ -476,10 +481,10 @@ class PassHash {
$iter = (int) $opts['iter'];
}
if(!function_exists('hash_pbkdf2')) {
- throw new Exception('This PHP installation has no PBKDF2 support');
+ throw new \Exception('This PHP installation has no PBKDF2 support');
}
if(!in_array($algo, hash_algos())) {
- throw new Exception("This PHP installation has no $algo support");
+ throw new \Exception("This PHP installation has no $algo support");
}
$hash = base64_encode(hash_pbkdf2($algo, $clear, $salt, $iter, 0, true));
@@ -493,7 +498,7 @@ class PassHash {
* @param string $salt The salt to use, null for random
* @param array $opts ('iter' => iterations)
* @return string Hashed password
- * @throws Exception when PHP is missing support for the method/algo
+ * @throws \Exception when PHP is missing support for the method/algo
*/
public function hash_djangopbkdf2_sha256($clear, $salt=null, $opts=array()) {
$opts['algo'] = 'sha256';
@@ -507,7 +512,7 @@ class PassHash {
* @param string $salt The salt to use, null for random
* @param array $opts ('iter' => iterations)
* @return string Hashed password
- * @throws Exception when PHP is missing support for the method/algo
+ * @throws \Exception when PHP is missing support for the method/algo
*/
public function hash_djangopbkdf2_sha1($clear, $salt=null, $opts=array()) {
$opts['algo'] = 'sha1';
@@ -528,12 +533,12 @@ class PassHash {
* @param string $clear The clear text to hash
* @param string $salt The salt to use, null for random
* @param int $compute The iteration count (between 4 and 31)
- * @throws Exception
+ * @throws \Exception
* @return string Hashed password
*/
public function hash_bcrypt($clear, $salt = null, $compute = 10) {
if(!defined('CRYPT_BLOWFISH') || CRYPT_BLOWFISH != 1) {
- throw new Exception('This PHP installation has no bcrypt support');
+ throw new \Exception('This PHP installation has no bcrypt support');
}
if(is_null($salt)) {
@@ -553,20 +558,20 @@ class PassHash {
*
* @param string $clear The clear text to hash
* @param string $salt The salt to use, null for random
- * @param string $magic The rounds for sha512 (for example "rounds=3000"), null for default value
+ * @param string $magic The rounds for sha512 (for example "rounds=3000"), null for default value
* @return string Hashed password
- * @throws Exception
+ * @throws \Exception
*/
public function hash_sha512($clear, $salt = null, $magic = null) {
if(!defined('CRYPT_SHA512') || CRYPT_SHA512 != 1) {
- throw new Exception('This PHP installation has no SHA512 support');
+ throw new \Exception('This PHP installation has no SHA512 support');
}
$this->init_salt($salt, 8, false);
- if(empty($magic)) {
- return crypt($clear, '$6$'.$salt.'$');
- }else{
- return crypt($clear, '$6$'.$magic.'$'.$salt.'$');
- }
+ if(empty($magic)) {
+ return crypt($clear, '$6$'.$salt.'$');
+ }else{
+ return crypt($clear, '$6$'.$magic.'$'.$salt.'$');
+ }
}
/**
@@ -633,13 +638,19 @@ class PassHash {
}
/**
- * Use DokuWiki's secure random generator if available
+ * Use a secure random generator
*
* @param int $min
* @param int $max
* @return int
*/
protected function random($min, $max){
- return random_int($min, $max);
+ try {
+ return random_int($min, $max);
+ } catch (\Exception $e) {
+ // availability of random source is checked elsewhere in DokuWiki
+ // we demote this to an unchecked runtime exception here
+ throw new \RuntimeException($e->getMessage(), $e->getCode(), $e);
+ }
}
}
diff --git a/inc/Plugin.php b/inc/Plugin.php
deleted file mode 100644
index 9cd0ae805..000000000
--- a/inc/Plugin.php
+++ /dev/null
@@ -1,11 +0,0 @@
-<?php
-
-/**
- * DokuWiki Plugin
- *
- * Most of DokuWiki's plugin types simply inherit from this. All it does is
- * add the DokuWiki_PluginTrait to the class.
- */
-class DokuWiki_Plugin implements DokuWiki_PluginInterface {
- use DokuWiki_PluginTrait;
-}
diff --git a/inc/Remote/AccessDeniedException.php b/inc/Remote/AccessDeniedException.php
new file mode 100644
index 000000000..65f668930
--- /dev/null
+++ b/inc/Remote/AccessDeniedException.php
@@ -0,0 +1,10 @@
+<?php
+
+namespace dokuwiki\Remote;
+
+/**
+ * Class AccessDeniedException
+ */
+class AccessDeniedException extends RemoteException
+{
+}
diff --git a/inc/remote.php b/inc/Remote/Api.php
index 2d2e327c8..5d9def59a 100644
--- a/inc/remote.php
+++ b/inc/Remote/Api.php
@@ -1,9 +1,9 @@
<?php
-if (!defined('DOKU_INC')) die();
+namespace dokuwiki\Remote;
-class RemoteException extends Exception {}
-class RemoteAccessDeniedException extends RemoteException {}
+use dokuwiki\Extension\Event;
+use dokuwiki\Extension\RemotePlugin;
/**
* This class provides information about remote access to the wiki.
@@ -33,19 +33,18 @@ class RemoteAccessDeniedException extends RemoteException {}
*
* plugin methods are formed like 'plugin.<plugin name>.<method name>'.
* i.e.: plugin.clock.getTime or plugin.clock_gmt.getTime
- *
- * @throws RemoteException
*/
-class RemoteAPI {
+class Api
+{
/**
- * @var RemoteAPICore
+ * @var ApiCore
*/
private $coreMethods = null;
/**
* @var array remote methods provided by dokuwiki plugins - will be filled lazy via
- * {@see RemoteAPI#getPluginMethods}
+ * {@see dokuwiki\Remote\RemoteAPI#getPluginMethods}
*/
private $pluginMethods = null;
@@ -63,7 +62,8 @@ class RemoteAPI {
/**
* constructor
*/
- public function __construct() {
+ public function __construct()
+ {
$this->dateTransformation = array($this, 'dummyTransformation');
$this->fileTransformation = array($this, 'dummyTransformation');
}
@@ -72,8 +72,10 @@ class RemoteAPI {
* Get all available methods with remote access.
*
* @return array with information to all available methods
+ * @throws RemoteException
*/
- public function getMethods() {
+ public function getMethods()
+ {
return array_merge($this->getCoreMethods(), $this->getPluginMethods());
}
@@ -83,8 +85,10 @@ class RemoteAPI {
* @param string $method name of the method to call.
* @param array $args arguments to pass to the given method
* @return mixed result of method call, must be a primitive type.
+ * @throws RemoteException
*/
- public function call($method, $args = array()) {
+ public function call($method, $args = array())
+ {
if ($args === null) {
$args = array();
}
@@ -104,7 +108,8 @@ class RemoteAPI {
* @param string $name name of the method
* @return bool if method exists
*/
- private function coreMethodExist($name) {
+ private function coreMethodExist($name)
+ {
$coreMethods = $this->getCoreMethods();
return array_key_exists($name, $coreMethods);
}
@@ -113,11 +118,12 @@ class RemoteAPI {
* Try to call custom methods provided by plugins
*
* @param string $method name of method
- * @param array $args
+ * @param array $args
* @return mixed
* @throws RemoteException if method not exists
*/
- private function callCustomCallPlugin($method, $args) {
+ private function callCustomCallPlugin($method, $args)
+ {
$customCalls = $this->getCustomCallPlugins();
if (!array_key_exists($method, $customCalls)) {
throw new RemoteException('Method does not exist', -32603);
@@ -132,10 +138,11 @@ class RemoteAPI {
* @return array with pairs of custom plugin calls
* @triggers RPC_CALL_ADD
*/
- private function getCustomCallPlugins() {
+ private function getCustomCallPlugins()
+ {
if ($this->pluginCustomCalls === null) {
$data = array();
- trigger_event('RPC_CALL_ADD', $data);
+ Event::createAndTrigger('RPC_CALL_ADD', $data);
$this->pluginCustomCalls = $data;
}
return $this->pluginCustomCalls;
@@ -146,11 +153,12 @@ class RemoteAPI {
*
* @param string $pluginName
* @param string $method method name
- * @param array $args
+ * @param array $args
* @return mixed return of custom method
* @throws RemoteException
*/
- private function callPlugin($pluginName, $method, $args) {
+ private function callPlugin($pluginName, $method, $args)
+ {
$plugin = plugin_load('remote', $pluginName);
$methods = $this->getPluginMethods();
if (!$plugin) {
@@ -165,11 +173,12 @@ class RemoteAPI {
* Call a core method
*
* @param string $method name of method
- * @param array $args
+ * @param array $args
* @return mixed
* @throws RemoteException if method not exist
*/
- private function callCoreMethod($method, $args) {
+ private function callCoreMethod($method, $args)
+ {
$coreMethods = $this->getCoreMethods();
$this->checkAccess($coreMethods[$method]);
if (!isset($coreMethods[$method])) {
@@ -183,11 +192,13 @@ class RemoteAPI {
* Check if access should be checked
*
* @param array $methodMeta data about the method
+ * @throws AccessDeniedException
*/
- private function checkAccess($methodMeta) {
+ private function checkAccess($methodMeta)
+ {
if (!isset($methodMeta['public'])) {
$this->forceAccess();
- } else{
+ } else {
if ($methodMeta['public'] == '0') {
$this->forceAccess();
}
@@ -201,7 +212,8 @@ class RemoteAPI {
* @param array $args
* @throws RemoteException if wrong parameter count
*/
- private function checkArgumentLength($methodMeta, $args) {
+ private function checkArgumentLength($methodMeta, $args)
+ {
if (count($methodMeta['args']) < count($args)) {
throw new RemoteException('Method does not exist - wrong parameter count.', -32603);
}
@@ -214,36 +226,38 @@ class RemoteAPI {
* @param string $method name of method
* @return string
*/
- private function getMethodName($methodMeta, $method) {
+ private function getMethodName($methodMeta, $method)
+ {
if (isset($methodMeta[$method]['name'])) {
return $methodMeta[$method]['name'];
}
$method = explode('.', $method);
- return $method[count($method)-1];
+ return $method[count($method) - 1];
}
/**
* Perform access check for current user
*
* @return bool true if the current user has access to remote api.
- * @throws RemoteAccessDeniedException If remote access disabled
+ * @throws AccessDeniedException If remote access disabled
*/
- public function hasAccess() {
+ public function hasAccess()
+ {
global $conf;
global $USERINFO;
- /** @var Input $INPUT */
+ /** @var \dokuwiki\Input\Input $INPUT */
global $INPUT;
if (!$conf['remote']) {
- throw new RemoteAccessDeniedException('server error. RPC server not enabled.',-32604); //should not be here,just throw
+ throw new AccessDeniedException('server error. RPC server not enabled.', -32604);
}
- if(trim($conf['remoteuser']) == '!!not set!!') {
+ if (trim($conf['remoteuser']) == '!!not set!!') {
return false;
}
- if(!$conf['useacl']) {
+ if (!$conf['useacl']) {
return true;
}
- if(trim($conf['remoteuser']) == '') {
+ if (trim($conf['remoteuser']) == '') {
return true;
}
@@ -254,11 +268,12 @@ class RemoteAPI {
* Requests access
*
* @return void
- * @throws RemoteException On denied access.
+ * @throws AccessDeniedException On denied access.
*/
- public function forceAccess() {
+ public function forceAccess()
+ {
if (!$this->hasAccess()) {
- throw new RemoteAccessDeniedException('server error. not authorized to call method', -32604);
+ throw new AccessDeniedException('server error. not authorized to call method', -32604);
}
}
@@ -268,19 +283,27 @@ class RemoteAPI {
* @return array all plugin methods.
* @throws RemoteException if not implemented
*/
- public function getPluginMethods() {
+ public function getPluginMethods()
+ {
if ($this->pluginMethods === null) {
$this->pluginMethods = array();
$plugins = plugin_list('remote');
foreach ($plugins as $pluginName) {
- /** @var DokuWiki_Remote_Plugin $plugin */
+ /** @var RemotePlugin $plugin */
$plugin = plugin_load('remote', $pluginName);
- if (!is_subclass_of($plugin, 'DokuWiki_Remote_Plugin')) {
- throw new RemoteException("Plugin $pluginName does not implement DokuWiki_Remote_Plugin");
+ if (!is_subclass_of($plugin, 'dokuwiki\Extension\RemotePlugin')) {
+ throw new RemoteException(
+ "Plugin $pluginName does not implement dokuwiki\Plugin\DokuWiki_Remote_Plugin"
+ );
+ }
+
+ try {
+ $methods = $plugin->_getMethods();
+ } catch (\ReflectionException $e) {
+ throw new RemoteException('Automatic aggregation of available remote methods failed', 0, $e);
}
- $methods = $plugin->_getMethods();
foreach ($methods as $method => $meta) {
$this->pluginMethods["plugin.$pluginName.$method"] = $meta;
}
@@ -292,14 +315,15 @@ class RemoteAPI {
/**
* Collects all the core methods
*
- * @param RemoteAPICore $apiCore this parameter is used for testing. Here you can pass a non-default RemoteAPICore
- * instance. (for mocking)
+ * @param ApiCore $apiCore this parameter is used for testing. Here you can pass a non-default RemoteAPICore
+ * instance. (for mocking)
* @return array all core methods.
*/
- public function getCoreMethods($apiCore = null) {
+ public function getCoreMethods($apiCore = null)
+ {
if ($this->coreMethods === null) {
if ($apiCore === null) {
- $this->coreMethods = new RemoteAPICore($this);
+ $this->coreMethods = new ApiCore($this);
} else {
$this->coreMethods = $apiCore;
}
@@ -313,7 +337,8 @@ class RemoteAPI {
* @param mixed $data
* @return mixed
*/
- public function toFile($data) {
+ public function toFile($data)
+ {
return call_user_func($this->fileTransformation, $data);
}
@@ -323,7 +348,8 @@ class RemoteAPI {
* @param mixed $data
* @return mixed
*/
- public function toDate($data) {
+ public function toDate($data)
+ {
return call_user_func($this->dateTransformation, $data);
}
@@ -333,7 +359,8 @@ class RemoteAPI {
* @param mixed $data
* @return mixed
*/
- public function dummyTransformation($data) {
+ public function dummyTransformation($data)
+ {
return $data;
}
@@ -342,7 +369,8 @@ class RemoteAPI {
*
* @param callback $dateTransformation
*/
- public function setDateTransformation($dateTransformation) {
+ public function setDateTransformation($dateTransformation)
+ {
$this->dateTransformation = $dateTransformation;
}
@@ -351,7 +379,8 @@ class RemoteAPI {
*
* @param callback $fileTransformation
*/
- public function setFileTransformation($fileTransformation) {
+ public function setFileTransformation($fileTransformation)
+ {
$this->fileTransformation = $fileTransformation;
}
}
diff --git a/inc/RemoteAPICore.php b/inc/Remote/ApiCore.php
index c56d20cb0..9a041452d 100644
--- a/inc/RemoteAPICore.php
+++ b/inc/Remote/ApiCore.php
@@ -1,22 +1,32 @@
<?php
-/**
- * Increased whenever the API is changed
- */
+namespace dokuwiki\Remote;
+
+use Doku_Renderer_xhtml;
+use dokuwiki\ChangeLog\MediaChangeLog;
+use dokuwiki\ChangeLog\PageChangeLog;
+use dokuwiki\Extension\Event;
+
define('DOKU_API_VERSION', 10);
/**
* Provides the core methods for the remote API.
* The methods are ordered in 'wiki.<method>' and 'dokuwiki.<method>' namespaces
*/
-class RemoteAPICore {
+class ApiCore
+{
+ /** @var int Increased whenever the API is changed */
+ const API_VERSION = 10;
+
+ /** @var Api */
private $api;
/**
- * @param RemoteAPI $api
+ * @param Api $api
*/
- public function __construct(RemoteAPI $api) {
+ public function __construct(Api $api)
+ {
$this->api = $api;
}
@@ -25,7 +35,8 @@ class RemoteAPICore {
*
* @return array
*/
- public function __getRemoteInfo() {
+ public function __getRemoteInfo()
+ {
return array(
'dokuwiki.getVersion' => array(
'args' => array(),
@@ -52,7 +63,7 @@ class RemoteAPICore {
), 'dokuwiki.getTime' => array(
'args' => array(),
'return' => 'int',
- 'doc' => 'Returns the current time at the remote wiki server as Unix timestamp.',
+ 'doc' => 'Returns the current time at the remote wiki server as Unix timestamp.',
), 'dokuwiki.setLocks' => array(
'args' => array('array'),
'return' => 'array',
@@ -165,7 +176,7 @@ class RemoteAPICore {
'public' => '1',
), 'wiki.getRPCVersionSupported' => array(
'args' => array(),
- 'name' => 'wiki_RPCVersion',
+ 'name' => 'wikiRpcVersion',
'return' => 'int',
'doc' => 'Returns 2 with the supported RPC API version.',
'public' => '1'
@@ -177,14 +188,16 @@ class RemoteAPICore {
/**
* @return string
*/
- public function getVersion() {
+ public function getVersion()
+ {
return getVersion();
}
/**
* @return int unix timestamp
*/
- public function getTime() {
+ public function getTime()
+ {
return time();
}
@@ -194,15 +207,16 @@ class RemoteAPICore {
* @param string $id wiki page id
* @param int|string $rev revision timestamp of the page or empty string
* @return string page text.
- * @throws RemoteAccessDeniedException if no permission for page
+ * @throws AccessDeniedException if no permission for page
*/
- public function rawPage($id,$rev=''){
+ public function rawPage($id, $rev = '')
+ {
$id = $this->resolvePageId($id);
- if(auth_quickaclcheck($id) < AUTH_READ){
- throw new RemoteAccessDeniedException('You are not allowed to read this file', 111);
+ if (auth_quickaclcheck($id) < AUTH_READ) {
+ throw new AccessDeniedException('You are not allowed to read this file', 111);
}
- $text = rawWiki($id,$rev);
- if(!$text) {
+ $text = rawWiki($id, $rev);
+ if (!$text) {
return pageTemplate($id);
} else {
return $text;
@@ -216,13 +230,14 @@ class RemoteAPICore {
*
* @param string $id file id
* @return mixed media file
- * @throws RemoteAccessDeniedException no permission for media
+ * @throws AccessDeniedException no permission for media
* @throws RemoteException not exist
*/
- public function getAttachment($id){
+ public function getAttachment($id)
+ {
$id = cleanID($id);
- if (auth_quickaclcheck(getNS($id).':*') < AUTH_READ) {
- throw new RemoteAccessDeniedException('You are not allowed to read this file', 211);
+ if (auth_quickaclcheck(getNS($id) . ':*') < AUTH_READ) {
+ throw new AccessDeniedException('You are not allowed to read this file', 211);
}
$file = mediaFN($id);
@@ -242,7 +257,8 @@ class RemoteAPICore {
* @param string $id page id
* @return array
*/
- public function getAttachmentInfo($id){
+ public function getAttachmentInfo($id)
+ {
$id = cleanID($id);
$info = array(
'lastModified' => $this->api->toDate(0),
@@ -250,15 +266,15 @@ class RemoteAPICore {
);
$file = mediaFN($id);
- if(auth_quickaclcheck(getNS($id) . ':*') >= AUTH_READ) {
- if(file_exists($file)) {
+ if (auth_quickaclcheck(getNS($id) . ':*') >= AUTH_READ) {
+ if (file_exists($file)) {
$info['lastModified'] = $this->api->toDate(filemtime($file));
$info['size'] = filesize($file);
} else {
//Is it deleted media with changelog?
$medialog = new MediaChangeLog($id);
$revisions = $medialog->getRevisions(0, 1);
- if(!empty($revisions)) {
+ if (!empty($revisions)) {
$info['lastModified'] = $this->api->toDate($revisions[0]);
}
}
@@ -270,17 +286,18 @@ class RemoteAPICore {
/**
* Return a wiki page rendered to html
*
- * @param string $id page id
+ * @param string $id page id
* @param string|int $rev revision timestamp or empty string
* @return null|string html
- * @throws RemoteAccessDeniedException no access to page
+ * @throws AccessDeniedException no access to page
*/
- public function htmlPage($id,$rev=''){
+ public function htmlPage($id, $rev = '')
+ {
$id = $this->resolvePageId($id);
- if(auth_quickaclcheck($id) < AUTH_READ){
- throw new RemoteAccessDeniedException('You are not allowed to read this page', 111);
+ if (auth_quickaclcheck($id) < AUTH_READ) {
+ throw new AccessDeniedException('You are not allowed to read this page', 111);
}
- return p_wiki_xhtml($id,$rev,false);
+ return p_wiki_xhtml($id, $rev, false);
}
/**
@@ -288,14 +305,15 @@ class RemoteAPICore {
*
* @return array
*/
- public function listPages(){
- $list = array();
+ public function listPages()
+ {
+ $list = array();
$pages = idx_get_indexer()->getPages();
- $pages = array_filter(array_filter($pages,'isVisiblePage'),'page_exists');
+ $pages = array_filter(array_filter($pages, 'isVisiblePage'), 'page_exists');
- foreach(array_keys($pages) as $idx) {
+ foreach (array_keys($pages) as $idx) {
$perm = auth_quickaclcheck($pages[$idx]);
- if($perm < AUTH_READ) {
+ if ($perm < AUTH_READ) {
continue;
}
$page = array();
@@ -313,15 +331,16 @@ class RemoteAPICore {
* List all pages in the given namespace (and below)
*
* @param string $ns
- * @param array $opts
+ * @param array $opts
* $opts['depth'] recursion level, 0 for all
* $opts['hash'] do md5 sum of content?
* @return array
*/
- public function readNamespace($ns,$opts){
+ public function readNamespace($ns, $opts)
+ {
global $conf;
- if(!is_array($opts)) $opts=array();
+ if (!is_array($opts)) $opts = array();
$ns = cleanID($ns);
$dir = utf8_encodeFN(str_replace(':', '/', $ns));
@@ -337,29 +356,30 @@ class RemoteAPICore {
* @param string $query
* @return array
*/
- public function search($query){
+ public function search($query)
+ {
$regex = array();
- $data = ft_pageSearch($query,$regex);
+ $data = ft_pageSearch($query, $regex);
$pages = array();
// prepare additional data
$idx = 0;
- foreach($data as $id => $score){
+ foreach ($data as $id => $score) {
$file = wikiFN($id);
- if($idx < FT_SNIPPET_NUMBER){
- $snippet = ft_snippet($id,$regex);
+ if ($idx < FT_SNIPPET_NUMBER) {
+ $snippet = ft_snippet($id, $regex);
$idx++;
- }else{
+ } else {
$snippet = '';
}
$pages[] = array(
- 'id' => $id,
- 'score' => intval($score),
- 'rev' => filemtime($file),
- 'mtime' => filemtime($file),
- 'size' => filesize($file),
+ 'id' => $id,
+ 'score' => intval($score),
+ 'rev' => filemtime($file),
+ 'mtime' => filemtime($file),
+ 'size' => filesize($file),
'snippet' => $snippet,
'title' => useHeading('navigation') ? p_get_first_heading($id) : $id
);
@@ -372,7 +392,8 @@ class RemoteAPICore {
*
* @return string
*/
- public function getTitle(){
+ public function getTitle()
+ {
global $conf;
return $conf['title'];
}
@@ -387,15 +408,16 @@ class RemoteAPICore {
* @author Gina Haeussge <osd@foosel.net>
*
* @param string $ns
- * @param array $options
+ * @param array $options
* $options['depth'] recursion level, 0 for all
* $options['showmsg'] shows message if invalid media id is used
* $options['pattern'] check given pattern
* $options['hash'] add hashes to result list
* @return array
- * @throws RemoteAccessDeniedException no access to the media files
+ * @throws AccessDeniedException no access to the media files
*/
- public function listAttachments($ns, $options = array()) {
+ public function listAttachments($ns, $options = array())
+ {
global $conf;
$ns = cleanID($ns);
@@ -403,15 +425,15 @@ class RemoteAPICore {
if (!is_array($options)) $options = array();
$options['skipacl'] = 0; // no ACL skipping for XMLRPC
- if(auth_quickaclcheck($ns.':*') >= AUTH_READ) {
+ if (auth_quickaclcheck($ns . ':*') >= AUTH_READ) {
$dir = utf8_encodeFN(str_replace(':', '/', $ns));
$data = array();
search($data, $conf['mediadir'], 'search_media', $options, $dir);
$len = count($data);
- if(!$len) return array();
+ if (!$len) return array();
- for($i=0; $i<$len; $i++) {
+ for ($i = 0; $i < $len; $i++) {
unset($data[$i]['meta']);
$data[$i]['perms'] = $data[$i]['perm'];
unset($data[$i]['perm']);
@@ -419,7 +441,7 @@ class RemoteAPICore {
}
return $data;
} else {
- throw new RemoteAccessDeniedException('You are not allowed to list media files.', 215);
+ throw new AccessDeniedException('You are not allowed to list media files.', 215);
}
}
@@ -429,33 +451,35 @@ class RemoteAPICore {
* @param string $id page id
* @return array
*/
- function listBackLinks($id){
+ public function listBackLinks($id)
+ {
return ft_backlinks($this->resolvePageId($id));
}
/**
* Return some basic data about a page
*
- * @param string $id page id
+ * @param string $id page id
* @param string|int $rev revision timestamp or empty string
* @return array
- * @throws RemoteAccessDeniedException no access for page
+ * @throws AccessDeniedException no access for page
* @throws RemoteException page not exist
*/
- public function pageInfo($id,$rev=''){
+ public function pageInfo($id, $rev = '')
+ {
$id = $this->resolvePageId($id);
- if(auth_quickaclcheck($id) < AUTH_READ){
- throw new RemoteAccessDeniedException('You are not allowed to read this page', 111);
+ if (auth_quickaclcheck($id) < AUTH_READ) {
+ throw new AccessDeniedException('You are not allowed to read this page', 111);
}
- $file = wikiFN($id,$rev);
+ $file = wikiFN($id, $rev);
$time = @filemtime($file);
- if(!$time){
+ if (!$time) {
throw new RemoteException('The requested page does not exist', 121);
}
// set revision to current version if empty, use revision otherwise
// as the timestamps of old files are not necessarily correct
- if($rev === '') {
+ if ($rev === '') {
$rev = $time;
}
@@ -463,10 +487,10 @@ class RemoteAPICore {
$info = $pagelog->getRevisionInfo($rev);
$data = array(
- 'name' => $id,
+ 'name' => $id,
'lastModified' => $this->api->toDate($rev),
- 'author' => (($info['user']) ? $info['user'] : $info['ip']),
- 'version' => $rev
+ 'author' => (($info['user']) ? $info['user'] : $info['ip']),
+ 'version' => $rev
);
return ($data);
@@ -481,53 +505,54 @@ class RemoteAPICore {
* @param string $text wiki text
* @param array $params parameters: summary, minor edit
* @return bool
- * @throws RemoteAccessDeniedException no write access for page
+ * @throws AccessDeniedException no write access for page
* @throws RemoteException no id, empty new page or locked
*/
- public function putPage($id, $text, $params) {
+ public function putPage($id, $text, $params)
+ {
global $TEXT;
global $lang;
- $id = $this->resolvePageId($id);
- $TEXT = cleanText($text);
- $sum = $params['sum'];
+ $id = $this->resolvePageId($id);
+ $TEXT = cleanText($text);
+ $sum = $params['sum'];
$minor = $params['minor'];
- if(empty($id)) {
+ if (empty($id)) {
throw new RemoteException('Empty page ID', 131);
}
- if(!page_exists($id) && trim($TEXT) == '' ) {
+ if (!page_exists($id) && trim($TEXT) == '') {
throw new RemoteException('Refusing to write an empty new wiki page', 132);
}
- if(auth_quickaclcheck($id) < AUTH_EDIT) {
- throw new RemoteAccessDeniedException('You are not allowed to edit this page', 112);
+ if (auth_quickaclcheck($id) < AUTH_EDIT) {
+ throw new AccessDeniedException('You are not allowed to edit this page', 112);
}
// Check, if page is locked
- if(checklock($id)) {
+ if (checklock($id)) {
throw new RemoteException('The page is currently locked', 133);
}
// SPAM check
- if(checkwordblock()) {
+ if (checkwordblock()) {
throw new RemoteException('Positive wordblock check', 134);
}
// autoset summary on new pages
- if(!page_exists($id) && empty($sum)) {
+ if (!page_exists($id) && empty($sum)) {
$sum = $lang['created'];
}
// autoset summary on deleted pages
- if(page_exists($id) && empty($TEXT) && empty($sum)) {
+ if (page_exists($id) && empty($TEXT) && empty($sum)) {
$sum = $lang['deleted'];
}
lock($id);
- saveWikiText($id,$TEXT,$sum,$minor);
+ saveWikiText($id, $TEXT, $sum, $minor);
unlock($id);
@@ -544,13 +569,15 @@ class RemoteAPICore {
* @param string $text wiki text
* @param array $params such as summary,minor
* @return bool|string
+ * @throws RemoteException
*/
- public function appendPage($id, $text, $params) {
+ public function appendPage($id, $text, $params)
+ {
$currentpage = $this->rawPage($id);
if (!is_string($currentpage)) {
return $currentpage;
}
- return $this->putPage($id, $currentpage.$text, $params);
+ return $this->putPage($id, $currentpage . $text, $params);
}
/**
@@ -560,14 +587,14 @@ class RemoteAPICore {
*
* @return bool
*
- * @throws RemoteAccessDeniedException
+ * @throws AccessDeniedException
*/
public function deleteUsers($usernames)
{
if (!auth_isadmin()) {
- throw new RemoteAccessDeniedException('Only admins are allowed to delete users', 114);
+ throw new AccessDeniedException('Only admins are allowed to delete users', 114);
}
- /** @var DokuWiki_Auth_Plugin $auth */
+ /** @var \dokuwiki\Extension\AuthPlugin $auth */
global $auth;
return (bool)$auth->triggerUserMod('delete', array($usernames));
}
@@ -583,17 +610,18 @@ class RemoteAPICore {
* @return false|string
* @throws RemoteException
*/
- public function putAttachment($id, $file, $params) {
+ public function putAttachment($id, $file, $params)
+ {
$id = cleanID($id);
- $auth = auth_quickaclcheck(getNS($id).':*');
+ $auth = auth_quickaclcheck(getNS($id) . ':*');
- if(!isset($id)) {
+ if (!isset($id)) {
throw new RemoteException('Filename not given.', 231);
}
global $conf;
- $ftmp = $conf['tmpdir'] . '/' . md5($id.clientIP());
+ $ftmp = $conf['tmpdir'] . '/' . md5($id . clientIP());
// save temporary file
@unlink($ftmp);
@@ -614,17 +642,18 @@ class RemoteAPICore {
*
* @param string $id page id
* @return int
- * @throws RemoteAccessDeniedException no permissions
+ * @throws AccessDeniedException no permissions
* @throws RemoteException file in use or not deleted
*/
- public function deleteAttachment($id){
+ public function deleteAttachment($id)
+ {
$id = cleanID($id);
- $auth = auth_quickaclcheck(getNS($id).':*');
+ $auth = auth_quickaclcheck(getNS($id) . ':*');
$res = media_delete($id, $auth);
if ($res & DOKU_MEDIA_DELETED) {
return 0;
} elseif ($res & DOKU_MEDIA_NOT_AUTH) {
- throw new RemoteAccessDeniedException('You don\'t have permissions to delete files.', 212);
+ throw new AccessDeniedException('You don\'t have permissions to delete files.', 212);
} elseif ($res & DOKU_MEDIA_INUSE) {
throw new RemoteException('File is still referenced', 232);
} else {
@@ -640,17 +669,18 @@ class RemoteAPICore {
* @param array|null $groups array of groups
* @return int permission level
*/
- public function aclCheck($id, $user = null, $groups = null) {
- /** @var DokuWiki_Auth_Plugin $auth */
+ public function aclCheck($id, $user = null, $groups = null)
+ {
+ /** @var \dokuwiki\Extension\AuthPlugin $auth */
global $auth;
$id = $this->resolvePageId($id);
- if($user === null) {
+ if ($user === null) {
return auth_quickaclcheck($id);
} else {
- if($groups === null) {
+ if ($groups === null) {
$userinfo = $auth->getUserData($user);
- if($userinfo === false) {
+ if ($userinfo === false) {
$groups = array();
} else {
$groups = $userinfo['grps'];
@@ -667,44 +697,45 @@ class RemoteAPICore {
*
* @param string $id page id
* @return array
- * @throws RemoteAccessDeniedException no read access for page
+ * @throws AccessDeniedException no read access for page
*/
- public function listLinks($id) {
+ public function listLinks($id)
+ {
$id = $this->resolvePageId($id);
- if(auth_quickaclcheck($id) < AUTH_READ){
- throw new RemoteAccessDeniedException('You are not allowed to read this page', 111);
+ if (auth_quickaclcheck($id) < AUTH_READ) {
+ throw new AccessDeniedException('You are not allowed to read this page', 111);
}
$links = array();
// resolve page instructions
- $ins = p_cached_instructions(wikiFN($id));
+ $ins = p_cached_instructions(wikiFN($id));
// instantiate new Renderer - needed for interwiki links
$Renderer = new Doku_Renderer_xhtml();
$Renderer->interwiki = getInterwiki();
// parse parse instructions
- foreach($ins as $in) {
+ foreach ($ins as $in) {
$link = array();
- switch($in[0]) {
+ switch ($in[0]) {
case 'internallink':
$link['type'] = 'local';
$link['page'] = $in[1][0];
$link['href'] = wl($in[1][0]);
- array_push($links,$link);
+ array_push($links, $link);
break;
case 'externallink':
$link['type'] = 'extern';
$link['page'] = $in[1][0];
$link['href'] = $in[1][0];
- array_push($links,$link);
+ array_push($links, $link);
break;
case 'interwikilink':
- $url = $Renderer->_resolveInterWiki($in[1][2],$in[1][3]);
+ $url = $Renderer->_resolveInterWiki($in[1][2], $in[1][3]);
$link['type'] = 'extern';
$link['page'] = $url;
$link['href'] = $url;
- array_push($links,$link);
+ array_push($links, $link);
break;
}
}
@@ -722,8 +753,9 @@ class RemoteAPICore {
* @return array
* @throws RemoteException no valid timestamp
*/
- public function getRecentChanges($timestamp) {
- if(strlen($timestamp) != 10) {
+ public function getRecentChanges($timestamp)
+ {
+ if (strlen($timestamp) != 10) {
throw new RemoteException('The provided value is not a valid timestamp', 311);
}
@@ -733,12 +765,12 @@ class RemoteAPICore {
foreach ($recents as $recent) {
$change = array();
- $change['name'] = $recent['id'];
+ $change['name'] = $recent['id'];
$change['lastModified'] = $this->api->toDate($recent['date']);
- $change['author'] = $recent['user'];
- $change['version'] = $recent['date'];
- $change['perms'] = $recent['perms'];
- $change['size'] = @filesize(wikiFN($recent['id']));
+ $change['author'] = $recent['user'];
+ $change['version'] = $recent['date'];
+ $change['perms'] = $recent['perms'];
+ $change['size'] = @filesize(wikiFN($recent['id']));
array_push($changes, $change);
}
@@ -760,8 +792,9 @@ class RemoteAPICore {
* @return array
* @throws RemoteException no valid timestamp
*/
- public function getRecentMediaChanges($timestamp) {
- if(strlen($timestamp) != 10)
+ public function getRecentMediaChanges($timestamp)
+ {
+ if (strlen($timestamp) != 10)
throw new RemoteException('The provided value is not a valid timestamp', 311);
$recents = getRecentsSince($timestamp, null, '', RECENTS_MEDIA_CHANGES);
@@ -770,12 +803,12 @@ class RemoteAPICore {
foreach ($recents as $recent) {
$change = array();
- $change['name'] = $recent['id'];
+ $change['name'] = $recent['id'];
$change['lastModified'] = $this->api->toDate($recent['date']);
- $change['author'] = $recent['user'];
- $change['version'] = $recent['date'];
- $change['perms'] = $recent['perms'];
- $change['size'] = @filesize(mediaFN($recent['id']));
+ $change['author'] = $recent['user'];
+ $change['version'] = $recent['date'];
+ $change['perms'] = $recent['perms'];
+ $change['size'] = @filesize(mediaFN($recent['id']));
array_push($changes, $change);
}
@@ -794,22 +827,26 @@ class RemoteAPICore {
*
* @author Michael Klier <chi@chimeric.de>
*
- * @param string $id page id
- * @param int $first skip the first n changelog lines (0 = from current(if exists), 1 = from 1st old rev, 2 = from 2nd old rev, etc)
+ * @param string $id page id
+ * @param int $first skip the first n changelog lines
+ * 0 = from current(if exists)
+ * 1 = from 1st old rev
+ * 2 = from 2nd old rev, etc
* @return array
- * @throws RemoteAccessDeniedException no read access for page
+ * @throws AccessDeniedException no read access for page
* @throws RemoteException empty id
*/
- public function pageVersions($id, $first) {
+ public function pageVersions($id, $first)
+ {
$id = $this->resolvePageId($id);
- if(auth_quickaclcheck($id) < AUTH_READ) {
- throw new RemoteAccessDeniedException('You are not allowed to read this page', 111);
+ if (auth_quickaclcheck($id) < AUTH_READ) {
+ throw new AccessDeniedException('You are not allowed to read this page', 111);
}
global $conf;
$versions = array();
- if(empty($id)) {
+ if (empty($id)) {
throw new RemoteException('Empty page ID', 131);
}
@@ -819,29 +856,29 @@ class RemoteAPICore {
$pagelog = new PageChangeLog($id);
$revisions = $pagelog->getRevisions($first_rev, $conf['recent']);
- if($first == 0) {
+ if ($first == 0) {
array_unshift($revisions, ''); // include current revision
- if ( count($revisions) > $conf['recent'] ){
+ if (count($revisions) > $conf['recent']) {
array_pop($revisions); // remove extra log entry
}
}
- if(!empty($revisions)) {
- foreach($revisions as $rev) {
- $file = wikiFN($id,$rev);
+ if (!empty($revisions)) {
+ foreach ($revisions as $rev) {
+ $file = wikiFN($id, $rev);
$time = @filemtime($file);
// we check if the page actually exists, if this is not the
// case this can lead to less pages being returned than
// specified via $conf['recent']
- if($time){
+ if ($time) {
$pagelog->setChunkSize(1024);
$info = $pagelog->getRevisionInfo($rev ? $rev : $time);
- if(!empty($info)) {
+ if (!empty($info)) {
$data = array();
$data['user'] = $info['user'];
- $data['ip'] = $info['ip'];
+ $data['ip'] = $info['ip'];
$data['type'] = $info['type'];
- $data['sum'] = $info['sum'];
+ $data['sum'] = $info['sum'];
$data['modified'] = $this->api->toDate($info['date']);
$data['version'] = $info['date'];
array_push($versions, $data);
@@ -857,11 +894,11 @@ class RemoteAPICore {
/**
* The version of Wiki RPC API supported
*/
- public function wiki_RPCVersion(){
+ public function wikiRpcVersion()
+ {
return 2;
}
-
/**
* Locks or unlocks a given batch of pages
*
@@ -874,35 +911,36 @@ class RemoteAPICore {
* @param array[] $set list pages with array('lock' => array, 'unlock' => array)
* @return array
*/
- public function setLocks($set){
- $locked = array();
- $lockfail = array();
- $unlocked = array();
+ public function setLocks($set)
+ {
+ $locked = array();
+ $lockfail = array();
+ $unlocked = array();
$unlockfail = array();
- foreach((array) $set['lock'] as $id){
+ foreach ((array) $set['lock'] as $id) {
$id = $this->resolvePageId($id);
- if(auth_quickaclcheck($id) < AUTH_EDIT || checklock($id)){
+ if (auth_quickaclcheck($id) < AUTH_EDIT || checklock($id)) {
$lockfail[] = $id;
- }else{
+ } else {
lock($id);
$locked[] = $id;
}
}
- foreach((array) $set['unlock'] as $id){
+ foreach ((array) $set['unlock'] as $id) {
$id = $this->resolvePageId($id);
- if(auth_quickaclcheck($id) < AUTH_EDIT || !unlock($id)){
+ if (auth_quickaclcheck($id) < AUTH_EDIT || !unlock($id)) {
$unlockfail[] = $id;
- }else{
+ } else {
$unlocked[] = $id;
}
}
return array(
- 'locked' => $locked,
- 'lockfail' => $lockfail,
- 'unlocked' => $unlocked,
+ 'locked' => $locked,
+ 'lockfail' => $lockfail,
+ 'unlocked' => $unlocked,
'unlockfail' => $unlockfail,
);
}
@@ -912,8 +950,9 @@ class RemoteAPICore {
*
* @return int
*/
- public function getAPIVersion(){
- return DOKU_API_VERSION;
+ public function getAPIVersion()
+ {
+ return self::API_VERSION;
}
/**
@@ -923,25 +962,26 @@ class RemoteAPICore {
* @param string $pass
* @return int
*/
- public function login($user,$pass){
+ public function login($user, $pass)
+ {
global $conf;
- /** @var DokuWiki_Auth_Plugin $auth */
+ /** @var \dokuwiki\Extension\AuthPlugin $auth */
global $auth;
- if(!$conf['useacl']) return 0;
- if(!$auth) return 0;
+ if (!$conf['useacl']) return 0;
+ if (!$auth) return 0;
@session_start(); // reopen session for login
- if($auth->canDo('external')){
- $ok = $auth->trustExternal($user,$pass,false);
- }else{
+ if ($auth->canDo('external')) {
+ $ok = $auth->trustExternal($user, $pass, false);
+ } else {
$evdata = array(
- 'user' => $user,
+ 'user' => $user,
'password' => $pass,
- 'sticky' => false,
- 'silent' => true,
+ 'sticky' => false,
+ 'silent' => true,
);
- $ok = trigger_event('AUTH_LOGIN_CHECK', $evdata, 'auth_login_wrapper');
+ $ok = Event::createAndTrigger('AUTH_LOGIN_CHECK', $evdata, 'auth_login_wrapper');
}
session_write_close(); // we're done with the session
@@ -953,11 +993,12 @@ class RemoteAPICore {
*
* @return int
*/
- public function logoff(){
+ public function logoff()
+ {
global $conf;
global $auth;
- if(!$conf['useacl']) return 0;
- if(!$auth) return 0;
+ if (!$conf['useacl']) return 0;
+ if (!$auth) return 0;
auth_logoff();
@@ -970,14 +1011,13 @@ class RemoteAPICore {
* @param string $id page id
* @return string
*/
- private function resolvePageId($id) {
+ private function resolvePageId($id)
+ {
$id = cleanID($id);
- if(empty($id)) {
+ if (empty($id)) {
global $conf;
$id = cleanID($conf['start']);
}
return $id;
}
-
}
-
diff --git a/inc/Remote/RemoteException.php b/inc/Remote/RemoteException.php
new file mode 100644
index 000000000..129a6c240
--- /dev/null
+++ b/inc/Remote/RemoteException.php
@@ -0,0 +1,10 @@
+<?php
+
+namespace dokuwiki\Remote;
+
+/**
+ * Class RemoteException
+ */
+class RemoteException extends \Exception
+{
+}
diff --git a/inc/Remote/XmlRpcServer.php b/inc/Remote/XmlRpcServer.php
new file mode 100644
index 000000000..1b0097856
--- /dev/null
+++ b/inc/Remote/XmlRpcServer.php
@@ -0,0 +1,61 @@
+<?php
+
+namespace dokuwiki\Remote;
+
+/**
+ * Contains needed wrapper functions and registers all available XMLRPC functions.
+ */
+class XmlRpcServer extends \IXR_Server
+{
+ protected $remote;
+
+ /**
+ * Constructor. Register methods and run Server
+ */
+ public function __construct()
+ {
+ $this->remote = new Api();
+ $this->remote->setDateTransformation(array($this, 'toDate'));
+ $this->remote->setFileTransformation(array($this, 'toFile'));
+ parent::__construct();
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function call($methodname, $args)
+ {
+ try {
+ $result = $this->remote->call($methodname, $args);
+ return $result;
+ } /** @noinspection PhpRedundantCatchClauseInspection */ catch (AccessDeniedException $e) {
+ if (!isset($_SERVER['REMOTE_USER'])) {
+ http_status(401);
+ return new \IXR_Error(-32603, "server error. not authorized to call method $methodname");
+ } else {
+ http_status(403);
+ return new \IXR_Error(-32604, "server error. forbidden to call the method $methodname");
+ }
+ } catch (RemoteException $e) {
+ return new \IXR_Error($e->getCode(), $e->getMessage());
+ }
+ }
+
+ /**
+ * @param string|int $data iso date(yyyy[-]mm[-]dd[ hh:mm[:ss]]) or timestamp
+ * @return \IXR_Date
+ */
+ public function toDate($data)
+ {
+ return new \IXR_Date($data);
+ }
+
+ /**
+ * @param string $data
+ * @return \IXR_Base64
+ */
+ public function toFile($data)
+ {
+ return new \IXR_Base64($data);
+ }
+}
diff --git a/inc/SafeFN.class.php b/inc/SafeFN.class.php
index b9e4a2b2a..c5489b185 100644
--- a/inc/SafeFN.class.php
+++ b/inc/SafeFN.class.php
@@ -45,7 +45,7 @@ class SafeFN {
* @author Christopher Smith <chris@jalakai.co.uk>
*/
public static function encode($filename) {
- return self::unicode_to_safe(utf8_to_unicode($filename));
+ return self::unicodeToSafe(\dokuwiki\Utf8\Unicode::fromUtf8($filename));
}
/**
@@ -74,14 +74,14 @@ class SafeFN {
* @author Christopher Smith <chris@jalakai.co.uk>
*/
public static function decode($filename) {
- return unicode_to_utf8(self::safe_to_unicode(strtolower($filename)));
+ return \dokuwiki\Utf8\Unicode::toUtf8(self::safeToUnicode(strtolower($filename)));
}
- public static function validate_printable_utf8($printable_utf8) {
+ public static function validatePrintableUtf8($printable_utf8) {
return !preg_match('#[\x01-\x1f]#',$printable_utf8);
}
- public static function validate_safe($safe) {
+ public static function validateSafe($safe) {
return !preg_match('#[^'.self::$plain.self::$post_indicator.self::$pre_indicator.']#',$safe);
}
@@ -93,7 +93,7 @@ class SafeFN {
*
* @author Christopher Smith <chris@jalakai.co.uk>
*/
- private static function unicode_to_safe($unicode) {
+ private static function unicodeToSafe($unicode) {
$safe = '';
$converted = false;
@@ -126,7 +126,7 @@ class SafeFN {
*
* @author Christopher Smith <chris@jalakai.co.uk>
*/
- private static function safe_to_unicode($safe) {
+ private static function safeToUnicode($safe) {
$unicode = array();
$split = preg_split('#(?=['.self::$post_indicator.self::$pre_indicator.'])#',$safe,-1,PREG_SPLIT_NO_EMPTY);
diff --git a/inc/Sitemap/Item.php b/inc/Sitemap/Item.php
new file mode 100644
index 000000000..d11bfc135
--- /dev/null
+++ b/inc/Sitemap/Item.php
@@ -0,0 +1,66 @@
+<?php
+
+namespace dokuwiki\Sitemap;
+
+/**
+ * An item of a sitemap.
+ *
+ * @author Michael Hamann
+ */
+class Item {
+ public $url;
+ public $lastmod;
+ public $changefreq;
+ public $priority;
+
+ /**
+ * Create a new item.
+ *
+ * @param string $url The url of the item
+ * @param int $lastmod Timestamp of the last modification
+ * @param string $changefreq How frequently the item is likely to change.
+ * Valid values: always, hourly, daily, weekly, monthly, yearly, never.
+ * @param $priority float|string The priority of the item relative to other URLs on your site.
+ * Valid values range from 0.0 to 1.0.
+ */
+ public function __construct($url, $lastmod, $changefreq = null, $priority = null) {
+ $this->url = $url;
+ $this->lastmod = $lastmod;
+ $this->changefreq = $changefreq;
+ $this->priority = $priority;
+ }
+
+ /**
+ * Helper function for creating an item for a wikipage id.
+ *
+ * @param string $id A wikipage id.
+ * @param string $changefreq How frequently the item is likely to change.
+ * Valid values: always, hourly, daily, weekly, monthly, yearly, never.
+ * @param float|string $priority The priority of the item relative to other URLs on your site.
+ * Valid values range from 0.0 to 1.0.
+ * @return Item The sitemap item.
+ */
+ public static function createFromID($id, $changefreq = null, $priority = null) {
+ $id = trim($id);
+ $date = @filemtime(wikiFN($id));
+ if(!$date) return null;
+ return new Item(wl($id, '', true), $date, $changefreq, $priority);
+ }
+
+ /**
+ * Get the XML representation of the sitemap item.
+ *
+ * @return string The XML representation.
+ */
+ public function toXML() {
+ $result = ' <url>'.NL
+ .' <loc>'.hsc($this->url).'</loc>'.NL
+ .' <lastmod>'.date_iso8601($this->lastmod).'</lastmod>'.NL;
+ if ($this->changefreq !== null)
+ $result .= ' <changefreq>'.hsc($this->changefreq).'</changefreq>'.NL;
+ if ($this->priority !== null)
+ $result .= ' <priority>'.hsc($this->priority).'</priority>'.NL;
+ $result .= ' </url>'.NL;
+ return $result;
+ }
+}
diff --git a/inc/Sitemapper.php b/inc/Sitemap/Mapper.php
index 037990e96..2f0567f05 100644
--- a/inc/Sitemapper.php
+++ b/inc/Sitemap/Mapper.php
@@ -6,14 +6,16 @@
* @author Michael Hamann <michael@content-space.de>
*/
-if(!defined('DOKU_INC')) die('meh.');
+namespace dokuwiki\Sitemap;
+
+use dokuwiki\HTTP\DokuHTTPClient;
/**
* A class for building sitemaps and pinging search engines with the sitemap URL.
*
* @author Michael Hamann
*/
-class Sitemapper {
+class Mapper {
/**
* Builds a Google Sitemap of all public pages known to the indexer
*
@@ -31,7 +33,7 @@ class Sitemapper {
global $conf;
if($conf['sitemap'] < 1 || !is_numeric($conf['sitemap'])) return false;
- $sitemap = Sitemapper::getFilePath();
+ $sitemap = Mapper::getFilePath();
if(file_exists($sitemap)){
if(!is_writable($sitemap)) return false;
@@ -56,16 +58,16 @@ class Sitemapper {
//skip hidden, non existing and restricted files
if(isHiddenPage($id)) continue;
if(auth_aclcheck($id,'',array()) < AUTH_READ) continue;
- $item = SitemapItem::createFromID($id);
+ $item = Item::createFromID($id);
if ($item !== null)
$items[] = $item;
}
$eventData = array('items' => &$items, 'sitemap' => &$sitemap);
- $event = new Doku_Event('SITEMAP_GENERATE', $eventData);
+ $event = new \dokuwiki\Extension\Event('SITEMAP_GENERATE', $eventData);
if ($event->advise_before(true)) {
//save the new sitemap
- $event->result = io_saveFile($sitemap, Sitemapper::getXML($items));
+ $event->result = io_saveFile($sitemap, Mapper::getXML($items));
}
$event->advise_after();
@@ -85,7 +87,7 @@ class Sitemapper {
echo '<?xml version="1.0" encoding="UTF-8"?>'.NL;
echo '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">'.NL;
foreach ($items as $item) {
- /** @var SitemapItem $item */
+ /** @var Item $item */
echo $item->toXML();
}
echo '</urlset>'.NL;
@@ -145,7 +147,7 @@ class Sitemapper {
$data = array('ping_urls' => $ping_urls,
'encoded_sitemap_url' => $encoded_sitemap_url
);
- $event = new Doku_Event('SITEMAP_PING', $data);
+ $event = new \dokuwiki\Extension\Event('SITEMAP_PING', $data);
if ($event->advise_before(true)) {
foreach ($data['ping_urls'] as $name => $url) {
dbglog("Sitemapper::PingSearchEngines(): pinging $name");
@@ -160,61 +162,3 @@ class Sitemapper {
}
}
-/**
- * An item of a sitemap.
- *
- * @author Michael Hamann
- */
-class SitemapItem {
- public $url;
- public $lastmod;
- public $changefreq;
- public $priority;
-
- /**
- * Create a new item.
- *
- * @param string $url The url of the item
- * @param int $lastmod Timestamp of the last modification
- * @param string $changefreq How frequently the item is likely to change. Valid values: always, hourly, daily, weekly, monthly, yearly, never.
- * @param $priority float|string The priority of the item relative to other URLs on your site. Valid values range from 0.0 to 1.0.
- */
- public function __construct($url, $lastmod, $changefreq = null, $priority = null) {
- $this->url = $url;
- $this->lastmod = $lastmod;
- $this->changefreq = $changefreq;
- $this->priority = $priority;
- }
-
- /**
- * Helper function for creating an item for a wikipage id.
- *
- * @param string $id A wikipage id.
- * @param string $changefreq How frequently the item is likely to change. Valid values: always, hourly, daily, weekly, monthly, yearly, never.
- * @param float|string $priority The priority of the item relative to other URLs on your site. Valid values range from 0.0 to 1.0.
- * @return SitemapItem The sitemap item.
- */
- public static function createFromID($id, $changefreq = null, $priority = null) {
- $id = trim($id);
- $date = @filemtime(wikiFN($id));
- if(!$date) return null;
- return new SitemapItem(wl($id, '', true), $date, $changefreq, $priority);
- }
-
- /**
- * Get the XML representation of the sitemap item.
- *
- * @return string The XML representation.
- */
- public function toXML() {
- $result = ' <url>'.NL
- .' <loc>'.hsc($this->url).'</loc>'.NL
- .' <lastmod>'.date_iso8601($this->lastmod).'</lastmod>'.NL;
- if ($this->changefreq !== null)
- $result .= ' <changefreq>'.hsc($this->changefreq).'</changefreq>'.NL;
- if ($this->priority !== null)
- $result .= ' <priority>'.hsc($this->priority).'</priority>'.NL;
- $result .= ' </url>'.NL;
- return $result;
- }
-}
diff --git a/inc/StyleUtils.php b/inc/StyleUtils.php
index f2ac4be5e..d9f19a58b 100644
--- a/inc/StyleUtils.php
+++ b/inc/StyleUtils.php
@@ -2,6 +2,11 @@
namespace dokuwiki;
+/**
+ * Class StyleUtils
+ *
+ * Reads and applies the template's style.ini settings
+ */
class StyleUtils
{
@@ -95,23 +100,27 @@ class StyleUtils
$config = parse_ini_file($inifile, true);
if (is_array($config['stylesheets'])) {
-
foreach ($config['stylesheets'] as $inifile => $mode) {
// validate and include style files
- $stylesheets = array_merge($stylesheets, $this->getValidatedStyles($stylesheets, $inifile, $mode, $incbase, $webbase));
+ $stylesheets = array_merge(
+ $stylesheets,
+ $this->getValidatedStyles($stylesheets, $inifile, $mode, $incbase, $webbase)
+ );
$combined['stylesheets'] = array_merge($combined['stylesheets'], $stylesheets);
}
}
if (is_array($config['replacements'])) {
- $replacements = array_replace($replacements, $this->cssFixreplacementurls($config['replacements'], $webbase));
+ $replacements = array_replace(
+ $replacements,
+ $this->cssFixreplacementurls($config['replacements'], $webbase)
+ );
$combined['replacements'] = array_merge($combined['replacements'], $replacements);
}
}
}
}
-
return $combined;
}
@@ -134,7 +143,8 @@ class StyleUtils
if (file_exists($incbase . $basename . '.' . $newExtension)) {
$stylesheets[$mode][$incbase . $basename . '.' . $newExtension] = $webbase;
if ($conf['allowdebug']) {
- msg("Stylesheet $file not found, using $basename.$newExtension instead. Please contact developer of \"$this->tpl\" template.", 2);
+ msg("Stylesheet $file not found, using $basename.$newExtension instead. " .
+ "Please contact developer of \"$this->tpl\" template.", 2);
}
} elseif ($conf['allowdebug']) {
msg("Stylesheet $file not found, please contact the developer of \"$this->tpl\" template.", 2);
@@ -173,7 +183,11 @@ class StyleUtils
protected function cssFixreplacementurls($replacements, $location)
{
foreach ($replacements as $key => $value) {
- $replacements[$key] = preg_replace('#(url\([ \'"]*)(?!/|data:|http://|https://| |\'|")#', '\\1' . $location, $value);
+ $replacements[$key] = preg_replace(
+ '#(url\([ \'"]*)(?!/|data:|http://|https://| |\'|")#',
+ '\\1' . $location,
+ $value
+ );
}
return $replacements;
}
diff --git a/inc/Subscriptions/BulkSubscriptionSender.php b/inc/Subscriptions/BulkSubscriptionSender.php
new file mode 100644
index 000000000..672ef90f6
--- /dev/null
+++ b/inc/Subscriptions/BulkSubscriptionSender.php
@@ -0,0 +1,261 @@
+<?php
+
+
+namespace dokuwiki\Subscriptions;
+
+
+use dokuwiki\ChangeLog\PageChangeLog;
+use dokuwiki\Input\Input;
+use DokuWiki_Auth_Plugin;
+
+class BulkSubscriptionSender extends SubscriptionSender
+{
+
+ /**
+ * Send digest and list subscriptions
+ *
+ * This sends mails to all subscribers that have a subscription for namespaces above
+ * the given page if the needed $conf['subscribe_time'] has passed already.
+ *
+ * This function is called form lib/exe/indexer.php
+ *
+ * @param string $page
+ *
+ * @return int number of sent mails
+ */
+ public function sendBulk($page)
+ {
+ $subscriberManager = new SubscriberManager();
+ if (!$subscriberManager->isenabled()) {
+ return 0;
+ }
+
+ /** @var DokuWiki_Auth_Plugin $auth */
+ global $auth;
+ global $conf;
+ global $USERINFO;
+ /** @var Input $INPUT */
+ global $INPUT;
+ $count = 0;
+
+ $subscriptions = $subscriberManager->subscribers($page, null, ['digest', 'list']);
+
+ // remember current user info
+ $olduinfo = $USERINFO;
+ $olduser = $INPUT->server->str('REMOTE_USER');
+
+ foreach ($subscriptions as $target => $users) {
+ if (!$this->lock($target)) {
+ continue;
+ }
+
+ foreach ($users as $user => $info) {
+ list($style, $lastupdate) = $info;
+
+ $lastupdate = (int)$lastupdate;
+ if ($lastupdate + $conf['subscribe_time'] > time()) {
+ // Less than the configured time period passed since last
+ // update.
+ continue;
+ }
+
+ // Work as the user to make sure ACLs apply correctly
+ $USERINFO = $auth->getUserData($user);
+ $INPUT->server->set('REMOTE_USER', $user);
+ if ($USERINFO === false) {
+ continue;
+ }
+ if (!$USERINFO['mail']) {
+ continue;
+ }
+
+ if (substr($target, -1, 1) === ':') {
+ // subscription target is a namespace, get all changes within
+ $changes = getRecentsSince($lastupdate, null, getNS($target));
+ } else {
+ // single page subscription, check ACL ourselves
+ if (auth_quickaclcheck($target) < AUTH_READ) {
+ continue;
+ }
+ $meta = p_get_metadata($target);
+ $changes = [$meta['last_change']];
+ }
+
+ // Filter out pages only changed in small and own edits
+ $change_ids = [];
+ foreach ($changes as $rev) {
+ $n = 0;
+ while (!is_null($rev) && $rev['date'] >= $lastupdate &&
+ ($INPUT->server->str('REMOTE_USER') === $rev['user'] ||
+ $rev['type'] === DOKU_CHANGE_TYPE_MINOR_EDIT)) {
+ $pagelog = new PageChangeLog($rev['id']);
+ $rev = $pagelog->getRevisions($n++, 1);
+ $rev = (count($rev) > 0) ? $rev[0] : null;
+ }
+
+ if (!is_null($rev) && $rev['date'] >= $lastupdate) {
+ // Some change was not a minor one and not by myself
+ $change_ids[] = $rev['id'];
+ }
+ }
+
+ // send it
+ if ($style === 'digest') {
+ foreach ($change_ids as $change_id) {
+ $this->sendDigest(
+ $USERINFO['mail'],
+ $change_id,
+ $lastupdate
+ );
+ $count++;
+ }
+ } else {
+ if ($style === 'list') {
+ $this->sendList($USERINFO['mail'], $change_ids, $target);
+ $count++;
+ }
+ }
+ // TODO: Handle duplicate subscriptions.
+
+ // Update notification time.
+ $subscriberManager->add($target, $user, $style, time());
+ }
+ $this->unlock($target);
+ }
+
+ // restore current user info
+ $USERINFO = $olduinfo;
+ $INPUT->server->set('REMOTE_USER', $olduser);
+ return $count;
+ }
+
+ /**
+ * Lock subscription info
+ *
+ * We don't use io_lock() her because we do not wait for the lock and use a larger stale time
+ *
+ * @param string $id The target page or namespace, specified by id; Namespaces
+ * are identified by appending a colon.
+ *
+ * @return bool true, if you got a succesful lock
+ * @author Adrian Lang <lang@cosmocode.de>
+ */
+ protected function lock($id)
+ {
+ global $conf;
+
+ $lock = $conf['lockdir'] . '/_subscr_' . md5($id) . '.lock';
+
+ if (is_dir($lock) && time() - @filemtime($lock) > 60 * 5) {
+ // looks like a stale lock - remove it
+ @rmdir($lock);
+ }
+
+ // try creating the lock directory
+ if (!@mkdir($lock, $conf['dmode'])) {
+ return false;
+ }
+
+ if (!empty($conf['dperm'])) {
+ chmod($lock, $conf['dperm']);
+ }
+ return true;
+ }
+
+ /**
+ * Unlock subscription info
+ *
+ * @param string $id The target page or namespace, specified by id; Namespaces
+ * are identified by appending a colon.
+ *
+ * @return bool
+ * @author Adrian Lang <lang@cosmocode.de>
+ */
+ protected function unlock($id)
+ {
+ global $conf;
+ $lock = $conf['lockdir'] . '/_subscr_' . md5($id) . '.lock';
+ return @rmdir($lock);
+ }
+
+ /**
+ * Send a digest mail
+ *
+ * Sends a digest mail showing a bunch of changes of a single page. Basically the same as sendPageDiff()
+ * but determines the last known revision first
+ *
+ * @param string $subscriber_mail The target mail address
+ * @param string $id The ID
+ * @param int $lastupdate Time of the last notification
+ *
+ * @return bool
+ * @author Adrian Lang <lang@cosmocode.de>
+ *
+ */
+ protected function sendDigest($subscriber_mail, $id, $lastupdate)
+ {
+ $pagelog = new PageChangeLog($id);
+ $n = 0;
+ do {
+ $rev = $pagelog->getRevisions($n++, 1);
+ $rev = (count($rev) > 0) ? $rev[0] : null;
+ } while (!is_null($rev) && $rev > $lastupdate);
+
+ // TODO I'm not happy with the following line and passing $this->mailer around. Not sure how to solve it better
+ $pageSubSender = new PageSubscriptionSender($this->mailer);
+ return $pageSubSender->sendPageDiff(
+ $subscriber_mail,
+ 'subscr_digest',
+ $id,
+ $rev
+ );
+ }
+
+ /**
+ * Send a list mail
+ *
+ * Sends a list mail showing a list of changed pages.
+ *
+ * @param string $subscriber_mail The target mail address
+ * @param array $ids Array of ids
+ * @param string $ns_id The id of the namespace
+ *
+ * @return bool true if a mail was sent
+ * @author Adrian Lang <lang@cosmocode.de>
+ *
+ */
+ protected function sendList($subscriber_mail, $ids, $ns_id)
+ {
+ if (count($ids) === 0) {
+ return false;
+ }
+
+ $tlist = '';
+ $hlist = '<ul>';
+ foreach ($ids as $id) {
+ $link = wl($id, [], true);
+ $tlist .= '* ' . $link . NL;
+ $hlist .= '<li><a href="' . $link . '">' . hsc($id) . '</a></li>' . NL;
+ }
+ $hlist .= '</ul>';
+
+ $id = prettyprint_id($ns_id);
+ $trep = [
+ 'DIFF' => rtrim($tlist),
+ 'PAGE' => $id,
+ 'SUBSCRIBE' => wl($id, ['do' => 'subscribe'], true, '&'),
+ ];
+ $hrep = [
+ 'DIFF' => $hlist,
+ ];
+
+ return $this->send(
+ $subscriber_mail,
+ 'subscribe_list',
+ $ns_id,
+ 'subscr_list',
+ $trep,
+ $hrep
+ );
+ }
+}
diff --git a/inc/Subscriptions/MediaSubscriptionSender.php b/inc/Subscriptions/MediaSubscriptionSender.php
new file mode 100644
index 000000000..5a0f86ed6
--- /dev/null
+++ b/inc/Subscriptions/MediaSubscriptionSender.php
@@ -0,0 +1,46 @@
+<?php
+
+
+namespace dokuwiki\Subscriptions;
+
+
+class MediaSubscriptionSender extends SubscriptionSender
+{
+
+ /**
+ * Send the diff for some media change
+ *
+ * @fixme this should embed thumbnails of images in HTML version
+ *
+ * @param string $subscriber_mail The target mail address
+ * @param string $template Mail template ('uploadmail', ...)
+ * @param string $id Media file for which the notification is
+ * @param int|bool $rev Old revision if any
+ */
+ public function sendMediaDiff($subscriber_mail, $template, $id, $rev = false)
+ {
+ global $conf;
+
+ $file = mediaFN($id);
+ list($mime, /* $ext */) = mimetype($id);
+
+ $trep = [
+ 'MIME' => $mime,
+ 'MEDIA' => ml($id, '', true, '&', true),
+ 'SIZE' => filesize_h(filesize($file)),
+ ];
+
+ if ($rev && $conf['mediarevisions']) {
+ $trep['OLD'] = ml($id, "rev=$rev", true, '&', true);
+ } else {
+ $trep['OLD'] = '---';
+ }
+
+ $headers = ['Message-Id' => $this->getMessageID($id, @filemtime($file))];
+ if ($rev) {
+ $headers['In-Reply-To'] = $this->getMessageID($id, $rev);
+ }
+
+ $this->send($subscriber_mail, 'upload', $id, $template, $trep, null, $headers);
+ }
+}
diff --git a/inc/Subscriptions/PageSubscriptionSender.php b/inc/Subscriptions/PageSubscriptionSender.php
new file mode 100644
index 000000000..8fca582a4
--- /dev/null
+++ b/inc/Subscriptions/PageSubscriptionSender.php
@@ -0,0 +1,87 @@
+<?php
+
+
+namespace dokuwiki\Subscriptions;
+
+
+use Diff;
+use InlineDiffFormatter;
+use UnifiedDiffFormatter;
+
+class PageSubscriptionSender extends SubscriptionSender
+{
+
+ /**
+ * Send the diff for some page change
+ *
+ * @param string $subscriber_mail The target mail address
+ * @param string $template Mail template ('subscr_digest', 'subscr_single', 'mailtext', ...)
+ * @param string $id Page for which the notification is
+ * @param int|null $rev Old revision if any
+ * @param string $summary Change summary if any
+ *
+ * @return bool true if successfully sent
+ */
+ public function sendPageDiff($subscriber_mail, $template, $id, $rev = null, $summary = '')
+ {
+ global $DIFF_INLINESTYLES;
+
+ // prepare replacements (keys not set in hrep will be taken from trep)
+ $trep = [
+ 'PAGE' => $id,
+ 'NEWPAGE' => wl($id, '', true, '&'),
+ 'SUMMARY' => $summary,
+ 'SUBSCRIBE' => wl($id, ['do' => 'subscribe'], true, '&'),
+ ];
+ $hrep = [];
+
+ if ($rev) {
+ $subject = 'changed';
+ $trep['OLDPAGE'] = wl($id, "rev=$rev", true, '&');
+
+ $old_content = rawWiki($id, $rev);
+ $new_content = rawWiki($id);
+
+ $df = new Diff(
+ explode("\n", $old_content),
+ explode("\n", $new_content)
+ );
+ $dformat = new UnifiedDiffFormatter();
+ $tdiff = $dformat->format($df);
+
+ $DIFF_INLINESTYLES = true;
+ $df = new Diff(
+ explode("\n", $old_content),
+ explode("\n", $new_content)
+ );
+ $dformat = new InlineDiffFormatter();
+ $hdiff = $dformat->format($df);
+ $hdiff = '<table>' . $hdiff . '</table>';
+ $DIFF_INLINESTYLES = false;
+ } else {
+ $subject = 'newpage';
+ $trep['OLDPAGE'] = '---';
+ $tdiff = rawWiki($id);
+ $hdiff = nl2br(hsc($tdiff));
+ }
+
+ $trep['DIFF'] = $tdiff;
+ $hrep['DIFF'] = $hdiff;
+
+ $headers = ['Message-Id' => $this->getMessageID($id)];
+ if ($rev) {
+ $headers['In-Reply-To'] = $this->getMessageID($id, $rev);
+ }
+
+ return $this->send(
+ $subscriber_mail,
+ $subject,
+ $id,
+ $template,
+ $trep,
+ $hrep,
+ $headers
+ );
+ }
+
+}
diff --git a/inc/Subscriptions/RegistrationSubscriptionSender.php b/inc/Subscriptions/RegistrationSubscriptionSender.php
new file mode 100644
index 000000000..bd4887599
--- /dev/null
+++ b/inc/Subscriptions/RegistrationSubscriptionSender.php
@@ -0,0 +1,40 @@
+<?php
+
+namespace dokuwiki\Subscriptions;
+
+class RegistrationSubscriptionSender extends SubscriptionSender
+{
+
+ /**
+ * Send a notify mail on new registration
+ *
+ * @param string $login login name of the new user
+ * @param string $fullname full name of the new user
+ * @param string $email email address of the new user
+ *
+ * @return bool true if a mail was sent
+ * @author Andreas Gohr <andi@splitbrain.org>
+ *
+ */
+ public function sendRegister($login, $fullname, $email)
+ {
+ global $conf;
+ if (empty($conf['registernotify'])) {
+ return false;
+ }
+
+ $trep = [
+ 'NEWUSER' => $login,
+ 'NEWNAME' => $fullname,
+ 'NEWEMAIL' => $email,
+ ];
+
+ return $this->send(
+ $conf['registernotify'],
+ 'new_user',
+ $login,
+ 'registermail',
+ $trep
+ );
+ }
+}
diff --git a/inc/Subscriptions/SubscriberManager.php b/inc/Subscriptions/SubscriberManager.php
new file mode 100644
index 000000000..138176fe9
--- /dev/null
+++ b/inc/Subscriptions/SubscriberManager.php
@@ -0,0 +1,285 @@
+<?php
+
+namespace dokuwiki\Subscriptions;
+
+use dokuwiki\Input\Input;
+use DokuWiki_Auth_Plugin;
+use Exception;
+
+class SubscriberManager
+{
+
+ /**
+ * Check if subscription system is enabled
+ *
+ * @return bool
+ */
+ public function isenabled()
+ {
+ return actionOK('subscribe');
+ }
+
+ /**
+ * Adds a new subscription for the given page or namespace
+ *
+ * This will automatically overwrite any existent subscription for the given user on this
+ * *exact* page or namespace. It will *not* modify any subscription that may exist in higher namespaces.
+ *
+ * @throws Exception when user or style is empty
+ *
+ * @param string $id The target page or namespace, specified by id; Namespaces
+ * are identified by appending a colon.
+ * @param string $user
+ * @param string $style
+ * @param string $data
+ *
+ * @return bool
+ */
+ public function add($id, $user, $style, $data = '')
+ {
+ if (!$this->isenabled()) {
+ return false;
+ }
+
+ // delete any existing subscription
+ $this->remove($id, $user);
+
+ $user = auth_nameencode(trim($user));
+ $style = trim($style);
+ $data = trim($data);
+
+ if (!$user) {
+ throw new Exception('no subscription user given');
+ }
+ if (!$style) {
+ throw new Exception('no subscription style given');
+ }
+ if (!$data) {
+ $data = time();
+ } //always add current time for new subscriptions
+
+ $line = "$user $style $data\n";
+ $file = $this->file($id);
+ return io_saveFile($file, $line, true);
+ }
+
+
+ /**
+ * Removes a subscription for the given page or namespace
+ *
+ * This removes all subscriptions matching the given criteria on the given page or
+ * namespace. It will *not* modify any subscriptions that may exist in higher
+ * namespaces.
+ *
+ * @param string $id The target object’s (namespace or page) id
+ * @param string|array $user
+ * @param string|array $style
+ * @param string|array $data
+ *
+ * @return bool
+ */
+ public function remove($id, $user = null, $style = null, $data = null)
+ {
+ if (!$this->isenabled()) {
+ return false;
+ }
+
+ $file = $this->file($id);
+ if (!file_exists($file)) {
+ return true;
+ }
+
+ $regexBuilder = new SubscriberRegexBuilder();
+ $re = $regexBuilder->buildRegex($user, $style, $data);
+ return io_deleteFromFile($file, $re, true);
+ }
+
+ /**
+ * Get data for $INFO['subscribed']
+ *
+ * $INFO['subscribed'] is either false if no subscription for the current page
+ * and user is in effect. Else it contains an array of arrays with the fields
+ * “target”, “style”, and optionally “data”.
+ *
+ * @author Adrian Lang <lang@cosmocode.de>
+ *
+ * @param string $id Page ID, defaults to global $ID
+ * @param string $user User, defaults to $_SERVER['REMOTE_USER']
+ *
+ * @return array|false
+ */
+ public function userSubscription($id = '', $user = '')
+ {
+ if (!$this->isenabled()) {
+ return false;
+ }
+
+ global $ID;
+ /** @var Input $INPUT */
+ global $INPUT;
+ if (!$id) {
+ $id = $ID;
+ }
+ if (!$user) {
+ $user = $INPUT->server->str('REMOTE_USER');
+ }
+
+ $subs = $this->subscribers($id, $user);
+ if (!count($subs)) {
+ return false;
+ }
+
+ $result = [];
+ foreach ($subs as $target => $info) {
+ $result[] = [
+ 'target' => $target,
+ 'style' => $info[$user][0],
+ 'data' => $info[$user][1],
+ ];
+ }
+
+ return $result;
+ }
+
+ /**
+ * Recursively search for matching subscriptions
+ *
+ * This function searches all relevant subscription files for a page or
+ * namespace.
+ *
+ * @author Adrian Lang <lang@cosmocode.de>
+ *
+ * @param string $page The target object’s (namespace or page) id
+ * @param string|array $user
+ * @param string|array $style
+ * @param string|array $data
+ *
+ * @return array
+ */
+ public function subscribers($page, $user = null, $style = null, $data = null)
+ {
+ if (!$this->isenabled()) {
+ return [];
+ }
+
+ // Construct list of files which may contain relevant subscriptions.
+ $files = [':' => $this->file(':')];
+ do {
+ $files[$page] = $this->file($page);
+ $page = getNS(rtrim($page, ':')) . ':';
+ } while ($page !== ':');
+
+ $regexBuilder = new SubscriberRegexBuilder();
+ $re = $regexBuilder->buildRegex($user, $style, $data);
+
+ // Handle files.
+ $result = [];
+ foreach ($files as $target => $file) {
+ if (!file_exists($file)) {
+ continue;
+ }
+
+ $lines = file($file);
+ foreach ($lines as $line) {
+ // fix old style subscription files
+ if (strpos($line, ' ') === false) {
+ $line = trim($line) . " every\n";
+ }
+
+ // check for matching entries
+ if (!preg_match($re, $line, $m)) {
+ continue;
+ }
+
+ $u = rawurldecode($m[1]); // decode the user name
+ if (!isset($result[$target])) {
+ $result[$target] = [];
+ }
+ $result[$target][$u] = [$m[2], $m[3]]; // add to result
+ }
+ }
+ return array_reverse($result);
+ }
+
+ /**
+ * Default callback for COMMON_NOTIFY_ADDRESSLIST
+ *
+ * Aggregates all email addresses of user who have subscribed the given page with 'every' style
+ *
+ * @author Adrian Lang <lang@cosmocode.de>
+ * @author Steven Danz <steven-danz@kc.rr.com>
+ *
+ * @todo move the whole functionality into this class, trigger SUBSCRIPTION_NOTIFY_ADDRESSLIST instead,
+ * use an array for the addresses within it
+ *
+ * @param array &$data Containing the entries:
+ * - $id (the page id),
+ * - $self (whether the author should be notified,
+ * - $addresslist (current email address list)
+ * - $replacements (array of additional string substitutions, @KEY@ to be replaced by value)
+ */
+ public function notifyAddresses(&$data)
+ {
+ if (!$this->isenabled()) {
+ return;
+ }
+
+ /** @var DokuWiki_Auth_Plugin $auth */
+ global $auth;
+ global $conf;
+ /** @var \Input $INPUT */
+ global $INPUT;
+
+ $id = $data['id'];
+ $self = $data['self'];
+ $addresslist = $data['addresslist'];
+
+ $subscriptions = $this->subscribers($id, null, 'every');
+
+ $result = [];
+ foreach ($subscriptions as $target => $users) {
+ foreach ($users as $user => $info) {
+ $userinfo = $auth->getUserData($user);
+ if ($userinfo === false) {
+ continue;
+ }
+ if (!$userinfo['mail']) {
+ continue;
+ }
+ if (!$self && $user == $INPUT->server->str('REMOTE_USER')) {
+ continue;
+ } //skip our own changes
+
+ $level = auth_aclcheck($id, $user, $userinfo['grps']);
+ if ($level >= AUTH_READ) {
+ if (strcasecmp($userinfo['mail'], $conf['notify']) != 0) { //skip user who get notified elsewhere
+ $result[$user] = $userinfo['mail'];
+ }
+ }
+ }
+ }
+ $data['addresslist'] = trim($addresslist . ',' . implode(',', $result), ',');
+ }
+
+ /**
+ * Return the subscription meta file for the given ID
+ *
+ * @author Adrian Lang <lang@cosmocode.de>
+ *
+ * @param string $id The target page or namespace, specified by id; Namespaces
+ * are identified by appending a colon.
+ *
+ * @return string
+ */
+ protected function file($id)
+ {
+ $meta_fname = '.mlist';
+ if ((substr($id, -1, 1) === ':')) {
+ $meta_froot = getNS($id);
+ $meta_fname = '/' . $meta_fname;
+ } else {
+ $meta_froot = $id;
+ }
+ return metaFN((string)$meta_froot, $meta_fname);
+ }
+}
diff --git a/inc/Subscriptions/SubscriberRegexBuilder.php b/inc/Subscriptions/SubscriberRegexBuilder.php
new file mode 100644
index 000000000..959702aac
--- /dev/null
+++ b/inc/Subscriptions/SubscriberRegexBuilder.php
@@ -0,0 +1,70 @@
+<?php
+
+namespace dokuwiki\Subscriptions;
+
+use Exception;
+
+class SubscriberRegexBuilder
+{
+
+ /**
+ * Construct a regular expression for parsing a subscription definition line
+ *
+ * @param string|array $user
+ * @param string|array $style
+ * @param string|array $data
+ *
+ * @return string complete regexp including delimiters
+ * @throws Exception when no data is passed
+ * @author Andreas Gohr <andi@splitbrain.org>
+ *
+ */
+ public function buildRegex($user = null, $style = null, $data = null)
+ {
+ // always work with arrays
+ $user = (array)$user;
+ $style = (array)$style;
+ $data = (array)$data;
+
+ // clean
+ $user = array_filter(array_map('trim', $user));
+ $style = array_filter(array_map('trim', $style));
+ $data = array_filter(array_map('trim', $data));
+
+ // user names are encoded
+ $user = array_map('auth_nameencode', $user);
+
+ // quote
+ $user = array_map('preg_quote_cb', $user);
+ $style = array_map('preg_quote_cb', $style);
+ $data = array_map('preg_quote_cb', $data);
+
+ // join
+ $user = join('|', $user);
+ $style = join('|', $style);
+ $data = join('|', $data);
+
+ // any data at all?
+ if ($user . $style . $data === '') {
+ throw new Exception('no data passed');
+ }
+
+ // replace empty values, set which ones are optional
+ $sopt = '';
+ $dopt = '';
+ if ($user === '') {
+ $user = '\S+';
+ }
+ if ($style === '') {
+ $style = '\S+';
+ $sopt = '?';
+ }
+ if ($data === '') {
+ $data = '\S+';
+ $dopt = '?';
+ }
+
+ // assemble
+ return "/^($user)(?:\\s+($style))$sopt(?:\\s+($data))$dopt$/";
+ }
+}
diff --git a/inc/Subscriptions/SubscriptionSender.php b/inc/Subscriptions/SubscriptionSender.php
new file mode 100644
index 000000000..afc05bfc0
--- /dev/null
+++ b/inc/Subscriptions/SubscriptionSender.php
@@ -0,0 +1,86 @@
+<?php
+
+namespace dokuwiki\Subscriptions;
+
+use Mailer;
+
+abstract class SubscriptionSender
+{
+ protected $mailer;
+
+ public function __construct(Mailer $mailer = null)
+ {
+ if ($mailer === null) {
+ $mailer = new Mailer();
+ }
+ $this->mailer = $mailer;
+ }
+
+ /**
+ * Get a valid message id for a certain $id and revision (or the current revision)
+ *
+ * @param string $id The id of the page (or media file) the message id should be for
+ * @param string $rev The revision of the page, set to the current revision of the page $id if not set
+ *
+ * @return string
+ */
+ protected function getMessageID($id, $rev = null)
+ {
+ static $listid = null;
+ if (is_null($listid)) {
+ $server = parse_url(DOKU_URL, PHP_URL_HOST);
+ $listid = join('.', array_reverse(explode('/', DOKU_BASE))) . $server;
+ $listid = urlencode($listid);
+ $listid = strtolower(trim($listid, '.'));
+ }
+
+ if (is_null($rev)) {
+ $rev = @filemtime(wikiFN($id));
+ }
+
+ return "<$id?rev=$rev@$listid>";
+ }
+
+ /**
+ * Helper function for sending a mail
+ *
+ * @param string $subscriber_mail The target mail address
+ * @param string $subject The lang id of the mail subject (without the
+ * prefix “mail_”)
+ * @param string $context The context of this mail, eg. page or namespace id
+ * @param string $template The name of the mail template
+ * @param array $trep Predefined parameters used to parse the
+ * template (in text format)
+ * @param array $hrep Predefined parameters used to parse the
+ * template (in HTML format), null to default to $trep
+ * @param array $headers Additional mail headers in the form 'name' => 'value'
+ *
+ * @return bool
+ * @author Adrian Lang <lang@cosmocode.de>
+ *
+ */
+ protected function send($subscriber_mail, $subject, $context, $template, $trep, $hrep = null, $headers = [])
+ {
+ global $lang;
+ global $conf;
+
+ $text = rawLocale($template);
+ $subject = $lang['mail_' . $subject] . ' ' . $context;
+ $mail = $this->mailer;
+ $mail->bcc($subscriber_mail);
+ $mail->subject($subject);
+ $mail->setBody($text, $trep, $hrep);
+ if (in_array($template, ['subscr_list', 'subscr_digest'])) {
+ $mail->from($conf['mailfromnobody']);
+ }
+ if (isset($trep['SUBSCRIBE'])) {
+ $mail->setHeader('List-Unsubscribe', '<' . $trep['SUBSCRIBE'] . '>', false);
+ }
+
+ foreach ($headers as $header => $value) {
+ $mail->setHeader($header, $value);
+ }
+
+ return $mail->send();
+ }
+}
diff --git a/inc/TaskRunner.php b/inc/TaskRunner.php
index a054ddfd0..96d32c9e7 100644
--- a/inc/TaskRunner.php
+++ b/inc/TaskRunner.php
@@ -2,8 +2,9 @@
namespace dokuwiki;
-use Doku_Event;
-use Sitemapper;
+use dokuwiki\Extension\Event;
+use dokuwiki\Sitemap\Mapper;
+use dokuwiki\Subscriptions\BulkSubscriptionSender;
use Subscription;
/**
@@ -44,7 +45,7 @@ class TaskRunner
// run one of the jobs
$tmp = []; // No event data
- $evt = new Doku_Event('INDEXER_TASKS_RUN', $tmp);
+ $evt = new Event('INDEXER_TASKS_RUN', $tmp);
if ($evt->advise_before()) {
$this->runIndexer() or
$this->runSitemapper() or
@@ -122,12 +123,15 @@ class TaskRunner
for ($i = 0; $i < count($lines); $i++) {
$log = parseChangelogLine($lines[$i]);
if ($log === false) {
- continue;
- } // discard junk
+ continue; // discard junk
+ }
+
if ($log['date'] < $trim_time) {
- $old_lines[$log['date'] . ".$i"] = $lines[$i]; // keep old lines for now (append .$i to prevent key collisions)
+ // keep old lines for now (append .$i to prevent key collisions)
+ $old_lines[$log['date'] . ".$i"] = $lines[$i];
} else {
- $out_lines[$log['date'] . ".$i"] = $lines[$i]; // definitely keep these lines
+ // definitely keep these lines
+ $out_lines[$log['date'] . ".$i"] = $lines[$i];
}
}
@@ -153,7 +157,7 @@ class TaskRunner
'trimmedChangelogLines' => $out_lines,
'removedChangelogLines' => $extra > 0 ? array_slice($old_lines, 0, -$extra) : $old_lines,
];
- trigger_event('TASK_RECENTCHANGES_TRIM', $eventData);
+ Event::createAndTrigger('TASK_RECENTCHANGES_TRIM', $eventData);
$out_lines = $eventData['trimmedChangelogLines'];
// save trimmed changelog
@@ -185,7 +189,6 @@ class TaskRunner
protected function runIndexer()
{
global $ID;
- global $conf;
print 'runIndexer(): started' . NL;
if ((string) $ID === '') {
@@ -208,7 +211,7 @@ class TaskRunner
protected function runSitemapper()
{
print 'runSitemapper(): started' . NL;
- $result = Sitemapper::generate() && Sitemapper::pingSearchEngines();
+ $result = Mapper::generate() && Mapper::pingSearchEngines();
print 'runSitemapper(): finished' . NL;
return $result;
}
@@ -221,7 +224,6 @@ class TaskRunner
*/
protected function sendDigest()
{
- global $conf;
global $ID;
echo 'sendDigest(): started' . NL;
@@ -229,8 +231,8 @@ class TaskRunner
echo 'sendDigest(): disabled' . NL;
return false;
}
- $sub = new Subscription();
- $sent = $sub->send_bulk($ID);
+ $sub = new BulkSubscriptionSender();
+ $sent = $sub->sendBulk($ID);
echo "sendDigest(): sent $sent mails" . NL;
echo 'sendDigest(): finished' . NL;
diff --git a/inc/Ui/Admin.php b/inc/Ui/Admin.php
index 20416e137..fe319d414 100644
--- a/inc/Ui/Admin.php
+++ b/inc/Ui/Admin.php
@@ -77,11 +77,11 @@ class Admin extends Ui {
protected function showSecurityCheck() {
global $conf;
if(substr($conf['savedir'], 0, 2) !== './') return;
+ $img = DOKU_URL . $conf['savedir'] .
+ '/dont-panic-if-you-see-this-in-your-logs-it-means-your-directory-permissions-are-correct.png';
echo '<a style="border:none; float:right;"
href="http://www.dokuwiki.org/security#web_access_security">
- <img src="' . DOKU_URL . $conf['savedir'] .
- '/dont-panic-if-you-see-this-in-your-logs-it-means-your-directory-permissions-are-correct.png"
- alt="Your data directory seems to be protected properly."
+ <img src="' . $img . '" alt="Your data directory seems to be protected properly."
onerror="this.parentNode.style.display=\'none\'" /></a>';
}
@@ -119,8 +119,8 @@ class Admin extends Ui {
$menu = ['admin' => [], 'manager' => [], 'other' => []];
foreach($pluginlist as $p) {
- /** @var \DokuWiki_Admin_Plugin $obj */
- if (($obj = plugin_load('admin', $p)) === null) continue;
+ /** @var \dokuwiki\Extension\AdminPlugin $obj */
+ if(($obj = plugin_load('admin', $p)) === null) continue;
// check permissions
if (!$obj->isAccessibleByCurrentUser()) continue;
@@ -158,7 +158,7 @@ class Admin extends Ui {
* @param array $b
* @return int
*/
- protected function menuSort ($a, $b) {
+ protected function menuSort($a, $b) {
$strcmp = strcasecmp($a['prompt'], $b['prompt']);
if($strcmp != 0) return $strcmp;
if($a['sort'] === $b['sort']) return 0;
diff --git a/inc/Ui/Search.php b/inc/Ui/Search.php
index 184fdb105..e4eef6706 100644
--- a/inc/Ui/Search.php
+++ b/inc/Ui/Search.php
@@ -2,7 +2,8 @@
namespace dokuwiki\Ui;
-use \dokuwiki\Form\Form;
+use dokuwiki\Extension\Event;
+use dokuwiki\Form\Form;
class Search extends Ui
{
@@ -86,7 +87,7 @@ class Search extends Ui
$searchForm->addFieldsetClose();
- trigger_event('FORM_SEARCH_OUTPUT', $searchForm);
+ Event::createAndTrigger('FORM_SEARCH_OUTPUT', $searchForm);
return $searchForm->toHTML();
}
@@ -499,7 +500,7 @@ class Search extends Ui
public function createPagenameFromQuery($parsedQuery)
{
$cleanedQuery = cleanID($parsedQuery['query']); // already strtolowered
- if ($cleanedQuery === utf8_strtolower($parsedQuery['query'])) {
+ if ($cleanedQuery === \dokuwiki\Utf8\PhpString::strtolower($parsedQuery['query'])) {
return ':' . $cleanedQuery;
}
$pagename = '';
@@ -538,7 +539,7 @@ class Search extends Ui
'listItemContent' => [$link],
'page' => $id,
];
- trigger_event('SEARCH_RESULT_PAGELOOKUP', $eventData);
+ Event::createAndTrigger('SEARCH_RESULT_PAGELOOKUP', $eventData);
$html .= '<li>' . implode('', $eventData['listItemContent']) . '</li>';
}
$html .= '</ul> ';
@@ -587,7 +588,9 @@ class Search extends Ui
$resultBody = [];
$mtime = filemtime(wikiFN($id));
$lastMod = '<span class="lastmod">' . $lang['lastmod'] . '</span> ';
- $lastMod .= '<time datetime="' . date_iso8601($mtime) . '" title="'.dformat($mtime).'">' . dformat($mtime, '%f') . '</time>';
+ $lastMod .= '<time datetime="' . date_iso8601($mtime) . '" title="' . dformat($mtime) . '">' .
+ dformat($mtime, '%f') .
+ '</time>';
$resultBody['meta'] = $lastMod;
if ($cnt !== 0) {
$num++;
@@ -604,7 +607,7 @@ class Search extends Ui
'page' => $id,
'position' => $position,
];
- trigger_event('SEARCH_RESULT_FULLPAGE', $eventData);
+ Event::createAndTrigger('SEARCH_RESULT_FULLPAGE', $eventData);
$html .= '<div class="search_fullpage_result">';
$html .= '<dt>' . implode(' ', $eventData['resultHeader']) . '</dt>';
foreach ($eventData['resultBody'] as $class => $htmlContent) {
diff --git a/inc/Utf8/Asian.php b/inc/Utf8/Asian.php
new file mode 100644
index 000000000..c7baa3029
--- /dev/null
+++ b/inc/Utf8/Asian.php
@@ -0,0 +1,99 @@
+<?php
+
+namespace dokuwiki\Utf8;
+
+/**
+ * Methods and constants to handle Asian "words"
+ *
+ * This uses a crude regexp to determine which parts of an Asian string should be treated as words.
+ * This is necessary because in some Asian languages a single unicode char represents a whole idea
+ * without spaces separating them.
+ */
+class Asian
+{
+
+ /**
+ * This defines a non-capturing group for the use in regular expressions to match any asian character that
+ * needs to be treated as a word. Uses the Unicode-Ranges for Asian characters taken from
+ * http://en.wikipedia.org/wiki/Unicode_block
+ */
+ const REGEXP =
+ '(?:' .
+
+ '[\x{0E00}-\x{0E7F}]' . // Thai
+
+ '|' .
+
+ '[' .
+ '\x{2E80}-\x{3040}' . // CJK -> Hangul
+ '\x{309D}-\x{30A0}' .
+ '\x{30FD}-\x{31EF}\x{3200}-\x{D7AF}' .
+ '\x{F900}-\x{FAFF}' . // CJK Compatibility Ideographs
+ '\x{FE30}-\x{FE4F}' . // CJK Compatibility Forms
+ "\xF0\xA0\x80\x80-\xF0\xAA\x9B\x9F" . // CJK Extension B
+ "\xF0\xAA\x9C\x80-\xF0\xAB\x9C\xBF" . // CJK Extension C
+ "\xF0\xAB\x9D\x80-\xF0\xAB\xA0\x9F" . // CJK Extension D
+ "\xF0\xAF\xA0\x80-\xF0\xAF\xAB\xBF" . // CJK Compatibility Supplement
+ ']' .
+
+ '|' .
+
+ '[' . // Hiragana/Katakana (can be two characters)
+ '\x{3042}\x{3044}\x{3046}\x{3048}' .
+ '\x{304A}-\x{3062}\x{3064}-\x{3082}' .
+ '\x{3084}\x{3086}\x{3088}-\x{308D}' .
+ '\x{308F}-\x{3094}' .
+ '\x{30A2}\x{30A4}\x{30A6}\x{30A8}' .
+ '\x{30AA}-\x{30C2}\x{30C4}-\x{30E2}' .
+ '\x{30E4}\x{30E6}\x{30E8}-\x{30ED}' .
+ '\x{30EF}-\x{30F4}\x{30F7}-\x{30FA}' .
+ '][' .
+ '\x{3041}\x{3043}\x{3045}\x{3047}\x{3049}' .
+ '\x{3063}\x{3083}\x{3085}\x{3087}\x{308E}\x{3095}-\x{309C}' .
+ '\x{30A1}\x{30A3}\x{30A5}\x{30A7}\x{30A9}' .
+ '\x{30C3}\x{30E3}\x{30E5}\x{30E7}\x{30EE}\x{30F5}\x{30F6}\x{30FB}\x{30FC}' .
+ '\x{31F0}-\x{31FF}' .
+ ']?' .
+ ')';
+
+
+ /**
+ * Check if the given term contains Asian word characters
+ *
+ * @param string $term
+ * @return bool
+ */
+ public static function isAsianWords($term)
+ {
+ return (bool)preg_match('/' . self::REGEXP . '/u', $term);
+ }
+
+ /**
+ * Surround all Asian words in the given text with the given separator
+ *
+ * @param string $text Original text containing asian words
+ * @param string $sep the separator to use
+ * @return string Text with separated asian words
+ */
+ public static function separateAsianWords($text, $sep = ' ')
+ {
+ // handle asian chars as single words (may fail on older PHP version)
+ $asia = @preg_replace('/(' . self::REGEXP . ')/u', $sep . '\1' . $sep, $text);
+ if (!is_null($asia)) $text = $asia; // recover from regexp falure
+
+ return $text;
+ }
+
+ /**
+ * Split the given text into separate parts
+ *
+ * Each part is either a non-asian string, or a single asian word
+ *
+ * @param string $term
+ * @return string[]
+ */
+ public static function splitAsianWords($term)
+ {
+ return preg_split('/(' . self::REGEXP . '+)/u', $term, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
+ }
+}
diff --git a/inc/Utf8/Clean.php b/inc/Utf8/Clean.php
new file mode 100644
index 000000000..79c46810c
--- /dev/null
+++ b/inc/Utf8/Clean.php
@@ -0,0 +1,204 @@
+<?php
+
+namespace dokuwiki\Utf8;
+
+/**
+ * Methods to assess and clean UTF-8 strings
+ */
+class Clean
+{
+ /**
+ * Checks if a string contains 7bit ASCII only
+ *
+ * @author Andreas Haerter <andreas.haerter@dev.mail-node.com>
+ *
+ * @param string $str
+ * @return bool
+ */
+ public static function isASCII($str)
+ {
+ return (preg_match('/(?:[^\x00-\x7F])/', $str) !== 1);
+ }
+
+ /**
+ * Tries to detect if a string is in Unicode encoding
+ *
+ * @author <bmorel@ssi.fr>
+ * @link http://php.net/manual/en/function.utf8-encode.php
+ *
+ * @param string $str
+ * @return bool
+ */
+ public static function isUtf8($str)
+ {
+ $len = strlen($str);
+ for ($i = 0; $i < $len; $i++) {
+ $b = ord($str[$i]);
+ if ($b < 0x80) continue; # 0bbbbbbb
+ elseif (($b & 0xE0) === 0xC0) $n = 1; # 110bbbbb
+ elseif (($b & 0xF0) === 0xE0) $n = 2; # 1110bbbb
+ elseif (($b & 0xF8) === 0xF0) $n = 3; # 11110bbb
+ elseif (($b & 0xFC) === 0xF8) $n = 4; # 111110bb
+ elseif (($b & 0xFE) === 0xFC) $n = 5; # 1111110b
+ else return false; # Does not match any model
+
+ for ($j = 0; $j < $n; $j++) { # n bytes matching 10bbbbbb follow ?
+ if ((++$i === $len) || ((ord($str[$i]) & 0xC0) !== 0x80))
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Strips all high byte chars
+ *
+ * Returns a pure ASCII7 string
+ *
+ * @author Andreas Gohr <andi@splitbrain.org>
+ *
+ * @param string $str
+ * @return string
+ */
+ public static function strip($str)
+ {
+ $ascii = '';
+ $len = strlen($str);
+ for ($i = 0; $i < $len; $i++) {
+ if (ord($str{$i}) < 128) {
+ $ascii .= $str{$i};
+ }
+ }
+ return $ascii;
+ }
+
+ /**
+ * Removes special characters (nonalphanumeric) from a UTF-8 string
+ *
+ * This function adds the controlchars 0x00 to 0x19 to the array of
+ * stripped chars (they are not included in $UTF8_SPECIAL_CHARS)
+ *
+ * @author Andreas Gohr <andi@splitbrain.org>
+ *
+ * @param string $string The UTF8 string to strip of special chars
+ * @param string $repl Replace special with this string
+ * @param string $additional Additional chars to strip (used in regexp char class)
+ * @return string
+ */
+ public static function stripspecials($string, $repl = '', $additional = '')
+ {
+ static $specials = null;
+ if ($specials === null) {
+ $specials = preg_quote(Table::specialChars(), '/');
+ }
+
+ return preg_replace('/[' . $additional . '\x00-\x19' . $specials . ']/u', $repl, $string);
+ }
+
+ /**
+ * Replace bad bytes with an alternative character
+ *
+ * ASCII character is recommended for replacement char
+ *
+ * PCRE Pattern to locate bad bytes in a UTF-8 string
+ * Comes from W3 FAQ: Multilingual Forms
+ * Note: modified to include full ASCII range including control chars
+ *
+ * @author Harry Fuecks <hfuecks@gmail.com>
+ * @see http://www.w3.org/International/questions/qa-forms-utf-8
+ *
+ * @param string $str to search
+ * @param string $replace to replace bad bytes with (defaults to '?') - use ASCII
+ * @return string
+ */
+ public static function replaceBadBytes($str, $replace = '')
+ {
+ $UTF8_BAD =
+ '([\x00-\x7F]' . # ASCII (including control chars)
+ '|[\xC2-\xDF][\x80-\xBF]' . # non-overlong 2-byte
+ '|\xE0[\xA0-\xBF][\x80-\xBF]' . # excluding overlongs
+ '|[\xE1-\xEC\xEE\xEF][\x80-\xBF]{2}' . # straight 3-byte
+ '|\xED[\x80-\x9F][\x80-\xBF]' . # excluding surrogates
+ '|\xF0[\x90-\xBF][\x80-\xBF]{2}' . # planes 1-3
+ '|[\xF1-\xF3][\x80-\xBF]{3}' . # planes 4-15
+ '|\xF4[\x80-\x8F][\x80-\xBF]{2}' . # plane 16
+ '|(.{1}))'; # invalid byte
+ ob_start();
+ while (preg_match('/' . $UTF8_BAD . '/S', $str, $matches)) {
+ if (!isset($matches[2])) {
+ echo $matches[0];
+ } else {
+ echo $replace;
+ }
+ $str = substr($str, strlen($matches[0]));
+ }
+ return ob_get_clean();
+ }
+
+
+ /**
+ * Replace accented UTF-8 characters by unaccented ASCII-7 equivalents
+ *
+ * Use the optional parameter to just deaccent lower ($case = -1) or upper ($case = 1)
+ * letters. Default is to deaccent both cases ($case = 0)
+ *
+ * @author Andreas Gohr <andi@splitbrain.org>
+ *
+ * @param string $string
+ * @param int $case
+ * @return string
+ */
+ public static function deaccent($string, $case = 0)
+ {
+ if ($case <= 0) {
+ $string = strtr($string, Table::lowerAccents());
+ }
+ if ($case >= 0) {
+ $string = strtr($string, Table::upperAccents());
+ }
+ return $string;
+ }
+
+ /**
+ * Romanize a non-latin string
+ *
+ * @author Andreas Gohr <andi@splitbrain.org>
+ *
+ * @param string $string
+ * @return string
+ */
+ public static function romanize($string)
+ {
+ if (self::isASCII($string)) return $string; //nothing to do
+
+ return strtr($string, Table::romanization());
+ }
+
+ /**
+ * adjust a byte index into a utf8 string to a utf8 character boundary
+ *
+ * @author chris smith <chris@jalakai.co.uk>
+ *
+ * @param string $str utf8 character string
+ * @param int $i byte index into $str
+ * @param bool $next direction to search for boundary, false = up (current character) true = down (next character)
+ * @return int byte index into $str now pointing to a utf8 character boundary
+ */
+ public static function correctIdx($str, $i, $next = false)
+ {
+
+ if ($i <= 0) return 0;
+
+ $limit = strlen($str);
+ if ($i >= $limit) return $limit;
+
+ if ($next) {
+ while (($i < $limit) && ((ord($str[$i]) & 0xC0) === 0x80)) $i++;
+ } else {
+ while ($i && ((ord($str[$i]) & 0xC0) === 0x80)) $i--;
+ }
+
+ return $i;
+ }
+
+}
diff --git a/inc/Utf8/Conversion.php b/inc/Utf8/Conversion.php
new file mode 100644
index 000000000..fad9cd0b1
--- /dev/null
+++ b/inc/Utf8/Conversion.php
@@ -0,0 +1,162 @@
+<?php
+
+namespace dokuwiki\Utf8;
+
+/**
+ * Methods to convert from and to UTF-8 strings
+ */
+class Conversion
+{
+
+ /**
+ * Encodes UTF-8 characters to HTML entities
+ *
+ * @author Tom N Harris <tnharris@whoopdedo.org>
+ * @author <vpribish at shopping dot com>
+ * @link http://php.net/manual/en/function.utf8-decode.php
+ *
+ * @param string $str
+ * @param bool $all Encode non-utf8 char to HTML as well
+ * @return string
+ */
+ public static function toHtml($str, $all = false)
+ {
+ $ret = '';
+ foreach (Unicode::fromUtf8($str) as $cp) {
+ if ($cp < 0x80 && !$all) {
+ $ret .= chr($cp);
+ } elseif ($cp < 0x100) {
+ $ret .= "&#$cp;";
+ } else {
+ $ret .= '&#x' . dechex($cp) . ';';
+ }
+ }
+ return $ret;
+ }
+
+ /**
+ * Decodes HTML entities to UTF-8 characters
+ *
+ * Convert any &#..; entity to a codepoint,
+ * The entities flag defaults to only decoding numeric entities.
+ * Pass HTML_ENTITIES and named entities, including &amp; &lt; etc.
+ * are handled as well. Avoids the problem that would occur if you
+ * had to decode "&amp;#38;&#38;amp;#38;"
+ *
+ * unhtmlspecialchars(\dokuwiki\Utf8\Conversion::fromHtml($s)) -> "&#38;&#38;"
+ * \dokuwiki\Utf8\Conversion::fromHtml(unhtmlspecialchars($s)) -> "&&amp#38;"
+ * what it should be -> "&#38;&amp#38;"
+ *
+ * @author Tom N Harris <tnharris@whoopdedo.org>
+ *
+ * @param string $str UTF-8 encoded string
+ * @param boolean $entities decode name entities in addtition to numeric ones
+ * @return string UTF-8 encoded string with numeric (and named) entities replaced.
+ */
+ public static function fromHtml($str, $entities = false)
+ {
+ if (!$entities) {
+ return preg_replace_callback(
+ '/(&#([Xx])?([0-9A-Za-z]+);)/m',
+ [__CLASS__, 'decodeNumericEntity'],
+ $str
+ );
+ }
+
+ return preg_replace_callback(
+ '/&(#)?([Xx])?([0-9A-Za-z]+);/m',
+ [__CLASS__, 'decodeAnyEntity'],
+ $str
+ );
+ }
+
+ /**
+ * Decodes any HTML entity to it's correct UTF-8 char equivalent
+ *
+ * @param string $ent An entity
+ * @return string
+ */
+ protected static function decodeAnyEntity($ent)
+ {
+ // create the named entity lookup table
+ static $table = null;
+ if ($table === null) {
+ $table = get_html_translation_table(HTML_ENTITIES);
+ $table = array_flip($table);
+ $table = array_map(
+ static function ($c) {
+ return Unicode::toUtf8(array(ord($c)));
+ },
+ $table
+ );
+ }
+
+ if ($ent[1] === '#') {
+ return self::decodeNumericEntity($ent);
+ }
+
+ if (array_key_exists($ent[0], $table)) {
+ return $table[$ent[0]];
+ }
+
+ return $ent[0];
+ }
+
+ /**
+ * Decodes numeric HTML entities to their correct UTF-8 characters
+ *
+ * @param $ent string A numeric entity
+ * @return string|false
+ */
+ protected static function decodeNumericEntity($ent)
+ {
+ switch ($ent[2]) {
+ case 'X':
+ case 'x':
+ $cp = hexdec($ent[3]);
+ break;
+ default:
+ $cp = intval($ent[3]);
+ break;
+ }
+ return Unicode::toUtf8(array($cp));
+ }
+
+ /**
+ * UTF-8 to UTF-16BE conversion.
+ *
+ * Maybe really UCS-2 without mb_string due to utf8_to_unicode limits
+ *
+ * @param string $str
+ * @param bool $bom
+ * @return string
+ */
+ public static function toUtf16be($str, $bom = false)
+ {
+ $out = $bom ? "\xFE\xFF" : '';
+ if (UTF8_MBSTRING) {
+ return $out . mb_convert_encoding($str, 'UTF-16BE', 'UTF-8');
+ }
+
+ $uni = Unicode::fromUtf8($str);
+ foreach ($uni as $cp) {
+ $out .= pack('n', $cp);
+ }
+ return $out;
+ }
+
+ /**
+ * UTF-8 to UTF-16BE conversion.
+ *
+ * Maybe really UCS-2 without mb_string due to utf8_to_unicode limits
+ *
+ * @param string $str
+ * @return false|string
+ */
+ public static function fromUtf16be($str)
+ {
+ $uni = unpack('n*', $str);
+ return Unicode::toUtf8($uni);
+ }
+
+}
diff --git a/inc/Utf8/PhpString.php b/inc/Utf8/PhpString.php
new file mode 100644
index 000000000..5bcd601a4
--- /dev/null
+++ b/inc/Utf8/PhpString.php
@@ -0,0 +1,383 @@
+<?php
+
+namespace dokuwiki\Utf8;
+
+/**
+ * UTF-8 aware equivalents to PHP's string functions
+ */
+class PhpString
+{
+
+ /**
+ * A locale independent basename() implementation
+ *
+ * works around a bug in PHP's basename() implementation
+ *
+ * @param string $path A path
+ * @param string $suffix If the name component ends in suffix this will also be cut off
+ * @return string
+ * @link https://bugs.php.net/bug.php?id=37738
+ *
+ * @see basename()
+ */
+ public static function basename($path, $suffix = '')
+ {
+ $path = trim($path, '\\/');
+ $rpos = max(strrpos($path, '/'), strrpos($path, '\\'));
+ if ($rpos) {
+ $path = substr($path, $rpos + 1);
+ }
+
+ $suflen = strlen($suffix);
+ if ($suflen && (substr($path, -$suflen) === $suffix)) {
+ $path = substr($path, 0, -$suflen);
+ }
+
+ return $path;
+ }
+
+ /**
+ * Unicode aware replacement for strlen()
+ *
+ * utf8_decode() converts characters that are not in ISO-8859-1
+ * to '?', which, for the purpose of counting, is alright - It's
+ * even faster than mb_strlen.
+ *
+ * @param string $string
+ * @return int
+ * @see utf8_decode()
+ *
+ * @author <chernyshevsky at hotmail dot com>
+ * @see strlen()
+ */
+ public static function strlen($string)
+ {
+ if (function_exists('utf8_decode')) {
+ return strlen(utf8_decode($string));
+ }
+
+ if (UTF8_MBSTRING) {
+ return mb_strlen($string, 'UTF-8');
+ }
+
+ if (function_exists('iconv_strlen')) {
+ return iconv_strlen($string, 'UTF-8');
+ }
+
+ return strlen($string);
+ }
+
+ /**
+ * UTF-8 aware alternative to substr
+ *
+ * Return part of a string given character offset (and optionally length)
+ *
+ * @param string $str
+ * @param int $offset number of UTF-8 characters offset (from left)
+ * @param int $length (optional) length in UTF-8 characters from offset
+ * @return string
+ * @author Harry Fuecks <hfuecks@gmail.com>
+ * @author Chris Smith <chris@jalakai.co.uk>
+ *
+ */
+ public static function substr($str, $offset, $length = null)
+ {
+ if (UTF8_MBSTRING) {
+ if ($length === null) {
+ return mb_substr($str, $offset);
+ }
+
+ return mb_substr($str, $offset, $length);
+ }
+
+ /*
+ * Notes:
+ *
+ * no mb string support, so we'll use pcre regex's with 'u' flag
+ * pcre only supports repetitions of less than 65536, in order to accept up to MAXINT values for
+ * offset and length, we'll repeat a group of 65535 characters when needed (ok, up to MAXINT-65536)
+ *
+ * substr documentation states false can be returned in some cases (e.g. offset > string length)
+ * mb_substr never returns false, it will return an empty string instead.
+ *
+ * calculating the number of characters in the string is a relatively expensive operation, so
+ * we only carry it out when necessary. It isn't necessary for +ve offsets and no specified length
+ */
+
+ // cast parameters to appropriate types to avoid multiple notices/warnings
+ $str = (string)$str; // generates E_NOTICE for PHP4 objects, but not PHP5 objects
+ $offset = (int)$offset;
+ if ($length !== null) $length = (int)$length;
+
+ // handle trivial cases
+ if ($length === 0) return '';
+ if ($offset < 0 && $length < 0 && $length < $offset) return '';
+
+ $offset_pattern = '';
+ $length_pattern = '';
+
+ // normalise -ve offsets (we could use a tail anchored pattern, but they are horribly slow!)
+ if ($offset < 0) {
+ $strlen = self::strlen($str); // see notes
+ $offset = $strlen + $offset;
+ if ($offset < 0) $offset = 0;
+ }
+
+ // establish a pattern for offset, a non-captured group equal in length to offset
+ if ($offset > 0) {
+ $Ox = (int)($offset / 65535);
+ $Oy = $offset % 65535;
+
+ if ($Ox) $offset_pattern = '(?:.{65535}){' . $Ox . '}';
+ $offset_pattern = '^(?:' . $offset_pattern . '.{' . $Oy . '})';
+ } else {
+ $offset_pattern = '^'; // offset == 0; just anchor the pattern
+ }
+
+ // establish a pattern for length
+ if ($length === null) {
+ $length_pattern = '(.*)$'; // the rest of the string
+ } else {
+
+ if (!isset($strlen)) $strlen = self::strlen($str); // see notes
+ if ($offset > $strlen) return ''; // another trivial case
+
+ if ($length > 0) {
+
+ // reduce any length that would go past the end of the string
+ $length = min($strlen - $offset, $length);
+
+ $Lx = (int)($length / 65535);
+ $Ly = $length % 65535;
+
+ // +ve length requires ... a captured group of length characters
+ if ($Lx) $length_pattern = '(?:.{65535}){' . $Lx . '}';
+ $length_pattern = '(' . $length_pattern . '.{' . $Ly . '})';
+
+ } else if ($length < 0) {
+
+ if ($length < ($offset - $strlen)) return '';
+
+ $Lx = (int)((-$length) / 65535);
+ $Ly = (-$length) % 65535;
+
+ // -ve length requires ... capture everything except a group of -length characters
+ // anchored at the tail-end of the string
+ if ($Lx) $length_pattern = '(?:.{65535}){' . $Lx . '}';
+ $length_pattern = '(.*)(?:' . $length_pattern . '.{' . $Ly . '})$';
+ }
+ }
+
+ if (!preg_match('#' . $offset_pattern . $length_pattern . '#us', $str, $match)) return '';
+ return $match[1];
+ }
+
+ // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
+ /**
+ * Unicode aware replacement for substr_replace()
+ *
+ * @param string $string input string
+ * @param string $replacement the replacement
+ * @param int $start the replacing will begin at the start'th offset into string.
+ * @param int $length If given and is positive, it represents the length of the portion of string which is
+ * to be replaced. If length is zero then this function will have the effect of inserting
+ * replacement into string at the given start offset.
+ * @return string
+ * @see substr_replace()
+ *
+ * @author Andreas Gohr <andi@splitbrain.org>
+ */
+ public static function substr_replace($string, $replacement, $start, $length = 0)
+ {
+ $ret = '';
+ if ($start > 0) $ret .= self::substr($string, 0, $start);
+ $ret .= $replacement;
+ $ret .= self::substr($string, $start + $length);
+ return $ret;
+ }
+ // phpcs:enable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
+
+ /**
+ * Unicode aware replacement for ltrim()
+ *
+ * @param string $str
+ * @param string $charlist
+ * @return string
+ * @see ltrim()
+ *
+ * @author Andreas Gohr <andi@splitbrain.org>
+ */
+ public static function ltrim($str, $charlist = '')
+ {
+ if ($charlist === '') return ltrim($str);
+
+ //quote charlist for use in a characterclass
+ $charlist = preg_replace('!([\\\\\\-\\]\\[/])!', '\\\${1}', $charlist);
+
+ return preg_replace('/^[' . $charlist . ']+/u', '', $str);
+ }
+
+ /**
+ * Unicode aware replacement for rtrim()
+ *
+ * @param string $str
+ * @param string $charlist
+ * @return string
+ * @see rtrim()
+ *
+ * @author Andreas Gohr <andi@splitbrain.org>
+ */
+ public static function rtrim($str, $charlist = '')
+ {
+ if ($charlist === '') return rtrim($str);
+
+ //quote charlist for use in a characterclass
+ $charlist = preg_replace('!([\\\\\\-\\]\\[/])!', '\\\${1}', $charlist);
+
+ return preg_replace('/[' . $charlist . ']+$/u', '', $str);
+ }
+
+ /**
+ * Unicode aware replacement for trim()
+ *
+ * @param string $str
+ * @param string $charlist
+ * @return string
+ * @see trim()
+ *
+ * @author Andreas Gohr <andi@splitbrain.org>
+ */
+ public static function trim($str, $charlist = '')
+ {
+ if ($charlist === '') return trim($str);
+
+ return self::ltrim(self::rtrim($str, $charlist), $charlist);
+ }
+
+ /**
+ * This is a unicode aware replacement for strtolower()
+ *
+ * Uses mb_string extension if available
+ *
+ * @param string $string
+ * @return string
+ * @see \dokuwiki\Utf8\PhpString::strtoupper()
+ *
+ * @author Leo Feyer <leo@typolight.org>
+ * @see strtolower()
+ */
+ public static function strtolower($string)
+ {
+ if (UTF8_MBSTRING) {
+ if (class_exists('Normalizer', $autoload = false)) {
+ return \Normalizer::normalize(mb_strtolower($string, 'utf-8'));
+ }
+ return (mb_strtolower($string, 'utf-8'));
+ }
+ return strtr($string, Table::upperCaseToLowerCase());
+ }
+
+ /**
+ * This is a unicode aware replacement for strtoupper()
+ *
+ * Uses mb_string extension if available
+ *
+ * @param string $string
+ * @return string
+ * @see \dokuwiki\Utf8\PhpString::strtoupper()
+ *
+ * @author Leo Feyer <leo@typolight.org>
+ * @see strtoupper()
+ */
+ public static function strtoupper($string)
+ {
+ if (UTF8_MBSTRING) return mb_strtoupper($string, 'utf-8');
+
+ return strtr($string, Table::lowerCaseToUpperCase());
+ }
+
+
+ /**
+ * UTF-8 aware alternative to ucfirst
+ * Make a string's first character uppercase
+ *
+ * @param string $str
+ * @return string with first character as upper case (if applicable)
+ * @author Harry Fuecks
+ *
+ */
+ public static function ucfirst($str)
+ {
+ switch (self::strlen($str)) {
+ case 0:
+ return '';
+ case 1:
+ return self::strtoupper($str);
+ default:
+ preg_match('/^(.{1})(.*)$/us', $str, $matches);
+ return self::strtoupper($matches[1]) . $matches[2];
+ }
+ }
+
+ /**
+ * UTF-8 aware alternative to ucwords
+ * Uppercase the first character of each word in a string
+ *
+ * @param string $str
+ * @return string with first char of each word uppercase
+ * @author Harry Fuecks
+ * @see http://php.net/ucwords
+ *
+ */
+ public static function ucwords($str)
+ {
+ // Note: [\x0c\x09\x0b\x0a\x0d\x20] matches;
+ // form feeds, horizontal tabs, vertical tabs, linefeeds and carriage returns
+ // This corresponds to the definition of a "word" defined at http://php.net/ucwords
+ $pattern = '/(^|([\x0c\x09\x0b\x0a\x0d\x20]+))([^\x0c\x09\x0b\x0a\x0d\x20]{1})[^\x0c\x09\x0b\x0a\x0d\x20]*/u';
+
+ return preg_replace_callback(
+ $pattern,
+ function ($matches) {
+ $leadingws = $matches[2];
+ $ucfirst = self::strtoupper($matches[3]);
+ $ucword = self::substr_replace(ltrim($matches[0]), $ucfirst, 0, 1);
+ return $leadingws . $ucword;
+ },
+ $str
+ );
+ }
+
+ /**
+ * This is an Unicode aware replacement for strpos
+ *
+ * @param string $haystack
+ * @param string $needle
+ * @param integer $offset
+ * @return integer
+ * @author Leo Feyer <leo@typolight.org>
+ * @see strpos()
+ *
+ */
+ public static function strpos($haystack, $needle, $offset = 0)
+ {
+ $comp = 0;
+ $length = null;
+
+ while ($length === null || $length < $offset) {
+ $pos = strpos($haystack, $needle, $offset + $comp);
+
+ if ($pos === false)
+ return false;
+
+ $length = self::strlen(substr($haystack, 0, $pos));
+
+ if ($length < $offset)
+ $comp = $pos - $length;
+ }
+
+ return $length;
+ }
+
+
+}
diff --git a/inc/Utf8/Table.php b/inc/Utf8/Table.php
new file mode 100644
index 000000000..8683c9238
--- /dev/null
+++ b/inc/Utf8/Table.php
@@ -0,0 +1,93 @@
+<?php
+
+namespace dokuwiki\Utf8;
+
+/**
+ * Provides static access to the UTF-8 conversion tables
+ *
+ * Lazy-Loads tables on first access
+ */
+class Table
+{
+
+ /**
+ * Get the upper to lower case conversion table
+ *
+ * @return array
+ */
+ public static function upperCaseToLowerCase()
+ {
+ static $table = null;
+ if ($table === null) $table = include __DIR__ . '/tables/case.php';
+ return $table;
+ }
+
+ /**
+ * Get the lower to upper case conversion table
+ *
+ * @return array
+ */
+ public static function lowerCaseToUpperCase()
+ {
+ static $table = null;
+ if ($table === null) {
+ $uclc = self::upperCaseToLowerCase();
+ $table = array_flip($uclc);
+ }
+ return $table;
+ }
+
+ /**
+ * Get the lower case accent table
+ * @return array
+ */
+ public static function lowerAccents()
+ {
+ static $table = null;
+ if ($table === null) {
+ $table = include __DIR__ . '/tables/loweraccents.php';
+ }
+ return $table;
+ }
+
+ /**
+ * Get the lower case accent table
+ * @return array
+ */
+ public static function upperAccents()
+ {
+ static $table = null;
+ if ($table === null) {
+ $table = include __DIR__ . '/tables/upperaccents.php';
+ }
+ return $table;
+ }
+
+ /**
+ * Get the romanization table
+ * @return array
+ */
+ public static function romanization()
+ {
+ static $table = null;
+ if ($table === null) {
+ $table = include __DIR__ . '/tables/romanization.php';
+ }
+ return $table;
+ }
+
+ /**
+ * Get the special chars as a concatenated string
+ * @return string
+ */
+ public static function specialChars()
+ {
+ static $string = null;
+ if ($string === null) {
+ $table = include __DIR__ . '/tables/specials.php';
+ // FIXME should we cache this to file system?
+ $string = Unicode::toUtf8($table);
+ }
+ return $string;
+ }
+}
diff --git a/inc/Utf8/Unicode.php b/inc/Utf8/Unicode.php
new file mode 100644
index 000000000..c706d716b
--- /dev/null
+++ b/inc/Utf8/Unicode.php
@@ -0,0 +1,277 @@
+<?php
+
+namespace dokuwiki\Utf8;
+
+/**
+ * Convert between UTF-8 and a list of Unicode Code Points
+ */
+class Unicode
+{
+
+ /**
+ * Takes an UTF-8 string and returns an array of ints representing the
+ * Unicode characters. Astral planes are supported ie. the ints in the
+ * output can be > 0xFFFF. Occurrances of the BOM are ignored. Surrogates
+ * are not allowed.
+ *
+ * If $strict is set to true the function returns false if the input
+ * string isn't a valid UTF-8 octet sequence and raises a PHP error at
+ * level E_USER_WARNING
+ *
+ * Note: this function has been modified slightly in this library to
+ * trigger errors on encountering bad bytes
+ *
+ * @author <hsivonen@iki.fi>
+ * @author Harry Fuecks <hfuecks@gmail.com>
+ * @see unicode_to_utf8
+ * @link http://hsivonen.iki.fi/php-utf8/
+ * @link http://sourceforge.net/projects/phputf8/
+ * @todo break into less complex chunks
+ * @todo use exceptions instead of user errors
+ *
+ * @param string $str UTF-8 encoded string
+ * @param boolean $strict Check for invalid sequences?
+ * @return mixed array of unicode code points or false if UTF-8 invalid
+ */
+ public static function fromUtf8($str, $strict = false)
+ {
+ $mState = 0; // cached expected number of octets after the current octet
+ // until the beginning of the next UTF8 character sequence
+ $mUcs4 = 0; // cached Unicode character
+ $mBytes = 1; // cached expected number of octets in the current sequence
+
+ $out = array();
+
+ $len = strlen($str);
+
+ for ($i = 0; $i < $len; $i++) {
+
+ $in = ord($str{$i});
+
+ if ($mState === 0) {
+
+ // When mState is zero we expect either a US-ASCII character or a
+ // multi-octet sequence.
+ if (0 === (0x80 & $in)) {
+ // US-ASCII, pass straight through.
+ $out[] = $in;
+ $mBytes = 1;
+
+ } else if (0xC0 === (0xE0 & $in)) {
+ // First octet of 2 octet sequence
+ $mUcs4 = $in;
+ $mUcs4 = ($mUcs4 & 0x1F) << 6;
+ $mState = 1;
+ $mBytes = 2;
+
+ } else if (0xE0 === (0xF0 & $in)) {
+ // First octet of 3 octet sequence
+ $mUcs4 = $in;
+ $mUcs4 = ($mUcs4 & 0x0F) << 12;
+ $mState = 2;
+ $mBytes = 3;
+
+ } else if (0xF0 === (0xF8 & $in)) {
+ // First octet of 4 octet sequence
+ $mUcs4 = $in;
+ $mUcs4 = ($mUcs4 & 0x07) << 18;
+ $mState = 3;
+ $mBytes = 4;
+
+ } else if (0xF8 === (0xFC & $in)) {
+ /* First octet of 5 octet sequence.
+ *
+ * This is illegal because the encoded codepoint must be either
+ * (a) not the shortest form or
+ * (b) outside the Unicode range of 0-0x10FFFF.
+ * Rather than trying to resynchronize, we will carry on until the end
+ * of the sequence and let the later error handling code catch it.
+ */
+ $mUcs4 = $in;
+ $mUcs4 = ($mUcs4 & 0x03) << 24;
+ $mState = 4;
+ $mBytes = 5;
+
+ } else if (0xFC === (0xFE & $in)) {
+ // First octet of 6 octet sequence, see comments for 5 octet sequence.
+ $mUcs4 = $in;
+ $mUcs4 = ($mUcs4 & 1) << 30;
+ $mState = 5;
+ $mBytes = 6;
+
+ } elseif ($strict) {
+ /* Current octet is neither in the US-ASCII range nor a legal first
+ * octet of a multi-octet sequence.
+ */
+ trigger_error(
+ 'utf8_to_unicode: Illegal sequence identifier ' .
+ 'in UTF-8 at byte ' . $i,
+ E_USER_WARNING
+ );
+ return false;
+
+ }
+
+ } else {
+
+ // When mState is non-zero, we expect a continuation of the multi-octet
+ // sequence
+ if (0x80 === (0xC0 & $in)) {
+
+ // Legal continuation.
+ $shift = ($mState - 1) * 6;
+ $tmp = $in;
+ $tmp = ($tmp & 0x0000003F) << $shift;
+ $mUcs4 |= $tmp;
+
+ /**
+ * End of the multi-octet sequence. mUcs4 now contains the final
+ * Unicode codepoint to be output
+ */
+ if (0 === --$mState) {
+
+ /*
+ * Check for illegal sequences and codepoints.
+ */
+ // From Unicode 3.1, non-shortest form is illegal
+ if (((2 === $mBytes) && ($mUcs4 < 0x0080)) ||
+ ((3 === $mBytes) && ($mUcs4 < 0x0800)) ||
+ ((4 === $mBytes) && ($mUcs4 < 0x10000)) ||
+ (4 < $mBytes) ||
+ // From Unicode 3.2, surrogate characters are illegal
+ (($mUcs4 & 0xFFFFF800) === 0xD800) ||
+ // Codepoints outside the Unicode range are illegal
+ ($mUcs4 > 0x10FFFF)) {
+
+ if ($strict) {
+ trigger_error(
+ 'utf8_to_unicode: Illegal sequence or codepoint ' .
+ 'in UTF-8 at byte ' . $i,
+ E_USER_WARNING
+ );
+
+ return false;
+ }
+
+ }
+
+ if (0xFEFF !== $mUcs4) {
+ // BOM is legal but we don't want to output it
+ $out[] = $mUcs4;
+ }
+
+ //initialize UTF8 cache
+ $mState = 0;
+ $mUcs4 = 0;
+ $mBytes = 1;
+ }
+
+ } elseif ($strict) {
+ /**
+ *((0xC0 & (*in) != 0x80) && (mState != 0))
+ * Incomplete multi-octet sequence.
+ */
+ trigger_error(
+ 'utf8_to_unicode: Incomplete multi-octet ' .
+ ' sequence in UTF-8 at byte ' . $i,
+ E_USER_WARNING
+ );
+
+ return false;
+ }
+ }
+ }
+ return $out;
+ }
+
+ /**
+ * Takes an array of ints representing the Unicode characters and returns
+ * a UTF-8 string. Astral planes are supported ie. the ints in the
+ * input can be > 0xFFFF. Occurrances of the BOM are ignored. Surrogates
+ * are not allowed.
+ *
+ * If $strict is set to true the function returns false if the input
+ * array contains ints that represent surrogates or are outside the
+ * Unicode range and raises a PHP error at level E_USER_WARNING
+ *
+ * Note: this function has been modified slightly in this library to use
+ * output buffering to concatenate the UTF-8 string (faster) as well as
+ * reference the array by it's keys
+ *
+ * @param array $arr of unicode code points representing a string
+ * @param boolean $strict Check for invalid sequences?
+ * @return string|false UTF-8 string or false if array contains invalid code points
+ *
+ * @author <hsivonen@iki.fi>
+ * @author Harry Fuecks <hfuecks@gmail.com>
+ * @see utf8_to_unicode
+ * @link http://hsivonen.iki.fi/php-utf8/
+ * @link http://sourceforge.net/projects/phputf8/
+ * @todo use exceptions instead of user errors
+ */
+ public static function toUtf8($arr, $strict = false)
+ {
+ if (!is_array($arr)) return '';
+ ob_start();
+
+ foreach (array_keys($arr) as $k) {
+
+ if (($arr[$k] >= 0) && ($arr[$k] <= 0x007f)) {
+ # ASCII range (including control chars)
+
+ echo chr($arr[$k]);
+
+ } else if ($arr[$k] <= 0x07ff) {
+ # 2 byte sequence
+
+ echo chr(0xc0 | ($arr[$k] >> 6));
+ echo chr(0x80 | ($arr[$k] & 0x003f));
+
+ } else if ($arr[$k] == 0xFEFF) {
+ # Byte order mark (skip)
+ // nop -- zap the BOM
+
+ } else if ($arr[$k] >= 0xD800 && $arr[$k] <= 0xDFFF) {
+ # Test for illegal surrogates
+
+ // found a surrogate
+ if ($strict) {
+ trigger_error(
+ 'unicode_to_utf8: Illegal surrogate ' .
+ 'at index: ' . $k . ', value: ' . $arr[$k],
+ E_USER_WARNING
+ );
+ return false;
+ }
+
+ } else if ($arr[$k] <= 0xffff) {
+ # 3 byte sequence
+
+ echo chr(0xe0 | ($arr[$k] >> 12));
+ echo chr(0x80 | (($arr[$k] >> 6) & 0x003f));
+ echo chr(0x80 | ($arr[$k] & 0x003f));
+
+ } else if ($arr[$k] <= 0x10ffff) {
+ # 4 byte sequence
+
+ echo chr(0xf0 | ($arr[$k] >> 18));
+ echo chr(0x80 | (($arr[$k] >> 12) & 0x3f));
+ echo chr(0x80 | (($arr[$k] >> 6) & 0x3f));
+ echo chr(0x80 | ($arr[$k] & 0x3f));
+
+ } elseif ($strict) {
+
+ trigger_error(
+ 'unicode_to_utf8: Codepoint out of Unicode range ' .
+ 'at index: ' . $k . ', value: ' . $arr[$k],
+ E_USER_WARNING
+ );
+
+ // out of range
+ return false;
+ }
+ }
+
+ return ob_get_clean();
+ }
+}
diff --git a/inc/Utf8/tables/case.php b/inc/Utf8/tables/case.php
new file mode 100644
index 000000000..ac5f5629e
--- /dev/null
+++ b/inc/Utf8/tables/case.php
@@ -0,0 +1,567 @@
+<?php
+/**
+ * UTF-8 Case lookup table
+ *
+ * This lookuptable defines the lower case letters to their corresponding
+ * upper case letter in UTF-8
+ *
+ * @author Andreas Gohr <andi@splitbrain.org>
+ */
+return [
+ 'A' => 'a',
+ 'A' => 'a',
+ 'Á' => 'á',
+ 'À' => 'à',
+ 'Ă' => 'ă',
+ 'Ắ' => 'ắ',
+ 'Ẵ' => 'ẵ',
+ 'Ẳ' => 'ẳ',
+ 'Â' => 'â',
+ 'Ấ' => 'ấ',
+ 'Ầ' => 'ầ',
+ 'Ẫ' => 'ẫ',
+ 'Ǎ' => 'ǎ',
+ 'Å' => 'å',
+ 'Ǻ' => 'ǻ',
+ 'Ä' => 'ä',
+ 'Ǟ' => 'ǟ',
+ 'Ã' => 'ã',
+ 'Ǡ' => 'ǡ',
+ 'Ą' => 'ą',
+ 'Ā' => 'ā',
+ 'Ả' => 'ả',
+ 'Ȁ' => 'ȁ',
+ 'Ȃ' => 'ȃ',
+ 'Ặ' => 'ặ',
+ 'Ậ' => 'ậ',
+ 'Ḁ' => 'ḁ',
+ 'Æ' => 'æ',
+ 'Ǽ' => 'ǽ',
+ 'Ǣ' => 'ǣ',
+ 'B' => 'b',
+ 'Ḃ' => 'ḃ',
+ 'Ḅ' => 'ḅ',
+ 'Ḇ' => 'ḇ',
+ 'Ɓ' => 'ɓ',
+ 'Ƃ' => 'ƃ',
+ 'C' => 'c',
+ 'Ć' => 'ć',
+ 'Ĉ' => 'ĉ',
+ 'Č' => 'č',
+ 'Ċ' => 'ċ',
+ 'Ç' => 'ç',
+ 'Ƈ' => 'ƈ',
+ 'D' => 'd',
+ 'D' => 'd',
+ 'Ď' => 'ď',
+ 'Ḋ' => 'ḋ',
+ 'Ḑ' => 'ḑ',
+ 'Ḍ' => 'ḍ',
+ 'Ḓ' => 'ḓ',
+ 'Ḏ' => 'ḏ',
+ 'Ð' => 'ð',
+ 'Dz' => 'dz', //FIXME
+ 'Dž' => 'dž', //FIXME
+ 'Ɗ' => 'ɗ',
+ 'Ƌ' => 'ƌ',
+ 'E' => 'e',
+ 'E' => 'e',
+ 'É' => 'é',
+ 'È' => 'è',
+ 'Ê' => 'ê',
+ 'Ế' => 'ế',
+ 'Ề' => 'ề',
+ 'Ễ' => 'ễ',
+ 'Ể' => 'ể',
+ 'Ě' => 'ě',
+ 'Ẽ' => 'ẽ',
+ 'Ė' => 'ė',
+ 'Ȩ' => 'ȩ',
+ 'Ḝ' => 'ḝ',
+ 'Ę' => 'ę',
+ 'Ē' => 'ē',
+ 'Ḕ' => 'ḕ',
+ 'Ẻ' => 'ẻ',
+ 'Ȅ' => 'ȅ',
+ 'Ȇ' => 'ȇ',
+ 'Ẹ' => 'ẹ',
+ 'Ệ' => 'ệ',
+ 'Ḛ' => 'ḛ',
+ 'Ǝ' => 'ǝ',
+ 'Ə' => 'ə',
+ 'Ɛ' => 'ɛ',
+ 'F' => 'f',
+ 'F' => 'f',
+ 'Ƒ' => 'ƒ',
+ 'G' => 'g',
+ 'G' => 'g',
+ 'Ǵ' => 'ǵ',
+ 'Ğ' => 'ğ',
+ 'Ĝ' => 'ĝ',
+ 'Ġ' => 'ġ',
+ 'Ģ' => 'ģ',
+ 'Ḡ' => 'ḡ',
+ 'Ǥ' => 'ǥ',
+ 'Ɣ' => 'ɣ',
+ 'Ƣ' => 'ƣ',
+ 'H' => 'h',
+ 'Ĥ' => 'ĥ',
+ 'Ȟ' => 'ȟ',
+ 'Ḧ' => 'ḧ',
+ 'Ḣ' => 'ḣ',
+ 'Ḩ' => 'ḩ',
+ 'Ḥ' => 'ḥ',
+ 'Ḫ' => 'ḫ',
+ 'Ƕ' => 'ƕ',
+ 'I' => 'i',
+ 'I' => 'i',
+ 'Í' => 'í',
+ 'Ĭ' => 'ĭ',
+ 'Î' => 'î',
+ 'Ǐ' => 'ǐ',
+ 'Ï' => 'ï',
+ 'Ḯ' => 'ḯ',
+ 'Ĩ' => 'ĩ',
+ 'Ī' => 'ī',
+ 'Ỉ' => 'ỉ',
+ 'Ȉ' => 'ȉ',
+ 'Ȋ' => 'ȋ',
+ 'Ị' => 'ị',
+ 'Ḭ' => 'ḭ',
+ 'Ɨ' => 'ɨ',
+ 'Ɩ' => 'ɩ',
+ 'J' => 'j',
+ 'J' => 'j',
+ 'Ĵ' => 'ĵ',
+ 'K' => 'k',
+ 'Ḱ' => 'ḱ',
+ 'Ǩ' => 'ǩ',
+ 'Ķ' => 'ķ',
+ 'Ḳ' => 'ḳ',
+ 'Ḵ' => 'ḵ',
+ 'Ƙ' => 'ƙ',
+ 'L' => 'l',
+ 'Ĺ' => 'ĺ',
+ 'Ľ' => 'ľ',
+ 'Ļ' => 'ļ',
+ 'Ł' => 'ł',
+ 'Ḷ' => 'ḷ',
+ 'Ḽ' => 'ḽ',
+ 'Ḻ' => 'ḻ',
+ 'Ŀ' => 'ŀ',
+ 'Lj' => 'lj', // FIXME
+ 'M' => 'm',
+ 'M' => 'm',
+ 'Ṁ' => 'ṁ',
+ 'Ṃ' => 'ṃ',
+ 'N' => 'n',
+ 'N' => 'n',
+ 'Ń' => 'ń',
+ 'Ǹ' => 'ǹ',
+ 'Ñ' => 'ñ',
+ 'Ṅ' => 'ṅ',
+ 'Ņ' => 'ņ',
+ 'Ṇ' => 'ṇ',
+ 'Ṋ' => 'ṋ',
+ 'Ṉ' => 'ṉ',
+ 'Ɲ' => 'ɲ',
+ 'Ƞ' => 'ƞ',
+ 'Ŋ' => 'ŋ',
+ 'O' => 'o',
+ 'O' => 'o',
+ 'Ó' => 'ó',
+ 'Ŏ' => 'ŏ',
+ 'Ô' => 'ô',
+ 'Ố' => 'ố',
+ 'Ồ' => 'ồ',
+ 'Ỗ' => 'ỗ',
+ 'Ổ' => 'ổ',
+ 'Ö' => 'ö',
+ 'Ȫ' => 'ȫ',
+ 'Ő' => 'ő',
+ 'Õ' => 'õ',
+ 'Ṍ' => 'ṍ',
+ 'Ṏ' => 'ṏ',
+ 'Ȯ' => 'ȯ',
+ 'Ȱ' => 'ȱ',
+ 'Ø' => 'ø',
+ 'Ǿ' => 'ǿ',
+ 'Ǫ' => 'ǫ',
+ 'Ǭ' => 'ǭ',
+ 'Ṓ' => 'ṓ',
+ 'Ṑ' => 'ṑ',
+ 'Ỏ' => 'ỏ',
+ 'Ȍ' => 'ȍ',
+ 'Ȏ' => 'ȏ',
+ 'Ơ' => 'ơ',
+ 'Ờ' => 'ờ',
+ 'Ỡ' => 'ỡ',
+ 'Ở' => 'ở',
+ 'Ợ' => 'ợ',
+ 'Ọ' => 'ọ',
+ 'Ộ' => 'ộ',
+ 'Ɔ' => 'ɔ',
+ 'Ɵ' => 'ɵ',
+ 'Ȣ' => 'ȣ',
+ 'P' => 'p',
+ 'P' => 'p',
+ 'Ṕ' => 'ṕ',
+ 'Ƥ' => 'ƥ',
+ 'Q' => 'q',
+ 'Q' => 'q',
+ 'R' => 'r',
+ 'R' => 'r',
+ 'Ŕ' => 'ŕ',
+ 'Ṙ' => 'ṙ',
+ 'Ŗ' => 'ŗ',
+ 'Ȑ' => 'ȑ',
+ 'Ȓ' => 'ȓ',
+ 'Ṛ' => 'ṛ',
+ 'Ṝ' => 'ṝ',
+ 'Ʀ' => 'ʀ',
+ 'S' => 's',
+ 'S' => 's',
+ 'Ś' => 'ś',
+ 'Ṥ' => 'ṥ',
+ 'Ŝ' => 'ŝ',
+ 'Ṧ' => 'ṧ',
+ 'Ṡ' => 'ṡ',
+ 'Ş' => 'ş',
+ 'Ṣ' => 'ṣ',
+ 'Ṩ' => 'ṩ',
+ 'Ș' => 'ș',
+ 'T' => 't',
+ 'T' => 't',
+ 'Ť' => 'ť',
+ 'Ṫ' => 'ṫ',
+ 'Ţ' => 'ţ',
+ 'Ṭ' => 'ṭ',
+ 'Ṱ' => 'ṱ',
+ 'Ṯ' => 'ṯ',
+ 'Ŧ' => 'ŧ',
+ 'Ƭ' => 'ƭ',
+ 'Ʈ' => 'ʈ',
+ 'U' => 'u',
+ 'Ú' => 'ú',
+ 'Ù' => 'ù',
+ 'Ŭ' => 'ŭ',
+ 'Û' => 'û',
+ 'Ǔ' => 'ǔ',
+ 'Ů' => 'ů',
+ 'Ǘ' => 'ǘ',
+ 'Ǜ' => 'ǜ',
+ 'Ǚ' => 'ǚ',
+ 'Ǖ' => 'ǖ',
+ 'Ű' => 'ű',
+ 'Ũ' => 'ũ',
+ 'Ų' => 'ų',
+ 'Ū' => 'ū',
+ 'Ṻ' => 'ṻ',
+ 'Ủ' => 'ủ',
+ 'Ȕ' => 'ȕ',
+ 'Ȗ' => 'ȗ',
+ 'Ứ' => 'ứ',
+ 'Ừ' => 'ừ',
+ 'Ữ' => 'ữ',
+ 'Ử' => 'ử',
+ 'Ự' => 'ự',
+ 'Ụ' => 'ụ',
+ 'Ṷ' => 'ṷ',
+ 'Ṵ' => 'ṵ',
+ 'Ɯ' => 'ɯ',
+ 'Ʊ' => 'ʊ',
+ 'V' => 'v',
+ 'V' => 'v',
+ 'Ṿ' => 'ṿ',
+ 'Ʋ' => 'ʋ',
+ 'W' => 'w',
+ 'W' => 'w',
+ 'Ẃ' => 'ẃ',
+ 'Ẁ' => 'ẁ',
+ 'Ẅ' => 'ẅ',
+ 'Ẇ' => 'ẇ',
+ 'Ẉ' => 'ẉ',
+ 'X' => 'x',
+ 'X' => 'x',
+ 'Ẍ' => 'ẍ',
+ 'Y' => 'y',
+ 'Y' => 'y',
+ 'Ý' => 'ý',
+ 'Ỳ' => 'ỳ',
+ 'Ŷ' => 'ŷ',
+ 'Ÿ' => 'ÿ',
+ 'Ẏ' => 'ẏ',
+ 'Ȳ' => 'ȳ',
+ 'Ỷ' => 'ỷ',
+ 'Ỵ' => 'ỵ',
+ 'Ƴ' => 'ƴ',
+ 'Ȝ' => 'ȝ',
+ 'Z' => 'z',
+ 'Ź' => 'ź',
+ 'Ẑ' => 'ẑ',
+ 'Ž' => 'ž',
+ 'Ż' => 'ż',
+ 'Ẓ' => 'ẓ',
+ 'Ƶ' => 'ƶ',
+ 'Ȥ' => 'ȥ',
+ 'Ʒ' => 'ʒ',
+ 'Ǯ' => 'ǯ',
+ 'Ƹ' => 'ƹ',
+ 'Þ' => 'þ',
+ 'Ƨ' => 'ƨ',
+ 'Ƽ' => 'ƽ',
+ 'Ƅ' => 'ƅ',
+ 'Α' => 'α',
+ 'Ἀ' => 'ἀ',
+ 'Ἄ' => 'ἄ',
+ 'Ἂ' => 'ἂ',
+ 'ᾊ' => 'ᾂ',
+ 'Ἆ' => 'ἆ',
+ 'ᾎ' => 'ᾆ',
+ 'ᾈ' => 'ᾀ',
+ 'Ἁ' => 'ἁ',
+ 'ᾍ' => 'ᾅ',
+ 'Ἃ' => 'ἃ',
+ 'ᾋ' => 'ᾃ',
+ 'Ἇ' => 'ἇ',
+ 'ᾏ' => 'ᾇ',
+ 'ᾉ' => 'ᾁ',
+ 'Ὰ' => 'ὰ',
+ 'Ᾰ' => 'ᾰ',
+ 'Ᾱ' => 'ᾱ',
+ 'ᾼ' => 'ᾳ',
+ 'Β' => 'β',
+ 'Γ' => 'γ',
+ 'Ε' => 'ε',
+ 'Ἐ' => 'ἐ',
+ 'Ἔ' => 'ἔ',
+ 'Ἒ' => 'ἒ',
+ 'Ἑ' => 'ἑ',
+ 'Ἕ' => 'ἕ',
+ 'Έ' => 'έ',
+ 'Ὲ' => 'ὲ',
+ 'Ϝ' => 'ϝ',
+ 'Ϛ' => 'ϛ',
+ 'Ζ' => 'ζ',
+ 'Η' => 'η',
+ 'ᾜ' => 'ᾔ',
+ 'Ἢ' => 'ἢ',
+ 'ᾚ' => 'ᾒ',
+ 'Ἦ' => 'ἦ',
+ 'ᾞ' => 'ᾖ',
+ 'ᾘ' => 'ᾐ',
+ 'Ἥ' => 'ἥ',
+ 'ᾝ' => 'ᾕ',
+ 'Ἣ' => 'ἣ',
+ 'ᾛ' => 'ᾓ',
+ 'Ἧ' => 'ἧ',
+ 'ᾟ' => 'ᾗ',
+ 'Ή' => 'ή',
+ 'Ὴ' => 'ὴ',
+ 'ῌ' => 'ῃ',
+ 'Θ' => 'θ',
+ 'Ι' => 'ι',
+ 'Ἰ' => 'ἰ',
+ 'Ἲ' => 'ἲ',
+ 'Ἶ' => 'ἶ',
+ 'Ἱ' => 'ἱ',
+ 'Ἵ' => 'ἵ',
+ 'Ἳ' => 'ἳ',
+ 'Ἷ' => 'ἷ',
+ 'Ὶ' => 'ὶ',
+ 'Ῐ' => 'ῐ',
+ 'Ϊ' => 'ϊ',
+ 'Ῑ' => 'ῑ',
+ 'Κ' => 'κ',
+ 'Λ' => 'λ',
+ 'Ν' => 'ν',
+ 'Ξ' => 'ξ',
+ 'Ο' => 'ο',
+ 'Ὀ' => 'ὀ',
+ 'Ὄ' => 'ὄ',
+ 'Ὂ' => 'ὂ',
+ 'Ὅ' => 'ὅ',
+ 'Ὃ' => 'ὃ',
+ 'Ό' => 'ό',
+ 'Ὸ' => 'ὸ',
+ 'Π' => 'π',
+ 'Ϟ' => 'ϟ',
+ 'Ρ' => 'ρ',
+ 'Ῥ' => 'ῥ',
+ 'Σ' => 'ς',
+ 'Τ' => 'τ',
+ 'Υ' => 'υ',
+ 'Ὑ' => 'ὑ',
+ 'Ὓ' => 'ὓ',
+ 'Ὗ' => 'ὗ',
+ 'Ύ' => 'ύ',
+ 'Ὺ' => 'ὺ',
+ 'Ϋ' => 'ϋ',
+ 'Ῡ' => 'ῡ',
+ 'Χ' => 'χ',
+ 'Ψ' => 'ψ',
+ 'Ω' => 'ω',
+ 'Ὤ' => 'ὤ',
+ 'ᾬ' => 'ᾤ',
+ 'Ὢ' => 'ὢ',
+ 'Ὦ' => 'ὦ',
+ 'ᾮ' => 'ᾦ',
+ 'Ὡ' => 'ὡ',
+ 'Ὥ' => 'ὥ',
+ 'ᾭ' => 'ᾥ',
+ 'Ὣ' => 'ὣ',
+ 'Ὧ' => 'ὧ',
+ 'ᾯ' => 'ᾧ',
+ 'ᾩ' => 'ᾡ',
+ 'Ώ' => 'ώ',
+ 'Ὼ' => 'ὼ',
+ 'ῼ' => 'ῳ',
+ 'Ϣ' => 'ϣ',
+ 'Ϥ' => 'ϥ',
+ 'Ϧ' => 'ϧ',
+ 'Ϩ' => 'ϩ',
+ 'Ϫ' => 'ϫ',
+ 'Ϭ' => 'ϭ',
+ 'А' => 'а',
+ 'Ӑ' => 'ӑ',
+ 'Ӓ' => 'ӓ',
+ 'Ә' => 'ә',
+ 'Ӛ' => 'ӛ',
+ 'Ӕ' => 'ӕ',
+ 'В' => 'в',
+ 'Г' => 'г',
+ 'Ѓ' => 'ѓ',
+ 'Ґ' => 'ґ',
+ 'Ғ' => 'ғ',
+ 'Ҕ' => 'ҕ',
+ 'Ԁ' => 'ԁ',
+ 'Ђ' => 'ђ',
+ 'Ԃ' => 'ԃ',
+ 'Ҙ' => 'ҙ',
+ 'Е' => 'е',
+ 'Ѐ' => 'ѐ',
+ 'Ё' => 'ё',
+ 'Є' => 'є',
+ 'Ж' => 'ж',
+ 'Ӂ' => 'ӂ',
+ 'Ӝ' => 'ӝ',
+ 'Җ' => 'җ',
+ 'Ӟ' => 'ӟ',
+ 'Ԅ' => 'ԅ',
+ 'Ѕ' => 'ѕ',
+ 'Ӡ' => 'ӡ',
+ 'Ԇ' => 'ԇ',
+ 'И' => 'и',
+ 'Ӥ' => 'ӥ',
+ 'Ӣ' => 'ӣ',
+ 'Ҋ' => 'ҋ',
+ 'І' => 'і',
+ 'Ї' => 'ї',
+ 'Й' => 'й',
+ 'К' => 'к',
+ 'Ќ' => 'ќ',
+ 'Қ' => 'қ',
+ 'Ӄ' => 'ӄ',
+ 'Ҡ' => 'ҡ',
+ 'Ҟ' => 'ҟ',
+ 'Л' => 'л',
+ 'Ӆ' => 'ӆ',
+ 'Љ' => 'љ',
+ 'Ԉ' => 'ԉ',
+ 'М' => 'м',
+ 'Ӎ' => 'ӎ',
+ 'Ӊ' => 'ӊ',
+ 'Ң' => 'ң',
+ 'Ӈ' => 'ӈ',
+ 'Ҥ' => 'ҥ',
+ 'Њ' => 'њ',
+ 'Ԋ' => 'ԋ',
+ 'Ӧ' => 'ӧ',
+ 'Ө' => 'ө',
+ 'Ӫ' => 'ӫ',
+ 'П' => 'п',
+ 'Ҧ' => 'ҧ',
+ 'Ҁ' => 'ҁ',
+ 'Ҏ' => 'ҏ',
+ 'С' => 'с',
+ 'Ԍ' => 'ԍ',
+ 'Ҫ' => 'ҫ',
+ 'Т' => 'т',
+ 'Ԏ' => 'ԏ',
+ 'Ћ' => 'ћ',
+ 'У' => 'у',
+ 'Ў' => 'ў',
+ 'Ӱ' => 'ӱ',
+ 'Ӳ' => 'ӳ',
+ 'Ӯ' => 'ӯ',
+ 'Ұ' => 'ұ',
+ 'Ѹ' => 'ѹ',
+ 'Ф' => 'ф',
+ 'Х' => 'х',
+ 'Ҳ' => 'ҳ',
+ 'Һ' => 'һ',
+ 'Ѿ' => 'ѿ',
+ 'Ѽ' => 'ѽ',
+ 'Ѻ' => 'ѻ',
+ 'Ц' => 'ц',
+ 'Ҵ' => 'ҵ',
+ 'Ч' => 'ч',
+ 'Ҷ' => 'ҷ',
+ 'Ӌ' => 'ӌ',
+ 'Ҹ' => 'ҹ',
+ 'Ҽ' => 'ҽ',
+ 'Ҿ' => 'ҿ',
+ 'Џ' => 'џ',
+ 'Щ' => 'щ',
+ 'Ъ' => 'ъ',
+ 'Ы' => 'ы',
+ 'Ӹ' => 'ӹ',
+ 'Ь' => 'ь',
+ 'Ҍ' => 'ҍ',
+ 'Э' => 'э',
+ 'Ӭ' => 'ӭ',
+ 'Ю' => 'ю',
+ 'Я' => 'я',
+ 'Ѥ' => 'ѥ',
+ 'Ѧ' => 'ѧ',
+ 'Ѩ' => 'ѩ',
+ 'Ѭ' => 'ѭ',
+ 'Ѯ' => 'ѯ',
+ 'Ѱ' => 'ѱ',
+ 'Ѳ' => 'ѳ',
+ 'Ѵ' => 'ѵ',
+ 'Ҩ' => 'ҩ',
+ 'Ա' => 'ա',
+ 'Բ' => 'բ',
+ 'Գ' => 'գ',
+ 'Դ' => 'դ',
+ 'Ե' => 'ե',
+ 'Է' => 'է',
+ 'Ը' => 'ը',
+ 'Թ' => 'թ',
+ 'Ժ' => 'ժ',
+ 'Ի' => 'ի',
+ 'Լ' => 'լ',
+ 'Ծ' => 'ծ',
+ 'Կ' => 'կ',
+ 'Հ' => 'հ',
+ 'Ձ' => 'ձ',
+ 'Ղ' => 'ղ',
+ 'Ճ' => 'ճ',
+ 'Յ' => 'յ',
+ 'Ն' => 'ն',
+ 'Շ' => 'շ',
+ 'Ո' => 'ո',
+ 'Չ' => 'չ',
+ 'Պ' => 'պ',
+ 'Ռ' => 'ռ',
+ 'Ս' => 'ս',
+ 'Վ' => 'վ',
+ 'Տ' => 'տ',
+ 'Ր' => 'ր',
+ 'Ց' => 'ց',
+ 'Փ' => 'փ',
+ 'Ք' => 'ք',
+ 'Օ' => 'օ',
+ 'Ֆ' => 'ֆ',
+];
diff --git a/inc/Utf8/tables/loweraccents.php b/inc/Utf8/tables/loweraccents.php
new file mode 100644
index 000000000..cc3ec8eae
--- /dev/null
+++ b/inc/Utf8/tables/loweraccents.php
@@ -0,0 +1,116 @@
+<?php
+/**
+ * UTF-8 lookup table for lower case accented letters
+ *
+ * This lookuptable defines replacements for accented characters from the ASCII-7
+ * range. This are lower case letters only.
+ *
+ * @author Andreas Gohr <andi@splitbrain.org>
+ * @see \dokuwiki\Utf8\Clean::deaccent()
+ */
+return [
+ 'á' => 'a',
+ 'à' => 'a',
+ 'ă' => 'a',
+ 'â' => 'a',
+ 'å' => 'a',
+ 'ä' => 'ae',
+ 'ã' => 'a',
+ 'ą' => 'a',
+ 'ā' => 'a',
+ 'æ' => 'ae',
+ 'ḃ' => 'b',
+ 'ć' => 'c',
+ 'ĉ' => 'c',
+ 'č' => 'c',
+ 'ċ' => 'c',
+ 'ç' => 'c',
+ 'ď' => 'd',
+ 'ḋ' => 'd',
+ 'đ' => 'd',
+ 'ð' => 'dh',
+ 'é' => 'e',
+ 'è' => 'e',
+ 'ĕ' => 'e',
+ 'ê' => 'e',
+ 'ě' => 'e',
+ 'ë' => 'e',
+ 'ė' => 'e',
+ 'ę' => 'e',
+ 'ē' => 'e',
+ 'ḟ' => 'f',
+ 'ƒ' => 'f',
+ 'ğ' => 'g',
+ 'ĝ' => 'g',
+ 'ġ' => 'g',
+ 'ģ' => 'g',
+ 'ĥ' => 'h',
+ 'ħ' => 'h',
+ 'í' => 'i',
+ 'ì' => 'i',
+ 'î' => 'i',
+ 'ï' => 'i',
+ 'ĩ' => 'i',
+ 'į' => 'i',
+ 'ī' => 'i',
+ 'ĵ' => 'j',
+ 'ķ' => 'k',
+ 'ĺ' => 'l',
+ 'ľ' => 'l',
+ 'ļ' => 'l',
+ 'ł' => 'l',
+ 'ṁ' => 'm',
+ 'ń' => 'n',
+ 'ň' => 'n',
+ 'ñ' => 'n',
+ 'ņ' => 'n',
+ 'ó' => 'o',
+ 'ò' => 'o',
+ 'ô' => 'o',
+ 'ö' => 'oe',
+ 'ő' => 'o',
+ 'õ' => 'o',
+ 'ø' => 'o',
+ 'ō' => 'o',
+ 'ơ' => 'o',
+ 'ṗ' => 'p',
+ 'ŕ' => 'r',
+ 'ř' => 'r',
+ 'ŗ' => 'r',
+ 'ś' => 's',
+ 'ŝ' => 's',
+ 'š' => 's',
+ 'ṡ' => 's',
+ 'ş' => 's',
+ 'ș' => 's',
+ 'ß' => 'ss',
+ 'ť' => 't',
+ 'ṫ' => 't',
+ 'ţ' => 't',
+ 'ț' => 't',
+ 'ŧ' => 't',
+ 'ú' => 'u',
+ 'ù' => 'u',
+ 'ŭ' => 'u',
+ 'û' => 'u',
+ 'ů' => 'u',
+ 'ü' => 'ue',
+ 'ű' => 'u',
+ 'ũ' => 'u',
+ 'ų' => 'u',
+ 'ū' => 'u',
+ 'ư' => 'u',
+ 'ẃ' => 'w',
+ 'ẁ' => 'w',
+ 'ŵ' => 'w',
+ 'ẅ' => 'w',
+ 'ý' => 'y',
+ 'ỳ' => 'y',
+ 'ŷ' => 'y',
+ 'ÿ' => 'y',
+ 'ź' => 'z',
+ 'ž' => 'z',
+ 'ż' => 'z',
+ 'þ' => 'th',
+ 'µ' => 'u',
+];
diff --git a/inc/Utf8/tables/romanization.php b/inc/Utf8/tables/romanization.php
new file mode 100644
index 000000000..e757b9c4d
--- /dev/null
+++ b/inc/Utf8/tables/romanization.php
@@ -0,0 +1,1458 @@
+<?php
+/**
+ * Romanization lookup table
+ *
+ * This lookup tables provides a way to transform strings written in a language
+ * different from the ones based upon latin letters into plain ASCII.
+ *
+ * Please note: this is not a scientific transliteration table. It only works
+ * oneway from nonlatin to ASCII and it works by simple character replacement
+ * only. Specialities of each language are not supported.
+ *
+ * @todo some keys are used multiple times
+ * @todo remove or integrate commented pairs
+ *
+ * @author Andreas Gohr <andi@splitbrain.org>
+ * @author Vitaly Blokhin <vitinfo@vitn.com>
+ * @author Bisqwit <bisqwit@iki.fi>
+ * @author Arthit Suriyawongkul <arthit@gmail.com>
+ * @author Denis Scheither <amorphis@uni-bremen.de>
+ * @author Eivind Morland <eivind.morland@gmail.com>
+ * @link http://www.uconv.com/translit.htm
+ * @link http://kanjidict.stc.cx/hiragana.php?src=2
+ * @link http://www.translatum.gr/converter/greek-transliteration.htm
+ * @link http://en.wikipedia.org/wiki/Royal_Thai_General_System_of_Transcription
+ * @link http://www.btranslations.com/resources/romanization/korean.asp
+ */
+return [
+ // scandinavian - differs from what we do in deaccent
+ 'å' => 'a',
+ 'Å' => 'A',
+ 'ä' => 'a',
+ 'Ä' => 'A',
+ 'ö' => 'o',
+ 'Ö' => 'O',
+
+ //russian cyrillic
+ 'а' => 'a',
+ 'А' => 'A',
+ 'б' => 'b',
+ 'Б' => 'B',
+ 'в' => 'v',
+ 'В' => 'V',
+ 'г' => 'g',
+ 'Г' => 'G',
+ 'д' => 'd',
+ 'Д' => 'D',
+ 'е' => 'e',
+ 'Е' => 'E',
+ 'ё' => 'jo',
+ 'Ё' => 'Jo',
+ 'ж' => 'zh',
+ 'Ж' => 'Zh',
+ 'з' => 'z',
+ 'З' => 'Z',
+ 'и' => 'i',
+ 'И' => 'I',
+ 'й' => 'j',
+ 'Й' => 'J',
+ 'к' => 'k',
+ 'К' => 'K',
+ 'л' => 'l',
+ 'Л' => 'L',
+ 'м' => 'm',
+ 'М' => 'M',
+ 'н' => 'n',
+ 'Н' => 'N',
+ 'о' => 'o',
+ 'О' => 'O',
+ 'п' => 'p',
+ 'П' => 'P',
+ 'р' => 'r',
+ 'Р' => 'R',
+ 'с' => 's',
+ 'С' => 'S',
+ 'т' => 't',
+ 'Т' => 'T',
+ 'у' => 'u',
+ 'У' => 'U',
+ 'ф' => 'f',
+ 'Ф' => 'F',
+ 'х' => 'x',
+ 'Х' => 'X',
+ 'ц' => 'c',
+ 'Ц' => 'C',
+ 'ч' => 'ch',
+ 'Ч' => 'Ch',
+ 'ш' => 'sh',
+ 'Ш' => 'Sh',
+ 'щ' => 'sch',
+ 'Щ' => 'Sch',
+ 'ъ' => '',
+ 'Ъ' => '',
+ 'ы' => 'y',
+ 'Ы' => 'Y',
+ 'ь' => '',
+ 'Ь' => '',
+ 'э' => 'eh',
+ 'Э' => 'Eh',
+ 'ю' => 'ju',
+ 'Ю' => 'Ju',
+ 'я' => 'ja',
+ 'Я' => 'Ja',
+
+ // Ukrainian cyrillic
+ 'Ґ' => 'Gh',
+ 'ґ' => 'gh',
+ 'Є' => 'Je',
+ 'є' => 'je',
+ 'І' => 'I',
+ 'і' => 'i',
+ 'Ї' => 'Ji',
+ 'ї' => 'ji',
+
+ // Georgian
+ 'ა' => 'a',
+ 'ბ' => 'b',
+ 'გ' => 'g',
+ 'დ' => 'd',
+ 'ე' => 'e',
+ 'ვ' => 'v',
+ 'ზ' => 'z',
+ 'თ' => 'th',
+ 'ი' => 'i',
+ 'კ' => 'p',
+ 'ლ' => 'l',
+ 'მ' => 'm',
+ 'ნ' => 'n',
+ 'ო' => 'o',
+ 'პ' => 'p',
+ 'ჟ' => 'zh',
+ 'რ' => 'r',
+ 'ს' => 's',
+ 'ტ' => 't',
+ 'უ' => 'u',
+ 'ფ' => 'ph',
+ 'ქ' => 'kh',
+ 'ღ' => 'gh',
+ 'ყ' => 'q',
+ 'შ' => 'sh',
+ 'ჩ' => 'ch',
+ 'ც' => 'c',
+ 'ძ' => 'dh',
+ 'წ' => 'w',
+ 'ჭ' => 'j',
+ 'ხ' => 'x',
+ 'ჯ' => 'jh',
+ 'ჰ' => 'xh',
+
+ //Sanskrit
+ 'अ' => 'a',
+ 'आ' => 'ah',
+ 'इ' => 'i',
+ 'ई' => 'ih',
+ 'उ' => 'u',
+ 'ऊ' => 'uh',
+ 'ऋ' => 'ry',
+ 'ॠ' => 'ryh',
+ 'ऌ' => 'ly',
+ 'ॡ' => 'lyh',
+ 'ए' => 'e',
+ 'ऐ' => 'ay',
+ 'ओ' => 'o',
+ 'औ' => 'aw',
+ 'अं' => 'amh',
+ 'अः' => 'aq',
+ 'क' => 'k',
+ 'ख' => 'kh',
+ 'ग' => 'g',
+ 'घ' => 'gh',
+ 'ङ' => 'nh',
+ 'च' => 'c',
+ 'छ' => 'ch',
+ 'ज' => 'j',
+ 'झ' => 'jh',
+ 'ञ' => 'ny',
+ 'ट' => 'tq',
+ 'ठ' => 'tqh',
+ 'ड' => 'dq',
+ 'ढ' => 'dqh',
+ 'ण' => 'nq',
+ 'त' => 't',
+ 'थ' => 'th',
+ 'द' => 'd',
+ 'ध' => 'dh',
+ 'न' => 'n',
+ 'प' => 'p',
+ 'फ' => 'ph',
+ 'ब' => 'b',
+ 'भ' => 'bh',
+ 'म' => 'm',
+ 'य' => 'z',
+ 'र' => 'r',
+ 'ल' => 'l',
+ 'व' => 'v',
+ 'श' => 'sh',
+ 'ष' => 'sqh',
+ 'स' => 's',
+ 'ह' => 'x',
+
+ //Sanskrit diacritics
+ 'Ā' => 'A',
+ 'Ī' => 'I',
+ 'Ū' => 'U',
+ 'Ṛ' => 'R',
+ 'Ṝ' => 'R',
+ 'Ṅ' => 'N',
+ 'Ñ' => 'N',
+ 'Ṭ' => 'T',
+ 'Ḍ' => 'D',
+ 'Ṇ' => 'N',
+ 'Ś' => 'S',
+ 'Ṣ' => 'S',
+ 'Ṁ' => 'M',
+ 'Ṃ' => 'M',
+ 'Ḥ' => 'H',
+ 'Ḷ' => 'L',
+ 'Ḹ' => 'L',
+ 'ā' => 'a',
+ 'ī' => 'i',
+ 'ū' => 'u',
+ 'ṛ' => 'r',
+ 'ṝ' => 'r',
+ 'ṅ' => 'n',
+ 'ñ' => 'n',
+ 'ṭ' => 't',
+ 'ḍ' => 'd',
+ 'ṇ' => 'n',
+ 'ś' => 's',
+ 'ṣ' => 's',
+ 'ṁ' => 'm',
+ 'ṃ' => 'm',
+ 'ḥ' => 'h',
+ 'ḷ' => 'l',
+ 'ḹ' => 'l',
+
+ //Hebrew
+ 'א' => 'a',
+ 'ב' => 'b',
+ 'ג' => 'g',
+ 'ד' => 'd',
+ 'ה' => 'h',
+ 'ו' => 'v',
+ 'ז' => 'z',
+ 'ח' => 'kh',
+ 'ט' => 'th',
+ 'י' => 'y',
+ 'ך' => 'h',
+ 'כ' => 'k',
+ 'ל' => 'l',
+ 'ם' => 'm',
+ 'מ' => 'm',
+ 'ן' => 'n',
+ 'נ' => 'n',
+ 'ס' => 's',
+ 'ע' => 'ah',
+ 'ף' => 'f',
+ 'פ' => 'p',
+ 'ץ' => 'c',
+ 'צ' => 'c',
+ 'ק' => 'q',
+ 'ר' => 'r',
+ 'ש' => 'sh',
+ 'ת' => 't',
+
+ //Arabic
+ 'ا' => 'a',
+ 'ب' => 'b',
+ 'ت' => 't',
+ 'ث' => 'th',
+ 'ج' => 'g',
+ 'ح' => 'xh',
+ 'خ' => 'x',
+ 'د' => 'd',
+ 'ذ' => 'dh',
+ 'ر' => 'r',
+ 'ز' => 'z',
+ 'س' => 's',
+ 'ش' => 'sh',
+ 'ص' => 's\'',
+ 'ض' => 'd\'',
+ 'ط' => 't\'',
+ 'ظ' => 'z\'',
+ 'ع' => 'y',
+ 'غ' => 'gh',
+ 'ف' => 'f',
+ 'ق' => 'q',
+ 'ك' => 'k',
+ 'ل' => 'l',
+ 'م' => 'm',
+ 'ن' => 'n',
+ 'ه' => 'x\'',
+ 'و' => 'u',
+ 'ي' => 'i',
+
+ // Japanese characters (last update: 2008-05-09)
+
+ // Japanese hiragana
+
+ // 3 character syllables, っ doubles the consonant after
+ 'っちゃ' => 'ccha',
+ 'っちぇ' => 'cche',
+ 'っちょ' => 'ccho',
+ 'っちゅ' => 'cchu',
+ 'っびゃ' => 'bbya',
+ 'っびぇ' => 'bbye',
+ 'っびぃ' => 'bbyi',
+ 'っびょ' => 'bbyo',
+ 'っびゅ' => 'bbyu',
+ 'っぴゃ' => 'ppya',
+ 'っぴぇ' => 'ppye',
+ 'っぴぃ' => 'ppyi',
+ 'っぴょ' => 'ppyo',
+ 'っぴゅ' => 'ppyu',
+ 'っちゃ' => 'ccha',
+ 'っちぇ' => 'cche',
+ 'っち' => 'cchi',
+ 'っちょ' => 'ccho',
+ 'っちゅ' => 'cchu',
+ // 'っひゃ'=>'hya',
+ // 'っひぇ'=>'hye',
+ // 'っひぃ'=>'hyi',
+ // 'っひょ'=>'hyo',
+ // 'っひゅ'=>'hyu',
+ 'っきゃ' => 'kkya',
+ 'っきぇ' => 'kkye',
+ 'っきぃ' => 'kkyi',
+ 'っきょ' => 'kkyo',
+ 'っきゅ' => 'kkyu',
+ 'っぎゃ' => 'ggya',
+ 'っぎぇ' => 'ggye',
+ 'っぎぃ' => 'ggyi',
+ 'っぎょ' => 'ggyo',
+ 'っぎゅ' => 'ggyu',
+ 'っみゃ' => 'mmya',
+ 'っみぇ' => 'mmye',
+ 'っみぃ' => 'mmyi',
+ 'っみょ' => 'mmyo',
+ 'っみゅ' => 'mmyu',
+ 'っにゃ' => 'nnya',
+ 'っにぇ' => 'nnye',
+ 'っにぃ' => 'nnyi',
+ 'っにょ' => 'nnyo',
+ 'っにゅ' => 'nnyu',
+ 'っりゃ' => 'rrya',
+ 'っりぇ' => 'rrye',
+ 'っりぃ' => 'rryi',
+ 'っりょ' => 'rryo',
+ 'っりゅ' => 'rryu',
+ 'っしゃ' => 'ssha',
+ 'っしぇ' => 'sshe',
+ 'っし' => 'sshi',
+ 'っしょ' => 'ssho',
+ 'っしゅ' => 'sshu',
+
+ // seperate hiragana 'n' ('n' + 'i' != 'ni', normally we would write "kon'nichi wa" but the
+ // apostrophe would be converted to _ anyway)
+ 'んあ' => 'n_a',
+ 'んえ' => 'n_e',
+ 'んい' => 'n_i',
+ 'んお' => 'n_o',
+ 'んう' => 'n_u',
+ 'んや' => 'n_ya',
+ 'んよ' => 'n_yo',
+ 'んゆ' => 'n_yu',
+
+ // 2 character syllables - normal
+ 'ふぁ' => 'fa',
+ 'ふぇ' => 'fe',
+ 'ふぃ' => 'fi',
+ 'ふぉ' => 'fo',
+ 'ちゃ' => 'cha',
+ 'ちぇ' => 'che',
+ 'ち' => 'chi',
+ 'ちょ' => 'cho',
+ 'ちゅ' => 'chu',
+ 'ひゃ' => 'hya',
+ 'ひぇ' => 'hye',
+ 'ひぃ' => 'hyi',
+ 'ひょ' => 'hyo',
+ 'ひゅ' => 'hyu',
+ 'びゃ' => 'bya',
+ 'びぇ' => 'bye',
+ 'びぃ' => 'byi',
+ 'びょ' => 'byo',
+ 'びゅ' => 'byu',
+ 'ぴゃ' => 'pya',
+ 'ぴぇ' => 'pye',
+ 'ぴぃ' => 'pyi',
+ 'ぴょ' => 'pyo',
+ 'ぴゅ' => 'pyu',
+ 'きゃ' => 'kya',
+ 'きぇ' => 'kye',
+ 'きぃ' => 'kyi',
+ 'きょ' => 'kyo',
+ 'きゅ' => 'kyu',
+ 'ぎゃ' => 'gya',
+ 'ぎぇ' => 'gye',
+ 'ぎぃ' => 'gyi',
+ 'ぎょ' => 'gyo',
+ 'ぎゅ' => 'gyu',
+ 'みゃ' => 'mya',
+ 'みぇ' => 'mye',
+ 'みぃ' => 'myi',
+ 'みょ' => 'myo',
+ 'みゅ' => 'myu',
+ 'にゃ' => 'nya',
+ 'にぇ' => 'nye',
+ 'にぃ' => 'nyi',
+ 'にょ' => 'nyo',
+ 'にゅ' => 'nyu',
+ 'りゃ' => 'rya',
+ 'りぇ' => 'rye',
+ 'りぃ' => 'ryi',
+ 'りょ' => 'ryo',
+ 'りゅ' => 'ryu',
+ 'しゃ' => 'sha',
+ 'しぇ' => 'she',
+ 'し' => 'shi',
+ 'しょ' => 'sho',
+ 'しゅ' => 'shu',
+ 'じゃ' => 'ja',
+ 'じぇ' => 'je',
+ 'じょ' => 'jo',
+ 'じゅ' => 'ju',
+ 'うぇ' => 'we',
+ 'うぃ' => 'wi',
+ 'いぇ' => 'ye',
+
+ // 2 character syllables, っ doubles the consonant after
+ 'っば' => 'bba',
+ 'っべ' => 'bbe',
+ 'っび' => 'bbi',
+ 'っぼ' => 'bbo',
+ 'っぶ' => 'bbu',
+ 'っぱ' => 'ppa',
+ 'っぺ' => 'ppe',
+ 'っぴ' => 'ppi',
+ 'っぽ' => 'ppo',
+ 'っぷ' => 'ppu',
+ 'った' => 'tta',
+ 'って' => 'tte',
+ 'っち' => 'cchi',
+ 'っと' => 'tto',
+ 'っつ' => 'ttsu',
+ 'っだ' => 'dda',
+ 'っで' => 'dde',
+ 'っぢ' => 'ddi',
+ 'っど' => 'ddo',
+ 'っづ' => 'ddu',
+ 'っが' => 'gga',
+ 'っげ' => 'gge',
+ 'っぎ' => 'ggi',
+ 'っご' => 'ggo',
+ 'っぐ' => 'ggu',
+ 'っか' => 'kka',
+ 'っけ' => 'kke',
+ 'っき' => 'kki',
+ 'っこ' => 'kko',
+ 'っく' => 'kku',
+ 'っま' => 'mma',
+ 'っめ' => 'mme',
+ 'っみ' => 'mmi',
+ 'っも' => 'mmo',
+ 'っむ' => 'mmu',
+ 'っな' => 'nna',
+ 'っね' => 'nne',
+ 'っに' => 'nni',
+ 'っの' => 'nno',
+ 'っぬ' => 'nnu',
+ 'っら' => 'rra',
+ 'っれ' => 'rre',
+ 'っり' => 'rri',
+ 'っろ' => 'rro',
+ 'っる' => 'rru',
+ 'っさ' => 'ssa',
+ 'っせ' => 'sse',
+ 'っし' => 'sshi',
+ 'っそ' => 'sso',
+ 'っす' => 'ssu',
+ 'っざ' => 'zza',
+ 'っぜ' => 'zze',
+ 'っじ' => 'jji',
+ 'っぞ' => 'zzo',
+ 'っず' => 'zzu',
+
+ // 1 character syllabels
+ 'あ' => 'a',
+ 'え' => 'e',
+ 'い' => 'i',
+ 'お' => 'o',
+ 'う' => 'u',
+ 'ん' => 'n',
+ 'は' => 'ha',
+ 'へ' => 'he',
+ 'ひ' => 'hi',
+ 'ほ' => 'ho',
+ 'ふ' => 'fu',
+ 'ば' => 'ba',
+ 'べ' => 'be',
+ 'び' => 'bi',
+ 'ぼ' => 'bo',
+ 'ぶ' => 'bu',
+ 'ぱ' => 'pa',
+ 'ぺ' => 'pe',
+ 'ぴ' => 'pi',
+ 'ぽ' => 'po',
+ 'ぷ' => 'pu',
+ 'た' => 'ta',
+ 'て' => 'te',
+ 'ち' => 'chi',
+ 'と' => 'to',
+ 'つ' => 'tsu',
+ 'だ' => 'da',
+ 'で' => 'de',
+ 'ぢ' => 'di',
+ 'ど' => 'do',
+ 'づ' => 'du',
+ 'が' => 'ga',
+ 'げ' => 'ge',
+ 'ぎ' => 'gi',
+ 'ご' => 'go',
+ 'ぐ' => 'gu',
+ 'か' => 'ka',
+ 'け' => 'ke',
+ 'き' => 'ki',
+ 'こ' => 'ko',
+ 'く' => 'ku',
+ 'ま' => 'ma',
+ 'め' => 'me',
+ 'み' => 'mi',
+ 'も' => 'mo',
+ 'む' => 'mu',
+ 'な' => 'na',
+ 'ね' => 'ne',
+ 'に' => 'ni',
+ 'の' => 'no',
+ 'ぬ' => 'nu',
+ 'ら' => 'ra',
+ 'れ' => 're',
+ 'り' => 'ri',
+ 'ろ' => 'ro',
+ 'る' => 'ru',
+ 'さ' => 'sa',
+ 'せ' => 'se',
+ 'し' => 'shi',
+ 'そ' => 'so',
+ 'す' => 'su',
+ 'わ' => 'wa',
+ 'を' => 'wo',
+ 'ざ' => 'za',
+ 'ぜ' => 'ze',
+ 'じ' => 'ji',
+ 'ぞ' => 'zo',
+ 'ず' => 'zu',
+ 'や' => 'ya',
+ 'よ' => 'yo',
+ 'ゆ' => 'yu',
+ // old characters
+ 'ゑ' => 'we',
+ 'ゐ' => 'wi',
+
+ // convert what's left (probably only kicks in when something's missing above)
+ // 'ぁ'=>'a','ぇ'=>'e','ぃ'=>'i','ぉ'=>'o','ぅ'=>'u',
+ // 'ゃ'=>'ya','ょ'=>'yo','ゅ'=>'yu',
+
+ // never seen one of those (disabled for the moment)
+ // 'ヴぁ'=>'va','ヴぇ'=>'ve','ヴぃ'=>'vi','ヴぉ'=>'vo','ヴ'=>'vu',
+ // 'でゃ'=>'dha','でぇ'=>'dhe','でぃ'=>'dhi','でょ'=>'dho','でゅ'=>'dhu',
+ // 'どぁ'=>'dwa','どぇ'=>'dwe','どぃ'=>'dwi','どぉ'=>'dwo','どぅ'=>'dwu',
+ // 'ぢゃ'=>'dya','ぢぇ'=>'dye','ぢぃ'=>'dyi','ぢょ'=>'dyo','ぢゅ'=>'dyu',
+ // 'ふぁ'=>'fwa','ふぇ'=>'fwe','ふぃ'=>'fwi','ふぉ'=>'fwo','ふぅ'=>'fwu',
+ // 'ふゃ'=>'fya','ふぇ'=>'fye','ふぃ'=>'fyi','ふょ'=>'fyo','ふゅ'=>'fyu',
+ // 'すぁ'=>'swa','すぇ'=>'swe','すぃ'=>'swi','すぉ'=>'swo','すぅ'=>'swu',
+ // 'てゃ'=>'tha','てぇ'=>'the','てぃ'=>'thi','てょ'=>'tho','てゅ'=>'thu',
+ // 'つゃ'=>'tsa','つぇ'=>'tse','つぃ'=>'tsi','つょ'=>'tso','つ'=>'tsu',
+ // 'とぁ'=>'twa','とぇ'=>'twe','とぃ'=>'twi','とぉ'=>'two','とぅ'=>'twu',
+ // 'ヴゃ'=>'vya','ヴぇ'=>'vye','ヴぃ'=>'vyi','ヴょ'=>'vyo','ヴゅ'=>'vyu',
+ // 'うぁ'=>'wha','うぇ'=>'whe','うぃ'=>'whi','うぉ'=>'who','うぅ'=>'whu',
+ // 'じゃ'=>'zha','じぇ'=>'zhe','じぃ'=>'zhi','じょ'=>'zho','じゅ'=>'zhu',
+ // 'じゃ'=>'zya','じぇ'=>'zye','じぃ'=>'zyi','じょ'=>'zyo','じゅ'=>'zyu',
+
+ // 'spare' characters from other romanization systems
+ // 'だ'=>'da','で'=>'de','ぢ'=>'di','ど'=>'do','づ'=>'du',
+ // 'ら'=>'la','れ'=>'le','り'=>'li','ろ'=>'lo','る'=>'lu',
+ // 'さ'=>'sa','せ'=>'se','し'=>'si','そ'=>'so','す'=>'su',
+ // 'ちゃ'=>'cya','ちぇ'=>'cye','ちぃ'=>'cyi','ちょ'=>'cyo','ちゅ'=>'cyu',
+ //'じゃ'=>'jya','じぇ'=>'jye','じぃ'=>'jyi','じょ'=>'jyo','じゅ'=>'jyu',
+ //'りゃ'=>'lya','りぇ'=>'lye','りぃ'=>'lyi','りょ'=>'lyo','りゅ'=>'lyu',
+ //'しゃ'=>'sya','しぇ'=>'sye','しぃ'=>'syi','しょ'=>'syo','しゅ'=>'syu',
+ //'ちゃ'=>'tya','ちぇ'=>'tye','ちぃ'=>'tyi','ちょ'=>'tyo','ちゅ'=>'tyu',
+ //'し'=>'ci',,い'=>'yi','ぢ'=>'dzi',
+ //'っじゃ'=>'jja','っじぇ'=>'jje','っじ'=>'jji','っじょ'=>'jjo','っじゅ'=>'jju',
+
+
+ // Japanese katakana
+
+ // 4 character syllables: ッ doubles the consonant after, ー doubles the vowel before
+ // (usualy written with macron, but we don't want that in our URLs)
+ 'ッビャー' => 'bbyaa',
+ 'ッビェー' => 'bbyee',
+ 'ッビィー' => 'bbyii',
+ 'ッビョー' => 'bbyoo',
+ 'ッビュー' => 'bbyuu',
+ 'ッピャー' => 'ppyaa',
+ 'ッピェー' => 'ppyee',
+ 'ッピィー' => 'ppyii',
+ 'ッピョー' => 'ppyoo',
+ 'ッピュー' => 'ppyuu',
+ 'ッキャー' => 'kkyaa',
+ 'ッキェー' => 'kkyee',
+ 'ッキィー' => 'kkyii',
+ 'ッキョー' => 'kkyoo',
+ 'ッキュー' => 'kkyuu',
+ 'ッギャー' => 'ggyaa',
+ 'ッギェー' => 'ggyee',
+ 'ッギィー' => 'ggyii',
+ 'ッギョー' => 'ggyoo',
+ 'ッギュー' => 'ggyuu',
+ 'ッミャー' => 'mmyaa',
+ 'ッミェー' => 'mmyee',
+ 'ッミィー' => 'mmyii',
+ 'ッミョー' => 'mmyoo',
+ 'ッミュー' => 'mmyuu',
+ 'ッニャー' => 'nnyaa',
+ 'ッニェー' => 'nnyee',
+ 'ッニィー' => 'nnyii',
+ 'ッニョー' => 'nnyoo',
+ 'ッニュー' => 'nnyuu',
+ 'ッリャー' => 'rryaa',
+ 'ッリェー' => 'rryee',
+ 'ッリィー' => 'rryii',
+ 'ッリョー' => 'rryoo',
+ 'ッリュー' => 'rryuu',
+ 'ッシャー' => 'sshaa',
+ 'ッシェー' => 'sshee',
+ 'ッシー' => 'sshii',
+ 'ッショー' => 'sshoo',
+ 'ッシュー' => 'sshuu',
+ 'ッチャー' => 'cchaa',
+ 'ッチェー' => 'cchee',
+ 'ッチー' => 'cchii',
+ 'ッチョー' => 'cchoo',
+ 'ッチュー' => 'cchuu',
+ 'ッティー' => 'ttii',
+ 'ッヂィー' => 'ddii',
+
+ // 3 character syllables - doubled vowels
+ 'ファー' => 'faa',
+ 'フェー' => 'fee',
+ 'フィー' => 'fii',
+ 'フォー' => 'foo',
+ 'フャー' => 'fyaa',
+ 'フェー' => 'fyee',
+ 'フィー' => 'fyii',
+ 'フョー' => 'fyoo',
+ 'フュー' => 'fyuu',
+ 'ヒャー' => 'hyaa',
+ 'ヒェー' => 'hyee',
+ 'ヒィー' => 'hyii',
+ 'ヒョー' => 'hyoo',
+ 'ヒュー' => 'hyuu',
+ 'ビャー' => 'byaa',
+ 'ビェー' => 'byee',
+ 'ビィー' => 'byii',
+ 'ビョー' => 'byoo',
+ 'ビュー' => 'byuu',
+ 'ピャー' => 'pyaa',
+ 'ピェー' => 'pyee',
+ 'ピィー' => 'pyii',
+ 'ピョー' => 'pyoo',
+ 'ピュー' => 'pyuu',
+ 'キャー' => 'kyaa',
+ 'キェー' => 'kyee',
+ 'キィー' => 'kyii',
+ 'キョー' => 'kyoo',
+ 'キュー' => 'kyuu',
+ 'ギャー' => 'gyaa',
+ 'ギェー' => 'gyee',
+ 'ギィー' => 'gyii',
+ 'ギョー' => 'gyoo',
+ 'ギュー' => 'gyuu',
+ 'ミャー' => 'myaa',
+ 'ミェー' => 'myee',
+ 'ミィー' => 'myii',
+ 'ミョー' => 'myoo',
+ 'ミュー' => 'myuu',
+ 'ニャー' => 'nyaa',
+ 'ニェー' => 'nyee',
+ 'ニィー' => 'nyii',
+ 'ニョー' => 'nyoo',
+ 'ニュー' => 'nyuu',
+ 'リャー' => 'ryaa',
+ 'リェー' => 'ryee',
+ 'リィー' => 'ryii',
+ 'リョー' => 'ryoo',
+ 'リュー' => 'ryuu',
+ 'シャー' => 'shaa',
+ 'シェー' => 'shee',
+ 'シー' => 'shii',
+ 'ショー' => 'shoo',
+ 'シュー' => 'shuu',
+ 'ジャー' => 'jaa',
+ 'ジェー' => 'jee',
+ 'ジー' => 'jii',
+ 'ジョー' => 'joo',
+ 'ジュー' => 'juu',
+ 'スァー' => 'swaa',
+ 'スェー' => 'swee',
+ 'スィー' => 'swii',
+ 'スォー' => 'swoo',
+ 'スゥー' => 'swuu',
+ 'デァー' => 'daa',
+ 'デェー' => 'dee',
+ 'ディー' => 'dii',
+ 'デォー' => 'doo',
+ 'デゥー' => 'duu',
+ 'チャー' => 'chaa',
+ 'チェー' => 'chee',
+ 'チー' => 'chii',
+ 'チョー' => 'choo',
+ 'チュー' => 'chuu',
+ 'ヂャー' => 'dyaa',
+ 'ヂェー' => 'dyee',
+ 'ヂィー' => 'dyii',
+ 'ヂョー' => 'dyoo',
+ 'ヂュー' => 'dyuu',
+ 'ツャー' => 'tsaa',
+ 'ツェー' => 'tsee',
+ 'ツィー' => 'tsii',
+ 'ツョー' => 'tsoo',
+ 'ツー' => 'tsuu',
+ 'トァー' => 'twaa',
+ 'トェー' => 'twee',
+ 'トィー' => 'twii',
+ 'トォー' => 'twoo',
+ 'トゥー' => 'twuu',
+ 'ドァー' => 'dwaa',
+ 'ドェー' => 'dwee',
+ 'ドィー' => 'dwii',
+ 'ドォー' => 'dwoo',
+ 'ドゥー' => 'dwuu',
+ 'ウァー' => 'whaa',
+ 'ウェー' => 'whee',
+ 'ウィー' => 'whii',
+ 'ウォー' => 'whoo',
+ 'ウゥー' => 'whuu',
+ 'ヴャー' => 'vyaa',
+ 'ヴェー' => 'vyee',
+ 'ヴィー' => 'vyii',
+ 'ヴョー' => 'vyoo',
+ 'ヴュー' => 'vyuu',
+ 'ヴァー' => 'vaa',
+ 'ヴェー' => 'vee',
+ 'ヴィー' => 'vii',
+ 'ヴォー' => 'voo',
+ 'ヴー' => 'vuu',
+ 'ウェー' => 'wee',
+ 'ウィー' => 'wii',
+ 'イェー' => 'yee',
+ 'ティー' => 'tii',
+ 'ヂィー' => 'dii',
+
+ // 3 character syllables - doubled consonants
+ 'ッビャ' => 'bbya',
+ 'ッビェ' => 'bbye',
+ 'ッビィ' => 'bbyi',
+ 'ッビョ' => 'bbyo',
+ 'ッビュ' => 'bbyu',
+ 'ッピャ' => 'ppya',
+ 'ッピェ' => 'ppye',
+ 'ッピィ' => 'ppyi',
+ 'ッピョ' => 'ppyo',
+ 'ッピュ' => 'ppyu',
+ 'ッキャ' => 'kkya',
+ 'ッキェ' => 'kkye',
+ 'ッキィ' => 'kkyi',
+ 'ッキョ' => 'kkyo',
+ 'ッキュ' => 'kkyu',
+ 'ッギャ' => 'ggya',
+ 'ッギェ' => 'ggye',
+ 'ッギィ' => 'ggyi',
+ 'ッギョ' => 'ggyo',
+ 'ッギュ' => 'ggyu',
+ 'ッミャ' => 'mmya',
+ 'ッミェ' => 'mmye',
+ 'ッミィ' => 'mmyi',
+ 'ッミョ' => 'mmyo',
+ 'ッミュ' => 'mmyu',
+ 'ッニャ' => 'nnya',
+ 'ッニェ' => 'nnye',
+ 'ッニィ' => 'nnyi',
+ 'ッニョ' => 'nnyo',
+ 'ッニュ' => 'nnyu',
+ 'ッリャ' => 'rrya',
+ 'ッリェ' => 'rrye',
+ 'ッリィ' => 'rryi',
+ 'ッリョ' => 'rryo',
+ 'ッリュ' => 'rryu',
+ 'ッシャ' => 'ssha',
+ 'ッシェ' => 'sshe',
+ 'ッシ' => 'sshi',
+ 'ッショ' => 'ssho',
+ 'ッシュ' => 'sshu',
+ 'ッチャ' => 'ccha',
+ 'ッチェ' => 'cche',
+ 'ッチ' => 'cchi',
+ 'ッチョ' => 'ccho',
+ 'ッチュ' => 'cchu',
+ 'ッティ' => 'tti',
+ 'ッヂィ' => 'ddi',
+
+ // 3 character syllables - doubled vowel and consonants
+ 'ッバー' => 'bbaa',
+ 'ッベー' => 'bbee',
+ 'ッビー' => 'bbii',
+ 'ッボー' => 'bboo',
+ 'ッブー' => 'bbuu',
+ 'ッパー' => 'ppaa',
+ 'ッペー' => 'ppee',
+ 'ッピー' => 'ppii',
+ 'ッポー' => 'ppoo',
+ 'ップー' => 'ppuu',
+ 'ッケー' => 'kkee',
+ 'ッキー' => 'kkii',
+ 'ッコー' => 'kkoo',
+ 'ックー' => 'kkuu',
+ 'ッカー' => 'kkaa',
+ 'ッガー' => 'ggaa',
+ 'ッゲー' => 'ggee',
+ 'ッギー' => 'ggii',
+ 'ッゴー' => 'ggoo',
+ 'ッグー' => 'gguu',
+ 'ッマー' => 'maa',
+ 'ッメー' => 'mee',
+ 'ッミー' => 'mii',
+ 'ッモー' => 'moo',
+ 'ッムー' => 'muu',
+ 'ッナー' => 'nnaa',
+ 'ッネー' => 'nnee',
+ 'ッニー' => 'nnii',
+ 'ッノー' => 'nnoo',
+ 'ッヌー' => 'nnuu',
+ 'ッラー' => 'rraa',
+ 'ッレー' => 'rree',
+ 'ッリー' => 'rrii',
+ 'ッロー' => 'rroo',
+ 'ッルー' => 'rruu',
+ 'ッサー' => 'ssaa',
+ 'ッセー' => 'ssee',
+ 'ッシー' => 'sshii',
+ 'ッソー' => 'ssoo',
+ 'ッスー' => 'ssuu',
+ 'ッザー' => 'zzaa',
+ 'ッゼー' => 'zzee',
+ 'ッジー' => 'jjii',
+ 'ッゾー' => 'zzoo',
+ 'ッズー' => 'zzuu',
+ 'ッター' => 'ttaa',
+ 'ッテー' => 'ttee',
+ 'ッチー' => 'chii',
+ 'ットー' => 'ttoo',
+ 'ッツー' => 'ttsuu',
+ 'ッダー' => 'ddaa',
+ 'ッデー' => 'ddee',
+ 'ッヂー' => 'ddii',
+ 'ッドー' => 'ddoo',
+ 'ッヅー' => 'dduu',
+
+ // 2 character syllables - normal
+ 'ファ' => 'fa',
+ 'フェ' => 'fe',
+ 'フィ' => 'fi',
+ 'フォ' => 'fo',
+ 'フゥ' => 'fu',
+ // 'フャ'=>'fya',
+ // 'フェ'=>'fye',
+ // 'フィ'=>'fyi',
+ // 'フョ'=>'fyo',
+ // 'フュ'=>'fyu',
+ 'フャ' => 'fa',
+ 'フェ' => 'fe',
+ 'フィ' => 'fi',
+ 'フョ' => 'fo',
+ 'フュ' => 'fu',
+ 'ヒャ' => 'hya',
+ 'ヒェ' => 'hye',
+ 'ヒィ' => 'hyi',
+ 'ヒョ' => 'hyo',
+ 'ヒュ' => 'hyu',
+ 'ビャ' => 'bya',
+ 'ビェ' => 'bye',
+ 'ビィ' => 'byi',
+ 'ビョ' => 'byo',
+ 'ビュ' => 'byu',
+ 'ピャ' => 'pya',
+ 'ピェ' => 'pye',
+ 'ピィ' => 'pyi',
+ 'ピョ' => 'pyo',
+ 'ピュ' => 'pyu',
+ 'キャ' => 'kya',
+ 'キェ' => 'kye',
+ 'キィ' => 'kyi',
+ 'キョ' => 'kyo',
+ 'キュ' => 'kyu',
+ 'ギャ' => 'gya',
+ 'ギェ' => 'gye',
+ 'ギィ' => 'gyi',
+ 'ギョ' => 'gyo',
+ 'ギュ' => 'gyu',
+ 'ミャ' => 'mya',
+ 'ミェ' => 'mye',
+ 'ミィ' => 'myi',
+ 'ミョ' => 'myo',
+ 'ミュ' => 'myu',
+ 'ニャ' => 'nya',
+ 'ニェ' => 'nye',
+ 'ニィ' => 'nyi',
+ 'ニョ' => 'nyo',
+ 'ニュ' => 'nyu',
+ 'リャ' => 'rya',
+ 'リェ' => 'rye',
+ 'リィ' => 'ryi',
+ 'リョ' => 'ryo',
+ 'リュ' => 'ryu',
+ 'シャ' => 'sha',
+ 'シェ' => 'she',
+ 'ショ' => 'sho',
+ 'シュ' => 'shu',
+ 'ジャ' => 'ja',
+ 'ジェ' => 'je',
+ 'ジョ' => 'jo',
+ 'ジュ' => 'ju',
+ 'スァ' => 'swa',
+ 'スェ' => 'swe',
+ 'スィ' => 'swi',
+ 'スォ' => 'swo',
+ 'スゥ' => 'swu',
+ 'デァ' => 'da',
+ 'デェ' => 'de',
+ 'ディ' => 'di',
+ 'デォ' => 'do',
+ 'デゥ' => 'du',
+ 'チャ' => 'cha',
+ 'チェ' => 'che',
+ 'チ' => 'chi',
+ 'チョ' => 'cho',
+ 'チュ' => 'chu',
+ // 'ヂャ'=>'dya',
+ // 'ヂェ'=>'dye',
+ // 'ヂィ'=>'dyi',
+ // 'ヂョ'=>'dyo',
+ // 'ヂュ'=>'dyu',
+ 'ツャ' => 'tsa',
+ 'ツェ' => 'tse',
+ 'ツィ' => 'tsi',
+ 'ツョ' => 'tso',
+ 'ツ' => 'tsu',
+ 'トァ' => 'twa',
+ 'トェ' => 'twe',
+ 'トィ' => 'twi',
+ 'トォ' => 'two',
+ 'トゥ' => 'twu',
+ 'ドァ' => 'dwa',
+ 'ドェ' => 'dwe',
+ 'ドィ' => 'dwi',
+ 'ドォ' => 'dwo',
+ 'ドゥ' => 'dwu',
+ 'ウァ' => 'wha',
+ 'ウェ' => 'whe',
+ 'ウィ' => 'whi',
+ 'ウォ' => 'who',
+ 'ウゥ' => 'whu',
+ 'ヴャ' => 'vya',
+ 'ヴェ' => 'vye',
+ 'ヴィ' => 'vyi',
+ 'ヴョ' => 'vyo',
+ 'ヴュ' => 'vyu',
+ 'ヴァ' => 'va',
+ 'ヴェ' => 've',
+ 'ヴィ' => 'vi',
+ 'ヴォ' => 'vo',
+ 'ヴ' => 'vu',
+ 'ウェ' => 'we',
+ 'ウィ' => 'wi',
+ 'イェ' => 'ye',
+ 'ティ' => 'ti',
+ 'ヂィ' => 'di',
+
+ // 2 character syllables - doubled vocal
+ 'アー' => 'aa',
+ 'エー' => 'ee',
+ 'イー' => 'ii',
+ 'オー' => 'oo',
+ 'ウー' => 'uu',
+ 'ダー' => 'daa',
+ 'デー' => 'dee',
+ 'ヂー' => 'dii',
+ 'ドー' => 'doo',
+ 'ヅー' => 'duu',
+ 'ハー' => 'haa',
+ 'ヘー' => 'hee',
+ 'ヒー' => 'hii',
+ 'ホー' => 'hoo',
+ 'フー' => 'fuu',
+ 'バー' => 'baa',
+ 'ベー' => 'bee',
+ 'ビー' => 'bii',
+ 'ボー' => 'boo',
+ 'ブー' => 'buu',
+ 'パー' => 'paa',
+ 'ペー' => 'pee',
+ 'ピー' => 'pii',
+ 'ポー' => 'poo',
+ 'プー' => 'puu',
+ 'ケー' => 'kee',
+ 'キー' => 'kii',
+ 'コー' => 'koo',
+ 'クー' => 'kuu',
+ 'カー' => 'kaa',
+ 'ガー' => 'gaa',
+ 'ゲー' => 'gee',
+ 'ギー' => 'gii',
+ 'ゴー' => 'goo',
+ 'グー' => 'guu',
+ 'マー' => 'maa',
+ 'メー' => 'mee',
+ 'ミー' => 'mii',
+ 'モー' => 'moo',
+ 'ムー' => 'muu',
+ 'ナー' => 'naa',
+ 'ネー' => 'nee',
+ 'ニー' => 'nii',
+ 'ノー' => 'noo',
+ 'ヌー' => 'nuu',
+ 'ラー' => 'raa',
+ 'レー' => 'ree',
+ 'リー' => 'rii',
+ 'ロー' => 'roo',
+ 'ルー' => 'ruu',
+ 'サー' => 'saa',
+ 'セー' => 'see',
+ 'シー' => 'shii',
+ 'ソー' => 'soo',
+ 'スー' => 'suu',
+ 'ザー' => 'zaa',
+ 'ゼー' => 'zee',
+ 'ジー' => 'jii',
+ 'ゾー' => 'zoo',
+ 'ズー' => 'zuu',
+ 'ター' => 'taa',
+ 'テー' => 'tee',
+ 'チー' => 'chii',
+ 'トー' => 'too',
+ 'ツー' => 'tsuu',
+ 'ワー' => 'waa',
+ 'ヲー' => 'woo',
+ 'ヤー' => 'yaa',
+ 'ヨー' => 'yoo',
+ 'ユー' => 'yuu',
+ 'ヵー' => 'kaa',
+ 'ヶー' => 'kee',
+ // old characters
+ 'ヱー' => 'wee',
+ 'ヰー' => 'wii',
+
+ // seperate katakana 'n'
+ 'ンア' => 'n_a',
+ 'ンエ' => 'n_e',
+ 'ンイ' => 'n_i',
+ 'ンオ' => 'n_o',
+ 'ンウ' => 'n_u',
+ 'ンヤ' => 'n_ya',
+ 'ンヨ' => 'n_yo',
+ 'ンユ' => 'n_yu',
+
+ // 2 character syllables - doubled consonants
+ 'ッバ' => 'bba',
+ 'ッベ' => 'bbe',
+ 'ッビ' => 'bbi',
+ 'ッボ' => 'bbo',
+ 'ッブ' => 'bbu',
+ 'ッパ' => 'ppa',
+ 'ッペ' => 'ppe',
+ 'ッピ' => 'ppi',
+ 'ッポ' => 'ppo',
+ 'ップ' => 'ppu',
+ 'ッケ' => 'kke',
+ 'ッキ' => 'kki',
+ 'ッコ' => 'kko',
+ 'ック' => 'kku',
+ 'ッカ' => 'kka',
+ 'ッガ' => 'gga',
+ 'ッゲ' => 'gge',
+ 'ッギ' => 'ggi',
+ 'ッゴ' => 'ggo',
+ 'ッグ' => 'ggu',
+ 'ッマ' => 'ma',
+ 'ッメ' => 'me',
+ 'ッミ' => 'mi',
+ 'ッモ' => 'mo',
+ 'ッム' => 'mu',
+ 'ッナ' => 'nna',
+ 'ッネ' => 'nne',
+ 'ッニ' => 'nni',
+ 'ッノ' => 'nno',
+ 'ッヌ' => 'nnu',
+ 'ッラ' => 'rra',
+ 'ッレ' => 'rre',
+ 'ッリ' => 'rri',
+ 'ッロ' => 'rro',
+ 'ッル' => 'rru',
+ 'ッサ' => 'ssa',
+ 'ッセ' => 'sse',
+ 'ッシ' => 'sshi',
+ 'ッソ' => 'sso',
+ 'ッス' => 'ssu',
+ 'ッザ' => 'zza',
+ 'ッゼ' => 'zze',
+ 'ッジ' => 'jji',
+ 'ッゾ' => 'zzo',
+ 'ッズ' => 'zzu',
+ 'ッタ' => 'tta',
+ 'ッテ' => 'tte',
+ 'ッチ' => 'cchi',
+ 'ット' => 'tto',
+ 'ッツ' => 'ttsu',
+ 'ッダ' => 'dda',
+ 'ッデ' => 'dde',
+ 'ッヂ' => 'ddi',
+ 'ッド' => 'ddo',
+ 'ッヅ' => 'ddu',
+
+ // 1 character syllables
+ 'ア' => 'a',
+ 'エ' => 'e',
+ 'イ' => 'i',
+ 'オ' => 'o',
+ 'ウ' => 'u',
+ 'ン' => 'n',
+ 'ハ' => 'ha',
+ 'ヘ' => 'he',
+ 'ヒ' => 'hi',
+ 'ホ' => 'ho',
+ 'フ' => 'fu',
+ 'バ' => 'ba',
+ 'ベ' => 'be',
+ 'ビ' => 'bi',
+ 'ボ' => 'bo',
+ 'ブ' => 'bu',
+ 'パ' => 'pa',
+ 'ペ' => 'pe',
+ 'ピ' => 'pi',
+ 'ポ' => 'po',
+ 'プ' => 'pu',
+ 'ケ' => 'ke',
+ 'キ' => 'ki',
+ 'コ' => 'ko',
+ 'ク' => 'ku',
+ 'カ' => 'ka',
+ 'ガ' => 'ga',
+ 'ゲ' => 'ge',
+ 'ギ' => 'gi',
+ 'ゴ' => 'go',
+ 'グ' => 'gu',
+ 'マ' => 'ma',
+ 'メ' => 'me',
+ 'ミ' => 'mi',
+ 'モ' => 'mo',
+ 'ム' => 'mu',
+ 'ナ' => 'na',
+ 'ネ' => 'ne',
+ 'ニ' => 'ni',
+ 'ノ' => 'no',
+ 'ヌ' => 'nu',
+ 'ラ' => 'ra',
+ 'レ' => 're',
+ 'リ' => 'ri',
+ 'ロ' => 'ro',
+ 'ル' => 'ru',
+ 'サ' => 'sa',
+ 'セ' => 'se',
+ 'シ' => 'shi',
+ 'ソ' => 'so',
+ 'ス' => 'su',
+ 'ザ' => 'za',
+ 'ゼ' => 'ze',
+ 'ジ' => 'ji',
+ 'ゾ' => 'zo',
+ 'ズ' => 'zu',
+ 'タ' => 'ta',
+ 'テ' => 'te',
+ 'チ' => 'chi',
+ 'ト' => 'to',
+ 'ツ' => 'tsu',
+ 'ダ' => 'da',
+ 'デ' => 'de',
+ 'ヂ' => 'di',
+ 'ド' => 'do',
+ 'ヅ' => 'du',
+ 'ワ' => 'wa',
+ 'ヲ' => 'wo',
+ 'ヤ' => 'ya',
+ 'ヨ' => 'yo',
+ 'ユ' => 'yu',
+ 'ヵ' => 'ka',
+ 'ヶ' => 'ke',
+ // old characters
+ 'ヱ' => 'we',
+ 'ヰ' => 'wi',
+
+ // convert what's left (probably only kicks in when something's missing above)
+ 'ァ' => 'a',
+ 'ェ' => 'e',
+ 'ィ' => 'i',
+ 'ォ' => 'o',
+ 'ゥ' => 'u',
+ 'ャ' => 'ya',
+ 'ョ' => 'yo',
+ 'ュ' => 'yu',
+
+ // special characters
+ '・' => '_',
+ '、' => '_',
+ 'ー' => '_',
+ // when used with hiragana (seldom), this character would not be converted otherwise
+
+ // 'ラ'=>'la',
+ // 'レ'=>'le',
+ // 'リ'=>'li',
+ // 'ロ'=>'lo',
+ // 'ル'=>'lu',
+ // 'チャ'=>'cya',
+ // 'チェ'=>'cye',
+ // 'チィ'=>'cyi',
+ // 'チョ'=>'cyo',
+ // 'チュ'=>'cyu',
+ // 'デャ'=>'dha',
+ // 'デェ'=>'dhe',
+ // 'ディ'=>'dhi',
+ // 'デョ'=>'dho',
+ // 'デュ'=>'dhu',
+ // 'リャ'=>'lya',
+ // 'リェ'=>'lye',
+ // 'リィ'=>'lyi',
+ // 'リョ'=>'lyo',
+ // 'リュ'=>'lyu',
+ // 'テャ'=>'tha',
+ // 'テェ'=>'the',
+ // 'ティ'=>'thi',
+ // 'テョ'=>'tho',
+ // 'テュ'=>'thu',
+ // 'ファ'=>'fwa',
+ // 'フェ'=>'fwe',
+ // 'フィ'=>'fwi',
+ // 'フォ'=>'fwo',
+ // 'フゥ'=>'fwu',
+ // 'チャ'=>'tya',
+ // 'チェ'=>'tye',
+ // 'チィ'=>'tyi',
+ // 'チョ'=>'tyo',
+ // 'チュ'=>'tyu',
+ // 'ジャ'=>'jya',
+ // 'ジェ'=>'jye',
+ // 'ジィ'=>'jyi',
+ // 'ジョ'=>'jyo',
+ // 'ジュ'=>'jyu',
+ // 'ジャ'=>'zha',
+ // 'ジェ'=>'zhe',
+ // 'ジィ'=>'zhi',
+ // 'ジョ'=>'zho',
+ // 'ジュ'=>'zhu',
+ // 'ジャ'=>'zya',
+ // 'ジェ'=>'zye',
+ // 'ジィ'=>'zyi',
+ // 'ジョ'=>'zyo',
+ // 'ジュ'=>'zyu',
+ // 'シャ'=>'sya',
+ // 'シェ'=>'sye',
+ // 'シィ'=>'syi',
+ // 'ショ'=>'syo',
+ // 'シュ'=>'syu',
+ // 'シ'=>'ci',
+ // 'フ'=>'hu',
+ // 'シ'=>'si',
+ // 'チ'=>'ti',
+ // 'ツ'=>'tu',
+ // 'イ'=>'yi',
+ // 'ヂ'=>'dzi',
+
+ // "Greeklish"
+ 'Γ' => 'G',
+ 'Δ' => 'E',
+ 'Θ' => 'Th',
+ 'Λ' => 'L',
+ 'Ξ' => 'X',
+ 'Π' => 'P',
+ 'Σ' => 'S',
+ 'Φ' => 'F',
+ 'Ψ' => 'Ps',
+ 'γ' => 'g',
+ 'δ' => 'e',
+ 'θ' => 'th',
+ 'λ' => 'l',
+ 'ξ' => 'x',
+ 'π' => 'p',
+ 'σ' => 's',
+ 'φ' => 'f',
+ 'ψ' => 'ps',
+
+ // Thai
+ 'ก' => 'k',
+ 'ข' => 'kh',
+ 'ฃ' => 'kh',
+ 'ค' => 'kh',
+ 'ฅ' => 'kh',
+ 'ฆ' => 'kh',
+ 'ง' => 'ng',
+ 'จ' => 'ch',
+ 'ฉ' => 'ch',
+ 'ช' => 'ch',
+ 'ซ' => 's',
+ 'ฌ' => 'ch',
+ 'ญ' => 'y',
+ 'ฎ' => 'd',
+ 'ฏ' => 't',
+ 'ฐ' => 'th',
+ 'ฑ' => 'd',
+ 'ฒ' => 'th',
+ 'ณ' => 'n',
+ 'ด' => 'd',
+ 'ต' => 't',
+ 'ถ' => 'th',
+ 'ท' => 'th',
+ 'ธ' => 'th',
+ 'น' => 'n',
+ 'บ' => 'b',
+ 'ป' => 'p',
+ 'ผ' => 'ph',
+ 'ฝ' => 'f',
+ 'พ' => 'ph',
+ 'ฟ' => 'f',
+ 'ภ' => 'ph',
+ 'ม' => 'm',
+ 'ย' => 'y',
+ 'ร' => 'r',
+ 'ฤ' => 'rue',
+ 'ฤๅ' => 'rue',
+ 'ล' => 'l',
+ 'ฦ' => 'lue',
+ 'ฦๅ' => 'lue',
+ 'ว' => 'w',
+ 'ศ' => 's',
+ 'ษ' => 's',
+ 'ส' => 's',
+ 'ห' => 'h',
+ 'ฬ' => 'l',
+ 'ฮ' => 'h',
+ 'ะ' => 'a',
+ 'ั' => 'a',
+ 'รร' => 'a',
+ 'า' => 'a',
+ 'ๅ' => 'a',
+ 'ำ' => 'am',
+ 'ํา' => 'am',
+ 'ิ' => 'i',
+ 'ี' => 'i',
+ 'ึ' => 'ue',
+ 'ี' => 'ue',
+ 'ุ' => 'u',
+ 'ู' => 'u',
+ 'เ' => 'e',
+ 'แ' => 'ae',
+ 'โ' => 'o',
+ 'อ' => 'o',
+ 'ียะ' => 'ia',
+ 'ีย' => 'ia',
+ 'ือะ' => 'uea',
+ 'ือ' => 'uea',
+ 'ัวะ' => 'ua',
+ 'ัว' => 'ua',
+ 'ใ' => 'ai',
+ 'ไ' => 'ai',
+ 'ัย' => 'ai',
+ 'าย' => 'ai',
+ 'าว' => 'ao',
+ 'ุย' => 'ui',
+ 'อย' => 'oi',
+ 'ือย' => 'ueai',
+ 'วย' => 'uai',
+ 'ิว' => 'io',
+ '็ว' => 'eo',
+ 'ียว' => 'iao',
+ '่' => '',
+ '้' => '',
+ '๊' => '',
+ '๋' => '',
+ '็' => '',
+ '์' => '',
+ '๎' => '',
+ 'ํ' => '',
+ 'ฺ' => '',
+ 'ๆ' => '2',
+ '๏' => 'o',
+ 'ฯ' => '-',
+ '๚' => '-',
+ '๛' => '-',
+ '๐' => '0',
+ '๑' => '1',
+ '๒' => '2',
+ '๓' => '3',
+ '๔' => '4',
+ '๕' => '5',
+ '๖' => '6',
+ '๗' => '7',
+ '๘' => '8',
+ '๙' => '9',
+
+ // Korean
+ 'ㄱ' => 'k', 'ㅋ' => 'kh',
+ 'ㄲ' => 'kk',
+ 'ㄷ' => 't',
+ 'ㅌ' => 'th',
+ 'ㄸ' => 'tt',
+ 'ㅂ' => 'p',
+ 'ㅍ' => 'ph',
+ 'ㅃ' => 'pp',
+ 'ㅈ' => 'c',
+ 'ㅊ' => 'ch',
+ 'ㅉ' => 'cc',
+ 'ㅅ' => 's',
+ 'ㅆ' => 'ss',
+ 'ㅎ' => 'h',
+ 'ㅇ' => 'ng',
+ 'ㄴ' => 'n',
+ 'ㄹ' => 'l',
+ 'ㅁ' => 'm',
+ 'ㅏ' => 'a',
+ 'ㅓ' => 'e',
+ 'ㅗ' => 'o',
+ 'ㅜ' => 'wu',
+ 'ㅡ' => 'u',
+ 'ㅣ' => 'i',
+ 'ㅐ' => 'ay',
+ 'ㅔ' => 'ey',
+ 'ㅚ' => 'oy',
+ 'ㅘ' => 'wa',
+ 'ㅝ' => 'we',
+ 'ㅟ' => 'wi',
+ 'ㅙ' => 'way',
+ 'ㅞ' => 'wey',
+ 'ㅢ' => 'uy',
+ 'ㅑ' => 'ya',
+ 'ㅕ' => 'ye',
+ 'ㅛ' => 'oy',
+ 'ㅠ' => 'yu',
+ 'ㅒ' => 'yay',
+ 'ㅖ' => 'yey',
+];
diff --git a/inc/Utf8/tables/specials.php b/inc/Utf8/tables/specials.php
new file mode 100644
index 000000000..3dda94b39
--- /dev/null
+++ b/inc/Utf8/tables/specials.php
@@ -0,0 +1,620 @@
+<?php
+/**
+ * UTF-8 array of common special characters
+ *
+ * This array should contain all special characters (not a letter or digit)
+ * defined in the various local charsets - it's not a complete list of non-alphanum
+ * characters in UTF-8. It's not perfect but should match most cases of special
+ * chars.
+ *
+ * The controlchars 0x00 to 0x19 are _not_ included in this array. The space 0x20 is!
+ * These chars are _not_ in the array either: _ (0x5f), : 0x3a, . 0x2e, - 0x2d, * 0x2a
+ *
+ * @author Andreas Gohr <andi@splitbrain.org>
+ * @see \dokuwiki\Utf8\Clean::stripspecials()
+ */
+return [
+ 0x1a, // 
+ 0x1b, // 
+ 0x1c, // 
+ 0x1d, // 
+ 0x1e, // 
+ 0x1f, // 
+ 0x20, // <space>
+ 0x21, // !
+ 0x22, // "
+ 0x23, // #
+ 0x24, // $
+ 0x25, // %
+ 0x26, // &
+ 0x27, // '
+ 0x28, // (
+ 0x29, // )
+ 0x2b, // +
+ 0x2c, // ,
+ 0x2f, // /
+ 0x3b, // ;
+ 0x3c, // <
+ 0x3d, // =
+ 0x3e, // >
+ 0x3f, // ?
+ 0x40, // @
+ 0x5b, // [
+ 0x5c, // \
+ 0x5d, // ]
+ 0x5e, // ^
+ 0x60, // `
+ 0x7b, // {
+ 0x7c, // |
+ 0x7d, // }
+ 0x7e, // ~
+ 0x7f, // 
+ 0x80, // €
+ 0x81, // 
+ 0x82, // ‚
+ 0x83, // ƒ
+ 0x84, // „
+ 0x85, // …
+ 0x86, // †
+ 0x87, // ‡
+ 0x88, // ˆ
+ 0x89, // ‰
+ 0x8a, // Š
+ 0x8b, // ‹
+ 0x8c, // Œ
+ 0x8d, // 
+ 0x8e, // Ž
+ 0x8f, // 
+ 0x90, // 
+ 0x91, // ‘
+ 0x92, // ’
+ 0x93, // “
+ 0x94, // ”
+ 0x95, // •
+ 0x96, // –
+ 0x97, // —
+ 0x98, // ˜
+ 0x99, // ™
+ 0x9a, // š
+ 0x9b, // ›
+ 0x9c, // œ
+ 0x9d, // 
+ 0x9e, // ž
+ 0x9f, // Ÿ
+ 0xa0, //  
+ 0xa1, // ¡
+ 0xa2, // ¢
+ 0xa3, // £
+ 0xa4, // ¤
+ 0xa5, // ¥
+ 0xa6, // ¦
+ 0xa7, // §
+ 0xa8, // ¨
+ 0xa9, // ©
+ 0xaa, // ª
+ 0xab, // «
+ 0xac, // ¬
+ 0xad, // ­
+ 0xae, // ®
+ 0xaf, // ¯
+ 0xb0, // °
+ 0xb1, // ±
+ 0xb2, // ²
+ 0xb3, // ³
+ 0xb4, // ´
+ 0xb5, // µ
+ 0xb6, // ¶
+ 0xb7, // ·
+ 0xb8, // ¸
+ 0xb9, // ¹
+ 0xba, // º
+ 0xbb, // »
+ 0xbc, // ¼
+ 0xbd, // ½
+ 0xbe, // ¾
+ 0xbf, // ¿
+ 0xd7, // ×
+ 0xf7, // ÷
+ 0x2c7, // ˇ
+ 0x2d8, // ˘
+ 0x2d9, // ˙
+ 0x2da, // ˚
+ 0x2db, // ˛
+ 0x2dc, // ˜
+ 0x2dd, // ˝
+ 0x300, // ̀
+ 0x301, // ́
+ 0x303, // ̃
+ 0x309, // ̉
+ 0x323, // ̣
+ 0x384, // ΄
+ 0x385, // ΅
+ 0x387, // ·
+ 0x3c6, // φ
+ 0x3d1, // ϑ
+ 0x3d2, // ϒ
+ 0x3d5, // ϕ
+ 0x3d6, // ϖ
+ 0x5b0, // ְ
+ 0x5b1, // ֱ
+ 0x5b2, // ֲ
+ 0x5b3, // ֳ
+ 0x5b4, // ִ
+ 0x5b5, // ֵ
+ 0x5b6, // ֶ
+ 0x5b7, // ַ
+ 0x5b8, // ָ
+ 0x5b9, // ֹ
+ 0x5bb, // ֻ
+ 0x5bc, // ּ
+ 0x5bd, // ֽ
+ 0x5be, // ־
+ 0x5bf, // ֿ
+ 0x5c0, // ׀
+ 0x5c1, // ׁ
+ 0x5c2, // ׂ
+ 0x5c3, // ׃
+ 0x5f3, // ׳
+ 0x5f4, // ״
+ 0x60c, // ،
+ 0x61b, // ؛
+ 0x61f, // ؟
+ 0x640, // ـ
+ 0x64b, // ً
+ 0x64c, // ٌ
+ 0x64d, // ٍ
+ 0x64e, // َ
+ 0x64f, // ُ
+ 0x650, // ِ
+ 0x651, // ّ
+ 0x652, // ْ
+ 0x66a, // ٪
+ 0xe3f, // ฿
+ 0x200c, // ‌
+ 0x200d, // ‍
+ 0x200e, // ‎
+ 0x200f, // ‏
+ 0x2013, // –
+ 0x2014, // —
+ 0x2015, // ―
+ 0x2017, // ‗
+ 0x2018, // ‘
+ 0x2019, // ’
+ 0x201a, // ‚
+ 0x201c, // “
+ 0x201d, // ”
+ 0x201e, // „
+ 0x2020, // †
+ 0x2021, // ‡
+ 0x2022, // •
+ 0x2026, // …
+ 0x2030, // ‰
+ 0x2032, // ′
+ 0x2033, // ″
+ 0x2039, // ‹
+ 0x203a, // ›
+ 0x2044, // ⁄
+ 0x20a7, // ₧
+ 0x20aa, // ₪
+ 0x20ab, // ₫
+ 0x20ac, // €
+ 0x2116, // №
+ 0x2118, // ℘
+ 0x2122, // ™
+ 0x2126, // Ω
+ 0x2135, // ℵ
+ 0x2190, // ←
+ 0x2191, // ↑
+ 0x2192, // →
+ 0x2193, // ↓
+ 0x2194, // ↔
+ 0x2195, // ↕
+ 0x21b5, // ↵
+ 0x21d0, // ⇐
+ 0x21d1, // ⇑
+ 0x21d2, // ⇒
+ 0x21d3, // ⇓
+ 0x21d4, // ⇔
+ 0x2200, // ∀
+ 0x2202, // ∂
+ 0x2203, // ∃
+ 0x2205, // ∅
+ 0x2206, // ∆
+ 0x2207, // ∇
+ 0x2208, // ∈
+ 0x2209, // ∉
+ 0x220b, // ∋
+ 0x220f, // ∏
+ 0x2211, // ∑
+ 0x2212, // −
+ 0x2215, // ∕
+ 0x2217, // ∗
+ 0x2219, // ∙
+ 0x221a, // √
+ 0x221d, // ∝
+ 0x221e, // ∞
+ 0x2220, // ∠
+ 0x2227, // ∧
+ 0x2228, // ∨
+ 0x2229, // ∩
+ 0x222a, // ∪
+ 0x222b, // ∫
+ 0x2234, // ∴
+ 0x223c, // ∼
+ 0x2245, // ≅
+ 0x2248, // ≈
+ 0x2260, // ≠
+ 0x2261, // ≡
+ 0x2264, // ≤
+ 0x2265, // ≥
+ 0x2282, // ⊂
+ 0x2283, // ⊃
+ 0x2284, // ⊄
+ 0x2286, // ⊆
+ 0x2287, // ⊇
+ 0x2295, // ⊕
+ 0x2297, // ⊗
+ 0x22a5, // ⊥
+ 0x22c5, // ⋅
+ 0x2310, // ⌐
+ 0x2320, // ⌠
+ 0x2321, // ⌡
+ 0x2329, // 〈
+ 0x232a, // 〉
+ 0x2469, // ⑩
+ 0x2500, // ─
+ 0x2502, // │
+ 0x250c, // ┌
+ 0x2510, // ┐
+ 0x2514, // └
+ 0x2518, // ┘
+ 0x251c, // ├
+ 0x2524, // ┤
+ 0x252c, // ┬
+ 0x2534, // ┴
+ 0x253c, // ┼
+ 0x2550, // ═
+ 0x2551, // ║
+ 0x2552, // ╒
+ 0x2553, // ╓
+ 0x2554, // ╔
+ 0x2555, // ╕
+ 0x2556, // ╖
+ 0x2557, // ╗
+ 0x2558, // ╘
+ 0x2559, // ╙
+ 0x255a, // ╚
+ 0x255b, // ╛
+ 0x255c, // ╜
+ 0x255d, // ╝
+ 0x255e, // ╞
+ 0x255f, // ╟
+ 0x2560, // ╠
+ 0x2561, // ╡
+ 0x2562, // ╢
+ 0x2563, // ╣
+ 0x2564, // ╤
+ 0x2565, // ╥
+ 0x2566, // ╦
+ 0x2567, // ╧
+ 0x2568, // ╨
+ 0x2569, // ╩
+ 0x256a, // ╪
+ 0x256b, // ╫
+ 0x256c, // ╬
+ 0x2580, // ▀
+ 0x2584, // ▄
+ 0x2588, // █
+ 0x258c, // ▌
+ 0x2590, // ▐
+ 0x2591, // ░
+ 0x2592, // ▒
+ 0x2593, // ▓
+ 0x25a0, // ■
+ 0x25b2, // ▲
+ 0x25bc, // ▼
+ 0x25c6, // ◆
+ 0x25ca, // ◊
+ 0x25cf, // ●
+ 0x25d7, // ◗
+ 0x2605, // ★
+ 0x260e, // ☎
+ 0x261b, // ☛
+ 0x261e, // ☞
+ 0x2660, // ♠
+ 0x2663, // ♣
+ 0x2665, // ♥
+ 0x2666, // ♦
+ 0x2701, // ✁
+ 0x2702, // ✂
+ 0x2703, // ✃
+ 0x2704, // ✄
+ 0x2706, // ✆
+ 0x2707, // ✇
+ 0x2708, // ✈
+ 0x2709, // ✉
+ 0x270c, // ✌
+ 0x270d, // ✍
+ 0x270e, // ✎
+ 0x270f, // ✏
+ 0x2710, // ✐
+ 0x2711, // ✑
+ 0x2712, // ✒
+ 0x2713, // ✓
+ 0x2714, // ✔
+ 0x2715, // ✕
+ 0x2716, // ✖
+ 0x2717, // ✗
+ 0x2718, // ✘
+ 0x2719, // ✙
+ 0x271a, // ✚
+ 0x271b, // ✛
+ 0x271c, // ✜
+ 0x271d, // ✝
+ 0x271e, // ✞
+ 0x271f, // ✟
+ 0x2720, // ✠
+ 0x2721, // ✡
+ 0x2722, // ✢
+ 0x2723, // ✣
+ 0x2724, // ✤
+ 0x2725, // ✥
+ 0x2726, // ✦
+ 0x2727, // ✧
+ 0x2729, // ✩
+ 0x272a, // ✪
+ 0x272b, // ✫
+ 0x272c, // ✬
+ 0x272d, // ✭
+ 0x272e, // ✮
+ 0x272f, // ✯
+ 0x2730, // ✰
+ 0x2731, // ✱
+ 0x2732, // ✲
+ 0x2733, // ✳
+ 0x2734, // ✴
+ 0x2735, // ✵
+ 0x2736, // ✶
+ 0x2737, // ✷
+ 0x2738, // ✸
+ 0x2739, // ✹
+ 0x273a, // ✺
+ 0x273b, // ✻
+ 0x273c, // ✼
+ 0x273d, // ✽
+ 0x273e, // ✾
+ 0x273f, // ✿
+ 0x2740, // ❀
+ 0x2741, // ❁
+ 0x2742, // ❂
+ 0x2743, // ❃
+ 0x2744, // ❄
+ 0x2745, // ❅
+ 0x2746, // ❆
+ 0x2747, // ❇
+ 0x2748, // ❈
+ 0x2749, // ❉
+ 0x274a, // ❊
+ 0x274b, // ❋
+ 0x274d, // ❍
+ 0x274f, // ❏
+ 0x2750, // ❐
+ 0x2751, // ❑
+ 0x2752, // ❒
+ 0x2756, // ❖
+ 0x2758, // ❘
+ 0x2759, // ❙
+ 0x275a, // ❚
+ 0x275b, // ❛
+ 0x275c, // ❜
+ 0x275d, // ❝
+ 0x275e, // ❞
+ 0x2761, // ❡
+ 0x2762, // ❢
+ 0x2763, // ❣
+ 0x2764, // ❤
+ 0x2765, // ❥
+ 0x2766, // ❦
+ 0x2767, // ❧
+ 0x277f, // ❿
+ 0x2789, // ➉
+ 0x2793, // ➓
+ 0x2794, // ➔
+ 0x2798, // ➘
+ 0x2799, // ➙
+ 0x279a, // ➚
+ 0x279b, // ➛
+ 0x279c, // ➜
+ 0x279d, // ➝
+ 0x279e, // ➞
+ 0x279f, // ➟
+ 0x27a0, // ➠
+ 0x27a1, // ➡
+ 0x27a2, // ➢
+ 0x27a3, // ➣
+ 0x27a4, // ➤
+ 0x27a5, // ➥
+ 0x27a6, // ➦
+ 0x27a7, // ➧
+ 0x27a8, // ➨
+ 0x27a9, // ➩
+ 0x27aa, // ➪
+ 0x27ab, // ➫
+ 0x27ac, // ➬
+ 0x27ad, // ➭
+ 0x27ae, // ➮
+ 0x27af, // ➯
+ 0x27b1, // ➱
+ 0x27b2, // ➲
+ 0x27b3, // ➳
+ 0x27b4, // ➴
+ 0x27b5, // ➵
+ 0x27b6, // ➶
+ 0x27b7, // ➷
+ 0x27b8, // ➸
+ 0x27b9, // ➹
+ 0x27ba, // ➺
+ 0x27bb, // ➻
+ 0x27bc, // ➼
+ 0x27bd, // ➽
+ 0x27be, // ➾
+ 0x3000, //  
+ 0x3001, // 、
+ 0x3002, // 。
+ 0x3003, // 〃
+ 0x3008, // 〈
+ 0x3009, // 〉
+ 0x300a, // 《
+ 0x300b, // 》
+ 0x300c, // 「
+ 0x300d, // 」
+ 0x300e, // 『
+ 0x300f, // 』
+ 0x3010, // 【
+ 0x3011, // 】
+ 0x3012, // 〒
+ 0x3014, // 〔
+ 0x3015, // 〕
+ 0x3016, // 〖
+ 0x3017, // 〗
+ 0x3018, // 〘
+ 0x3019, // 〙
+ 0x301a, // 〚
+ 0x301b, // 〛
+ 0x3036, // 〶
+ 0xf6d9, // 
+ 0xf6da, // 
+ 0xf6db, // 
+ 0xf8d7, // 
+ 0xf8d8, // 
+ 0xf8d9, // 
+ 0xf8da, // 
+ 0xf8db, // 
+ 0xf8dc, // 
+ 0xf8dd, // 
+ 0xf8de, // 
+ 0xf8df, // 
+ 0xf8e0, // 
+ 0xf8e1, // 
+ 0xf8e2, // 
+ 0xf8e3, // 
+ 0xf8e4, // 
+ 0xf8e5, // 
+ 0xf8e6, // 
+ 0xf8e7, // 
+ 0xf8e8, // 
+ 0xf8e9, // 
+ 0xf8ea, // 
+ 0xf8eb, // 
+ 0xf8ec, // 
+ 0xf8ed, // 
+ 0xf8ee, // 
+ 0xf8ef, // 
+ 0xf8f0, // 
+ 0xf8f1, // 
+ 0xf8f2, // 
+ 0xf8f3, // 
+ 0xf8f4, // 
+ 0xf8f5, // 
+ 0xf8f6, // 
+ 0xf8f7, // 
+ 0xf8f8, // 
+ 0xf8f9, // 
+ 0xf8fa, // 
+ 0xf8fb, // 
+ 0xf8fc, // 
+ 0xf8fd, // 
+ 0xf8fe, // 
+ 0xfe7c, // ﹼ
+ 0xfe7d, // ﹽ
+ 0xff01, // !
+ 0xff02, // "
+ 0xff03, // #
+ 0xff04, // $
+ 0xff05, // %
+ 0xff06, // &
+ 0xff07, // '
+ 0xff08, // (
+ 0xff09, // )
+ 0xff09, // )
+ 0xff0a, // *
+ 0xff0b, // +
+ 0xff0c, // ,
+ 0xff0d, // -
+ 0xff0e, // .
+ 0xff0f, // /
+ 0xff1a, // :
+ 0xff1b, // ;
+ 0xff1c, // <
+ 0xff1d, // =
+ 0xff1e, // >
+ 0xff1f, // ?
+ 0xff20, // @
+ 0xff3b, // [
+ 0xff3c, // \
+ 0xff3d, // ]
+ 0xff3e, // ^
+ 0xff40, // `
+ 0xff5b, // {
+ 0xff5c, // |
+ 0xff5d, // }
+ 0xff5e, // ~
+ 0xff5f, // ⦅
+ 0xff60, // ⦆
+ 0xff61, // 。
+ 0xff62, // 「
+ 0xff63, // 」
+ 0xff64, // 、
+ 0xff65, // ・
+ 0xffe0, // ¢
+ 0xffe1, // £
+ 0xffe2, // ¬
+ 0xffe3, //  ̄
+ 0xffe4, // ¦
+ 0xffe5, // ¥
+ 0xffe6, // ₩
+ 0xffe8, // │
+ 0xffe9, // ←
+ 0xffea, // ↑
+ 0xffeb, // →
+ 0xffec, // ↓
+ 0xffed, // ■
+ 0xffee, // ○
+ 0x1d6fc, // 𝛼
+ 0x1d6fd, // 𝛽
+ 0x1d6fe, // 𝛾
+ 0x1d6ff, // 𝛿
+ 0x1d700, // 𝜀
+ 0x1d701, // 𝜁
+ 0x1d702, // 𝜂
+ 0x1d703, // 𝜃
+ 0x1d704, // 𝜄
+ 0x1d705, // 𝜅
+ 0x1d706, // 𝜆
+ 0x1d707, // 𝜇
+ 0x1d708, // 𝜈
+ 0x1d709, // 𝜉
+ 0x1d70a, // 𝜊
+ 0x1d70b, // 𝜋
+ 0x1d70c, // 𝜌
+ 0x1d70d, // 𝜍
+ 0x1d70e, // 𝜎
+ 0x1d70f, // 𝜏
+ 0x1d710, // 𝜐
+ 0x1d711, // 𝜑
+ 0x1d712, // 𝜒
+ 0x1d713, // 𝜓
+ 0x1d714, // 𝜔
+ 0x1d715, // 𝜕
+ 0x1d716, // 𝜖
+ 0x1d717, // 𝜗
+ 0x1d718, // 𝜘
+ 0x1d719, // 𝜙
+ 0x1d71a, // 𝜚
+ 0x1d71b, // 𝜛
+ 0xc2a0, // 슠
+ 0xe28087, //
+ 0xe280af, //
+ 0xe281a0, //
+ 0xefbbbf, //
+];
diff --git a/inc/Utf8/tables/upperaccents.php b/inc/Utf8/tables/upperaccents.php
new file mode 100644
index 000000000..e6e48de2c
--- /dev/null
+++ b/inc/Utf8/tables/upperaccents.php
@@ -0,0 +1,114 @@
+<?php
+/**
+ * UTF-8 lookup table for upper case accented letters
+ *
+ * This lookuptable defines replacements for accented characters from the ASCII-7
+ * range. This are upper case letters only.
+ *
+ * @author Andreas Gohr <andi@splitbrain.org>
+ * @see \dokuwiki\Utf8\Clean::deaccent()
+ */
+return [
+ 'Á' => 'A',
+ 'À' => 'A',
+ 'Ă' => 'A',
+ 'Â' => 'A',
+ 'Å' => 'A',
+ 'Ä' => 'Ae',
+ 'Ã' => 'A',
+ 'Ą' => 'A',
+ 'Ā' => 'A',
+ 'Æ' => 'Ae',
+ 'Ḃ' => 'B',
+ 'Ć' => 'C',
+ 'Ĉ' => 'C',
+ 'Č' => 'C',
+ 'Ċ' => 'C',
+ 'Ç' => 'C',
+ 'Ď' => 'D',
+ 'Ḋ' => 'D',
+ 'Đ' => 'D',
+ 'Ð' => 'Dh',
+ 'É' => 'E',
+ 'È' => 'E',
+ 'Ĕ' => 'E',
+ 'Ê' => 'E',
+ 'Ě' => 'E',
+ 'Ë' => 'E',
+ 'Ė' => 'E',
+ 'Ę' => 'E',
+ 'Ē' => 'E',
+ 'Ḟ' => 'F',
+ 'Ƒ' => 'F',
+ 'Ğ' => 'G',
+ 'Ĝ' => 'G',
+ 'Ġ' => 'G',
+ 'Ģ' => 'G',
+ 'Ĥ' => 'H',
+ 'Ħ' => 'H',
+ 'Í' => 'I',
+ 'Ì' => 'I',
+ 'Î' => 'I',
+ 'Ï' => 'I',
+ 'Ĩ' => 'I',
+ 'Į' => 'I',
+ 'Ī' => 'I',
+ 'Ĵ' => 'J',
+ 'Ķ' => 'K',
+ 'Ĺ' => 'L',
+ 'Ľ' => 'L',
+ 'Ļ' => 'L',
+ 'Ł' => 'L',
+ 'Ṁ' => 'M',
+ 'Ń' => 'N',
+ 'Ň' => 'N',
+ 'Ñ' => 'N',
+ 'Ņ' => 'N',
+ 'Ó' => 'O',
+ 'Ò' => 'O',
+ 'Ô' => 'O',
+ 'Ö' => 'Oe',
+ 'Ő' => 'O',
+ 'Õ' => 'O',
+ 'Ø' => 'O',
+ 'Ō' => 'O',
+ 'Ơ' => 'O',
+ 'Ṗ' => 'P',
+ 'Ŕ' => 'R',
+ 'Ř' => 'R',
+ 'Ŗ' => 'R',
+ 'Ś' => 'S',
+ 'Ŝ' => 'S',
+ 'Š' => 'S',
+ 'Ṡ' => 'S',
+ 'Ş' => 'S',
+ 'Ș' => 'S',
+ 'Ť' => 'T',
+ 'Ṫ' => 'T',
+ 'Ţ' => 'T',
+ 'Ț' => 'T',
+ 'Ŧ' => 'T',
+ 'Ú' => 'U',
+ 'Ù' => 'U',
+ 'Ŭ' => 'U',
+ 'Û' => 'U',
+ 'Ů' => 'U',
+ 'Ü' => 'Ue',
+ 'Ű' => 'U',
+ 'Ũ' => 'U',
+ 'Ų' => 'U',
+ 'Ū' => 'U',
+ 'Ư' => 'U',
+ 'Ẃ' => 'W',
+ 'Ẁ' => 'W',
+ 'Ŵ' => 'W',
+ 'Ẅ' => 'W',
+ 'Ý' => 'Y',
+ 'Ỳ' => 'Y',
+ 'Ŷ' => 'Y',
+ 'Ÿ' => 'Y',
+ 'Ź' => 'Z',
+ 'Ž' => 'Z',
+ 'Ż' => 'Z',
+ 'Þ' => 'Th',
+];
diff --git a/inc/actions.php b/inc/actions.php
index 9ba887860..4ea529dcd 100644
--- a/inc/actions.php
+++ b/inc/actions.php
@@ -6,7 +6,7 @@
* @author Andreas Gohr <andi@splitbrain.org>
*/
-if(!defined('DOKU_INC')) die('meh.');
+use dokuwiki\Extension\Event;
/**
* All action processing starts here
@@ -16,7 +16,7 @@ function act_dispatch(){
$router = \dokuwiki\ActionRouter::getInstance(true);
$headers = array('Content-Type: text/html; charset=utf-8');
- trigger_event('ACTION_HEADERS_SEND',$headers,'act_sendheaders');
+ Event::createAndTrigger('ACTION_HEADERS_SEND',$headers,'act_sendheaders');
// clear internal variables
unset($router);
diff --git a/inc/auth.php b/inc/auth.php
index 8599891fe..3fa8d8672 100644
--- a/inc/auth.php
+++ b/inc/auth.php
@@ -9,9 +9,13 @@
* @author Andreas Gohr <andi@splitbrain.org>
*/
-if(!defined('DOKU_INC')) die('meh.');
-
// some ACL level defines
+use dokuwiki\PassHash;
+use dokuwiki\Subscriptions\RegistrationSubscriptionSender;
+use dokuwiki\Extension\AuthPlugin;
+use dokuwiki\Extension\PluginController;
+use dokuwiki\Extension\Event;
+
define('AUTH_NONE', 0);
define('AUTH_READ', 1);
define('AUTH_EDIT', 2);
@@ -34,13 +38,13 @@ define('AUTH_ADMIN', 255);
*/
function auth_setup() {
global $conf;
- /* @var DokuWiki_Auth_Plugin $auth */
+ /* @var AuthPlugin $auth */
global $auth;
/* @var Input $INPUT */
global $INPUT;
global $AUTH_ACL;
global $lang;
- /* @var Doku_Plugin_Controller $plugin_controller */
+ /* @var PluginController $plugin_controller */
global $plugin_controller;
$AUTH_ACL = array();
@@ -106,7 +110,7 @@ function auth_setup() {
'sticky' => $INPUT->bool('r'),
'silent' => $INPUT->bool('http_credentials')
);
- trigger_event('AUTH_LOGIN_CHECK', $evdata, 'auth_login_wrapper');
+ Event::createAndTrigger('AUTH_LOGIN_CHECK', $evdata, 'auth_login_wrapper');
}
//load ACL into a global array XXX
@@ -211,7 +215,7 @@ function auth_login($user, $pass, $sticky = false, $silent = false) {
global $USERINFO;
global $conf;
global $lang;
- /* @var DokuWiki_Auth_Plugin $auth */
+ /* @var AuthPlugin $auth */
global $auth;
/* @var Input $INPUT */
global $INPUT;
@@ -407,7 +411,7 @@ function auth_decrypt($ciphertext, $secret) {
function auth_logoff($keepbc = false) {
global $conf;
global $USERINFO;
- /* @var DokuWiki_Auth_Plugin $auth */
+ /* @var AuthPlugin $auth */
global $auth;
/* @var Input $INPUT */
global $INPUT;
@@ -451,7 +455,7 @@ function auth_logoff($keepbc = false) {
function auth_ismanager($user = null, $groups = null, $adminonly = false) {
global $conf;
global $USERINFO;
- /* @var DokuWiki_Auth_Plugin $auth */
+ /* @var AuthPlugin $auth */
global $auth;
/* @var Input $INPUT */
global $INPUT;
@@ -508,13 +512,13 @@ function auth_isadmin($user = null, $groups = null) {
* @return bool true for membership acknowledged
*/
function auth_isMember($memberlist, $user, array $groups) {
- /* @var DokuWiki_Auth_Plugin $auth */
+ /* @var AuthPlugin $auth */
global $auth;
if(!$auth) return false;
// clean user and groups
if(!$auth->isCaseSensitive()) {
- $user = utf8_strtolower($user);
+ $user = \dokuwiki\Utf8\PhpString::strtolower($user);
$groups = array_map('utf8_strtolower', $groups);
}
$user = $auth->cleanUser($user);
@@ -529,7 +533,7 @@ function auth_isMember($memberlist, $user, array $groups) {
// compare cleaned values
foreach($members as $member) {
if($member == '@ALL' ) return true;
- if(!$auth->isCaseSensitive()) $member = utf8_strtolower($member);
+ if(!$auth->isCaseSensitive()) $member = \dokuwiki\Utf8\PhpString::strtolower($member);
if($member[0] == '@') {
$member = $auth->cleanGroup(substr($member, 1));
if(in_array($member, $groups)) return true;
@@ -581,7 +585,7 @@ function auth_aclcheck($id, $user, $groups) {
'groups' => $groups
);
- return trigger_event('AUTH_ACL_CHECK', $data, 'auth_aclcheck_cb');
+ return Event::createAndTrigger('AUTH_ACL_CHECK', $data, 'auth_aclcheck_cb');
}
/**
@@ -601,7 +605,7 @@ function auth_aclcheck_cb($data) {
global $conf;
global $AUTH_ACL;
- /* @var DokuWiki_Auth_Plugin $auth */
+ /* @var AuthPlugin $auth */
global $auth;
// if no ACL is used always return upload rights
@@ -617,7 +621,7 @@ function auth_aclcheck_cb($data) {
}
if(!$auth->isCaseSensitive()) {
- $user = utf8_strtolower($user);
+ $user = \dokuwiki\Utf8\PhpString::strtolower($user);
$groups = array_map('utf8_strtolower', $groups);
}
$user = auth_nameencode($auth->cleanUser($user));
@@ -644,7 +648,7 @@ function auth_aclcheck_cb($data) {
$match = preg_replace('/#.*$/', '', $match); //ignore comments
$acl = preg_split('/[ \t]+/', $match);
if(!$auth->isCaseSensitive() && $acl[1] !== '@ALL') {
- $acl[1] = utf8_strtolower($acl[1]);
+ $acl[1] = \dokuwiki\Utf8\PhpString::strtolower($acl[1]);
}
if(!in_array($acl[1], $groups)) {
continue;
@@ -674,7 +678,7 @@ function auth_aclcheck_cb($data) {
$match = preg_replace('/#.*$/', '', $match); //ignore comments
$acl = preg_split('/[ \t]+/', $match);
if(!$auth->isCaseSensitive() && $acl[1] !== '@ALL') {
- $acl[1] = utf8_strtolower($acl[1]);
+ $acl[1] = \dokuwiki\Utf8\PhpString::strtolower($acl[1]);
}
if(!in_array($acl[1], $groups)) {
continue;
@@ -778,7 +782,7 @@ function auth_pwgen($foruser = '') {
'foruser' => $foruser
);
- $evt = new Doku_Event('AUTH_PASSWORD_GENERATE', $data);
+ $evt = new Event('AUTH_PASSWORD_GENERATE', $data);
if($evt->advise_before(true)) {
$c = 'bcdfghjklmnprstvwz'; //consonants except hard to speak ones
$v = 'aeiou'; //vowels
@@ -810,7 +814,7 @@ function auth_pwgen($foruser = '') {
*/
function auth_sendPassword($user, $password) {
global $lang;
- /* @var DokuWiki_Auth_Plugin $auth */
+ /* @var AuthPlugin $auth */
global $auth;
if(!$auth) return false;
@@ -845,7 +849,7 @@ function auth_sendPassword($user, $password) {
function register() {
global $lang;
global $conf;
- /* @var DokuWiki_Auth_Plugin $auth */
+ /* @var \dokuwiki\Extension\AuthPlugin $auth */
global $auth;
global $INPUT;
@@ -887,8 +891,8 @@ function register() {
}
// send notification about the new user
- $subscription = new Subscription();
- $subscription->send_register($login, $fullname, $email);
+ $subscription = new RegistrationSubscriptionSender();
+ $subscription->sendRegister($login, $fullname, $email);
// are we done?
if(!$conf['autopasswd']) {
@@ -914,7 +918,7 @@ function register() {
function updateprofile() {
global $conf;
global $lang;
- /* @var DokuWiki_Auth_Plugin $auth */
+ /* @var AuthPlugin $auth */
global $auth;
/* @var Input $INPUT */
global $INPUT;
@@ -1003,7 +1007,7 @@ function updateprofile() {
function auth_deleteprofile(){
global $conf;
global $lang;
- /* @var DokuWiki_Auth_Plugin $auth */
+ /* @var \dokuwiki\Extension\AuthPlugin $auth */
global $auth;
/* @var Input $INPUT */
global $INPUT;
@@ -1057,7 +1061,7 @@ function auth_deleteprofile(){
function act_resendpwd() {
global $lang;
global $conf;
- /* @var DokuWiki_Auth_Plugin $auth */
+ /* @var AuthPlugin $auth */
global $auth;
/* @var Input $INPUT */
global $INPUT;
@@ -1225,7 +1229,7 @@ function auth_verifyPassword($clear, $crypt) {
*/
function auth_setCookie($user, $pass, $sticky) {
global $conf;
- /* @var DokuWiki_Auth_Plugin $auth */
+ /* @var AuthPlugin $auth */
global $auth;
global $USERINFO;
diff --git a/inc/cache.php b/inc/cache.php
index 8589d91ba..b5793c263 100644
--- a/inc/cache.php
+++ b/inc/cache.php
@@ -1,337 +1,57 @@
<?php
-/**
- * Generic class to handle caching
- *
- * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
- * @author Chris Smith <chris@jalakai.co.uk>
- */
-
-if(!defined('DOKU_INC')) die('meh.');
+// phpcs:ignoreFile
+use dokuwiki\Cache\CacheParser;
+use dokuwiki\Cache\CacheInstructions;
+use dokuwiki\Cache\CacheRenderer;
+use dokuwiki\Debug\DebugHelper;
/**
- * Generic handling of caching
+ * @deprecated since 2019-02-02 use \dokuwiki\Cache\Cache instead!
*/
-class cache {
- public $key = ''; // primary identifier for this item
- public $ext = ''; // file ext for cache data, secondary identifier for this item
- public $cache = ''; // cache file name
- public $depends = array(); // array containing cache dependency information,
- // used by _useCache to determine cache validity
-
- public $_event = ''; // event to be triggered during useCache
- public $_time;
- public $_nocache = false; // if set to true, cache will not be used or stored
-
- /**
- * @param string $key primary identifier
- * @param string $ext file extension
- */
- public function __construct($key,$ext) {
- $this->key = $key;
- $this->ext = $ext;
- $this->cache = getCacheName($key,$ext);
- }
-
- /**
- * public method to determine whether the cache can be used
- *
- * to assist in centralisation of event triggering and calculation of cache statistics,
- * don't override this function override _useCache()
- *
- * @param array $depends array of cache dependencies, support dependecies:
- * 'age' => max age of the cache in seconds
- * 'files' => cache must be younger than mtime of each file
- * (nb. dependency passes if file doesn't exist)
- *
- * @return bool true if cache can be used, false otherwise
- */
- public function useCache($depends=array()) {
- $this->depends = $depends;
- $this->_addDependencies();
-
- if ($this->_event) {
- return $this->_stats(trigger_event($this->_event, $this, array($this,'_useCache')));
- } else {
- return $this->_stats($this->_useCache());
- }
- }
-
- /**
- * private method containing cache use decision logic
- *
- * this function processes the following keys in the depends array
- * purge - force a purge on any non empty value
- * age - expire cache if older than age (seconds)
- * files - expire cache if any file in this array was updated more recently than the cache
- *
- * Note that this function needs to be public as it is used as callback for the event handler
- *
- * can be overridden
- *
- * @return bool see useCache()
- */
- public function _useCache() {
-
- if ($this->_nocache) return false; // caching turned off
- if (!empty($this->depends['purge'])) return false; // purge requested?
- if (!($this->_time = @filemtime($this->cache))) return false; // cache exists?
-
- // cache too old?
- if (!empty($this->depends['age']) && ((time() - $this->_time) > $this->depends['age'])) return false;
-
- if (!empty($this->depends['files'])) {
- foreach ($this->depends['files'] as $file) {
- if ($this->_time <= @filemtime($file)) return false; // cache older than files it depends on?
- }
- }
-
- return true;
- }
-
- /**
- * add dependencies to the depends array
- *
- * this method should only add dependencies,
- * it should not remove any existing dependencies and
- * it should only overwrite a dependency when the new value is more stringent than the old
- */
- protected function _addDependencies() {
- global $INPUT;
- if ($INPUT->has('purge')) $this->depends['purge'] = true; // purge requested
- }
-
- /**
- * retrieve the cached data
- *
- * @param bool $clean true to clean line endings, false to leave line endings alone
- * @return string cache contents
- */
- public function retrieveCache($clean=true) {
- return io_readFile($this->cache, $clean);
- }
-
- /**
- * cache $data
- *
- * @param string $data the data to be cached
- * @return bool true on success, false otherwise
- */
- public function storeCache($data) {
- if ($this->_nocache) return false;
-
- return io_savefile($this->cache, $data);
- }
-
- /**
- * remove any cached data associated with this cache instance
- */
- public function removeCache() {
- @unlink($this->cache);
- }
-
- /**
- * Record cache hits statistics.
- * (Only when debugging allowed, to reduce overhead.)
- *
- * @param bool $success result of this cache use attempt
- * @return bool pass-thru $success value
- */
- protected function _stats($success) {
- global $conf;
- static $stats = null;
- static $file;
-
- if (!$conf['allowdebug']) { return $success; }
-
- if (is_null($stats)) {
- $file = $conf['cachedir'].'/cache_stats.txt';
- $lines = explode("\n",io_readFile($file));
-
- foreach ($lines as $line) {
- $i = strpos($line,',');
- $stats[substr($line,0,$i)] = $line;
- }
- }
-
- if (isset($stats[$this->ext])) {
- list($ext,$count,$hits) = explode(',',$stats[$this->ext]);
- } else {
- $ext = $this->ext;
- $count = 0;
- $hits = 0;
- }
-
- $count++;
- if ($success) $hits++;
- $stats[$this->ext] = "$ext,$count,$hits";
-
- io_saveFile($file,join("\n",$stats));
-
- return $success;
+class cache extends \dokuwiki\Cache\Cache
+{
+ public function __construct($key, $ext)
+ {
+ DebugHelper::dbgDeprecatedFunction(dokuwiki\Cache\Cache::class);
+ parent::__construct($key, $ext);
}
}
/**
- * Parser caching
+ * @deprecated since 2019-02-02 use \dokuwiki\Cache\CacheParser instead!
*/
-class cache_parser extends cache {
+class cache_parser extends \dokuwiki\Cache\CacheParser
+{
- public $file = ''; // source file for cache
- public $mode = ''; // input mode (represents the processing the input file will undergo)
- public $page = '';
-
- public $_event = 'PARSER_CACHE_USE';
-
- /**
- *
- * @param string $id page id
- * @param string $file source file for cache
- * @param string $mode input mode
- */
- public function __construct($id, $file, $mode) {
- if ($id) $this->page = $id;
- $this->file = $file;
- $this->mode = $mode;
-
- parent::__construct($file.$_SERVER['HTTP_HOST'].$_SERVER['SERVER_PORT'],'.'.$mode);
- }
-
- /**
- * method contains cache use decision logic
- *
- * @return bool see useCache()
- */
- public function _useCache() {
-
- if (!file_exists($this->file)) return false; // source exists?
- return parent::_useCache();
- }
-
- protected function _addDependencies() {
-
- // parser cache file dependencies ...
- $files = array($this->file, // ... source
- DOKU_INC.'inc/parser/parser.php', // ... parser
- DOKU_INC.'inc/parser/handler.php', // ... handler
- );
- $files = array_merge($files, getConfigFiles('main')); // ... wiki settings
-
- $this->depends['files'] = !empty($this->depends['files']) ? array_merge($files, $this->depends['files']) : $files;
- parent::_addDependencies();
+ public function __construct($id, $file, $mode)
+ {
+ DebugHelper::dbgDeprecatedFunction(CacheParser::class);
+ parent::__construct($id, $file, $mode);
}
}
/**
- * Caching of data of renderer
+ * @deprecated since 2019-02-02 use \dokuwiki\Cache\CacheRenderer instead!
*/
-class cache_renderer extends cache_parser {
-
- /**
- * method contains cache use decision logic
- *
- * @return bool see useCache()
- */
- public function _useCache() {
- global $conf;
-
- if (!parent::_useCache()) return false;
-
- if (!isset($this->page)) {
- return true;
- }
-
- if ($this->_time < @filemtime(metaFN($this->page,'.meta'))) return false; // meta cache older than file it depends on?
-
- // check current link existence is consistent with cache version
- // first check the purgefile
- // - if the cache is more recent than the purgefile we know no links can have been updated
- if ($this->_time >= @filemtime($conf['cachedir'].'/purgefile')) {
- return true;
- }
-
- // for wiki pages, check metadata dependencies
- $metadata = p_get_metadata($this->page);
+class cache_renderer extends \dokuwiki\Cache\CacheRenderer
+{
- if (!isset($metadata['relation']['references']) ||
- empty($metadata['relation']['references'])) {
- return true;
- }
-
- foreach ($metadata['relation']['references'] as $id => $exists) {
- if ($exists != page_exists($id,'',false)) return false;
- }
-
- return true;
- }
-
- protected function _addDependencies() {
- global $conf;
-
- // default renderer cache file 'age' is dependent on 'cachetime' setting, two special values:
- // -1 : do not cache (should not be overridden)
- // 0 : cache never expires (can be overridden) - no need to set depends['age']
- if ($conf['cachetime'] == -1) {
- $this->_nocache = true;
- return;
- } elseif ($conf['cachetime'] > 0) {
- $this->depends['age'] = isset($this->depends['age']) ?
- min($this->depends['age'],$conf['cachetime']) : $conf['cachetime'];
- }
-
- // renderer cache file dependencies ...
- $files = array(
- DOKU_INC.'inc/parser/'.$this->mode.'.php', // ... the renderer
- );
-
- // page implies metadata and possibly some other dependencies
- if (isset($this->page)) {
-
- $valid = p_get_metadata($this->page, 'date valid'); // for xhtml this will render the metadata if needed
- if (!empty($valid['age'])) {
- $this->depends['age'] = isset($this->depends['age']) ?
- min($this->depends['age'],$valid['age']) : $valid['age'];
- }
- }
-
- $this->depends['files'] = !empty($this->depends['files']) ? array_merge($files, $this->depends['files']) : $files;
- parent::_addDependencies();
+ public function __construct($id, $file, $mode)
+ {
+ DebugHelper::dbgDeprecatedFunction(CacheRenderer::class);
+ parent::__construct($id, $file, $mode);
}
}
/**
- * Caching of parser instructions
+ * @deprecated since 2019-02-02 use \dokuwiki\Cache\CacheInstructions instead!
*/
-class cache_instructions extends cache_parser {
-
- /**
- * @param string $id page id
- * @param string $file source file for cache
- */
- public function __construct($id, $file) {
- parent::__construct($id, $file, 'i');
- }
-
- /**
- * retrieve the cached data
- *
- * @param bool $clean true to clean line endings, false to leave line endings alone
- * @return array cache contents
- */
- public function retrieveCache($clean=true) {
- $contents = io_readFile($this->cache, false);
- return !empty($contents) ? unserialize($contents) : array();
- }
-
- /**
- * cache $instructions
- *
- * @param array $instructions the instruction to be cached
- * @return bool true on success, false otherwise
- */
- public function storeCache($instructions) {
- if ($this->_nocache) return false;
-
- return io_savefile($this->cache,serialize($instructions));
+class cache_instructions extends \dokuwiki\Cache\CacheInstructions
+{
+ public function __construct($id, $file)
+ {
+ DebugHelper::dbgDeprecatedFunction(CacheInstructions::class);
+ parent::__construct($id, $file);
}
}
diff --git a/inc/changelog.php b/inc/changelog.php
index b70945b1c..60c49c2ee 100644
--- a/inc/changelog.php
+++ b/inc/changelog.php
@@ -93,7 +93,7 @@ function addLogEntry($date, $id, $type=DOKU_CHANGE_TYPE_EDIT, $summary='', $extr
'type' => str_replace($strip, '', $type),
'id' => $id,
'user' => $user,
- 'sum' => utf8_substr(str_replace($strip, '', $summary), 0, 255),
+ 'sum' => \dokuwiki\Utf8\PhpString::substr(str_replace($strip, '', $summary), 0, 255),
'extra' => str_replace($strip, '', $extra),
'sizechange' => $sizechange
);
@@ -104,13 +104,15 @@ function addLogEntry($date, $id, $type=DOKU_CHANGE_TYPE_EDIT, $summary='', $extr
if (!$wasRemoved) {
$oldmeta = p_read_metadata($id);
$meta = array();
- if ($wasCreated && empty($oldmeta['persistent']['date']['created'])){ // newly created
+ if ($wasCreated && empty($oldmeta['persistent']['date']['created'])){
+ // newly created
$meta['date']['created'] = $created;
if ($user){
$meta['creator'] = $INFO['userinfo']['name'];
$meta['user'] = $user;
}
- } elseif (($wasCreated || $wasReverted) && !empty($oldmeta['persistent']['date']['created'])) { // re-created / restored
+ } elseif (($wasCreated || $wasReverted) && !empty($oldmeta['persistent']['date']['created'])) {
+ // re-created / restored
$meta['date']['created'] = $oldmeta['persistent']['date']['created'];
$meta['date']['modified'] = $created; // use the files ctime here
$meta['creator'] = $oldmeta['persistent']['creator'];
@@ -147,7 +149,15 @@ function addLogEntry($date, $id, $type=DOKU_CHANGE_TYPE_EDIT, $summary='', $extr
* - (none, so far)
* @param null|int $sizechange Change of filesize
*/
-function addMediaLogEntry($date, $id, $type=DOKU_CHANGE_TYPE_EDIT, $summary='', $extra='', $flags=null, $sizechange = null){
+function addMediaLogEntry(
+ $date,
+ $id,
+ $type=DOKU_CHANGE_TYPE_EDIT,
+ $summary='',
+ $extra='',
+ $flags=null,
+ $sizechange = null)
+{
global $conf;
/** @var Input $INPUT */
global $INPUT;
@@ -170,7 +180,7 @@ function addMediaLogEntry($date, $id, $type=DOKU_CHANGE_TYPE_EDIT, $summary='',
'type' => str_replace($strip, '', $type),
'id' => $id,
'user' => $user,
- 'sum' => utf8_substr(str_replace($strip, '', $summary), 0, 255),
+ 'sum' => \dokuwiki\Utf8\PhpString::substr(str_replace($strip, '', $summary), 0, 255),
'extra' => str_replace($strip, '', $extra),
'sizechange' => $sizechange
);
@@ -244,7 +254,12 @@ function getRecents($first,$num,$ns='',$flags=0){
}
}
if (($flags & RECENTS_MEDIA_PAGES_MIXED) && empty($media_rec) && $media_lines_position >= 0) {
- $media_rec = _handleRecent(@$media_lines[$media_lines_position], $ns, $flags | RECENTS_MEDIA_CHANGES, $seen);
+ $media_rec = _handleRecent(
+ @$media_lines[$media_lines_position],
+ $ns,
+ $flags | RECENTS_MEDIA_CHANGES,
+ $seen
+ );
if (!$media_rec) {
$media_lines_position --;
continue;
@@ -384,691 +399,3 @@ function _handleRecent($line,$ns,$flags,&$seen){
return $recent;
}
-
-/**
- * Class ChangeLog
- * methods for handling of changelog of pages or media files
- */
-abstract class ChangeLog {
-
- /** @var string */
- protected $id;
- /** @var int */
- protected $chunk_size;
- /** @var array */
- protected $cache;
-
- /**
- * Constructor
- *
- * @param string $id page id
- * @param int $chunk_size maximum block size read from file
- */
- public function __construct($id, $chunk_size = 8192) {
- global $cache_revinfo;
-
- $this->cache =& $cache_revinfo;
- if(!isset($this->cache[$id])) {
- $this->cache[$id] = array();
- }
-
- $this->id = $id;
- $this->setChunkSize($chunk_size);
-
- }
-
- /**
- * Set chunk size for file reading
- * Chunk size zero let read whole file at once
- *
- * @param int $chunk_size maximum block size read from file
- */
- public function setChunkSize($chunk_size) {
- if(!is_numeric($chunk_size)) $chunk_size = 0;
-
- $this->chunk_size = (int) max($chunk_size, 0);
- }
-
- /**
- * Returns path to changelog
- *
- * @return string path to file
- */
- abstract protected function getChangelogFilename();
-
- /**
- * Returns path to current page/media
- *
- * @return string path to file
- */
- abstract protected function getFilename();
-
- /**
- * Get the changelog information for a specific page id and revision (timestamp)
- *
- * Adjacent changelog lines are optimistically parsed and cached to speed up
- * consecutive calls to getRevisionInfo. For large changelog files, only the chunk
- * containing the requested changelog line is read.
- *
- * @param int $rev revision timestamp
- * @return bool|array false or array with entries:
- * - date: unix timestamp
- * - ip: IPv4 address (127.0.0.1)
- * - type: log line type
- * - id: page id
- * - user: user name
- * - sum: edit summary (or action reason)
- * - extra: extra data (varies by line type)
- *
- * @author Ben Coburn <btcoburn@silicodon.net>
- * @author Kate Arzamastseva <pshns@ukr.net>
- */
- public function getRevisionInfo($rev) {
- $rev = max($rev, 0);
-
- // check if it's already in the memory cache
- if(isset($this->cache[$this->id]) && isset($this->cache[$this->id][$rev])) {
- return $this->cache[$this->id][$rev];
- }
-
- //read lines from changelog
- list($fp, $lines) = $this->readloglines($rev);
- if($fp) {
- fclose($fp);
- }
- if(empty($lines)) return false;
-
- // parse and cache changelog lines
- foreach($lines as $value) {
- $tmp = parseChangelogLine($value);
- if($tmp !== false) {
- $this->cache[$this->id][$tmp['date']] = $tmp;
- }
- }
- if(!isset($this->cache[$this->id][$rev])) {
- return false;
- }
- return $this->cache[$this->id][$rev];
- }
-
- /**
- * Return a list of page revisions numbers
- *
- * Does not guarantee that the revision exists in the attic,
- * only that a line with the date exists in the changelog.
- * By default the current revision is skipped.
- *
- * The current revision is automatically skipped when the page exists.
- * See $INFO['meta']['last_change'] for the current revision.
- * A negative $first let read the current revision too.
- *
- * For efficiency, the log lines are parsed and cached for later
- * calls to getRevisionInfo. Large changelog files are read
- * backwards in chunks until the requested number of changelog
- * lines are recieved.
- *
- * @param int $first skip the first n changelog lines
- * @param int $num number of revisions to return
- * @return array with the revision timestamps
- *
- * @author Ben Coburn <btcoburn@silicodon.net>
- * @author Kate Arzamastseva <pshns@ukr.net>
- */
- public function getRevisions($first, $num) {
- $revs = array();
- $lines = array();
- $count = 0;
-
- $num = max($num, 0);
- if($num == 0) {
- return $revs;
- }
-
- if($first < 0) {
- $first = 0;
- } else if(file_exists($this->getFilename())) {
- // skip current revision if the page exists
- $first = max($first + 1, 0);
- }
-
- $file = $this->getChangelogFilename();
-
- if(!file_exists($file)) {
- return $revs;
- }
- if(filesize($file) < $this->chunk_size || $this->chunk_size == 0) {
- // read whole file
- $lines = file($file);
- if($lines === false) {
- return $revs;
- }
- } else {
- // read chunks backwards
- $fp = fopen($file, 'rb'); // "file pointer"
- if($fp === false) {
- return $revs;
- }
- fseek($fp, 0, SEEK_END);
- $tail = ftell($fp);
-
- // chunk backwards
- $finger = max($tail - $this->chunk_size, 0);
- while($count < $num + $first) {
- $nl = $this->getNewlinepointer($fp, $finger);
-
- // was the chunk big enough? if not, take another bite
- if($nl > 0 && $tail <= $nl) {
- $finger = max($finger - $this->chunk_size, 0);
- continue;
- } else {
- $finger = $nl;
- }
-
- // read chunk
- $chunk = '';
- $read_size = max($tail - $finger, 0); // found chunk size
- $got = 0;
- while($got < $read_size && !feof($fp)) {
- $tmp = @fread($fp, max(min($this->chunk_size, $read_size - $got), 0));
- if($tmp === false) {
- break;
- } //error state
- $got += strlen($tmp);
- $chunk .= $tmp;
- }
- $tmp = explode("\n", $chunk);
- array_pop($tmp); // remove trailing newline
-
- // combine with previous chunk
- $count += count($tmp);
- $lines = array_merge($tmp, $lines);
-
- // next chunk
- if($finger == 0) {
- break;
- } // already read all the lines
- else {
- $tail = $finger;
- $finger = max($tail - $this->chunk_size, 0);
- }
- }
- fclose($fp);
- }
-
- // skip parsing extra lines
- $num = max(min(count($lines) - $first, $num), 0);
- if ($first > 0 && $num > 0) { $lines = array_slice($lines, max(count($lines) - $first - $num, 0), $num); }
- else if($first > 0 && $num == 0) { $lines = array_slice($lines, 0, max(count($lines) - $first, 0)); }
- else if($first == 0 && $num > 0) { $lines = array_slice($lines, max(count($lines) - $num, 0)); }
-
- // handle lines in reverse order
- for($i = count($lines) - 1; $i >= 0; $i--) {
- $tmp = parseChangelogLine($lines[$i]);
- if($tmp !== false) {
- $this->cache[$this->id][$tmp['date']] = $tmp;
- $revs[] = $tmp['date'];
- }
- }
-
- return $revs;
- }
-
- /**
- * Get the nth revision left or right handside for a specific page id and revision (timestamp)
- *
- * For large changelog files, only the chunk containing the
- * reference revision $rev is read and sometimes a next chunck.
- *
- * Adjacent changelog lines are optimistically parsed and cached to speed up
- * consecutive calls to getRevisionInfo.
- *
- * @param int $rev revision timestamp used as startdate (doesn't need to be revisionnumber)
- * @param int $direction give position of returned revision with respect to $rev; positive=next, negative=prev
- * @return bool|int
- * timestamp of the requested revision
- * otherwise false
- */
- public function getRelativeRevision($rev, $direction) {
- $rev = max($rev, 0);
- $direction = (int) $direction;
-
- //no direction given or last rev, so no follow-up
- if(!$direction || ($direction > 0 && $this->isCurrentRevision($rev))) {
- return false;
- }
-
- //get lines from changelog
- list($fp, $lines, $head, $tail, $eof) = $this->readloglines($rev);
- if(empty($lines)) return false;
-
- // look for revisions later/earlier then $rev, when founded count till the wanted revision is reached
- // also parse and cache changelog lines for getRevisionInfo().
- $revcounter = 0;
- $relativerev = false;
- $checkotherchunck = true; //always runs once
- while(!$relativerev && $checkotherchunck) {
- $tmp = array();
- //parse in normal or reverse order
- $count = count($lines);
- if($direction > 0) {
- $start = 0;
- $step = 1;
- } else {
- $start = $count - 1;
- $step = -1;
- }
- for($i = $start; $i >= 0 && $i < $count; $i = $i + $step) {
- $tmp = parseChangelogLine($lines[$i]);
- if($tmp !== false) {
- $this->cache[$this->id][$tmp['date']] = $tmp;
- //look for revs older/earlier then reference $rev and select $direction-th one
- if(($direction > 0 && $tmp['date'] > $rev) || ($direction < 0 && $tmp['date'] < $rev)) {
- $revcounter++;
- if($revcounter == abs($direction)) {
- $relativerev = $tmp['date'];
- }
- }
- }
- }
-
- //true when $rev is found, but not the wanted follow-up.
- $checkotherchunck = $fp
- && ($tmp['date'] == $rev || ($revcounter > 0 && !$relativerev))
- && !(($tail == $eof && $direction > 0) || ($head == 0 && $direction < 0));
-
- if($checkotherchunck) {
- list($lines, $head, $tail) = $this->readAdjacentChunk($fp, $head, $tail, $direction);
-
- if(empty($lines)) break;
- }
- }
- if($fp) {
- fclose($fp);
- }
-
- return $relativerev;
- }
-
- /**
- * Returns revisions around rev1 and rev2
- * When available it returns $max entries for each revision
- *
- * @param int $rev1 oldest revision timestamp
- * @param int $rev2 newest revision timestamp (0 looks up last revision)
- * @param int $max maximum number of revisions returned
- * @return array with two arrays with revisions surrounding rev1 respectively rev2
- */
- public function getRevisionsAround($rev1, $rev2, $max = 50) {
- $max = floor(abs($max) / 2)*2 + 1;
- $rev1 = max($rev1, 0);
- $rev2 = max($rev2, 0);
-
- if($rev2) {
- if($rev2 < $rev1) {
- $rev = $rev2;
- $rev2 = $rev1;
- $rev1 = $rev;
- }
- } else {
- //empty right side means a removed page. Look up last revision.
- $revs = $this->getRevisions(-1, 1);
- $rev2 = $revs[0];
- }
- //collect revisions around rev2
- list($revs2, $allrevs, $fp, $lines, $head, $tail) = $this->retrieveRevisionsAround($rev2, $max);
-
- if(empty($revs2)) return array(array(), array());
-
- //collect revisions around rev1
- $index = array_search($rev1, $allrevs);
- if($index === false) {
- //no overlapping revisions
- list($revs1,,,,,) = $this->retrieveRevisionsAround($rev1, $max);
- if(empty($revs1)) $revs1 = array();
- } else {
- //revisions overlaps, reuse revisions around rev2
- $revs1 = $allrevs;
- while($head > 0) {
- for($i = count($lines) - 1; $i >= 0; $i--) {
- $tmp = parseChangelogLine($lines[$i]);
- if($tmp !== false) {
- $this->cache[$this->id][$tmp['date']] = $tmp;
- $revs1[] = $tmp['date'];
- $index++;
-
- if($index > floor($max / 2)) break 2;
- }
- }
-
- list($lines, $head, $tail) = $this->readAdjacentChunk($fp, $head, $tail, -1);
- }
- sort($revs1);
- //return wanted selection
- $revs1 = array_slice($revs1, max($index - floor($max/2), 0), $max);
- }
-
- return array(array_reverse($revs1), array_reverse($revs2));
- }
-
- /**
- * Checks if the ID has old revisons
- * @return boolean
- */
- public function hasRevisions() {
- $file = $this->getChangelogFilename();
- return file_exists($file);
- }
-
- /**
- * Returns lines from changelog.
- * If file larger than $chuncksize, only chunck is read that could contain $rev.
- *
- * @param int $rev revision timestamp
- * @return array|false
- * if success returns array(fp, array(changeloglines), $head, $tail, $eof)
- * where fp only defined for chuck reading, needs closing.
- * otherwise false
- */
- protected function readloglines($rev) {
- $file = $this->getChangelogFilename();
-
- if(!file_exists($file)) {
- return false;
- }
-
- $fp = null;
- $head = 0;
- $tail = 0;
- $eof = 0;
-
- if(filesize($file) < $this->chunk_size || $this->chunk_size == 0) {
- // read whole file
- $lines = file($file);
- if($lines === false) {
- return false;
- }
- } else {
- // read by chunk
- $fp = fopen($file, 'rb'); // "file pointer"
- if($fp === false) {
- return false;
- }
- $head = 0;
- fseek($fp, 0, SEEK_END);
- $eof = ftell($fp);
- $tail = $eof;
-
- // find chunk
- while($tail - $head > $this->chunk_size) {
- $finger = $head + floor(($tail - $head) / 2.0);
- $finger = $this->getNewlinepointer($fp, $finger);
- $tmp = fgets($fp);
- if($finger == $head || $finger == $tail) {
- break;
- }
- $tmp = parseChangelogLine($tmp);
- $finger_rev = $tmp['date'];
-
- if($finger_rev > $rev) {
- $tail = $finger;
- } else {
- $head = $finger;
- }
- }
-
- if($tail - $head < 1) {
- // cound not find chunk, assume requested rev is missing
- fclose($fp);
- return false;
- }
-
- $lines = $this->readChunk($fp, $head, $tail);
- }
- return array(
- $fp,
- $lines,
- $head,
- $tail,
- $eof
- );
- }
-
- /**
- * Read chunk and return array with lines of given chunck.
- * Has no check if $head and $tail are really at a new line
- *
- * @param resource $fp resource filepointer
- * @param int $head start point chunck
- * @param int $tail end point chunck
- * @return array lines read from chunck
- */
- protected function readChunk($fp, $head, $tail) {
- $chunk = '';
- $chunk_size = max($tail - $head, 0); // found chunk size
- $got = 0;
- fseek($fp, $head);
- while($got < $chunk_size && !feof($fp)) {
- $tmp = @fread($fp, max(min($this->chunk_size, $chunk_size - $got), 0));
- if($tmp === false) { //error state
- break;
- }
- $got += strlen($tmp);
- $chunk .= $tmp;
- }
- $lines = explode("\n", $chunk);
- array_pop($lines); // remove trailing newline
- return $lines;
- }
-
- /**
- * Set pointer to first new line after $finger and return its position
- *
- * @param resource $fp filepointer
- * @param int $finger a pointer
- * @return int pointer
- */
- protected function getNewlinepointer($fp, $finger) {
- fseek($fp, $finger);
- $nl = $finger;
- if($finger > 0) {
- fgets($fp); // slip the finger forward to a new line
- $nl = ftell($fp);
- }
- return $nl;
- }
-
- /**
- * Check whether given revision is the current page
- *
- * @param int $rev timestamp of current page
- * @return bool true if $rev is current revision, otherwise false
- */
- public function isCurrentRevision($rev) {
- return $rev == @filemtime($this->getFilename());
- }
-
- /**
- * Return an existing revision for a specific date which is
- * the current one or younger or equal then the date
- *
- * @param number $date_at timestamp
- * @return string revision ('' for current)
- */
- function getLastRevisionAt($date_at){
- //requested date_at(timestamp) younger or equal then modified_time($this->id) => load current
- if(file_exists($this->getFilename()) && $date_at >= @filemtime($this->getFilename())) {
- return '';
- } else if ($rev = $this->getRelativeRevision($date_at+1, -1)) { //+1 to get also the requested date revision
- return $rev;
- } else {
- return false;
- }
- }
-
- /**
- * Returns the next lines of the changelog of the chunck before head or after tail
- *
- * @param resource $fp filepointer
- * @param int $head position head of last chunk
- * @param int $tail position tail of last chunk
- * @param int $direction positive forward, negative backward
- * @return array with entries:
- * - $lines: changelog lines of readed chunk
- * - $head: head of chunk
- * - $tail: tail of chunk
- */
- protected function readAdjacentChunk($fp, $head, $tail, $direction) {
- if(!$fp) return array(array(), $head, $tail);
-
- if($direction > 0) {
- //read forward
- $head = $tail;
- $tail = $head + floor($this->chunk_size * (2 / 3));
- $tail = $this->getNewlinepointer($fp, $tail);
- } else {
- //read backward
- $tail = $head;
- $head = max($tail - $this->chunk_size, 0);
- while(true) {
- $nl = $this->getNewlinepointer($fp, $head);
- // was the chunk big enough? if not, take another bite
- if($nl > 0 && $tail <= $nl) {
- $head = max($head - $this->chunk_size, 0);
- } else {
- $head = $nl;
- break;
- }
- }
- }
-
- //load next chunck
- $lines = $this->readChunk($fp, $head, $tail);
- return array($lines, $head, $tail);
- }
-
- /**
- * Collect the $max revisions near to the timestamp $rev
- *
- * @param int $rev revision timestamp
- * @param int $max maximum number of revisions to be returned
- * @return bool|array
- * return array with entries:
- * - $requestedrevs: array of with $max revision timestamps
- * - $revs: all parsed revision timestamps
- * - $fp: filepointer only defined for chuck reading, needs closing.
- * - $lines: non-parsed changelog lines before the parsed revisions
- * - $head: position of first readed changelogline
- * - $lasttail: position of end of last readed changelogline
- * otherwise false
- */
- protected function retrieveRevisionsAround($rev, $max) {
- //get lines from changelog
- list($fp, $lines, $starthead, $starttail, /* $eof */) = $this->readloglines($rev);
- if(empty($lines)) return false;
-
- //parse chunk containing $rev, and read forward more chunks until $max/2 is reached
- $head = $starthead;
- $tail = $starttail;
- $revs = array();
- $aftercount = $beforecount = 0;
- while(count($lines) > 0) {
- foreach($lines as $line) {
- $tmp = parseChangelogLine($line);
- if($tmp !== false) {
- $this->cache[$this->id][$tmp['date']] = $tmp;
- $revs[] = $tmp['date'];
- if($tmp['date'] >= $rev) {
- //count revs after reference $rev
- $aftercount++;
- if($aftercount == 1) $beforecount = count($revs);
- }
- //enough revs after reference $rev?
- if($aftercount > floor($max / 2)) break 2;
- }
- }
- //retrieve next chunk
- list($lines, $head, $tail) = $this->readAdjacentChunk($fp, $head, $tail, 1);
- }
- if($aftercount == 0) return false;
-
- $lasttail = $tail;
-
- //read additional chuncks backward until $max/2 is reached and total number of revs is equal to $max
- $lines = array();
- $i = 0;
- if($aftercount > 0) {
- $head = $starthead;
- $tail = $starttail;
- while($head > 0) {
- list($lines, $head, $tail) = $this->readAdjacentChunk($fp, $head, $tail, -1);
-
- for($i = count($lines) - 1; $i >= 0; $i--) {
- $tmp = parseChangelogLine($lines[$i]);
- if($tmp !== false) {
- $this->cache[$this->id][$tmp['date']] = $tmp;
- $revs[] = $tmp['date'];
- $beforecount++;
- //enough revs before reference $rev?
- if($beforecount > max(floor($max / 2), $max - $aftercount)) break 2;
- }
- }
- }
- }
- sort($revs);
-
- //keep only non-parsed lines
- $lines = array_slice($lines, 0, $i);
- //trunk desired selection
- $requestedrevs = array_slice($revs, -$max, $max);
-
- return array($requestedrevs, $revs, $fp, $lines, $head, $lasttail);
- }
-}
-
-/**
- * Class PageChangelog handles changelog of a wiki page
- */
-class PageChangelog extends ChangeLog {
-
- /**
- * Returns path to changelog
- *
- * @return string path to file
- */
- protected function getChangelogFilename() {
- return metaFN($this->id, '.changes');
- }
-
- /**
- * Returns path to current page/media
- *
- * @return string path to file
- */
- protected function getFilename() {
- return wikiFN($this->id);
- }
-}
-
-/**
- * Class MediaChangelog handles changelog of a media file
- */
-class MediaChangelog extends ChangeLog {
-
- /**
- * Returns path to changelog
- *
- * @return string path to file
- */
- protected function getChangelogFilename() {
- return mediaMetaFN($this->id, '.changes');
- }
-
- /**
- * Returns path to current page/media
- *
- * @return string path to file
- */
- protected function getFilename() {
- return mediaFN($this->id);
- }
-}
diff --git a/inc/cli.php b/inc/cli.php
index cb4fc587d..e64798386 100644
--- a/inc/cli.php
+++ b/inc/cli.php
@@ -5,6 +5,7 @@
*
* All DokuWiki commandline scripts should inherit from this class and implement the abstract methods.
*
+ * @deprecated 2017-11-10
* @author Andreas Gohr <andi@splitbrain.org>
*/
abstract class DokuCLI {
diff --git a/inc/common.php b/inc/common.php
index 2d1f9703c..6822ccbd3 100644
--- a/inc/common.php
+++ b/inc/common.php
@@ -6,7 +6,13 @@
* @author Andreas Gohr <andi@splitbrain.org>
*/
-if(!defined('DOKU_INC')) die('meh.');
+use dokuwiki\Cache\CacheInstructions;
+use dokuwiki\Cache\CacheRenderer;
+use dokuwiki\ChangeLog\PageChangeLog;
+use dokuwiki\Subscriptions\PageSubscriptionSender;
+use dokuwiki\Subscriptions\SubscriberManager;
+use dokuwiki\Extension\AuthPlugin;
+use dokuwiki\Extension\Event;
/**
* These constants are used with the recents function
@@ -100,7 +106,7 @@ function getSecurityToken() {
// CSRF checks are only for logged in users - do not generate for anonymous
if(trim($user) == '' || trim($session) == '') return '';
- return PassHash::hmac('md5', $session.$user, auth_cookiesalt());
+ return \dokuwiki\PassHash::hmac('md5', $session.$user, auth_cookiesalt());
}
/**
@@ -212,8 +218,8 @@ function pageinfo() {
$info['rev'] = $REV;
if($INPUT->server->has('REMOTE_USER')) {
- $sub = new Subscription();
- $info['subscribed'] = $sub->user_subscription();
+ $subManager = new SubscriberManager();
+ $info['subscribed'] = $subManager->userSubscription();
} else {
$info['subscribed'] = false;
}
@@ -485,7 +491,9 @@ function wl($id = '', $urlParameters = '', $absolute = false, $separator = '&amp
global $conf;
if(is_array($urlParameters)) {
if(isset($urlParameters['rev']) && !$urlParameters['rev']) unset($urlParameters['rev']);
- if(isset($urlParameters['at']) && $conf['date_at_format']) $urlParameters['at'] = date($conf['date_at_format'],$urlParameters['at']);
+ if(isset($urlParameters['at']) && $conf['date_at_format']) {
+ $urlParameters['at'] = date($conf['date_at_format'], $urlParameters['at']);
+ }
$urlParameters = buildURLparams($urlParameters, $separator);
} else {
$urlParameters = str_replace(',', $separator, $urlParameters);
@@ -709,7 +717,13 @@ function checkwordblock($text = '') {
if(!$text) $text = "$PRE $TEXT $SUF $SUM";
// we prepare the text a tiny bit to prevent spammers circumventing URL checks
- $text = preg_replace('!(\b)(www\.[\w.:?\-;,]+?\.[\w.:?\-;,]+?[\w/\#~:.?+=&%@\!\-.:?\-;,]+?)([.:?\-;,]*[^\w/\#~:.?+=&%@\!\-.:?\-;,])!i', '\1http://\2 \2\3', $text);
+ // phpcs:disable Generic.Files.LineLength.TooLong
+ $text = preg_replace(
+ '!(\b)(www\.[\w.:?\-;,]+?\.[\w.:?\-;,]+?[\w/\#~:.?+=&%@\!\-.:?\-;,]+?)([.:?\-;,]*[^\w/\#~:.?+=&%@\!\-.:?\-;,])!i',
+ '\1http://\2 \2\3',
+ $text
+ );
+ // phpcs:enable
$wordblocks = getWordblocks();
// how many lines to read at once (to work around some PCRE limits)
@@ -745,7 +759,7 @@ function checkwordblock($text = '') {
$callback = function () {
return true;
};
- return trigger_event('COMMON_WORDBLOCK_BLOCKED', $data, $callback, true);
+ return Event::createAndTrigger('COMMON_WORDBLOCK_BLOCKED', $data, $callback, true);
}
}
return false;
@@ -835,6 +849,7 @@ function clientIP($single = false) {
*
* @link http://www.brainhandles.com/2007/10/15/detecting-mobile-browsers/#code
*
+ * @deprecated 2018-04-27 you probably want media queries instead anyway
* @return bool if true, client is mobile browser; otherwise false
*/
function clientismobile() {
@@ -847,7 +862,18 @@ function clientismobile() {
if(!$INPUT->server->has('HTTP_USER_AGENT')) return false;
- $uamatches = 'midp|j2me|avantg|docomo|novarra|palmos|palmsource|240x320|opwv|chtml|pda|windows ce|mmp\/|blackberry|mib\/|symbian|wireless|nokia|hand|mobi|phone|cdm|up\.b|audio|SIE\-|SEC\-|samsung|HTC|mot\-|mitsu|sagem|sony|alcatel|lg|erics|vx|NEC|philips|mmm|xx|panasonic|sharp|wap|sch|rover|pocket|benq|java|pt|pg|vox|amoi|bird|compal|kg|voda|sany|kdd|dbt|sendo|sgh|gradi|jb|\d\d\di|moto';
+ $uamatches = join(
+ '|',
+ [
+ 'midp', 'j2me', 'avantg', 'docomo', 'novarra', 'palmos', 'palmsource', '240x320', 'opwv',
+ 'chtml', 'pda', 'windows ce', 'mmp\/', 'blackberry', 'mib\/', 'symbian', 'wireless', 'nokia',
+ 'hand', 'mobi', 'phone', 'cdm', 'up\.b', 'audio', 'SIE\-', 'SEC\-', 'samsung', 'HTC', 'mot\-',
+ 'mitsu', 'sagem', 'sony', 'alcatel', 'lg', 'erics', 'vx', 'NEC', 'philips', 'mmm', 'xx',
+ 'panasonic', 'sharp', 'wap', 'sch', 'rover', 'pocket', 'benq', 'java', 'pt', 'pg', 'vox',
+ 'amoi', 'bird', 'compal', 'kg', 'voda', 'sany', 'kdd', 'dbt', 'sendo', 'sgh', 'gradi', 'jb',
+ '\d\d\di', 'moto'
+ ]
+ );
if(preg_match("/$uamatches/i", $INPUT->server->str('HTTP_USER_AGENT'))) return true;
@@ -991,7 +1017,7 @@ function cleanText($text) {
// if the text is not valid UTF-8 we simply assume latin1
// this won't break any worse than it breaks with the wrong encoding
// but might actually fix the problem in many cases
- if(!utf8_check($text)) $text = utf8_encode($text);
+ if(!\dokuwiki\Utf8\Clean::isUtf8($text)) $text = utf8_encode($text);
return $text;
}
@@ -1060,7 +1086,7 @@ function pageTemplate($id) {
'doreplace' => true // should wildcard replacements be done on the text?
);
- $evt = new Doku_Event('COMMON_PAGETPL_LOAD', $data);
+ $evt = new Event('COMMON_PAGETPL_LOAD', $data);
if($evt->advise_before(true)) {
// the before event might have loaded the content already
if(empty($data['tpl'])) {
@@ -1147,12 +1173,12 @@ function parsePageTemplate(&$data) {
utf8_ucwords(curNS($id)),
utf8_strtoupper(curNS($id)),
$file,
- utf8_ucfirst($file),
- utf8_strtoupper($file),
+ \dokuwiki\Utf8\PhpString::ucfirst($file),
+ \dokuwiki\Utf8\PhpString::strtoupper($file),
$page,
- utf8_ucfirst($page),
- utf8_ucwords($page),
- utf8_strtoupper($page),
+ \dokuwiki\Utf8\PhpString::ucfirst($page),
+ \dokuwiki\Utf8\PhpString::ucwords($page),
+ \dokuwiki\Utf8\PhpString::strtoupper($page),
$INPUT->server->str('REMOTE_USER'),
$USERINFO['name'],
$USERINFO['mail'],
@@ -1269,9 +1295,17 @@ function detectExternalEdit($id) {
$filesize_new = filesize($fileLastMod);
$sizechange = $filesize_new - $filesize_old;
- addLogEntry($lastMod, $id, DOKU_CHANGE_TYPE_EDIT, $lang['external_edit'], '', array('ExternalEdit'=> true), $sizechange);
+ addLogEntry(
+ $lastMod,
+ $id,
+ DOKU_CHANGE_TYPE_EDIT,
+ $lang['external_edit'],
+ '',
+ array('ExternalEdit' => true),
+ $sizechange
+ );
// remove soon to be stale instructions
- $cache = new cache_instructions($id, $fileLastMod);
+ $cache = new CacheInstructions($id, $fileLastMod);
$cache->removeCache();
}
}
@@ -1335,7 +1369,7 @@ function saveWikiText($id, $text, $summary, $minor = false) {
$svdta['changeType'] = DOKU_CHANGE_TYPE_MINOR_EDIT;
}
- $event = new Doku_Event('COMMON_WIKIPAGE_SAVE', $svdta);
+ $event = new Event('COMMON_WIKIPAGE_SAVE', $svdta);
if(!$event->advise_before()) return;
// if the content has not been changed, no save happens (plugins may override this)
@@ -1354,7 +1388,7 @@ function saveWikiText($id, $text, $summary, $minor = false) {
if($svdta['changeType'] == DOKU_CHANGE_TYPE_DELETE) {
// Send "update" event with empty data, so plugins can react to page deletion
$data = array(array($svdta['file'], '', false), getNS($id), noNS($id), false);
- trigger_event('IO_WIKIPAGE_WRITE', $data);
+ Event::createAndTrigger('IO_WIKIPAGE_WRITE', $data);
// pre-save deleted revision
@touch($svdta['file']);
clearstatcache();
@@ -1362,7 +1396,8 @@ function saveWikiText($id, $text, $summary, $minor = false) {
// remove empty file
@unlink($svdta['file']);
$filesize_new = 0;
- // don't remove old meta info as it should be saved, plugins can use IO_WIKIPAGE_WRITE for removing their metadata...
+ // don't remove old meta info as it should be saved, plugins can use
+ // IO_WIKIPAGE_WRITE for removing their metadata...
// purge non-persistant meta data
p_purge_metadata($id);
// remove empty namespaces
@@ -1379,7 +1414,15 @@ function saveWikiText($id, $text, $summary, $minor = false) {
$event->advise_after();
- addLogEntry($svdta['newRevision'], $svdta['id'], $svdta['changeType'], $svdta['summary'], $svdta['changeInfo'], null, $svdta['sizechange']);
+ addLogEntry(
+ $svdta['newRevision'],
+ $svdta['id'],
+ $svdta['changeType'],
+ $svdta['summary'],
+ $svdta['changeInfo'],
+ null,
+ $svdta['sizechange']
+ );
// send notify mails
notify($svdta['id'], 'admin', $svdta['oldRevision'], $svdta['summary'], $minor);
@@ -1392,7 +1435,7 @@ function saveWikiText($id, $text, $summary, $minor = false) {
if(useHeading('content')) {
$pages = ft_backlinks($id, true);
foreach($pages as $page) {
- $cache = new cache_renderer($page, wikiFN($page), 'xhtml');
+ $cache = new CacheRenderer($page, wikiFN($page), 'xhtml');
$cache->removeCache();
}
}
@@ -1443,7 +1486,7 @@ function notify($id, $who, $rev = '', $summary = '', $minor = false, $replace =
if(!actionOK('subscribe')) return false; //subscribers enabled?
if($conf['useacl'] && $INPUT->server->str('REMOTE_USER') && $minor) return false; //skip minors
$data = array('id' => $id, 'addresslist' => '', 'self' => false, 'replacements' => $replace);
- trigger_event(
+ Event::createAndTrigger(
'COMMON_NOTIFY_ADDRESSLIST', $data,
array(new Subscription(), 'notifyaddresses')
);
@@ -1455,8 +1498,8 @@ function notify($id, $who, $rev = '', $summary = '', $minor = false, $replace =
}
// prepare content
- $subscription = new Subscription();
- return $subscription->send_diff($to, $tpl, $id, $rev, $summary);
+ $subscription = new PageSubscriptionSender();
+ return $subscription->sendPageDiff($to, $tpl, $id, $rev, $summary);
}
/**
@@ -1660,7 +1703,7 @@ function php_to_byte($value) {
case 'K':
$ret = intval(substr($value, 0, -1)) * 1024;
break;
- default;
+ default:
$ret = intval($value);
break;
}
@@ -1693,12 +1736,15 @@ function preg_quote_cb($string) {
* @return string
*/
function shorten($keep, $short, $max, $min = 9, $char = '…') {
- $max = $max - utf8_strlen($keep);
+ $max = $max - \dokuwiki\Utf8\PhpString::strlen($keep);
if($max < $min) return $keep;
- $len = utf8_strlen($short);
+ $len = \dokuwiki\Utf8\PhpString::strlen($short);
if($len <= $max) return $keep.$short;
$half = floor($max / 2);
- return $keep.utf8_substr($short, 0, $half - 1).$char.utf8_substr($short, $len - $half);
+ return $keep .
+ \dokuwiki\Utf8\PhpString::substr($short, 0, $half - 1) .
+ $char .
+ \dokuwiki\Utf8\PhpString::substr($short, $len - $half);
}
/**
@@ -1726,7 +1772,7 @@ function editorinfo($username, $textonly = false) {
*/
function userlink($username = null, $textonly = false) {
global $conf, $INFO;
- /** @var DokuWiki_Auth_Plugin $auth */
+ /** @var AuthPlugin $auth */
global $auth;
/** @var Input $INPUT */
global $INPUT;
@@ -1753,11 +1799,12 @@ function userlink($username = null, $textonly = false) {
if($textonly){
$data['name'] = $INFO['userinfo']['name']. ' (' . $INPUT->server->str('REMOTE_USER') . ')';
}else {
- $data['name'] = '<bdi>' . hsc($INFO['userinfo']['name']) . '</bdi> (<bdi>' . hsc($INPUT->server->str('REMOTE_USER')) . '</bdi>)';
+ $data['name'] = '<bdi>' . hsc($INFO['userinfo']['name']) . '</bdi> '.
+ '(<bdi>' . hsc($INPUT->server->str('REMOTE_USER')) . '</bdi>)';
}
}
- $evt = new Doku_Event('COMMON_USER_LINK', $data);
+ $evt = new Event('COMMON_USER_LINK', $data);
if($evt->advise_before(true)) {
if(empty($data['name'])) {
if($auth) $info = $auth->getUserData($username);
@@ -2037,7 +2084,8 @@ function set_doku_pref($pref, $val) {
}
$cookieVal = implode('#', $parts);
} else if ($orig === false && $val !== false) {
- $cookieVal = ($_COOKIE['DOKU_PREFS'] ? $_COOKIE['DOKU_PREFS'].'#' : '').rawurlencode($pref).'#'.rawurlencode($val);
+ $cookieVal = ($_COOKIE['DOKU_PREFS'] ? $_COOKIE['DOKU_PREFS'] . '#' : '') .
+ rawurlencode($pref) . '#' . rawurlencode($val);
}
$cookieDir = empty($conf['cookiedir']) ? DOKU_REL : $conf['cookiedir'];
diff --git a/inc/confutils.php b/inc/confutils.php
index 59147010f..de4d418b4 100644
--- a/inc/confutils.php
+++ b/inc/confutils.php
@@ -11,6 +11,9 @@
* (scheme.conf & stopwords.conf), e.g.
* !gopher
*/
+
+use dokuwiki\Extension\AuthPlugin;
+use dokuwiki\Extension\Event;
const DOKU_CONF_NEGATION = '!';
/**
@@ -145,7 +148,7 @@ function getCdnUrls() {
'versions' => $versions,
'src' => &$src
);
- $event = new Doku_Event('CONFUTIL_CDN_SELECT', $data);
+ $event = new Event('CONFUTIL_CDN_SELECT', $data);
if($event->advise_before()) {
if(!$conf['jquerycdn']) {
$jqmod = md5(join('-', $versions));
@@ -155,9 +158,18 @@ function getCdnUrls() {
$src[] = sprintf('https://code.jquery.com/jquery-migrate-%s.min.js', $versions['JQM_VERSION']);
$src[] = sprintf('https://code.jquery.com/ui/%s/jquery-ui.min.js', $versions['JQUI_VERSION']);
} elseif($conf['jquerycdn'] == 'cdnjs') {
- $src[] = sprintf('https://cdnjs.cloudflare.com/ajax/libs/jquery/%s/jquery.min.js', $versions['JQ_VERSION']);
- $src[] = sprintf('https://cdnjs.cloudflare.com/ajax/libs/jquery-migrate/%s/jquery-migrate.min.js', $versions['JQM_VERSION']);
- $src[] = sprintf('https://cdnjs.cloudflare.com/ajax/libs/jqueryui/%s/jquery-ui.min.js', $versions['JQUI_VERSION']);
+ $src[] = sprintf(
+ 'https://cdnjs.cloudflare.com/ajax/libs/jquery/%s/jquery.min.js',
+ $versions['JQ_VERSION']
+ );
+ $src[] = sprintf(
+ 'https://cdnjs.cloudflare.com/ajax/libs/jquery-migrate/%s/jquery-migrate.min.js',
+ $versions['JQM_VERSION']
+ );
+ $src[] = sprintf(
+ 'https://cdnjs.cloudflare.com/ajax/libs/jqueryui/%s/jquery-ui.min.js',
+ $versions['JQUI_VERSION']
+ );
}
}
$event->advise_after();
@@ -341,7 +353,7 @@ function actionOK($action){
static $disabled = null;
if(is_null($disabled) || defined('SIMPLE_TEST')){
global $conf;
- /** @var DokuWiki_Auth_Plugin $auth */
+ /** @var AuthPlugin $auth */
global $auth;
// prepare disabled actions array and handle legacy options
diff --git a/inc/deprecated.php b/inc/deprecated.php
new file mode 100644
index 000000000..d3de76080
--- /dev/null
+++ b/inc/deprecated.php
@@ -0,0 +1,565 @@
+<?php
+// phpcs:ignoreFile -- this file violates PSR2 by definition
+/**
+ * These classes and functions are deprecated and will be removed in future releases
+ */
+
+use dokuwiki\Debug\DebugHelper;
+use dokuwiki\Subscriptions\BulkSubscriptionSender;
+use dokuwiki\Subscriptions\MediaSubscriptionSender;
+use dokuwiki\Subscriptions\PageSubscriptionSender;
+use dokuwiki\Subscriptions\RegistrationSubscriptionSender;
+use dokuwiki\Subscriptions\SubscriberManager;
+
+/**
+ * @inheritdoc
+ * @deprecated 2018-05-07
+ */
+class RemoteAccessDeniedException extends \dokuwiki\Remote\AccessDeniedException
+{
+ /** @inheritdoc */
+ public function __construct($message = "", $code = 0, Throwable $previous = null)
+ {
+ dbg_deprecated(\dokuwiki\Remote\AccessDeniedException::class);
+ parent::__construct($message, $code, $previous);
+ }
+
+}
+
+/**
+ * @inheritdoc
+ * @deprecated 2018-05-07
+ */
+class RemoteException extends \dokuwiki\Remote\RemoteException
+{
+ /** @inheritdoc */
+ public function __construct($message = "", $code = 0, Throwable $previous = null)
+ {
+ dbg_deprecated(\dokuwiki\Remote\RemoteException::class);
+ parent::__construct($message, $code, $previous);
+ }
+
+}
+
+/**
+ * Escapes regex characters other than (, ) and /
+ *
+ * @param string $str
+ * @return string
+ * @deprecated 2018-05-04
+ */
+function Doku_Lexer_Escape($str)
+{
+ dbg_deprecated('\\dokuwiki\\Parsing\\Lexer\\Lexer::escape()');
+ return \dokuwiki\Parsing\Lexer\Lexer::escape($str);
+}
+
+/**
+ * @inheritdoc
+ * @deprecated 2018-06-01
+ */
+class setting extends \dokuwiki\plugin\config\core\Setting\Setting
+{
+ /** @inheritdoc */
+ public function __construct($key, array $params = null)
+ {
+ dbg_deprecated(\dokuwiki\plugin\config\core\Setting\Setting::class);
+ parent::__construct($key, $params);
+ }
+}
+
+/**
+ * @inheritdoc
+ * @deprecated 2018-06-01
+ */
+class setting_authtype extends \dokuwiki\plugin\config\core\Setting\SettingAuthtype
+{
+ /** @inheritdoc */
+ public function __construct($key, array $params = null)
+ {
+ dbg_deprecated(\dokuwiki\plugin\config\core\Setting\SettingAuthtype::class);
+ parent::__construct($key, $params);
+ }
+}
+
+/**
+ * @inheritdoc
+ * @deprecated 2018-06-01
+ */
+class setting_string extends \dokuwiki\plugin\config\core\Setting\SettingString
+{
+ /** @inheritdoc */
+ public function __construct($key, array $params = null)
+ {
+ dbg_deprecated(\dokuwiki\plugin\config\core\Setting\SettingString::class);
+ parent::__construct($key, $params);
+ }
+}
+
+/**
+ * @inheritdoc
+ * @deprecated 2018-06-15
+ */
+class PageChangelog extends \dokuwiki\ChangeLog\PageChangeLog
+{
+ /** @inheritdoc */
+ public function __construct($id, $chunk_size = 8192)
+ {
+ dbg_deprecated(\dokuwiki\ChangeLog\PageChangeLog::class);
+ parent::__construct($id, $chunk_size);
+ }
+}
+
+/**
+ * @inheritdoc
+ * @deprecated 2018-06-15
+ */
+class MediaChangelog extends \dokuwiki\ChangeLog\MediaChangeLog
+{
+ /** @inheritdoc */
+ public function __construct($id, $chunk_size = 8192)
+ {
+ dbg_deprecated(\dokuwiki\ChangeLog\MediaChangeLog::class);
+ parent::__construct($id, $chunk_size);
+ }
+}
+
+/** Behavior switch for JSON::decode() */
+define('JSON_LOOSE_TYPE', 16);
+
+/** Behavior switch for JSON::decode() */
+define('JSON_STRICT_TYPE', 0);
+
+/**
+ * Encode/Decode JSON
+ * @deprecated 2018-07-27
+ */
+class JSON
+{
+ protected $use = 0;
+
+ /**
+ * @param int $use JSON_*_TYPE flag
+ * @deprecated 2018-07-27
+ */
+ public function __construct($use = JSON_STRICT_TYPE)
+ {
+ $this->use = $use;
+ }
+
+ /**
+ * Encode given structure to JSON
+ *
+ * @param mixed $var
+ * @return string
+ * @deprecated 2018-07-27
+ */
+ public function encode($var)
+ {
+ dbg_deprecated('json_encode');
+ return json_encode($var);
+ }
+
+ /**
+ * Alias for encode()
+ * @param $var
+ * @return string
+ * @deprecated 2018-07-27
+ */
+ public function enc($var) {
+ return $this->encode($var);
+ }
+
+ /**
+ * Decode given string from JSON
+ *
+ * @param string $str
+ * @return mixed
+ * @deprecated 2018-07-27
+ */
+ public function decode($str)
+ {
+ dbg_deprecated('json_encode');
+ return json_decode($str, ($this->use == JSON_LOOSE_TYPE));
+ }
+
+ /**
+ * Alias for decode
+ *
+ * @param $str
+ * @return mixed
+ * @deprecated 2018-07-27
+ */
+ public function dec($str) {
+ return $this->decode($str);
+ }
+}
+
+/**
+ * @inheritdoc
+ * @deprecated 2019-02-19
+ */
+class Input extends \dokuwiki\Input\Input {
+ /**
+ * @inheritdoc
+ * @deprecated 2019-02-19
+ */
+ public function __construct()
+ {
+ dbg_deprecated(\dokuwiki\Input\Input::class);
+ parent::__construct();
+ }
+}
+
+/**
+ * @inheritdoc
+ * @deprecated 2019-02-19
+ */
+class PostInput extends \dokuwiki\Input\Post {
+ /**
+ * @inheritdoc
+ * @deprecated 2019-02-19
+ */
+ public function __construct()
+ {
+ dbg_deprecated(\dokuwiki\Input\Post::class);
+ parent::__construct();
+ }
+}
+
+/**
+ * @inheritdoc
+ * @deprecated 2019-02-19
+ */
+class GetInput extends \dokuwiki\Input\Get {
+ /**
+ * @inheritdoc
+ * @deprecated 2019-02-19
+ */
+ public function __construct()
+ {
+ dbg_deprecated(\dokuwiki\Input\Get::class);
+ parent::__construct();
+ }
+}
+
+/**
+ * @inheritdoc
+ * @deprecated 2019-02-19
+ */
+class ServerInput extends \dokuwiki\Input\Server {
+ /**
+ * @inheritdoc
+ * @deprecated 2019-02-19
+ */
+ public function __construct()
+ {
+ dbg_deprecated(\dokuwiki\Input\Server::class);
+ parent::__construct();
+ }
+}
+
+/**
+ * @inheritdoc
+ * @deprecated 2019-03-06
+ */
+class PassHash extends \dokuwiki\PassHash {
+ /**
+ * @inheritdoc
+ * @deprecated 2019-03-06
+ */
+ public function __construct()
+ {
+ dbg_deprecated(\dokuwiki\PassHash::class);
+ }
+}
+
+/**
+ * @deprecated since 2019-03-17 use \dokuwiki\HTTP\HTTPClientException instead!
+ */
+class HTTPClientException extends \dokuwiki\HTTP\HTTPClientException {
+
+ /**
+ * @inheritdoc
+ * @deprecated 2019-03-17
+ */
+ public function __construct($message = '', $code = 0, $previous = null)
+ {
+ DebugHelper::dbgDeprecatedFunction(dokuwiki\HTTP\HTTPClientException::class);
+ parent::__construct($message, $code, $previous);
+ }
+}
+
+/**
+ * @deprecated since 2019-03-17 use \dokuwiki\HTTP\HTTPClient instead!
+ */
+class HTTPClient extends \dokuwiki\HTTP\HTTPClient {
+
+ /**
+ * @inheritdoc
+ * @deprecated 2019-03-17
+ */
+ public function __construct()
+ {
+ DebugHelper::dbgDeprecatedFunction(dokuwiki\HTTP\HTTPClient::class);
+ parent::__construct();
+ }
+}
+
+/**
+ * @deprecated since 2019-03-17 use \dokuwiki\HTTP\DokuHTTPClient instead!
+ */
+class DokuHTTPClient extends \dokuwiki\HTTP\DokuHTTPClient
+{
+
+ /**
+ * @inheritdoc
+ * @deprecated 2019-03-17
+ */
+ public function __construct()
+ {
+ DebugHelper::dbgDeprecatedFunction(dokuwiki\HTTP\DokuHTTPClient::class);
+ parent::__construct();
+ }
+}
+
+/**
+ * function wrapper to process (create, trigger and destroy) an event
+ *
+ * @param string $name name for the event
+ * @param mixed $data event data
+ * @param callback $action (optional, default=NULL) default action, a php callback function
+ * @param bool $canPreventDefault (optional, default=true) can hooks prevent the default action
+ *
+ * @return mixed the event results value after all event processing is complete
+ * by default this is the return value of the default action however
+ * it can be set or modified by event handler hooks
+ * @deprecated 2018-06-15
+ */
+function trigger_event($name, &$data, $action=null, $canPreventDefault=true) {
+ dbg_deprecated('\dokuwiki\Extension\Event::createAndTrigger');
+ return \dokuwiki\Extension\Event::createAndTrigger($name, $data, $action, $canPreventDefault);
+}
+
+/**
+ * @inheritdoc
+ * @deprecated 2018-06-15
+ */
+class Doku_Plugin_Controller extends \dokuwiki\Extension\PluginController {
+ /** @inheritdoc */
+ public function __construct()
+ {
+ dbg_deprecated(\dokuwiki\Extension\PluginController::class);
+ parent::__construct();
+ }
+}
+
+
+/**
+ * Class for handling (email) subscriptions
+ *
+ * @author Adrian Lang <lang@cosmocode.de>
+ * @author Andreas Gohr <andi@splitbrain.org>
+ * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ *
+ * @deprecated 2019-04-22 Use the classes in the \dokuwiki\Subscriptions namespace instead!
+ */
+class Subscription {
+
+ /**
+ * Check if subscription system is enabled
+ *
+ * @return bool
+ *
+ * @deprecated 2019-04-20 \dokuwiki\Subscriptions\SubscriberManager::isenabled
+ */
+ public function isenabled() {
+ DebugHelper::dbgDeprecatedFunction('\dokuwiki\Subscriptions\SubscriberManager::isenabled');
+ $subscriberManager = new SubscriberManager();
+ return $subscriberManager->isenabled();
+ }
+
+ /**
+ * Recursively search for matching subscriptions
+ *
+ * This function searches all relevant subscription files for a page or
+ * namespace.
+ *
+ * @author Adrian Lang <lang@cosmocode.de>
+ *
+ * @param string $page The target object’s (namespace or page) id
+ * @param string|array $user
+ * @param string|array $style
+ * @param string|array $data
+ * @return array
+ *
+ * @deprecated 2019-04-20 \dokuwiki\Subscriptions\SubscriberManager::subscribers
+ */
+ public function subscribers($page, $user = null, $style = null, $data = null) {
+ DebugHelper::dbgDeprecatedFunction('\dokuwiki\Subscriptions\SubscriberManager::subscribers');
+ $manager = new SubscriberManager();
+ return $manager->subscribers($page, $user, $style, $data);
+ }
+
+ /**
+ * Adds a new subscription for the given page or namespace
+ *
+ * This will automatically overwrite any existent subscription for the given user on this
+ * *exact* page or namespace. It will *not* modify any subscription that may exist in higher namespaces.
+ *
+ * @param string $id The target page or namespace, specified by id; Namespaces
+ * are identified by appending a colon.
+ * @param string $user
+ * @param string $style
+ * @param string $data
+ * @throws Exception when user or style is empty
+ * @return bool
+ *
+ * @deprecated 2019-04-20 \dokuwiki\Subscriptions\SubscriberManager::add
+ */
+ public function add($id, $user, $style, $data = '') {
+ DebugHelper::dbgDeprecatedFunction('\dokuwiki\Subscriptions\SubscriberManager::add');
+ $manager = new SubscriberManager();
+ return $manager->add($id, $user, $style, $data);
+ }
+
+ /**
+ * Removes a subscription for the given page or namespace
+ *
+ * This removes all subscriptions matching the given criteria on the given page or
+ * namespace. It will *not* modify any subscriptions that may exist in higher
+ * namespaces.
+ *
+ * @param string $id The target object’s (namespace or page) id
+ * @param string|array $user
+ * @param string|array $style
+ * @param string|array $data
+ * @return bool
+ *
+ * @deprecated 2019-04-20 \dokuwiki\Subscriptions\SubscriberManager::remove
+ */
+ public function remove($id, $user = null, $style = null, $data = null) {
+ DebugHelper::dbgDeprecatedFunction('\dokuwiki\Subscriptions\SubscriberManager::remove');
+ $manager = new SubscriberManager();
+ return $manager->remove($id, $user, $style, $data);
+ }
+
+ /**
+ * Get data for $INFO['subscribed']
+ *
+ * $INFO['subscribed'] is either false if no subscription for the current page
+ * and user is in effect. Else it contains an array of arrays with the fields
+ * “target”, “style”, and optionally “data”.
+ *
+ * @param string $id Page ID, defaults to global $ID
+ * @param string $user User, defaults to $_SERVER['REMOTE_USER']
+ * @return array|false
+ * @author Adrian Lang <lang@cosmocode.de>
+ *
+ * @deprecated 2019-04-20 \dokuwiki\Subscriptions\SubscriberManager::userSubscription
+ */
+ public function user_subscription($id = '', $user = '') {
+ DebugHelper::dbgDeprecatedFunction('\dokuwiki\Subscriptions\SubscriberManager::userSubscription');
+ $manager = new SubscriberManager();
+ return $manager->userSubscription($id, $user);
+ }
+
+ /**
+ * Send digest and list subscriptions
+ *
+ * This sends mails to all subscribers that have a subscription for namespaces above
+ * the given page if the needed $conf['subscribe_time'] has passed already.
+ *
+ * This function is called form lib/exe/indexer.php
+ *
+ * @param string $page
+ * @return int number of sent mails
+ *
+ * @deprecated 2019-04-20 \dokuwiki\Subscriptions\BulkSubscriptionSender::sendBulk
+ */
+ public function send_bulk($page) {
+ DebugHelper::dbgDeprecatedFunction('\dokuwiki\Subscriptions\BulkSubscriptionSender::sendBulk');
+ $subscriptionSender = new BulkSubscriptionSender();
+ return $subscriptionSender->sendBulk($page);
+ }
+
+ /**
+ * Send the diff for some page change
+ *
+ * @param string $subscriber_mail The target mail address
+ * @param string $template Mail template ('subscr_digest', 'subscr_single', 'mailtext', ...)
+ * @param string $id Page for which the notification is
+ * @param int|null $rev Old revision if any
+ * @param string $summary Change summary if any
+ * @return bool true if successfully sent
+ *
+ * @deprecated 2019-04-20 \dokuwiki\Subscriptions\PageSubscriptionSender::sendPageDiff
+ */
+ public function send_diff($subscriber_mail, $template, $id, $rev = null, $summary = '') {
+ DebugHelper::dbgDeprecatedFunction('\dokuwiki\Subscriptions\PageSubscriptionSender::sendPageDiff');
+ $subscriptionSender = new PageSubscriptionSender();
+ return $subscriptionSender->sendPageDiff($subscriber_mail, $template, $id, $rev, $summary);
+ }
+
+ /**
+ * Send the diff for some media change
+ *
+ * @fixme this should embed thumbnails of images in HTML version
+ *
+ * @param string $subscriber_mail The target mail address
+ * @param string $template Mail template ('uploadmail', ...)
+ * @param string $id Media file for which the notification is
+ * @param int|bool $rev Old revision if any
+ *
+ * @deprecated 2019-04-20 \dokuwiki\Subscriptions\MediaSubscriptionSender::sendMediaDiff
+ */
+ public function send_media_diff($subscriber_mail, $template, $id, $rev = false) {
+ DebugHelper::dbgDeprecatedFunction('\dokuwiki\Subscriptions\MediaSubscriptionSender::sendMediaDiff');
+ $subscriptionSender = new MediaSubscriptionSender();
+ return $subscriptionSender->sendMediaDiff($subscriber_mail, $template, $id, $rev);
+ }
+
+ /**
+ * Send a notify mail on new registration
+ *
+ * @author Andreas Gohr <andi@splitbrain.org>
+ *
+ * @param string $login login name of the new user
+ * @param string $fullname full name of the new user
+ * @param string $email email address of the new user
+ * @return bool true if a mail was sent
+ *
+ * @deprecated 2019-04-20 \dokuwiki\Subscriptions\RegistrationSubscriptionSender::sendRegister
+ */
+ public function send_register($login, $fullname, $email) {
+ DebugHelper::dbgDeprecatedFunction('\dokuwiki\Subscriptions\RegistrationSubscriptionSender::sendRegister');
+ $subscriptionSender = new RegistrationSubscriptionSender();
+ return $subscriptionSender->sendRegister($login, $fullname, $email);
+ }
+
+
+ /**
+ * Default callback for COMMON_NOTIFY_ADDRESSLIST
+ *
+ * Aggregates all email addresses of user who have subscribed the given page with 'every' style
+ *
+ * @author Steven Danz <steven-danz@kc.rr.com>
+ * @author Adrian Lang <lang@cosmocode.de>
+ *
+ * @todo move the whole functionality into this class, trigger SUBSCRIPTION_NOTIFY_ADDRESSLIST instead,
+ * use an array for the addresses within it
+ *
+ * @param array &$data Containing the entries:
+ * - $id (the page id),
+ * - $self (whether the author should be notified,
+ * - $addresslist (current email address list)
+ * - $replacements (array of additional string substitutions, @KEY@ to be replaced by value)
+ *
+ * @deprecated 2019-04-20 \dokuwiki\Subscriptions\SubscriberManager::notifyAddresses
+ */
+ public function notifyaddresses(&$data) {
+ DebugHelper::dbgDeprecatedFunction('\dokuwiki\Subscriptions\SubscriberManager::notifyAddresses');
+ $manager = new SubscriberManager();
+ $manager->notifyAddresses($data);
+ }
+}
diff --git a/inc/events.php b/inc/events.php
deleted file mode 100644
index 3ac49bf3f..000000000
--- a/inc/events.php
+++ /dev/null
@@ -1,275 +0,0 @@
-<?php
-/**
- * DokuWiki Events
- *
- * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
- * @author Christopher Smith <chris@jalakai.co.uk>
- */
-
-if(!defined('DOKU_INC')) die('meh.');
-
-/**
- * The event
- */
-class Doku_Event {
-
- // public properties
- public $name = ''; // READONLY event name, objects must register against this name to see the event
- public $data = null; // READWRITE data relevant to the event, no standardised format (YET!)
- public $result = null; // READWRITE the results of the event action, only relevant in "_AFTER" advise
- // event handlers may modify this if they are preventing the default action
- // to provide the after event handlers with event results
- public $canPreventDefault = true; // READONLY if true, event handlers can prevent the events default action
-
- // private properties, event handlers can effect these through the provided methods
- protected $_default = true; // whether or not to carry out the default action associated with the event
- protected $_continue = true; // whether or not to continue propagating the event to other handlers
-
- /**
- * event constructor
- *
- * @param string $name
- * @param mixed $data
- */
- function __construct($name, &$data) {
-
- $this->name = $name;
- $this->data =& $data;
-
- }
-
- /**
- * @return string
- */
- function __toString() {
- return $this->name;
- }
-
- /**
- * advise functions
- *
- * advise all registered handlers of this event
- *
- * if these methods are used by functions outside of this object, they must
- * properly handle correct processing of any default action and issue an
- * advise_after() signal. e.g.
- * $evt = new Doku_Event(name, data);
- * if ($evt->advise_before(canPreventDefault) {
- * // default action code block
- * }
- * $evt->advise_after();
- * unset($evt);
- *
- * @param bool $enablePreventDefault
- * @return bool results of processing the event, usually $this->_default
- */
- function advise_before($enablePreventDefault=true) {
- global $EVENT_HANDLER;
-
- $this->canPreventDefault = $enablePreventDefault;
- $EVENT_HANDLER->process_event($this,'BEFORE');
-
- return (!$enablePreventDefault || $this->_default);
- }
-
- function advise_after() {
- global $EVENT_HANDLER;
-
- $this->_continue = true;
- $EVENT_HANDLER->process_event($this,'AFTER');
- }
-
- /**
- * trigger
- *
- * - advise all registered (<event>_BEFORE) handlers that this event is about to take place
- * - carry out the default action using $this->data based on $enablePrevent and
- * $this->_default, all of which may have been modified by the event handlers.
- * - advise all registered (<event>_AFTER) handlers that the event has taken place
- *
- * @param null|callable $action
- * @param bool $enablePrevent
- * @return mixed $event->results
- * the value set by any <event>_before or <event> handlers if the default action is prevented
- * or the results of the default action (as modified by <event>_after handlers)
- * or NULL no action took place and no handler modified the value
- */
- function trigger($action=null, $enablePrevent=true) {
-
- if (!is_callable($action)) {
- $enablePrevent = false;
- if (!is_null($action)) {
- trigger_error('The default action of '.$this.' is not null but also not callable. Maybe the method is not public?', E_USER_WARNING);
- }
- }
-
- if ($this->advise_before($enablePrevent) && is_callable($action)) {
- if (is_array($action)) {
- list($obj,$method) = $action;
- $this->result = $obj->$method($this->data);
- } else {
- $this->result = $action($this->data);
- }
- }
-
- $this->advise_after();
-
- return $this->result;
- }
-
- /**
- * stopPropagation
- *
- * stop any further processing of the event by event handlers
- * this function does not prevent the default action taking place
- */
- public function stopPropagation() {
- $this->_continue = false;
- }
-
- /**
- * may the event propagate to the next handler?
- *
- * @return bool
- */
- public function mayPropagate() {
- return $this->_continue;
- }
-
- /**
- * preventDefault
- *
- * prevent the default action taking place
- */
- public function preventDefault() {
- $this->_default = false;
- }
-
- /**
- * should the default action be executed?
- *
- * @return bool
- */
- public function mayRunDefault() {
- return $this->_default;
- }
-}
-
-/**
- * Controls the registration and execution of all events,
- */
-class Doku_Event_Handler {
-
- // public properties: none
-
- // private properties
- protected $_hooks = array(); // array of events and their registered handlers
-
- /**
- * event_handler
- *
- * constructor, loads all action plugins and calls their register() method giving them
- * an opportunity to register any hooks they require
- */
- function __construct() {
-
- // load action plugins
- /** @var DokuWiki_Action_Plugin $plugin */
- $plugin = null;
- $pluginlist = plugin_list('action');
-
- foreach ($pluginlist as $plugin_name) {
- $plugin = plugin_load('action',$plugin_name);
-
- if ($plugin !== null) $plugin->register($this);
- }
- }
-
- /**
- * register_hook
- *
- * register a hook for an event
- *
- * @param string $event string name used by the event, (incl '_before' or '_after' for triggers)
- * @param string $advise
- * @param object $obj object in whose scope method is to be executed,
- * if NULL, method is assumed to be a globally available function
- * @param string $method event handler function
- * @param mixed $param data passed to the event handler
- * @param int $seq sequence number for ordering hook execution (ascending)
- */
- function register_hook($event, $advise, $obj, $method, $param=null, $seq=0) {
- $seq = (int)$seq;
- $doSort = !isset($this->_hooks[$event.'_'.$advise][$seq]);
- $this->_hooks[$event.'_'.$advise][$seq][] = array($obj, $method, $param);
-
- if ($doSort) {
- ksort($this->_hooks[$event.'_'.$advise]);
- }
- }
-
- /**
- * process the before/after event
- *
- * @param Doku_Event $event
- * @param string $advise BEFORE or AFTER
- */
- function process_event($event,$advise='') {
-
- $evt_name = $event->name . ($advise ? '_'.$advise : '_BEFORE');
-
- if (!empty($this->_hooks[$evt_name])) {
- foreach ($this->_hooks[$evt_name] as $sequenced_hooks) {
- foreach ($sequenced_hooks as $hook) {
- list($obj, $method, $param) = $hook;
-
- if (is_null($obj)) {
- $method($event, $param);
- } else {
- $obj->$method($event, $param);
- }
-
- if (!$event->mayPropagate()) return;
- }
- }
- }
- }
-
- /**
- * Check if an event has any registered handlers
- *
- * When $advise is empty, both BEFORE and AFTER events will be considered,
- * otherwise only the given advisory is checked
- *
- * @param string $name Name of the event
- * @param string $advise BEFORE, AFTER or empty
- * @return bool
- */
- public function hasHandlerForEvent($name, $advise = '') {
- if($advise) {
- return isset($this->_hooks[$name . '_' . $advise]);
- } else {
- return isset($this->_hooks[$name . '_BEFORE']) || isset($this->_hooks[$name . '_AFTER']);
- }
- }
-}
-
-/**
- * trigger_event
- *
- * function wrapper to process (create, trigger and destroy) an event
- *
- * @param string $name name for the event
- * @param mixed $data event data
- * @param callback $action (optional, default=NULL) default action, a php callback function
- * @param bool $canPreventDefault (optional, default=true) can hooks prevent the default action
- *
- * @return mixed the event results value after all event processing is complete
- * by default this is the return value of the default action however
- * it can be set or modified by event handler hooks
- */
-function trigger_event($name, &$data, $action=null, $canPreventDefault=true) {
-
- $evt = new Doku_Event($name, $data);
- return $evt->trigger($action, $canPreventDefault);
-}
diff --git a/inc/farm.php b/inc/farm.php
index 0cd9d4f9c..03aa0eb30 100644
--- a/inc/farm.php
+++ b/inc/farm.php
@@ -22,7 +22,7 @@
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
*/
-// DOKU_FARMDIR needs to be set in preload.php, here the fallback is the same as DOKU_INC would be (if it was set already)
+// DOKU_FARMDIR needs to be set in preload.php, the fallback is the same as DOKU_INC would be (if it was set already)
if(!defined('DOKU_FARMDIR')) define('DOKU_FARMDIR', fullpath(dirname(__FILE__).'/../').'/');
if(!defined('DOKU_CONF')) define('DOKU_CONF', farm_confpath(DOKU_FARMDIR));
if(!defined('DOKU_FARM')) define('DOKU_FARM', false);
diff --git a/inc/fetch.functions.php b/inc/fetch.functions.php
index b8e75eaec..63672629d 100644
--- a/inc/fetch.functions.php
+++ b/inc/fetch.functions.php
@@ -68,10 +68,14 @@ function sendFile($file, $mime, $dl, $cache, $public = false, $orig = null) {
}
//download or display?
- if($dl) {
- header('Content-Disposition: attachment;'.rfc2231_encode('filename', utf8_basename($orig)).';');
+ if ($dl) {
+ header('Content-Disposition: attachment;' . rfc2231_encode(
+ 'filename', \dokuwiki\Utf8\PhpString::basename($orig)) . ';'
+ );
} else {
- header('Content-Disposition: inline;'.rfc2231_encode('filename', utf8_basename($orig)).';');
+ header('Content-Disposition: inline;' . rfc2231_encode(
+ 'filename', \dokuwiki\Utf8\PhpString::basename($orig)) . ';'
+ );
}
//use x-sendfile header to pass the delivery to compatible webservers
@@ -104,7 +108,13 @@ function sendFile($file, $mime, $dl, $cache, $public = false, $orig = null) {
* @return string in the format " name*=charset'lang'value" for values WITH special characters
*/
function rfc2231_encode($name, $value, $charset='utf-8', $lang='en') {
- $internal = preg_replace_callback('/[\x00-\x20*\'%()<>@,;:\\\\"\/[\]?=\x80-\xFF]/', function($match) { return rawurlencode($match[0]); }, $value);
+ $internal = preg_replace_callback(
+ '/[\x00-\x20*\'%()<>@,;:\\\\"\/[\]?=\x80-\xFF]/',
+ function ($match) {
+ return rawurlencode($match[0]);
+ },
+ $value
+ );
if ( $value != $internal ) {
return ' '.$name.'*='.$charset."'".$lang."'".$internal;
} else {
diff --git a/inc/form.php b/inc/form.php
index 7afb0ba30..7a4d737a0 100644
--- a/inc/form.php
+++ b/inc/form.php
@@ -6,7 +6,9 @@
* @author Tom N Harris <tnharris@whoopdedo.org>
*/
-if(!defined('DOKU_INC')) die('meh.');
+// phpcs:disable Squiz.Classes.ValidClassName.NotCamelCaps
+// phpcs:disable PSR2.Classes.PropertyDeclaration.Underscore
+
/**
* Class for creating simple HTML forms.
@@ -23,6 +25,11 @@ if(!defined('DOKU_INC')) die('meh.');
*
* See the form_make* functions later in this file.
*
+ * Please note that even though this class is technically deprecated (use dokuwiki\Form instead),
+ * it is still widely used in the core and the related form events. Until those have been rewritten,
+ * this will continue to be used
+ *
+ * @deprecated 2019-07-14
* @author Tom N Harris <tnharris@whoopdedo.org>
*/
class Doku_Form {
@@ -55,7 +62,7 @@ class Doku_Form {
*
* @author Tom N Harris <tnharris@whoopdedo.org>
*/
- function __construct($params, $action=false, $method=false, $enctype=false) {
+ public function __construct($params, $action=false, $method=false, $enctype=false) {
if(!is_array($params)) {
$this->params = array('id' => $params);
if ($action !== false) $this->params['action'] = $action;
@@ -88,7 +95,7 @@ class Doku_Form {
*
* @author Tom N Harris <tnharris@whoopdedo.org>
*/
- function startFieldset($legend) {
+ public function startFieldset($legend) {
if ($this->_infieldset) {
$this->addElement(array('_elem'=>'closefieldset'));
}
@@ -101,7 +108,7 @@ class Doku_Form {
*
* @author Tom N Harris <tnharris@whoopdedo.org>
*/
- function endFieldset() {
+ public function endFieldset() {
if ($this->_infieldset) {
$this->addElement(array('_elem'=>'closefieldset'));
}
@@ -120,7 +127,7 @@ class Doku_Form {
*
* @author Tom N Harris <tnharris@whoopdedo.org>
*/
- function addHidden($name, $value) {
+ public function addHidden($name, $value) {
if (is_null($value))
unset($this->_hidden[$name]);
else
@@ -138,7 +145,7 @@ class Doku_Form {
*
* @author Tom N Harris <tnharris@whoopdedo.org>
*/
- function addElement($elem) {
+ public function addElement($elem) {
$this->_content[] = $elem;
}
@@ -152,7 +159,7 @@ class Doku_Form {
*
* @author Tom N Harris <tnharris@whoopdedo.org>
*/
- function insertElement($pos, $elem) {
+ public function insertElement($pos, $elem) {
array_splice($this->_content, $pos, 0, array($elem));
}
@@ -166,7 +173,7 @@ class Doku_Form {
*
* @author Tom N Harris <tnharris@whoopdedo.org>
*/
- function replaceElement($pos, $elem) {
+ public function replaceElement($pos, $elem) {
$rep = array();
if (!is_null($elem)) $rep[] = $elem;
array_splice($this->_content, $pos, 1, $rep);
@@ -182,7 +189,7 @@ class Doku_Form {
*
* @author Tom N Harris <tnharris@whoopdedo.org>
*/
- function findElementByType($type) {
+ public function findElementByType($type) {
foreach ($this->_content as $pos=>$elem) {
if (is_array($elem) && $elem['_elem'] == $type)
return $pos;
@@ -200,7 +207,7 @@ class Doku_Form {
*
* @author Tom N Harris <tnharris@whoopdedo.org>
*/
- function findElementById($id) {
+ public function findElementById($id) {
foreach ($this->_content as $pos=>$elem) {
if (is_array($elem) && isset($elem['id']) && $elem['id'] == $id)
return $pos;
@@ -219,7 +226,7 @@ class Doku_Form {
*
* @author Tom N Harris <tnharris@whoopdedo.org>
*/
- function findElementByAttribute($name, $value) {
+ public function findElementByAttribute($name, $value) {
foreach ($this->_content as $pos=>$elem) {
if (is_array($elem) && isset($elem[$name]) && $elem[$name] == $value)
return $pos;
@@ -239,7 +246,7 @@ class Doku_Form {
*
* @author Tom N Harris <tnharris@whoopdedo.org>
*/
- function &getElementAt($pos) {
+ public function &getElementAt($pos) {
if ($pos < 0) $pos = count($this->_content) + $pos;
if ($pos < 0) $pos = 0;
if ($pos >= count($this->_content)) $pos = count($this->_content) - 1;
@@ -256,7 +263,7 @@ class Doku_Form {
*
* @return string html of the form
*/
- function getForm() {
+ public function getForm() {
global $lang;
$form = '';
$this->params['accept-charset'] = $lang['encoding'];
@@ -286,7 +293,7 @@ class Doku_Form {
*
* wraps around getForm()
*/
- function printForm(){
+ public function printForm(){
echo $this->getForm();
}
@@ -302,7 +309,7 @@ class Doku_Form {
* @author Adrian Lang <lang@cosmocode.de>
*/
- function addRadioSet($name, $entries) {
+ public function addRadioSet($name, $entries) {
global $INPUT;
$value = (array_key_exists($INPUT->post->str($name), $entries)) ?
$INPUT->str($name) : key($entries);
diff --git a/inc/fulltext.php b/inc/fulltext.php
index dba11d0e4..48fe28da2 100644
--- a/inc/fulltext.php
+++ b/inc/fulltext.php
@@ -6,7 +6,7 @@
* @author Andreas Gohr <andi@splitbrain.org>
*/
-if(!defined('DOKU_INC')) die('meh.');
+use dokuwiki\Extension\Event;
/**
* create snippets for the first few results only
@@ -23,8 +23,8 @@ if(!defined('FT_SNIPPET_NUMBER')) define('FT_SNIPPET_NUMBER',15);
* @param string $query
* @param array $highlight
* @param string $sort
- * @param int|string $after only show results with an modified time after this date, accepts timestap or strtotime arguments
- * @param int|string $before only show results with an modified time before this date, accepts timestap or strtotime arguments
+ * @param int|string $after only show results with mtime after this date, accepts timestap or strtotime arguments
+ * @param int|string $before only show results with mtime before this date, accepts timestap or strtotime arguments
*
* @return array
*/
@@ -41,7 +41,7 @@ function ft_pageSearch($query,&$highlight, $sort = null, $after = null, $before
];
$data['highlight'] =& $highlight;
- return trigger_event('SEARCH_QUERY_FULLPAGE', $data, '_ft_pageSearch');
+ return Event::createAndTrigger('SEARCH_QUERY_FULLPAGE', $data, '_ft_pageSearch');
}
/**
@@ -95,9 +95,9 @@ function _ft_pageSearch(&$data) {
'phrase' => $phrase,
'text' => rawWiki($id)
);
- $evt = new Doku_Event('FULLTEXT_PHRASE_MATCH',$evdata);
+ $evt = new Event('FULLTEXT_PHRASE_MATCH',$evdata);
if ($evt->advise_before() && $evt->result !== true) {
- $text = utf8_strtolower($evdata['text']);
+ $text = \dokuwiki\Utf8\PhpString::strtolower($evdata['text']);
if (strpos($text, $phrase) !== false) {
$evt->result = true;
}
@@ -232,8 +232,8 @@ function ft_mediause($id, $ignore_perms = false){
* @param string $id page id
* @param bool $in_ns match against namespace as well?
* @param bool $in_title search in title?
- * @param int|string $after only show results with an modified time after this date, accepts timestap or strtotime arguments
- * @param int|string $before only show results with an modified time before this date, accepts timestap or strtotime arguments
+ * @param int|string $after only show results with mtime after this date, accepts timestap or strtotime arguments
+ * @param int|string $before only show results with mtime before this date, accepts timestap or strtotime arguments
*
* @return string[]
*/
@@ -246,7 +246,7 @@ function ft_pageLookup($id, $in_ns=false, $in_title=false, $after = null, $befor
'before' => $before
];
$data['has_titles'] = true; // for plugin backward compatibility check
- return trigger_event('SEARCH_QUERY_PAGELOOKUP', $data, '_ft_pageLookup');
+ return Event::createAndTrigger('SEARCH_QUERY_PAGELOOKUP', $data, '_ft_pageLookup');
}
/**
@@ -315,8 +315,8 @@ function _ft_pageLookup(&$data){
/**
* @param array $results search results in the form pageid => value
- * @param int|string $after only returns results with an modified time after this date, accepts timestap or strtotime arguments
- * @param int|string $before only returns results with an modified time after this date, accepts timestap or strtotime arguments
+ * @param int|string $after only returns results with mtime after this date, accepts timestap or strtotime arguments
+ * @param int|string $before only returns results with mtime after this date, accepts timestap or strtotime arguments
*
* @return array
*/
@@ -407,15 +407,26 @@ function ft_snippet($id,$highlight){
'snippet' => '',
);
- $evt = new Doku_Event('FULLTEXT_SNIPPET_CREATE',$evdata);
+ $evt = new Event('FULLTEXT_SNIPPET_CREATE',$evdata);
if ($evt->advise_before()) {
$match = array();
$snippets = array();
$utf8_offset = $offset = $end = 0;
- $len = utf8_strlen($text);
+ $len = \dokuwiki\Utf8\PhpString::strlen($text);
// build a regexp from the phrases to highlight
- $re1 = '('.join('|',array_map('ft_snippet_re_preprocess', array_map('preg_quote_cb',array_filter((array) $highlight)))).')';
+ $re1 = '(' .
+ join(
+ '|',
+ array_map(
+ 'ft_snippet_re_preprocess',
+ array_map(
+ 'preg_quote_cb',
+ array_filter((array) $highlight)
+ )
+ )
+ ) .
+ ')';
$re2 = "$re1.{0,75}(?!\\1)$re1";
$re3 = "$re1.{0,45}(?!\\1)$re1.{0,45}(?!\\1)(?!\\2)$re1";
@@ -431,8 +442,8 @@ function ft_snippet($id,$highlight){
list($str,$idx) = $match[0];
// convert $idx (a byte offset) into a utf8 character offset
- $utf8_idx = utf8_strlen(substr($text,0,$idx));
- $utf8_len = utf8_strlen($str);
+ $utf8_idx = \dokuwiki\Utf8\PhpString::strlen(substr($text,0,$idx));
+ $utf8_len = \dokuwiki\Utf8\PhpString::strlen($str);
// establish context, 100 bytes surrounding the match string
// first look to see if we can go 100 either side,
@@ -461,9 +472,9 @@ function ft_snippet($id,$highlight){
$end = $utf8_idx + $utf8_len + $post; // now set it to the end of this context
if ($append) {
- $snippets[count($snippets)-1] .= utf8_substr($text,$append,$end-$append);
+ $snippets[count($snippets)-1] .= \dokuwiki\Utf8\PhpString::substr($text,$append,$end-$append);
} else {
- $snippets[] = utf8_substr($text,$start,$end-$start);
+ $snippets[] = \dokuwiki\Utf8\PhpString::substr($text,$start,$end-$start);
}
// set $offset for next match attempt
@@ -472,13 +483,17 @@ function ft_snippet($id,$highlight){
// this prevents further matching of this snippet but for possible matches of length
// smaller than match length + context (at least 50 characters) this match is part of the context
$utf8_offset = $utf8_idx + $utf8_len;
- $offset = $idx + strlen(utf8_substr($text,$utf8_idx,$utf8_len));
- $offset = utf8_correctIdx($text,$offset);
+ $offset = $idx + strlen(\dokuwiki\Utf8\PhpString::substr($text,$utf8_idx,$utf8_len));
+ $offset = \dokuwiki\Utf8\Clean::correctIdx($text,$offset);
}
$m = "\1";
$snippets = preg_replace('/'.$re1.'/iu',$m.'$1'.$m,$snippets);
- $snippet = preg_replace('/'.$m.'([^'.$m.']*?)'.$m.'/iu','<strong class="search_hit">$1</strong>',hsc(join('... ',$snippets)));
+ $snippet = preg_replace(
+ '/' . $m . '([^' . $m . ']*?)' . $m . '/iu',
+ '<strong class="search_hit">$1</strong>',
+ hsc(join('... ', $snippets))
+ );
$evdata['snippet'] = $snippet;
}
@@ -496,9 +511,7 @@ function ft_snippet($id,$highlight){
*/
function ft_snippet_re_preprocess($term) {
// do not process asian terms where word boundaries are not explicit
- if(preg_match('/'.IDX_ASIAN.'/u',$term)){
- return $term;
- }
+ if(\dokuwiki\Utf8\Asian::isAsianWords($term)) return $term;
if (UTF8_PROPERTYSUPPORT) {
// unicode word boundaries
@@ -659,7 +672,8 @@ function ft_queryParser($Indexer, $query){
*/
$parsed_query = '';
$parens_level = 0;
- $terms = preg_split('/(-?".*?")/u', utf8_strtolower($query), -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
+ $terms = preg_split('/(-?".*?")/u', \dokuwiki\Utf8\PhpString::strtolower($query),
+ -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
foreach ($terms as $term) {
$parsed = '';
@@ -860,9 +874,9 @@ function ft_termParser($Indexer, $term, $consider_asian = true, $phrase_mode = f
$parsed = '';
if ($consider_asian) {
// successive asian characters need to be searched as a phrase
- $words = preg_split('/('.IDX_ASIAN.'+)/u', $term, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
+ $words = \dokuwiki\Utf8\Asian::splitAsianWords($term);
foreach ($words as $word) {
- $phrase_mode = $phrase_mode ? true : preg_match('/'.IDX_ASIAN.'/u', $word);
+ $phrase_mode = $phrase_mode ? true : \dokuwiki\Utf8\Asian::isAsianWords($word);
$parsed .= ft_termParser($Indexer, $word, false, $phrase_mode);
}
} else {
diff --git a/inc/html.php b/inc/html.php
index 4059d1286..773d55364 100644
--- a/inc/html.php
+++ b/inc/html.php
@@ -6,8 +6,11 @@
* @author Andreas Gohr <andi@splitbrain.org>
*/
-if(!defined('DOKU_INC')) die('meh.');
-if(!defined('NL')) define('NL',"\n");
+use dokuwiki\ChangeLog\MediaChangeLog;
+use dokuwiki\ChangeLog\PageChangeLog;
+use dokuwiki\Extension\AuthPlugin;
+use dokuwiki\Extension\Event;
+
if (!defined('SEC_EDIT_PATTERN')) {
define('SEC_EDIT_PATTERN', '#<!-- EDIT({.*?}) -->#');
}
@@ -51,7 +54,13 @@ function html_login($svg = false){
$form->startFieldset($lang['btn_login']);
$form->addHidden('id', $ID);
$form->addHidden('do', 'login');
- $form->addElement(form_makeTextField('u', ((!$INPUT->bool('http_credentials')) ? $INPUT->str('u') : ''), $lang['user'], 'focus__this', 'block'));
+ $form->addElement(form_makeTextField(
+ 'u',
+ ((!$INPUT->bool('http_credentials')) ? $INPUT->str('u') : ''),
+ $lang['user'],
+ 'focus__this',
+ 'block')
+ );
$form->addElement(form_makePasswordField('p', $lang['pass'], '', 'block'));
if($conf['rememberme']) {
$form->addElement(form_makeCheckboxField('r', '1', $lang['remember'], 'remember__me', 'simple'));
@@ -126,7 +135,7 @@ function html_secedit_button($matches){
$data ['target'] = strtolower($data['target']);
$data ['hid'] = strtolower($data['hid']);
- return trigger_event('HTML_SECEDIT_BUTTON', $data,
+ return Event::createAndTrigger('HTML_SECEDIT_BUTTON', $data,
'html_secedit_get_button');
}
@@ -170,7 +179,10 @@ function html_secedit_get_button($data) {
function html_topbtn(){
global $lang;
- $ret = '<a class="nolink" href="#dokuwiki__top"><button class="button" onclick="window.scrollTo(0, 0)" title="'.$lang['btn_top'].'">'.$lang['btn_top'].'</button></a>';
+ $ret = '<a class="nolink" href="#dokuwiki__top">' .
+ '<button class="button" onclick="window.scrollTo(0, 0)" title="' . $lang['btn_top'] . '">' .
+ $lang['btn_top'] .
+ '</button></a>';
return $ret;
}
@@ -288,7 +300,7 @@ function html_show($txt=null){
}else{
if ($REV||$DATE_AT){
$data = array('rev' => &$REV, 'date_at' => &$DATE_AT);
- trigger_event('HTML_SHOWREV_OUTPUT', $data, 'html_showrev');
+ Event::createAndTrigger('HTML_SHOWREV_OUTPUT', $data, 'html_showrev');
}
$html = p_wiki_xhtml($ID,$REV,true,$DATE_AT);
$html = html_secedit($html,$secedit);
@@ -343,7 +355,7 @@ function html_hilight($html,$phrases){
$regex = join('|',$phrases);
if ($regex === '') return $html;
- if (!utf8_check($regex)) return $html;
+ if (!\dokuwiki\Utf8\Clean::isUtf8($regex)) return $html;
$html = @preg_replace_callback("/((<[^>]*)|$regex)/ui",'html_hilight_callback',$html);
return $html;
}
@@ -690,7 +702,9 @@ function html_recent($first = 0, $show_changes = 'both') {
print p_locale_xhtml('recent');
if(getNS($ID) != '') {
- print '<div class="level1"><p>' . sprintf($lang['recent_global'], getNS($ID), wl('', 'do=recent')) . '</p></div>';
+ print '<div class="level1"><p>' .
+ sprintf($lang['recent_global'], getNS($ID), wl('', 'do=recent')) .
+ '</p></div>';
}
$form = new Doku_Form(array('id' => 'dw__recent', 'method' => 'GET', 'class' => 'changes'));
@@ -773,7 +787,14 @@ function html_recent($first = 0, $show_changes = 'both') {
}
if(!empty($recent['media'])) {
- $href = media_managerURL(array('tab_details' => 'history', 'image' => $recent['id'], 'ns' => getNS($recent['id'])), '&');
+ $href = media_managerURL(
+ array(
+ 'tab_details' => 'history',
+ 'image' => $recent['id'],
+ 'ns' => getNS($recent['id'])
+ ),
+ '&'
+ );
} else {
$href = wl($recent['id'], "do=revisions", false, '&');
}
@@ -790,7 +811,14 @@ function html_recent($first = 0, $show_changes = 'both') {
$form->addElement(form_makeCloseTag('a'));
if(!empty($recent['media'])) {
- $href = media_managerURL(array('tab_details' => 'view', 'image' => $recent['id'], 'ns' => getNS($recent['id'])), '&');
+ $href = media_managerURL(
+ array(
+ 'tab_details' => 'view',
+ 'image' => $recent['id'],
+ 'ns' => getNS($recent['id'])
+ ),
+ '&'
+ );
$class = file_exists(mediaFN($recent['id'])) ? 'wikilink1' : 'wikilink2';
$form->addElement(form_makeOpenTag('a', array(
'class' => $class,
@@ -897,14 +925,15 @@ function html_list_index($item){
global $ID, $conf;
// prevent searchbots needlessly following links
- $nofollow = ($ID != $conf['start'] || $conf['sitemap']) ? ' rel="nofollow"' : '';
+ $nofollow = ($ID != $conf['start'] || $conf['sitemap']) ? 'rel="nofollow"' : '';
$ret = '';
$base = ':'.$item['id'];
$base = substr($base,strrpos($base,':')+1);
if($item['type']=='d'){
// FS#2766, no need for search bots to follow namespace links in the index
- $ret .= '<a href="'.wl($ID,'idx='.rawurlencode($item['id'])).'" title="' . $item['id'] . '" class="idx_dir"' . $nofollow . '><strong>';
+ $link = wl($ID, 'idx=' . rawurlencode($item['id']));
+ $ret .= '<a href="' . $link . '" title="' . $item['id'] . '" class="idx_dir" ' . $nofollow . '><strong>';
$ret .= $base;
$ret .= '</strong></a>';
}else{
@@ -1562,12 +1591,12 @@ function html_softbreak_callback($match){
// make certain characters into breaking characters by inserting a
// word break opportunity (<wbr> tag) in front of them.
$regex = <<< REGEX
-(?(?= # start a conditional expression with a positive look ahead ...
-&\#?\\w{1,6};) # ... for html entities - we don't want to split them (ok to catch some invalid combinations)
-&\#?\\w{1,6}; # yes pattern - a quicker match for the html entity, since we know we have one
+(?(?= # start a conditional expression with a positive look ahead ...
+&\#?\\w{1,6};) # ... for html entities - we don't want to split them (ok to catch some invalid combinations)
+&\#?\\w{1,6}; # yes pattern - a quicker match for the html entity, since we know we have one
|
-[?/,&\#;:] # no pattern - any other group of 'special' characters to insert a breaking character after
-)+ # end conditional expression
+[?/,&\#;:] # no pattern - any other group of 'special' characters to insert a breaking character after
+)+ # end conditional expression
REGEX;
return preg_replace('<'.$regex.'>xu','\0<wbr>',$match[0]);
@@ -1643,13 +1672,41 @@ function html_register(){
$form->startFieldset($lang['btn_register']);
$form->addHidden('do', 'register');
$form->addHidden('save', '1');
- $form->addElement(form_makeTextField('login', $INPUT->post->str('login'), $lang['user'], '', 'block', $base_attrs));
+ $form->addElement(
+ form_makeTextField(
+ 'login',
+ $INPUT->post->str('login'),
+ $lang['user'],
+ '',
+ 'block',
+ $base_attrs
+ )
+ );
if (!$conf['autopasswd']) {
$form->addElement(form_makePasswordField('pass', $lang['pass'], '', 'block', $base_attrs));
$form->addElement(form_makePasswordField('passchk', $lang['passchk'], '', 'block', $base_attrs));
}
- $form->addElement(form_makeTextField('fullname', $INPUT->post->str('fullname'), $lang['fullname'], '', 'block', $base_attrs));
- $form->addElement(form_makeField('email','email', $INPUT->post->str('email'), $lang['email'], '', 'block', $email_attrs));
+ $form->addElement(
+ form_makeTextField(
+ 'fullname',
+ $INPUT->post->str('fullname'),
+ $lang['fullname'],
+ '',
+ 'block',
+ $base_attrs
+ )
+ );
+ $form->addElement(
+ form_makeField(
+ 'email',
+ 'email',
+ $INPUT->post->str('email'),
+ $lang['email'],
+ '',
+ 'block',
+ $email_attrs
+ )
+ );
$form->addElement(form_makeButton('submit', '', $lang['btn_register']));
$form->endFieldset();
html_form('register', $form);
@@ -1668,7 +1725,7 @@ function html_updateprofile(){
global $conf;
global $INPUT;
global $INFO;
- /** @var DokuWiki_Auth_Plugin $auth */
+ /** @var AuthPlugin $auth */
global $auth;
print p_locale_xhtml('updateprofile');
@@ -1680,7 +1737,16 @@ function html_updateprofile(){
$form->startFieldset($lang['profile']);
$form->addHidden('do', 'profile');
$form->addHidden('save', '1');
- $form->addElement(form_makeTextField('login', $_SERVER['REMOTE_USER'], $lang['user'], '', 'block', array('size'=>'50', 'disabled'=>'disabled')));
+ $form->addElement(
+ form_makeTextField(
+ 'login',
+ $_SERVER['REMOTE_USER'],
+ $lang['user'],
+ '',
+ 'block',
+ array('size' => '50', 'disabled' => 'disabled')
+ )
+ );
$attr = array('size'=>'50');
if (!$auth->canDo('modName')) $attr['disabled'] = 'disabled';
$form->addElement(form_makeTextField('fullname', $fullname, $lang['fullname'], '', 'block', $attr));
@@ -1694,7 +1760,15 @@ function html_updateprofile(){
}
if ($conf['profileconfirm']) {
$form->addElement(form_makeTag('br'));
- $form->addElement(form_makePasswordField('oldpass', $lang['oldpass'], '', 'block', array('size'=>'50', 'required' => 'required')));
+ $form->addElement(
+ form_makePasswordField(
+ 'oldpass',
+ $lang['oldpass'],
+ '',
+ 'block',
+ array('size' => '50', 'required' => 'required')
+ )
+ );
}
$form->addElement(form_makeButton('submit', '', $lang['btn_save']));
$form->addElement(form_makeButton('reset', '', $lang['btn_reset']));
@@ -1707,10 +1781,27 @@ function html_updateprofile(){
$form_profiledelete->startFieldset($lang['profdeleteuser']);
$form_profiledelete->addHidden('do', 'profile_delete');
$form_profiledelete->addHidden('delete', '1');
- $form_profiledelete->addElement(form_makeCheckboxField('confirm_delete', '1', $lang['profconfdelete'],'dw__confirmdelete','', array('required' => 'required')));
+ $form_profiledelete->addElement(
+ form_makeCheckboxField(
+ 'confirm_delete',
+ '1',
+ $lang['profconfdelete'],
+ 'dw__confirmdelete',
+ '',
+ array('required' => 'required')
+ )
+ );
if ($conf['profileconfirm']) {
$form_profiledelete->addElement(form_makeTag('br'));
- $form_profiledelete->addElement(form_makePasswordField('oldpass', $lang['oldpass'], '', 'block', array('size'=>'50', 'required' => 'required')));
+ $form_profiledelete->addElement(
+ form_makePasswordField(
+ 'oldpass',
+ $lang['oldpass'],
+ '',
+ 'block',
+ array('size' => '50', 'required' => 'required')
+ )
+ );
}
$form_profiledelete->addElement(form_makeButton('submit', '', $lang['btn_deleteuser']));
$form_profiledelete->endFieldset();
@@ -1783,7 +1874,7 @@ function html_edit(){
if ($data['target'] !== 'section') {
// Only emit event if page is writable, section edit data is valid and
// edit target is not section.
- trigger_event('HTML_EDIT_FORMSELECTION', $data, 'html_edit_form', true);
+ Event::createAndTrigger('HTML_EDIT_FORMSELECTION', $data, 'html_edit_form', true);
} else {
html_edit_form($data);
}
@@ -1803,12 +1894,35 @@ function html_edit(){
$form->addElement(form_makeCloseTag('div'));
if ($wr) {
$form->addElement(form_makeOpenTag('div', array('class'=>'editButtons')));
- $form->addElement(form_makeButton('submit', 'save', $lang['btn_save'], array('id'=>'edbtn__save', 'accesskey'=>'s', 'tabindex'=>'4')));
- $form->addElement(form_makeButton('submit', 'preview', $lang['btn_preview'], array('id'=>'edbtn__preview', 'accesskey'=>'p', 'tabindex'=>'5')));
+ $form->addElement(
+ form_makeButton(
+ 'submit',
+ 'save',
+ $lang['btn_save'],
+ array('id' => 'edbtn__save', 'accesskey' => 's', 'tabindex' => '4')
+ )
+ );
+ $form->addElement(
+ form_makeButton(
+ 'submit',
+ 'preview',
+ $lang['btn_preview'],
+ array('id' => 'edbtn__preview', 'accesskey' => 'p', 'tabindex' => '5')
+ )
+ );
$form->addElement(form_makeButton('submit', 'cancel', $lang['btn_cancel'], array('tabindex'=>'6')));
$form->addElement(form_makeCloseTag('div'));
$form->addElement(form_makeOpenTag('div', array('class'=>'summary')));
- $form->addElement(form_makeTextField('summary', $SUM, $lang['summary'], 'edit__summary', 'nowrap', array('size'=>'50', 'tabindex'=>'2')));
+ $form->addElement(
+ form_makeTextField(
+ 'summary',
+ $SUM,
+ $lang['summary'],
+ 'edit__summary',
+ 'nowrap',
+ array('size' => '50', 'tabindex' => '2')
+ )
+ );
$elem = html_minoredit();
if ($elem) $form->addElement($elem);
$form->addElement(form_makeCloseTag('div'));
@@ -1833,8 +1947,12 @@ function html_edit(){
<div class="editBox" role="application">
<div class="toolbar group">
- <div id="tool__bar" class="tool__bar"><?php if ($wr && $data['media_manager']){?><a href="<?php echo DOKU_BASE?>lib/exe/mediamanager.php?ns=<?php echo $INFO['namespace']?>"
- target="_blank"><?php echo $lang['mediaselect'] ?></a><?php }?></div>
+ <div id="tool__bar" class="tool__bar"><?php
+ if ($wr && $data['media_manager']){
+ ?><a href="<?php echo DOKU_BASE?>lib/exe/mediamanager.php?ns=<?php echo $INFO['namespace']?>"
+ target="_blank"><?php echo $lang['mediaselect'] ?></a><?php
+ }?>
+ </div>
</div>
<div id="draft__status" class="draft__status">
<?php
@@ -1900,7 +2018,7 @@ function html_minoredit(){
function html_debug(){
global $conf;
global $lang;
- /** @var DokuWiki_Auth_Plugin $auth */
+ /** @var AuthPlugin $auth */
global $auth;
global $INFO;
@@ -2105,7 +2223,7 @@ function html_mktocitem($link, $text, $level, $hash='#'){
function html_form($name, &$form) {
// Safety check in case the caller forgets.
$form->endFieldset();
- trigger_event('HTML_'.strtoupper($name).'FORM_OUTPUT', $form, 'html_form_output', false);
+ Event::createAndTrigger('HTML_'.strtoupper($name).'FORM_OUTPUT', $form, 'html_form_output', false);
}
/**
diff --git a/inc/indexer.php b/inc/indexer.php
index e0acb2ac2..f2c8a9aa8 100644
--- a/inc/indexer.php
+++ b/inc/indexer.php
@@ -7,7 +7,7 @@
* @author Tom N Harris <tnharris@whoopdedo.org>
*/
-if(!defined('DOKU_INC')) die('meh.');
+use dokuwiki\Extension\Event;
// Version tag used to force rebuild on upgrade
define('INDEXER_VERSION', 8);
@@ -15,41 +15,6 @@ define('INDEXER_VERSION', 8);
// set the minimum token length to use in the index (note, this doesn't apply to numeric tokens)
if (!defined('IDX_MINWORDLENGTH')) define('IDX_MINWORDLENGTH',2);
-// Asian characters are handled as words. The following regexp defines the
-// Unicode-Ranges for Asian characters
-// Ranges taken from http://en.wikipedia.org/wiki/Unicode_block
-// I'm no language expert. If you think some ranges are wrongly chosen or
-// a range is missing, please contact me
-define('IDX_ASIAN1','[\x{0E00}-\x{0E7F}]'); // Thai
-define('IDX_ASIAN2','['.
- '\x{2E80}-\x{3040}'. // CJK -> Hangul
- '\x{309D}-\x{30A0}'.
- '\x{30FD}-\x{31EF}\x{3200}-\x{D7AF}'.
- '\x{F900}-\x{FAFF}'. // CJK Compatibility Ideographs
- '\x{FE30}-\x{FE4F}'. // CJK Compatibility Forms
- "\xF0\xA0\x80\x80-\xF0\xAA\x9B\x9F". // CJK Extension B
- "\xF0\xAA\x9C\x80-\xF0\xAB\x9C\xBF". // CJK Extension C
- "\xF0\xAB\x9D\x80-\xF0\xAB\xA0\x9F". // CJK Extension D
- "\xF0\xAF\xA0\x80-\xF0\xAF\xAB\xBF". // CJK Compatibility Supplement
- ']');
-define('IDX_ASIAN3','['. // Hiragana/Katakana (can be two characters)
- '\x{3042}\x{3044}\x{3046}\x{3048}'.
- '\x{304A}-\x{3062}\x{3064}-\x{3082}'.
- '\x{3084}\x{3086}\x{3088}-\x{308D}'.
- '\x{308F}-\x{3094}'.
- '\x{30A2}\x{30A4}\x{30A6}\x{30A8}'.
- '\x{30AA}-\x{30C2}\x{30C4}-\x{30E2}'.
- '\x{30E4}\x{30E6}\x{30E8}-\x{30ED}'.
- '\x{30EF}-\x{30F4}\x{30F7}-\x{30FA}'.
- ']['.
- '\x{3041}\x{3043}\x{3045}\x{3047}\x{3049}'.
- '\x{3063}\x{3083}\x{3085}\x{3087}\x{308E}\x{3095}-\x{309C}'.
- '\x{30A1}\x{30A3}\x{30A5}\x{30A7}\x{30A9}'.
- '\x{30C3}\x{30E3}\x{30E5}\x{30E7}\x{30EE}\x{30F5}\x{30F6}\x{30FB}\x{30FC}'.
- '\x{31F0}-\x{31FF}'.
- ']?');
-define('IDX_ASIAN', '(?:'.IDX_ASIAN1.'|'.IDX_ASIAN2.'|'.IDX_ASIAN3.')');
-
/**
* Version of the indexer taking into consideration the external tokenizer.
* The indexer is only compatible with data written by the same version.
@@ -71,7 +36,7 @@ function idx_get_version(){
// DokuWiki version is included for the convenience of plugins
$data = array('dokuwiki'=>$version);
- trigger_event('INDEXER_VERSION_GET', $data, null, false);
+ Event::createAndTrigger('INDEXER_VERSION_GET', $data, null, false);
unset($data['dokuwiki']); // this needs to be first
ksort($data);
foreach ($data as $plugin=>$vers)
@@ -403,7 +368,7 @@ class Doku_Indexer {
*
* @param string $key The metadata key of which a value shall be changed
* @param string $oldvalue The old value that shall be renamed
- * @param string $newvalue The new value to which the old value shall be renamed, can exist (then values will be merged)
+ * @param string $newvalue The new value to which the old value shall be renamed, if exists values will be merged
* @return bool|string If renaming the value has been successful, false or error message on error.
*/
public function renameMetaValue($key, $oldvalue, $newvalue) {
@@ -587,12 +552,10 @@ class Doku_Indexer {
$stopwords =& idx_get_stopwords();
// prepare the text to be tokenized
- $evt = new Doku_Event('INDEXER_TEXT_PREPARE', $text);
+ $evt = new Event('INDEXER_TEXT_PREPARE', $text);
if ($evt->advise_before(true)) {
if (preg_match('/[^0-9A-Za-z ]/u', $text)) {
- // handle asian chars as single words (may fail on older PHP version)
- $asia = @preg_replace('/('.IDX_ASIAN.')/u', ' \1 ', $text);
- if (!is_null($asia)) $text = $asia; // recover from regexp falure
+ $text = \dokuwiki\Utf8\Asian::separateAsianWords($text);
}
}
$evt->advise_after();
@@ -607,12 +570,12 @@ class Doku_Indexer {
)
);
if (preg_match('/[^0-9A-Za-z ]/u', $text))
- $text = utf8_stripspecials($text, ' ', '\._\-:'.$wc);
+ $text = \dokuwiki\Utf8\Clean::stripspecials($text, ' ', '\._\-:'.$wc);
$wordlist = explode(' ', $text);
foreach ($wordlist as $i => $word) {
$wordlist[$i] = (preg_match('/[^0-9A-Za-z]/u', $word)) ?
- utf8_strtolower($word) : strtolower($word);
+ \dokuwiki\Utf8\PhpString::strtolower($word) : strtolower($word);
}
foreach ($wordlist as $i => $word) {
@@ -1425,7 +1388,7 @@ function idx_addPage($page, $verbose=false, $force=false) {
$metadata['relation_media'] = array();
$data = compact('page', 'body', 'metadata', 'pid');
- $evt = new Doku_Event('INDEXER_PAGE_ADD', $data);
+ $evt = new Event('INDEXER_PAGE_ADD', $data);
if ($evt->advise_before()) $data['body'] = $data['body'] . " " . rawWiki($page);
$evt->advise_after();
unset($evt);
@@ -1521,7 +1484,10 @@ function idx_listIndexLengths() {
clearstatcache();
if (file_exists($conf['indexdir'].'/lengths.idx')
&& (time() < @filemtime($conf['indexdir'].'/lengths.idx') + $conf['readdircache'])) {
- if (($lengths = @file($conf['indexdir'].'/lengths.idx', FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES)) !== false) {
+ if (
+ ($lengths = @file($conf['indexdir'].'/lengths.idx', FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES))
+ !== false
+ ) {
$idx = array();
foreach ($lengths as $length) {
$idx[] = (int)$length;
@@ -1602,7 +1568,7 @@ function idx_indexLengths($filter) {
* @return string
*/
function idx_cleanName($name) {
- $name = utf8_romanize(trim((string)$name));
+ $name = \dokuwiki\Utf8\Clean::romanize(trim((string)$name));
$name = preg_replace('#[ \./\\:-]+#', '_', $name);
$name = preg_replace('/[^A-Za-z0-9_]/', '', $name);
return strtolower($name);
diff --git a/inc/infoutils.php b/inc/infoutils.php
index efed33041..771d5845b 100644
--- a/inc/infoutils.php
+++ b/inc/infoutils.php
@@ -5,7 +5,8 @@
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
* @author Andreas Gohr <andi@splitbrain.org>
*/
-if(!defined('DOKU_INC')) die('meh.');
+
+use dokuwiki\HTTP\DokuHTTPClient;
if(!defined('DOKU_MESSAGEURL')){
if(in_array('ssl', stream_get_transports())) {
@@ -135,16 +136,19 @@ function check(){
$mem = (int) php_to_byte(ini_get('memory_limit'));
if($mem){
- if($mem === -1) {
+ if ($mem === -1) {
msg('PHP memory is unlimited', 1);
- } else if($mem < 16777216){
- msg('PHP is limited to less than 16MB RAM ('.filesize_h($mem).'). Increase memory_limit in php.ini',-1);
- } else if($mem < 20971520){
- msg('PHP is limited to less than 20MB RAM ('.filesize_h($mem).'), you might encounter problems with bigger pages. Increase memory_limit in php.ini',-1);
- } else if($mem < 33554432){
- msg('PHP is limited to less than 32MB RAM ('.filesize_h($mem).'), but that should be enough in most cases. If not, increase memory_limit in php.ini',0);
+ } else if ($mem < 16777216) {
+ msg('PHP is limited to less than 16MB RAM (' . filesize_h($mem) . ').
+ Increase memory_limit in php.ini', -1);
+ } else if ($mem < 20971520) {
+ msg('PHP is limited to less than 20MB RAM (' . filesize_h($mem) . '),
+ you might encounter problems with bigger pages. Increase memory_limit in php.ini', -1);
+ } else if ($mem < 33554432) {
+ msg('PHP is limited to less than 32MB RAM (' . filesize_h($mem) . '),
+ but that should be enough in most cases. If not, increase memory_limit in php.ini', 0);
} else {
- msg('More than 32MB RAM ('.filesize_h($mem).') available.',1);
+ msg('More than 32MB RAM (' . filesize_h($mem) . ') available.', 1);
}
}
@@ -210,7 +214,8 @@ function check(){
if(!$loc){
msg('No valid locale is set for your PHP setup. You should fix this',-1);
}elseif(stripos($loc,'utf') === false){
- msg('Your locale <code>'.hsc($loc).'</code> seems not to be a UTF-8 locale, you should fix this if you encounter problems.',0);
+ msg('Your locale <code>'.hsc($loc).'</code> seems not to be a UTF-8 locale,
+ you should fix this if you encounter problems.',0);
}else{
msg('Valid locale '.hsc($loc).' found.', 1);
}
@@ -290,7 +295,8 @@ function check(){
if(abs($diff) < 4) {
msg("Server time seems to be okay. Diff: {$diff}s", 1);
} else {
- msg("Your server's clock seems to be out of sync! Consider configuring a sync with a NTP server. Diff: {$diff}s");
+ msg("Your server's clock seems to be out of sync!
+ Consider configuring a sync with a NTP server. Diff: {$diff}s");
}
}
@@ -336,7 +342,7 @@ function msg($message,$lvl=0,$line='',$file='',$allow=MSG_PUBLIC){
$errors[1] = 'success';
$errors[2] = 'notify';
- if($line || $file) $message.=' ['.utf8_basename($file).':'.$line.']';
+ if($line || $file) $message.=' ['.\dokuwiki\Utf8\PhpString::basename($file).':'.$line.']';
if(!isset($MSG)) $MSG = array();
$MSG[]=array('lvl' => $errors[$lvl], 'msg' => $message, 'allow' => $allow);
@@ -380,7 +386,8 @@ function info_msg_allowed($msg){
return $INFO['isadmin'];
default:
- trigger_error('invalid msg allow restriction. msg="'.$msg['msg'].'" allow='.$msg['allow'].'"', E_USER_WARNING);
+ trigger_error('invalid msg allow restriction. msg="'.$msg['msg'].'" allow='.$msg['allow'].'"',
+ E_USER_WARNING);
return $INFO['isadmin'];
}
@@ -446,37 +453,7 @@ function dbglog($msg,$header=''){
* @triggers INFO_DEPRECATION_LOG
*/
function dbg_deprecated($alternative = '') {
- global $conf;
- global $EVENT_HANDLER;
- if(!$conf['allowdebug'] && !$EVENT_HANDLER->hasHandlerForEvent('INFO_DEPRECATION_LOG')) {
- // avoid any work if no one cares
- return;
- }
-
- $backtrace = debug_backtrace();
- array_shift($backtrace);
- $self = $backtrace[0];
- $call = $backtrace[1];
-
- $data = [
- 'trace' => $backtrace,
- 'alternative' => $alternative,
- 'called' => trim($self['class'] . '::' . $self['function'] . '()', ':'),
- 'caller' => trim($call['class'] . '::' . $call['function'] . '()', ':'),
- 'file' => $call['file'],
- 'line' => $call['line'],
- ];
-
- $event = new Doku_Event('INFO_DEPRECATION_LOG', $data);
- if($event->advise_before()) {
- $msg = $event->data['called'] . ' is deprecated. It was called from ';
- $msg .= $event->data['caller'] . ' in ' . $event->data['file'] . ':' . $event->data['line'];
- if($event->data['alternative']) {
- $msg .= ' ' . $event->data['alternative'] . ' should be used instead!';
- }
- dbglog($msg);
- }
- $event->advise_after();
+ \dokuwiki\Debug\DebugHelper::dbgDeprecatedFunction($alternative, 2);
}
/**
diff --git a/inc/init.php b/inc/init.php
index 931b8d31a..548ac80db 100644
--- a/inc/init.php
+++ b/inc/init.php
@@ -3,6 +3,8 @@
* Initialize some defaults needed for DokuWiki
*/
+use dokuwiki\Extension\Event;
+use dokuwiki\Extension\EventHandler;
/**
* timing Dokuwiki execution
@@ -104,6 +106,7 @@ if(!defined('DOKU_BASE')){
}
// define whitespace
+if(!defined('NL')) define ('NL',"\n");
if(!defined('DOKU_LF')) define ('DOKU_LF',"\n");
if(!defined('DOKU_TAB')) define ('DOKU_TAB',"\t");
@@ -111,9 +114,9 @@ if(!defined('DOKU_TAB')) define ('DOKU_TAB',"\t");
if (!defined('DOKU_COOKIE')) {
$serverPort = isset($_SERVER['SERVER_PORT']) ? $_SERVER['SERVER_PORT'] : '';
define('DOKU_COOKIE', 'DW' . md5(DOKU_REL . (($conf['securecookie']) ? $serverPort : '')));
+ unset($serverPort);
}
-
// define main script
if(!defined('DOKU_SCRIPT')) define('DOKU_SCRIPT','doku.php');
@@ -189,9 +192,8 @@ init_paths();
init_files();
// setup plugin controller class (can be overwritten in preload.php)
-$plugin_types = array('auth', 'admin','syntax','action','renderer', 'helper','remote');
global $plugin_controller_class, $plugin_controller;
-if (empty($plugin_controller_class)) $plugin_controller_class = 'Doku_Plugin_Controller';
+if (empty($plugin_controller_class)) $plugin_controller_class = dokuwiki\Extension\PluginController::class;
// load libraries
require_once(DOKU_INC.'vendor/autoload.php');
@@ -209,17 +211,17 @@ if($conf['compression'] == 'gz' && !DOKU_HAS_GZIP) {
// input handle class
global $INPUT;
-$INPUT = new Input();
+$INPUT = new \dokuwiki\Input\Input();
// initialize plugin controller
$plugin_controller = new $plugin_controller_class();
// initialize the event handler
global $EVENT_HANDLER;
-$EVENT_HANDLER = new Doku_Event_Handler();
+$EVENT_HANDLER = new EventHandler();
$local = $conf['lang'];
-trigger_event('INIT_LANG_LOAD', $local, 'init_lang', true);
+Event::createAndTrigger('INIT_LANG_LOAD', $local, 'init_lang', true);
// setup authentication system
@@ -241,7 +243,13 @@ mail_setup();
function init_session() {
global $conf;
session_name(DOKU_SESSION_NAME);
- session_set_cookie_params(DOKU_SESSION_LIFETIME, DOKU_SESSION_PATH, DOKU_SESSION_DOMAIN, ($conf['securecookie'] && is_ssl()), true);
+ session_set_cookie_params(
+ DOKU_SESSION_LIFETIME,
+ DOKU_SESSION_PATH,
+ DOKU_SESSION_DOMAIN,
+ ($conf['securecookie'] && is_ssl()),
+ true
+ );
// make sure the session cookie contains a valid session ID
if(isset($_COOKIE[DOKU_SESSION_NAME]) && !preg_match('/^[-,a-zA-Z0-9]{22,256}$/', $_COOKIE[DOKU_SESSION_NAME])) {
@@ -280,7 +288,9 @@ function init_paths(){
}
// path to old changelog only needed for upgrading
- $conf['changelog_old'] = init_path((isset($conf['changelog']))?($conf['changelog']):($conf['savedir'].'/changes.log'));
+ $conf['changelog_old'] = init_path(
+ (isset($conf['changelog'])) ? ($conf['changelog']) : ($conf['savedir'] . '/changes.log')
+ );
if ($conf['changelog_old']=='') { unset($conf['changelog_old']); }
// hardcoded changelog because it is now a cache that lives in meta
$conf['changelog'] = $conf['metadir'].'/_dokuwiki.changes';
@@ -449,7 +459,7 @@ function getBaseURL($abs=null){
//finish here for relative URLs
if(!$abs) return $dir;
- //use config option if available, trim any slash from end of baseurl to avoid multiple consecutive slashes in the path
+ //use config if available, trim any slash from end of baseurl to avoid multiple consecutive slashes in the path
if(!empty($conf['baseurl'])) return rtrim($conf['baseurl'],'/').$dir;
//split hostheader into host and port
diff --git a/inc/io.php b/inc/io.php
index 0ab1d560a..18aae25e7 100644
--- a/inc/io.php
+++ b/inc/io.php
@@ -6,7 +6,8 @@
* @author Andreas Gohr <andi@splitbrain.org>
*/
-if(!defined('DOKU_INC')) die('meh.');
+use dokuwiki\HTTP\DokuHTTPClient;
+use dokuwiki\Extension\Event;
/**
* Removes empty directories
@@ -39,7 +40,7 @@ function io_sweepNS($id,$basedir='datadir'){
if ($ns_type!==false) {
$data = array($id, $ns_type);
$delone = true; // we deleted at least one dir
- trigger_event('IO_NAMESPACE_DELETED', $data);
+ Event::createAndTrigger('IO_NAMESPACE_DELETED', $data);
}
} else { return $delone; }
}
@@ -69,7 +70,7 @@ function io_sweepNS($id,$basedir='datadir'){
function io_readWikiPage($file, $id, $rev=false) {
if (empty($rev)) { $rev = false; }
$data = array(array($file, true), getNS($id), noNS($id), $rev);
- return trigger_event('IO_WIKIPAGE_READ', $data, '_io_readWikiPage_action', false);
+ return Event::createAndTrigger('IO_WIKIPAGE_READ', $data, '_io_readWikiPage_action', false);
}
/**
@@ -189,7 +190,7 @@ function io_writeWikiPage($file, $content, $id, $rev=false) {
if (empty($rev)) { $rev = false; }
if ($rev===false) { io_createNamespace($id); } // create namespaces as needed
$data = array(array($file, $content, false), getNS($id), noNS($id), $rev);
- return trigger_event('IO_WIKIPAGE_WRITE', $data, '_io_writeWikiPage_action', false);
+ return Event::createAndTrigger('IO_WIKIPAGE_WRITE', $data, '_io_writeWikiPage_action', false);
}
/**
@@ -469,7 +470,7 @@ function io_createNamespace($id, $ns_type='pages') {
$missing = array_reverse($missing); // inside out
foreach ($missing as $ns) {
$data = array($ns, $ns_type);
- trigger_event('IO_NAMESPACE_CREATED', $data);
+ Event::createAndTrigger('IO_NAMESPACE_CREATED', $data);
}
}
@@ -598,7 +599,8 @@ function io_mktmpdir() {
*
* @param string $url url to download
* @param string $file path to file or directory where to save
- * @param bool $useAttachment if true: try to use name of download, uses otherwise $defaultName, false: uses $file as path to file
+ * @param bool $useAttachment true: try to use name of download, uses otherwise $defaultName
+ * false: uses $file as path to file
* @param string $defaultName fallback for if using $useAttachment
* @param int $maxSize maximum file size
* @return bool|string if failed false, otherwise true or the name of the file in the given dir
@@ -621,7 +623,7 @@ function io_download($url,$file,$useAttachment=false,$defaultName='',$maxSize=20
if (is_string($content_disposition) &&
preg_match('/attachment;\s*filename\s*=\s*"([^"]*)"/i', $content_disposition, $match)) {
- $name = utf8_basename($match[1]);
+ $name = \dokuwiki\Utf8\PhpString::basename($match[1]);
}
}
diff --git a/inc/lang/az/wordblock.txt b/inc/lang/az/wordblock.txt
deleted file mode 100644
index ec8b102af..000000000
--- a/inc/lang/az/wordblock.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-====== SPAM-ın qarşısı alındı ======
-
-Sizin dəyişiklər **yaddaşa saxlanmadı**, çünki onların içində bir və ya daha çox içazəsiz sözlər var idi. Əgər siz wiki-yə spam əlavə etmək istəyirdinizsə, onda utanmırsız?! Əgər siz bunu səhv hesab edirsinizsə, onda administrator ilə əlaqə saxlayın.
diff --git a/inc/lang/be/wordblock.txt b/inc/lang/be/wordblock.txt
deleted file mode 100644
index a92d7524e..000000000
--- a/inc/lang/be/wordblock.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-====== СПАМ заблакаваны ======
-
-Вашы змены **не** захаваны, так як яны ўтрымліваюць адзін ці больш забароненых слоў. Калі Вы спрабавалі дадаць спам у Вікі -- ай-яй-яй! Калі Вы лічыце, што гэта нейкая памылка, звярніцеся да адміністратара вікі.
diff --git a/inc/lang/gl/wordblock.txt b/inc/lang/gl/wordblock.txt
deleted file mode 100644
index 686aea36c..000000000
--- a/inc/lang/gl/wordblock.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-====== Bloqueo por Correo-lixo ======
-
-Os teus trocos **non** foron gardados porque conteñen unha ou varias verbas bloqueadas. Se tentaches deixar correo-lixo no wiki -- Estívoche ben! Se consideras que é un erro, contacta co administrador deste Wiki.
diff --git a/inc/lang/ru/wordblock.txt b/inc/lang/ru/wordblock.txt
deleted file mode 100644
index 09c663fb3..000000000
--- a/inc/lang/ru/wordblock.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-====== СПАМ заблокирован ======
-
-Ваши изменения **не были** сохранены, так как они содержат одно или более запрещенных слов. Если Вы пытались добавить спам в Вики -- ай-яй-яй! Если Вы считаете, что это какая-то ошибка, обратитесь к администратору вики.
diff --git a/inc/legacy.php b/inc/legacy.php
new file mode 100644
index 000000000..fa72649b7
--- /dev/null
+++ b/inc/legacy.php
@@ -0,0 +1,18 @@
+<?php
+/**
+ * We map legacy class names to the new namespaced versions here
+ *
+ * These are names that we will probably never change because they have been part of DokuWiki's
+ * public interface for years and renaming would break just too many plugins
+ */
+
+class_alias('\dokuwiki\Extension\EventHandler', 'Doku_Event_Handler');
+class_alias('\dokuwiki\Extension\Event', 'Doku_Event');
+
+class_alias('\dokuwiki\Extension\ActionPlugin', 'DokuWiki_Action_Plugin');
+class_alias('\dokuwiki\Extension\AdminPlugin', 'DokuWiki_Admin_Plugin');
+class_alias('\dokuwiki\Extension\AuthPlugin', 'DokuWiki_Auth_Plugin');
+class_alias('\dokuwiki\Extension\CLIPlugin', 'DokuWiki_CLI_Plugin');
+class_alias('\dokuwiki\Extension\Plugin', 'DokuWiki_Plugin');
+class_alias('\dokuwiki\Extension\RemotePlugin', 'DokuWiki_Remote_Plugin');
+class_alias('\dokuwiki\Extension\SyntaxPlugin', 'DokuWiki_Syntax_Plugin');
diff --git a/inc/load.php b/inc/load.php
index 2131b9d62..f4b15af27 100644
--- a/inc/load.php
+++ b/inc/load.php
@@ -5,6 +5,8 @@
* @author Andreas Gohr <andi@splitbrain.org>
*/
+use dokuwiki\Extension\PluginController;
+
// setup class autoloader
spl_autoload_register('load_autoload');
@@ -15,7 +17,6 @@ require_once(DOKU_INC.'inc/changelog.php');
require_once(DOKU_INC.'inc/common.php');
require_once(DOKU_INC.'inc/confutils.php');
require_once(DOKU_INC.'inc/pluginutils.php');
-require_once(DOKU_INC.'inc/events.php');
require_once(DOKU_INC.'inc/form.php');
require_once(DOKU_INC.'inc/fulltext.php');
require_once(DOKU_INC.'inc/html.php');
@@ -28,12 +29,13 @@ require_once(DOKU_INC.'inc/media.php');
require_once(DOKU_INC.'inc/pageutils.php');
require_once(DOKU_INC.'inc/parserutils.php');
require_once(DOKU_INC.'inc/search.php');
-require_once(DOKU_INC.'inc/subscription.php');
require_once(DOKU_INC.'inc/template.php');
require_once(DOKU_INC.'inc/toolbar.php');
require_once(DOKU_INC.'inc/utf8.php');
require_once(DOKU_INC.'inc/auth.php');
require_once(DOKU_INC.'inc/compatibility.php');
+require_once(DOKU_INC.'inc/deprecated.php');
+require_once(DOKU_INC.'inc/legacy.php');
/**
* spl_autoload_register callback
@@ -50,10 +52,7 @@ require_once(DOKU_INC.'inc/compatibility.php');
*/
function load_autoload($name){
static $classes = null;
- if(is_null($classes)) $classes = array(
- 'DokuHTTPClient' => DOKU_INC.'inc/HTTPClient.php',
- 'HTTPClient' => DOKU_INC.'inc/HTTPClient.php',
- 'JSON' => DOKU_INC.'inc/JSON.php',
+ if($classes === null) $classes = array(
'Diff' => DOKU_INC.'inc/DifferenceEngine.php',
'UnifiedDiffFormatter' => DOKU_INC.'inc/DifferenceEngine.php',
'TableDiffFormatter' => DOKU_INC.'inc/DifferenceEngine.php',
@@ -61,8 +60,6 @@ function load_autoload($name){
'cache_parser' => DOKU_INC.'inc/cache.php',
'cache_instructions' => DOKU_INC.'inc/cache.php',
'cache_renderer' => DOKU_INC.'inc/cache.php',
- 'Doku_Event' => DOKU_INC.'inc/events.php',
- 'Doku_Event_Handler' => DOKU_INC.'inc/events.php',
'Input' => DOKU_INC.'inc/Input.class.php',
'JpegMeta' => DOKU_INC.'inc/JpegMeta.php',
'SimplePie' => DOKU_INC.'inc/SimplePie.php',
@@ -71,29 +68,11 @@ function load_autoload($name){
'IXR_Client' => DOKU_INC.'inc/IXR_Library.php',
'IXR_Error' => DOKU_INC.'inc/IXR_Library.php',
'IXR_IntrospectionServer' => DOKU_INC.'inc/IXR_Library.php',
- 'Doku_Plugin_Controller'=> DOKU_INC.'inc/plugincontroller.class.php',
- 'Doku_Parser_Mode' => DOKU_INC.'inc/parser/parser.php',
- 'Doku_Parser_Mode_Plugin' => DOKU_INC.'inc/parser/parser.php',
'SafeFN' => DOKU_INC.'inc/SafeFN.class.php',
'Sitemapper' => DOKU_INC.'inc/Sitemapper.php',
- 'PassHash' => DOKU_INC.'inc/PassHash.class.php',
'Mailer' => DOKU_INC.'inc/Mailer.class.php',
- 'RemoteAPI' => DOKU_INC.'inc/remote.php',
- 'RemoteAPICore' => DOKU_INC.'inc/RemoteAPICore.php',
- 'Subscription' => DOKU_INC.'inc/subscription.php',
-
- 'DokuWiki_PluginInterface' => DOKU_INC.'inc/PluginInterface.php',
- 'DokuWiki_PluginTrait' => DOKU_INC.'inc/PluginTrait.php',
- 'DokuWiki_Plugin' => DOKU_INC.'inc/Plugin.php',
-
-
- 'DokuWiki_Action_Plugin' => DOKU_PLUGIN.'action.php',
- 'DokuWiki_Admin_Plugin' => DOKU_PLUGIN.'admin.php',
- 'DokuWiki_Syntax_Plugin' => DOKU_PLUGIN.'syntax.php',
- 'DokuWiki_Remote_Plugin' => DOKU_PLUGIN.'remote.php',
- 'DokuWiki_Auth_Plugin' => DOKU_PLUGIN.'auth.php',
- 'DokuWiki_CLI_Plugin' => DOKU_PLUGIN.'cli.php',
+ 'Doku_Handler' => DOKU_INC.'inc/parser/handler.php',
'Doku_Renderer' => DOKU_INC.'inc/parser/renderer.php',
'Doku_Renderer_xhtml' => DOKU_INC.'inc/parser/xhtml.php',
'Doku_Renderer_code' => DOKU_INC.'inc/parser/code.php',
@@ -114,8 +93,17 @@ function load_autoload($name){
// namespace to directory conversion
$name = str_replace('\\', '/', $name);
+ // test namespace
+ if(substr($name, 0, 14) === 'dokuwiki/test/') {
+ $file = DOKU_INC . '_test/' . substr($name, 14) . '.php';
+ if(file_exists($file)) {
+ require $file;
+ return true;
+ }
+ }
+
// plugin namespace
- if(substr($name, 0, 16) == 'dokuwiki/plugin/') {
+ if(substr($name, 0, 16) === 'dokuwiki/plugin/') {
$name = str_replace('/test/', '/_test/', $name); // no underscore in test namespace
$file = DOKU_PLUGIN . substr($name, 16) . '.php';
if(file_exists($file)) {
@@ -125,7 +113,7 @@ function load_autoload($name){
}
// template namespace
- if(substr($name, 0, 18) == 'dokuwiki/template/') {
+ if(substr($name, 0, 18) === 'dokuwiki/template/') {
$name = str_replace('/test/', '/_test/', $name); // no underscore in test namespace
$file = DOKU_INC.'lib/tpl/' . substr($name, 18) . '.php';
if(file_exists($file)) {
@@ -135,7 +123,7 @@ function load_autoload($name){
}
// our own namespace
- if(substr($name, 0, 9) == 'dokuwiki/') {
+ if(substr($name, 0, 9) === 'dokuwiki/') {
$file = DOKU_INC . 'inc/' . substr($name, 9) . '.php';
if(file_exists($file)) {
require $file;
@@ -144,8 +132,13 @@ function load_autoload($name){
}
// Plugin loading
- if(preg_match('/^(auth|helper|syntax|action|admin|renderer|remote|cli)_plugin_('.DOKU_PLUGIN_NAME_REGEX.')(?:_([^_]+))?$/',
- $name, $m)) {
+ if(preg_match(
+ '/^(' . implode('|', PluginController::PLUGIN_TYPES) . ')_plugin_(' .
+ DOKU_PLUGIN_NAME_REGEX .
+ ')(?:_([^_]+))?$/',
+ $name,
+ $m
+ )) {
// try to load the wanted plugin file
$c = ((count($m) === 4) ? "/{$m[3]}" : '');
$plg = DOKU_PLUGIN . "{$m[2]}/{$m[1]}$c.php";
diff --git a/inc/mail.php b/inc/mail.php
index f72dbdeec..12a669dbe 100644
--- a/inc/mail.php
+++ b/inc/mail.php
@@ -6,10 +6,10 @@
* @author Andreas Gohr <andi@splitbrain.org>
*/
-if(!defined('DOKU_INC')) die('meh.');
-
// end of line for mail lines - RFC822 says CRLF but postfix (and other MTAs?)
// think different
+use dokuwiki\Extension\Event;
+
if(!defined('MAILHEADER_EOL')) define('MAILHEADER_EOL',"\n");
#define('MAILHEADER_ASCIIONLY',1);
@@ -27,7 +27,10 @@ if(!defined('MAILHEADER_EOL')) define('MAILHEADER_EOL',"\n");
* Check if a given mail address is valid
*/
if (!defined('RFC2822_ATEXT')) define('RFC2822_ATEXT',"0-9a-zA-Z!#$%&'*+/=?^_`{|}~-");
-if (!defined('PREG_PATTERN_VALID_EMAIL')) define('PREG_PATTERN_VALID_EMAIL', '['.RFC2822_ATEXT.']+(?:\.['.RFC2822_ATEXT.']+)*@(?i:[0-9a-z][0-9a-z-]*\.)+(?i:[a-z]{2,63})');
+if (!defined('PREG_PATTERN_VALID_EMAIL')) define(
+ 'PREG_PATTERN_VALID_EMAIL',
+ '['.RFC2822_ATEXT.']+(?:\.['.RFC2822_ATEXT.']+)*@(?i:[0-9a-z][0-9a-z-]*\.)+(?i:[a-z]{2,63})'
+);
/**
* Prepare mailfrom replacement patterns
@@ -102,7 +105,7 @@ function mail_setup(){
function mail_send($to, $subject, $body, $from='', $cc='', $bcc='', $headers=null, $params=null){
dbg_deprecated('class Mailer::');
$message = compact('to','subject','body','from','cc','bcc','headers','params');
- return trigger_event('MAIL_MESSAGE_SEND',$message,'_mail_send_action');
+ return Event::createAndTrigger('MAIL_MESSAGE_SEND',$message,'_mail_send_action');
}
/**
@@ -131,11 +134,11 @@ function _mail_send_action($data) {
// end additional code to support event ... original mail_send() code from here
if(defined('MAILHEADER_ASCIIONLY')){
- $subject = utf8_deaccent($subject);
- $subject = utf8_strip($subject);
+ $subject = \dokuwiki\Utf8\Clean::deaccent($subject);
+ $subject = \dokuwiki\Utf8\Clean::strip($subject);
}
- if(!utf8_isASCII($subject)) {
+ if(!\dokuwiki\Utf8\Clean::isASCII($subject)) {
$enc_subj = '=?UTF-8?Q?'.mail_quotedprintable_encode($subject,0).'?=';
// Spaces must be encoded according to rfc2047. Use the "_" shorthand
$enc_subj = preg_replace('/ /', '_', $enc_subj);
@@ -209,7 +212,7 @@ function mail_encode_address($string,$header='',$names=true){
}
// FIXME: is there a way to encode the localpart of a emailaddress?
- if(!utf8_isASCII($addr)){
+ if(!\dokuwiki\Utf8\Clean::isASCII($addr)){
msg(hsc("E-Mail address <$addr> is not ASCII"),-1);
continue;
}
@@ -225,11 +228,11 @@ function mail_encode_address($string,$header='',$names=true){
$addr = "<$addr>";
if(defined('MAILHEADER_ASCIIONLY')){
- $text = utf8_deaccent($text);
- $text = utf8_strip($text);
+ $text = \dokuwiki\Utf8\Clean::deaccent($text);
+ $text = \dokuwiki\Utf8\Clean::strip($text);
}
- if(!utf8_isASCII($text)){
+ if(!\dokuwiki\Utf8\Clean::isASCII($text)){
// put the quotes outside as in =?UTF-8?Q?"Elan Ruusam=C3=A4e"?= vs "=?UTF-8?Q?Elan Ruusam=C3=A4e?="
if (preg_match('/^"(.+)"$/', $text, $matches)) {
$text = '"=?UTF-8?Q?'.mail_quotedprintable_encode($matches[1], 0).'?="';
diff --git a/inc/media.php b/inc/media.php
index 128466061..41fbc0b8f 100644
--- a/inc/media.php
+++ b/inc/media.php
@@ -6,8 +6,10 @@
* @author Andreas Gohr <andi@splitbrain.org>
*/
-if(!defined('DOKU_INC')) die('meh.');
-if(!defined('NL')) define('NL',"\n");
+use dokuwiki\ChangeLog\MediaChangeLog;
+use dokuwiki\HTTP\DokuHTTPClient;
+use dokuwiki\Subscriptions\MediaSubscriptionSender;
+use dokuwiki\Extension\Event;
/**
* Lists pages which currently use a media file selected for deletion
@@ -172,7 +174,17 @@ function media_metaform($id,$auth){
$form->addElement('<div class="row">');
if($field[2] == 'text'){
- $form->addElement(form_makeField('text', $p['name'], $value, ($lang[$field[1]]) ? $lang[$field[1]] : $field[1] . ':', $p['id'], $p['class'], $p_attrs));
+ $form->addElement(
+ form_makeField(
+ 'text',
+ $p['name'],
+ $value,
+ ($lang[$field[1]]) ? $lang[$field[1]] : $field[1] . ':',
+ $p['id'],
+ $p['class'],
+ $p_attrs
+ )
+ );
}else{
$att = buildAttributes($p);
$form->addElement('<label for="meta__'.$key.'">'.$lang[$field[1]].'</label>');
@@ -181,7 +193,14 @@ function media_metaform($id,$auth){
$form->addElement('</div>'.NL);
}
$form->addElement('<div class="buttons">');
- $form->addElement(form_makeButton('submit', '', $lang['btn_save'], array('accesskey' => 's', 'name' => 'mediado[save]')));
+ $form->addElement(
+ form_makeButton(
+ 'submit',
+ '',
+ $lang['btn_save'],
+ array('accesskey' => 's', 'name' => 'mediado[save]')
+ )
+ );
$form->addElement('</div>'.NL);
$form->printForm();
@@ -242,13 +261,13 @@ function media_delete($id,$auth){
// trigger an event - MEDIA_DELETE_FILE
$data = array();
$data['id'] = $id;
- $data['name'] = utf8_basename($file);
+ $data['name'] = \dokuwiki\Utf8\PhpString::basename($file);
$data['path'] = $file;
$data['size'] = (file_exists($file)) ? filesize($file) : 0;
$data['unl'] = false;
$data['del'] = false;
- $evt = new Doku_Event('MEDIA_DELETE_FILE',$data);
+ $evt = new Event('MEDIA_DELETE_FILE',$data);
if ($evt->advise_before()) {
$old = @filemtime($file);
if(!file_exists(mediaFN($id, $old)) && file_exists($file)) {
@@ -466,7 +485,7 @@ function media_save($file, $id, $ow, $auth, $move) {
$data[5] = $move;
// trigger event
- return trigger_event('MEDIA_UPLOAD_FINISH', $data, '_media_upload_action', true);
+ return Event::createAndTrigger('MEDIA_UPLOAD_FINISH', $data, '_media_upload_action', true);
}
/**
@@ -530,7 +549,15 @@ function media_upload_finish($fn_tmp, $fn, $id, $imime, $overwrite, $move = 'mov
$filesize_new = filesize($fn);
$sizechange = $filesize_new - $filesize_old;
if($REV) {
- addMediaLogEntry($new, $id, DOKU_CHANGE_TYPE_REVERT, sprintf($lang['restored'], dformat($REV)), $REV, null, $sizechange);
+ addMediaLogEntry(
+ $new,
+ $id,
+ DOKU_CHANGE_TYPE_REVERT,
+ sprintf($lang['restored'], dformat($REV)),
+ $REV,
+ null,
+ $sizechange
+ );
} elseif($overwrite) {
addMediaLogEntry($new, $id, DOKU_CHANGE_TYPE_EDIT, '', '', null, $sizechange);
} else {
@@ -649,8 +676,8 @@ function media_notify($id,$file,$mime,$old_rev=false){
global $conf;
if(empty($conf['notify'])) return false; //notify enabled?
- $subscription = new Subscription();
- return $subscription->send_media_diff($conf['notify'], 'uploadmail', $id, $old_rev);
+ $subscription = new MediaSubscriptionSender();
+ return $subscription->sendMediaDiff($conf['notify'], 'uploadmail', $id, $old_rev);
}
/**
@@ -1249,7 +1276,7 @@ function media_diff($image, $ns, $auth, $fromajax = false) {
$data[5] = $fromajax;
// trigger event
- return trigger_event('MEDIA_DIFF', $data, '_media_file_diff', true);
+ return Event::createAndTrigger('MEDIA_DIFF', $data, '_media_file_diff', true);
}
/**
@@ -1487,7 +1514,7 @@ function media_searchlist($query,$ns,$auth=null,$fullscreen=false,$sort='natural
'query' => $query
);
if (!blank($query)) {
- $evt = new Doku_Event('MEDIA_SEARCH', $evdata);
+ $evt = new Event('MEDIA_SEARCH', $evdata);
if ($evt->advise_before()) {
$dir = utf8_encodeFN(str_replace(':','/',$evdata['ns']));
$quoted = preg_quote($evdata['query'],'/');
@@ -1716,7 +1743,7 @@ function media_printimgdetail($item, $fullscreen=false){
// output
if ($fullscreen) {
echo '<a id="l_:'.$item['id'].'" class="image thumb" href="'.
- media_managerURL(array('image' => hsc($item['id']), 'ns' => getNS($item['id']), 'tab_details' => 'view')).'">';
+ media_managerURL(['image' => hsc($item['id']), 'ns' => getNS($item['id']), 'tab_details' => 'view']).'">';
echo '<img src="'.$src.'" '.$att.' />';
echo '</a>';
}
@@ -1735,7 +1762,7 @@ function media_printimgdetail($item, $fullscreen=false){
$d = $item['meta']->getField(array('IPTC.Caption','EXIF.UserComment',
'EXIF.TIFFImageDescription',
'EXIF.TIFFUserComment'));
- if(utf8_strlen($d) > 250) $d = utf8_substr($d,0,250).'...';
+ if(\dokuwiki\Utf8\PhpString::strlen($d) > 250) $d = \dokuwiki\Utf8\PhpString::substr($d,0,250).'...';
$k = $item['meta']->getField(array('IPTC.Keywords','IPTC.Category','xmp.dc:subject'));
// print EXIF/IPTC data
@@ -1900,7 +1927,16 @@ function media_searchform($ns,$query='',$fullscreen=false){
$form->addHidden($fullscreen ? 'mediado' : 'do', 'searchlist');
$form->addElement(form_makeOpenTag('p'));
- $form->addElement(form_makeTextField('q', $query,$lang['searchmedia'],'','',array('title'=>sprintf($lang['searchmedia_in'],hsc($ns).':*'))));
+ $form->addElement(
+ form_makeTextField(
+ 'q',
+ $query,
+ $lang['searchmedia'],
+ '',
+ '',
+ array('title' => sprintf($lang['searchmedia_in'], hsc($ns) . ':*'))
+ )
+ );
$form->addElement(form_makeButton('submit', '', $lang['btn_search']));
$form->addElement(form_makeCloseTag('p'));
html_form('searchmedia', $form);
@@ -1943,7 +1979,13 @@ function media_nstree($ns){
// find the namespace parts or insert them
while ($data[$pos]['id'] != $tmp_ns) {
- if ($pos >= count($data) || ($data[$pos]['level'] <= $level+1 && strnatcmp(utf8_encodeFN($data[$pos]['id']), utf8_encodeFN($tmp_ns)) > 0)) {
+ if (
+ $pos >= count($data) ||
+ (
+ $data[$pos]['level'] <= $level+1 &&
+ strnatcmp(utf8_encodeFN($data[$pos]['id']), utf8_encodeFN($tmp_ns)) > 0
+ )
+ ) {
array_splice($data, $pos, 0, array(array('level' => $level+1, 'id' => $tmp_ns, 'open' => 'true')));
break;
}
@@ -2134,7 +2176,7 @@ function media_get_token($id,$w,$h){
if ($w) $token .= '.'.$w;
if ($h) $token .= '.'.$h;
- return substr(PassHash::hmac('md5', $token, auth_cookiesalt()),0,6);
+ return substr(\dokuwiki\PassHash::hmac('md5', $token, auth_cookiesalt()),0,6);
}
return '';
@@ -2353,7 +2395,12 @@ function media_resize_imageGD($ext,$from,$from_w,$from_h,$to,$to_w,$to_h,$ofs_x=
$transcolorindex = @imagecolortransparent($image);
if($transcolorindex >= 0 ) { //transparent color exists
$transcolor = @imagecolorsforindex($image, $transcolorindex);
- $transcolorindex = @imagecolorallocate($newimg, $transcolor['red'], $transcolor['green'], $transcolor['blue']);
+ $transcolorindex = @imagecolorallocate(
+ $newimg,
+ $transcolor['red'],
+ $transcolor['green'],
+ $transcolor['blue']
+ );
@imagefill($newimg, 0, 0, $transcolorindex);
@imagecolortransparent($newimg, $transcolorindex);
}else{ //filling with white
diff --git a/inc/pageutils.php b/inc/pageutils.php
index 3f81eb7e7..bc39a6fef 100644
--- a/inc/pageutils.php
+++ b/inc/pageutils.php
@@ -7,6 +7,9 @@
* @todo Combine similar functions like {wiki,media,meta}FN()
*/
+use dokuwiki\ChangeLog\MediaChangeLog;
+use dokuwiki\ChangeLog\PageChangeLog;
+
/**
* Fetch the an ID from request
*
@@ -41,7 +44,8 @@ function getID($param='id',$clean=true){
if($param != 'id') {
$relpath = 'lib/exe/';
}
- $script = $conf['basedir'].$relpath.utf8_basename($INPUT->server->str('SCRIPT_FILENAME'));
+ $script = $conf['basedir'] . $relpath .
+ \dokuwiki\Utf8\PhpString::basename($INPUT->server->str('SCRIPT_FILENAME'));
}elseif($INPUT->server->str('PATH_INFO')){
$request = $INPUT->server->str('PATH_INFO');
@@ -124,7 +128,7 @@ function cleanID($raw_id,$ascii=false){
$sepcharpat = '#\\'.$sepchar.'+#';
$id = trim((string)$raw_id);
- $id = utf8_strtolower($id);
+ $id = \dokuwiki\Utf8\PhpString::strtolower($id);
//alternative namespace seperator
if($conf['useslash']){
@@ -133,13 +137,13 @@ function cleanID($raw_id,$ascii=false){
$id = strtr($id,';/',':'.$sepchar);
}
- if($conf['deaccent'] == 2 || $ascii) $id = utf8_romanize($id);
- if($conf['deaccent'] || $ascii) $id = utf8_deaccent($id,-1);
+ if($conf['deaccent'] == 2 || $ascii) $id = \dokuwiki\Utf8\Clean::romanize($id);
+ if($conf['deaccent'] || $ascii) $id = \dokuwiki\Utf8\Clean::deaccent($id,-1);
//remove specials
- $id = utf8_stripspecials($id,$sepchar,'\*');
+ $id = \dokuwiki\Utf8\Clean::stripspecials($id,$sepchar,'\*');
- if($ascii) $id = utf8_strip($id);
+ if($ascii) $id = \dokuwiki\Utf8\Clean::strip($id);
//clean up
$id = preg_replace($sepcharpat,$sepchar,$id);
@@ -633,7 +637,7 @@ function isHiddenPage($id){
'id' => $id,
'hidden' => false
);
- trigger_event('PAGEUTILS_ID_HIDEPAGE', $data, '_isHiddenPage');
+ \dokuwiki\Extension\Event::createAndTrigger('PAGEUTILS_ID_HIDEPAGE', $data, '_isHiddenPage');
return $data['hidden'];
}
diff --git a/inc/parser/code.php b/inc/parser/code.php
index f91f1d228..cded87d6d 100644
--- a/inc/parser/code.php
+++ b/inc/parser/code.php
@@ -4,10 +4,8 @@
*
* @author Andreas Gohr <andi@splitbrain.org>
*/
-if(!defined('DOKU_INC')) die('meh.');
-
class Doku_Renderer_code extends Doku_Renderer {
- var $_codeblock = 0;
+ protected $_codeblock = 0;
/**
* Send the wanted code block to the browser
@@ -18,13 +16,13 @@ class Doku_Renderer_code extends Doku_Renderer {
* @param string $language
* @param string $filename
*/
- function code($text, $language = null, $filename = '') {
+ public function code($text, $language = null, $filename = '') {
global $INPUT;
if(!$language) $language = 'txt';
$language = preg_replace(PREG_PATTERN_VALID_LANGUAGE, '', $language);
if(!$filename) $filename = 'snippet.'.$language;
- $filename = utf8_basename($filename);
- $filename = utf8_stripspecials($filename, '_');
+ $filename = \dokuwiki\Utf8\PhpString::basename($filename);
+ $filename = \dokuwiki\Utf8\Clean::stripspecials($filename, '_');
// send CRLF to Windows clients
if(strpos($INPUT->server->str('HTTP_USER_AGENT'), 'Windows') !== false) {
@@ -49,14 +47,14 @@ class Doku_Renderer_code extends Doku_Renderer {
* @param string $language
* @param string $filename
*/
- function file($text, $language = null, $filename = '') {
+ public function file($text, $language = null, $filename = '') {
$this->code($text, $language, $filename);
}
/**
* This should never be reached, if it is send a 404
*/
- function document_end() {
+ public function document_end() {
http_status(404);
echo '404 - Not found';
exit;
@@ -67,7 +65,7 @@ class Doku_Renderer_code extends Doku_Renderer {
*
* @returns string 'code'
*/
- function getFormat() {
+ public function getFormat() {
return 'code';
}
}
diff --git a/inc/parser/handler.php b/inc/parser/handler.php
index 12551588b..19c2aafe8 100644
--- a/inc/parser/handler.php
+++ b/inc/parser/handler.php
@@ -1,44 +1,78 @@
<?php
-if(!defined('DOKU_INC')) die('meh.');
-if (!defined('DOKU_PARSER_EOL')) define('DOKU_PARSER_EOL',"\n"); // add this to make handling test cases simpler
-class Doku_Handler {
-
- var $Renderer = null;
+use dokuwiki\Extension\Event;
+use dokuwiki\Extension\SyntaxPlugin;
+use dokuwiki\Parsing\Handler\Block;
+use dokuwiki\Parsing\Handler\CallWriter;
+use dokuwiki\Parsing\Handler\CallWriterInterface;
+use dokuwiki\Parsing\Handler\Lists;
+use dokuwiki\Parsing\Handler\Nest;
+use dokuwiki\Parsing\Handler\Preformatted;
+use dokuwiki\Parsing\Handler\Quote;
+use dokuwiki\Parsing\Handler\Table;
- var $CallWriter = null;
+/**
+ * Class Doku_Handler
+ */
+class Doku_Handler {
+ /** @var CallWriterInterface */
+ protected $callWriter = null;
- var $calls = array();
+ /** @var array The current CallWriter will write directly to this list of calls, Parser reads it */
+ public $calls = array();
- var $status = array(
+ /** @var array internal status holders for some modes */
+ protected $status = array(
'section' => false,
'doublequote' => 0,
);
- var $rewriteBlocks = true;
+ /** @var bool should blocks be rewritten? FIXME seems to always be true */
+ protected $rewriteBlocks = true;
- function __construct() {
- $this->CallWriter = new Doku_Handler_CallWriter($this);
+ /**
+ * Doku_Handler constructor.
+ */
+ public function __construct() {
+ $this->callWriter = new CallWriter($this);
}
/**
- * @param string $handler
- * @param mixed $args
- * @param integer|string $pos
+ * Add a new call by passing it to the current CallWriter
+ *
+ * @param string $handler handler method name (see mode handlers below)
+ * @param mixed $args arguments for this call
+ * @param int $pos byte position in the original source file
*/
- function _addCall($handler, $args, $pos) {
+ protected function addCall($handler, $args, $pos) {
$call = array($handler,$args, $pos);
- $this->CallWriter->writeCall($call);
+ $this->callWriter->writeCall($call);
}
- function addPluginCall($plugin, $args, $state, $pos, $match) {
+ /**
+ * Similar to addCall, but adds a plugin call
+ *
+ * @param string $plugin name of the plugin
+ * @param mixed $args arguments for this call
+ * @param int $state a LEXER_STATE_* constant
+ * @param int $pos byte position in the original source file
+ * @param string $match matched syntax
+ */
+ protected function addPluginCall($plugin, $args, $state, $pos, $match) {
$call = array('plugin',array($plugin, $args, $state, $match), $pos);
- $this->CallWriter->writeCall($call);
+ $this->callWriter->writeCall($call);
}
- function _finalize(){
-
- $this->CallWriter->finalise();
+ /**
+ * Finishes handling
+ *
+ * Called from the parser. Calls finalise() on the call writer, closes open
+ * sections, rewrites blocks and adds document_start and document_end calls.
+ *
+ * @triggers PARSER_HANDLER_DONE
+ */
+ public function finalize(){
+ $this->callWriter->finalise();
if ( $this->status['section'] ) {
$last_call = end($this->calls);
@@ -46,11 +80,11 @@ class Doku_Handler {
}
if ( $this->rewriteBlocks ) {
- $B = new Doku_Handler_Block();
+ $B = new Block();
$this->calls = $B->process($this->calls);
}
- trigger_event('PARSER_HANDLER_DONE',$this);
+ Event::createAndTrigger('PARSER_HANDLER_DONE',$this);
array_unshift($this->calls,array('document_start',array(),0));
$last_call = end($this->calls);
@@ -60,9 +94,10 @@ class Doku_Handler {
/**
* fetch the current call and advance the pointer to the next one
*
+ * @fixme seems to be unused?
* @return bool|mixed
*/
- function fetch() {
+ public function fetch() {
$call = current($this->calls);
if($call !== false) {
next($this->calls); //advance the pointer
@@ -73,23 +108,127 @@ class Doku_Handler {
/**
+ * Internal function for parsing highlight options.
+ * $options is parsed for key value pairs separated by commas.
+ * A value might also be missing in which case the value will simple
+ * be set to true. Commas in strings are ignored, e.g. option="4,56"
+ * will work as expected and will only create one entry.
+ *
+ * @param string $options space separated list of key-value pairs,
+ * e.g. option1=123, option2="456"
+ * @return array|null Array of key-value pairs $array['key'] = 'value';
+ * or null if no entries found
+ */
+ protected function parse_highlight_options($options) {
+ $result = array();
+ preg_match_all('/(\w+(?:="[^"]*"))|(\w+(?:=[^\s]*))|(\w+[^=\s\]])(?:\s*)/', $options, $matches, PREG_SET_ORDER);
+ foreach ($matches as $match) {
+ $equal_sign = strpos($match [0], '=');
+ if ($equal_sign === false) {
+ $key = trim($match[0]);
+ $result [$key] = 1;
+ } else {
+ $key = substr($match[0], 0, $equal_sign);
+ $value = substr($match[0], $equal_sign+1);
+ $value = trim($value, '"');
+ if (strlen($value) > 0) {
+ $result [$key] = $value;
+ } else {
+ $result [$key] = 1;
+ }
+ }
+ }
+
+ // Check for supported options
+ $result = array_intersect_key(
+ $result,
+ array_flip(array(
+ 'enable_line_numbers',
+ 'start_line_numbers_at',
+ 'highlight_lines_extra',
+ 'enable_keyword_links')
+ )
+ );
+
+ // Sanitize values
+ if(isset($result['enable_line_numbers'])) {
+ if($result['enable_line_numbers'] === 'false') {
+ $result['enable_line_numbers'] = false;
+ }
+ $result['enable_line_numbers'] = (bool) $result['enable_line_numbers'];
+ }
+ if(isset($result['highlight_lines_extra'])) {
+ $result['highlight_lines_extra'] = array_map('intval', explode(',', $result['highlight_lines_extra']));
+ $result['highlight_lines_extra'] = array_filter($result['highlight_lines_extra']);
+ $result['highlight_lines_extra'] = array_unique($result['highlight_lines_extra']);
+ }
+ if(isset($result['start_line_numbers_at'])) {
+ $result['start_line_numbers_at'] = (int) $result['start_line_numbers_at'];
+ }
+ if(isset($result['enable_keyword_links'])) {
+ if($result['enable_keyword_links'] === 'false') {
+ $result['enable_keyword_links'] = false;
+ }
+ $result['enable_keyword_links'] = (bool) $result['enable_keyword_links'];
+ }
+ if (count($result) == 0) {
+ return null;
+ }
+
+ return $result;
+ }
+
+ /**
+ * Simplifies handling for the formatting tags which all behave the same
+ *
+ * @param string $match matched syntax
+ * @param int $state a LEXER_STATE_* constant
+ * @param int $pos byte position in the original source file
+ * @param string $name actual mode name
+ */
+ protected function nestingTag($match, $state, $pos, $name) {
+ switch ( $state ) {
+ case DOKU_LEXER_ENTER:
+ $this->addCall($name.'_open', array(), $pos);
+ break;
+ case DOKU_LEXER_EXIT:
+ $this->addCall($name.'_close', array(), $pos);
+ break;
+ case DOKU_LEXER_UNMATCHED:
+ $this->addCall('cdata', array($match), $pos);
+ break;
+ }
+ }
+
+
+ /**
+ * The following methods define the handlers for the different Syntax modes
+ *
+ * The handlers are called from dokuwiki\Parsing\Lexer\Lexer\invokeParser()
+ *
+ * @todo it might make sense to move these into their own class or merge them with the
+ * ParserMode classes some time.
+ */
+ // region mode handlers
+
+ /**
* Special plugin handler
*
* This handler is called for all modes starting with 'plugin_'.
- * An additional parameter with the plugin name is passed
+ * An additional parameter with the plugin name is passed. The plugin's handle()
+ * method is called here
*
* @author Andreas Gohr <andi@splitbrain.org>
*
- * @param string|integer $match
- * @param string|integer $state
- * @param integer $pos
- * @param $pluginname
- *
- * @return bool
+ * @param string $match matched syntax
+ * @param int $state a LEXER_STATE_* constant
+ * @param int $pos byte position in the original source file
+ * @param string $pluginname name of the plugin
+ * @return bool mode handled?
*/
- function plugin($match, $state, $pos, $pluginname){
+ public function plugin($match, $state, $pos, $pluginname){
$data = array($match);
- /** @var DokuWiki_Syntax_Plugin $plugin */
+ /** @var SyntaxPlugin $plugin */
$plugin = plugin_load('syntax',$pluginname);
if($plugin != null){
$data = $plugin->handle($match, $state, $pos, $this);
@@ -100,16 +239,29 @@ class Doku_Handler {
return true;
}
- function base($match, $state, $pos) {
+ /**
+ * @param string $match matched syntax
+ * @param int $state a LEXER_STATE_* constant
+ * @param int $pos byte position in the original source file
+ * @return bool mode handled?
+ */
+ public function base($match, $state, $pos) {
switch ( $state ) {
case DOKU_LEXER_UNMATCHED:
- $this->_addCall('cdata',array($match), $pos);
+ $this->addCall('cdata', array($match), $pos);
return true;
break;
}
+ return false;
}
- function header($match, $state, $pos) {
+ /**
+ * @param string $match matched syntax
+ * @param int $state a LEXER_STATE_* constant
+ * @param int $pos byte position in the original source file
+ * @return bool mode handled?
+ */
+ public function header($match, $state, $pos) {
// get level and title
$title = trim($match);
$level = 7 - strspn($title,'=');
@@ -117,98 +269,154 @@ class Doku_Handler {
$title = trim($title,'=');
$title = trim($title);
- if ($this->status['section']) $this->_addCall('section_close',array(),$pos);
+ if ($this->status['section']) $this->addCall('section_close', array(), $pos);
- $this->_addCall('header',array($title,$level,$pos), $pos);
+ $this->addCall('header', array($title, $level, $pos), $pos);
- $this->_addCall('section_open',array($level),$pos);
+ $this->addCall('section_open', array($level), $pos);
$this->status['section'] = true;
return true;
}
- function notoc($match, $state, $pos) {
- $this->_addCall('notoc',array(),$pos);
+ /**
+ * @param string $match matched syntax
+ * @param int $state a LEXER_STATE_* constant
+ * @param int $pos byte position in the original source file
+ * @return bool mode handled?
+ */
+ public function notoc($match, $state, $pos) {
+ $this->addCall('notoc', array(), $pos);
return true;
}
- function nocache($match, $state, $pos) {
- $this->_addCall('nocache',array(),$pos);
+ /**
+ * @param string $match matched syntax
+ * @param int $state a LEXER_STATE_* constant
+ * @param int $pos byte position in the original source file
+ * @return bool mode handled?
+ */
+ public function nocache($match, $state, $pos) {
+ $this->addCall('nocache', array(), $pos);
return true;
}
- function linebreak($match, $state, $pos) {
- $this->_addCall('linebreak',array(),$pos);
+ /**
+ * @param string $match matched syntax
+ * @param int $state a LEXER_STATE_* constant
+ * @param int $pos byte position in the original source file
+ * @return bool mode handled?
+ */
+ public function linebreak($match, $state, $pos) {
+ $this->addCall('linebreak', array(), $pos);
return true;
}
- function eol($match, $state, $pos) {
- $this->_addCall('eol',array(),$pos);
+ /**
+ * @param string $match matched syntax
+ * @param int $state a LEXER_STATE_* constant
+ * @param int $pos byte position in the original source file
+ * @return bool mode handled?
+ */
+ public function eol($match, $state, $pos) {
+ $this->addCall('eol', array(), $pos);
return true;
}
- function hr($match, $state, $pos) {
- $this->_addCall('hr',array(),$pos);
+ /**
+ * @param string $match matched syntax
+ * @param int $state a LEXER_STATE_* constant
+ * @param int $pos byte position in the original source file
+ * @return bool mode handled?
+ */
+ public function hr($match, $state, $pos) {
+ $this->addCall('hr', array(), $pos);
return true;
}
/**
- * @param string|integer $match
- * @param string|integer $state
- * @param integer $pos
- * @param string $name
+ * @param string $match matched syntax
+ * @param int $state a LEXER_STATE_* constant
+ * @param int $pos byte position in the original source file
+ * @return bool mode handled?
*/
- function _nestingTag($match, $state, $pos, $name) {
- switch ( $state ) {
- case DOKU_LEXER_ENTER:
- $this->_addCall($name.'_open', array(), $pos);
- break;
- case DOKU_LEXER_EXIT:
- $this->_addCall($name.'_close', array(), $pos);
- break;
- case DOKU_LEXER_UNMATCHED:
- $this->_addCall('cdata',array($match), $pos);
- break;
- }
- }
-
- function strong($match, $state, $pos) {
- $this->_nestingTag($match, $state, $pos, 'strong');
+ public function strong($match, $state, $pos) {
+ $this->nestingTag($match, $state, $pos, 'strong');
return true;
}
- function emphasis($match, $state, $pos) {
- $this->_nestingTag($match, $state, $pos, 'emphasis');
+ /**
+ * @param string $match matched syntax
+ * @param int $state a LEXER_STATE_* constant
+ * @param int $pos byte position in the original source file
+ * @return bool mode handled?
+ */
+ public function emphasis($match, $state, $pos) {
+ $this->nestingTag($match, $state, $pos, 'emphasis');
return true;
}
- function underline($match, $state, $pos) {
- $this->_nestingTag($match, $state, $pos, 'underline');
+ /**
+ * @param string $match matched syntax
+ * @param int $state a LEXER_STATE_* constant
+ * @param int $pos byte position in the original source file
+ * @return bool mode handled?
+ */
+ public function underline($match, $state, $pos) {
+ $this->nestingTag($match, $state, $pos, 'underline');
return true;
}
- function monospace($match, $state, $pos) {
- $this->_nestingTag($match, $state, $pos, 'monospace');
+ /**
+ * @param string $match matched syntax
+ * @param int $state a LEXER_STATE_* constant
+ * @param int $pos byte position in the original source file
+ * @return bool mode handled?
+ */
+ public function monospace($match, $state, $pos) {
+ $this->nestingTag($match, $state, $pos, 'monospace');
return true;
}
- function subscript($match, $state, $pos) {
- $this->_nestingTag($match, $state, $pos, 'subscript');
+ /**
+ * @param string $match matched syntax
+ * @param int $state a LEXER_STATE_* constant
+ * @param int $pos byte position in the original source file
+ * @return bool mode handled?
+ */
+ public function subscript($match, $state, $pos) {
+ $this->nestingTag($match, $state, $pos, 'subscript');
return true;
}
- function superscript($match, $state, $pos) {
- $this->_nestingTag($match, $state, $pos, 'superscript');
+ /**
+ * @param string $match matched syntax
+ * @param int $state a LEXER_STATE_* constant
+ * @param int $pos byte position in the original source file
+ * @return bool mode handled?
+ */
+ public function superscript($match, $state, $pos) {
+ $this->nestingTag($match, $state, $pos, 'superscript');
return true;
}
- function deleted($match, $state, $pos) {
- $this->_nestingTag($match, $state, $pos, 'deleted');
+ /**
+ * @param string $match matched syntax
+ * @param int $state a LEXER_STATE_* constant
+ * @param int $pos byte position in the original source file
+ * @return bool mode handled?
+ */
+ public function deleted($match, $state, $pos) {
+ $this->nestingTag($match, $state, $pos, 'deleted');
return true;
}
-
- function footnote($match, $state, $pos) {
-// $this->_nestingTag($match, $state, $pos, 'footnote');
+ /**
+ * @param string $match matched syntax
+ * @param int $state a LEXER_STATE_* constant
+ * @param int $pos byte position in the original source file
+ * @return bool mode handled?
+ */
+ public function footnote($match, $state, $pos) {
if (!isset($this->_footnote)) $this->_footnote = false;
switch ( $state ) {
@@ -216,146 +424,185 @@ class Doku_Handler {
// footnotes can not be nested - however due to limitations in lexer it can't be prevented
// we will still enter a new footnote mode, we just do nothing
if ($this->_footnote) {
- $this->_addCall('cdata',array($match), $pos);
+ $this->addCall('cdata', array($match), $pos);
break;
}
-
$this->_footnote = true;
- $ReWriter = new Doku_Handler_Nest($this->CallWriter,'footnote_close');
- $this->CallWriter = & $ReWriter;
- $this->_addCall('footnote_open', array(), $pos);
+ $this->callWriter = new Nest($this->callWriter, 'footnote_close');
+ $this->addCall('footnote_open', array(), $pos);
break;
case DOKU_LEXER_EXIT:
// check whether we have already exitted the footnote mode, can happen if the modes were nested
if (!$this->_footnote) {
- $this->_addCall('cdata',array($match), $pos);
+ $this->addCall('cdata', array($match), $pos);
break;
}
$this->_footnote = false;
+ $this->addCall('footnote_close', array(), $pos);
- $this->_addCall('footnote_close', array(), $pos);
- $this->CallWriter->process();
- $ReWriter = & $this->CallWriter;
- $this->CallWriter = & $ReWriter->CallWriter;
+ /** @var Nest $reWriter */
+ $reWriter = $this->callWriter;
+ $this->callWriter = $reWriter->process();
break;
case DOKU_LEXER_UNMATCHED:
- $this->_addCall('cdata', array($match), $pos);
+ $this->addCall('cdata', array($match), $pos);
break;
}
return true;
}
- function listblock($match, $state, $pos) {
+ /**
+ * @param string $match matched syntax
+ * @param int $state a LEXER_STATE_* constant
+ * @param int $pos byte position in the original source file
+ * @return bool mode handled?
+ */
+ public function listblock($match, $state, $pos) {
switch ( $state ) {
case DOKU_LEXER_ENTER:
- $ReWriter = new Doku_Handler_List($this->CallWriter);
- $this->CallWriter = & $ReWriter;
- $this->_addCall('list_open', array($match), $pos);
+ $this->callWriter = new Lists($this->callWriter);
+ $this->addCall('list_open', array($match), $pos);
break;
case DOKU_LEXER_EXIT:
- $this->_addCall('list_close', array(), $pos);
- $this->CallWriter->process();
- $ReWriter = & $this->CallWriter;
- $this->CallWriter = & $ReWriter->CallWriter;
+ $this->addCall('list_close', array(), $pos);
+ /** @var Lists $reWriter */
+ $reWriter = $this->callWriter;
+ $this->callWriter = $reWriter->process();
break;
case DOKU_LEXER_MATCHED:
- $this->_addCall('list_item', array($match), $pos);
+ $this->addCall('list_item', array($match), $pos);
break;
case DOKU_LEXER_UNMATCHED:
- $this->_addCall('cdata', array($match), $pos);
+ $this->addCall('cdata', array($match), $pos);
break;
}
return true;
}
- function unformatted($match, $state, $pos) {
+ /**
+ * @param string $match matched syntax
+ * @param int $state a LEXER_STATE_* constant
+ * @param int $pos byte position in the original source file
+ * @return bool mode handled?
+ */
+ public function unformatted($match, $state, $pos) {
if ( $state == DOKU_LEXER_UNMATCHED ) {
- $this->_addCall('unformatted',array($match), $pos);
+ $this->addCall('unformatted', array($match), $pos);
}
return true;
}
- function php($match, $state, $pos) {
- global $conf;
+ /**
+ * @param string $match matched syntax
+ * @param int $state a LEXER_STATE_* constant
+ * @param int $pos byte position in the original source file
+ * @return bool mode handled?
+ */
+ public function php($match, $state, $pos) {
if ( $state == DOKU_LEXER_UNMATCHED ) {
- $this->_addCall('php',array($match), $pos);
+ $this->addCall('php', array($match), $pos);
}
return true;
}
- function phpblock($match, $state, $pos) {
- global $conf;
+ /**
+ * @param string $match matched syntax
+ * @param int $state a LEXER_STATE_* constant
+ * @param int $pos byte position in the original source file
+ * @return bool mode handled?
+ */
+ public function phpblock($match, $state, $pos) {
if ( $state == DOKU_LEXER_UNMATCHED ) {
- $this->_addCall('phpblock',array($match), $pos);
+ $this->addCall('phpblock', array($match), $pos);
}
return true;
}
- function html($match, $state, $pos) {
- global $conf;
+ /**
+ * @param string $match matched syntax
+ * @param int $state a LEXER_STATE_* constant
+ * @param int $pos byte position in the original source file
+ * @return bool mode handled?
+ */
+ public function html($match, $state, $pos) {
if ( $state == DOKU_LEXER_UNMATCHED ) {
- $this->_addCall('html',array($match), $pos);
+ $this->addCall('html', array($match), $pos);
}
return true;
}
- function htmlblock($match, $state, $pos) {
- global $conf;
+ /**
+ * @param string $match matched syntax
+ * @param int $state a LEXER_STATE_* constant
+ * @param int $pos byte position in the original source file
+ * @return bool mode handled?
+ */
+ public function htmlblock($match, $state, $pos) {
if ( $state == DOKU_LEXER_UNMATCHED ) {
- $this->_addCall('htmlblock',array($match), $pos);
+ $this->addCall('htmlblock', array($match), $pos);
}
return true;
}
- function preformatted($match, $state, $pos) {
+ /**
+ * @param string $match matched syntax
+ * @param int $state a LEXER_STATE_* constant
+ * @param int $pos byte position in the original source file
+ * @return bool mode handled?
+ */
+ public function preformatted($match, $state, $pos) {
switch ( $state ) {
case DOKU_LEXER_ENTER:
- $ReWriter = new Doku_Handler_Preformatted($this->CallWriter);
- $this->CallWriter = $ReWriter;
- $this->_addCall('preformatted_start',array(), $pos);
+ $this->callWriter = new Preformatted($this->callWriter);
+ $this->addCall('preformatted_start', array(), $pos);
break;
case DOKU_LEXER_EXIT:
- $this->_addCall('preformatted_end',array(), $pos);
- $this->CallWriter->process();
- $ReWriter = & $this->CallWriter;
- $this->CallWriter = & $ReWriter->CallWriter;
+ $this->addCall('preformatted_end', array(), $pos);
+ /** @var Preformatted $reWriter */
+ $reWriter = $this->callWriter;
+ $this->callWriter = $reWriter->process();
break;
case DOKU_LEXER_MATCHED:
- $this->_addCall('preformatted_newline',array(), $pos);
+ $this->addCall('preformatted_newline', array(), $pos);
break;
case DOKU_LEXER_UNMATCHED:
- $this->_addCall('preformatted_content',array($match), $pos);
+ $this->addCall('preformatted_content', array($match), $pos);
break;
}
return true;
}
- function quote($match, $state, $pos) {
+ /**
+ * @param string $match matched syntax
+ * @param int $state a LEXER_STATE_* constant
+ * @param int $pos byte position in the original source file
+ * @return bool mode handled?
+ */
+ public function quote($match, $state, $pos) {
switch ( $state ) {
case DOKU_LEXER_ENTER:
- $ReWriter = new Doku_Handler_Quote($this->CallWriter);
- $this->CallWriter = & $ReWriter;
- $this->_addCall('quote_start',array($match), $pos);
+ $this->callWriter = new Quote($this->callWriter);
+ $this->addCall('quote_start', array($match), $pos);
break;
case DOKU_LEXER_EXIT:
- $this->_addCall('quote_end',array(), $pos);
- $this->CallWriter->process();
- $ReWriter = & $this->CallWriter;
- $this->CallWriter = & $ReWriter->CallWriter;
+ $this->addCall('quote_end', array(), $pos);
+ /** @var Lists $reWriter */
+ $reWriter = $this->callWriter;
+ $this->callWriter = $reWriter->process();
break;
case DOKU_LEXER_MATCHED:
- $this->_addCall('quote_newline',array($match), $pos);
+ $this->addCall('quote_newline', array($match), $pos);
break;
case DOKU_LEXER_UNMATCHED:
- $this->_addCall('cdata',array($match), $pos);
+ $this->addCall('cdata', array($match), $pos);
break;
}
@@ -364,81 +611,23 @@ class Doku_Handler {
}
/**
- * Internal function for parsing highlight options.
- * $options is parsed for key value pairs separated by commas.
- * A value might also be missing in which case the value will simple
- * be set to true. Commas in strings are ignored, e.g. option="4,56"
- * will work as expected and will only create one entry.
- *
- * @param string $options space separated list of key-value pairs,
- * e.g. option1=123, option2="456"
- * @return array|null Array of key-value pairs $array['key'] = 'value';
- * or null if no entries found
+ * @param string $match matched syntax
+ * @param int $state a LEXER_STATE_* constant
+ * @param int $pos byte position in the original source file
+ * @return bool mode handled?
*/
- protected function parse_highlight_options ($options) {
- $result = array();
- preg_match_all('/(\w+(?:="[^"]*"))|(\w+(?:=[^\s]*))|(\w+[^=\s\]])(?:\s*)/', $options, $matches, PREG_SET_ORDER);
- foreach ($matches as $match) {
- $equal_sign = strpos($match [0], '=');
- if ($equal_sign === false) {
- $key = trim($match[0]);
- $result [$key] = 1;
- } else {
- $key = substr($match[0], 0, $equal_sign);
- $value = substr($match[0], $equal_sign+1);
- $value = trim($value, '"');
- if (strlen($value) > 0) {
- $result [$key] = $value;
- } else {
- $result [$key] = 1;
- }
- }
- }
-
- // Check for supported options
- $result = array_intersect_key(
- $result,
- array_flip(array(
- 'enable_line_numbers',
- 'start_line_numbers_at',
- 'highlight_lines_extra',
- 'enable_keyword_links')
- )
- );
-
- // Sanitize values
- if(isset($result['enable_line_numbers'])) {
- if($result['enable_line_numbers'] === 'false') {
- $result['enable_line_numbers'] = false;
- }
- $result['enable_line_numbers'] = (bool) $result['enable_line_numbers'];
- }
- if(isset($result['highlight_lines_extra'])) {
- $result['highlight_lines_extra'] = array_map('intval', explode(',', $result['highlight_lines_extra']));
- $result['highlight_lines_extra'] = array_filter($result['highlight_lines_extra']);
- $result['highlight_lines_extra'] = array_unique($result['highlight_lines_extra']);
- }
- if(isset($result['start_line_numbers_at'])) {
- $result['start_line_numbers_at'] = (int) $result['start_line_numbers_at'];
- }
- if(isset($result['enable_keyword_links'])) {
- if($result['enable_keyword_links'] === 'false') {
- $result['enable_keyword_links'] = false;
- }
- $result['enable_keyword_links'] = (bool) $result['enable_keyword_links'];
- }
- if (count($result) == 0) {
- return null;
- }
-
- return $result;
- }
-
- function file($match, $state, $pos) {
+ public function file($match, $state, $pos) {
return $this->code($match, $state, $pos, 'file');
}
- function code($match, $state, $pos, $type='code') {
+ /**
+ * @param string $match matched syntax
+ * @param int $state a LEXER_STATE_* constant
+ * @param int $pos byte position in the original source file
+ * @param string $type either 'code' or 'file'
+ * @return bool mode handled?
+ */
+ public function code($match, $state, $pos, $type='code') {
if ( $state == DOKU_LEXER_UNMATCHED ) {
$matches = explode('>',$match,2);
// Cut out variable options enclosed in []
@@ -455,76 +644,146 @@ class Doku_Handler {
if (!empty($options[0])) {
$param [] = $this->parse_highlight_options ($options[0]);
}
- $this->_addCall($type, $param, $pos);
+ $this->addCall($type, $param, $pos);
}
return true;
}
- function acronym($match, $state, $pos) {
- $this->_addCall('acronym',array($match), $pos);
+ /**
+ * @param string $match matched syntax
+ * @param int $state a LEXER_STATE_* constant
+ * @param int $pos byte position in the original source file
+ * @return bool mode handled?
+ */
+ public function acronym($match, $state, $pos) {
+ $this->addCall('acronym', array($match), $pos);
return true;
}
- function smiley($match, $state, $pos) {
- $this->_addCall('smiley',array($match), $pos);
+ /**
+ * @param string $match matched syntax
+ * @param int $state a LEXER_STATE_* constant
+ * @param int $pos byte position in the original source file
+ * @return bool mode handled?
+ */
+ public function smiley($match, $state, $pos) {
+ $this->addCall('smiley', array($match), $pos);
return true;
}
- function wordblock($match, $state, $pos) {
- $this->_addCall('wordblock',array($match), $pos);
+ /**
+ * @param string $match matched syntax
+ * @param int $state a LEXER_STATE_* constant
+ * @param int $pos byte position in the original source file
+ * @return bool mode handled?
+ */
+ public function wordblock($match, $state, $pos) {
+ $this->addCall('wordblock', array($match), $pos);
return true;
}
- function entity($match, $state, $pos) {
- $this->_addCall('entity',array($match), $pos);
+ /**
+ * @param string $match matched syntax
+ * @param int $state a LEXER_STATE_* constant
+ * @param int $pos byte position in the original source file
+ * @return bool mode handled?
+ */
+ public function entity($match, $state, $pos) {
+ $this->addCall('entity', array($match), $pos);
return true;
}
- function multiplyentity($match, $state, $pos) {
+ /**
+ * @param string $match matched syntax
+ * @param int $state a LEXER_STATE_* constant
+ * @param int $pos byte position in the original source file
+ * @return bool mode handled?
+ */
+ public function multiplyentity($match, $state, $pos) {
preg_match_all('/\d+/',$match,$matches);
- $this->_addCall('multiplyentity',array($matches[0][0],$matches[0][1]), $pos);
+ $this->addCall('multiplyentity', array($matches[0][0], $matches[0][1]), $pos);
return true;
}
- function singlequoteopening($match, $state, $pos) {
- $this->_addCall('singlequoteopening',array(), $pos);
+ /**
+ * @param string $match matched syntax
+ * @param int $state a LEXER_STATE_* constant
+ * @param int $pos byte position in the original source file
+ * @return bool mode handled?
+ */
+ public function singlequoteopening($match, $state, $pos) {
+ $this->addCall('singlequoteopening', array(), $pos);
return true;
}
- function singlequoteclosing($match, $state, $pos) {
- $this->_addCall('singlequoteclosing',array(), $pos);
+ /**
+ * @param string $match matched syntax
+ * @param int $state a LEXER_STATE_* constant
+ * @param int $pos byte position in the original source file
+ * @return bool mode handled?
+ */
+ public function singlequoteclosing($match, $state, $pos) {
+ $this->addCall('singlequoteclosing', array(), $pos);
return true;
}
- function apostrophe($match, $state, $pos) {
- $this->_addCall('apostrophe',array(), $pos);
+ /**
+ * @param string $match matched syntax
+ * @param int $state a LEXER_STATE_* constant
+ * @param int $pos byte position in the original source file
+ * @return bool mode handled?
+ */
+ public function apostrophe($match, $state, $pos) {
+ $this->addCall('apostrophe', array(), $pos);
return true;
}
- function doublequoteopening($match, $state, $pos) {
- $this->_addCall('doublequoteopening',array(), $pos);
+ /**
+ * @param string $match matched syntax
+ * @param int $state a LEXER_STATE_* constant
+ * @param int $pos byte position in the original source file
+ * @return bool mode handled?
+ */
+ public function doublequoteopening($match, $state, $pos) {
+ $this->addCall('doublequoteopening', array(), $pos);
$this->status['doublequote']++;
return true;
}
- function doublequoteclosing($match, $state, $pos) {
+ /**
+ * @param string $match matched syntax
+ * @param int $state a LEXER_STATE_* constant
+ * @param int $pos byte position in the original source file
+ * @return bool mode handled?
+ */
+ public function doublequoteclosing($match, $state, $pos) {
if ($this->status['doublequote'] <= 0) {
$this->doublequoteopening($match, $state, $pos);
} else {
- $this->_addCall('doublequoteclosing',array(), $pos);
+ $this->addCall('doublequoteclosing', array(), $pos);
$this->status['doublequote'] = max(0, --$this->status['doublequote']);
}
return true;
}
- function camelcaselink($match, $state, $pos) {
- $this->_addCall('camelcaselink',array($match), $pos);
+ /**
+ * @param string $match matched syntax
+ * @param int $state a LEXER_STATE_* constant
+ * @param int $pos byte position in the original source file
+ * @return bool mode handled?
+ */
+ public function camelcaselink($match, $state, $pos) {
+ $this->addCall('camelcaselink', array($match), $pos);
return true;
}
- /*
- */
- function internallink($match, $state, $pos) {
+ /**
+ * @param string $match matched syntax
+ * @param int $state a LEXER_STATE_* constant
+ * @param int $pos byte position in the original source file
+ * @return bool mode handled?
+ */
+ public function internallink($match, $state, $pos) {
// Strip the opening and closing markup
$link = preg_replace(array('/^\[\[/','/\]\]$/u'),'',$match);
@@ -543,42 +802,42 @@ class Doku_Handler {
if ( link_isinterwiki($link[0]) ) {
// Interwiki
$interwiki = explode('>',$link[0],2);
- $this->_addCall(
+ $this->addCall(
'interwikilink',
array($link[0],$link[1],strtolower($interwiki[0]),$interwiki[1]),
$pos
);
}elseif ( preg_match('/^\\\\\\\\[^\\\\]+?\\\\/u',$link[0]) ) {
// Windows Share
- $this->_addCall(
+ $this->addCall(
'windowssharelink',
array($link[0],$link[1]),
$pos
);
}elseif ( preg_match('#^([a-z0-9\-\.+]+?)://#i',$link[0]) ) {
// external link (accepts all protocols)
- $this->_addCall(
+ $this->addCall(
'externallink',
array($link[0],$link[1]),
$pos
);
}elseif ( preg_match('<'.PREG_PATTERN_VALID_EMAIL.'>',$link[0]) ) {
// E-Mail (pattern above is defined in inc/mail.php)
- $this->_addCall(
+ $this->addCall(
'emaillink',
array($link[0],$link[1]),
$pos
);
}elseif ( preg_match('!^#.+!',$link[0]) ){
// local link
- $this->_addCall(
+ $this->addCall(
'locallink',
array(substr($link[0],1),$link[1]),
$pos
);
}else{
// internal link
- $this->_addCall(
+ $this->addCall(
'internallink',
array($link[0],$link[1]),
$pos
@@ -588,20 +847,38 @@ class Doku_Handler {
return true;
}
- function filelink($match, $state, $pos) {
- $this->_addCall('filelink',array($match, null), $pos);
+ /**
+ * @param string $match matched syntax
+ * @param int $state a LEXER_STATE_* constant
+ * @param int $pos byte position in the original source file
+ * @return bool mode handled?
+ */
+ public function filelink($match, $state, $pos) {
+ $this->addCall('filelink', array($match, null), $pos);
return true;
}
- function windowssharelink($match, $state, $pos) {
- $this->_addCall('windowssharelink',array($match, null), $pos);
+ /**
+ * @param string $match matched syntax
+ * @param int $state a LEXER_STATE_* constant
+ * @param int $pos byte position in the original source file
+ * @return bool mode handled?
+ */
+ public function windowssharelink($match, $state, $pos) {
+ $this->addCall('windowssharelink', array($match, null), $pos);
return true;
}
- function media($match, $state, $pos) {
+ /**
+ * @param string $match matched syntax
+ * @param int $state a LEXER_STATE_* constant
+ * @param int $pos byte position in the original source file
+ * @return bool mode handled?
+ */
+ public function media($match, $state, $pos) {
$p = Doku_Handler_Parse_Media($match);
- $this->_addCall(
+ $this->addCall(
$p['type'],
array($p['src'], $p['title'], $p['align'], $p['width'],
$p['height'], $p['cache'], $p['linking']),
@@ -610,7 +887,13 @@ class Doku_Handler {
return true;
}
- function rss($match, $state, $pos) {
+ /**
+ * @param string $match matched syntax
+ * @param int $state a LEXER_STATE_* constant
+ * @param int $pos byte position in the original source file
+ * @return bool mode handled?
+ */
+ public function rss($match, $state, $pos) {
$link = preg_replace(array('/^\{\{rss>/','/\}\}$/'),'',$match);
// get params
@@ -635,11 +918,17 @@ class Doku_Handler {
$p['refresh'] = 14400; // default to 4 hours
}
- $this->_addCall('rss',array($link,$p),$pos);
+ $this->addCall('rss', array($link, $p), $pos);
return true;
}
- function externallink($match, $state, $pos) {
+ /**
+ * @param string $match matched syntax
+ * @param int $state a LEXER_STATE_* constant
+ * @param int $pos byte position in the original source file
+ * @return bool mode handled?
+ */
+ public function externallink($match, $state, $pos) {
$url = $match;
$title = null;
@@ -653,69 +942,82 @@ class Doku_Handler {
$url = 'http://'.$url;
}
- $this->_addCall('externallink',array($url, $title), $pos);
+ $this->addCall('externallink', array($url, $title), $pos);
return true;
}
- function emaillink($match, $state, $pos) {
+ /**
+ * @param string $match matched syntax
+ * @param int $state a LEXER_STATE_* constant
+ * @param int $pos byte position in the original source file
+ * @return bool mode handled?
+ */
+ public function emaillink($match, $state, $pos) {
$email = preg_replace(array('/^</','/>$/'),'',$match);
- $this->_addCall('emaillink',array($email, null), $pos);
+ $this->addCall('emaillink', array($email, null), $pos);
return true;
}
- function table($match, $state, $pos) {
+ /**
+ * @param string $match matched syntax
+ * @param int $state a LEXER_STATE_* constant
+ * @param int $pos byte position in the original source file
+ * @return bool mode handled?
+ */
+ public function table($match, $state, $pos) {
switch ( $state ) {
case DOKU_LEXER_ENTER:
- $ReWriter = new Doku_Handler_Table($this->CallWriter);
- $this->CallWriter = & $ReWriter;
+ $this->callWriter = new Table($this->callWriter);
- $this->_addCall('table_start', array($pos + 1), $pos);
+ $this->addCall('table_start', array($pos + 1), $pos);
if ( trim($match) == '^' ) {
- $this->_addCall('tableheader', array(), $pos);
+ $this->addCall('tableheader', array(), $pos);
} else {
- $this->_addCall('tablecell', array(), $pos);
+ $this->addCall('tablecell', array(), $pos);
}
break;
case DOKU_LEXER_EXIT:
- $this->_addCall('table_end', array($pos), $pos);
- $this->CallWriter->process();
- $ReWriter = & $this->CallWriter;
- $this->CallWriter = & $ReWriter->CallWriter;
+ $this->addCall('table_end', array($pos), $pos);
+ /** @var Table $reWriter */
+ $reWriter = $this->callWriter;
+ $this->callWriter = $reWriter->process();
break;
case DOKU_LEXER_UNMATCHED:
if ( trim($match) != '' ) {
- $this->_addCall('cdata',array($match), $pos);
+ $this->addCall('cdata', array($match), $pos);
}
break;
case DOKU_LEXER_MATCHED:
if ( $match == ' ' ){
- $this->_addCall('cdata', array($match), $pos);
+ $this->addCall('cdata', array($match), $pos);
} else if ( preg_match('/:::/',$match) ) {
- $this->_addCall('rowspan', array($match), $pos);
+ $this->addCall('rowspan', array($match), $pos);
} else if ( preg_match('/\t+/',$match) ) {
- $this->_addCall('table_align', array($match), $pos);
+ $this->addCall('table_align', array($match), $pos);
} else if ( preg_match('/ {2,}/',$match) ) {
- $this->_addCall('table_align', array($match), $pos);
+ $this->addCall('table_align', array($match), $pos);
} else if ( $match == "\n|" ) {
- $this->_addCall('table_row', array(), $pos);
- $this->_addCall('tablecell', array(), $pos);
+ $this->addCall('table_row', array(), $pos);
+ $this->addCall('tablecell', array(), $pos);
} else if ( $match == "\n^" ) {
- $this->_addCall('table_row', array(), $pos);
- $this->_addCall('tableheader', array(), $pos);
+ $this->addCall('table_row', array(), $pos);
+ $this->addCall('tableheader', array(), $pos);
} else if ( $match == '|' ) {
- $this->_addCall('tablecell', array(), $pos);
+ $this->addCall('tablecell', array(), $pos);
} else if ( $match == '^' ) {
- $this->_addCall('tableheader', array(), $pos);
+ $this->addCall('tableheader', array(), $pos);
}
break;
}
return true;
}
+
+ // endregion modes
}
//------------------------------------------------------------------------
@@ -808,1004 +1110,3 @@ function Doku_Handler_Parse_Media($match) {
return $params;
}
-//------------------------------------------------------------------------
-interface Doku_Handler_CallWriter_Interface {
- public function writeCall($call);
- public function writeCalls($calls);
- public function finalise();
-}
-
-class Doku_Handler_CallWriter implements Doku_Handler_CallWriter_Interface {
-
- var $Handler;
-
- /**
- * @param Doku_Handler $Handler
- */
- function __construct(Doku_Handler $Handler) {
- $this->Handler = $Handler;
- }
-
- function writeCall($call) {
- $this->Handler->calls[] = $call;
- }
-
- function writeCalls($calls) {
- $this->Handler->calls = array_merge($this->Handler->calls, $calls);
- }
-
- // function is required, but since this call writer is first/highest in
- // the chain it is not required to do anything
- function finalise() {
- unset($this->Handler);
- }
-}
-
-//------------------------------------------------------------------------
-/**
- * Generic call writer class to handle nesting of rendering instructions
- * within a render instruction. Also see nest() method of renderer base class
- *
- * @author Chris Smith <chris@jalakai.co.uk>
- */
-class Doku_Handler_Nest implements Doku_Handler_CallWriter_Interface {
-
- var $CallWriter;
- var $calls = array();
-
- var $closingInstruction;
-
- /**
- * constructor
- *
- * @param Doku_Handler_CallWriter $CallWriter the renderers current call writer
- * @param string $close closing instruction name, this is required to properly terminate the
- * syntax mode if the document ends without a closing pattern
- */
- function __construct(Doku_Handler_CallWriter_Interface $CallWriter, $close="nest_close") {
- $this->CallWriter = $CallWriter;
-
- $this->closingInstruction = $close;
- }
-
- function writeCall($call) {
- $this->calls[] = $call;
- }
-
- function writeCalls($calls) {
- $this->calls = array_merge($this->calls, $calls);
- }
-
- function finalise() {
- $last_call = end($this->calls);
- $this->writeCall(array($this->closingInstruction,array(), $last_call[2]));
-
- $this->process();
- $this->CallWriter->finalise();
- unset($this->CallWriter);
- }
-
- function process() {
- // merge consecutive cdata
- $unmerged_calls = $this->calls;
- $this->calls = array();
-
- foreach ($unmerged_calls as $call) $this->addCall($call);
-
- $first_call = reset($this->calls);
- $this->CallWriter->writeCall(array("nest", array($this->calls), $first_call[2]));
- }
-
- function addCall($call) {
- $key = count($this->calls);
- if ($key and ($call[0] == 'cdata') and ($this->calls[$key-1][0] == 'cdata')) {
- $this->calls[$key-1][1][0] .= $call[1][0];
- } else if ($call[0] == 'eol') {
- // do nothing (eol shouldn't be allowed, to counter preformatted fix in #1652 & #1699)
- } else {
- $this->calls[] = $call;
- }
- }
-}
-
-class Doku_Handler_List implements Doku_Handler_CallWriter_Interface {
-
- var $CallWriter;
-
- var $calls = array();
- var $listCalls = array();
- var $listStack = array();
-
- const NODE = 1;
-
- function __construct(Doku_Handler_CallWriter_Interface $CallWriter) {
- $this->CallWriter = $CallWriter;
- }
-
- function writeCall($call) {
- $this->calls[] = $call;
- }
-
- // Probably not needed but just in case...
- function writeCalls($calls) {
- $this->calls = array_merge($this->calls, $calls);
-# $this->CallWriter->writeCalls($this->calls);
- }
-
- function finalise() {
- $last_call = end($this->calls);
- $this->writeCall(array('list_close',array(), $last_call[2]));
-
- $this->process();
- $this->CallWriter->finalise();
- unset($this->CallWriter);
- }
-
- //------------------------------------------------------------------------
- function process() {
-
- foreach ( $this->calls as $call ) {
- switch ($call[0]) {
- case 'list_item':
- $this->listOpen($call);
- break;
- case 'list_open':
- $this->listStart($call);
- break;
- case 'list_close':
- $this->listEnd($call);
- break;
- default:
- $this->listContent($call);
- break;
- }
- }
-
- $this->CallWriter->writeCalls($this->listCalls);
- }
-
- //------------------------------------------------------------------------
- function listStart($call) {
- $depth = $this->interpretSyntax($call[1][0], $listType);
-
- $this->initialDepth = $depth;
- // array(list type, current depth, index of current listitem_open)
- $this->listStack[] = array($listType, $depth, 1);
-
- $this->listCalls[] = array('list'.$listType.'_open',array(),$call[2]);
- $this->listCalls[] = array('listitem_open',array(1),$call[2]);
- $this->listCalls[] = array('listcontent_open',array(),$call[2]);
- }
-
- //------------------------------------------------------------------------
- function listEnd($call) {
- $closeContent = true;
-
- while ( $list = array_pop($this->listStack) ) {
- if ( $closeContent ) {
- $this->listCalls[] = array('listcontent_close',array(),$call[2]);
- $closeContent = false;
- }
- $this->listCalls[] = array('listitem_close',array(),$call[2]);
- $this->listCalls[] = array('list'.$list[0].'_close', array(), $call[2]);
- }
- }
-
- //------------------------------------------------------------------------
- function listOpen($call) {
- $depth = $this->interpretSyntax($call[1][0], $listType);
- $end = end($this->listStack);
- $key = key($this->listStack);
-
- // Not allowed to be shallower than initialDepth
- if ( $depth < $this->initialDepth ) {
- $depth = $this->initialDepth;
- }
-
- //------------------------------------------------------------------------
- if ( $depth == $end[1] ) {
-
- // Just another item in the list...
- if ( $listType == $end[0] ) {
- $this->listCalls[] = array('listcontent_close',array(),$call[2]);
- $this->listCalls[] = array('listitem_close',array(),$call[2]);
- $this->listCalls[] = array('listitem_open',array($depth-1),$call[2]);
- $this->listCalls[] = array('listcontent_open',array(),$call[2]);
-
- // new list item, update list stack's index into current listitem_open
- $this->listStack[$key][2] = count($this->listCalls) - 2;
-
- // Switched list type...
- } else {
-
- $this->listCalls[] = array('listcontent_close',array(),$call[2]);
- $this->listCalls[] = array('listitem_close',array(),$call[2]);
- $this->listCalls[] = array('list'.$end[0].'_close', array(), $call[2]);
- $this->listCalls[] = array('list'.$listType.'_open', array(), $call[2]);
- $this->listCalls[] = array('listitem_open', array($depth-1), $call[2]);
- $this->listCalls[] = array('listcontent_open',array(),$call[2]);
-
- array_pop($this->listStack);
- $this->listStack[] = array($listType, $depth, count($this->listCalls) - 2);
- }
-
- //------------------------------------------------------------------------
- // Getting deeper...
- } else if ( $depth > $end[1] ) {
-
- $this->listCalls[] = array('listcontent_close',array(),$call[2]);
- $this->listCalls[] = array('list'.$listType.'_open', array(), $call[2]);
- $this->listCalls[] = array('listitem_open', array($depth-1), $call[2]);
- $this->listCalls[] = array('listcontent_open',array(),$call[2]);
-
- // set the node/leaf state of this item's parent listitem_open to NODE
- $this->listCalls[$this->listStack[$key][2]][1][1] = self::NODE;
-
- $this->listStack[] = array($listType, $depth, count($this->listCalls) - 2);
-
- //------------------------------------------------------------------------
- // Getting shallower ( $depth < $end[1] )
- } else {
- $this->listCalls[] = array('listcontent_close',array(),$call[2]);
- $this->listCalls[] = array('listitem_close',array(),$call[2]);
- $this->listCalls[] = array('list'.$end[0].'_close',array(),$call[2]);
-
- // Throw away the end - done
- array_pop($this->listStack);
-
- while (1) {
- $end = end($this->listStack);
- $key = key($this->listStack);
-
- if ( $end[1] <= $depth ) {
-
- // Normalize depths
- $depth = $end[1];
-
- $this->listCalls[] = array('listitem_close',array(),$call[2]);
-
- if ( $end[0] == $listType ) {
- $this->listCalls[] = array('listitem_open',array($depth-1),$call[2]);
- $this->listCalls[] = array('listcontent_open',array(),$call[2]);
-
- // new list item, update list stack's index into current listitem_open
- $this->listStack[$key][2] = count($this->listCalls) - 2;
-
- } else {
- // Switching list type...
- $this->listCalls[] = array('list'.$end[0].'_close', array(), $call[2]);
- $this->listCalls[] = array('list'.$listType.'_open', array(), $call[2]);
- $this->listCalls[] = array('listitem_open', array($depth-1), $call[2]);
- $this->listCalls[] = array('listcontent_open',array(),$call[2]);
-
- array_pop($this->listStack);
- $this->listStack[] = array($listType, $depth, count($this->listCalls) - 2);
- }
-
- break;
-
- // Haven't dropped down far enough yet.... ( $end[1] > $depth )
- } else {
-
- $this->listCalls[] = array('listitem_close',array(),$call[2]);
- $this->listCalls[] = array('list'.$end[0].'_close',array(),$call[2]);
-
- array_pop($this->listStack);
-
- }
-
- }
-
- }
- }
-
- //------------------------------------------------------------------------
- function listContent($call) {
- $this->listCalls[] = $call;
- }
-
- //------------------------------------------------------------------------
- function interpretSyntax($match, & $type) {
- if ( substr($match,-1) == '*' ) {
- $type = 'u';
- } else {
- $type = 'o';
- }
- // Is the +1 needed? It used to be count(explode(...))
- // but I don't think the number is seen outside this handler
- return substr_count(str_replace("\t",' ',$match), ' ') + 1;
- }
-}
-
-//------------------------------------------------------------------------
-class Doku_Handler_Preformatted implements Doku_Handler_CallWriter_Interface {
-
- var $CallWriter;
-
- var $calls = array();
- var $pos;
- var $text ='';
-
-
-
- function __construct(Doku_Handler_CallWriter_Interface $CallWriter) {
- $this->CallWriter = $CallWriter;
- }
-
- function writeCall($call) {
- $this->calls[] = $call;
- }
-
- // Probably not needed but just in case...
- function writeCalls($calls) {
- $this->calls = array_merge($this->calls, $calls);
-# $this->CallWriter->writeCalls($this->calls);
- }
-
- function finalise() {
- $last_call = end($this->calls);
- $this->writeCall(array('preformatted_end',array(), $last_call[2]));
-
- $this->process();
- $this->CallWriter->finalise();
- unset($this->CallWriter);
- }
-
- function process() {
- foreach ( $this->calls as $call ) {
- switch ($call[0]) {
- case 'preformatted_start':
- $this->pos = $call[2];
- break;
- case 'preformatted_newline':
- $this->text .= "\n";
- break;
- case 'preformatted_content':
- $this->text .= $call[1][0];
- break;
- case 'preformatted_end':
- if (trim($this->text)) {
- $this->CallWriter->writeCall(array('preformatted',array($this->text),$this->pos));
- }
- // see FS#1699 & FS#1652, add 'eol' instructions to ensure proper triggering of following p_open
- $this->CallWriter->writeCall(array('eol',array(),$this->pos));
- $this->CallWriter->writeCall(array('eol',array(),$this->pos));
- break;
- }
- }
- }
-
-}
-
-//------------------------------------------------------------------------
-class Doku_Handler_Quote implements Doku_Handler_CallWriter_Interface {
-
- var $CallWriter;
-
- var $calls = array();
-
- var $quoteCalls = array();
-
- function __construct(Doku_Handler_CallWriter_Interface $CallWriter) {
- $this->CallWriter = $CallWriter;
- }
-
- function writeCall($call) {
- $this->calls[] = $call;
- }
-
- // Probably not needed but just in case...
- function writeCalls($calls) {
- $this->calls = array_merge($this->calls, $calls);
- }
-
- function finalise() {
- $last_call = end($this->calls);
- $this->writeCall(array('quote_end',array(), $last_call[2]));
-
- $this->process();
- $this->CallWriter->finalise();
- unset($this->CallWriter);
- }
-
- function process() {
-
- $quoteDepth = 1;
-
- foreach ( $this->calls as $call ) {
- switch ($call[0]) {
-
- case 'quote_start':
-
- $this->quoteCalls[] = array('quote_open',array(),$call[2]);
-
- case 'quote_newline':
-
- $quoteLength = $this->getDepth($call[1][0]);
-
- if ( $quoteLength > $quoteDepth ) {
- $quoteDiff = $quoteLength - $quoteDepth;
- for ( $i = 1; $i <= $quoteDiff; $i++ ) {
- $this->quoteCalls[] = array('quote_open',array(),$call[2]);
- }
- } else if ( $quoteLength < $quoteDepth ) {
- $quoteDiff = $quoteDepth - $quoteLength;
- for ( $i = 1; $i <= $quoteDiff; $i++ ) {
- $this->quoteCalls[] = array('quote_close',array(),$call[2]);
- }
- } else {
- if ($call[0] != 'quote_start') $this->quoteCalls[] = array('linebreak',array(),$call[2]);
- }
-
- $quoteDepth = $quoteLength;
-
- break;
-
- case 'quote_end':
-
- if ( $quoteDepth > 1 ) {
- $quoteDiff = $quoteDepth - 1;
- for ( $i = 1; $i <= $quoteDiff; $i++ ) {
- $this->quoteCalls[] = array('quote_close',array(),$call[2]);
- }
- }
-
- $this->quoteCalls[] = array('quote_close',array(),$call[2]);
-
- $this->CallWriter->writeCalls($this->quoteCalls);
- break;
-
- default:
- $this->quoteCalls[] = $call;
- break;
- }
- }
- }
-
- function getDepth($marker) {
- preg_match('/>{1,}/', $marker, $matches);
- $quoteLength = strlen($matches[0]);
- return $quoteLength;
- }
-}
-
-//------------------------------------------------------------------------
-class Doku_Handler_Table implements Doku_Handler_CallWriter_Interface {
-
- var $CallWriter;
-
- var $calls = array();
- var $tableCalls = array();
- var $maxCols = 0;
- var $maxRows = 1;
- var $currentCols = 0;
- var $firstCell = false;
- var $lastCellType = 'tablecell';
- var $inTableHead = true;
- var $currentRow = array('tableheader' => 0, 'tablecell' => 0);
- var $countTableHeadRows = 0;
-
- function __construct(Doku_Handler_CallWriter_Interface $CallWriter) {
- $this->CallWriter = $CallWriter;
- }
-
- function writeCall($call) {
- $this->calls[] = $call;
- }
-
- // Probably not needed but just in case...
- function writeCalls($calls) {
- $this->calls = array_merge($this->calls, $calls);
- }
-
- function finalise() {
- $last_call = end($this->calls);
- $this->writeCall(array('table_end',array(), $last_call[2]));
-
- $this->process();
- $this->CallWriter->finalise();
- unset($this->CallWriter);
- }
-
- //------------------------------------------------------------------------
- function process() {
- foreach ( $this->calls as $call ) {
- switch ( $call[0] ) {
- case 'table_start':
- $this->tableStart($call);
- break;
- case 'table_row':
- $this->tableRowClose($call);
- $this->tableRowOpen(array('tablerow_open',$call[1],$call[2]));
- break;
- case 'tableheader':
- case 'tablecell':
- $this->tableCell($call);
- break;
- case 'table_end':
- $this->tableRowClose($call);
- $this->tableEnd($call);
- break;
- default:
- $this->tableDefault($call);
- break;
- }
- }
- $this->CallWriter->writeCalls($this->tableCalls);
- }
-
- function tableStart($call) {
- $this->tableCalls[] = array('table_open',$call[1],$call[2]);
- $this->tableCalls[] = array('tablerow_open',array(),$call[2]);
- $this->firstCell = true;
- }
-
- function tableEnd($call) {
- $this->tableCalls[] = array('table_close',$call[1],$call[2]);
- $this->finalizeTable();
- }
-
- function tableRowOpen($call) {
- $this->tableCalls[] = $call;
- $this->currentCols = 0;
- $this->firstCell = true;
- $this->lastCellType = 'tablecell';
- $this->maxRows++;
- if ($this->inTableHead) {
- $this->currentRow = array('tablecell' => 0, 'tableheader' => 0);
- }
- }
-
- function tableRowClose($call) {
- if ($this->inTableHead && ($this->inTableHead = $this->isTableHeadRow())) {
- $this->countTableHeadRows++;
- }
- // Strip off final cell opening and anything after it
- while ( $discard = array_pop($this->tableCalls ) ) {
-
- if ( $discard[0] == 'tablecell_open' || $discard[0] == 'tableheader_open') {
- break;
- }
- if (!empty($this->currentRow[$discard[0]])) {
- $this->currentRow[$discard[0]]--;
- }
- }
- $this->tableCalls[] = array('tablerow_close', array(), $call[2]);
-
- if ( $this->currentCols > $this->maxCols ) {
- $this->maxCols = $this->currentCols;
- }
- }
-
- function isTableHeadRow() {
- $td = $this->currentRow['tablecell'];
- $th = $this->currentRow['tableheader'];
-
- if (!$th || $td > 2) return false;
- if (2*$td > $th) return false;
-
- return true;
- }
-
- function tableCell($call) {
- if ($this->inTableHead) {
- $this->currentRow[$call[0]]++;
- }
- if ( !$this->firstCell ) {
-
- // Increase the span
- $lastCall = end($this->tableCalls);
-
- // A cell call which follows an open cell means an empty cell so span
- if ( $lastCall[0] == 'tablecell_open' || $lastCall[0] == 'tableheader_open' ) {
- $this->tableCalls[] = array('colspan',array(),$call[2]);
-
- }
-
- $this->tableCalls[] = array($this->lastCellType.'_close',array(),$call[2]);
- $this->tableCalls[] = array($call[0].'_open',array(1,null,1),$call[2]);
- $this->lastCellType = $call[0];
-
- } else {
-
- $this->tableCalls[] = array($call[0].'_open',array(1,null,1),$call[2]);
- $this->lastCellType = $call[0];
- $this->firstCell = false;
-
- }
-
- $this->currentCols++;
- }
-
- function tableDefault($call) {
- $this->tableCalls[] = $call;
- }
-
- function finalizeTable() {
-
- // Add the max cols and rows to the table opening
- if ( $this->tableCalls[0][0] == 'table_open' ) {
- // Adjust to num cols not num col delimeters
- $this->tableCalls[0][1][] = $this->maxCols - 1;
- $this->tableCalls[0][1][] = $this->maxRows;
- $this->tableCalls[0][1][] = array_shift($this->tableCalls[0][1]);
- } else {
- trigger_error('First element in table call list is not table_open');
- }
-
- $lastRow = 0;
- $lastCell = 0;
- $cellKey = array();
- $toDelete = array();
-
- // if still in tableheader, then there can be no table header
- // as all rows can't be within <THEAD>
- if ($this->inTableHead) {
- $this->inTableHead = false;
- $this->countTableHeadRows = 0;
- }
-
- // Look for the colspan elements and increment the colspan on the
- // previous non-empty opening cell. Once done, delete all the cells
- // that contain colspans
- for ($key = 0 ; $key < count($this->tableCalls) ; ++$key) {
- $call = $this->tableCalls[$key];
-
- switch ($call[0]) {
- case 'table_open' :
- if($this->countTableHeadRows) {
- array_splice($this->tableCalls, $key+1, 0, array(
- array('tablethead_open', array(), $call[2]))
- );
- }
- break;
-
- case 'tablerow_open':
-
- $lastRow++;
- $lastCell = 0;
- break;
-
- case 'tablecell_open':
- case 'tableheader_open':
-
- $lastCell++;
- $cellKey[$lastRow][$lastCell] = $key;
- break;
-
- case 'table_align':
-
- $prev = in_array($this->tableCalls[$key-1][0], array('tablecell_open', 'tableheader_open'));
- $next = in_array($this->tableCalls[$key+1][0], array('tablecell_close', 'tableheader_close'));
- // If the cell is empty, align left
- if ($prev && $next) {
- $this->tableCalls[$key-1][1][1] = 'left';
-
- // If the previous element was a cell open, align right
- } elseif ($prev) {
- $this->tableCalls[$key-1][1][1] = 'right';
-
- // If the next element is the close of an element, align either center or left
- } elseif ( $next) {
- if ( $this->tableCalls[$cellKey[$lastRow][$lastCell]][1][1] == 'right' ) {
- $this->tableCalls[$cellKey[$lastRow][$lastCell]][1][1] = 'center';
- } else {
- $this->tableCalls[$cellKey[$lastRow][$lastCell]][1][1] = 'left';
- }
-
- }
-
- // Now convert the whitespace back to cdata
- $this->tableCalls[$key][0] = 'cdata';
- break;
-
- case 'colspan':
-
- $this->tableCalls[$key-1][1][0] = false;
-
- for($i = $key-2; $i >= $cellKey[$lastRow][1]; $i--) {
-
- if ( $this->tableCalls[$i][0] == 'tablecell_open' || $this->tableCalls[$i][0] == 'tableheader_open' ) {
-
- if ( false !== $this->tableCalls[$i][1][0] ) {
- $this->tableCalls[$i][1][0]++;
- break;
- }
-
- }
- }
-
- $toDelete[] = $key-1;
- $toDelete[] = $key;
- $toDelete[] = $key+1;
- break;
-
- case 'rowspan':
-
- if ( $this->tableCalls[$key-1][0] == 'cdata' ) {
- // ignore rowspan if previous call was cdata (text mixed with :::) we don't have to check next call as that wont match regex
- $this->tableCalls[$key][0] = 'cdata';
-
- } else {
-
- $spanning_cell = null;
-
- // can't cross thead/tbody boundary
- if (!$this->countTableHeadRows || ($lastRow-1 != $this->countTableHeadRows)) {
- for($i = $lastRow-1; $i > 0; $i--) {
-
- if ( $this->tableCalls[$cellKey[$i][$lastCell]][0] == 'tablecell_open' || $this->tableCalls[$cellKey[$i][$lastCell]][0] == 'tableheader_open' ) {
-
- if ($this->tableCalls[$cellKey[$i][$lastCell]][1][2] >= $lastRow - $i) {
- $spanning_cell = $i;
- break;
- }
-
- }
- }
- }
- if (is_null($spanning_cell)) {
- // No spanning cell found, so convert this cell to
- // an empty one to avoid broken tables
- $this->tableCalls[$key][0] = 'cdata';
- $this->tableCalls[$key][1][0] = '';
- break;
- }
- $this->tableCalls[$cellKey[$spanning_cell][$lastCell]][1][2]++;
-
- $this->tableCalls[$key-1][1][2] = false;
-
- $toDelete[] = $key-1;
- $toDelete[] = $key;
- $toDelete[] = $key+1;
- }
- break;
-
- case 'tablerow_close':
-
- // Fix broken tables by adding missing cells
- $moreCalls = array();
- while (++$lastCell < $this->maxCols) {
- $moreCalls[] = array('tablecell_open', array(1, null, 1), $call[2]);
- $moreCalls[] = array('cdata', array(''), $call[2]);
- $moreCalls[] = array('tablecell_close', array(), $call[2]);
- }
- $moreCallsLength = count($moreCalls);
- if($moreCallsLength) {
- array_splice($this->tableCalls, $key, 0, $moreCalls);
- $key += $moreCallsLength;
- }
-
- if($this->countTableHeadRows == $lastRow) {
- array_splice($this->tableCalls, $key+1, 0, array(
- array('tablethead_close', array(), $call[2])));
- }
- break;
-
- }
- }
-
- // condense cdata
- $cnt = count($this->tableCalls);
- for( $key = 0; $key < $cnt; $key++){
- if($this->tableCalls[$key][0] == 'cdata'){
- $ckey = $key;
- $key++;
- while($this->tableCalls[$key][0] == 'cdata'){
- $this->tableCalls[$ckey][1][0] .= $this->tableCalls[$key][1][0];
- $toDelete[] = $key;
- $key++;
- }
- continue;
- }
- }
-
- foreach ( $toDelete as $delete ) {
- unset($this->tableCalls[$delete]);
- }
- $this->tableCalls = array_values($this->tableCalls);
- }
-}
-
-
-/**
- * Handler for paragraphs
- *
- * @author Harry Fuecks <hfuecks@gmail.com>
- */
-class Doku_Handler_Block {
- var $calls = array();
- var $skipEol = false;
- var $inParagraph = false;
-
- // Blocks these should not be inside paragraphs
- var $blockOpen = array(
- 'header',
- 'listu_open','listo_open','listitem_open','listcontent_open',
- 'table_open','tablerow_open','tablecell_open','tableheader_open','tablethead_open',
- 'quote_open',
- 'code','file','hr','preformatted','rss',
- 'htmlblock','phpblock',
- 'footnote_open',
- );
-
- var $blockClose = array(
- 'header',
- 'listu_close','listo_close','listitem_close','listcontent_close',
- 'table_close','tablerow_close','tablecell_close','tableheader_close','tablethead_close',
- 'quote_close',
- 'code','file','hr','preformatted','rss',
- 'htmlblock','phpblock',
- 'footnote_close',
- );
-
- // Stacks can contain paragraphs
- var $stackOpen = array(
- 'section_open',
- );
-
- var $stackClose = array(
- 'section_close',
- );
-
-
- /**
- * Constructor. Adds loaded syntax plugins to the block and stack
- * arrays
- *
- * @author Andreas Gohr <andi@splitbrain.org>
- */
- function __construct(){
- global $DOKU_PLUGINS;
- //check if syntax plugins were loaded
- if(empty($DOKU_PLUGINS['syntax'])) return;
- foreach($DOKU_PLUGINS['syntax'] as $n => $p){
- $ptype = $p->getPType();
- if($ptype == 'block'){
- $this->blockOpen[] = 'plugin_'.$n;
- $this->blockClose[] = 'plugin_'.$n;
- }elseif($ptype == 'stack'){
- $this->stackOpen[] = 'plugin_'.$n;
- $this->stackClose[] = 'plugin_'.$n;
- }
- }
- }
-
- function openParagraph($pos){
- if ($this->inParagraph) return;
- $this->calls[] = array('p_open',array(), $pos);
- $this->inParagraph = true;
- $this->skipEol = true;
- }
-
- /**
- * Close a paragraph if needed
- *
- * This function makes sure there are no empty paragraphs on the stack
- *
- * @author Andreas Gohr <andi@splitbrain.org>
- *
- * @param string|integer $pos
- */
- function closeParagraph($pos){
- if (!$this->inParagraph) return;
- // look back if there was any content - we don't want empty paragraphs
- $content = '';
- $ccount = count($this->calls);
- for($i=$ccount-1; $i>=0; $i--){
- if($this->calls[$i][0] == 'p_open'){
- break;
- }elseif($this->calls[$i][0] == 'cdata'){
- $content .= $this->calls[$i][1][0];
- }else{
- $content = 'found markup';
- break;
- }
- }
-
- if(trim($content)==''){
- //remove the whole paragraph
- //array_splice($this->calls,$i); // <- this is much slower than the loop below
- for($x=$ccount; $x>$i; $x--) array_pop($this->calls);
- }else{
- // remove ending linebreaks in the paragraph
- $i=count($this->calls)-1;
- if ($this->calls[$i][0] == 'cdata') $this->calls[$i][1][0] = rtrim($this->calls[$i][1][0],DOKU_PARSER_EOL);
- $this->calls[] = array('p_close',array(), $pos);
- }
-
- $this->inParagraph = false;
- $this->skipEol = true;
- }
-
- function addCall($call) {
- $key = count($this->calls);
- if ($key and ($call[0] == 'cdata') and ($this->calls[$key-1][0] == 'cdata')) {
- $this->calls[$key-1][1][0] .= $call[1][0];
- } else {
- $this->calls[] = $call;
- }
- }
-
- // simple version of addCall, without checking cdata
- function storeCall($call) {
- $this->calls[] = $call;
- }
-
- /**
- * Processes the whole instruction stack to open and close paragraphs
- *
- * @author Harry Fuecks <hfuecks@gmail.com>
- * @author Andreas Gohr <andi@splitbrain.org>
- *
- * @param array $calls
- *
- * @return array
- */
- function process($calls) {
- // open first paragraph
- $this->openParagraph(0);
- foreach ( $calls as $key => $call ) {
- $cname = $call[0];
- if ($cname == 'plugin') {
- $cname='plugin_'.$call[1][0];
- $plugin = true;
- $plugin_open = (($call[1][2] == DOKU_LEXER_ENTER) || ($call[1][2] == DOKU_LEXER_SPECIAL));
- $plugin_close = (($call[1][2] == DOKU_LEXER_EXIT) || ($call[1][2] == DOKU_LEXER_SPECIAL));
- } else {
- $plugin = false;
- }
- /* stack */
- if ( in_array($cname,$this->stackClose ) && (!$plugin || $plugin_close)) {
- $this->closeParagraph($call[2]);
- $this->storeCall($call);
- $this->openParagraph($call[2]);
- continue;
- }
- if ( in_array($cname,$this->stackOpen ) && (!$plugin || $plugin_open) ) {
- $this->closeParagraph($call[2]);
- $this->storeCall($call);
- $this->openParagraph($call[2]);
- continue;
- }
- /* block */
- // If it's a substition it opens and closes at the same call.
- // To make sure next paragraph is correctly started, let close go first.
- if ( in_array($cname, $this->blockClose) && (!$plugin || $plugin_close)) {
- $this->closeParagraph($call[2]);
- $this->storeCall($call);
- $this->openParagraph($call[2]);
- continue;
- }
- if ( in_array($cname, $this->blockOpen) && (!$plugin || $plugin_open)) {
- $this->closeParagraph($call[2]);
- $this->storeCall($call);
- continue;
- }
- /* eol */
- if ( $cname == 'eol' ) {
- // Check this isn't an eol instruction to skip...
- if ( !$this->skipEol ) {
- // Next is EOL => double eol => mark as paragraph
- if ( isset($calls[$key+1]) && $calls[$key+1][0] == 'eol' ) {
- $this->closeParagraph($call[2]);
- $this->openParagraph($call[2]);
- } else {
- //if this is just a single eol make a space from it
- $this->addCall(array('cdata',array(DOKU_PARSER_EOL), $call[2]));
- }
- }
- continue;
- }
- /* normal */
- $this->addCall($call);
- $this->skipEol = false;
- }
- // close last paragraph
- $call = end($this->calls);
- $this->closeParagraph($call[2]);
- return $this->calls;
- }
-}
-
-//Setup VIM: ex: et ts=4 :
diff --git a/inc/parser/lexer.php b/inc/parser/lexer.php
deleted file mode 100644
index ba6a65397..000000000
--- a/inc/parser/lexer.php
+++ /dev/null
@@ -1,614 +0,0 @@
-<?php
-/**
- * Author Markus Baker: http://www.lastcraft.com
- * Version adapted from Simple Test: http://sourceforge.net/projects/simpletest/
- * For an intro to the Lexer see:
- * https://web.archive.org/web/20120125041816/http://www.phppatterns.com/docs/develop/simple_test_lexer_notes
- * @author Marcus Baker
- * @package Doku
- * @subpackage Lexer
- * @version $Id: lexer.php,v 1.1 2005/03/23 23:14:09 harryf Exp $
- */
-
-/**
- * Init path constant
- */
-if(!defined('DOKU_INC')) die('meh.');
-
-/**#@+
- * lexer mode constant
- */
-define("DOKU_LEXER_ENTER", 1);
-define("DOKU_LEXER_MATCHED", 2);
-define("DOKU_LEXER_UNMATCHED", 3);
-define("DOKU_LEXER_EXIT", 4);
-define("DOKU_LEXER_SPECIAL", 5);
-/**#@-*/
-
-/**
- * Compounded regular expression. Any of
- * the contained patterns could match and
- * when one does it's label is returned.
- *
- * @package Doku
- * @subpackage Lexer
- */
-class Doku_LexerParallelRegex {
- var $_patterns;
- var $_labels;
- var $_regex;
- var $_case;
-
- /**
- * Constructor. Starts with no patterns.
- *
- * @param boolean $case True for case sensitive, false
- * for insensitive.
- * @access public
- */
- function __construct($case) {
- $this->_case = $case;
- $this->_patterns = array();
- $this->_labels = array();
- $this->_regex = null;
- }
-
- /**
- * Adds a pattern with an optional label.
- *
- * @param mixed $pattern Perl style regex. Must be UTF-8
- * encoded. If its a string, the (, )
- * lose their meaning unless they
- * form part of a lookahead or
- * lookbehind assertation.
- * @param bool|string $label Label of regex to be returned
- * on a match. Label must be ASCII
- * @access public
- */
- function addPattern($pattern, $label = true) {
- $count = count($this->_patterns);
- $this->_patterns[$count] = $pattern;
- $this->_labels[$count] = $label;
- $this->_regex = null;
- }
-
- /**
- * Attempts to match all patterns at once against a string.
- *
- * @param string $subject String to match against.
- * @param string $match First matched portion of
- * subject.
- * @return boolean True on success.
- * @access public
- */
- function match($subject, &$match) {
- if (count($this->_patterns) == 0) {
- return false;
- }
- if (! preg_match($this->_getCompoundedRegex(), $subject, $matches)) {
- $match = "";
- return false;
- }
-
- $match = $matches[0];
- $size = count($matches);
- for ($i = 1; $i < $size; $i++) {
- if ($matches[$i] && isset($this->_labels[$i - 1])) {
- return $this->_labels[$i - 1];
- }
- }
- return true;
- }
-
- /**
- * Attempts to split the string against all patterns at once
- *
- * @param string $subject String to match against.
- * @param array $split The split result: array containing, pre-match, match & post-match strings
- * @return boolean True on success.
- * @access public
- *
- * @author Christopher Smith <chris@jalakai.co.uk>
- */
- function split($subject, &$split) {
- if (count($this->_patterns) == 0) {
- return false;
- }
-
- if (! preg_match($this->_getCompoundedRegex(), $subject, $matches)) {
- if(function_exists('preg_last_error')){
- $err = preg_last_error();
- switch($err){
- case PREG_BACKTRACK_LIMIT_ERROR:
- msg('A PCRE backtrack error occured. Try to increase the pcre.backtrack_limit in php.ini',-1);
- break;
- case PREG_RECURSION_LIMIT_ERROR:
- msg('A PCRE recursion error occured. Try to increase the pcre.recursion_limit in php.ini',-1);
- break;
- case PREG_BAD_UTF8_ERROR:
- msg('A PCRE UTF-8 error occured. This might be caused by a faulty plugin',-1);
- break;
- case PREG_INTERNAL_ERROR:
- msg('A PCRE internal error occured. This might be caused by a faulty plugin',-1);
- break;
- }
- }
-
- $split = array($subject, "", "");
- return false;
- }
-
- $idx = count($matches)-2;
- list($pre, $post) = preg_split($this->_patterns[$idx].$this->_getPerlMatchingFlags(), $subject, 2);
- $split = array($pre, $matches[0], $post);
-
- return isset($this->_labels[$idx]) ? $this->_labels[$idx] : true;
- }
-
- /**
- * Compounds the patterns into a single
- * regular expression separated with the
- * "or" operator. Caches the regex.
- * Will automatically escape (, ) and / tokens.
- *
- * @internal array $_patterns List of patterns in order.
- * @return null|string
- * @access private
- */
- function _getCompoundedRegex() {
- if ($this->_regex == null) {
- $cnt = count($this->_patterns);
- for ($i = 0; $i < $cnt; $i++) {
-
- /*
- * decompose the input pattern into "(", "(?", ")",
- * "[...]", "[]..]", "[^]..]", "[...[:...:]..]", "\x"...
- * elements.
- */
- preg_match_all('/\\\\.|' .
- '\(\?|' .
- '[()]|' .
- '\[\^?\]?(?:\\\\.|\[:[^]]*:\]|[^]\\\\])*\]|' .
- '[^[()\\\\]+/', $this->_patterns[$i], $elts);
-
- $pattern = "";
- $level = 0;
-
- foreach ($elts[0] as $elt) {
- /*
- * for "(", ")" remember the nesting level, add "\"
- * only to the non-"(?" ones.
- */
-
- switch($elt) {
- case '(':
- $pattern .= '\(';
- break;
- case ')':
- if ($level > 0)
- $level--; /* closing (? */
- else
- $pattern .= '\\';
- $pattern .= ')';
- break;
- case '(?':
- $level++;
- $pattern .= '(?';
- break;
- default:
- if (substr($elt, 0, 1) == '\\')
- $pattern .= $elt;
- else
- $pattern .= str_replace('/', '\/', $elt);
- }
- }
- $this->_patterns[$i] = "($pattern)";
- }
- $this->_regex = "/" . implode("|", $this->_patterns) . "/" . $this->_getPerlMatchingFlags();
- }
- return $this->_regex;
- }
-
- /**
- * Accessor for perl regex mode flags to use.
- * @return string Perl regex flags.
- * @access private
- */
- function _getPerlMatchingFlags() {
- return ($this->_case ? "msS" : "msSi");
- }
-}
-
-/**
- * States for a stack machine.
- * @package Lexer
- * @subpackage Lexer
- */
-class Doku_LexerStateStack {
- var $_stack;
-
- /**
- * Constructor. Starts in named state.
- * @param string $start Starting state name.
- * @access public
- */
- function __construct($start) {
- $this->_stack = array($start);
- }
-
- /**
- * Accessor for current state.
- * @return string State.
- * @access public
- */
- function getCurrent() {
- return $this->_stack[count($this->_stack) - 1];
- }
-
- /**
- * Adds a state to the stack and sets it
- * to be the current state.
- * @param string $state New state.
- * @access public
- */
- function enter($state) {
- array_push($this->_stack, $state);
- }
-
- /**
- * Leaves the current state and reverts
- * to the previous one.
- * @return boolean False if we drop off
- * the bottom of the list.
- * @access public
- */
- function leave() {
- if (count($this->_stack) == 1) {
- return false;
- }
- array_pop($this->_stack);
- return true;
- }
-}
-
-/**
- * Accepts text and breaks it into tokens.
- * Some optimisation to make the sure the
- * content is only scanned by the PHP regex
- * parser once. Lexer modes must not start
- * with leading underscores.
- * @package Doku
- * @subpackage Lexer
- */
-class Doku_Lexer {
- var $_regexes;
- var $_parser;
- var $_mode;
- var $_mode_handlers;
- var $_case;
-
- /**
- * Sets up the lexer in case insensitive matching
- * by default.
- * @param Doku_Parser $parser Handling strategy by
- * reference.
- * @param string $start Starting handler.
- * @param boolean $case True for case sensitive.
- * @access public
- */
- function __construct($parser, $start = "accept", $case = false) {
- $this->_case = $case;
- /** @var Doku_LexerParallelRegex[] _regexes */
- $this->_regexes = array();
- $this->_parser = $parser;
- $this->_mode = new Doku_LexerStateStack($start);
- $this->_mode_handlers = array();
- }
-
- /**
- * Adds a token search pattern for a particular
- * parsing mode. The pattern does not change the
- * current mode.
- * @param string $pattern Perl style regex, but ( and )
- * lose the usual meaning.
- * @param string $mode Should only apply this
- * pattern when dealing with
- * this type of input.
- * @access public
- */
- function addPattern($pattern, $mode = "accept") {
- if (! isset($this->_regexes[$mode])) {
- $this->_regexes[$mode] = new Doku_LexerParallelRegex($this->_case);
- }
- $this->_regexes[$mode]->addPattern($pattern);
- }
-
- /**
- * Adds a pattern that will enter a new parsing
- * mode. Useful for entering parenthesis, strings,
- * tags, etc.
- * @param string $pattern Perl style regex, but ( and )
- * lose the usual meaning.
- * @param string $mode Should only apply this
- * pattern when dealing with
- * this type of input.
- * @param string $new_mode Change parsing to this new
- * nested mode.
- * @access public
- */
- function addEntryPattern($pattern, $mode, $new_mode) {
- if (! isset($this->_regexes[$mode])) {
- $this->_regexes[$mode] = new Doku_LexerParallelRegex($this->_case);
- }
- $this->_regexes[$mode]->addPattern($pattern, $new_mode);
- }
-
- /**
- * Adds a pattern that will exit the current mode
- * and re-enter the previous one.
- * @param string $pattern Perl style regex, but ( and )
- * lose the usual meaning.
- * @param string $mode Mode to leave.
- * @access public
- */
- function addExitPattern($pattern, $mode) {
- if (! isset($this->_regexes[$mode])) {
- $this->_regexes[$mode] = new Doku_LexerParallelRegex($this->_case);
- }
- $this->_regexes[$mode]->addPattern($pattern, "__exit");
- }
-
- /**
- * Adds a pattern that has a special mode. Acts as an entry
- * and exit pattern in one go, effectively calling a special
- * parser handler for this token only.
- * @param string $pattern Perl style regex, but ( and )
- * lose the usual meaning.
- * @param string $mode Should only apply this
- * pattern when dealing with
- * this type of input.
- * @param string $special Use this mode for this one token.
- * @access public
- */
- function addSpecialPattern($pattern, $mode, $special) {
- if (! isset($this->_regexes[$mode])) {
- $this->_regexes[$mode] = new Doku_LexerParallelRegex($this->_case);
- }
- $this->_regexes[$mode]->addPattern($pattern, "_$special");
- }
-
- /**
- * Adds a mapping from a mode to another handler.
- * @param string $mode Mode to be remapped.
- * @param string $handler New target handler.
- * @access public
- */
- function mapHandler($mode, $handler) {
- $this->_mode_handlers[$mode] = $handler;
- }
-
- /**
- * Splits the page text into tokens. Will fail
- * if the handlers report an error or if no
- * content is consumed. If successful then each
- * unparsed and parsed token invokes a call to the
- * held listener.
- * @param string $raw Raw HTML text.
- * @return boolean True on success, else false.
- * @access public
- */
- function parse($raw) {
- if (! isset($this->_parser)) {
- return false;
- }
- $initialLength = strlen($raw);
- $length = $initialLength;
- $pos = 0;
- while (is_array($parsed = $this->_reduce($raw))) {
- list($unmatched, $matched, $mode) = $parsed;
- $currentLength = strlen($raw);
- $matchPos = $initialLength - $currentLength - strlen($matched);
- if (! $this->_dispatchTokens($unmatched, $matched, $mode, $pos, $matchPos)) {
- return false;
- }
- if ($currentLength == $length) {
- return false;
- }
- $length = $currentLength;
- $pos = $initialLength - $currentLength;
- }
- if (!$parsed) {
- return false;
- }
- return $this->_invokeParser($raw, DOKU_LEXER_UNMATCHED, $pos);
- }
-
- /**
- * Sends the matched token and any leading unmatched
- * text to the parser changing the lexer to a new
- * mode if one is listed.
- * @param string $unmatched Unmatched leading portion.
- * @param string $matched Actual token match.
- * @param bool|string $mode Mode after match. A boolean
- * false mode causes no change.
- * @param int $initialPos
- * @param int $matchPos
- * Current byte index location in raw doc
- * thats being parsed
- * @return boolean False if there was any error
- * from the parser.
- * @access private
- */
- function _dispatchTokens($unmatched, $matched, $mode = false, $initialPos, $matchPos) {
- if (! $this->_invokeParser($unmatched, DOKU_LEXER_UNMATCHED, $initialPos) ){
- return false;
- }
- if ($this->_isModeEnd($mode)) {
- if (! $this->_invokeParser($matched, DOKU_LEXER_EXIT, $matchPos)) {
- return false;
- }
- return $this->_mode->leave();
- }
- if ($this->_isSpecialMode($mode)) {
- $this->_mode->enter($this->_decodeSpecial($mode));
- if (! $this->_invokeParser($matched, DOKU_LEXER_SPECIAL, $matchPos)) {
- return false;
- }
- return $this->_mode->leave();
- }
- if (is_string($mode)) {
- $this->_mode->enter($mode);
- return $this->_invokeParser($matched, DOKU_LEXER_ENTER, $matchPos);
- }
- return $this->_invokeParser($matched, DOKU_LEXER_MATCHED, $matchPos);
- }
-
- /**
- * Tests to see if the new mode is actually to leave
- * the current mode and pop an item from the matching
- * mode stack.
- * @param string $mode Mode to test.
- * @return boolean True if this is the exit mode.
- * @access private
- */
- function _isModeEnd($mode) {
- return ($mode === "__exit");
- }
-
- /**
- * Test to see if the mode is one where this mode
- * is entered for this token only and automatically
- * leaves immediately afterwoods.
- * @param string $mode Mode to test.
- * @return boolean True if this is the exit mode.
- * @access private
- */
- function _isSpecialMode($mode) {
- return (strncmp($mode, "_", 1) == 0);
- }
-
- /**
- * Strips the magic underscore marking single token
- * modes.
- * @param string $mode Mode to decode.
- * @return string Underlying mode name.
- * @access private
- */
- function _decodeSpecial($mode) {
- return substr($mode, 1);
- }
-
- /**
- * Calls the parser method named after the current
- * mode. Empty content will be ignored. The lexer
- * has a parser handler for each mode in the lexer.
- * @param string $content Text parsed.
- * @param boolean $is_match Token is recognised rather
- * than unparsed data.
- * @param int $pos Current byte index location in raw doc
- * thats being parsed
- * @return bool
- * @access private
- */
- function _invokeParser($content, $is_match, $pos) {
- if (($content === "") || ($content === false)) {
- return true;
- }
- $handler = $this->_mode->getCurrent();
- if (isset($this->_mode_handlers[$handler])) {
- $handler = $this->_mode_handlers[$handler];
- }
-
- // modes starting with plugin_ are all handled by the same
- // handler but with an additional parameter
- if(substr($handler,0,7)=='plugin_'){
- list($handler,$plugin) = explode('_',$handler,2);
- return $this->_parser->$handler($content, $is_match, $pos, $plugin);
- }
-
- return $this->_parser->$handler($content, $is_match, $pos);
- }
-
- /**
- * Tries to match a chunk of text and if successful
- * removes the recognised chunk and any leading
- * unparsed data. Empty strings will not be matched.
- * @param string $raw The subject to parse. This is the
- * content that will be eaten.
- * @return array Three item list of unparsed
- * content followed by the
- * recognised token and finally the
- * action the parser is to take.
- * True if no match, false if there
- * is a parsing error.
- * @access private
- */
- function _reduce(&$raw) {
- if (! isset($this->_regexes[$this->_mode->getCurrent()])) {
- return false;
- }
- if ($raw === "") {
- return true;
- }
- if ($action = $this->_regexes[$this->_mode->getCurrent()]->split($raw, $split)) {
- list($unparsed, $match, $raw) = $split;
- return array($unparsed, $match, $action);
- }
- return true;
- }
-}
-
-/**
- * Escapes regex characters other than (, ) and /
- *
- * @TODO
- *
- * @param string $str
- *
- * @return mixed
- */
-function Doku_Lexer_Escape($str) {
- //$str = addslashes($str);
- $chars = array(
- '/\\\\/',
- '/\./',
- '/\+/',
- '/\*/',
- '/\?/',
- '/\[/',
- '/\^/',
- '/\]/',
- '/\$/',
- '/\{/',
- '/\}/',
- '/\=/',
- '/\!/',
- '/\</',
- '/\>/',
- '/\|/',
- '/\:/'
- );
-
- $escaped = array(
- '\\\\\\\\',
- '\.',
- '\+',
- '\*',
- '\?',
- '\[',
- '\^',
- '\]',
- '\$',
- '\{',
- '\}',
- '\=',
- '\!',
- '\<',
- '\>',
- '\|',
- '\:'
- );
- return preg_replace($chars, $escaped, $str);
-}
-
-//Setup VIM: ex: et ts=4 sw=4 :
diff --git a/inc/parser/metadata.php b/inc/parser/metadata.php
index f9e05bd81..fa64ae2ec 100644
--- a/inc/parser/metadata.php
+++ b/inc/parser/metadata.php
@@ -1,22 +1,5 @@
<?php
/**
- * Renderer for metadata
- *
- * @author Esther Brunner <wikidesign@gmail.com>
- */
-if(!defined('DOKU_INC')) die('meh.');
-
-if(!defined('DOKU_LF')) {
- // Some whitespace to help View > Source
- define ('DOKU_LF', "\n");
-}
-
-if(!defined('DOKU_TAB')) {
- // Some whitespace to help View > Source
- define ('DOKU_TAB', "\t");
-}
-
-/**
* The MetaData Renderer
*
* Metadata is additional information about a DokuWiki page that gets extracted mainly from the page's content
@@ -24,8 +7,11 @@ if(!defined('DOKU_TAB')) {
* $persistent.
*
* Some simplified rendering to $doc is done to gather the page's (text-only) abstract.
+ *
+ * @author Esther Brunner <wikidesign@gmail.com>
*/
-class Doku_Renderer_metadata extends Doku_Renderer {
+class Doku_Renderer_metadata extends Doku_Renderer
+{
/** the approximate byte lenght to capture for the abstract */
const ABSTRACT_LEN = 250;
@@ -61,7 +47,8 @@ class Doku_Renderer_metadata extends Doku_Renderer {
*
* @return string always 'metadata'
*/
- function getFormat() {
+ public function getFormat()
+ {
return 'metadata';
}
@@ -70,19 +57,20 @@ class Doku_Renderer_metadata extends Doku_Renderer {
*
* Sets up some of the persistent info about the page if it doesn't exist, yet.
*/
- function document_start() {
+ public function document_start()
+ {
global $ID;
$this->headers = array();
// external pages are missing create date
- if(!$this->persistent['date']['created']) {
+ if (!$this->persistent['date']['created']) {
$this->persistent['date']['created'] = filectime(wikiFN($ID));
}
- if(!isset($this->persistent['user'])) {
+ if (!isset($this->persistent['user'])) {
$this->persistent['user'] = '';
}
- if(!isset($this->persistent['creator'])) {
+ if (!isset($this->persistent['creator'])) {
$this->persistent['creator'] = '';
}
// reset metadata to persistent values
@@ -94,27 +82,27 @@ class Doku_Renderer_metadata extends Doku_Renderer {
*
* Stores collected data in the metadata
*/
- function document_end() {
+ public function document_end()
+ {
global $ID;
// store internal info in metadata (notoc,nocache)
$this->meta['internal'] = $this->info;
- if(!isset($this->meta['description']['abstract'])) {
+ if (!isset($this->meta['description']['abstract'])) {
// cut off too long abstracts
$this->doc = trim($this->doc);
- if(strlen($this->doc) > self::ABSTRACT_MAX) {
- $this->doc = utf8_substr($this->doc, 0, self::ABSTRACT_MAX).'…';
+ if (strlen($this->doc) > self::ABSTRACT_MAX) {
+ $this->doc = \dokuwiki\Utf8\PhpString::substr($this->doc, 0, self::ABSTRACT_MAX).'…';
}
$this->meta['description']['abstract'] = $this->doc;
}
$this->meta['relation']['firstimage'] = $this->firstimage;
- if(!isset($this->meta['date']['modified'])) {
+ if (!isset($this->meta['date']['modified'])) {
$this->meta['date']['modified'] = filemtime(wikiFN($ID));
}
-
}
/**
@@ -125,13 +113,18 @@ class Doku_Renderer_metadata extends Doku_Renderer {
*
* @param $text
*/
- function cdata($text) {
- if(!$this->capture || !$this->capturing) return;
+ public function cdata($text)
+ {
+ if (!$this->capture || !$this->capturing) {
+ return;
+ }
$this->doc .= $text;
$this->captured += strlen($text);
- if($this->captured > self::ABSTRACT_LEN) $this->capture = false;
+ if ($this->captured > self::ABSTRACT_LEN) {
+ $this->capture = false;
+ }
}
/**
@@ -141,11 +134,12 @@ class Doku_Renderer_metadata extends Doku_Renderer {
* @param string $text the text to display
* @param int $level the nesting level
*/
- function toc_additem($id, $text, $level) {
+ public function toc_additem($id, $text, $level)
+ {
global $conf;
//only add items within configured levels
- if($level >= $conf['toptoclevel'] && $level <= $conf['maxtoclevel']) {
+ if ($level >= $conf['toptoclevel'] && $level <= $conf['maxtoclevel']) {
// the TOC is one of our standard ul list arrays ;-)
$this->meta['description']['tableofcontents'][] = array(
'hid' => $id,
@@ -154,7 +148,6 @@ class Doku_Renderer_metadata extends Doku_Renderer {
'level' => $level - $conf['toptoclevel'] + 1
);
}
-
}
/**
@@ -164,8 +157,11 @@ class Doku_Renderer_metadata extends Doku_Renderer {
* @param int $level header level
* @param int $pos byte position in the original source
*/
- function header($text, $level, $pos) {
- if(!isset($this->meta['title'])) $this->meta['title'] = $text;
+ public function header($text, $level, $pos)
+ {
+ if (!isset($this->meta['title'])) {
+ $this->meta['title'] = $text;
+ }
// add the header to the TOC
$hid = $this->_headerToLink($text, true);
@@ -178,28 +174,32 @@ class Doku_Renderer_metadata extends Doku_Renderer {
/**
* Open a paragraph
*/
- function p_open() {
+ public function p_open()
+ {
$this->cdata(DOKU_LF);
}
/**
* Close a paragraph
*/
- function p_close() {
+ public function p_close()
+ {
$this->cdata(DOKU_LF);
}
/**
* Create a line break
*/
- function linebreak() {
+ public function linebreak()
+ {
$this->cdata(DOKU_LF);
}
/**
* Create a horizontal line
*/
- function hr() {
+ public function hr()
+ {
$this->cdata(DOKU_LF.'----------'.DOKU_LF);
}
@@ -212,8 +212,9 @@ class Doku_Renderer_metadata extends Doku_Renderer {
*
* @author Andreas Gohr <andi@splitbrain.org>
*/
- function footnote_open() {
- if($this->capture) {
+ public function footnote_open()
+ {
+ if ($this->capture) {
// move current content to store
// this is required to ensure safe behaviour of plugins accessed within footnotes
$this->store = $this->doc;
@@ -232,8 +233,9 @@ class Doku_Renderer_metadata extends Doku_Renderer {
*
* @author Andreas Gohr
*/
- function footnote_close() {
- if($this->capture) {
+ public function footnote_close()
+ {
+ if ($this->capture) {
// re-enable capturing
$this->capturing = true;
// restore previously rendered content
@@ -245,14 +247,16 @@ class Doku_Renderer_metadata extends Doku_Renderer {
/**
* Open an unordered list
*/
- function listu_open() {
+ public function listu_open()
+ {
$this->cdata(DOKU_LF);
}
/**
* Open an ordered list
*/
- function listo_open() {
+ public function listo_open()
+ {
$this->cdata(DOKU_LF);
}
@@ -262,14 +266,16 @@ class Doku_Renderer_metadata extends Doku_Renderer {
* @param int $level the nesting level
* @param bool $node true when a node; false when a leaf
*/
- function listitem_open($level,$node=false) {
+ public function listitem_open($level, $node=false)
+ {
$this->cdata(str_repeat(DOKU_TAB, $level).'* ');
}
/**
* Close a list item
*/
- function listitem_close() {
+ public function listitem_close()
+ {
$this->cdata(DOKU_LF);
}
@@ -278,21 +284,24 @@ class Doku_Renderer_metadata extends Doku_Renderer {
*
* @param string $text
*/
- function preformatted($text) {
+ public function preformatted($text)
+ {
$this->cdata($text);
}
/**
* Start a block quote
*/
- function quote_open() {
+ public function quote_open()
+ {
$this->cdata(DOKU_LF.DOKU_TAB.'"');
}
/**
* Stop a block quote
*/
- function quote_close() {
+ public function quote_close()
+ {
$this->cdata('"'.DOKU_LF);
}
@@ -303,7 +312,8 @@ class Doku_Renderer_metadata extends Doku_Renderer {
* @param string $lang programming language to use for syntax highlighting
* @param string $file file path label
*/
- function file($text, $lang = null, $file = null) {
+ public function file($text, $lang = null, $file = null)
+ {
$this->cdata(DOKU_LF.$text.DOKU_LF);
}
@@ -314,7 +324,8 @@ class Doku_Renderer_metadata extends Doku_Renderer {
* @param string $language programming language to use for syntax highlighting
* @param string $file file path label
*/
- function code($text, $language = null, $file = null) {
+ public function code($text, $language = null, $file = null)
+ {
$this->cdata(DOKU_LF.$text.DOKU_LF);
}
@@ -325,7 +336,8 @@ class Doku_Renderer_metadata extends Doku_Renderer {
*
* @param string $acronym
*/
- function acronym($acronym) {
+ public function acronym($acronym)
+ {
$this->cdata($acronym);
}
@@ -336,7 +348,8 @@ class Doku_Renderer_metadata extends Doku_Renderer {
*
* @param string $smiley
*/
- function smiley($smiley) {
+ public function smiley($smiley)
+ {
$this->cdata($smiley);
}
@@ -349,7 +362,8 @@ class Doku_Renderer_metadata extends Doku_Renderer {
*
* @param string $entity
*/
- function entity($entity) {
+ public function entity($entity)
+ {
$this->cdata($entity);
}
@@ -361,14 +375,16 @@ class Doku_Renderer_metadata extends Doku_Renderer {
* @param string|int $x first value
* @param string|int $y second value
*/
- function multiplyentity($x, $y) {
+ public function multiplyentity($x, $y)
+ {
$this->cdata($x.'×'.$y);
}
/**
* Render an opening single quote char (language specific)
*/
- function singlequoteopening() {
+ public function singlequoteopening()
+ {
global $lang;
$this->cdata($lang['singlequoteopening']);
}
@@ -376,7 +392,8 @@ class Doku_Renderer_metadata extends Doku_Renderer {
/**
* Render a closing single quote char (language specific)
*/
- function singlequoteclosing() {
+ public function singlequoteclosing()
+ {
global $lang;
$this->cdata($lang['singlequoteclosing']);
}
@@ -384,7 +401,8 @@ class Doku_Renderer_metadata extends Doku_Renderer {
/**
* Render an apostrophe char (language specific)
*/
- function apostrophe() {
+ public function apostrophe()
+ {
global $lang;
$this->cdata($lang['apostrophe']);
}
@@ -392,7 +410,8 @@ class Doku_Renderer_metadata extends Doku_Renderer {
/**
* Render an opening double quote char (language specific)
*/
- function doublequoteopening() {
+ public function doublequoteopening()
+ {
global $lang;
$this->cdata($lang['doublequoteopening']);
}
@@ -400,7 +419,8 @@ class Doku_Renderer_metadata extends Doku_Renderer {
/**
* Render an closinging double quote char (language specific)
*/
- function doublequoteclosing() {
+ public function doublequoteclosing()
+ {
global $lang;
$this->cdata($lang['doublequoteclosing']);
}
@@ -411,7 +431,8 @@ class Doku_Renderer_metadata extends Doku_Renderer {
* @param string $link The link name
* @see http://en.wikipedia.org/wiki/CamelCase
*/
- function camelcaselink($link) {
+ public function camelcaselink($link)
+ {
$this->internallink($link, $link);
}
@@ -421,10 +442,13 @@ class Doku_Renderer_metadata extends Doku_Renderer {
* @param string $hash hash link identifier
* @param string $name name for the link
*/
- function locallink($hash, $name = null) {
- if(is_array($name)) {
+ public function locallink($hash, $name = null)
+ {
+ if (is_array($name)) {
$this->_firstimage($name['src']);
- if($name['type'] == 'internalmedia') $this->_recordMediaUsage($name['src']);
+ if ($name['type'] == 'internalmedia') {
+ $this->_recordMediaUsage($name['src']);
+ }
}
}
@@ -434,16 +458,19 @@ class Doku_Renderer_metadata extends Doku_Renderer {
* @param string $id page ID to link to. eg. 'wiki:syntax'
* @param string|array|null $name name for the link, array for media file
*/
- function internallink($id, $name = null) {
+ public function internallink($id, $name = null)
+ {
global $ID;
- if(is_array($name)) {
+ if (is_array($name)) {
$this->_firstimage($name['src']);
- if($name['type'] == 'internalmedia') $this->_recordMediaUsage($name['src']);
+ if ($name['type'] == 'internalmedia') {
+ $this->_recordMediaUsage($name['src']);
+ }
}
$parts = explode('?', $id, 2);
- if(count($parts) === 2) {
+ if (count($parts) === 2) {
$id = $parts[0];
}
@@ -459,7 +486,7 @@ class Doku_Renderer_metadata extends Doku_Renderer {
// p_set_metadata($id, $data);
// add link title to summary
- if($this->capture) {
+ if ($this->capture) {
$name = $this->_getLinkTitle($name, $default, $id);
$this->doc .= $name;
}
@@ -471,13 +498,16 @@ class Doku_Renderer_metadata extends Doku_Renderer {
* @param string $url full URL with scheme
* @param string|array|null $name name for the link, array for media file
*/
- function externallink($url, $name = null) {
- if(is_array($name)) {
+ public function externallink($url, $name = null)
+ {
+ if (is_array($name)) {
$this->_firstimage($name['src']);
- if($name['type'] == 'internalmedia') $this->_recordMediaUsage($name['src']);
+ if ($name['type'] == 'internalmedia') {
+ $this->_recordMediaUsage($name['src']);
+ }
}
- if($this->capture) {
+ if ($this->capture) {
$this->doc .= $this->_getLinkTitle($name, '<'.$url.'>');
}
}
@@ -492,13 +522,16 @@ class Doku_Renderer_metadata extends Doku_Renderer {
* @param string $wikiName indentifier (shortcut) for the remote wiki
* @param string $wikiUri the fragment parsed from the original link
*/
- function interwikilink($match, $name = null, $wikiName, $wikiUri) {
- if(is_array($name)) {
+ public function interwikilink($match, $name, $wikiName, $wikiUri)
+ {
+ if (is_array($name)) {
$this->_firstimage($name['src']);
- if($name['type'] == 'internalmedia') $this->_recordMediaUsage($name['src']);
+ if ($name['type'] == 'internalmedia') {
+ $this->_recordMediaUsage($name['src']);
+ }
}
- if($this->capture) {
+ if ($this->capture) {
list($wikiUri) = explode('#', $wikiUri, 2);
$name = $this->_getLinkTitle($name, $wikiUri);
$this->doc .= $name;
@@ -511,15 +544,21 @@ class Doku_Renderer_metadata extends Doku_Renderer {
* @param string $url the link
* @param string|array $name name for the link, array for media file
*/
- function windowssharelink($url, $name = null) {
- if(is_array($name)) {
+ public function windowssharelink($url, $name = null)
+ {
+ if (is_array($name)) {
$this->_firstimage($name['src']);
- if($name['type'] == 'internalmedia') $this->_recordMediaUsage($name['src']);
+ if ($name['type'] == 'internalmedia') {
+ $this->_recordMediaUsage($name['src']);
+ }
}
- if($this->capture) {
- if($name) $this->doc .= $name;
- else $this->doc .= '<'.$url.'>';
+ if ($this->capture) {
+ if ($name) {
+ $this->doc .= $name;
+ } else {
+ $this->doc .= '<'.$url.'>';
+ }
}
}
@@ -531,15 +570,21 @@ class Doku_Renderer_metadata extends Doku_Renderer {
* @param string $address Email-Address
* @param string|array $name name for the link, array for media file
*/
- function emaillink($address, $name = null) {
- if(is_array($name)) {
+ public function emaillink($address, $name = null)
+ {
+ if (is_array($name)) {
$this->_firstimage($name['src']);
- if($name['type'] == 'internalmedia') $this->_recordMediaUsage($name['src']);
+ if ($name['type'] == 'internalmedia') {
+ $this->_recordMediaUsage($name['src']);
+ }
}
- if($this->capture) {
- if($name) $this->doc .= $name;
- else $this->doc .= '<'.$address.'>';
+ if ($this->capture) {
+ if ($name) {
+ $this->doc .= $name;
+ } else {
+ $this->doc .= '<'.$address.'>';
+ }
}
}
@@ -554,9 +599,12 @@ class Doku_Renderer_metadata extends Doku_Renderer {
* @param string $cache cache|recache|nocache
* @param string $linking linkonly|detail|nolink
*/
- function internalmedia($src, $title = null, $align = null, $width = null,
- $height = null, $cache = null, $linking = null) {
- if($this->capture && $title) $this->doc .= '['.$title.']';
+ public function internalmedia($src, $title = null, $align = null, $width = null,
+ $height = null, $cache = null, $linking = null)
+ {
+ if ($this->capture && $title) {
+ $this->doc .= '['.$title.']';
+ }
$this->_firstimage($src);
$this->_recordMediaUsage($src);
}
@@ -572,9 +620,12 @@ class Doku_Renderer_metadata extends Doku_Renderer {
* @param string $cache cache|recache|nocache
* @param string $linking linkonly|detail|nolink
*/
- function externalmedia($src, $title = null, $align = null, $width = null,
- $height = null, $cache = null, $linking = null) {
- if($this->capture && $title) $this->doc .= '['.$title.']';
+ public function externalmedia($src, $title = null, $align = null, $width = null,
+ $height = null, $cache = null, $linking = null)
+ {
+ if ($this->capture && $title) {
+ $this->doc .= '['.$title.']';
+ }
$this->_firstimage($src);
}
@@ -584,7 +635,8 @@ class Doku_Renderer_metadata extends Doku_Renderer {
* @param string $url URL of the feed
* @param array $params Finetuning of the output
*/
- function rss($url, $params) {
+ public function rss($url, $params)
+ {
$this->meta['relation']['haspart'][$url] = true;
$this->meta['date']['valid']['age'] =
@@ -605,12 +657,15 @@ class Doku_Renderer_metadata extends Doku_Renderer {
*
* @return mixed|string
*/
- function _simpleTitle($name) {
+ public function _simpleTitle($name)
+ {
global $conf;
- if(is_array($name)) return '';
+ if (is_array($name)) {
+ return '';
+ }
- if($conf['useslash']) {
+ if ($conf['useslash']) {
$nssep = '[:;/]';
} else {
$nssep = '[:;]';
@@ -622,23 +677,6 @@ class Doku_Renderer_metadata extends Doku_Renderer {
}
/**
- * Creates a linkid from a headline
- *
- * @author Andreas Gohr <andi@splitbrain.org>
- * @param string $title The headline title
- * @param boolean $create Create a new unique ID?
- * @return string
- */
- function _headerToLink($title, $create = false) {
- if($create) {
- return sectionID($title, $this->headers);
- } else {
- $check = false;
- return sectionID($title, $check);
- }
- }
-
- /**
* Construct a title and handle images in titles
*
* @author Harry Fuecks <hfuecks@gmail.com>
@@ -647,17 +685,20 @@ class Doku_Renderer_metadata extends Doku_Renderer {
* @param null|string $id linked page id (used to extract title from first heading)
* @return string title text
*/
- function _getLinkTitle($title, $default, $id = null) {
- if(is_array($title)) {
- if($title['title']) {
+ public function _getLinkTitle($title, $default, $id = null)
+ {
+ if (is_array($title)) {
+ if ($title['title']) {
return '['.$title['title'].']';
} else {
return $default;
}
- } else if(is_null($title) || trim($title) == '') {
- if(useHeading('content') && $id) {
+ } elseif (is_null($title) || trim($title) == '') {
+ if (useHeading('content') && $id) {
$heading = p_get_first_heading($id, METADATA_DONT_RENDER);
- if($heading) return $heading;
+ if ($heading) {
+ return $heading;
+ }
}
return $default;
} else {
@@ -670,15 +711,19 @@ class Doku_Renderer_metadata extends Doku_Renderer {
*
* @param string $src image URL or ID
*/
- function _firstimage($src) {
- if($this->firstimage) return;
+ protected function _firstimage($src)
+ {
global $ID;
+ if ($this->firstimage) {
+ return;
+ }
+
list($src) = explode('#', $src, 2);
- if(!media_isexternal($src)) {
+ if (!media_isexternal($src)) {
resolve_mediaid(getNS($ID), $src, $exists);
}
- if(preg_match('/.(jpe?g|gif|png)$/i', $src)) {
+ if (preg_match('/.(jpe?g|gif|png)$/i', $src)) {
$this->firstimage = $src;
}
}
@@ -688,11 +733,14 @@ class Doku_Renderer_metadata extends Doku_Renderer {
*
* @param string $src media ID
*/
- function _recordMediaUsage($src) {
+ protected function _recordMediaUsage($src)
+ {
global $ID;
list ($src) = explode('#', $src, 2);
- if(media_isexternal($src)) return;
+ if (media_isexternal($src)) {
+ return;
+ }
resolve_mediaid(getNS($ID), $src, $exists);
$this->meta['relation']['media'][$src] = $exists;
}
diff --git a/inc/parser/parser.php b/inc/parser/parser.php
index 8cff2b8be..d9fc5fb8f 100644
--- a/inc/parser/parser.php
+++ b/inc/parser/parser.php
@@ -1,8 +1,4 @@
<?php
-if(!defined('DOKU_INC')) die('meh.');
-require_once DOKU_INC . 'inc/parser/lexer.php';
-require_once DOKU_INC . 'inc/parser/handler.php';
-
/**
* Define various types of modes used by the parser - they are used to
@@ -13,1022 +9,49 @@ $PARSER_MODES = array(
// containers are complex modes that can contain many other modes
// hr breaks the principle but they shouldn't be used in tables / lists
// so they are put here
- 'container' => array('listblock','table','quote','hr'),
+ 'container' => array('listblock', 'table', 'quote', 'hr'),
// some mode are allowed inside the base mode only
- 'baseonly' => array('header'),
+ 'baseonly' => array('header'),
// modes for styling text -- footnote behaves similar to styling
- 'formatting' => array('strong', 'emphasis', 'underline', 'monospace',
- 'subscript', 'superscript', 'deleted', 'footnote'),
+ 'formatting' => array(
+ 'strong', 'emphasis', 'underline', 'monospace',
+ 'subscript', 'superscript', 'deleted', 'footnote'
+ ),
// modes where the token is simply replaced - they can not contain any
// other modes
- 'substition' => array('acronym','smiley','wordblock','entity',
- 'camelcaselink', 'internallink','media',
- 'externallink','linebreak','emaillink',
- 'windowssharelink','filelink','notoc',
- 'nocache','multiplyentity','quotes','rss'),
+ 'substition' => array(
+ 'acronym', 'smiley', 'wordblock', 'entity',
+ 'camelcaselink', 'internallink', 'media',
+ 'externallink', 'linebreak', 'emaillink',
+ 'windowssharelink', 'filelink', 'notoc',
+ 'nocache', 'multiplyentity', 'quotes', 'rss'
+ ),
// modes which have a start and end token but inside which
// no other modes should be applied
- 'protected' => array('preformatted','code','file','php','html','htmlblock','phpblock'),
+ 'protected' => array('preformatted', 'code', 'file', 'php', 'html', 'htmlblock', 'phpblock'),
// inside this mode no wiki markup should be applied but lineendings
// and whitespace isn't preserved
- 'disabled' => array('unformatted'),
+ 'disabled' => array('unformatted'),
// used to mark paragraph boundaries
- 'paragraphs' => array('eol')
+ 'paragraphs' => array('eol')
);
-//-------------------------------------------------------------------
-
-/**
- * Sets up the Lexer with modes and points it to the Handler
- * For an intro to the Lexer see: wiki:parser
- */
-class Doku_Parser {
-
- var $Handler;
-
- /**
- * @var Doku_Lexer $Lexer
- */
- var $Lexer;
-
- var $modes = array();
-
- var $connected = false;
-
- /**
- * @param Doku_Parser_Mode_base $BaseMode
- */
- function addBaseMode($BaseMode) {
- $this->modes['base'] = $BaseMode;
- if ( !$this->Lexer ) {
- $this->Lexer = new Doku_Lexer($this->Handler,'base', true);
- }
- $this->modes['base']->Lexer = $this->Lexer;
- }
-
- /**
- * PHP preserves order of associative elements
- * Mode sequence is important
- *
- * @param string $name
- * @param Doku_Parser_Mode_Interface $Mode
- */
- function addMode($name, Doku_Parser_Mode_Interface $Mode) {
- if ( !isset($this->modes['base']) ) {
- $this->addBaseMode(new Doku_Parser_Mode_base());
- }
- $Mode->Lexer = $this->Lexer;
- $this->modes[$name] = $Mode;
- }
-
- function connectModes() {
-
- if ( $this->connected ) {
- return;
- }
-
- foreach ( array_keys($this->modes) as $mode ) {
-
- // Base isn't connected to anything
- if ( $mode == 'base' ) {
- continue;
- }
- $this->modes[$mode]->preConnect();
-
- foreach ( array_keys($this->modes) as $cm ) {
-
- if ( $this->modes[$cm]->accepts($mode) ) {
- $this->modes[$mode]->connectTo($cm);
- }
-
- }
-
- $this->modes[$mode]->postConnect();
- }
-
- $this->connected = true;
- }
-
- function parse($doc) {
- if ( $this->Lexer ) {
- $this->connectModes();
- // Normalize CRs and pad doc
- $doc = "\n".str_replace("\r\n","\n",$doc)."\n";
- $this->Lexer->parse($doc);
- $this->Handler->_finalize();
- return $this->Handler->calls;
- } else {
- return false;
- }
- }
-
-}
-
-//-------------------------------------------------------------------
-
-/**
- * Class Doku_Parser_Mode_Interface
- *
- * Defines a mode (syntax component) in the Parser
- */
-interface Doku_Parser_Mode_Interface {
- /**
- * returns a number used to determine in which order modes are added
- */
- public function getSort();
-
- /**
- * Called before any calls to connectTo
- * @return void
- */
- function preConnect();
-
- /**
- * Connects the mode
- *
- * @param string $mode
- * @return void
- */
- function connectTo($mode);
-
- /**
- * Called after all calls to connectTo
- * @return void
- */
- function postConnect();
-
- /**
- * Check if given mode is accepted inside this mode
- *
- * @param string $mode
- * @return bool
- */
- function accepts($mode);
-}
-
-/**
- * This class and all the subclasses below are used to reduce the effort required to register
- * modes with the Lexer.
- *
- * @author Harry Fuecks <hfuecks@gmail.com>
- */
-class Doku_Parser_Mode implements Doku_Parser_Mode_Interface {
- /**
- * @var Doku_Lexer $Lexer
- */
- var $Lexer;
- var $allowedModes = array();
-
- function getSort() {
- trigger_error('getSort() not implemented in '.get_class($this), E_USER_WARNING);
- }
-
- function preConnect() {}
- function connectTo($mode) {}
- function postConnect() {}
- function accepts($mode) {
- return in_array($mode, (array) $this->allowedModes );
- }
-}
-
/**
- * Basically the same as Doku_Parser_Mode but extends from DokuWiki_Plugin
+ * Class Doku_Parser
*
- * Adds additional functions to syntax plugins
+ * @deprecated 2018-05-04
*/
-class Doku_Parser_Mode_Plugin extends DokuWiki_Plugin implements Doku_Parser_Mode_Interface {
- /**
- * @var Doku_Lexer $Lexer
- */
- var $Lexer;
- var $allowedModes = array();
-
- /**
- * Sort for applying this mode
- *
- * @return int
- */
- function getSort() {
- trigger_error('getSort() not implemented in '.get_class($this), E_USER_WARNING);
- }
-
- function preConnect() {}
- function connectTo($mode) {}
- function postConnect() {}
- function accepts($mode) {
- return in_array($mode, (array) $this->allowedModes );
- }
-}
-
-//-------------------------------------------------------------------
-class Doku_Parser_Mode_base extends Doku_Parser_Mode {
-
- function __construct() {
- global $PARSER_MODES;
-
- $this->allowedModes = array_merge (
- $PARSER_MODES['container'],
- $PARSER_MODES['baseonly'],
- $PARSER_MODES['paragraphs'],
- $PARSER_MODES['formatting'],
- $PARSER_MODES['substition'],
- $PARSER_MODES['protected'],
- $PARSER_MODES['disabled']
- );
- }
-
- function getSort() {
- return 0;
- }
-}
-
-//-------------------------------------------------------------------
-class Doku_Parser_Mode_footnote extends Doku_Parser_Mode {
-
- function __construct() {
- global $PARSER_MODES;
-
- $this->allowedModes = array_merge (
- $PARSER_MODES['container'],
- $PARSER_MODES['formatting'],
- $PARSER_MODES['substition'],
- $PARSER_MODES['protected'],
- $PARSER_MODES['disabled']
- );
-
- unset($this->allowedModes[array_search('footnote', $this->allowedModes)]);
- }
-
- function connectTo($mode) {
- $this->Lexer->addEntryPattern(
- '\x28\x28(?=.*\x29\x29)',$mode,'footnote'
- );
- }
-
- function postConnect() {
- $this->Lexer->addExitPattern(
- '\x29\x29','footnote'
- );
- }
-
- function getSort() {
- return 150;
- }
-}
-
-//-------------------------------------------------------------------
-class Doku_Parser_Mode_header extends Doku_Parser_Mode {
-
- function connectTo($mode) {
- //we're not picky about the closing ones, two are enough
- $this->Lexer->addSpecialPattern(
- '[ \t]*={2,}[^\n]+={2,}[ \t]*(?=\n)',
- $mode,
- 'header'
- );
- }
-
- function getSort() {
- return 50;
- }
-}
-
-//-------------------------------------------------------------------
-class Doku_Parser_Mode_notoc extends Doku_Parser_Mode {
-
- function connectTo($mode) {
- $this->Lexer->addSpecialPattern('~~NOTOC~~',$mode,'notoc');
- }
-
- function getSort() {
- return 30;
- }
-}
-
-//-------------------------------------------------------------------
-class Doku_Parser_Mode_nocache extends Doku_Parser_Mode {
-
- function connectTo($mode) {
- $this->Lexer->addSpecialPattern('~~NOCACHE~~',$mode,'nocache');
- }
-
- function getSort() {
- return 40;
- }
-}
-
-//-------------------------------------------------------------------
-class Doku_Parser_Mode_linebreak extends Doku_Parser_Mode {
-
- function connectTo($mode) {
- $this->Lexer->addSpecialPattern('\x5C{2}(?:[ \t]|(?=\n))',$mode,'linebreak');
- }
-
- function getSort() {
- return 140;
- }
-}
-
-//-------------------------------------------------------------------
-class Doku_Parser_Mode_eol extends Doku_Parser_Mode {
-
- function connectTo($mode) {
- $badModes = array('listblock','table');
- if ( in_array($mode, $badModes) ) {
- return;
- }
- // see FS#1652, pattern extended to swallow preceding whitespace to avoid issues with lines that only contain whitespace
- $this->Lexer->addSpecialPattern('(?:^[ \t]*)?\n',$mode,'eol');
- }
-
- function getSort() {
- return 370;
- }
-}
-
-//-------------------------------------------------------------------
-class Doku_Parser_Mode_hr extends Doku_Parser_Mode {
-
- function connectTo($mode) {
- $this->Lexer->addSpecialPattern('\n[ \t]*-{4,}[ \t]*(?=\n)',$mode,'hr');
- }
-
- function getSort() {
- return 160;
- }
-}
-
-//-------------------------------------------------------------------
-/**
- * This class sets the markup for bold (=strong),
- * italic (=emphasis), underline etc.
- */
-class Doku_Parser_Mode_formatting extends Doku_Parser_Mode {
- var $type;
-
- var $formatting = array (
- 'strong' => array (
- 'entry'=>'\*\*(?=.*\*\*)',
- 'exit'=>'\*\*',
- 'sort'=>70
- ),
-
- 'emphasis'=> array (
- 'entry'=>'//(?=[^\x00]*[^:])', //hack for bugs #384 #763 #1468
- 'exit'=>'//',
- 'sort'=>80
- ),
-
- 'underline'=> array (
- 'entry'=>'__(?=.*__)',
- 'exit'=>'__',
- 'sort'=>90
- ),
-
- 'monospace'=> array (
- 'entry'=>'\x27\x27(?=.*\x27\x27)',
- 'exit'=>'\x27\x27',
- 'sort'=>100
- ),
-
- 'subscript'=> array (
- 'entry'=>'<sub>(?=.*</sub>)',
- 'exit'=>'</sub>',
- 'sort'=>110
- ),
-
- 'superscript'=> array (
- 'entry'=>'<sup>(?=.*</sup>)',
- 'exit'=>'</sup>',
- 'sort'=>120
- ),
-
- 'deleted'=> array (
- 'entry'=>'<del>(?=.*</del>)',
- 'exit'=>'</del>',
- 'sort'=>130
- ),
- );
-
- /**
- * @param string $type
- */
- function __construct($type) {
- global $PARSER_MODES;
-
- if ( !array_key_exists($type, $this->formatting) ) {
- trigger_error('Invalid formatting type '.$type, E_USER_WARNING);
- }
-
- $this->type = $type;
-
- // formatting may contain other formatting but not it self
- $modes = $PARSER_MODES['formatting'];
- $key = array_search($type, $modes);
- if ( is_int($key) ) {
- unset($modes[$key]);
- }
-
- $this->allowedModes = array_merge (
- $modes,
- $PARSER_MODES['substition'],
- $PARSER_MODES['disabled']
- );
- }
-
- function connectTo($mode) {
-
- // Can't nest formatting in itself
- if ( $mode == $this->type ) {
- return;
- }
-
- $this->Lexer->addEntryPattern(
- $this->formatting[$this->type]['entry'],
- $mode,
- $this->type
- );
- }
-
- function postConnect() {
-
- $this->Lexer->addExitPattern(
- $this->formatting[$this->type]['exit'],
- $this->type
- );
-
- }
-
- function getSort() {
- return $this->formatting[$this->type]['sort'];
- }
-}
-
-//-------------------------------------------------------------------
-class Doku_Parser_Mode_listblock extends Doku_Parser_Mode {
-
- function __construct() {
- global $PARSER_MODES;
-
- $this->allowedModes = array_merge (
- $PARSER_MODES['formatting'],
- $PARSER_MODES['substition'],
- $PARSER_MODES['disabled'],
- $PARSER_MODES['protected'] #XXX new
- );
-
- // $this->allowedModes[] = 'footnote';
- }
-
- function connectTo($mode) {
- $this->Lexer->addEntryPattern('[ \t]*\n {2,}[\-\*]',$mode,'listblock');
- $this->Lexer->addEntryPattern('[ \t]*\n\t{1,}[\-\*]',$mode,'listblock');
-
- $this->Lexer->addPattern('\n {2,}[\-\*]','listblock');
- $this->Lexer->addPattern('\n\t{1,}[\-\*]','listblock');
-
- }
-
- function postConnect() {
- $this->Lexer->addExitPattern('\n','listblock');
- }
-
- function getSort() {
- return 10;
- }
-}
-
-//-------------------------------------------------------------------
-class Doku_Parser_Mode_table extends Doku_Parser_Mode {
-
- function __construct() {
- global $PARSER_MODES;
-
- $this->allowedModes = array_merge (
- $PARSER_MODES['formatting'],
- $PARSER_MODES['substition'],
- $PARSER_MODES['disabled'],
- $PARSER_MODES['protected']
- );
- }
-
- function connectTo($mode) {
- $this->Lexer->addEntryPattern('[\t ]*\n\^',$mode,'table');
- $this->Lexer->addEntryPattern('[\t ]*\n\|',$mode,'table');
- }
-
- function postConnect() {
- $this->Lexer->addPattern('\n\^','table');
- $this->Lexer->addPattern('\n\|','table');
- $this->Lexer->addPattern('[\t ]*:::[\t ]*(?=[\|\^])','table');
- $this->Lexer->addPattern('[\t ]+','table');
- $this->Lexer->addPattern('\^','table');
- $this->Lexer->addPattern('\|','table');
- $this->Lexer->addExitPattern('\n','table');
- }
-
- function getSort() {
- return 60;
- }
-}
-
-//-------------------------------------------------------------------
-class Doku_Parser_Mode_unformatted extends Doku_Parser_Mode {
-
- function connectTo($mode) {
- $this->Lexer->addEntryPattern('<nowiki>(?=.*</nowiki>)',$mode,'unformatted');
- $this->Lexer->addEntryPattern('%%(?=.*%%)',$mode,'unformattedalt');
- }
-
- function postConnect() {
- $this->Lexer->addExitPattern('</nowiki>','unformatted');
- $this->Lexer->addExitPattern('%%','unformattedalt');
- $this->Lexer->mapHandler('unformattedalt','unformatted');
- }
-
- function getSort() {
- return 170;
- }
-}
-
-//-------------------------------------------------------------------
-class Doku_Parser_Mode_php extends Doku_Parser_Mode {
-
- function connectTo($mode) {
- $this->Lexer->addEntryPattern('<php>(?=.*</php>)',$mode,'php');
- $this->Lexer->addEntryPattern('<PHP>(?=.*</PHP>)',$mode,'phpblock');
- }
-
- function postConnect() {
- $this->Lexer->addExitPattern('</php>','php');
- $this->Lexer->addExitPattern('</PHP>','phpblock');
- }
-
- function getSort() {
- return 180;
- }
-}
-
-//-------------------------------------------------------------------
-class Doku_Parser_Mode_html extends Doku_Parser_Mode {
+class Doku_Parser extends \dokuwiki\Parsing\Parser {
- function connectTo($mode) {
- $this->Lexer->addEntryPattern('<html>(?=.*</html>)',$mode,'html');
- $this->Lexer->addEntryPattern('<HTML>(?=.*</HTML>)',$mode,'htmlblock');
- }
-
- function postConnect() {
- $this->Lexer->addExitPattern('</html>','html');
- $this->Lexer->addExitPattern('</HTML>','htmlblock');
- }
-
- function getSort() {
- return 190;
- }
-}
-
-//-------------------------------------------------------------------
-class Doku_Parser_Mode_preformatted extends Doku_Parser_Mode {
-
- function connectTo($mode) {
- // Has hard coded awareness of lists...
- $this->Lexer->addEntryPattern('\n (?![\*\-])',$mode,'preformatted');
- $this->Lexer->addEntryPattern('\n\t(?![\*\-])',$mode,'preformatted');
-
- // How to effect a sub pattern with the Lexer!
- $this->Lexer->addPattern('\n ','preformatted');
- $this->Lexer->addPattern('\n\t','preformatted');
-
- }
-
- function postConnect() {
- $this->Lexer->addExitPattern('\n','preformatted');
- }
-
- function getSort() {
- return 20;
- }
-}
-
-//-------------------------------------------------------------------
-class Doku_Parser_Mode_code extends Doku_Parser_Mode {
-
- function connectTo($mode) {
- $this->Lexer->addEntryPattern('<code\b(?=.*</code>)',$mode,'code');
- }
-
- function postConnect() {
- $this->Lexer->addExitPattern('</code>','code');
- }
-
- function getSort() {
- return 200;
- }
-}
-
-//-------------------------------------------------------------------
-class Doku_Parser_Mode_file extends Doku_Parser_Mode {
-
- function connectTo($mode) {
- $this->Lexer->addEntryPattern('<file\b(?=.*</file>)',$mode,'file');
- }
-
- function postConnect() {
- $this->Lexer->addExitPattern('</file>','file');
- }
-
- function getSort() {
- return 210;
- }
-}
-
-//-------------------------------------------------------------------
-class Doku_Parser_Mode_quote extends Doku_Parser_Mode {
-
- function __construct() {
- global $PARSER_MODES;
-
- $this->allowedModes = array_merge (
- $PARSER_MODES['formatting'],
- $PARSER_MODES['substition'],
- $PARSER_MODES['disabled'],
- $PARSER_MODES['protected'] #XXX new
- );
- #$this->allowedModes[] = 'footnote';
- #$this->allowedModes[] = 'preformatted';
- #$this->allowedModes[] = 'unformatted';
- }
-
- function connectTo($mode) {
- $this->Lexer->addEntryPattern('\n>{1,}',$mode,'quote');
- }
-
- function postConnect() {
- $this->Lexer->addPattern('\n>{1,}','quote');
- $this->Lexer->addExitPattern('\n','quote');
- }
-
- function getSort() {
- return 220;
- }
-}
-
-//-------------------------------------------------------------------
-class Doku_Parser_Mode_acronym extends Doku_Parser_Mode {
- // A list
- var $acronyms = array();
- var $pattern = '';
-
- function __construct($acronyms) {
- usort($acronyms,array($this,'_compare'));
- $this->acronyms = $acronyms;
- }
-
- function preConnect() {
- if(!count($this->acronyms)) return;
-
- $bound = '[\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f]';
- $acronyms = array_map('Doku_Lexer_Escape',$this->acronyms);
- $this->pattern = '(?<=^|'.$bound.')(?:'.join('|',$acronyms).')(?='.$bound.')';
- }
-
- function connectTo($mode) {
- if(!count($this->acronyms)) return;
-
- if ( strlen($this->pattern) > 0 ) {
- $this->Lexer->addSpecialPattern($this->pattern,$mode,'acronym');
- }
- }
-
- function getSort() {
- return 240;
- }
-
- /**
- * sort callback to order by string length descending
- *
- * @param string $a
- * @param string $b
- *
- * @return int
- */
- function _compare($a,$b) {
- $a_len = strlen($a);
- $b_len = strlen($b);
- if ($a_len > $b_len) {
- return -1;
- } else if ($a_len < $b_len) {
- return 1;
- }
-
- return 0;
- }
-}
-
-//-------------------------------------------------------------------
-class Doku_Parser_Mode_smiley extends Doku_Parser_Mode {
- // A list
- var $smileys = array();
- var $pattern = '';
-
- function __construct($smileys) {
- $this->smileys = $smileys;
- }
-
- function preConnect() {
- if(!count($this->smileys) || $this->pattern != '') return;
-
- $sep = '';
- foreach ( $this->smileys as $smiley ) {
- $this->pattern .= $sep.'(?<=\W|^)'.Doku_Lexer_Escape($smiley).'(?=\W|$)';
- $sep = '|';
- }
- }
-
- function connectTo($mode) {
- if(!count($this->smileys)) return;
-
- if ( strlen($this->pattern) > 0 ) {
- $this->Lexer->addSpecialPattern($this->pattern,$mode,'smiley');
- }
- }
-
- function getSort() {
- return 230;
- }
-}
-
-//-------------------------------------------------------------------
-class Doku_Parser_Mode_wordblock extends Doku_Parser_Mode {
- // A list
- var $badwords = array();
- var $pattern = '';
-
- function __construct($badwords) {
- $this->badwords = $badwords;
- }
-
- function preConnect() {
-
- if ( count($this->badwords) == 0 || $this->pattern != '') {
- return;
- }
-
- $sep = '';
- foreach ( $this->badwords as $badword ) {
- $this->pattern .= $sep.'(?<=\b)(?i)'.Doku_Lexer_Escape($badword).'(?-i)(?=\b)';
- $sep = '|';
- }
-
- }
-
- function connectTo($mode) {
- if ( strlen($this->pattern) > 0 ) {
- $this->Lexer->addSpecialPattern($this->pattern,$mode,'wordblock');
- }
- }
-
- function getSort() {
- return 250;
+ /** @inheritdoc */
+ public function __construct(Doku_Handler $handler) {
+ dbg_deprecated(\dokuwiki\Parsing\Parser::class);
+ parent::__construct($handler);
}
}
-
-//-------------------------------------------------------------------
-class Doku_Parser_Mode_entity extends Doku_Parser_Mode {
- // A list
- var $entities = array();
- var $pattern = '';
-
- function __construct($entities) {
- $this->entities = $entities;
- }
-
- function preConnect() {
- if(!count($this->entities) || $this->pattern != '') return;
-
- $sep = '';
- foreach ( $this->entities as $entity ) {
- $this->pattern .= $sep.Doku_Lexer_Escape($entity);
- $sep = '|';
- }
- }
-
- function connectTo($mode) {
- if(!count($this->entities)) return;
-
- if ( strlen($this->pattern) > 0 ) {
- $this->Lexer->addSpecialPattern($this->pattern,$mode,'entity');
- }
- }
-
- function getSort() {
- return 260;
- }
-}
-
-//-------------------------------------------------------------------
-// Implements the 640x480 replacement
-class Doku_Parser_Mode_multiplyentity extends Doku_Parser_Mode {
-
- function connectTo($mode) {
-
- $this->Lexer->addSpecialPattern(
- '(?<=\b)(?:[1-9]|\d{2,})[xX]\d+(?=\b)',$mode,'multiplyentity'
- );
-
- }
-
- function getSort() {
- return 270;
- }
-}
-
-//-------------------------------------------------------------------
-class Doku_Parser_Mode_quotes extends Doku_Parser_Mode {
-
- function connectTo($mode) {
- global $conf;
-
- $ws = '\s/\#~:+=&%@\-\x28\x29\]\[{}><"\''; // whitespace
- $punc = ';,\.?!';
-
- if($conf['typography'] == 2){
- $this->Lexer->addSpecialPattern(
- "(?<=^|[$ws])'(?=[^$ws$punc])",$mode,'singlequoteopening'
- );
- $this->Lexer->addSpecialPattern(
- "(?<=^|[^$ws]|[$punc])'(?=$|[$ws$punc])",$mode,'singlequoteclosing'
- );
- $this->Lexer->addSpecialPattern(
- "(?<=^|[^$ws$punc])'(?=$|[^$ws$punc])",$mode,'apostrophe'
- );
- }
-
- $this->Lexer->addSpecialPattern(
- "(?<=^|[$ws])\"(?=[^$ws$punc])",$mode,'doublequoteopening'
- );
- $this->Lexer->addSpecialPattern(
- "\"",$mode,'doublequoteclosing'
- );
-
- }
-
- function getSort() {
- return 280;
- }
-}
-
-//-------------------------------------------------------------------
-class Doku_Parser_Mode_camelcaselink extends Doku_Parser_Mode {
-
- function connectTo($mode) {
- $this->Lexer->addSpecialPattern(
- '\b[A-Z]+[a-z]+[A-Z][A-Za-z]*\b',$mode,'camelcaselink'
- );
- }
-
- function getSort() {
- return 290;
- }
-}
-
-//-------------------------------------------------------------------
-class Doku_Parser_Mode_internallink extends Doku_Parser_Mode {
-
- function connectTo($mode) {
- // Word boundaries?
- $this->Lexer->addSpecialPattern("\[\[.*?\]\](?!\])",$mode,'internallink');
- }
-
- function getSort() {
- return 300;
- }
-}
-
-//-------------------------------------------------------------------
-class Doku_Parser_Mode_media extends Doku_Parser_Mode {
-
- function connectTo($mode) {
- // Word boundaries?
- $this->Lexer->addSpecialPattern("\{\{(?:[^\}]|(?:\}[^\}]))+\}\}",$mode,'media');
- }
-
- function getSort() {
- return 320;
- }
-}
-
-//-------------------------------------------------------------------
-class Doku_Parser_Mode_rss extends Doku_Parser_Mode {
-
- function connectTo($mode) {
- $this->Lexer->addSpecialPattern("\{\{rss>[^\}]+\}\}",$mode,'rss');
- }
-
- function getSort() {
- return 310;
- }
-}
-
-//-------------------------------------------------------------------
-class Doku_Parser_Mode_externallink extends Doku_Parser_Mode {
- var $schemes = array();
- var $patterns = array();
-
- function preConnect() {
- if(count($this->patterns)) return;
-
- $ltrs = '\w';
- $gunk = '/\#~:.?+=&%@!\-\[\]';
- $punc = '.:?\-;,';
- $host = $ltrs.$punc;
- $any = $ltrs.$gunk.$punc;
-
- $this->schemes = getSchemes();
- foreach ( $this->schemes as $scheme ) {
- $this->patterns[] = '\b(?i)'.$scheme.'(?-i)://['.$any.']+?(?=['.$punc.']*[^'.$any.'])';
- }
-
- $this->patterns[] = '(?<=\s)(?i)www?(?-i)\.['.$host.']+?\.['.$host.']+?['.$any.']+?(?=['.$punc.']*[^'.$any.'])';
- $this->patterns[] = '(?<=\s)(?i)ftp?(?-i)\.['.$host.']+?\.['.$host.']+?['.$any.']+?(?=['.$punc.']*[^'.$any.'])';
- }
-
- function connectTo($mode) {
-
- foreach ( $this->patterns as $pattern ) {
- $this->Lexer->addSpecialPattern($pattern,$mode,'externallink');
- }
- }
-
- function getSort() {
- return 330;
- }
-}
-
-//-------------------------------------------------------------------
-class Doku_Parser_Mode_filelink extends Doku_Parser_Mode {
-
- var $pattern;
-
- function preConnect() {
-
- $ltrs = '\w';
- $gunk = '/\#~:.?+=&%@!\-';
- $punc = '.:?\-;,';
- $host = $ltrs.$punc;
- $any = $ltrs.$gunk.$punc;
-
- $this->pattern = '\b(?i)file(?-i)://['.$any.']+?['.
- $punc.']*[^'.$any.']';
- }
-
- function connectTo($mode) {
- $this->Lexer->addSpecialPattern(
- $this->pattern,$mode,'filelink');
- }
-
- function getSort() {
- return 360;
- }
-}
-
-//-------------------------------------------------------------------
-class Doku_Parser_Mode_windowssharelink extends Doku_Parser_Mode {
-
- var $pattern;
-
- function preConnect() {
- $this->pattern = "\\\\\\\\\w+?(?:\\\\[\w\-$]+)+";
- }
-
- function connectTo($mode) {
- $this->Lexer->addSpecialPattern(
- $this->pattern,$mode,'windowssharelink');
- }
-
- function getSort() {
- return 350;
- }
-}
-
-//-------------------------------------------------------------------
-class Doku_Parser_Mode_emaillink extends Doku_Parser_Mode {
-
- function connectTo($mode) {
- // pattern below is defined in inc/mail.php
- $this->Lexer->addSpecialPattern('<'.PREG_PATTERN_VALID_EMAIL.'>',$mode,'emaillink');
- }
-
- function getSort() {
- return 340;
- }
-}
-
-
-//Setup VIM: ex: et ts=4 :
diff --git a/inc/parser/renderer.php b/inc/parser/renderer.php
index 83b51d4b1..d00e7388c 100644
--- a/inc/parser/renderer.php
+++ b/inc/parser/renderer.php
@@ -5,7 +5,9 @@
* @author Harry Fuecks <hfuecks@gmail.com>
* @author Andreas Gohr <andi@splitbrain.org>
*/
-if(!defined('DOKU_INC')) die('meh.');
+
+use dokuwiki\Extension\Plugin;
+use dokuwiki\Extension\SyntaxPlugin;
/**
* Allowed chars in $language for code highlighting
@@ -16,7 +18,7 @@ define('PREG_PATTERN_VALID_LANGUAGE', '#[^a-zA-Z0-9\-_]#');
/**
* An empty renderer, produces no output
*
- * Inherits from DokuWiki_Plugin for giving additional functions to render plugins
+ * Inherits from dokuwiki\Plugin\DokuWiki_Plugin for giving additional functions to render plugins
*
* The renderer transforms the syntax instructions created by the parser and handler into the
* desired output format. For each instruction a corresponding method defined in this class will
@@ -24,7 +26,7 @@ define('PREG_PATTERN_VALID_LANGUAGE', '#[^a-zA-Z0-9\-_]#');
* $doc field. When all instructions are processed, the $doc field contents will be cached by
* DokuWiki and sent to the user.
*/
-class Doku_Renderer extends DokuWiki_Plugin {
+abstract class Doku_Renderer extends Plugin {
/** @var array Settings, control the behavior of the renderer */
public $info = array(
'cache' => true, // may the rendered result cached?
@@ -40,6 +42,9 @@ class Doku_Renderer extends DokuWiki_Plugin {
/** @var array contains the interwiki configuration, set in p_render() */
public $interwiki = array();
+ /** @var array the list of headers used to create unique link ids */
+ protected $headers = array();
+
/**
* @var string the rendered document, this will be cached after the renderer ran through
*/
@@ -51,7 +56,8 @@ class Doku_Renderer extends DokuWiki_Plugin {
* This is called before each use of the renderer object and should be used to
* completely reset the state of the renderer to be reused for a new document
*/
- function reset() {
+ public function reset(){
+ $this->headers = array();
}
/**
@@ -62,7 +68,7 @@ class Doku_Renderer extends DokuWiki_Plugin {
*
* @return bool false if the plugin has to be instantiated
*/
- function isSingleton() {
+ public function isSingleton() {
return false;
}
@@ -73,15 +79,12 @@ class Doku_Renderer extends DokuWiki_Plugin {
*
* @return string
*/
- function getFormat() {
- trigger_error('getFormat() not implemented in '.get_class($this), E_USER_WARNING);
- return '';
- }
+ abstract public function getFormat();
/**
* Disable caching of this renderer's output
*/
- function nocache() {
+ public function nocache() {
$this->info['cache'] = false;
}
@@ -90,7 +93,7 @@ class Doku_Renderer extends DokuWiki_Plugin {
*
* This might not be used for certain sub renderer
*/
- function notoc() {
+ public function notoc() {
$this->info['toc'] = false;
}
@@ -104,8 +107,8 @@ class Doku_Renderer extends DokuWiki_Plugin {
* @param string $state matched state if any
* @param string $match raw matched syntax
*/
- function plugin($name, $data, $state = '', $match = '') {
- /** @var DokuWiki_Syntax_Plugin $plugin */
+ public function plugin($name, $data, $state = '', $match = '') {
+ /** @var SyntaxPlugin $plugin */
$plugin = plugin_load('syntax', $name);
if($plugin != null) {
$plugin->render($this->getFormat(), $this, $data);
@@ -118,7 +121,7 @@ class Doku_Renderer extends DokuWiki_Plugin {
*
* @param array $instructions
*/
- function nest($instructions) {
+ public function nest($instructions) {
foreach($instructions as $instruction) {
// execute the callback against ourself
if(method_exists($this, $instruction[0])) {
@@ -133,7 +136,7 @@ class Doku_Renderer extends DokuWiki_Plugin {
* normally the syntax mode should override this instruction when instantiating Doku_Handler_Nest -
* however plugins will not be able to - as their instructions require data.
*/
- function nest_close() {
+ public function nest_close() {
}
#region Syntax modes - sub classes will need to implement them to fill $doc
@@ -141,13 +144,13 @@ class Doku_Renderer extends DokuWiki_Plugin {
/**
* Initialize the document
*/
- function document_start() {
+ public function document_start() {
}
/**
* Finalize the document
*/
- function document_end() {
+ public function document_end() {
}
/**
@@ -155,7 +158,7 @@ class Doku_Renderer extends DokuWiki_Plugin {
*
* @return string
*/
- function render_TOC() {
+ public function render_TOC() {
return '';
}
@@ -166,7 +169,7 @@ class Doku_Renderer extends DokuWiki_Plugin {
* @param string $text the text to display
* @param int $level the nesting level
*/
- function toc_additem($id, $text, $level) {
+ public function toc_additem($id, $text, $level) {
}
/**
@@ -176,7 +179,7 @@ class Doku_Renderer extends DokuWiki_Plugin {
* @param int $level header level
* @param int $pos byte position in the original source
*/
- function header($text, $level, $pos) {
+ public function header($text, $level, $pos) {
}
/**
@@ -184,13 +187,13 @@ class Doku_Renderer extends DokuWiki_Plugin {
*
* @param int $level section level (as determined by the previous header)
*/
- function section_open($level) {
+ public function section_open($level) {
}
/**
* Close the current section
*/
- function section_close() {
+ public function section_close() {
}
/**
@@ -198,151 +201,151 @@ class Doku_Renderer extends DokuWiki_Plugin {
*
* @param string $text
*/
- function cdata($text) {
+ public function cdata($text) {
}
/**
* Open a paragraph
*/
- function p_open() {
+ public function p_open() {
}
/**
* Close a paragraph
*/
- function p_close() {
+ public function p_close() {
}
/**
* Create a line break
*/
- function linebreak() {
+ public function linebreak() {
}
/**
* Create a horizontal line
*/
- function hr() {
+ public function hr() {
}
/**
* Start strong (bold) formatting
*/
- function strong_open() {
+ public function strong_open() {
}
/**
* Stop strong (bold) formatting
*/
- function strong_close() {
+ public function strong_close() {
}
/**
* Start emphasis (italics) formatting
*/
- function emphasis_open() {
+ public function emphasis_open() {
}
/**
* Stop emphasis (italics) formatting
*/
- function emphasis_close() {
+ public function emphasis_close() {
}
/**
* Start underline formatting
*/
- function underline_open() {
+ public function underline_open() {
}
/**
* Stop underline formatting
*/
- function underline_close() {
+ public function underline_close() {
}
/**
* Start monospace formatting
*/
- function monospace_open() {
+ public function monospace_open() {
}
/**
* Stop monospace formatting
*/
- function monospace_close() {
+ public function monospace_close() {
}
/**
* Start a subscript
*/
- function subscript_open() {
+ public function subscript_open() {
}
/**
* Stop a subscript
*/
- function subscript_close() {
+ public function subscript_close() {
}
/**
* Start a superscript
*/
- function superscript_open() {
+ public function superscript_open() {
}
/**
* Stop a superscript
*/
- function superscript_close() {
+ public function superscript_close() {
}
/**
* Start deleted (strike-through) formatting
*/
- function deleted_open() {
+ public function deleted_open() {
}
/**
* Stop deleted (strike-through) formatting
*/
- function deleted_close() {
+ public function deleted_close() {
}
/**
* Start a footnote
*/
- function footnote_open() {
+ public function footnote_open() {
}
/**
* Stop a footnote
*/
- function footnote_close() {
+ public function footnote_close() {
}
/**
* Open an unordered list
*/
- function listu_open() {
+ public function listu_open() {
}
/**
* Close an unordered list
*/
- function listu_close() {
+ public function listu_close() {
}
/**
* Open an ordered list
*/
- function listo_open() {
+ public function listo_open() {
}
/**
* Close an ordered list
*/
- function listo_close() {
+ public function listo_close() {
}
/**
@@ -351,25 +354,25 @@ class Doku_Renderer extends DokuWiki_Plugin {
* @param int $level the nesting level
* @param bool $node true when a node; false when a leaf
*/
- function listitem_open($level,$node=false) {
+ public function listitem_open($level,$node=false) {
}
/**
* Close a list item
*/
- function listitem_close() {
+ public function listitem_close() {
}
/**
* Start the content of a list item
*/
- function listcontent_open() {
+ public function listcontent_open() {
}
/**
* Stop the content of a list item
*/
- function listcontent_close() {
+ public function listcontent_close() {
}
/**
@@ -379,7 +382,7 @@ class Doku_Renderer extends DokuWiki_Plugin {
*
* @param string $text
*/
- function unformatted($text) {
+ public function unformatted($text) {
$this->cdata($text);
}
@@ -391,7 +394,7 @@ class Doku_Renderer extends DokuWiki_Plugin {
*
* @param string $text The PHP code
*/
- function php($text) {
+ public function php($text) {
}
/**
@@ -402,7 +405,7 @@ class Doku_Renderer extends DokuWiki_Plugin {
*
* @param string $text The PHP code
*/
- function phpblock($text) {
+ public function phpblock($text) {
}
/**
@@ -412,7 +415,7 @@ class Doku_Renderer extends DokuWiki_Plugin {
*
* @param string $text The HTML
*/
- function html($text) {
+ public function html($text) {
}
/**
@@ -422,7 +425,7 @@ class Doku_Renderer extends DokuWiki_Plugin {
*
* @param string $text The HTML
*/
- function htmlblock($text) {
+ public function htmlblock($text) {
}
/**
@@ -430,19 +433,19 @@ class Doku_Renderer extends DokuWiki_Plugin {
*
* @param string $text
*/
- function preformatted($text) {
+ public function preformatted($text) {
}
/**
* Start a block quote
*/
- function quote_open() {
+ public function quote_open() {
}
/**
* Stop a block quote
*/
- function quote_close() {
+ public function quote_close() {
}
/**
@@ -452,7 +455,7 @@ class Doku_Renderer extends DokuWiki_Plugin {
* @param string $lang programming language to use for syntax highlighting
* @param string $file file path label
*/
- function file($text, $lang = null, $file = null) {
+ public function file($text, $lang = null, $file = null) {
}
/**
@@ -462,7 +465,7 @@ class Doku_Renderer extends DokuWiki_Plugin {
* @param string $lang programming language to use for syntax highlighting
* @param string $file file path label
*/
- function code($text, $lang = null, $file = null) {
+ public function code($text, $lang = null, $file = null) {
}
/**
@@ -472,7 +475,7 @@ class Doku_Renderer extends DokuWiki_Plugin {
*
* @param string $acronym
*/
- function acronym($acronym) {
+ public function acronym($acronym) {
}
/**
@@ -482,7 +485,7 @@ class Doku_Renderer extends DokuWiki_Plugin {
*
* @param string $smiley
*/
- function smiley($smiley) {
+ public function smiley($smiley) {
}
/**
@@ -494,7 +497,7 @@ class Doku_Renderer extends DokuWiki_Plugin {
*
* @param string $entity
*/
- function entity($entity) {
+ public function entity($entity) {
}
/**
@@ -505,37 +508,37 @@ class Doku_Renderer extends DokuWiki_Plugin {
* @param string|int $x first value
* @param string|int $y second value
*/
- function multiplyentity($x, $y) {
+ public function multiplyentity($x, $y) {
}
/**
* Render an opening single quote char (language specific)
*/
- function singlequoteopening() {
+ public function singlequoteopening() {
}
/**
* Render a closing single quote char (language specific)
*/
- function singlequoteclosing() {
+ public function singlequoteclosing() {
}
/**
* Render an apostrophe char (language specific)
*/
- function apostrophe() {
+ public function apostrophe() {
}
/**
* Render an opening double quote char (language specific)
*/
- function doublequoteopening() {
+ public function doublequoteopening() {
}
/**
* Render an closinging double quote char (language specific)
*/
- function doublequoteclosing() {
+ public function doublequoteclosing() {
}
/**
@@ -544,7 +547,7 @@ class Doku_Renderer extends DokuWiki_Plugin {
* @param string $link The link name
* @see http://en.wikipedia.org/wiki/CamelCase
*/
- function camelcaselink($link) {
+ public function camelcaselink($link) {
}
/**
@@ -553,7 +556,7 @@ class Doku_Renderer extends DokuWiki_Plugin {
* @param string $hash hash link identifier
* @param string $name name for the link
*/
- function locallink($hash, $name = null) {
+ public function locallink($hash, $name = null) {
}
/**
@@ -562,7 +565,7 @@ class Doku_Renderer extends DokuWiki_Plugin {
* @param string $link page ID to link to. eg. 'wiki:syntax'
* @param string|array $title name for the link, array for media file
*/
- function internallink($link, $title = null) {
+ public function internallink($link, $title = null) {
}
/**
@@ -571,7 +574,7 @@ class Doku_Renderer extends DokuWiki_Plugin {
* @param string $link full URL with scheme
* @param string|array $title name for the link, array for media file
*/
- function externallink($link, $title = null) {
+ public function externallink($link, $title = null) {
}
/**
@@ -580,7 +583,7 @@ class Doku_Renderer extends DokuWiki_Plugin {
* @param string $url URL of the feed
* @param array $params Finetuning of the output
*/
- function rss($url, $params) {
+ public function rss($url, $params) {
}
/**
@@ -593,7 +596,7 @@ class Doku_Renderer extends DokuWiki_Plugin {
* @param string $wikiName indentifier (shortcut) for the remote wiki
* @param string $wikiUri the fragment parsed from the original link
*/
- function interwikilink($link, $title = null, $wikiName, $wikiUri) {
+ public function interwikilink($link, $title, $wikiName, $wikiUri) {
}
/**
@@ -602,7 +605,7 @@ class Doku_Renderer extends DokuWiki_Plugin {
* @param string $link the link
* @param string|array $title name for the link, array for media file
*/
- function filelink($link, $title = null) {
+ public function filelink($link, $title = null) {
}
/**
@@ -611,7 +614,7 @@ class Doku_Renderer extends DokuWiki_Plugin {
* @param string $link the link
* @param string|array $title name for the link, array for media file
*/
- function windowssharelink($link, $title = null) {
+ public function windowssharelink($link, $title = null) {
}
/**
@@ -622,7 +625,7 @@ class Doku_Renderer extends DokuWiki_Plugin {
* @param string $address Email-Address
* @param string|array $name name for the link, array for media file
*/
- function emaillink($address, $name = null) {
+ public function emaillink($address, $name = null) {
}
/**
@@ -636,7 +639,7 @@ class Doku_Renderer extends DokuWiki_Plugin {
* @param string $cache cache|recache|nocache
* @param string $linking linkonly|detail|nolink
*/
- function internalmedia($src, $title = null, $align = null, $width = null,
+ public function internalmedia($src, $title = null, $align = null, $width = null,
$height = null, $cache = null, $linking = null) {
}
@@ -651,7 +654,7 @@ class Doku_Renderer extends DokuWiki_Plugin {
* @param string $cache cache|recache|nocache
* @param string $linking linkonly|detail|nolink
*/
- function externalmedia($src, $title = null, $align = null, $width = null,
+ public function externalmedia($src, $title = null, $align = null, $width = null,
$height = null, $cache = null, $linking = null) {
}
@@ -665,7 +668,7 @@ class Doku_Renderer extends DokuWiki_Plugin {
* @param int $height height of media in pixel
* @param string $cache cache|recache|nocache
*/
- function internalmedialink($src, $title = null, $align = null,
+ public function internalmedialink($src, $title = null, $align = null,
$width = null, $height = null, $cache = null) {
}
@@ -679,7 +682,7 @@ class Doku_Renderer extends DokuWiki_Plugin {
* @param int $height height of media in pixel
* @param string $cache cache|recache|nocache
*/
- function externalmedialink($src, $title = null, $align = null,
+ public function externalmedialink($src, $title = null, $align = null,
$width = null, $height = null, $cache = null) {
}
@@ -690,7 +693,7 @@ class Doku_Renderer extends DokuWiki_Plugin {
* @param int $numrows NOT IMPLEMENTED
* @param int $pos byte position in the original source
*/
- function table_open($maxcols = null, $numrows = null, $pos = null) {
+ public function table_open($maxcols = null, $numrows = null, $pos = null) {
}
/**
@@ -698,55 +701,55 @@ class Doku_Renderer extends DokuWiki_Plugin {
*
* @param int $pos byte position in the original source
*/
- function table_close($pos = null) {
+ public function table_close($pos = null) {
}
/**
* Open a table header
*/
- function tablethead_open() {
+ public function tablethead_open() {
}
/**
* Close a table header
*/
- function tablethead_close() {
+ public function tablethead_close() {
}
/**
* Open a table body
*/
- function tabletbody_open() {
+ public function tabletbody_open() {
}
/**
* Close a table body
*/
- function tabletbody_close() {
+ public function tabletbody_close() {
}
/**
* Open a table footer
*/
- function tabletfoot_open() {
+ public function tabletfoot_open() {
}
/**
* Close a table footer
*/
- function tabletfoot_close() {
+ public function tabletfoot_close() {
}
/**
* Open a table row
*/
- function tablerow_open() {
+ public function tablerow_open() {
}
/**
* Close a table row
*/
- function tablerow_close() {
+ public function tablerow_close() {
}
/**
@@ -756,13 +759,13 @@ class Doku_Renderer extends DokuWiki_Plugin {
* @param string $align left|center|right
* @param int $rowspan
*/
- function tableheader_open($colspan = 1, $align = null, $rowspan = 1) {
+ public function tableheader_open($colspan = 1, $align = null, $rowspan = 1) {
}
/**
* Close a table header cell
*/
- function tableheader_close() {
+ public function tableheader_close() {
}
/**
@@ -772,13 +775,13 @@ class Doku_Renderer extends DokuWiki_Plugin {
* @param string $align left|center|right
* @param int $rowspan
*/
- function tablecell_open($colspan = 1, $align = null, $rowspan = 1) {
+ public function tablecell_open($colspan = 1, $align = null, $rowspan = 1) {
}
/**
* Close a table cell
*/
- function tablecell_close() {
+ public function tablecell_close() {
}
#endregion
@@ -786,6 +789,23 @@ class Doku_Renderer extends DokuWiki_Plugin {
#region util functions, you probably won't need to reimplement them
/**
+ * Creates a linkid from a headline
+ *
+ * @author Andreas Gohr <andi@splitbrain.org>
+ * @param string $title The headline title
+ * @param boolean $create Create a new unique ID?
+ * @return string
+ */
+ public function _headerToLink($title, $create = false) {
+ if($create) {
+ return sectionID($title, $this->headers);
+ } else {
+ $check = false;
+ return sectionID($title, $check);
+ }
+ }
+
+ /**
* Removes any Namespace from the given name but keeps
* casing and special chars
*
@@ -794,7 +814,7 @@ class Doku_Renderer extends DokuWiki_Plugin {
* @param string $name
* @return string
*/
- function _simpleTitle($name) {
+ protected function _simpleTitle($name) {
global $conf;
//if there is a hash we use the ancor name only
@@ -818,7 +838,7 @@ class Doku_Renderer extends DokuWiki_Plugin {
* @param null|bool $exists reference which returns if an internal page exists
* @return string interwikilink
*/
- function _resolveInterWiki(&$shortcut, $reference, &$exists = null) {
+ public function _resolveInterWiki(&$shortcut, $reference, &$exists = null) {
//get interwiki URL
if(isset($this->interwiki[$shortcut])) {
$url = $this->interwiki[$shortcut];
diff --git a/inc/parser/xhtml.php b/inc/parser/xhtml.php
index 0771b7abd..388e1b7ad 100644
--- a/inc/parser/xhtml.php
+++ b/inc/parser/xhtml.php
@@ -1,26 +1,15 @@
<?php
+
+use dokuwiki\ChangeLog\MediaChangeLog;
+
/**
* Renderer for XHTML output
*
+ * This is DokuWiki's main renderer used to display page content in the wiki
+ *
* @author Harry Fuecks <hfuecks@gmail.com>
* @author Andreas Gohr <andi@splitbrain.org>
- */
-if(!defined('DOKU_INC')) die('meh.');
-
-if(!defined('DOKU_LF')) {
- // Some whitespace to help View > Source
- define ('DOKU_LF', "\n");
-}
-
-if(!defined('DOKU_TAB')) {
- // Some whitespace to help View > Source
- define ('DOKU_TAB', "\t");
-}
-
-/**
- * The XHTML Renderer
*
- * This is DokuWiki's main renderer used to display page content in the wiki
*/
class Doku_Renderer_xhtml extends Doku_Renderer {
/** @var array store the table of contents */
@@ -28,14 +17,13 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
/** @var array A stack of section edit data */
protected $sectionedits = array();
- var $date_at = ''; // link pages and media against this revision
+
+ /** @var string|int link pages and media against this revision */
+ public $date_at = '';
/** @var int last section edit id, used by startSectionEdit */
protected $lastsecid = 0;
- /** @var array the list of headers used to create unique link ids */
- protected $headers = array();
-
/** @var array a list of footnotes, list starts at 1! */
protected $footnotes = array();
@@ -122,23 +110,22 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
*
* @return string always 'xhtml'
*/
- function getFormat() {
+ public function getFormat() {
return 'xhtml';
}
/**
* Initialize the document
*/
- function document_start() {
+ public function document_start() {
//reset some internals
$this->toc = array();
- $this->headers = array();
}
/**
* Finalize the document
*/
- function document_end() {
+ public function document_end() {
// Finish open section edits.
while(count($this->sectionedits) > 0) {
if($this->sectionedits[count($this->sectionedits) - 1]['start'] <= 1) {
@@ -183,7 +170,11 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
// Prepare the TOC
global $conf;
- if($this->info['toc'] && is_array($this->toc) && $conf['tocminheads'] && count($this->toc) >= $conf['tocminheads']) {
+ if(
+ $this->info['toc'] &&
+ is_array($this->toc) &&
+ $conf['tocminheads'] && count($this->toc) >= $conf['tocminheads']
+ ) {
global $TOC;
$TOC = $this->toc;
}
@@ -199,7 +190,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
* @param string $text the text to display
* @param int $level the nesting level
*/
- function toc_additem($id, $text, $level) {
+ public function toc_additem($id, $text, $level) {
global $conf;
//handle TOC
@@ -215,7 +206,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
* @param int $level header level
* @param int $pos byte position in the original source
*/
- function header($text, $level, $pos) {
+ public function header($text, $level, $pos) {
global $conf;
if(blank($text)) return; //skip empty headlines
@@ -261,14 +252,14 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
*
* @param int $level section level (as determined by the previous header)
*/
- function section_open($level) {
+ public function section_open($level) {
$this->doc .= '<div class="level'.$level.'">'.DOKU_LF;
}
/**
* Close the current section
*/
- function section_close() {
+ public function section_close() {
$this->doc .= DOKU_LF.'</div>'.DOKU_LF;
}
@@ -277,133 +268,133 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
*
* @param $text
*/
- function cdata($text) {
+ public function cdata($text) {
$this->doc .= $this->_xmlEntities($text);
}
/**
* Open a paragraph
*/
- function p_open() {
+ public function p_open() {
$this->doc .= DOKU_LF.'<p>'.DOKU_LF;
}
/**
* Close a paragraph
*/
- function p_close() {
+ public function p_close() {
$this->doc .= DOKU_LF.'</p>'.DOKU_LF;
}
/**
* Create a line break
*/
- function linebreak() {
+ public function linebreak() {
$this->doc .= '<br/>'.DOKU_LF;
}
/**
* Create a horizontal line
*/
- function hr() {
+ public function hr() {
$this->doc .= '<hr />'.DOKU_LF;
}
/**
* Start strong (bold) formatting
*/
- function strong_open() {
+ public function strong_open() {
$this->doc .= '<strong>';
}
/**
* Stop strong (bold) formatting
*/
- function strong_close() {
+ public function strong_close() {
$this->doc .= '</strong>';
}
/**
* Start emphasis (italics) formatting
*/
- function emphasis_open() {
+ public function emphasis_open() {
$this->doc .= '<em>';
}
/**
* Stop emphasis (italics) formatting
*/
- function emphasis_close() {
+ public function emphasis_close() {
$this->doc .= '</em>';
}
/**
* Start underline formatting
*/
- function underline_open() {
+ public function underline_open() {
$this->doc .= '<em class="u">';
}
/**
* Stop underline formatting
*/
- function underline_close() {
+ public function underline_close() {
$this->doc .= '</em>';
}
/**
* Start monospace formatting
*/
- function monospace_open() {
+ public function monospace_open() {
$this->doc .= '<code>';
}
/**
* Stop monospace formatting
*/
- function monospace_close() {
+ public function monospace_close() {
$this->doc .= '</code>';
}
/**
* Start a subscript
*/
- function subscript_open() {
+ public function subscript_open() {
$this->doc .= '<sub>';
}
/**
* Stop a subscript
*/
- function subscript_close() {
+ public function subscript_close() {
$this->doc .= '</sub>';
}
/**
* Start a superscript
*/
- function superscript_open() {
+ public function superscript_open() {
$this->doc .= '<sup>';
}
/**
* Stop a superscript
*/
- function superscript_close() {
+ public function superscript_close() {
$this->doc .= '</sup>';
}
/**
* Start deleted (strike-through) formatting
*/
- function deleted_open() {
+ public function deleted_open() {
$this->doc .= '<del>';
}
/**
* Stop deleted (strike-through) formatting
*/
- function deleted_close() {
+ public function deleted_close() {
$this->doc .= '</del>';
}
@@ -416,7 +407,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
*
* @author Andreas Gohr <andi@splitbrain.org>
*/
- function footnote_open() {
+ public function footnote_open() {
// move current content to store and record footnote
$this->store = $this->doc;
@@ -431,7 +422,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
*
* @author Andreas Gohr
*/
- function footnote_close() {
+ public function footnote_close() {
/** @var $fnid int takes track of seen footnotes, assures they are unique even across multiple docs FS#2841 */
static $fnid = 0;
// assign new footnote id (we start at 1)
@@ -462,7 +453,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
*
* @param string|string[] $classes css classes - have to be valid, do not pass unfiltered user input
*/
- function listu_open($classes = null) {
+ public function listu_open($classes = null) {
$class = '';
if($classes !== null) {
if(is_array($classes)) $classes = join(' ', $classes);
@@ -474,7 +465,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
/**
* Close an unordered list
*/
- function listu_close() {
+ public function listu_close() {
$this->doc .= '</ul>'.DOKU_LF;
}
@@ -483,7 +474,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
*
* @param string|string[] $classes css classes - have to be valid, do not pass unfiltered user input
*/
- function listo_open($classes = null) {
+ public function listo_open($classes = null) {
$class = '';
if($classes !== null) {
if(is_array($classes)) $classes = join(' ', $classes);
@@ -495,7 +486,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
/**
* Close an ordered list
*/
- function listo_close() {
+ public function listo_close() {
$this->doc .= '</ol>'.DOKU_LF;
}
@@ -505,7 +496,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
* @param int $level the nesting level
* @param bool $node true when a node; false when a leaf
*/
- function listitem_open($level, $node=false) {
+ public function listitem_open($level, $node=false) {
$branching = $node ? ' node' : '';
$this->doc .= '<li class="level'.$level.$branching.'">';
}
@@ -513,21 +504,21 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
/**
* Close a list item
*/
- function listitem_close() {
+ public function listitem_close() {
$this->doc .= '</li>'.DOKU_LF;
}
/**
* Start the content of a list item
*/
- function listcontent_open() {
+ public function listcontent_open() {
$this->doc .= '<div class="li">';
}
/**
* Stop the content of a list item
*/
- function listcontent_close() {
+ public function listcontent_close() {
$this->doc .= '</div>'.DOKU_LF;
}
@@ -538,7 +529,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
*
* @param string $text
*/
- function unformatted($text) {
+ public function unformatted($text) {
$this->doc .= $this->_xmlEntities($text);
}
@@ -550,7 +541,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
*
* @author Andreas Gohr <andi@splitbrain.org>
*/
- function php($text, $wrapper = 'code') {
+ public function php($text, $wrapper = 'code') {
global $conf;
if($conf['phpok']) {
@@ -571,7 +562,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
*
* @param string $text The PHP code
*/
- function phpblock($text) {
+ public function phpblock($text) {
$this->php($text, 'pre');
}
@@ -583,7 +574,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
*
* @author Andreas Gohr <andi@splitbrain.org>
*/
- function html($text, $wrapper = 'code') {
+ public function html($text, $wrapper = 'code') {
global $conf;
if($conf['htmlok']) {
@@ -600,21 +591,21 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
*
* @param string $text The HTML
*/
- function htmlblock($text) {
+ public function htmlblock($text) {
$this->html($text, 'pre');
}
/**
* Start a block quote
*/
- function quote_open() {
+ public function quote_open() {
$this->doc .= '<blockquote><div class="no">'.DOKU_LF;
}
/**
* Stop a block quote
*/
- function quote_close() {
+ public function quote_close() {
$this->doc .= '</div></blockquote>'.DOKU_LF;
}
@@ -623,7 +614,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
*
* @param string $text
*/
- function preformatted($text) {
+ public function preformatted($text) {
$this->doc .= '<pre class="code">'.trim($this->_xmlEntities($text), "\n\r").'</pre>'.DOKU_LF;
}
@@ -635,7 +626,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
* @param string $filename file path label
* @param array $options assoziative array with additional geshi options
*/
- function file($text, $language = null, $filename = null, $options=null) {
+ public function file($text, $language = null, $filename = null, $options=null) {
$this->_highlight('file', $text, $language, $filename, $options);
}
@@ -647,7 +638,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
* @param string $filename file path label
* @param array $options assoziative array with additional geshi options
*/
- function code($text, $language = null, $filename = null, $options=null) {
+ public function code($text, $language = null, $filename = null, $options=null) {
$this->_highlight('code', $text, $language, $filename, $options);
}
@@ -661,7 +652,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
* @param string $filename file path label
* @param array $options assoziative array with additional geshi options
*/
- function _highlight($type, $text, $language = null, $filename = null, $options = null) {
+ public function _highlight($type, $text, $language = null, $filename = null, $options = null) {
global $ID;
global $lang;
global $INPUT;
@@ -679,7 +670,12 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
$offset = $INPUT->str('codeblockOffset');
}
$this->doc .= '<dl class="'.$type.'">'.DOKU_LF;
- $this->doc .= '<dt><a href="'.exportlink($ID, 'code', array('codeblock' => $offset+$this->_codeblock)).'" title="'.$lang['download'].'" class="'.$class.'">';
+ $this->doc .= '<dt><a href="' .
+ exportlink(
+ $ID,
+ 'code',
+ array('codeblock' => $offset + $this->_codeblock)
+ ) . '" title="' . $lang['download'] . '" class="' . $class . '">';
$this->doc .= hsc($filename);
$this->doc .= '</a></dt>'.DOKU_LF.'<dd>';
}
@@ -697,7 +693,9 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
$class = 'code'; //we always need the code class to make the syntax highlighting apply
if($type != 'code') $class .= ' '.$type;
- $this->doc .= "<pre class=\"$class $language\">".p_xhtml_cached_geshi($text, $language, '', $options).'</pre>'.DOKU_LF;
+ $this->doc .= "<pre class=\"$class $language\">" .
+ p_xhtml_cached_geshi($text, $language, '', $options) .
+ '</pre>' . DOKU_LF;
}
if($filename) {
@@ -714,7 +712,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
*
* @param string $acronym
*/
- function acronym($acronym) {
+ public function acronym($acronym) {
if(array_key_exists($acronym, $this->acronyms)) {
@@ -735,7 +733,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
*
* @param string $smiley
*/
- function smiley($smiley) {
+ public function smiley($smiley) {
if(array_key_exists($smiley, $this->smileys)) {
$this->doc .= '<img src="'.DOKU_BASE.'lib/images/smileys/'.$this->smileys[$smiley].
'" class="icon" alt="'.
@@ -754,7 +752,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
*
* @param string $entity
*/
- function entity($entity) {
+ public function entity($entity) {
if(array_key_exists($entity, $this->entities)) {
$this->doc .= $this->entities[$entity];
} else {
@@ -770,14 +768,14 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
* @param string|int $x first value
* @param string|int $y second value
*/
- function multiplyentity($x, $y) {
+ public function multiplyentity($x, $y) {
$this->doc .= "$x&times;$y";
}
/**
* Render an opening single quote char (language specific)
*/
- function singlequoteopening() {
+ public function singlequoteopening() {
global $lang;
$this->doc .= $lang['singlequoteopening'];
}
@@ -785,7 +783,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
/**
* Render a closing single quote char (language specific)
*/
- function singlequoteclosing() {
+ public function singlequoteclosing() {
global $lang;
$this->doc .= $lang['singlequoteclosing'];
}
@@ -793,7 +791,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
/**
* Render an apostrophe char (language specific)
*/
- function apostrophe() {
+ public function apostrophe() {
global $lang;
$this->doc .= $lang['apostrophe'];
}
@@ -801,7 +799,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
/**
* Render an opening double quote char (language specific)
*/
- function doublequoteopening() {
+ public function doublequoteopening() {
global $lang;
$this->doc .= $lang['doublequoteopening'];
}
@@ -809,7 +807,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
/**
* Render an closinging double quote char (language specific)
*/
- function doublequoteclosing() {
+ public function doublequoteclosing() {
global $lang;
$this->doc .= $lang['doublequoteclosing'];
}
@@ -823,7 +821,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
*
* @see http://en.wikipedia.org/wiki/CamelCase
*/
- function camelcaselink($link, $returnonly = false) {
+ public function camelcaselink($link, $returnonly = false) {
if($returnonly) {
return $this->internallink($link, $link, null, true);
} else {
@@ -839,7 +837,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
* @param bool $returnonly whether to return html or write to doc attribute
* @return void|string writes to doc attribute or returns html depends on $returnonly
*/
- function locallink($hash, $name = null, $returnonly = false) {
+ public function locallink($hash, $name = null, $returnonly = false) {
global $ID;
$name = $this->_getLinkTitle($name, $hash, $isImage);
$hash = $this->_headerToLink($hash);
@@ -870,7 +868,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
* @param string $linktype type to set use of headings
* @return void|string writes to doc attribute or returns html depends on $returnonly
*/
- function internallink($id, $name = null, $search = null, $returnonly = false, $linktype = 'content') {
+ public function internallink($id, $name = null, $search = null, $returnonly = false, $linktype = 'content') {
global $conf;
global $ID;
global $INFO;
@@ -961,7 +959,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
* @param bool $returnonly whether to return html or write to doc attribute
* @return void|string writes to doc attribute or returns html depends on $returnonly
*/
- function externallink($url, $name = null, $returnonly = false) {
+ public function externallink($url, $name = null, $returnonly = false) {
global $conf;
$name = $this->_getLinkTitle($name, $url, $isImage);
@@ -1025,7 +1023,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
* @param bool $returnonly whether to return html or write to doc attribute
* @return void|string writes to doc attribute or returns html depends on $returnonly
*/
- function interwikilink($match, $name = null, $wikiName, $wikiUri, $returnonly = false) {
+ public function interwikilink($match, $name, $wikiName, $wikiUri, $returnonly = false) {
global $conf;
$link = array();
@@ -1080,7 +1078,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
* @param bool $returnonly whether to return html or write to doc attribute
* @return void|string writes to doc attribute or returns html depends on $returnonly
*/
- function windowssharelink($url, $name = null, $returnonly = false) {
+ public function windowssharelink($url, $name = null, $returnonly = false) {
global $conf;
//simple setup
@@ -1120,7 +1118,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
* @param bool $returnonly whether to return html or write to doc attribute
* @return void|string writes to doc attribute or returns html depends on $returnonly
*/
- function emaillink($address, $name = null, $returnonly = false) {
+ public function emaillink($address, $name = null, $returnonly = false) {
global $conf;
//simple setup
$link = array();
@@ -1172,7 +1170,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
* @param bool $return return HTML instead of adding to $doc
* @return void|string writes to doc attribute or returns html depends on $return
*/
- function internalmedia($src, $title = null, $align = null, $width = null,
+ public function internalmedia($src, $title = null, $align = null, $width = null,
$height = null, $cache = null, $linking = null, $return = false) {
global $ID;
if (strpos($src, '#') !== false) {
@@ -1186,7 +1184,15 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
list($ext, $mime) = mimetype($src, false);
if(substr($mime, 0, 5) == 'image' && $render) {
- $link['url'] = ml($src, array('id' => $ID, 'cache' => $cache, 'rev'=>$this->_getLastMediaRevisionAt($src)), ($linking == 'direct'));
+ $link['url'] = ml(
+ $src,
+ array(
+ 'id' => $ID,
+ 'cache' => $cache,
+ 'rev' => $this->_getLastMediaRevisionAt($src)
+ ),
+ ($linking == 'direct')
+ );
} elseif(($mime == 'application/x-shockwave-flash' || media_supportedav($mime)) && $render) {
// don't link movies
$noLink = true;
@@ -1194,7 +1200,15 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
// add file icons
$class = preg_replace('/[^_\-a-z0-9]+/i', '_', $ext);
$link['class'] .= ' mediafile mf_'.$class;
- $link['url'] = ml($src, array('id' => $ID, 'cache' => $cache , 'rev'=>$this->_getLastMediaRevisionAt($src)), true);
+ $link['url'] = ml(
+ $src,
+ array(
+ 'id' => $ID,
+ 'cache' => $cache,
+ 'rev' => $this->_getLastMediaRevisionAt($src)
+ ),
+ true
+ );
if($exists) $link['title'] .= ' ('.filesize_h(filesize(mediaFN($src))).')';
}
@@ -1228,7 +1242,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
* @param bool $return return HTML instead of adding to $doc
* @return void|string writes to doc attribute or returns html depends on $return
*/
- function externalmedia($src, $title = null, $align = null, $width = null,
+ public function externalmedia($src, $title = null, $align = null, $width = null,
$height = null, $cache = null, $linking = null, $return = false) {
if(link_isinterwiki($src)){
list($shortcut, $reference) = explode('>', $src, 2);
@@ -1275,7 +1289,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
*
* @author Andreas Gohr <andi@splitbrain.org>
*/
- function rss($url, $params) {
+ public function rss($url, $params) {
global $lang;
global $conf;
@@ -1367,7 +1381,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
* @param int $pos byte position in the original source
* @param string|string[] $classes css classes - have to be valid, do not pass unfiltered user input
*/
- function table_open($maxcols = null, $numrows = null, $pos = null, $classes = null) {
+ public function table_open($maxcols = null, $numrows = null, $pos = null, $classes = null) {
// initialize the row counter used for classes
$this->_counter['row_counter'] = 0;
$class = 'table';
@@ -1392,7 +1406,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
*
* @param int $pos byte position in the original source
*/
- function table_close($pos = null) {
+ public function table_close($pos = null) {
$this->doc .= '</table></div>'.DOKU_LF;
if($pos !== null) {
$this->finishSectionEdit($pos);
@@ -1402,42 +1416,42 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
/**
* Open a table header
*/
- function tablethead_open() {
+ public function tablethead_open() {
$this->doc .= DOKU_TAB.'<thead>'.DOKU_LF;
}
/**
* Close a table header
*/
- function tablethead_close() {
+ public function tablethead_close() {
$this->doc .= DOKU_TAB.'</thead>'.DOKU_LF;
}
/**
* Open a table body
*/
- function tabletbody_open() {
+ public function tabletbody_open() {
$this->doc .= DOKU_TAB.'<tbody>'.DOKU_LF;
}
/**
* Close a table body
*/
- function tabletbody_close() {
+ public function tabletbody_close() {
$this->doc .= DOKU_TAB.'</tbody>'.DOKU_LF;
}
/**
* Open a table footer
*/
- function tabletfoot_open() {
+ public function tabletfoot_open() {
$this->doc .= DOKU_TAB.'<tfoot>'.DOKU_LF;
}
/**
* Close a table footer
*/
- function tabletfoot_close() {
+ public function tabletfoot_close() {
$this->doc .= DOKU_TAB.'</tfoot>'.DOKU_LF;
}
@@ -1446,7 +1460,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
*
* @param string|string[] $classes css classes - have to be valid, do not pass unfiltered user input
*/
- function tablerow_open($classes = null) {
+ public function tablerow_open($classes = null) {
// initialize the cell counter used for classes
$this->_counter['cell_counter'] = 0;
$class = 'row'.$this->_counter['row_counter']++;
@@ -1460,7 +1474,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
/**
* Close a table row
*/
- function tablerow_close() {
+ public function tablerow_close() {
$this->doc .= DOKU_LF.DOKU_TAB.'</tr>'.DOKU_LF;
}
@@ -1472,7 +1486,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
* @param int $rowspan
* @param string|string[] $classes css classes - have to be valid, do not pass unfiltered user input
*/
- function tableheader_open($colspan = 1, $align = null, $rowspan = 1, $classes = null) {
+ public function tableheader_open($colspan = 1, $align = null, $rowspan = 1, $classes = null) {
$class = 'class="col'.$this->_counter['cell_counter']++;
if(!is_null($align)) {
$class .= ' '.$align.'align';
@@ -1496,7 +1510,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
/**
* Close a table header cell
*/
- function tableheader_close() {
+ public function tableheader_close() {
$this->doc .= '</th>';
}
@@ -1508,7 +1522,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
* @param int $rowspan
* @param string|string[] $classes css classes - have to be valid, do not pass unfiltered user input
*/
- function tablecell_open($colspan = 1, $align = null, $rowspan = 1, $classes = null) {
+ public function tablecell_open($colspan = 1, $align = null, $rowspan = 1, $classes = null) {
$class = 'class="col'.$this->_counter['cell_counter']++;
if(!is_null($align)) {
$class .= ' '.$align.'align';
@@ -1532,7 +1546,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
/**
* Close a table cell
*/
- function tablecell_close() {
+ public function tablecell_close() {
$this->doc .= '</td>';
}
@@ -1542,7 +1556,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
*
* @return int The current header level
*/
- function getLastlevel() {
+ public function getLastlevel() {
return $this->lastlevel;
}
@@ -1558,7 +1572,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
*
* @author Andreas Gohr <andi@splitbrain.org>
*/
- function _formatLink($link) {
+ public function _formatLink($link) {
//make sure the url is XHTML compliant (skip mailto)
if(substr($link['url'], 0, 7) != 'mailto:') {
$link['url'] = str_replace('&', '&amp;', $link['url']);
@@ -1601,7 +1615,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
* @param bool $render should the media be embedded inline or just linked
* @return string
*/
- function _media($src, $title = null, $align = null, $width = null,
+ public function _media($src, $title = null, $align = null, $width = null,
$height = null, $cache = null, $render = true) {
$ret = '';
@@ -1625,12 +1639,19 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
// return the title of the picture
if(!$title) {
// just show the sourcename
- $title = $this->_xmlEntities(utf8_basename(noNS($src)));
+ $title = $this->_xmlEntities(\dokuwiki\Utf8\PhpString::basename(noNS($src)));
}
return $title;
}
//add image tag
- $ret .= '<img src="'.ml($src, array('w' => $width, 'h' => $height, 'cache' => $cache, 'rev'=>$this->_getLastMediaRevisionAt($src))).'"';
+ $ret .= '<img src="' . ml(
+ $src,
+ array(
+ 'w' => $width, 'h' => $height,
+ 'cache' => $cache,
+ 'rev' => $this->_getLastMediaRevisionAt($src)
+ )
+ ) . '"';
$ret .= ' class="media'.$align.'"';
if($title) {
@@ -1654,7 +1675,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
if(!$render) {
// if the file is not supposed to be rendered
// return the title of the file (just the sourcename if there is no title)
- return $title ? $title : $this->_xmlEntities(utf8_basename(noNS($src)));
+ return $title ? $title : $this->_xmlEntities(\dokuwiki\Utf8\PhpString::basename(noNS($src)));
}
$att = array();
@@ -1678,7 +1699,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
// return the title of the flash
if(!$title) {
// just show the sourcename
- $title = utf8_basename(noNS($src));
+ $title = \dokuwiki\Utf8\PhpString::basename(noNS($src));
}
return $this->_xmlEntities($title);
}
@@ -1699,7 +1720,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
$ret .= $this->_xmlEntities($title);
} else {
// just show the sourcename
- $ret .= $this->_xmlEntities(utf8_basename(noNS($src)));
+ $ret .= $this->_xmlEntities(\dokuwiki\Utf8\PhpString::basename(noNS($src)));
}
return $ret;
@@ -1711,26 +1732,11 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
* @param $string
* @return string
*/
- function _xmlEntities($string) {
+ public function _xmlEntities($string) {
return htmlspecialchars($string, ENT_QUOTES, 'UTF-8');
}
- /**
- * Creates a linkid from a headline
- *
- * @author Andreas Gohr <andi@splitbrain.org>
- * @param string $title The headline title
- * @param boolean $create Create a new unique ID?
- * @return string
- */
- function _headerToLink($title, $create = false) {
- if($create) {
- return sectionID($title, $this->headers);
- } else {
- $check = false;
- return sectionID($title, $check);
- }
- }
+
/**
* Construct a title and handle images in titles
@@ -1743,7 +1749,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
* @param string $linktype content|navigation
* @return string HTML of the title, might be full image tag or just escaped text
*/
- function _getLinkTitle($title, $default, &$isImage, $id = null, $linktype = 'content') {
+ public function _getLinkTitle($title, $default, &$isImage, $id = null, $linktype = 'content') {
$isImage = false;
if(is_array($title)) {
$isImage = true;
@@ -1768,7 +1774,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
* @param array $img
* @return string HTML img tag or similar
*/
- function _imageTitle($img) {
+ public function _imageTitle($img) {
global $ID;
// some fixes on $img['src']
@@ -1803,7 +1809,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
* @param bool $render should the media be embedded inline or just linked
* @return array associative array with link config
*/
- function _getMediaLinkConf($src, $title, $align, $width, $height, $cache, $render) {
+ public function _getMediaLinkConf($src, $title, $align, $width, $height, $cache, $render) {
global $conf;
$link = array();
@@ -1832,7 +1838,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
* @param array $atts - additional attributes for the <video> tag
* @return string
*/
- function _video($src, $width, $height, $atts = null) {
+ public function _video($src, $width, $height, $atts = null) {
// prepare width and height
if(is_null($atts)) $atts = array();
$atts['width'] = (int) $width;
@@ -1876,11 +1882,20 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
$url = ml($file, '', true, '&');
$linkType = 'internalmedia';
}
- $title = $atts['title'] ? $atts['title'] : $this->_xmlEntities(utf8_basename(noNS($file)));
+ $title = $atts['title'] ? $atts['title'] : $this->_xmlEntities(\dokuwiki\Utf8\PhpString::basename(noNS($file)));
$out .= '<source src="'.hsc($url).'" type="'.$mime.'" />'.NL;
// alternative content (just a link to the file)
- $fallback .= $this->$linkType($file, $title, null, null, null, $cache = null, $linking = 'linkonly', $return = true);
+ $fallback .= $this->$linkType(
+ $file,
+ $title,
+ null,
+ null,
+ null,
+ $cache = null,
+ $linking = 'linkonly',
+ $return = true
+ );
}
// output each track if any
@@ -1906,7 +1921,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
* @param array $atts - additional attributes for the <audio> tag
* @return string
*/
- function _audio($src, $atts = array()) {
+ public function _audio($src, $atts = array()) {
$files = array();
$isExternal = media_isexternal($src);
@@ -1934,11 +1949,20 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
$url = ml($file, '', true, '&');
$linkType = 'internalmedia';
}
- $title = $atts['title'] ? $atts['title'] : $this->_xmlEntities(utf8_basename(noNS($file)));
+ $title = $atts['title'] ? $atts['title'] : $this->_xmlEntities(\dokuwiki\Utf8\PhpString::basename(noNS($file)));
$out .= '<source src="'.hsc($url).'" type="'.$mime.'" />'.NL;
// alternative content (just a link to the file)
- $fallback .= $this->$linkType($file, $title, null, null, null, $cache = null, $linking = 'linkonly', $return = true);
+ $fallback .= $this->$linkType(
+ $file,
+ $title,
+ null,
+ null,
+ null,
+ $cache = null,
+ $linking = 'linkonly',
+ $return = true
+ );
}
// finish
@@ -1956,7 +1980,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
* @access protected
* @return string revision ('' for current)
*/
- function _getLastMediaRevisionAt($media_id){
+ protected function _getLastMediaRevisionAt($media_id){
if(!$this->date_at || media_isexternal($media_id)) return '';
$pagelog = new MediaChangeLog($media_id);
return $pagelog->getLastRevisionAt($this->date_at);
diff --git a/inc/parser/xhtmlsummary.php b/inc/parser/xhtmlsummary.php
index 867b71f6a..4641bf836 100644
--- a/inc/parser/xhtmlsummary.php
+++ b/inc/parser/xhtmlsummary.php
@@ -1,6 +1,4 @@
<?php
-if(!defined('DOKU_INC')) die('meh.');
-
/**
* The summary XHTML form selects either up to the first two paragraphs
* it find in a page or the first section (whichever comes first)
@@ -20,32 +18,25 @@ class Doku_Renderer_xhtmlsummary extends Doku_Renderer_xhtml {
// Namespace these variables to
// avoid clashes with parent classes
- var $sum_paragraphs = 0;
- var $sum_capture = true;
- var $sum_inSection = false;
- var $sum_summary = '';
- var $sum_pageTitle = false;
+ protected $sum_paragraphs = 0;
+ protected $sum_capture = true;
+ protected $sum_inSection = false;
+ protected $sum_summary = '';
+ protected $sum_pageTitle = false;
- function document_start() {
+ /** @inheritdoc */
+ public function document_start() {
$this->doc .= DOKU_LF.'<div>'.DOKU_LF;
}
- function document_end() {
+ /** @inheritdoc */
+ public function document_end() {
$this->doc = $this->sum_summary;
$this->doc .= DOKU_LF.'</div>'.DOKU_LF;
}
- // FIXME not supported anymore
- function toc_open() {
- $this->sum_summary .= $this->doc;
- }
-
- // FIXME not supported anymore
- function toc_close() {
- $this->doc = '';
- }
-
- function header($text, $level, $pos) {
+ /** @inheritdoc */
+ public function header($text, $level, $pos) {
if ( !$this->sum_pageTitle ) {
$this->info['sum_pagetitle'] = $text;
$this->sum_pageTitle = true;
@@ -55,27 +46,31 @@ class Doku_Renderer_xhtmlsummary extends Doku_Renderer_xhtml {
$this->doc .= "</h$level>".DOKU_LF;
}
- function section_open($level) {
+ /** @inheritdoc */
+ public function section_open($level) {
if ( $this->sum_capture ) {
$this->sum_inSection = true;
}
}
- function section_close() {
+ /** @inheritdoc */
+ public function section_close() {
if ( $this->sum_capture && $this->sum_inSection ) {
$this->sum_summary .= $this->doc;
$this->sum_capture = false;
}
}
- function p_open() {
+ /** @inheritdoc */
+ public function p_open() {
if ( $this->sum_capture && $this->sum_paragraphs < 2 ) {
$this->sum_paragraphs++;
}
parent :: p_open();
}
- function p_close() {
+ /** @inheritdoc */
+ public function p_close() {
parent :: p_close();
if ( $this->sum_capture && $this->sum_paragraphs >= 2 ) {
$this->sum_summary .= $this->doc;
diff --git a/inc/parserutils.php b/inc/parserutils.php
index ddd21beda..846be54db 100644
--- a/inc/parserutils.php
+++ b/inc/parserutils.php
@@ -7,7 +7,12 @@
* @author Andreas Gohr <andi@splitbrain.org>
*/
-if(!defined('DOKU_INC')) die('meh.');
+use dokuwiki\Cache\CacheInstructions;
+use dokuwiki\Cache\CacheRenderer;
+use dokuwiki\ChangeLog\PageChangeLog;
+use dokuwiki\Extension\PluginController;
+use dokuwiki\Extension\Event;
+use dokuwiki\Parsing\Parser;
/**
* How many pages shall be rendered for getting metadata during one request
@@ -74,7 +79,8 @@ function p_wiki_xhtml($id, $rev='', $excuse=true,$date_at=''){
if($rev || $date_at){
if(file_exists($file)){
- $ret = p_render('xhtml',p_get_instructions(io_readWikiPage($file,$id,$rev)),$info,$date_at); //no caching on old revisions
+ //no caching on old revisions
+ $ret = p_render('xhtml',p_get_instructions(io_readWikiPage($file,$id,$rev)),$info,$date_at);
}elseif($excuse){
$ret = p_locale_xhtml('norev');
}
@@ -83,7 +89,7 @@ function p_wiki_xhtml($id, $rev='', $excuse=true,$date_at=''){
$ret = p_cached_output($file,'xhtml',$id);
}elseif($excuse){
//check if the page once existed
- $changelog = new PageChangelog($id);
+ $changelog = new PageChangeLog($id);
if($changelog->hasRevisions()) {
$ret = p_locale_xhtml('onceexisted');
} else {
@@ -126,7 +132,7 @@ function p_locale_xhtml($id){
function p_cached_output($file, $format='xhtml', $id='') {
global $conf;
- $cache = new cache_renderer($id, $file, $format);
+ $cache = new CacheRenderer($id, $file, $format);
if ($cache->useCache()) {
$parsed = $cache->retrieveCache(false);
if($conf['allowdebug'] && $format=='xhtml') {
@@ -166,7 +172,7 @@ function p_cached_instructions($file,$cacheonly=false,$id='') {
static $run = null;
if(is_null($run)) $run = array();
- $cache = new cache_instructions($id, $file);
+ $cache = new CacheInstructions($id, $file);
if ($cacheonly || $cache->useCache() || (isset($run[$file]) && !defined('DOKU_UNITTEST'))) {
return $cache->retrieveCache();
@@ -197,11 +203,8 @@ function p_get_instructions($text){
$modes = p_get_parsermodes();
- // Create the parser
- $Parser = new Doku_Parser();
-
- // Add the Handler
- $Parser->Handler = new Doku_Handler();
+ // Create the parser and handler
+ $Parser = new Parser(new Doku_Handler());
//add modes to parser
foreach($modes as $mode){
@@ -209,7 +212,7 @@ function p_get_instructions($text){
}
// Do the parsing
- trigger_event('PARSER_WIKITEXT_PREPROCESS', $text);
+ Event::createAndTrigger('PARSER_WIKITEXT_PREPROCESS', $text);
$p = $Parser->parse($text);
// dbg($p);
return $p;
@@ -219,7 +222,8 @@ function p_get_instructions($text){
* returns the metadata of a page
*
* @param string $id The id of the page the metadata should be returned from
- * @param string $key The key of the metdata value that shall be read (by default everything) - separate hierarchies by " " like "date created"
+ * @param string $key The key of the metdata value that shall be read (by default everything)
+ * separate hierarchies by " " like "date created"
* @param int $render If the page should be rendererd - possible values:
* METADATA_DONT_RENDER, METADATA_RENDER_USING_SIMPLE_CACHE, METADATA_RENDER_USING_CACHE
* METADATA_RENDER_UNLIMITED (also combined with the previous two options),
@@ -255,7 +259,7 @@ function p_get_metadata($id, $key='', $render=METADATA_RENDER_USING_CACHE){
if (!$recursion && $render != METADATA_DONT_RENDER && !isset($rendered_pages[$id])&& page_exists($id)){
$recursion = true;
- $cachefile = new cache_renderer($id, wikiFN($id), 'metadata');
+ $cachefile = new CacheRenderer($id, wikiFN($id), 'metadata');
$do_render = false;
if ($render & METADATA_RENDER_UNLIMITED || $render_count < P_GET_METADATA_RENDER_LIMIT) {
@@ -306,10 +310,10 @@ function p_get_metadata($id, $key='', $render=METADATA_RENDER_USING_CACHE){
*
* @see http://www.dokuwiki.org/devel:metadata#functions_to_get_and_set_metadata
*
- * @param String $id is the ID of a wiki page
- * @param Array $data is an array with key ⇒ value pairs to be set in the metadata
- * @param Boolean $render whether or not the page metadata should be generated with the renderer
- * @param Boolean $persistent indicates whether or not the particular metadata value will persist through
+ * @param string $id is the ID of a wiki page
+ * @param array $data is an array with key ⇒ value pairs to be set in the metadata
+ * @param boolean $render whether or not the page metadata should be generated with the renderer
+ * @param boolean $persistent indicates whether or not the particular metadata value will persist through
* the next metadata rendering.
* @return boolean true on success
*
@@ -349,7 +353,10 @@ function p_set_metadata($id, $data, $render=false, $persistent=true){
}
if($persistent) {
if(isset($meta['persistent'][$key][$subkey]) && is_array($meta['persistent'][$key][$subkey])) {
- $meta['persistent'][$key][$subkey] = array_replace($meta['persistent'][$key][$subkey], (array)$subvalue);
+ $meta['persistent'][$key][$subkey] = array_replace(
+ $meta['persistent'][$key][$subkey],
+ (array) $subvalue
+ );
} else {
$meta['persistent'][$key][$subkey] = $subvalue;
}
@@ -361,10 +368,14 @@ function p_set_metadata($id, $data, $render=false, $persistent=true){
// these keys, must have subkeys - a legitimate value must be an array
if (is_array($value)) {
- $meta['current'][$key] = !empty($meta['current'][$key]) ? array_replace((array)$meta['current'][$key],$value) : $value;
+ $meta['current'][$key] = !empty($meta['current'][$key]) ?
+ array_replace((array)$meta['current'][$key],$value) :
+ $value;
if ($persistent) {
- $meta['persistent'][$key] = !empty($meta['persistent'][$key]) ? array_replace((array)$meta['persistent'][$key],$value) : $value;
+ $meta['persistent'][$key] = !empty($meta['persistent'][$key]) ?
+ array_replace((array)$meta['persistent'][$key],$value) :
+ $value;
}
}
@@ -428,7 +439,9 @@ function p_read_metadata($id,$cache=false) {
if (isset($cache_metadata[(string)$id])) return $cache_metadata[(string)$id];
$file = metaFN($id, '.meta');
- $meta = file_exists($file) ? unserialize(io_readFile($file, false)) : array('current'=>array(),'persistent'=>array());
+ $meta = file_exists($file) ?
+ unserialize(io_readFile($file, false)) :
+ array('current'=>array(),'persistent'=>array());
if ($cache) {
$cache_metadata[(string)$id] = $meta;
@@ -481,7 +494,7 @@ function p_render_metadata($id, $orig){
// add an extra key for the event - to tell event handlers the page whose metadata this is
$orig['page'] = $id;
- $evt = new Doku_Event('PARSER_METADATA_RENDER', $orig);
+ $evt = new Event('PARSER_METADATA_RENDER', $orig);
if ($evt->advise_before()) {
// get instructions
@@ -542,7 +555,7 @@ function p_get_parsermodes(){
global $PARSER_MODES;
$obj = null;
foreach($pluginlist as $p){
- /** @var DokuWiki_Syntax_Plugin $obj */
+ /** @var \dokuwiki\Extension\SyntaxPlugin $obj */
if(!$obj = plugin_load('syntax',$p)) continue; //attempt to load plugin into $obj
$PARSER_MODES[$obj->getType()][] = "plugin_$p"; //register mode type
//add to modes
@@ -566,7 +579,7 @@ function p_get_parsermodes(){
$std_modes[] = 'multiplyentity';
}
foreach($std_modes as $m){
- $class = "Doku_Parser_Mode_$m";
+ $class = 'dokuwiki\\Parsing\\ParserMode\\'.ucfirst($m);
$obj = new $class();
$modes[] = array(
'sort' => $obj->getSort(),
@@ -579,7 +592,7 @@ function p_get_parsermodes(){
$fmt_modes = array('strong','emphasis','underline','monospace',
'subscript','superscript','deleted');
foreach($fmt_modes as $m){
- $obj = new Doku_Parser_Mode_formatting($m);
+ $obj = new \dokuwiki\Parsing\ParserMode\Formatting($m);
$modes[] = array(
'sort' => $obj->getSort(),
'mode' => $m,
@@ -588,16 +601,16 @@ function p_get_parsermodes(){
}
// add modes which need files
- $obj = new Doku_Parser_Mode_smiley(array_keys(getSmileys()));
+ $obj = new \dokuwiki\Parsing\ParserMode\Smiley(array_keys(getSmileys()));
$modes[] = array('sort' => $obj->getSort(), 'mode' => 'smiley','obj' => $obj );
- $obj = new Doku_Parser_Mode_acronym(array_keys(getAcronyms()));
+ $obj = new \dokuwiki\Parsing\ParserMode\Acronym(array_keys(getAcronyms()));
$modes[] = array('sort' => $obj->getSort(), 'mode' => 'acronym','obj' => $obj );
- $obj = new Doku_Parser_Mode_entity(array_keys(getEntities()));
+ $obj = new \dokuwiki\Parsing\ParserMode\Entity(array_keys(getEntities()));
$modes[] = array('sort' => $obj->getSort(), 'mode' => 'entity','obj' => $obj );
// add optional camelcase mode
if($conf['camelcase']){
- $obj = new Doku_Parser_Mode_camelcaselink();
+ $obj = new \dokuwiki\Parsing\ParserMode\Camelcaselink();
$modes[] = array('sort' => $obj->getSort(), 'mode' => 'camelcaselink','obj' => $obj );
}
@@ -666,7 +679,7 @@ function p_render($mode,$instructions,&$info,$date_at=''){
// Post process and return the output
$data = array($mode,& $Renderer->doc);
- trigger_event('RENDERER_CONTENT_POSTPROCESS',$data);
+ Event::createAndTrigger('RENDERER_CONTENT_POSTPROCESS',$data);
return $Renderer->doc;
}
@@ -680,7 +693,7 @@ function p_render($mode,$instructions,&$info,$date_at=''){
* @author Christopher Smith <chris@jalakai.co.uk>
*/
function p_get_renderer($mode) {
- /** @var Doku_Plugin_Controller $plugin_controller */
+ /** @var PluginController $plugin_controller */
global $conf, $plugin_controller;
$rname = !empty($conf['renderer_'.$mode]) ? $conf['renderer_'.$mode] : $mode;
diff --git a/inc/plugincontroller.class.php b/inc/plugincontroller.class.php
deleted file mode 100644
index fd8cd9663..000000000
--- a/inc/plugincontroller.class.php
+++ /dev/null
@@ -1,347 +0,0 @@
-<?php
-/**
- * Class to encapsulate access to dokuwiki plugins
- *
- * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
- * @author Christopher Smith <chris@jalakai.co.uk>
- */
-
-// plugin related constants
-if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/');
-
-class Doku_Plugin_Controller {
-
- protected $list_bytype = array();
- protected $tmp_plugins = array();
- protected $plugin_cascade = array('default'=>array(),'local'=>array(),'protected'=>array());
- protected $last_local_config_file = '';
-
- /**
- * Populates the master list of plugins
- */
- public function __construct() {
- $this->loadConfig();
- $this->_populateMasterList();
- }
-
- /**
- * Returns a list of available plugins of given type
- *
- * @param $type string, plugin_type name;
- * the type of plugin to return,
- * use empty string for all types
- * @param $all bool;
- * false to only return enabled plugins,
- * true to return both enabled and disabled plugins
- *
- * @return array of
- * - plugin names when $type = ''
- * - or plugin component names when a $type is given
- *
- * @author Andreas Gohr <andi@splitbrain.org>
- */
- public function getList($type='',$all=false){
-
- // request the complete list
- if (!$type) {
- return $all ? array_keys($this->tmp_plugins) : array_keys(array_filter($this->tmp_plugins));
- }
-
- if (!isset($this->list_bytype[$type]['enabled'])) {
- $this->list_bytype[$type]['enabled'] = $this->_getListByType($type,true);
- }
- if ($all && !isset($this->list_bytype[$type]['disabled'])) {
- $this->list_bytype[$type]['disabled'] = $this->_getListByType($type,false);
- }
-
- return $all ? array_merge($this->list_bytype[$type]['enabled'],$this->list_bytype[$type]['disabled']) : $this->list_bytype[$type]['enabled'];
- }
-
- /**
- * Loads the given plugin and creates an object of it
- *
- * @author Andreas Gohr <andi@splitbrain.org>
- *
- * @param $type string type of plugin to load
- * @param $name string name of the plugin to load
- * @param $new bool true to return a new instance of the plugin, false to use an already loaded instance
- * @param $disabled bool true to load even disabled plugins
- * @return DokuWiki_PluginInterface|null the plugin object or null on failure
- */
- public function load($type,$name,$new=false,$disabled=false){
-
- //we keep all loaded plugins available in global scope for reuse
- global $DOKU_PLUGINS;
-
- list($plugin, /* $component */) = $this->_splitName($name);
-
- // check if disabled
- if(!$disabled && $this->isdisabled($plugin)){
- return null;
- }
-
- $class = $type.'_plugin_'.$name;
-
- //plugin already loaded?
- if(!empty($DOKU_PLUGINS[$type][$name])){
- if ($new || !$DOKU_PLUGINS[$type][$name]->isSingleton()) {
- return class_exists($class, true) ? new $class : null;
- } else {
- return $DOKU_PLUGINS[$type][$name];
- }
- }
-
- //construct class and instantiate
- if (!class_exists($class, true)) {
-
- # the plugin might be in the wrong directory
- $dir = $this->get_directory($plugin);
- $inf = confToHash(DOKU_PLUGIN."$dir/plugin.info.txt");
- if($inf['base'] && $inf['base'] != $plugin){
- msg(sprintf("Plugin installed incorrectly. Rename plugin directory '%s' to '%s'.", hsc($plugin), hsc($inf['base'])), -1);
- } elseif (preg_match('/^'.DOKU_PLUGIN_NAME_REGEX.'$/', $plugin) !== 1) {
- msg(sprintf("Plugin name '%s' is not a valid plugin name, only the characters a-z and 0-9 are allowed. ".
- 'Maybe the plugin has been installed in the wrong directory?', hsc($plugin)), -1);
- }
- return null;
- }
-
- $DOKU_PLUGINS[$type][$name] = new $class;
- return $DOKU_PLUGINS[$type][$name];
- }
-
- /**
- * Whether plugin is disabled
- *
- * @param string $plugin name of plugin
- * @return bool true disabled, false enabled
- */
- public function isdisabled($plugin) {
- return empty($this->tmp_plugins[$plugin]);
- }
-
- /**
- * Disable the plugin
- *
- * @param string $plugin name of plugin
- * @return bool true saving succeed, false saving failed
- */
- public function disable($plugin) {
- if(array_key_exists($plugin,$this->plugin_cascade['protected'])) return false;
- $this->tmp_plugins[$plugin] = 0;
- return $this->saveList();
- }
-
- /**
- * Enable the plugin
- *
- * @param string $plugin name of plugin
- * @return bool true saving succeed, false saving failed
- */
- public function enable($plugin) {
- if(array_key_exists($plugin,$this->plugin_cascade['protected'])) return false;
- $this->tmp_plugins[$plugin] = 1;
- return $this->saveList();
- }
-
- /**
- * Returns directory name of plugin
- *
- * @param string $plugin name of plugin
- * @return string name of directory
- */
- public function get_directory($plugin) {
- return $plugin;
- }
-
- /**
- * Returns cascade of the config files
- *
- * @return array with arrays of plugin configs
- */
- public function getCascade() {
- return $this->plugin_cascade;
- }
-
- protected function _populateMasterList() {
- global $conf;
-
- if ($dh = @opendir(DOKU_PLUGIN)) {
- $all_plugins = array();
- while (false !== ($plugin = readdir($dh))) {
- if ($plugin[0] == '.') continue; // skip hidden entries
- if (is_file(DOKU_PLUGIN.$plugin)) continue; // skip files, we're only interested in directories
-
- if (array_key_exists($plugin,$this->tmp_plugins) && $this->tmp_plugins[$plugin] == 0){
- $all_plugins[$plugin] = 0;
-
- } elseif ((array_key_exists($plugin,$this->tmp_plugins) && $this->tmp_plugins[$plugin] == 1)) {
- $all_plugins[$plugin] = 1;
- } else {
- $all_plugins[$plugin] = 1;
- }
- }
- $this->tmp_plugins = $all_plugins;
- if (!file_exists($this->last_local_config_file)) {
- $this->saveList(true);
- }
- }
- }
-
- /**
- * Includes the plugin config $files
- * and returns the entries of the $plugins array set in these files
- *
- * @param array $files list of files to include, latter overrides previous
- * @return array with entries of the $plugins arrays of the included files
- */
- protected function checkRequire($files) {
- $plugins = array();
- foreach($files as $file) {
- if(file_exists($file)) {
- include_once($file);
- }
- }
- return $plugins;
- }
-
- /**
- * Save the current list of plugins
- *
- * @param bool $forceSave;
- * false to save only when config changed
- * true to always save
- * @return bool true saving succeed, false saving failed
- */
- protected function saveList($forceSave = false) {
- global $conf;
-
- if (empty($this->tmp_plugins)) return false;
-
- // Rebuild list of local settings
- $local_plugins = $this->rebuildLocal();
- if($local_plugins != $this->plugin_cascade['local'] || $forceSave) {
- $file = $this->last_local_config_file;
- $out = "<?php\n/*\n * Local plugin enable/disable settings\n * Auto-generated through plugin/extension manager\n *\n".
- " * NOTE: Plugins will not be added to this file unless there is a need to override a default setting. Plugins are\n".
- " * enabled by default.\n */\n";
- foreach ($local_plugins as $plugin => $value) {
- $out .= "\$plugins['$plugin'] = $value;\n";
- }
- // backup current file (remove any existing backup)
- if (file_exists($file)) {
- $backup = $file.'.bak';
- if (file_exists($backup)) @unlink($backup);
- if (!@copy($file,$backup)) return false;
- if (!empty($conf['fperm'])) chmod($backup, $conf['fperm']);
- }
- //check if can open for writing, else restore
- return io_saveFile($file,$out);
- }
- return false;
- }
-
- /**
- * Rebuild the set of local plugins
- *
- * @return array array of plugins to be saved in end($config_cascade['plugins']['local'])
- */
- protected function rebuildLocal() {
- //assign to local variable to avoid overwriting
- $backup = $this->tmp_plugins;
- //Can't do anything about protected one so rule them out completely
- $local_default = array_diff_key($backup,$this->plugin_cascade['protected']);
- //Diff between local+default and default
- //gives us the ones we need to check and save
- $diffed_ones = array_diff_key($local_default,$this->plugin_cascade['default']);
- //The ones which we are sure of (list of 0s not in default)
- $sure_plugins = array_filter($diffed_ones,array($this,'negate'));
- //the ones in need of diff
- $conflicts = array_diff_key($local_default,$diffed_ones);
- //The final list
- return array_merge($sure_plugins,array_diff_assoc($conflicts,$this->plugin_cascade['default']));
- }
-
- /**
- * Build the list of plugins and cascade
- *
- */
- protected function loadConfig() {
- global $config_cascade;
- foreach(array('default','protected') as $type) {
- if(array_key_exists($type,$config_cascade['plugins']))
- $this->plugin_cascade[$type] = $this->checkRequire($config_cascade['plugins'][$type]);
- }
- $local = $config_cascade['plugins']['local'];
- $this->last_local_config_file = array_pop($local);
- $this->plugin_cascade['local'] = $this->checkRequire(array($this->last_local_config_file));
- if(is_array($local)) {
- $this->plugin_cascade['default'] = array_merge($this->plugin_cascade['default'],$this->checkRequire($local));
- }
- $this->tmp_plugins = array_merge($this->plugin_cascade['default'],$this->plugin_cascade['local'],$this->plugin_cascade['protected']);
- }
-
- /**
- * Returns a list of available plugin components of given type
- *
- * @param string $type plugin_type name; the type of plugin to return,
- * @param bool $enabled true to return enabled plugins,
- * false to return disabled plugins
- * @return array of plugin components of requested type
- */
- protected function _getListByType($type, $enabled) {
- $master_list = $enabled ? array_keys(array_filter($this->tmp_plugins)) : array_keys(array_filter($this->tmp_plugins,array($this,'negate')));
- $plugins = array();
-
- foreach ($master_list as $plugin) {
-
- $basedir = $this->get_directory($plugin);
- if (file_exists(DOKU_PLUGIN."$basedir/$type.php")){
- $plugins[] = $plugin;
- continue;
- }
-
- $typedir = DOKU_PLUGIN."$basedir/$type/";
- if (is_dir($typedir)) {
- if ($dp = opendir($typedir)) {
- while (false !== ($component = readdir($dp))) {
- if (substr($component,0,1) == '.' || strtolower(substr($component, -4)) != ".php") continue;
- if (is_file($typedir.$component)) {
- $plugins[] = $plugin.'_'.substr($component, 0, -4);
- }
- }
- closedir($dp);
- }
- }
-
- }//foreach
-
- return $plugins;
- }
-
- /**
- * Split name in a plugin name and a component name
- *
- * @param string $name
- * @return array with
- * - plugin name
- * - and component name when available, otherwise empty string
- */
- protected function _splitName($name) {
- if (array_search($name, array_keys($this->tmp_plugins)) === false) {
- return explode('_',$name,2);
- }
-
- return array($name,'');
- }
-
- /**
- * Returns inverse boolean value of the input
- *
- * @param mixed $input
- * @return bool inversed boolean value of input
- */
- protected function negate($input) {
- return !(bool) $input;
- }
-}
diff --git a/inc/pluginutils.php b/inc/pluginutils.php
index 0cd113b14..f1ad82fe6 100644
--- a/inc/pluginutils.php
+++ b/inc/pluginutils.php
@@ -7,8 +7,13 @@
*/
// plugin related constants
+use dokuwiki\Extension\AdminPlugin;
+use dokuwiki\Extension\PluginController;
+use dokuwiki\Extension\PluginInterface;
+
if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/');
-// note that only [a-z0-9]+ is officially supported, this is only to support plugins that don't follow these conventions, too
+// note that only [a-z0-9]+ is officially supported,
+// this is only to support plugins that don't follow these conventions, too
if(!defined('DOKU_PLUGIN_NAME_REGEX')) define('DOKU_PLUGIN_NAME_REGEX', '[a-zA-Z0-9\x7f-\xff]+');
/**
@@ -23,7 +28,7 @@ if(!defined('DOKU_PLUGIN_NAME_REGEX')) define('DOKU_PLUGIN_NAME_REGEX', '[a-zA-Z
* @return array with plugin names or plugin component names
*/
function plugin_list($type='',$all=false) {
- /** @var $plugin_controller Doku_Plugin_Controller */
+ /** @var $plugin_controller PluginController */
global $plugin_controller;
return $plugin_controller->getList($type,$all);
}
@@ -37,10 +42,10 @@ function plugin_list($type='',$all=false) {
* @param $name string name of the plugin to load
* @param $new bool true to return a new instance of the plugin, false to use an already loaded instance
* @param $disabled bool true to load even disabled plugins
- * @return DokuWiki_PluginInterface|null the plugin object or null on failure
+ * @return PluginInterface|null the plugin object or null on failure
*/
function plugin_load($type,$name,$new=false,$disabled=false) {
- /** @var $plugin_controller Doku_Plugin_Controller */
+ /** @var $plugin_controller PluginController */
global $plugin_controller;
return $plugin_controller->load($type,$name,$new,$disabled);
}
@@ -52,7 +57,7 @@ function plugin_load($type,$name,$new=false,$disabled=false) {
* @return bool true disabled, false enabled
*/
function plugin_isdisabled($plugin) {
- /** @var $plugin_controller Doku_Plugin_Controller */
+ /** @var $plugin_controller PluginController */
global $plugin_controller;
return $plugin_controller->isdisabled($plugin);
}
@@ -64,7 +69,7 @@ function plugin_isdisabled($plugin) {
* @return bool true saving succeed, false saving failed
*/
function plugin_enable($plugin) {
- /** @var $plugin_controller Doku_Plugin_Controller */
+ /** @var $plugin_controller PluginController */
global $plugin_controller;
return $plugin_controller->enable($plugin);
}
@@ -76,7 +81,7 @@ function plugin_enable($plugin) {
* @return bool true saving succeed, false saving failed
*/
function plugin_disable($plugin) {
- /** @var $plugin_controller Doku_Plugin_Controller */
+ /** @var $plugin_controller PluginController */
global $plugin_controller;
return $plugin_controller->disable($plugin);
}
@@ -86,11 +91,11 @@ function plugin_disable($plugin) {
*
* @param string $plugin name of plugin
* @return string name of directory
+ * @deprecated 2018-07-20
*/
function plugin_directory($plugin) {
- /** @var $plugin_controller Doku_Plugin_Controller */
- global $plugin_controller;
- return $plugin_controller->get_directory($plugin);
+ dbg_deprecated('$plugin directly');
+ return $plugin;
}
/**
@@ -99,7 +104,7 @@ function plugin_directory($plugin) {
* @return array with arrays of plugin configs
*/
function plugin_getcascade() {
- /** @var $plugin_controller Doku_Plugin_Controller */
+ /** @var $plugin_controller PluginController */
global $plugin_controller;
return $plugin_controller->getCascade();
}
@@ -120,7 +125,7 @@ function plugin_getRequestAdminPlugin(){
$pluginlist = plugin_list('admin');
if (in_array($page, $pluginlist)) {
// attempt to load the plugin
- /** @var $admin_plugin DokuWiki_Admin_Plugin */
+ /** @var $admin_plugin AdminPlugin */
$admin_plugin = plugin_load('admin', $page);
// verify
if ($admin_plugin && !$admin_plugin->isAccessibleByCurrentUser()) {
diff --git a/inc/search.php b/inc/search.php
index e4d9c3caf..27efc65fe 100644
--- a/inc/search.php
+++ b/inc/search.php
@@ -6,8 +6,6 @@
* @author Andreas Gohr <andi@splitbrain.org>
*/
-if(!defined('DOKU_INC')) die('meh.');
-
/**
* Recurse directory
*
@@ -20,7 +18,8 @@ if(!defined('DOKU_INC')) die('meh.');
* @param array $opts option array will be given to the Callback
* @param string $dir Current directory beyond $base
* @param int $lvl Recursion Level
- * @param mixed $sort 'natural' to use natural order sorting (default); 'date' to sort by filemtime; leave empty to skip sorting.
+ * @param mixed $sort 'natural' to use natural order sorting (default);
+ * 'date' to sort by filemtime; leave empty to skip sorting.
* @author Andreas Gohr <andi@splitbrain.org>
*/
function search(&$data,$base,$func,$opts,$dir='',$lvl=1,$sort='natural'){
@@ -212,7 +211,7 @@ function search_media(&$data,$base,$file,$type,$lvl,$opts){
return false;
}
- $info['file'] = utf8_basename($file);
+ $info['file'] = \dokuwiki\Utf8\PhpString::basename($file);
$info['size'] = filesize($base.'/'.$file);
$info['mtime'] = filemtime($base.'/'.$file);
$info['writable'] = is_writable($base.'/'.$file);
@@ -479,7 +478,8 @@ function search_universal(&$data,$base,$file,$type,$lvl,$opts){
// are we done here maybe?
if($type == 'd'){
if(empty($opts['listdirs'])) return $return;
- if(empty($opts['skipacl']) && !empty($opts['sneakyacl']) && $item['perm'] < AUTH_READ) return false; //neither list nor recurse
+ //neither list nor recurse forbidden items:
+ if(empty($opts['skipacl']) && !empty($opts['sneakyacl']) && $item['perm'] < AUTH_READ) return false;
if(!empty($opts['dirmatch']) && !preg_match('/'.$opts['dirmatch'].'/',$file)) return $return;
if(!empty($opts['nsmatch']) && !preg_match('/'.$opts['nsmatch'].'/',$item['ns'])) return $return;
}else{
@@ -497,7 +497,7 @@ function search_universal(&$data,$base,$file,$type,$lvl,$opts){
$item['open'] = $return;
if(!empty($opts['meta'])){
- $item['file'] = utf8_basename($file);
+ $item['file'] = \dokuwiki\Utf8\PhpString::basename($file);
$item['size'] = filesize($base.'/'.$file);
$item['mtime'] = filemtime($base.'/'.$file);
$item['rev'] = $item['mtime'];
diff --git a/inc/subscription.php b/inc/subscription.php
deleted file mode 100644
index 74bec656d..000000000
--- a/inc/subscription.php
+++ /dev/null
@@ -1,693 +0,0 @@
-<?php
-/**
- * Class for handling (email) subscriptions
- *
- * @author Adrian Lang <lang@cosmocode.de>
- * @author Andreas Gohr <andi@splitbrain.org>
- * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
- */
-class Subscription {
-
- /**
- * Check if subscription system is enabled
- *
- * @return bool
- */
- public function isenabled() {
- return actionOK('subscribe');
- }
-
- /**
- * Return the subscription meta file for the given ID
- *
- * @author Adrian Lang <lang@cosmocode.de>
- *
- * @param string $id The target page or namespace, specified by id; Namespaces
- * are identified by appending a colon.
- * @return string
- */
- protected function file($id) {
- $meta_fname = '.mlist';
- if((substr($id, -1, 1) === ':')) {
- $meta_froot = getNS($id);
- $meta_fname = '/'.$meta_fname;
- } else {
- $meta_froot = $id;
- }
- return metaFN((string) $meta_froot, $meta_fname);
- }
-
- /**
- * Lock subscription info
- *
- * We don't use io_lock() her because we do not wait for the lock and use a larger stale time
- *
- * @author Adrian Lang <lang@cosmocode.de>
- * @param string $id The target page or namespace, specified by id; Namespaces
- * are identified by appending a colon.
- * @return bool true, if you got a succesful lock
- */
- protected function lock($id) {
- global $conf;
-
- $lock = $conf['lockdir'].'/_subscr_'.md5($id).'.lock';
-
- if(is_dir($lock) && time() - @filemtime($lock) > 60 * 5) {
- // looks like a stale lock - remove it
- @rmdir($lock);
- }
-
- // try creating the lock directory
- if(!@mkdir($lock, $conf['dmode'])) {
- return false;
- }
-
- if(!empty($conf['dperm'])) chmod($lock, $conf['dperm']);
- return true;
- }
-
- /**
- * Unlock subscription info
- *
- * @author Adrian Lang <lang@cosmocode.de>
- * @param string $id The target page or namespace, specified by id; Namespaces
- * are identified by appending a colon.
- * @return bool
- */
- protected function unlock($id) {
- global $conf;
- $lock = $conf['lockdir'].'/_subscr_'.md5($id).'.lock';
- return @rmdir($lock);
- }
-
- /**
- * Construct a regular expression for parsing a subscription definition line
- *
- * @author Andreas Gohr <andi@splitbrain.org>
- *
- * @param string|array $user
- * @param string|array $style
- * @param string|array $data
- * @return string complete regexp including delimiters
- * @throws Exception when no data is passed
- */
- protected function buildregex($user = null, $style = null, $data = null) {
- // always work with arrays
- $user = (array) $user;
- $style = (array) $style;
- $data = (array) $data;
-
- // clean
- $user = array_filter(array_map('trim', $user));
- $style = array_filter(array_map('trim', $style));
- $data = array_filter(array_map('trim', $data));
-
- // user names are encoded
- $user = array_map('auth_nameencode', $user);
-
- // quote
- $user = array_map('preg_quote_cb', $user);
- $style = array_map('preg_quote_cb', $style);
- $data = array_map('preg_quote_cb', $data);
-
- // join
- $user = join('|', $user);
- $style = join('|', $style);
- $data = join('|', $data);
-
- // any data at all?
- if($user.$style.$data === '') throw new Exception('no data passed');
-
- // replace empty values, set which ones are optional
- $sopt = '';
- $dopt = '';
- if($user === '') {
- $user = '\S+';
- }
- if($style === '') {
- $style = '\S+';
- $sopt = '?';
- }
- if($data === '') {
- $data = '\S+';
- $dopt = '?';
- }
-
- // assemble
- return "/^($user)(?:\\s+($style))$sopt(?:\\s+($data))$dopt$/";
- }
-
- /**
- * Recursively search for matching subscriptions
- *
- * This function searches all relevant subscription files for a page or
- * namespace.
- *
- * @author Adrian Lang <lang@cosmocode.de>
- *
- * @param string $page The target object’s (namespace or page) id
- * @param string|array $user
- * @param string|array $style
- * @param string|array $data
- * @return array
- */
- public function subscribers($page, $user = null, $style = null, $data = null) {
- if(!$this->isenabled()) return array();
-
- // Construct list of files which may contain relevant subscriptions.
- $files = array(':' => $this->file(':'));
- do {
- $files[$page] = $this->file($page);
- $page = getNS(rtrim($page, ':')).':';
- } while($page !== ':');
-
- $re = $this->buildregex($user, $style, $data);
-
- // Handle files.
- $result = array();
- foreach($files as $target => $file) {
- if(!file_exists($file)) continue;
-
- $lines = file($file);
- foreach($lines as $line) {
- // fix old style subscription files
- if(strpos($line, ' ') === false) $line = trim($line)." every\n";
-
- // check for matching entries
- if(!preg_match($re, $line, $m)) continue;
-
- $u = rawurldecode($m[1]); // decode the user name
- if(!isset($result[$target])) $result[$target] = array();
- $result[$target][$u] = array($m[2], $m[3]); // add to result
- }
- }
- return array_reverse($result);
- }
-
- /**
- * Adds a new subscription for the given page or namespace
- *
- * This will automatically overwrite any existent subscription for the given user on this
- * *exact* page or namespace. It will *not* modify any subscription that may exist in higher namespaces.
- *
- * @param string $id The target page or namespace, specified by id; Namespaces
- * are identified by appending a colon.
- * @param string $user
- * @param string $style
- * @param string $data
- * @throws Exception when user or style is empty
- * @return bool
- */
- public function add($id, $user, $style, $data = '') {
- if(!$this->isenabled()) return false;
-
- // delete any existing subscription
- $this->remove($id, $user);
-
- $user = auth_nameencode(trim($user));
- $style = trim($style);
- $data = trim($data);
-
- if(!$user) throw new Exception('no subscription user given');
- if(!$style) throw new Exception('no subscription style given');
- if(!$data) $data = time(); //always add current time for new subscriptions
-
- $line = "$user $style $data\n";
- $file = $this->file($id);
- return io_saveFile($file, $line, true);
- }
-
- /**
- * Removes a subscription for the given page or namespace
- *
- * This removes all subscriptions matching the given criteria on the given page or
- * namespace. It will *not* modify any subscriptions that may exist in higher
- * namespaces.
- *
- * @param string $id The target object’s (namespace or page) id
- * @param string|array $user
- * @param string|array $style
- * @param string|array $data
- * @return bool
- */
- public function remove($id, $user = null, $style = null, $data = null) {
- if(!$this->isenabled()) return false;
-
- $file = $this->file($id);
- if(!file_exists($file)) return true;
-
- $re = $this->buildregex($user, $style, $data);
- return io_deleteFromFile($file, $re, true);
- }
-
- /**
- * Get data for $INFO['subscribed']
- *
- * $INFO['subscribed'] is either false if no subscription for the current page
- * and user is in effect. Else it contains an array of arrays with the fields
- * “target”, “style”, and optionally “data”.
- *
- * @param string $id Page ID, defaults to global $ID
- * @param string $user User, defaults to $_SERVER['REMOTE_USER']
- * @return array
- * @author Adrian Lang <lang@cosmocode.de>
- */
- function user_subscription($id = '', $user = '') {
- if(!$this->isenabled()) return false;
-
- global $ID;
- /** @var Input $INPUT */
- global $INPUT;
- if(!$id) $id = $ID;
- if(!$user) $user = $INPUT->server->str('REMOTE_USER');
-
- $subs = $this->subscribers($id, $user);
- if(!count($subs)) return false;
-
- $result = array();
- foreach($subs as $target => $info) {
- $result[] = array(
- 'target' => $target,
- 'style' => $info[$user][0],
- 'data' => $info[$user][1]
- );
- }
-
- return $result;
- }
-
- /**
- * Send digest and list subscriptions
- *
- * This sends mails to all subscribers that have a subscription for namespaces above
- * the given page if the needed $conf['subscribe_time'] has passed already.
- *
- * This function is called form lib/exe/indexer.php
- *
- * @param string $page
- * @return int number of sent mails
- */
- public function send_bulk($page) {
- if(!$this->isenabled()) return 0;
-
- /** @var DokuWiki_Auth_Plugin $auth */
- global $auth;
- global $conf;
- global $USERINFO;
- /** @var Input $INPUT */
- global $INPUT;
- $count = 0;
-
- $subscriptions = $this->subscribers($page, null, array('digest', 'list'));
-
- // remember current user info
- $olduinfo = $USERINFO;
- $olduser = $INPUT->server->str('REMOTE_USER');
-
- foreach($subscriptions as $target => $users) {
- if(!$this->lock($target)) continue;
-
- foreach($users as $user => $info) {
- list($style, $lastupdate) = $info;
-
- $lastupdate = (int) $lastupdate;
- if($lastupdate + $conf['subscribe_time'] > time()) {
- // Less than the configured time period passed since last
- // update.
- continue;
- }
-
- // Work as the user to make sure ACLs apply correctly
- $USERINFO = $auth->getUserData($user);
- $INPUT->server->set('REMOTE_USER',$user);
- if($USERINFO === false) continue;
- if(!$USERINFO['mail']) continue;
-
- if(substr($target, -1, 1) === ':') {
- // subscription target is a namespace, get all changes within
- $changes = getRecentsSince($lastupdate, null, getNS($target));
- } else {
- // single page subscription, check ACL ourselves
- if(auth_quickaclcheck($target) < AUTH_READ) continue;
- $meta = p_get_metadata($target);
- $changes = array($meta['last_change']);
- }
-
- // Filter out pages only changed in small and own edits
- $change_ids = array();
- foreach($changes as $rev) {
- $n = 0;
- while(!is_null($rev) && $rev['date'] >= $lastupdate &&
- ($INPUT->server->str('REMOTE_USER') === $rev['user'] ||
- $rev['type'] === DOKU_CHANGE_TYPE_MINOR_EDIT)) {
- $pagelog = new PageChangeLog($rev['id']);
- $rev = $pagelog->getRevisions($n++, 1);
- $rev = (count($rev) > 0) ? $rev[0] : null;
- }
-
- if(!is_null($rev) && $rev['date'] >= $lastupdate) {
- // Some change was not a minor one and not by myself
- $change_ids[] = $rev['id'];
- }
- }
-
- // send it
- if($style === 'digest') {
- foreach($change_ids as $change_id) {
- $this->send_digest(
- $USERINFO['mail'], $change_id,
- $lastupdate
- );
- $count++;
- }
- } elseif($style === 'list') {
- $this->send_list($USERINFO['mail'], $change_ids, $target);
- $count++;
- }
- // TODO: Handle duplicate subscriptions.
-
- // Update notification time.
- $this->add($target, $user, $style, time());
- }
- $this->unlock($target);
- }
-
- // restore current user info
- $USERINFO = $olduinfo;
- $INPUT->server->set('REMOTE_USER',$olduser);
- return $count;
- }
-
- /**
- * Send the diff for some page change
- *
- * @param string $subscriber_mail The target mail address
- * @param string $template Mail template ('subscr_digest', 'subscr_single', 'mailtext', ...)
- * @param string $id Page for which the notification is
- * @param int|null $rev Old revision if any
- * @param string $summary Change summary if any
- * @return bool true if successfully sent
- */
- public function send_diff($subscriber_mail, $template, $id, $rev = null, $summary = '') {
- global $DIFF_INLINESTYLES;
-
- // prepare replacements (keys not set in hrep will be taken from trep)
- $trep = array(
- 'PAGE' => $id,
- 'NEWPAGE' => wl($id, '', true, '&'),
- 'SUMMARY' => $summary,
- 'SUBSCRIBE' => wl($id, array('do' => 'subscribe'), true, '&')
- );
- $hrep = array();
-
- if($rev) {
- $subject = 'changed';
- $trep['OLDPAGE'] = wl($id, "rev=$rev", true, '&');
-
- $old_content = rawWiki($id, $rev);
- $new_content = rawWiki($id);
-
- $df = new Diff(explode("\n", $old_content),
- explode("\n", $new_content));
- $dformat = new UnifiedDiffFormatter();
- $tdiff = $dformat->format($df);
-
- $DIFF_INLINESTYLES = true;
- $df = new Diff(explode("\n", $old_content),
- explode("\n", $new_content));
- $dformat = new InlineDiffFormatter();
- $hdiff = $dformat->format($df);
- $hdiff = '<table>'.$hdiff.'</table>';
- $DIFF_INLINESTYLES = false;
- } else {
- $subject = 'newpage';
- $trep['OLDPAGE'] = '---';
- $tdiff = rawWiki($id);
- $hdiff = nl2br(hsc($tdiff));
- }
-
- $trep['DIFF'] = $tdiff;
- $hrep['DIFF'] = $hdiff;
-
- $headers = array('Message-Id' => $this->getMessageID($id));
- if ($rev) {
- $headers['In-Reply-To'] = $this->getMessageID($id, $rev);
- }
-
- return $this->send(
- $subscriber_mail, $subject, $id,
- $template, $trep, $hrep, $headers
- );
- }
-
- /**
- * Send the diff for some media change
- *
- * @fixme this should embed thumbnails of images in HTML version
- *
- * @param string $subscriber_mail The target mail address
- * @param string $template Mail template ('uploadmail', ...)
- * @param string $id Media file for which the notification is
- * @param int|bool $rev Old revision if any
- */
- public function send_media_diff($subscriber_mail, $template, $id, $rev = false) {
- global $conf;
-
- $file = mediaFN($id);
- list($mime, /* $ext */) = mimetype($id);
-
- $trep = array(
- 'MIME' => $mime,
- 'MEDIA' => ml($id,'',true,'&',true),
- 'SIZE' => filesize_h(filesize($file)),
- );
-
- if ($rev && $conf['mediarevisions']) {
- $trep['OLD'] = ml($id, "rev=$rev", true, '&', true);
- } else {
- $trep['OLD'] = '---';
- }
-
- $headers = array('Message-Id' => $this->getMessageID($id, @filemtime($file)));
- if ($rev) {
- $headers['In-Reply-To'] = $this->getMessageID($id, $rev);
- }
-
- $this->send($subscriber_mail, 'upload', $id, $template, $trep, null, $headers);
-
- }
-
- /**
- * Send a notify mail on new registration
- *
- * @author Andreas Gohr <andi@splitbrain.org>
- *
- * @param string $login login name of the new user
- * @param string $fullname full name of the new user
- * @param string $email email address of the new user
- * @return bool true if a mail was sent
- */
- public function send_register($login, $fullname, $email) {
- global $conf;
- if(empty($conf['registernotify'])) return false;
-
- $trep = array(
- 'NEWUSER' => $login,
- 'NEWNAME' => $fullname,
- 'NEWEMAIL' => $email,
- );
-
- return $this->send(
- $conf['registernotify'],
- 'new_user',
- $login,
- 'registermail',
- $trep
- );
- }
-
- /**
- * Send a digest mail
- *
- * Sends a digest mail showing a bunch of changes of a single page. Basically the same as send_diff()
- * but determines the last known revision first
- *
- * @author Adrian Lang <lang@cosmocode.de>
- *
- * @param string $subscriber_mail The target mail address
- * @param string $id The ID
- * @param int $lastupdate Time of the last notification
- * @return bool
- */
- protected function send_digest($subscriber_mail, $id, $lastupdate) {
- $pagelog = new PageChangeLog($id);
- $n = 0;
- do {
- $rev = $pagelog->getRevisions($n++, 1);
- $rev = (count($rev) > 0) ? $rev[0] : null;
- } while(!is_null($rev) && $rev > $lastupdate);
-
- return $this->send_diff(
- $subscriber_mail,
- 'subscr_digest',
- $id, $rev
- );
- }
-
- /**
- * Send a list mail
- *
- * Sends a list mail showing a list of changed pages.
- *
- * @author Adrian Lang <lang@cosmocode.de>
- *
- * @param string $subscriber_mail The target mail address
- * @param array $ids Array of ids
- * @param string $ns_id The id of the namespace
- * @return bool true if a mail was sent
- */
- protected function send_list($subscriber_mail, $ids, $ns_id) {
- if(count($ids) === 0) return false;
-
- $tlist = '';
- $hlist = '<ul>';
- foreach($ids as $id) {
- $link = wl($id, array(), true);
- $tlist .= '* '.$link.NL;
- $hlist .= '<li><a href="'.$link.'">'.hsc($id).'</a></li>'.NL;
- }
- $hlist .= '</ul>';
-
- $id = prettyprint_id($ns_id);
- $trep = array(
- 'DIFF' => rtrim($tlist),
- 'PAGE' => $id,
- 'SUBSCRIBE' => wl($id, array('do' => 'subscribe'), true, '&')
- );
- $hrep = array(
- 'DIFF' => $hlist
- );
-
- return $this->send(
- $subscriber_mail,
- 'subscribe_list',
- $ns_id,
- 'subscr_list', $trep, $hrep
- );
- }
-
- /**
- * Helper function for sending a mail
- *
- * @author Adrian Lang <lang@cosmocode.de>
- *
- * @param string $subscriber_mail The target mail address
- * @param string $subject The lang id of the mail subject (without the
- * prefix “mail_”)
- * @param string $context The context of this mail, eg. page or namespace id
- * @param string $template The name of the mail template
- * @param array $trep Predefined parameters used to parse the
- * template (in text format)
- * @param array $hrep Predefined parameters used to parse the
- * template (in HTML format), null to default to $trep
- * @param array $headers Additional mail headers in the form 'name' => 'value'
- * @return bool
- */
- protected function send($subscriber_mail, $subject, $context, $template, $trep, $hrep = null, $headers = array()) {
- global $lang;
- global $conf;
-
- $text = rawLocale($template);
- $subject = $lang['mail_'.$subject].' '.$context;
- $mail = new Mailer();
- $mail->bcc($subscriber_mail);
- $mail->subject($subject);
- $mail->setBody($text, $trep, $hrep);
- if(in_array($template, array('subscr_list', 'subscr_digest'))){
- $mail->from($conf['mailfromnobody']);
- }
- if(isset($trep['SUBSCRIBE'])) {
- $mail->setHeader('List-Unsubscribe', '<'.$trep['SUBSCRIBE'].'>', false);
- }
-
- foreach ($headers as $header => $value) {
- $mail->setHeader($header, $value);
- }
-
- return $mail->send();
- }
-
- /**
- * Get a valid message id for a certain $id and revision (or the current revision)
- *
- * @param string $id The id of the page (or media file) the message id should be for
- * @param string $rev The revision of the page, set to the current revision of the page $id if not set
- * @return string
- */
- protected function getMessageID($id, $rev = null) {
- static $listid = null;
- if (is_null($listid)) {
- $server = parse_url(DOKU_URL, PHP_URL_HOST);
- $listid = join('.', array_reverse(explode('/', DOKU_BASE))).$server;
- $listid = urlencode($listid);
- $listid = strtolower(trim($listid, '.'));
- }
-
- if (is_null($rev)) {
- $rev = @filemtime(wikiFN($id));
- }
-
- return "<$id?rev=$rev@$listid>";
- }
-
- /**
- * Default callback for COMMON_NOTIFY_ADDRESSLIST
- *
- * Aggregates all email addresses of user who have subscribed the given page with 'every' style
- *
- * @author Steven Danz <steven-danz@kc.rr.com>
- * @author Adrian Lang <lang@cosmocode.de>
- *
- * @todo move the whole functionality into this class, trigger SUBSCRIPTION_NOTIFY_ADDRESSLIST instead,
- * use an array for the addresses within it
- *
- * @param array &$data Containing the entries:
- * - $id (the page id),
- * - $self (whether the author should be notified,
- * - $addresslist (current email address list)
- * - $replacements (array of additional string substitutions, @KEY@ to be replaced by value)
- */
- public function notifyaddresses(&$data) {
- if(!$this->isenabled()) return;
-
- /** @var DokuWiki_Auth_Plugin $auth */
- global $auth;
- global $conf;
- /** @var Input $INPUT */
- global $INPUT;
-
- $id = $data['id'];
- $self = $data['self'];
- $addresslist = $data['addresslist'];
-
- $subscriptions = $this->subscribers($id, null, 'every');
-
- $result = array();
- foreach($subscriptions as $target => $users) {
- foreach($users as $user => $info) {
- $userinfo = $auth->getUserData($user);
- if($userinfo === false) continue;
- if(!$userinfo['mail']) continue;
- if(!$self && $user == $INPUT->server->str('REMOTE_USER')) continue; //skip our own changes
-
- $level = auth_aclcheck($id, $user, $userinfo['grps']);
- if($level >= AUTH_READ) {
- if(strcasecmp($userinfo['mail'], $conf['notify']) != 0) { //skip user who get notified elsewhere
- $result[$user] = $userinfo['mail'];
- }
- }
- }
- }
- $data['addresslist'] = trim($addresslist.','.implode(',', $result), ',');
- }
-}
diff --git a/inc/template.php b/inc/template.php
index c333bae2e..caec0b87b 100644
--- a/inc/template.php
+++ b/inc/template.php
@@ -6,7 +6,8 @@
* @author Andreas Gohr <andi@splitbrain.org>
*/
-if(!defined('DOKU_INC')) die('meh.');
+use dokuwiki\Extension\AdminPlugin;
+use dokuwiki\Extension\Event;
/**
* Access a template file
@@ -80,9 +81,9 @@ function tpl_content($prependTOC = true) {
$INFO['prependTOC'] = $prependTOC;
ob_start();
- trigger_event('TPL_ACT_RENDER', $ACT, 'tpl_content_core');
+ Event::createAndTrigger('TPL_ACT_RENDER', $ACT, 'tpl_content_core');
$html_output = ob_get_clean();
- trigger_event('TPL_CONTENT_DISPLAY', $html_output, 'ptln');
+ Event::createAndTrigger('TPL_CONTENT_DISPLAY', $html_output, 'ptln');
return !empty($html_output);
}
@@ -142,14 +143,14 @@ function tpl_toc($return = false) {
}
} elseif($ACT == 'admin') {
// try to load admin plugin TOC
- /** @var $plugin DokuWiki_Admin_Plugin */
+ /** @var $plugin AdminPlugin */
if ($plugin = plugin_getRequestAdminPlugin()) {
$toc = $plugin->getTOC();
$TOC = $toc; // avoid later rebuild
}
}
- trigger_event('TPL_TOC_RENDER', $toc, null, false);
+ Event::createAndTrigger('TPL_TOC_RENDER', $toc, null, false);
$html = html_TOC($toc);
if($return) return $html;
echo $html;
@@ -175,7 +176,7 @@ function tpl_admin() {
if(in_array($class, $pluginlist)) {
// attempt to load the plugin
- /** @var $plugin DokuWiki_Admin_Plugin */
+ /** @var $plugin AdminPlugin */
$plugin = plugin_load('admin', $class);
}
}
@@ -358,7 +359,7 @@ function tpl_metaheaders($alt = true) {
);
// trigger event here
- trigger_event('TPL_METAHEADER_OUTPUT', $head, '_tpl_metaheaders_action', true);
+ Event::createAndTrigger('TPL_METAHEADER_OUTPUT', $head, '_tpl_metaheaders_action', true);
return true;
}
@@ -603,7 +604,7 @@ function tpl_get_action($type) {
$unknown = true;
}
- $evt = new Doku_Event('TPL_ACTION_GET', $data);
+ $evt = new Event('TPL_ACTION_GET', $data);
if($evt->advise_before()) {
//handle unknown types
if($unknown) {
@@ -702,7 +703,7 @@ function tpl_searchform($ajax = true, $autocomplete = true) {
$searchForm->addTagClose('div');
}
$searchForm->addTagClose('div');
- trigger_event('FORM_QUICKSEARCH_OUTPUT', $searchForm);
+ Event::createAndTrigger('FORM_QUICKSEARCH_OUTPUT', $searchForm);
echo $searchForm->toHTML();
@@ -933,7 +934,7 @@ function tpl_pagetitle($id = null, $ret = false) {
case 'admin' :
$page_title = $lang['btn_admin'];
// try to get the plugin name
- /** @var $plugin DokuWiki_Admin_Plugin */
+ /** @var $plugin AdminPlugin */
if ($plugin = plugin_getRequestAdminPlugin()){
$plugin_title = $plugin->getMenuText($conf['lang']);
$page_title = $plugin_title ? $plugin_title : $plugin->getPluginName();
@@ -1138,7 +1139,7 @@ function tpl_img($maxwidth = 0, $maxheight = 0, $link = true, $params = null) {
$p['src'] = $src;
$data = array('url'=> ($link ? $url : null), 'params'=> $p);
- return trigger_event('TPL_IMG_DISPLAY', $data, '_tpl_img_action', true);
+ return Event::createAndTrigger('TPL_IMG_DISPLAY', $data, '_tpl_img_action', true);
}
/**
@@ -1343,7 +1344,7 @@ function tpl_mediaContent($fromajax = false, $sort='natural') {
// output the content pane, wrapped in an event.
if(!$fromajax) ptln('<div id="media__content">');
$data = array('do' => $do);
- $evt = new Doku_Event('MEDIAMANAGER_CONTENT_OUTPUT', $data);
+ $evt = new Event('MEDIAMANAGER_CONTENT_OUTPUT', $data);
if($evt->advise_before()) {
$do = $data['do'];
if($do == 'filesinuse') {
@@ -1422,7 +1423,11 @@ function tpl_mediaFileDetails($image, $rev) {
/** @var Input $INPUT */
global $INPUT;
- $removed = (!file_exists(mediaFN($image)) && file_exists(mediaMetaFN($image, '.changes')) && $conf['mediarevisions']);
+ $removed = (
+ !file_exists(mediaFN($image)) &&
+ file_exists(mediaMetaFN($image, '.changes')) &&
+ $conf['mediarevisions']
+ );
if(!$image || (!file_exists(mediaFN($image)) && !$removed) || $DEL) return;
if($rev && !file_exists(mediaFN($image, $rev))) $rev = false;
$ns = getNS($image);
@@ -1450,7 +1455,8 @@ function tpl_mediaFileDetails($image, $rev) {
$class = preg_replace('/[^_\-a-z0-9]+/i', '_', $ext);
$class = 'select mediafile mf_'.$class;
$attributes = $rev ? ['rev' => $rev] : [];
- $tabTitle = '<strong><a href="'.ml($image, $attributes).'" class="'.$class.'" title="'.$lang['mediaview'].'">'.$image.'</a>'.'</strong>';
+ $tabTitle = '<strong><a href="'.ml($image, $attributes).'" class="'.$class.'" title="'.$lang['mediaview'].'">'.
+ $image.'</a>'.'</strong>';
if($opened_tab === 'view' && $rev) {
printf($lang['media_viewold'], $tabTitle, dformat($rev));
} else {
@@ -1862,7 +1868,7 @@ function tpl_toolsevent($toolsname, $items, $view = 'main') {
);
$hook = 'TEMPLATE_' . strtoupper($toolsname) . '_DISPLAY';
- $evt = new Doku_Event($hook, $data);
+ $evt = new Event($hook, $data);
if($evt->advise_before()) {
foreach($evt->data['items'] as $k => $html) echo $html;
}
diff --git a/inc/toolbar.php b/inc/toolbar.php
index 7cc29e866..056221aa4 100644
--- a/inc/toolbar.php
+++ b/inc/toolbar.php
@@ -4,9 +4,7 @@
*
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
* @author Andreas Gohr <andi@splitbrain.org>
- */
-
-if(!defined('DOKU_INC')) die('meh.');
+ */use dokuwiki\Extension\Event;
/**
* Prepares and prints an JavaScript array with all toolbar buttons
@@ -20,7 +18,7 @@ function toolbar_JSdefines($varname){
$menu = array();
- $evt = new Doku_Event('TOOLBAR_DEFINE', $menu);
+ $evt = new Event('TOOLBAR_DEFINE', $menu);
if ($evt->advise_before()){
// build button array
@@ -213,7 +211,30 @@ function toolbar_JSdefines($varname){
'type' => 'picker',
'title' => $lang['qb_chars'],
'icon' => 'chars.png',
- 'list' => explode(' ','À à Á á  â à ã Ä ä Ǎ ǎ Ă ă Å å Ā ā Ą ą Æ æ Ć ć Ç ç Č č Ĉ ĉ Ċ ċ Ð đ ð Ď ď È è É é Ê ê Ë ë Ě ě Ē ē Ė ė Ę ę Ģ ģ Ĝ ĝ Ğ ğ Ġ ġ Ĥ ĥ Ì ì Í í Î î Ï ï Ǐ ǐ Ī ī İ ı Į į Ĵ ĵ Ķ ķ Ĺ ĺ Ļ ļ Ľ ľ Ł ł Ŀ ŀ Ń ń Ñ ñ Ņ ņ Ň ň Ò ò Ó ó Ô ô Õ õ Ö ö Ǒ ǒ Ō ō Ő ő Œ œ Ø ø Ŕ ŕ Ŗ ŗ Ř ř Ś ś Ş ş Š š Ŝ ŝ Ţ ţ Ť ť Ù ù Ú ú Û û Ü ü Ǔ ǔ Ŭ ŭ Ū ū Ů ů ǖ ǘ ǚ ǜ Ų ų Ű ű Ŵ ŵ Ý ý Ÿ ÿ Ŷ ŷ Ź ź Ž ž Ż ż Þ þ ß Ħ ħ ¿ ¡ ¢ £ ¤ ¥ € ¦ § ª ¬ ¯ ° ± ÷ ‰ ¼ ½ ¾ ¹ ² ³ µ ¶ † ‡ · • º ∀ ∂ ∃ Ə ə ∅ ∇ ∈ ∉ ∋ ∏ ∑ ‾ − ∗ × ⁄ √ ∝ ∞ ∠ ∧ ∨ ∩ ∪ ∫ ∴ ∼ ≅ ≈ ≠ ≡ ≤ ≥ ⊂ ⊃ ⊄ ⊆ ⊇ ⊕ ⊗ ⊥ ⋅ ◊ ℘ ℑ ℜ ℵ ♠ ♣ ♥ ♦ α β Γ γ Δ δ ε ζ η Θ θ ι κ Λ λ μ Ξ ξ Π π ρ Σ σ Τ τ υ Φ φ χ Ψ ψ Ω ω ★ ☆ ☎ ☚ ☛ ☜ ☝ ☞ ☟ ☹ ☺ ✔ ✘ „ “ ” ‚ ‘ ’ « » ‹ › — – … ← ↑ → ↓ ↔ ⇐ ⇑ ⇒ ⇓ ⇔ © ™ ® ′ ″ [ ] { } ~ ( ) % § $ # | @'),
+ 'list' => [
+ 'À', 'à', 'Á', 'á', 'Â', 'â', 'Ã', 'ã', 'Ä', 'ä', 'Ǎ', 'ǎ', 'Ă', 'ă', 'Å', 'å',
+ 'Ā', 'ā', 'Ą', 'ą', 'Æ', 'æ', 'Ć', 'ć', 'Ç', 'ç', 'Č', 'č', 'Ĉ', 'ĉ', 'Ċ', 'ċ',
+ 'Ð', 'đ', 'ð', 'Ď', 'ď', 'È', 'è', 'É', 'é', 'Ê', 'ê', 'Ë', 'ë', 'Ě', 'ě', 'Ē',
+ 'ē', 'Ė', 'ė', 'Ę', 'ę', 'Ģ', 'ģ', 'Ĝ', 'ĝ', 'Ğ', 'ğ', 'Ġ', 'ġ', 'Ĥ', 'ĥ', 'Ì',
+ 'ì', 'Í', 'í', 'Î', 'î', 'Ï', 'ï', 'Ǐ', 'ǐ', 'Ī', 'ī', 'İ', 'ı', 'Į', 'į', 'Ĵ',
+ 'ĵ', 'Ķ', 'ķ', 'Ĺ', 'ĺ', 'Ļ', 'ļ', 'Ľ', 'ľ', 'Ł', 'ł', 'Ŀ', 'ŀ', 'Ń', 'ń', 'Ñ',
+ 'ñ', 'Ņ', 'ņ', 'Ň', 'ň', 'Ò', 'ò', 'Ó', 'ó', 'Ô', 'ô', 'Õ', 'õ', 'Ö', 'ö', 'Ǒ',
+ 'ǒ', 'Ō', 'ō', 'Ő', 'ő', 'Œ', 'œ', 'Ø', 'ø', 'Ŕ', 'ŕ', 'Ŗ', 'ŗ', 'Ř', 'ř', 'Ś',
+ 'ś', 'Ş', 'ş', 'Š', 'š', 'Ŝ', 'ŝ', 'Ţ', 'ţ', 'Ť', 'ť', 'Ù', 'ù', 'Ú', 'ú', 'Û',
+ 'û', 'Ü', 'ü', 'Ǔ', 'ǔ', 'Ŭ', 'ŭ', 'Ū', 'ū', 'Ů', 'ů', 'ǖ', 'ǘ', 'ǚ', 'ǜ', 'Ų',
+ 'ų', 'Ű', 'ű', 'Ŵ', 'ŵ', 'Ý', 'ý', 'Ÿ', 'ÿ', 'Ŷ', 'ŷ', 'Ź', 'ź', 'Ž', 'ž', 'Ż',
+ 'ż', 'Þ', 'þ', 'ß', 'Ħ', 'ħ', '¿', '¡', '¢', '£', '¤', '¥', '€', '¦', '§', 'ª',
+ '¬', '¯', '°', '±', '÷', '‰', '¼', '½', '¾', '¹', '²', '³', 'µ', '¶', '†', '‡',
+ '·', '•', 'º', '∀', '∂', '∃', 'Ə', 'ə', '∅', '∇', '∈', '∉', '∋', '∏', '∑', '‾',
+ '−', '∗', '×', '⁄', '√', '∝', '∞', '∠', '∧', '∨', '∩', '∪', '∫', '∴', '∼', '≅',
+ '≈', '≠', '≡', '≤', '≥', '⊂', '⊃', '⊄', '⊆', '⊇', '⊕', '⊗', '⊥', '⋅', '◊', '℘',
+ 'ℑ', 'ℜ', 'ℵ', '♠', '♣', '♥', '♦', 'α', 'β', 'Γ', 'γ', 'Δ', 'δ', 'ε', 'ζ', 'η',
+ 'Θ', 'θ', 'ι', 'κ', 'Λ', 'λ', 'μ', 'Ξ', 'ξ', 'Π', 'π', 'ρ', 'Σ', 'σ', 'Τ', 'τ',
+ 'υ', 'Φ', 'φ', 'χ', 'Ψ', 'ψ', 'Ω', 'ω', '★', '☆', '☎', '☚', '☛', '☜', '☝', '☞',
+ '☟', '☹', '☺', '✔', '✘', '„', '“', '”', '‚', '‘', '’', '«', '»', '‹', '›', '—',
+ '–', '…', '←', '↑', '→', '↓', '↔', '⇐', '⇑', '⇒', '⇓', '⇔', '©', '™', '®', '′',
+ '″', '[', ']', '{', '}', '~', '(', ')', '%', '§', '$', '#', '|', '@'
+ ],
'block' => false
),
array(
@@ -229,8 +250,7 @@ function toolbar_JSdefines($varname){
unset($evt);
// use JSON to build the JavaScript array
- $json = new JSON();
- print "var $varname = ".$json->encode($menu).";\n";
+ print "var $varname = ".json_encode($menu).";\n";
}
/**
diff --git a/inc/utf8.php b/inc/utf8.php
index fe1d90d9f..1227407bf 100644
--- a/inc/utf8.php
+++ b/inc/utf8.php
@@ -2,18 +2,25 @@
/**
* UTF8 helper functions
*
- * @license LGPL 2.1 (http://www.gnu.org/copyleft/lesser.html)
+ * This file now only intitializes the UTF-8 capability detection and defines helper
+ * functions if needed. All actual code is in the \dokuwiki\Utf8 classes
+ *
* @author Andreas Gohr <andi@splitbrain.org>
*/
+use dokuwiki\Utf8\Clean;
+use dokuwiki\Utf8\Conversion;
+use dokuwiki\Utf8\PhpString;
+use dokuwiki\Utf8\Unicode;
+
/**
* check for mb_string support
*/
-if(!defined('UTF8_MBSTRING')){
- if(function_exists('mb_substr') && !defined('UTF8_NOMBSTRING')){
- define('UTF8_MBSTRING',1);
- }else{
- define('UTF8_MBSTRING',0);
+if (!defined('UTF8_MBSTRING')) {
+ if (function_exists('mb_substr') && !defined('UTF8_NOMBSTRING')) {
+ define('UTF8_MBSTRING', 1);
+ } else {
+ define('UTF8_MBSTRING', 0);
}
}
@@ -22,8 +29,8 @@ if(!defined('UTF8_MBSTRING')){
*
* Without this many of the functions below will not work, so this is a minimal requirement
*/
-if(!defined('UTF8_PREGSUPPORT')){
- define('UTF8_PREGSUPPORT', (bool) @preg_match('/^.$/u', 'ñ'));
+if (!defined('UTF8_PREGSUPPORT')) {
+ define('UTF8_PREGSUPPORT', (bool)@preg_match('/^.$/u', 'ñ'));
}
/**
@@ -31,1742 +38,247 @@ if(!defined('UTF8_PREGSUPPORT')){
*
* This is not required for the functions below, but might be needed in a UTF-8 aware application
*/
-if(!defined('UTF8_PROPERTYSUPPORT')){
- define('UTF8_PROPERTYSUPPORT', (bool) @preg_match('/^\pL$/u', 'ñ'));
+if (!defined('UTF8_PROPERTYSUPPORT')) {
+ define('UTF8_PROPERTYSUPPORT', (bool)@preg_match('/^\pL$/u', 'ñ'));
}
-if(UTF8_MBSTRING){ mb_internal_encoding('UTF-8'); }
-
-if(!function_exists('utf8_isASCII')){
- /**
- * Checks if a string contains 7bit ASCII only
- *
- * @author Andreas Haerter <andreas.haerter@dev.mail-node.com>
- *
- * @param string $str
- * @return bool
- */
- function utf8_isASCII($str){
- return (preg_match('/(?:[^\x00-\x7F])/', $str) !== 1);
- }
-}
-
-if(!function_exists('utf8_strip')){
- /**
- * Strips all highbyte chars
- *
- * Returns a pure ASCII7 string
- *
- * @author Andreas Gohr <andi@splitbrain.org>
- *
- * @param string $str
- * @return string
- */
- function utf8_strip($str){
- $ascii = '';
- $len = strlen($str);
- for($i=0; $i<$len; $i++){
- if(ord($str{$i}) <128){
- $ascii .= $str{$i};
- }
- }
- return $ascii;
- }
+if (UTF8_MBSTRING) {
+ mb_internal_encoding('UTF-8');
}
-if(!function_exists('utf8_check')){
- /**
- * Tries to detect if a string is in Unicode encoding
- *
- * @author <bmorel@ssi.fr>
- * @link http://php.net/manual/en/function.utf8-encode.php
- *
- * @param string $Str
- * @return bool
- */
- function utf8_check($Str) {
- $len = strlen($Str);
- for ($i=0; $i<$len; $i++) {
- $b = ord($Str[$i]);
- if ($b < 0x80) continue; # 0bbbbbbb
- elseif (($b & 0xE0) == 0xC0) $n=1; # 110bbbbb
- elseif (($b & 0xF0) == 0xE0) $n=2; # 1110bbbb
- elseif (($b & 0xF8) == 0xF0) $n=3; # 11110bbb
- elseif (($b & 0xFC) == 0xF8) $n=4; # 111110bb
- elseif (($b & 0xFE) == 0xFC) $n=5; # 1111110b
- else return false; # Does not match any model
- for ($j=0; $j<$n; $j++) { # n bytes matching 10bbbbbb follow ?
- if ((++$i == $len) || ((ord($Str[$i]) & 0xC0) != 0x80))
- return false;
- }
- }
- return true;
+if (!function_exists('utf8_isASCII')) {
+ /** @deprecated 2019-06-09 */
+ function utf8_isASCII($str)
+ {
+ dbg_deprecated(Clean::class . '::isASCII()');
+ return Clean::isASCII($str);
}
}
-if(!function_exists('utf8_basename')){
- /**
- * A locale independent basename() implementation
- *
- * works around a bug in PHP's basename() implementation
- *
- * @see basename()
- * @link https://bugs.php.net/bug.php?id=37738
- *
- * @param string $path A path
- * @param string $suffix If the name component ends in suffix this will also be cut off
- * @return string
- */
- function utf8_basename($path, $suffix=''){
- $path = trim($path,'\\/');
- $rpos = max(strrpos($path, '/'), strrpos($path, '\\'));
- if($rpos) $path = substr($path, $rpos+1);
-
- $suflen = strlen($suffix);
- if($suflen && (substr($path, -$suflen) == $suffix)){
- $path = substr($path, 0, -$suflen);
- }
- return $path;
+if (!function_exists('utf8_strip')) {
+ /** @deprecated 2019-06-09 */
+ function utf8_strip($str)
+ {
+ dbg_deprecated(Clean::class . '::strip()');
+ return Clean::strip($str);
}
}
-if(!function_exists('utf8_strlen')){
- /**
- * Unicode aware replacement for strlen()
- *
- * utf8_decode() converts characters that are not in ISO-8859-1
- * to '?', which, for the purpose of counting, is alright - It's
- * even faster than mb_strlen.
- *
- * @author <chernyshevsky at hotmail dot com>
- * @see strlen()
- * @see utf8_decode()
- *
- * @param string $string
- * @return int
- */
- function utf8_strlen($string) {
- if (function_exists('utf8_decode')) {
- return strlen(utf8_decode($string));
- } elseif (UTF8_MBSTRING) {
- return mb_strlen($string, 'UTF-8');
- } elseif (function_exists('iconv_strlen')) {
- return iconv_strlen($string, 'UTF-8');
- } else {
- return strlen($string);
- }
+if (!function_exists('utf8_check')) {
+ /** @deprecated 2019-06-09 */
+ function utf8_check($str)
+ {
+ dbg_deprecated(Clean::class . '::isUtf8()');
+ return Clean::isUtf8($str);
}
}
-if(!function_exists('utf8_substr')){
- /**
- * UTF-8 aware alternative to substr
- *
- * Return part of a string given character offset (and optionally length)
- *
- * @author Harry Fuecks <hfuecks@gmail.com>
- * @author Chris Smith <chris@jalakai.co.uk>
- *
- * @param string $str
- * @param int $offset number of UTF-8 characters offset (from left)
- * @param int $length (optional) length in UTF-8 characters from offset
- * @return string
- */
- function utf8_substr($str, $offset, $length = null) {
- if(UTF8_MBSTRING){
- if( $length === null ){
- return mb_substr($str, $offset);
- }else{
- return mb_substr($str, $offset, $length);
- }
- }
-
- /*
- * Notes:
- *
- * no mb string support, so we'll use pcre regex's with 'u' flag
- * pcre only supports repetitions of less than 65536, in order to accept up to MAXINT values for
- * offset and length, we'll repeat a group of 65535 characters when needed (ok, up to MAXINT-65536)
- *
- * substr documentation states false can be returned in some cases (e.g. offset > string length)
- * mb_substr never returns false, it will return an empty string instead.
- *
- * calculating the number of characters in the string is a relatively expensive operation, so
- * we only carry it out when necessary. It isn't necessary for +ve offsets and no specified length
- */
-
- // cast parameters to appropriate types to avoid multiple notices/warnings
- $str = (string)$str; // generates E_NOTICE for PHP4 objects, but not PHP5 objects
- $offset = (int)$offset;
- if (!is_null($length)) $length = (int)$length;
-
- // handle trivial cases
- if ($length === 0) return '';
- if ($offset < 0 && $length < 0 && $length < $offset) return '';
-
- $offset_pattern = '';
- $length_pattern = '';
-
- // normalise -ve offsets (we could use a tail anchored pattern, but they are horribly slow!)
- if ($offset < 0) {
- $strlen = utf8_strlen($str); // see notes
- $offset = $strlen + $offset;
- if ($offset < 0) $offset = 0;
- }
-
- // establish a pattern for offset, a non-captured group equal in length to offset
- if ($offset > 0) {
- $Ox = (int)($offset/65535);
- $Oy = $offset%65535;
-
- if ($Ox) $offset_pattern = '(?:.{65535}){'.$Ox.'}';
- $offset_pattern = '^(?:'.$offset_pattern.'.{'.$Oy.'})';
- } else {
- $offset_pattern = '^'; // offset == 0; just anchor the pattern
- }
-
- // establish a pattern for length
- if (is_null($length)) {
- $length_pattern = '(.*)$'; // the rest of the string
- } else {
-
- if (!isset($strlen)) $strlen = utf8_strlen($str); // see notes
- if ($offset > $strlen) return ''; // another trivial case
-
- if ($length > 0) {
-
- $length = min($strlen-$offset, $length); // reduce any length that would go passed the end of the string
-
- $Lx = (int)($length/65535);
- $Ly = $length%65535;
-
- // +ve length requires ... a captured group of length characters
- if ($Lx) $length_pattern = '(?:.{65535}){'.$Lx.'}';
- $length_pattern = '('.$length_pattern.'.{'.$Ly.'})';
-
- } else if ($length < 0) {
-
- if ($length < ($offset - $strlen)) return '';
-
- $Lx = (int)((-$length)/65535);
- $Ly = (-$length)%65535;
-
- // -ve length requires ... capture everything except a group of -length characters
- // anchored at the tail-end of the string
- if ($Lx) $length_pattern = '(?:.{65535}){'.$Lx.'}';
- $length_pattern = '(.*)(?:'.$length_pattern.'.{'.$Ly.'})$';
- }
- }
-
- if (!preg_match('#'.$offset_pattern.$length_pattern.'#us',$str,$match)) return '';
- return $match[1];
+if (!function_exists('utf8_basename')) {
+ /** @deprecated 2019-06-09 */
+ function utf8_basename($path, $suffix = '')
+ {
+ dbg_deprecated(PhpString::class . '::basename()');
+ return PhpString::basename($path, $suffix);
}
}
-if(!function_exists('utf8_substr_replace')){
- /**
- * Unicode aware replacement for substr_replace()
- *
- * @author Andreas Gohr <andi@splitbrain.org>
- * @see substr_replace()
- *
- * @param string $string input string
- * @param string $replacement the replacement
- * @param int $start the replacing will begin at the start'th offset into string.
- * @param int $length If given and is positive, it represents the length of the portion of string which is
- * to be replaced. If length is zero then this function will have the effect of inserting
- * replacement into string at the given start offset.
- * @return string
- */
- function utf8_substr_replace($string, $replacement, $start , $length=0 ){
- $ret = '';
- if($start>0) $ret .= utf8_substr($string, 0, $start);
- $ret .= $replacement;
- $ret .= utf8_substr($string, $start+$length);
- return $ret;
+if (!function_exists('utf8_strlen')) {
+ /** @deprecated 2019-06-09 */
+ function utf8_strlen($str)
+ {
+ dbg_deprecated(PhpString::class . '::strlen()');
+ return PhpString::strlen($str);
}
}
-if(!function_exists('utf8_ltrim')){
- /**
- * Unicode aware replacement for ltrim()
- *
- * @author Andreas Gohr <andi@splitbrain.org>
- * @see ltrim()
- *
- * @param string $str
- * @param string $charlist
- * @return string
- */
- function utf8_ltrim($str,$charlist=''){
- if($charlist == '') return ltrim($str);
-
- //quote charlist for use in a characterclass
- $charlist = preg_replace('!([\\\\\\-\\]\\[/])!','\\\${1}',$charlist);
-
- return preg_replace('/^['.$charlist.']+/u','',$str);
+if (!function_exists('utf8_substr')) {
+ /** @deprecated 2019-06-09 */
+ function utf8_substr($str, $offset, $length = null)
+ {
+ dbg_deprecated(PhpString::class . '::substr()');
+ return PhpString::substr($str, $offset, $length);
}
}
-if(!function_exists('utf8_rtrim')){
- /**
- * Unicode aware replacement for rtrim()
- *
- * @author Andreas Gohr <andi@splitbrain.org>
- * @see rtrim()
- *
- * @param string $str
- * @param string $charlist
- * @return string
- */
- function utf8_rtrim($str,$charlist=''){
- if($charlist == '') return rtrim($str);
-
- //quote charlist for use in a characterclass
- $charlist = preg_replace('!([\\\\\\-\\]\\[/])!','\\\${1}',$charlist);
-
- return preg_replace('/['.$charlist.']+$/u','',$str);
+if (!function_exists('utf8_substr_replace')) {
+ /** @deprecated 2019-06-09 */
+ function utf8_substr_replace($string, $replacement, $start, $length = 0)
+ {
+ dbg_deprecated(PhpString::class . '::substr_replace()');
+ return PhpString::substr_replace($string, $replacement, $start, $length);
}
}
-if(!function_exists('utf8_trim')){
- /**
- * Unicode aware replacement for trim()
- *
- * @author Andreas Gohr <andi@splitbrain.org>
- * @see trim()
- *
- * @param string $str
- * @param string $charlist
- * @return string
- */
- function utf8_trim($str,$charlist='') {
- if($charlist == '') return trim($str);
-
- return utf8_ltrim(utf8_rtrim($str,$charlist),$charlist);
+if (!function_exists('utf8_ltrim')) {
+ /** @deprecated 2019-06-09 */
+ function utf8_ltrim($str, $charlist = '')
+ {
+ dbg_deprecated(PhpString::class . '::ltrim()');
+ return PhpString::ltrim($str, $charlist);
}
}
-if(!function_exists('utf8_strtolower')){
- /**
- * This is a unicode aware replacement for strtolower()
- *
- * Uses mb_string extension if available
- *
- * @author Leo Feyer <leo@typolight.org>
- * @see strtolower()
- * @see utf8_strtoupper()
- *
- * @param string $string
- * @return string
- */
- function utf8_strtolower($string){
- if(UTF8_MBSTRING) {
- if (class_exists("Normalizer", $autoload = false))
- return normalizer::normalize(mb_strtolower($string,'utf-8'));
- else
- return (mb_strtolower($string,'utf-8'));
- }
- global $UTF8_UPPER_TO_LOWER;
- return strtr($string,$UTF8_UPPER_TO_LOWER);
+if (!function_exists('utf8_rtrim')) {
+ /** @deprecated 2019-06-09 */
+ function utf8_rtrim($str, $charlist = '')
+ {
+ dbg_deprecated(PhpString::class . '::rtrim()');
+ return PhpString::rtrim($str, $charlist);
}
}
-if(!function_exists('utf8_strtoupper')){
- /**
- * This is a unicode aware replacement for strtoupper()
- *
- * Uses mb_string extension if available
- *
- * @author Leo Feyer <leo@typolight.org>
- * @see strtoupper()
- * @see utf8_strtoupper()
- *
- * @param string $string
- * @return string
- */
- function utf8_strtoupper($string){
- if(UTF8_MBSTRING) return mb_strtoupper($string,'utf-8');
-
- global $UTF8_LOWER_TO_UPPER;
- return strtr($string,$UTF8_LOWER_TO_UPPER);
+if (!function_exists('utf8_trim')) {
+ /** @deprecated 2019-06-09 */
+ function utf8_trim($str, $charlist = '')
+ {
+ dbg_deprecated(PhpString::class . '::trim()');
+ return PhpString::trim($str, $charlist);
}
}
-if(!function_exists('utf8_ucfirst')){
- /**
- * UTF-8 aware alternative to ucfirst
- * Make a string's first character uppercase
- *
- * @author Harry Fuecks
- *
- * @param string $str
- * @return string with first character as upper case (if applicable)
- */
- function utf8_ucfirst($str){
- switch ( utf8_strlen($str) ) {
- case 0:
- return '';
- case 1:
- return utf8_strtoupper($str);
- default:
- preg_match('/^(.{1})(.*)$/us', $str, $matches);
- return utf8_strtoupper($matches[1]).$matches[2];
- }
+if (!function_exists('utf8_strtolower')) {
+ /** @deprecated 2019-06-09 */
+ function utf8_strtolower($str)
+ {
+ dbg_deprecated(PhpString::class . '::strtolower()');
+ return PhpString::strtolower($str);
}
}
-if(!function_exists('utf8_ucwords')){
- /**
- * UTF-8 aware alternative to ucwords
- * Uppercase the first character of each word in a string
- *
- * @author Harry Fuecks
- * @see http://php.net/ucwords
- *
- * @param string $str
- * @return string with first char of each word uppercase
- */
- function utf8_ucwords($str) {
- // Note: [\x0c\x09\x0b\x0a\x0d\x20] matches;
- // form feeds, horizontal tabs, vertical tabs, linefeeds and carriage returns
- // This corresponds to the definition of a "word" defined at http://php.net/ucwords
- $pattern = '/(^|([\x0c\x09\x0b\x0a\x0d\x20]+))([^\x0c\x09\x0b\x0a\x0d\x20]{1})[^\x0c\x09\x0b\x0a\x0d\x20]*/u';
-
- return preg_replace_callback($pattern, 'utf8_ucwords_callback',$str);
- }
-
- /**
- * Callback function for preg_replace_callback call in utf8_ucwords
- * You don't need to call this yourself
- *
- * @author Harry Fuecks
- * @see utf8_ucwords
- * @see utf8_strtoupper
- *
- * @param array $matches matches corresponding to a single word
- * @return string with first char of the word in uppercase
- */
- function utf8_ucwords_callback($matches) {
- $leadingws = $matches[2];
- $ucfirst = utf8_strtoupper($matches[3]);
- $ucword = utf8_substr_replace(ltrim($matches[0]),$ucfirst,0,1);
- return $leadingws . $ucword;
+if (!function_exists('utf8_strtoupper')) {
+ /** @deprecated 2019-06-09 */
+ function utf8_strtoupper($str)
+ {
+ dbg_deprecated(PhpString::class . '::strtoupper()');
+ return PhpString::strtoupper($str);
}
}
-if(!function_exists('utf8_deaccent')){
- /**
- * Replace accented UTF-8 characters by unaccented ASCII-7 equivalents
- *
- * Use the optional parameter to just deaccent lower ($case = -1) or upper ($case = 1)
- * letters. Default is to deaccent both cases ($case = 0)
- *
- * @author Andreas Gohr <andi@splitbrain.org>
- *
- * @param string $string
- * @param int $case
- * @return string
- */
- function utf8_deaccent($string,$case=0){
- if($case <= 0){
- global $UTF8_LOWER_ACCENTS;
- $string = strtr($string,$UTF8_LOWER_ACCENTS);
- }
- if($case >= 0){
- global $UTF8_UPPER_ACCENTS;
- $string = strtr($string,$UTF8_UPPER_ACCENTS);
- }
- return $string;
+if (!function_exists('utf8_ucfirst')) {
+ /** @deprecated 2019-06-09 */
+ function utf8_ucfirst($str)
+ {
+ dbg_deprecated(PhpString::class . '::ucfirst()');
+ return PhpString::ucfirst($str);
}
}
-if(!function_exists('utf8_romanize')){
- /**
- * Romanize a non-latin string
- *
- * @author Andreas Gohr <andi@splitbrain.org>
- *
- * @param string $string
- * @return string
- */
- function utf8_romanize($string){
- if(utf8_isASCII($string)) return $string; //nothing to do
-
- global $UTF8_ROMANIZATION;
- return strtr($string,$UTF8_ROMANIZATION);
+if (!function_exists('utf8_ucwords')) {
+ /** @deprecated 2019-06-09 */
+ function utf8_ucwords($str)
+ {
+ dbg_deprecated(PhpString::class . '::ucwords()');
+ return PhpString::ucwords($str);
}
}
-if(!function_exists('utf8_stripspecials')){
- /**
- * Removes special characters (nonalphanumeric) from a UTF-8 string
- *
- * This function adds the controlchars 0x00 to 0x19 to the array of
- * stripped chars (they are not included in $UTF8_SPECIAL_CHARS)
- *
- * @author Andreas Gohr <andi@splitbrain.org>
- *
- * @param string $string The UTF8 string to strip of special chars
- * @param string $repl Replace special with this string
- * @param string $additional Additional chars to strip (used in regexp char class)
- * @return string
- */
- function utf8_stripspecials($string,$repl='',$additional=''){
- global $UTF8_SPECIAL_CHARS2;
-
- static $specials = null;
- if(is_null($specials)){
- #$specials = preg_quote(unicode_to_utf8($UTF8_SPECIAL_CHARS), '/');
- $specials = preg_quote($UTF8_SPECIAL_CHARS2, '/');
- }
-
- return preg_replace('/['.$additional.'\x00-\x19'.$specials.']/u',$repl,$string);
+if (!function_exists('utf8_deaccent')) {
+ /** @deprecated 2019-06-09 */
+ function utf8_deaccent($str, $case = 0)
+ {
+ dbg_deprecated(Clean::class . '::deaccent()');
+ return Clean::deaccent($str, $case);
}
}
-if(!function_exists('utf8_strpos')){
- /**
- * This is an Unicode aware replacement for strpos
- *
- * @author Leo Feyer <leo@typolight.org>
- * @see strpos()
- *
- * @param string $haystack
- * @param string $needle
- * @param integer $offset
- * @return integer
- */
- function utf8_strpos($haystack, $needle, $offset=0){
- $comp = 0;
- $length = null;
-
- while (is_null($length) || $length < $offset) {
- $pos = strpos($haystack, $needle, $offset + $comp);
-
- if ($pos === false)
- return false;
-
- $length = utf8_strlen(substr($haystack, 0, $pos));
-
- if ($length < $offset)
- $comp = $pos - $length;
- }
-
- return $length;
+if (!function_exists('utf8_romanize')) {
+ /** @deprecated 2019-06-09 */
+ function utf8_romanize($str)
+ {
+ dbg_deprecated(Clean::class . '::romanize()');
+ return Clean::romanize($str);
}
}
-if(!function_exists('utf8_tohtml')){
- /**
- * Encodes UTF-8 characters to HTML entities
- *
- * @author Tom N Harris <tnharris@whoopdedo.org>
- * @author <vpribish at shopping dot com>
- * @link http://php.net/manual/en/function.utf8-decode.php
- *
- * @param string $str
- * @param bool $all Encode non-utf8 char to HTML as well
- * @return string
- */
- function utf8_tohtml($str, $all = false) {
- $ret = '';
- foreach (utf8_to_unicode($str) as $cp) {
- if ($cp < 0x80 && !$all)
- $ret .= chr($cp);
- elseif ($cp < 0x100)
- $ret .= "&#$cp;";
- else
- $ret .= '&#x'.dechex($cp).';';
- }
- return $ret;
+if (!function_exists('utf8_stripspecials')) {
+ /** @deprecated 2019-06-09 */
+ function utf8_stripspecials($str, $repl = '', $additional = '')
+ {
+ dbg_deprecated(Clean::class . '::stripspecials()');
+ return Clean::stripspecials($str, $repl, $additional);
}
}
-if(!function_exists('utf8_unhtml')){
- /**
- * Decodes HTML entities to UTF-8 characters
- *
- * Convert any &#..; entity to a codepoint,
- * The entities flag defaults to only decoding numeric entities.
- * Pass HTML_ENTITIES and named entities, including &amp; &lt; etc.
- * are handled as well. Avoids the problem that would occur if you
- * had to decode "&amp;#38;&#38;amp;#38;"
- *
- * unhtmlspecialchars(utf8_unhtml($s)) -> "&#38;&#38;"
- * utf8_unhtml(unhtmlspecialchars($s)) -> "&&amp#38;"
- * what it should be -> "&#38;&amp#38;"
- *
- * @author Tom N Harris <tnharris@whoopdedo.org>
- *
- * @param string $str UTF-8 encoded string
- * @param boolean $entities Flag controlling decoding of named entities.
- * @return string UTF-8 encoded string with numeric (and named) entities replaced.
- */
- function utf8_unhtml($str, $entities=null) {
- static $decoder = null;
- if (is_null($decoder))
- $decoder = new utf8_entity_decoder();
- if (is_null($entities))
- return preg_replace_callback('/(&#([Xx])?([0-9A-Za-z]+);)/m',
- 'utf8_decode_numeric', $str);
- else
- return preg_replace_callback('/&(#)?([Xx])?([0-9A-Za-z]+);/m',
- array(&$decoder, 'decode'), $str);
+if (!function_exists('utf8_strpos')) {
+ /** @deprecated 2019-06-09 */
+ function utf8_strpos($haystack, $needle, $offset = 0)
+ {
+ dbg_deprecated(PhpString::class . '::strpos()');
+ return PhpString::strpos($haystack, $needle, $offset);
}
}
-if(!function_exists('utf8_decode_numeric')){
- /**
- * Decodes numeric HTML entities to their correct UTF-8 characters
- *
- * @param $ent string A numeric entity
- * @return string|false
- */
- function utf8_decode_numeric($ent) {
- switch ($ent[2]) {
- case 'X':
- case 'x':
- $cp = hexdec($ent[3]);
- break;
- default:
- $cp = intval($ent[3]);
- break;
- }
- return unicode_to_utf8(array($cp));
+if (!function_exists('utf8_tohtml')) {
+ /** @deprecated 2019-06-09 */
+ function utf8_tohtml($str, $all = false)
+ {
+ dbg_deprecated(Conversion::class . '::toHtml()');
+ return Conversion::toHtml($str, $all);
}
}
-if(!class_exists('utf8_entity_decoder')){
- /**
- * Encapsulate HTML entity decoding tables
- */
- class utf8_entity_decoder {
- protected $table;
-
- /**
- * Initializes the decoding tables
- */
- function __construct() {
- $table = get_html_translation_table(HTML_ENTITIES);
- $table = array_flip($table);
- $this->table = array_map(array(&$this,'makeutf8'), $table);
- }
-
- /**
- * Wrapper around unicode_to_utf8()
- *
- * @param string $c
- * @return string|false
- */
- function makeutf8($c) {
- return unicode_to_utf8(array(ord($c)));
- }
-
- /**
- * Decodes any HTML entity to it's correct UTF-8 char equivalent
- *
- * @param string $ent An entity
- * @return string|false
- */
- function decode($ent) {
- if ($ent[1] == '#') {
- return utf8_decode_numeric($ent);
- } elseif (array_key_exists($ent[0],$this->table)) {
- return $this->table[$ent[0]];
- } else {
- return $ent[0];
- }
- }
+if (!function_exists('utf8_unhtml')) {
+ /** @deprecated 2019-06-09 */
+ function utf8_unhtml($str, $enties = false)
+ {
+ dbg_deprecated(Conversion::class . '::fromHtml()');
+ return Conversion::fromHtml($str, $enties);
}
}
-if(!function_exists('utf8_to_unicode')){
- /**
- * Takes an UTF-8 string and returns an array of ints representing the
- * Unicode characters. Astral planes are supported ie. the ints in the
- * output can be > 0xFFFF. Occurrances of the BOM are ignored. Surrogates
- * are not allowed.
- *
- * If $strict is set to true the function returns false if the input
- * string isn't a valid UTF-8 octet sequence and raises a PHP error at
- * level E_USER_WARNING
- *
- * Note: this function has been modified slightly in this library to
- * trigger errors on encountering bad bytes
- *
- * @author <hsivonen@iki.fi>
- * @author Harry Fuecks <hfuecks@gmail.com>
- * @see unicode_to_utf8
- * @link http://hsivonen.iki.fi/php-utf8/
- * @link http://sourceforge.net/projects/phputf8/
- *
- * @param string $str UTF-8 encoded string
- * @param boolean $strict Check for invalid sequences?
- * @return mixed array of unicode code points or false if UTF-8 invalid
- */
- function utf8_to_unicode($str,$strict=false) {
- $mState = 0; // cached expected number of octets after the current octet
- // until the beginning of the next UTF8 character sequence
- $mUcs4 = 0; // cached Unicode character
- $mBytes = 1; // cached expected number of octets in the current sequence
-
- $out = array();
-
- $len = strlen($str);
-
- for($i = 0; $i < $len; $i++) {
-
- $in = ord($str{$i});
-
- if ( $mState == 0) {
-
- // When mState is zero we expect either a US-ASCII character or a
- // multi-octet sequence.
- if (0 == (0x80 & ($in))) {
- // US-ASCII, pass straight through.
- $out[] = $in;
- $mBytes = 1;
-
- } else if (0xC0 == (0xE0 & ($in))) {
- // First octet of 2 octet sequence
- $mUcs4 = ($in);
- $mUcs4 = ($mUcs4 & 0x1F) << 6;
- $mState = 1;
- $mBytes = 2;
-
- } else if (0xE0 == (0xF0 & ($in))) {
- // First octet of 3 octet sequence
- $mUcs4 = ($in);
- $mUcs4 = ($mUcs4 & 0x0F) << 12;
- $mState = 2;
- $mBytes = 3;
-
- } else if (0xF0 == (0xF8 & ($in))) {
- // First octet of 4 octet sequence
- $mUcs4 = ($in);
- $mUcs4 = ($mUcs4 & 0x07) << 18;
- $mState = 3;
- $mBytes = 4;
-
- } else if (0xF8 == (0xFC & ($in))) {
- /* First octet of 5 octet sequence.
- *
- * This is illegal because the encoded codepoint must be either
- * (a) not the shortest form or
- * (b) outside the Unicode range of 0-0x10FFFF.
- * Rather than trying to resynchronize, we will carry on until the end
- * of the sequence and let the later error handling code catch it.
- */
- $mUcs4 = ($in);
- $mUcs4 = ($mUcs4 & 0x03) << 24;
- $mState = 4;
- $mBytes = 5;
-
- } else if (0xFC == (0xFE & ($in))) {
- // First octet of 6 octet sequence, see comments for 5 octet sequence.
- $mUcs4 = ($in);
- $mUcs4 = ($mUcs4 & 1) << 30;
- $mState = 5;
- $mBytes = 6;
-
- } elseif($strict) {
- /* Current octet is neither in the US-ASCII range nor a legal first
- * octet of a multi-octet sequence.
- */
- trigger_error(
- 'utf8_to_unicode: Illegal sequence identifier '.
- 'in UTF-8 at byte '.$i,
- E_USER_WARNING
- );
- return false;
-
- }
-
- } else {
-
- // When mState is non-zero, we expect a continuation of the multi-octet
- // sequence
- if (0x80 == (0xC0 & ($in))) {
-
- // Legal continuation.
- $shift = ($mState - 1) * 6;
- $tmp = $in;
- $tmp = ($tmp & 0x0000003F) << $shift;
- $mUcs4 |= $tmp;
-
- /**
- * End of the multi-octet sequence. mUcs4 now contains the final
- * Unicode codepoint to be output
- */
- if (0 == --$mState) {
-
- /*
- * Check for illegal sequences and codepoints.
- */
- // From Unicode 3.1, non-shortest form is illegal
- if (((2 == $mBytes) && ($mUcs4 < 0x0080)) ||
- ((3 == $mBytes) && ($mUcs4 < 0x0800)) ||
- ((4 == $mBytes) && ($mUcs4 < 0x10000)) ||
- (4 < $mBytes) ||
- // From Unicode 3.2, surrogate characters are illegal
- (($mUcs4 & 0xFFFFF800) == 0xD800) ||
- // Codepoints outside the Unicode range are illegal
- ($mUcs4 > 0x10FFFF)) {
-
- if($strict){
- trigger_error(
- 'utf8_to_unicode: Illegal sequence or codepoint '.
- 'in UTF-8 at byte '.$i,
- E_USER_WARNING
- );
-
- return false;
- }
-
- }
-
- if (0xFEFF != $mUcs4) {
- // BOM is legal but we don't want to output it
- $out[] = $mUcs4;
- }
-
- //initialize UTF8 cache
- $mState = 0;
- $mUcs4 = 0;
- $mBytes = 1;
- }
-
- } elseif($strict) {
- /**
- *((0xC0 & (*in) != 0x80) && (mState != 0))
- * Incomplete multi-octet sequence.
- */
- trigger_error(
- 'utf8_to_unicode: Incomplete multi-octet '.
- ' sequence in UTF-8 at byte '.$i,
- E_USER_WARNING
- );
-
- return false;
- }
- }
- }
- return $out;
+if (!function_exists('utf8_to_unicode')) {
+ /** @deprecated 2019-06-09 */
+ function utf8_to_unicode($str, $strict = false)
+ {
+ dbg_deprecated(Unicode::class . '::fromUtf8()');
+ return Unicode::fromUtf8($str, $strict);
}
}
-if(!function_exists('unicode_to_utf8')){
- /**
- * Takes an array of ints representing the Unicode characters and returns
- * a UTF-8 string. Astral planes are supported ie. the ints in the
- * input can be > 0xFFFF. Occurrances of the BOM are ignored. Surrogates
- * are not allowed.
- *
- * If $strict is set to true the function returns false if the input
- * array contains ints that represent surrogates or are outside the
- * Unicode range and raises a PHP error at level E_USER_WARNING
- *
- * Note: this function has been modified slightly in this library to use
- * output buffering to concatenate the UTF-8 string (faster) as well as
- * reference the array by it's keys
- *
- * @param array $arr of unicode code points representing a string
- * @param boolean $strict Check for invalid sequences?
- * @return string|false UTF-8 string or false if array contains invalid code points
- *
- * @author <hsivonen@iki.fi>
- * @author Harry Fuecks <hfuecks@gmail.com>
- * @see utf8_to_unicode
- * @link http://hsivonen.iki.fi/php-utf8/
- * @link http://sourceforge.net/projects/phputf8/
- */
- function unicode_to_utf8($arr,$strict=false) {
- if (!is_array($arr)) return '';
- ob_start();
-
- foreach (array_keys($arr) as $k) {
-
- if ( ($arr[$k] >= 0) && ($arr[$k] <= 0x007f) ) {
- # ASCII range (including control chars)
-
- echo chr($arr[$k]);
-
- } else if ($arr[$k] <= 0x07ff) {
- # 2 byte sequence
-
- echo chr(0xc0 | ($arr[$k] >> 6));
- echo chr(0x80 | ($arr[$k] & 0x003f));
-
- } else if($arr[$k] == 0xFEFF) {
- # Byte order mark (skip)
-
- // nop -- zap the BOM
-
- } else if ($arr[$k] >= 0xD800 && $arr[$k] <= 0xDFFF) {
- # Test for illegal surrogates
-
- // found a surrogate
- if($strict){
- trigger_error(
- 'unicode_to_utf8: Illegal surrogate '.
- 'at index: '.$k.', value: '.$arr[$k],
- E_USER_WARNING
- );
- return false;
- }
-
- } else if ($arr[$k] <= 0xffff) {
- # 3 byte sequence
-
- echo chr(0xe0 | ($arr[$k] >> 12));
- echo chr(0x80 | (($arr[$k] >> 6) & 0x003f));
- echo chr(0x80 | ($arr[$k] & 0x003f));
-
- } else if ($arr[$k] <= 0x10ffff) {
- # 4 byte sequence
-
- echo chr(0xf0 | ($arr[$k] >> 18));
- echo chr(0x80 | (($arr[$k] >> 12) & 0x3f));
- echo chr(0x80 | (($arr[$k] >> 6) & 0x3f));
- echo chr(0x80 | ($arr[$k] & 0x3f));
-
- } elseif($strict) {
-
- trigger_error(
- 'unicode_to_utf8: Codepoint out of Unicode range '.
- 'at index: '.$k.', value: '.$arr[$k],
- E_USER_WARNING
- );
-
- // out of range
- return false;
- }
- }
-
- $result = ob_get_contents();
- ob_end_clean();
- return $result;
+if (!function_exists('unicode_to_utf8')) {
+ /** @deprecated 2019-06-09 */
+ function unicode_to_utf8($arr, $strict = false)
+ {
+ dbg_deprecated(Unicode::class . '::toUtf8()');
+ return Unicode::toUtf8($arr, $strict);
}
}
-if(!function_exists('utf8_to_utf16be')){
- /**
- * UTF-8 to UTF-16BE conversion.
- *
- * Maybe really UCS-2 without mb_string due to utf8_to_unicode limits
- *
- * @param string $str
- * @param bool $bom
- * @return string
- */
- function utf8_to_utf16be(&$str, $bom = false) {
- $out = $bom ? "\xFE\xFF" : '';
- if(UTF8_MBSTRING) return $out.mb_convert_encoding($str,'UTF-16BE','UTF-8');
-
- $uni = utf8_to_unicode($str);
- foreach($uni as $cp){
- $out .= pack('n',$cp);
- }
- return $out;
+if (!function_exists('utf8_to_utf16be')) {
+ /** @deprecated 2019-06-09 */
+ function utf8_to_utf16be($str, $bom = false)
+ {
+ dbg_deprecated(Conversion::class . '::toUtf16be()');
+ return Conversion::toUtf16be($str, $bom);
}
}
-if(!function_exists('utf16be_to_utf8')){
- /**
- * UTF-8 to UTF-16BE conversion.
- *
- * Maybe really UCS-2 without mb_string due to utf8_to_unicode limits
- *
- * @param string $str
- * @return false|string
- */
- function utf16be_to_utf8(&$str) {
- $uni = unpack('n*',$str);
- return unicode_to_utf8($uni);
+if (!function_exists('utf16be_to_utf8')) {
+ /** @deprecated 2019-06-09 */
+ function utf16be_to_utf8($str)
+ {
+ dbg_deprecated(Conversion::class . '::fromUtf16be()');
+ return Conversion::fromUtf16be($str);
}
}
-if(!function_exists('utf8_bad_replace')){
- /**
- * Replace bad bytes with an alternative character
- *
- * ASCII character is recommended for replacement char
- *
- * PCRE Pattern to locate bad bytes in a UTF-8 string
- * Comes from W3 FAQ: Multilingual Forms
- * Note: modified to include full ASCII range including control chars
- *
- * @author Harry Fuecks <hfuecks@gmail.com>
- * @see http://www.w3.org/International/questions/qa-forms-utf-8
- *
- * @param string $str to search
- * @param string $replace to replace bad bytes with (defaults to '?') - use ASCII
- * @return string
- */
- function utf8_bad_replace($str, $replace = '') {
- $UTF8_BAD =
- '([\x00-\x7F]'. # ASCII (including control chars)
- '|[\xC2-\xDF][\x80-\xBF]'. # non-overlong 2-byte
- '|\xE0[\xA0-\xBF][\x80-\xBF]'. # excluding overlongs
- '|[\xE1-\xEC\xEE\xEF][\x80-\xBF]{2}'. # straight 3-byte
- '|\xED[\x80-\x9F][\x80-\xBF]'. # excluding surrogates
- '|\xF0[\x90-\xBF][\x80-\xBF]{2}'. # planes 1-3
- '|[\xF1-\xF3][\x80-\xBF]{3}'. # planes 4-15
- '|\xF4[\x80-\x8F][\x80-\xBF]{2}'. # plane 16
- '|(.{1}))'; # invalid byte
- ob_start();
- while (preg_match('/'.$UTF8_BAD.'/S', $str, $matches)) {
- if ( !isset($matches[2])) {
- echo $matches[0];
- } else {
- echo $replace;
- }
- $str = substr($str,strlen($matches[0]));
- }
- $result = ob_get_contents();
- ob_end_clean();
- return $result;
+if (!function_exists('utf8_bad_replace')) {
+ /** @deprecated 2019-06-09 */
+ function utf8_bad_replace($str, $replace = '')
+ {
+ dbg_deprecated(Clean::class . '::replaceBadBytes()');
+ return Clean::replaceBadBytes($str, $replace);
}
}
-if(!function_exists('utf8_correctIdx')){
- /**
- * adjust a byte index into a utf8 string to a utf8 character boundary
- *
- * @param string $str utf8 character string
- * @param int $i byte index into $str
- * @param $next bool direction to search for boundary,
- * false = up (current character)
- * true = down (next character)
- *
- * @return int byte index into $str now pointing to a utf8 character boundary
- *
- * @author chris smith <chris@jalakai.co.uk>
- */
- function utf8_correctIdx(&$str,$i,$next=false) {
-
- if ($i <= 0) return 0;
-
- $limit = strlen($str);
- if ($i>=$limit) return $limit;
-
- if ($next) {
- while (($i<$limit) && ((ord($str[$i]) & 0xC0) == 0x80)) $i++;
- } else {
- while ($i && ((ord($str[$i]) & 0xC0) == 0x80)) $i--;
- }
-
- return $i;
+if (!function_exists('utf8_correctIdx')) {
+ /** @deprecated 2019-06-09 */
+ function utf8_correctIdx($str, $i, $next = false)
+ {
+ dbg_deprecated(Clean::class . '::correctIdx()');
+ return Clean::correctIdx($str, $i, $next);
}
}
-
-// only needed if no mb_string available
-if(!UTF8_MBSTRING){
- /**
- * UTF-8 Case lookup table
- *
- * This lookuptable defines the upper case letters to their correspponding
- * lower case letter in UTF-8
- *
- * @author Andreas Gohr <andi@splitbrain.org>
- */
- global $UTF8_LOWER_TO_UPPER;
- if(empty($UTF8_LOWER_TO_UPPER)) $UTF8_LOWER_TO_UPPER = array(
- "z"=>"Z","y"=>"Y","x"=>"X","w"=>"W","v"=>"V","u"=>"U","t"=>"T","s"=>"S","r"=>"R","q"=>"Q",
- "p"=>"P","o"=>"O","n"=>"N","m"=>"M","l"=>"L","k"=>"K","j"=>"J","i"=>"I","h"=>"H","g"=>"G",
- "f"=>"F","e"=>"E","d"=>"D","c"=>"C","b"=>"B","a"=>"A","ῳ"=>"ῼ","ῥ"=>"Ῥ","ῡ"=>"Ῡ","ῑ"=>"Ῑ",
- "ῐ"=>"Ῐ","ῃ"=>"ῌ","ι"=>"Ι","ᾳ"=>"ᾼ","ᾱ"=>"Ᾱ","ᾰ"=>"Ᾰ","ᾧ"=>"ᾯ","ᾦ"=>"ᾮ","ᾥ"=>"ᾭ","ᾤ"=>"ᾬ",
- "ᾣ"=>"ᾫ","ᾢ"=>"ᾪ","ᾡ"=>"ᾩ","ᾗ"=>"ᾟ","ᾖ"=>"ᾞ","ᾕ"=>"ᾝ","ᾔ"=>"ᾜ","ᾓ"=>"ᾛ","ᾒ"=>"ᾚ","ᾑ"=>"ᾙ",
- "ᾐ"=>"ᾘ","ᾇ"=>"ᾏ","ᾆ"=>"ᾎ","ᾅ"=>"ᾍ","ᾄ"=>"ᾌ","ᾃ"=>"ᾋ","ᾂ"=>"ᾊ","ᾁ"=>"ᾉ","ᾀ"=>"ᾈ","ώ"=>"Ώ",
- "ὼ"=>"Ὼ","ύ"=>"Ύ","ὺ"=>"Ὺ","ό"=>"Ό","ὸ"=>"Ὸ","ί"=>"Ί","ὶ"=>"Ὶ","ή"=>"Ή","ὴ"=>"Ὴ","έ"=>"Έ",
- "ὲ"=>"Ὲ","ά"=>"Ά","ὰ"=>"Ὰ","ὧ"=>"Ὧ","ὦ"=>"Ὦ","ὥ"=>"Ὥ","ὤ"=>"Ὤ","ὣ"=>"Ὣ","ὢ"=>"Ὢ","ὡ"=>"Ὡ",
- "ὗ"=>"Ὗ","ὕ"=>"Ὕ","ὓ"=>"Ὓ","ὑ"=>"Ὑ","ὅ"=>"Ὅ","ὄ"=>"Ὄ","ὃ"=>"Ὃ","ὂ"=>"Ὂ","ὁ"=>"Ὁ","ὀ"=>"Ὀ",
- "ἷ"=>"Ἷ","ἶ"=>"Ἶ","ἵ"=>"Ἵ","ἴ"=>"Ἴ","ἳ"=>"Ἳ","ἲ"=>"Ἲ","ἱ"=>"Ἱ","ἰ"=>"Ἰ","ἧ"=>"Ἧ","ἦ"=>"Ἦ",
- "ἥ"=>"Ἥ","ἤ"=>"Ἤ","ἣ"=>"Ἣ","ἢ"=>"Ἢ","ἡ"=>"Ἡ","ἕ"=>"Ἕ","ἔ"=>"Ἔ","ἓ"=>"Ἓ","ἒ"=>"Ἒ","ἑ"=>"Ἑ",
- "ἐ"=>"Ἐ","ἇ"=>"Ἇ","ἆ"=>"Ἆ","ἅ"=>"Ἅ","ἄ"=>"Ἄ","ἃ"=>"Ἃ","ἂ"=>"Ἂ","ἁ"=>"Ἁ","ἀ"=>"Ἀ","ỹ"=>"Ỹ",
- "ỷ"=>"Ỷ","ỵ"=>"Ỵ","ỳ"=>"Ỳ","ự"=>"Ự","ữ"=>"Ữ","ử"=>"Ử","ừ"=>"Ừ","ứ"=>"Ứ","ủ"=>"Ủ","ụ"=>"Ụ",
- "ợ"=>"Ợ","ỡ"=>"Ỡ","ở"=>"Ở","ờ"=>"Ờ","ớ"=>"Ớ","ộ"=>"Ộ","ỗ"=>"Ỗ","ổ"=>"Ổ","ồ"=>"Ồ","ố"=>"Ố",
- "ỏ"=>"Ỏ","ọ"=>"Ọ","ị"=>"Ị","ỉ"=>"Ỉ","ệ"=>"Ệ","ễ"=>"Ễ","ể"=>"Ể","ề"=>"Ề","ế"=>"Ế","ẽ"=>"Ẽ",
- "ẻ"=>"Ẻ","ẹ"=>"Ẹ","ặ"=>"Ặ","ẵ"=>"Ẵ","ẳ"=>"Ẳ","ằ"=>"Ằ","ắ"=>"Ắ","ậ"=>"Ậ","ẫ"=>"Ẫ","ẩ"=>"Ẩ",
- "ầ"=>"Ầ","ấ"=>"Ấ","ả"=>"Ả","ạ"=>"Ạ","ẛ"=>"Ṡ","ẕ"=>"Ẕ","ẓ"=>"Ẓ","ẑ"=>"Ẑ","ẏ"=>"Ẏ","ẍ"=>"Ẍ",
- "ẋ"=>"Ẋ","ẉ"=>"Ẉ","ẇ"=>"Ẇ","ẅ"=>"Ẅ","ẃ"=>"Ẃ","ẁ"=>"Ẁ","ṿ"=>"Ṿ","ṽ"=>"Ṽ","ṻ"=>"Ṻ","ṹ"=>"Ṹ",
- "ṷ"=>"Ṷ","ṵ"=>"Ṵ","ṳ"=>"Ṳ","ṱ"=>"Ṱ","ṯ"=>"Ṯ","ṭ"=>"Ṭ","ṫ"=>"Ṫ","ṩ"=>"Ṩ","ṧ"=>"Ṧ","ṥ"=>"Ṥ",
- "ṣ"=>"Ṣ","ṡ"=>"Ṡ","ṟ"=>"Ṟ","ṝ"=>"Ṝ","ṛ"=>"Ṛ","ṙ"=>"Ṙ","ṗ"=>"Ṗ","ṕ"=>"Ṕ","ṓ"=>"Ṓ","ṑ"=>"Ṑ",
- "ṏ"=>"Ṏ","ṍ"=>"Ṍ","ṋ"=>"Ṋ","ṉ"=>"Ṉ","ṇ"=>"Ṇ","ṅ"=>"Ṅ","ṃ"=>"Ṃ","ṁ"=>"Ṁ","ḿ"=>"Ḿ","ḽ"=>"Ḽ",
- "ḻ"=>"Ḻ","ḹ"=>"Ḹ","ḷ"=>"Ḷ","ḵ"=>"Ḵ","ḳ"=>"Ḳ","ḱ"=>"Ḱ","ḯ"=>"Ḯ","ḭ"=>"Ḭ","ḫ"=>"Ḫ","ḩ"=>"Ḩ",
- "ḧ"=>"Ḧ","ḥ"=>"Ḥ","ḣ"=>"Ḣ","ḡ"=>"Ḡ","ḟ"=>"Ḟ","ḝ"=>"Ḝ","ḛ"=>"Ḛ","ḙ"=>"Ḙ","ḗ"=>"Ḗ","ḕ"=>"Ḕ",
- "ḓ"=>"Ḓ","ḑ"=>"Ḑ","ḏ"=>"Ḏ","ḍ"=>"Ḍ","ḋ"=>"Ḋ","ḉ"=>"Ḉ","ḇ"=>"Ḇ","ḅ"=>"Ḅ","ḃ"=>"Ḃ","ḁ"=>"Ḁ",
- "ֆ"=>"Ֆ","օ"=>"Օ","ք"=>"Ք","փ"=>"Փ","ւ"=>"Ւ","ց"=>"Ց","ր"=>"Ր","տ"=>"Տ","վ"=>"Վ","ս"=>"Ս",
- "ռ"=>"Ռ","ջ"=>"Ջ","պ"=>"Պ","չ"=>"Չ","ո"=>"Ո","շ"=>"Շ","ն"=>"Ն","յ"=>"Յ","մ"=>"Մ","ճ"=>"Ճ",
- "ղ"=>"Ղ","ձ"=>"Ձ","հ"=>"Հ","կ"=>"Կ","ծ"=>"Ծ","խ"=>"Խ","լ"=>"Լ","ի"=>"Ի","ժ"=>"Ժ","թ"=>"Թ",
- "ը"=>"Ը","է"=>"Է","զ"=>"Զ","ե"=>"Ե","դ"=>"Դ","գ"=>"Գ","բ"=>"Բ","ա"=>"Ա","ԏ"=>"Ԏ","ԍ"=>"Ԍ",
- "ԋ"=>"Ԋ","ԉ"=>"Ԉ","ԇ"=>"Ԇ","ԅ"=>"Ԅ","ԃ"=>"Ԃ","ԁ"=>"Ԁ","ӹ"=>"Ӹ","ӵ"=>"Ӵ","ӳ"=>"Ӳ","ӱ"=>"Ӱ",
- "ӯ"=>"Ӯ","ӭ"=>"Ӭ","ӫ"=>"Ӫ","ө"=>"Ө","ӧ"=>"Ӧ","ӥ"=>"Ӥ","ӣ"=>"Ӣ","ӡ"=>"Ӡ","ӟ"=>"Ӟ","ӝ"=>"Ӝ",
- "ӛ"=>"Ӛ","ә"=>"Ә","ӗ"=>"Ӗ","ӕ"=>"Ӕ","ӓ"=>"Ӓ","ӑ"=>"Ӑ","ӎ"=>"Ӎ","ӌ"=>"Ӌ","ӊ"=>"Ӊ","ӈ"=>"Ӈ",
- "ӆ"=>"Ӆ","ӄ"=>"Ӄ","ӂ"=>"Ӂ","ҿ"=>"Ҿ","ҽ"=>"Ҽ","һ"=>"Һ","ҹ"=>"Ҹ","ҷ"=>"Ҷ","ҵ"=>"Ҵ","ҳ"=>"Ҳ",
- "ұ"=>"Ұ","ү"=>"Ү","ҭ"=>"Ҭ","ҫ"=>"Ҫ","ҩ"=>"Ҩ","ҧ"=>"Ҧ","ҥ"=>"Ҥ","ң"=>"Ң","ҡ"=>"Ҡ","ҟ"=>"Ҟ",
- "ҝ"=>"Ҝ","қ"=>"Қ","ҙ"=>"Ҙ","җ"=>"Җ","ҕ"=>"Ҕ","ғ"=>"Ғ","ґ"=>"Ґ","ҏ"=>"Ҏ","ҍ"=>"Ҍ","ҋ"=>"Ҋ",
- "ҁ"=>"Ҁ","ѿ"=>"Ѿ","ѽ"=>"Ѽ","ѻ"=>"Ѻ","ѹ"=>"Ѹ","ѷ"=>"Ѷ","ѵ"=>"Ѵ","ѳ"=>"Ѳ","ѱ"=>"Ѱ","ѯ"=>"Ѯ",
- "ѭ"=>"Ѭ","ѫ"=>"Ѫ","ѩ"=>"Ѩ","ѧ"=>"Ѧ","ѥ"=>"Ѥ","ѣ"=>"Ѣ","ѡ"=>"Ѡ","џ"=>"Џ","ў"=>"Ў","ѝ"=>"Ѝ",
- "ќ"=>"Ќ","ћ"=>"Ћ","њ"=>"Њ","љ"=>"Љ","ј"=>"Ј","ї"=>"Ї","і"=>"І","ѕ"=>"Ѕ","є"=>"Є","ѓ"=>"Ѓ",
- "ђ"=>"Ђ","ё"=>"Ё","ѐ"=>"Ѐ","я"=>"Я","ю"=>"Ю","э"=>"Э","ь"=>"Ь","ы"=>"Ы","ъ"=>"Ъ","щ"=>"Щ",
- "ш"=>"Ш","ч"=>"Ч","ц"=>"Ц","х"=>"Х","ф"=>"Ф","у"=>"У","т"=>"Т","с"=>"С","р"=>"Р","п"=>"П",
- "о"=>"О","н"=>"Н","м"=>"М","л"=>"Л","к"=>"К","й"=>"Й","и"=>"И","з"=>"З","ж"=>"Ж","е"=>"Е",
- "д"=>"Д","г"=>"Г","в"=>"В","б"=>"Б","а"=>"А","ϵ"=>"Ε","ϲ"=>"Σ","ϱ"=>"Ρ","ϰ"=>"Κ","ϯ"=>"Ϯ",
- "ϭ"=>"Ϭ","ϫ"=>"Ϫ","ϩ"=>"Ϩ","ϧ"=>"Ϧ","ϥ"=>"Ϥ","ϣ"=>"Ϣ","ϡ"=>"Ϡ","ϟ"=>"Ϟ","ϝ"=>"Ϝ","ϛ"=>"Ϛ",
- "ϙ"=>"Ϙ","ϖ"=>"Π","ϕ"=>"Φ","ϑ"=>"Θ","ϐ"=>"Β","ώ"=>"Ώ","ύ"=>"Ύ","ό"=>"Ό","ϋ"=>"Ϋ","ϊ"=>"Ϊ",
- "ω"=>"Ω","ψ"=>"Ψ","χ"=>"Χ","φ"=>"Φ","υ"=>"Υ","τ"=>"Τ","σ"=>"Σ","ς"=>"Σ","ρ"=>"Ρ","π"=>"Π",
- "ο"=>"Ο","ξ"=>"Ξ","ν"=>"Ν","μ"=>"Μ","λ"=>"Λ","κ"=>"Κ","ι"=>"Ι","θ"=>"Θ","η"=>"Η","ζ"=>"Ζ",
- "ε"=>"Ε","δ"=>"Δ","γ"=>"Γ","β"=>"Β","α"=>"Α","ί"=>"Ί","ή"=>"Ή","έ"=>"Έ","ά"=>"Ά","ʒ"=>"Ʒ",
- "ʋ"=>"Ʋ","ʊ"=>"Ʊ","ʈ"=>"Ʈ","ʃ"=>"Ʃ","ʀ"=>"Ʀ","ɵ"=>"Ɵ","ɲ"=>"Ɲ","ɯ"=>"Ɯ","ɩ"=>"Ɩ","ɨ"=>"Ɨ",
- "ɣ"=>"Ɣ","ɛ"=>"Ɛ","ə"=>"Ə","ɗ"=>"Ɗ","ɖ"=>"Ɖ","ɔ"=>"Ɔ","ɓ"=>"Ɓ","ȳ"=>"Ȳ","ȱ"=>"Ȱ","ȯ"=>"Ȯ",
- "ȭ"=>"Ȭ","ȫ"=>"Ȫ","ȩ"=>"Ȩ","ȧ"=>"Ȧ","ȥ"=>"Ȥ","ȣ"=>"Ȣ","ȟ"=>"Ȟ","ȝ"=>"Ȝ","ț"=>"Ț","ș"=>"Ș",
- "ȗ"=>"Ȗ","ȕ"=>"Ȕ","ȓ"=>"Ȓ","ȑ"=>"Ȑ","ȏ"=>"Ȏ","ȍ"=>"Ȍ","ȋ"=>"Ȋ","ȉ"=>"Ȉ","ȇ"=>"Ȇ","ȅ"=>"Ȅ",
- "ȃ"=>"Ȃ","ȁ"=>"Ȁ","ǿ"=>"Ǿ","ǽ"=>"Ǽ","ǻ"=>"Ǻ","ǹ"=>"Ǹ","ǵ"=>"Ǵ","dz"=>"Dz","ǯ"=>"Ǯ","ǭ"=>"Ǭ",
- "ǫ"=>"Ǫ","ǩ"=>"Ǩ","ǧ"=>"Ǧ","ǥ"=>"Ǥ","ǣ"=>"Ǣ","ǡ"=>"Ǡ","ǟ"=>"Ǟ","ǝ"=>"Ǝ","ǜ"=>"Ǜ","ǚ"=>"Ǚ",
- "ǘ"=>"Ǘ","ǖ"=>"Ǖ","ǔ"=>"Ǔ","ǒ"=>"Ǒ","ǐ"=>"Ǐ","ǎ"=>"Ǎ","nj"=>"Nj","lj"=>"Lj","dž"=>"Dž","ƿ"=>"Ƿ",
- "ƽ"=>"Ƽ","ƹ"=>"Ƹ","ƶ"=>"Ƶ","ƴ"=>"Ƴ","ư"=>"Ư","ƭ"=>"Ƭ","ƨ"=>"Ƨ","ƥ"=>"Ƥ","ƣ"=>"Ƣ","ơ"=>"Ơ",
- "ƞ"=>"Ƞ","ƙ"=>"Ƙ","ƕ"=>"Ƕ","ƒ"=>"Ƒ","ƌ"=>"Ƌ","ƈ"=>"Ƈ","ƅ"=>"Ƅ","ƃ"=>"Ƃ","ſ"=>"S","ž"=>"Ž",
- "ż"=>"Ż","ź"=>"Ź","ŷ"=>"Ŷ","ŵ"=>"Ŵ","ų"=>"Ų","ű"=>"Ű","ů"=>"Ů","ŭ"=>"Ŭ","ū"=>"Ū","ũ"=>"Ũ",
- "ŧ"=>"Ŧ","ť"=>"Ť","ţ"=>"Ţ","š"=>"Š","ş"=>"Ş","ŝ"=>"Ŝ","ś"=>"Ś","ř"=>"Ř","ŗ"=>"Ŗ","ŕ"=>"Ŕ",
- "œ"=>"Œ","ő"=>"Ő","ŏ"=>"Ŏ","ō"=>"Ō","ŋ"=>"Ŋ","ň"=>"Ň","ņ"=>"Ņ","ń"=>"Ń","ł"=>"Ł","ŀ"=>"Ŀ",
- "ľ"=>"Ľ","ļ"=>"Ļ","ĺ"=>"Ĺ","ķ"=>"Ķ","ĵ"=>"Ĵ","ij"=>"IJ","ı"=>"I","į"=>"Į","ĭ"=>"Ĭ","ī"=>"Ī",
- "ĩ"=>"Ĩ","ħ"=>"Ħ","ĥ"=>"Ĥ","ģ"=>"Ģ","ġ"=>"Ġ","ğ"=>"Ğ","ĝ"=>"Ĝ","ě"=>"Ě","ę"=>"Ę","ė"=>"Ė",
- "ĕ"=>"Ĕ","ē"=>"Ē","đ"=>"Đ","ď"=>"Ď","č"=>"Č","ċ"=>"Ċ","ĉ"=>"Ĉ","ć"=>"Ć","ą"=>"Ą","ă"=>"Ă",
- "ā"=>"Ā","ÿ"=>"Ÿ","þ"=>"Þ","ý"=>"Ý","ü"=>"Ü","û"=>"Û","ú"=>"Ú","ù"=>"Ù","ø"=>"Ø","ö"=>"Ö",
- "õ"=>"Õ","ô"=>"Ô","ó"=>"Ó","ò"=>"Ò","ñ"=>"Ñ","ð"=>"Ð","ï"=>"Ï","î"=>"Î","í"=>"Í","ì"=>"Ì",
- "ë"=>"Ë","ê"=>"Ê","é"=>"É","è"=>"È","ç"=>"Ç","æ"=>"Æ","å"=>"Å","ä"=>"Ä","ã"=>"Ã","â"=>"Â",
- "á"=>"Á","à"=>"À","µ"=>"Μ","z"=>"Z","y"=>"Y","x"=>"X","w"=>"W","v"=>"V","u"=>"U","t"=>"T",
- "s"=>"S","r"=>"R","q"=>"Q","p"=>"P","o"=>"O","n"=>"N","m"=>"M","l"=>"L","k"=>"K","j"=>"J",
- "i"=>"I","h"=>"H","g"=>"G","f"=>"F","e"=>"E","d"=>"D","c"=>"C","b"=>"B","a"=>"A"
- );
-
- /**
- * UTF-8 Case lookup table
- *
- * This lookuptable defines the lower case letters to their corresponding
- * upper case letter in UTF-8
- *
- * @author Andreas Gohr <andi@splitbrain.org>
- */
- global $UTF8_UPPER_TO_LOWER;
- if(empty($UTF8_UPPER_TO_LOWER)) $UTF8_UPPER_TO_LOWER = array (
- "Z"=>"z","Y"=>"y","X"=>"x","W"=>"w","V"=>"v","U"=>"u","T"=>"t","S"=>"s","R"=>"r","Q"=>"q",
- "P"=>"p","O"=>"o","N"=>"n","M"=>"m","L"=>"l","K"=>"k","J"=>"j","I"=>"i","H"=>"h","G"=>"g",
- "F"=>"f","E"=>"e","D"=>"d","C"=>"c","B"=>"b","A"=>"a","ῼ"=>"ῳ","Ῥ"=>"ῥ","Ῡ"=>"ῡ","Ῑ"=>"ῑ",
- "Ῐ"=>"ῐ","ῌ"=>"ῃ","Ι"=>"ι","ᾼ"=>"ᾳ","Ᾱ"=>"ᾱ","Ᾰ"=>"ᾰ","ᾯ"=>"ᾧ","ᾮ"=>"ᾦ","ᾭ"=>"ᾥ","ᾬ"=>"ᾤ",
- "ᾫ"=>"ᾣ","ᾪ"=>"ᾢ","ᾩ"=>"ᾡ","ᾟ"=>"ᾗ","ᾞ"=>"ᾖ","ᾝ"=>"ᾕ","ᾜ"=>"ᾔ","ᾛ"=>"ᾓ","ᾚ"=>"ᾒ","ᾙ"=>"ᾑ",
- "ᾘ"=>"ᾐ","ᾏ"=>"ᾇ","ᾎ"=>"ᾆ","ᾍ"=>"ᾅ","ᾌ"=>"ᾄ","ᾋ"=>"ᾃ","ᾊ"=>"ᾂ","ᾉ"=>"ᾁ","ᾈ"=>"ᾀ","Ώ"=>"ώ",
- "Ὼ"=>"ὼ","Ύ"=>"ύ","Ὺ"=>"ὺ","Ό"=>"ό","Ὸ"=>"ὸ","Ί"=>"ί","Ὶ"=>"ὶ","Ή"=>"ή","Ὴ"=>"ὴ","Έ"=>"έ",
- "Ὲ"=>"ὲ","Ά"=>"ά","Ὰ"=>"ὰ","Ὧ"=>"ὧ","Ὦ"=>"ὦ","Ὥ"=>"ὥ","Ὤ"=>"ὤ","Ὣ"=>"ὣ","Ὢ"=>"ὢ","Ὡ"=>"ὡ",
- "Ὗ"=>"ὗ","Ὕ"=>"ὕ","Ὓ"=>"ὓ","Ὑ"=>"ὑ","Ὅ"=>"ὅ","Ὄ"=>"ὄ","Ὃ"=>"ὃ","Ὂ"=>"ὂ","Ὁ"=>"ὁ","Ὀ"=>"ὀ",
- "Ἷ"=>"ἷ","Ἶ"=>"ἶ","Ἵ"=>"ἵ","Ἴ"=>"ἴ","Ἳ"=>"ἳ","Ἲ"=>"ἲ","Ἱ"=>"ἱ","Ἰ"=>"ἰ","Ἧ"=>"ἧ","Ἦ"=>"ἦ",
- "Ἥ"=>"ἥ","Ἤ"=>"ἤ","Ἣ"=>"ἣ","Ἢ"=>"ἢ","Ἡ"=>"ἡ","Ἕ"=>"ἕ","Ἔ"=>"ἔ","Ἓ"=>"ἓ","Ἒ"=>"ἒ","Ἑ"=>"ἑ",
- "Ἐ"=>"ἐ","Ἇ"=>"ἇ","Ἆ"=>"ἆ","Ἅ"=>"ἅ","Ἄ"=>"ἄ","Ἃ"=>"ἃ","Ἂ"=>"ἂ","Ἁ"=>"ἁ","Ἀ"=>"ἀ","Ỹ"=>"ỹ",
- "Ỷ"=>"ỷ","Ỵ"=>"ỵ","Ỳ"=>"ỳ","Ự"=>"ự","Ữ"=>"ữ","Ử"=>"ử","Ừ"=>"ừ","Ứ"=>"ứ","Ủ"=>"ủ","Ụ"=>"ụ",
- "Ợ"=>"ợ","Ỡ"=>"ỡ","Ở"=>"ở","Ờ"=>"ờ","Ớ"=>"ớ","Ộ"=>"ộ","Ỗ"=>"ỗ","Ổ"=>"ổ","Ồ"=>"ồ","Ố"=>"ố",
- "Ỏ"=>"ỏ","Ọ"=>"ọ","Ị"=>"ị","Ỉ"=>"ỉ","Ệ"=>"ệ","Ễ"=>"ễ","Ể"=>"ể","Ề"=>"ề","Ế"=>"ế","Ẽ"=>"ẽ",
- "Ẻ"=>"ẻ","Ẹ"=>"ẹ","Ặ"=>"ặ","Ẵ"=>"ẵ","Ẳ"=>"ẳ","Ằ"=>"ằ","Ắ"=>"ắ","Ậ"=>"ậ","Ẫ"=>"ẫ","Ẩ"=>"ẩ",
- "Ầ"=>"ầ","Ấ"=>"ấ","Ả"=>"ả","Ạ"=>"ạ","Ṡ"=>"ẛ","Ẕ"=>"ẕ","Ẓ"=>"ẓ","Ẑ"=>"ẑ","Ẏ"=>"ẏ","Ẍ"=>"ẍ",
- "Ẋ"=>"ẋ","Ẉ"=>"ẉ","Ẇ"=>"ẇ","Ẅ"=>"ẅ","Ẃ"=>"ẃ","Ẁ"=>"ẁ","Ṿ"=>"ṿ","Ṽ"=>"ṽ","Ṻ"=>"ṻ","Ṹ"=>"ṹ",
- "Ṷ"=>"ṷ","Ṵ"=>"ṵ","Ṳ"=>"ṳ","Ṱ"=>"ṱ","Ṯ"=>"ṯ","Ṭ"=>"ṭ","Ṫ"=>"ṫ","Ṩ"=>"ṩ","Ṧ"=>"ṧ","Ṥ"=>"ṥ",
- "Ṣ"=>"ṣ","Ṡ"=>"ṡ","Ṟ"=>"ṟ","Ṝ"=>"ṝ","Ṛ"=>"ṛ","Ṙ"=>"ṙ","Ṗ"=>"ṗ","Ṕ"=>"ṕ","Ṓ"=>"ṓ","Ṑ"=>"ṑ",
- "Ṏ"=>"ṏ","Ṍ"=>"ṍ","Ṋ"=>"ṋ","Ṉ"=>"ṉ","Ṇ"=>"ṇ","Ṅ"=>"ṅ","Ṃ"=>"ṃ","Ṁ"=>"ṁ","Ḿ"=>"ḿ","Ḽ"=>"ḽ",
- "Ḻ"=>"ḻ","Ḹ"=>"ḹ","Ḷ"=>"ḷ","Ḵ"=>"ḵ","Ḳ"=>"ḳ","Ḱ"=>"ḱ","Ḯ"=>"ḯ","Ḭ"=>"ḭ","Ḫ"=>"ḫ","Ḩ"=>"ḩ",
- "Ḧ"=>"ḧ","Ḥ"=>"ḥ","Ḣ"=>"ḣ","Ḡ"=>"ḡ","Ḟ"=>"ḟ","Ḝ"=>"ḝ","Ḛ"=>"ḛ","Ḙ"=>"ḙ","Ḗ"=>"ḗ","Ḕ"=>"ḕ",
- "Ḓ"=>"ḓ","Ḑ"=>"ḑ","Ḏ"=>"ḏ","Ḍ"=>"ḍ","Ḋ"=>"ḋ","Ḉ"=>"ḉ","Ḇ"=>"ḇ","Ḅ"=>"ḅ","Ḃ"=>"ḃ","Ḁ"=>"ḁ",
- "Ֆ"=>"ֆ","Օ"=>"օ","Ք"=>"ք","Փ"=>"փ","Ւ"=>"ւ","Ց"=>"ց","Ր"=>"ր","Տ"=>"տ","Վ"=>"վ","Ս"=>"ս",
- "Ռ"=>"ռ","Ջ"=>"ջ","Պ"=>"պ","Չ"=>"չ","Ո"=>"ո","Շ"=>"շ","Ն"=>"ն","Յ"=>"յ","Մ"=>"մ","Ճ"=>"ճ",
- "Ղ"=>"ղ","Ձ"=>"ձ","Հ"=>"հ","Կ"=>"կ","Ծ"=>"ծ","Խ"=>"խ","Լ"=>"լ","Ի"=>"ի","Ժ"=>"ժ","Թ"=>"թ",
- "Ը"=>"ը","Է"=>"է","Զ"=>"զ","Ե"=>"ե","Դ"=>"դ","Գ"=>"գ","Բ"=>"բ","Ա"=>"ա","Ԏ"=>"ԏ","Ԍ"=>"ԍ",
- "Ԋ"=>"ԋ","Ԉ"=>"ԉ","Ԇ"=>"ԇ","Ԅ"=>"ԅ","Ԃ"=>"ԃ","Ԁ"=>"ԁ","Ӹ"=>"ӹ","Ӵ"=>"ӵ","Ӳ"=>"ӳ","Ӱ"=>"ӱ",
- "Ӯ"=>"ӯ","Ӭ"=>"ӭ","Ӫ"=>"ӫ","Ө"=>"ө","Ӧ"=>"ӧ","Ӥ"=>"ӥ","Ӣ"=>"ӣ","Ӡ"=>"ӡ","Ӟ"=>"ӟ","Ӝ"=>"ӝ",
- "Ӛ"=>"ӛ","Ә"=>"ә","Ӗ"=>"ӗ","Ӕ"=>"ӕ","Ӓ"=>"ӓ","Ӑ"=>"ӑ","Ӎ"=>"ӎ","Ӌ"=>"ӌ","Ӊ"=>"ӊ","Ӈ"=>"ӈ",
- "Ӆ"=>"ӆ","Ӄ"=>"ӄ","Ӂ"=>"ӂ","Ҿ"=>"ҿ","Ҽ"=>"ҽ","Һ"=>"һ","Ҹ"=>"ҹ","Ҷ"=>"ҷ","Ҵ"=>"ҵ","Ҳ"=>"ҳ",
- "Ұ"=>"ұ","Ү"=>"ү","Ҭ"=>"ҭ","Ҫ"=>"ҫ","Ҩ"=>"ҩ","Ҧ"=>"ҧ","Ҥ"=>"ҥ","Ң"=>"ң","Ҡ"=>"ҡ","Ҟ"=>"ҟ",
- "Ҝ"=>"ҝ","Қ"=>"қ","Ҙ"=>"ҙ","Җ"=>"җ","Ҕ"=>"ҕ","Ғ"=>"ғ","Ґ"=>"ґ","Ҏ"=>"ҏ","Ҍ"=>"ҍ","Ҋ"=>"ҋ",
- "Ҁ"=>"ҁ","Ѿ"=>"ѿ","Ѽ"=>"ѽ","Ѻ"=>"ѻ","Ѹ"=>"ѹ","Ѷ"=>"ѷ","Ѵ"=>"ѵ","Ѳ"=>"ѳ","Ѱ"=>"ѱ","Ѯ"=>"ѯ",
- "Ѭ"=>"ѭ","Ѫ"=>"ѫ","Ѩ"=>"ѩ","Ѧ"=>"ѧ","Ѥ"=>"ѥ","Ѣ"=>"ѣ","Ѡ"=>"ѡ","Џ"=>"џ","Ў"=>"ў","Ѝ"=>"ѝ",
- "Ќ"=>"ќ","Ћ"=>"ћ","Њ"=>"њ","Љ"=>"љ","Ј"=>"ј","Ї"=>"ї","І"=>"і","Ѕ"=>"ѕ","Є"=>"є","Ѓ"=>"ѓ",
- "Ђ"=>"ђ","Ё"=>"ё","Ѐ"=>"ѐ","Я"=>"я","Ю"=>"ю","Э"=>"э","Ь"=>"ь","Ы"=>"ы","Ъ"=>"ъ","Щ"=>"щ",
- "Ш"=>"ш","Ч"=>"ч","Ц"=>"ц","Х"=>"х","Ф"=>"ф","У"=>"у","Т"=>"т","С"=>"с","Р"=>"р","П"=>"п",
- "О"=>"о","Н"=>"н","М"=>"м","Л"=>"л","К"=>"к","Й"=>"й","И"=>"и","З"=>"з","Ж"=>"ж","Е"=>"е",
- "Д"=>"д","Г"=>"г","В"=>"в","Б"=>"б","А"=>"а","Ε"=>"ϵ","Σ"=>"ϲ","Ρ"=>"ϱ","Κ"=>"ϰ","Ϯ"=>"ϯ",
- "Ϭ"=>"ϭ","Ϫ"=>"ϫ","Ϩ"=>"ϩ","Ϧ"=>"ϧ","Ϥ"=>"ϥ","Ϣ"=>"ϣ","Ϡ"=>"ϡ","Ϟ"=>"ϟ","Ϝ"=>"ϝ","Ϛ"=>"ϛ",
- "Ϙ"=>"ϙ","Π"=>"ϖ","Φ"=>"ϕ","Θ"=>"ϑ","Β"=>"ϐ","Ώ"=>"ώ","Ύ"=>"ύ","Ό"=>"ό","Ϋ"=>"ϋ","Ϊ"=>"ϊ",
- "Ω"=>"ω","Ψ"=>"ψ","Χ"=>"χ","Φ"=>"φ","Υ"=>"υ","Τ"=>"τ","Σ"=>"σ","Σ"=>"ς","Ρ"=>"ρ","Π"=>"π",
- "Ο"=>"ο","Ξ"=>"ξ","Ν"=>"ν","Μ"=>"μ","Λ"=>"λ","Κ"=>"κ","Ι"=>"ι","Θ"=>"θ","Η"=>"η","Ζ"=>"ζ",
- "Ε"=>"ε","Δ"=>"δ","Γ"=>"γ","Β"=>"β","Α"=>"α","Ί"=>"ί","Ή"=>"ή","Έ"=>"έ","Ά"=>"ά","Ʒ"=>"ʒ",
- "Ʋ"=>"ʋ","Ʊ"=>"ʊ","Ʈ"=>"ʈ","Ʃ"=>"ʃ","Ʀ"=>"ʀ","Ɵ"=>"ɵ","Ɲ"=>"ɲ","Ɯ"=>"ɯ","Ɩ"=>"ɩ","Ɨ"=>"ɨ",
- "Ɣ"=>"ɣ","Ɛ"=>"ɛ","Ə"=>"ə","Ɗ"=>"ɗ","Ɖ"=>"ɖ","Ɔ"=>"ɔ","Ɓ"=>"ɓ","Ȳ"=>"ȳ","Ȱ"=>"ȱ","Ȯ"=>"ȯ",
- "Ȭ"=>"ȭ","Ȫ"=>"ȫ","Ȩ"=>"ȩ","Ȧ"=>"ȧ","Ȥ"=>"ȥ","Ȣ"=>"ȣ","Ȟ"=>"ȟ","Ȝ"=>"ȝ","Ț"=>"ț","Ș"=>"ș",
- "Ȗ"=>"ȗ","Ȕ"=>"ȕ","Ȓ"=>"ȓ","Ȑ"=>"ȑ","Ȏ"=>"ȏ","Ȍ"=>"ȍ","Ȋ"=>"ȋ","Ȉ"=>"ȉ","Ȇ"=>"ȇ","Ȅ"=>"ȅ",
- "Ȃ"=>"ȃ","Ȁ"=>"ȁ","Ǿ"=>"ǿ","Ǽ"=>"ǽ","Ǻ"=>"ǻ","Ǹ"=>"ǹ","Ǵ"=>"ǵ","Dz"=>"dz","Ǯ"=>"ǯ","Ǭ"=>"ǭ",
- "Ǫ"=>"ǫ","Ǩ"=>"ǩ","Ǧ"=>"ǧ","Ǥ"=>"ǥ","Ǣ"=>"ǣ","Ǡ"=>"ǡ","Ǟ"=>"ǟ","Ǝ"=>"ǝ","Ǜ"=>"ǜ","Ǚ"=>"ǚ",
- "Ǘ"=>"ǘ","Ǖ"=>"ǖ","Ǔ"=>"ǔ","Ǒ"=>"ǒ","Ǐ"=>"ǐ","Ǎ"=>"ǎ","Nj"=>"nj","Lj"=>"lj","Dž"=>"dž","Ƿ"=>"ƿ",
- "Ƽ"=>"ƽ","Ƹ"=>"ƹ","Ƶ"=>"ƶ","Ƴ"=>"ƴ","Ư"=>"ư","Ƭ"=>"ƭ","Ƨ"=>"ƨ","Ƥ"=>"ƥ","Ƣ"=>"ƣ","Ơ"=>"ơ",
- "Ƞ"=>"ƞ","Ƙ"=>"ƙ","Ƕ"=>"ƕ","Ƒ"=>"ƒ","Ƌ"=>"ƌ","Ƈ"=>"ƈ","Ƅ"=>"ƅ","Ƃ"=>"ƃ","S"=>"ſ","Ž"=>"ž",
- "Ż"=>"ż","Ź"=>"ź","Ŷ"=>"ŷ","Ŵ"=>"ŵ","Ų"=>"ų","Ű"=>"ű","Ů"=>"ů","Ŭ"=>"ŭ","Ū"=>"ū","Ũ"=>"ũ",
- "Ŧ"=>"ŧ","Ť"=>"ť","Ţ"=>"ţ","Š"=>"š","Ş"=>"ş","Ŝ"=>"ŝ","Ś"=>"ś","Ř"=>"ř","Ŗ"=>"ŗ","Ŕ"=>"ŕ",
- "Œ"=>"œ","Ő"=>"ő","Ŏ"=>"ŏ","Ō"=>"ō","Ŋ"=>"ŋ","Ň"=>"ň","Ņ"=>"ņ","Ń"=>"ń","Ł"=>"ł","Ŀ"=>"ŀ",
- "Ľ"=>"ľ","Ļ"=>"ļ","Ĺ"=>"ĺ","Ķ"=>"ķ","Ĵ"=>"ĵ","IJ"=>"ij","I"=>"ı","Į"=>"į","Ĭ"=>"ĭ","Ī"=>"ī",
- "Ĩ"=>"ĩ","Ħ"=>"ħ","Ĥ"=>"ĥ","Ģ"=>"ģ","Ġ"=>"ġ","Ğ"=>"ğ","Ĝ"=>"ĝ","Ě"=>"ě","Ę"=>"ę","Ė"=>"ė",
- "Ĕ"=>"ĕ","Ē"=>"ē","Đ"=>"đ","Ď"=>"ď","Č"=>"č","Ċ"=>"ċ","Ĉ"=>"ĉ","Ć"=>"ć","Ą"=>"ą","Ă"=>"ă",
- "Ā"=>"ā","Ÿ"=>"ÿ","Þ"=>"þ","Ý"=>"ý","Ü"=>"ü","Û"=>"û","Ú"=>"ú","Ù"=>"ù","Ø"=>"ø","Ö"=>"ö",
- "Õ"=>"õ","Ô"=>"ô","Ó"=>"ó","Ò"=>"ò","Ñ"=>"ñ","Ð"=>"ð","Ï"=>"ï","Î"=>"î","Í"=>"í","Ì"=>"ì",
- "Ë"=>"ë","Ê"=>"ê","É"=>"é","È"=>"è","Ç"=>"ç","Æ"=>"æ","Å"=>"å","Ä"=>"ä","Ã"=>"ã","Â"=>"â",
- "Á"=>"á","À"=>"à","Μ"=>"µ","Z"=>"z","Y"=>"y","X"=>"x","W"=>"w","V"=>"v","U"=>"u","T"=>"t",
- "S"=>"s","R"=>"r","Q"=>"q","P"=>"p","O"=>"o","N"=>"n","M"=>"m","L"=>"l","K"=>"k","J"=>"j",
- "I"=>"i","H"=>"h","G"=>"g","F"=>"f","E"=>"e","D"=>"d","C"=>"c","B"=>"b","A"=>"a"
- );
-}; // end of case lookup tables
-
-/**
- * UTF-8 lookup table for lower case accented letters
- *
- * This lookuptable defines replacements for accented characters from the ASCII-7
- * range. This are lower case letters only.
- *
- * @author Andreas Gohr <andi@splitbrain.org>
- * @see utf8_deaccent()
- */
-global $UTF8_LOWER_ACCENTS;
-if(empty($UTF8_LOWER_ACCENTS)) $UTF8_LOWER_ACCENTS = array(
- 'à' => 'a', 'ô' => 'o', 'ď' => 'd', 'ḟ' => 'f', 'ë' => 'e', 'š' => 's', 'ơ' => 'o',
- 'ß' => 'ss', 'ă' => 'a', 'ř' => 'r', 'ț' => 't', 'ň' => 'n', 'ā' => 'a', 'ķ' => 'k',
- 'ŝ' => 's', 'ỳ' => 'y', 'ņ' => 'n', 'ĺ' => 'l', 'ħ' => 'h', 'ṗ' => 'p', 'ó' => 'o',
- 'ú' => 'u', 'ě' => 'e', 'é' => 'e', 'ç' => 'c', 'ẁ' => 'w', 'ċ' => 'c', 'õ' => 'o',
- 'ṡ' => 's', 'ø' => 'o', 'ģ' => 'g', 'ŧ' => 't', 'ș' => 's', 'ė' => 'e', 'ĉ' => 'c',
- 'ś' => 's', 'î' => 'i', 'ű' => 'u', 'ć' => 'c', 'ę' => 'e', 'ŵ' => 'w', 'ṫ' => 't',
- 'ū' => 'u', 'č' => 'c', 'ö' => 'oe', 'è' => 'e', 'ŷ' => 'y', 'ą' => 'a', 'ł' => 'l',
- 'ų' => 'u', 'ů' => 'u', 'ş' => 's', 'ğ' => 'g', 'ļ' => 'l', 'ƒ' => 'f', 'ž' => 'z',
- 'ẃ' => 'w', 'ḃ' => 'b', 'å' => 'a', 'ì' => 'i', 'ï' => 'i', 'ḋ' => 'd', 'ť' => 't',
- 'ŗ' => 'r', 'ä' => 'ae', 'í' => 'i', 'ŕ' => 'r', 'ê' => 'e', 'ü' => 'ue', 'ò' => 'o',
- 'ē' => 'e', 'ñ' => 'n', 'ń' => 'n', 'ĥ' => 'h', 'ĝ' => 'g', 'đ' => 'd', 'ĵ' => 'j',
- 'ÿ' => 'y', 'ũ' => 'u', 'ŭ' => 'u', 'ư' => 'u', 'ţ' => 't', 'ý' => 'y', 'ő' => 'o',
- 'â' => 'a', 'ľ' => 'l', 'ẅ' => 'w', 'ż' => 'z', 'ī' => 'i', 'ã' => 'a', 'ġ' => 'g',
- 'ṁ' => 'm', 'ō' => 'o', 'ĩ' => 'i', 'ù' => 'u', 'į' => 'i', 'ź' => 'z', 'á' => 'a',
- 'û' => 'u', 'þ' => 'th', 'ð' => 'dh', 'æ' => 'ae', 'µ' => 'u', 'ĕ' => 'e',
-);
-
-/**
- * UTF-8 lookup table for upper case accented letters
- *
- * This lookuptable defines replacements for accented characters from the ASCII-7
- * range. This are upper case letters only.
- *
- * @author Andreas Gohr <andi@splitbrain.org>
- * @see utf8_deaccent()
- */
-global $UTF8_UPPER_ACCENTS;
-if(empty($UTF8_UPPER_ACCENTS)) $UTF8_UPPER_ACCENTS = array(
- 'À' => 'A', 'Ô' => 'O', 'Ď' => 'D', 'Ḟ' => 'F', 'Ë' => 'E', 'Š' => 'S', 'Ơ' => 'O',
- 'Ă' => 'A', 'Ř' => 'R', 'Ț' => 'T', 'Ň' => 'N', 'Ā' => 'A', 'Ķ' => 'K',
- 'Ŝ' => 'S', 'Ỳ' => 'Y', 'Ņ' => 'N', 'Ĺ' => 'L', 'Ħ' => 'H', 'Ṗ' => 'P', 'Ó' => 'O',
- 'Ú' => 'U', 'Ě' => 'E', 'É' => 'E', 'Ç' => 'C', 'Ẁ' => 'W', 'Ċ' => 'C', 'Õ' => 'O',
- 'Ṡ' => 'S', 'Ø' => 'O', 'Ģ' => 'G', 'Ŧ' => 'T', 'Ș' => 'S', 'Ė' => 'E', 'Ĉ' => 'C',
- 'Ś' => 'S', 'Î' => 'I', 'Ű' => 'U', 'Ć' => 'C', 'Ę' => 'E', 'Ŵ' => 'W', 'Ṫ' => 'T',
- 'Ū' => 'U', 'Č' => 'C', 'Ö' => 'Oe', 'È' => 'E', 'Ŷ' => 'Y', 'Ą' => 'A', 'Ł' => 'L',
- 'Ų' => 'U', 'Ů' => 'U', 'Ş' => 'S', 'Ğ' => 'G', 'Ļ' => 'L', 'Ƒ' => 'F', 'Ž' => 'Z',
- 'Ẃ' => 'W', 'Ḃ' => 'B', 'Å' => 'A', 'Ì' => 'I', 'Ï' => 'I', 'Ḋ' => 'D', 'Ť' => 'T',
- 'Ŗ' => 'R', 'Ä' => 'Ae', 'Í' => 'I', 'Ŕ' => 'R', 'Ê' => 'E', 'Ü' => 'Ue', 'Ò' => 'O',
- 'Ē' => 'E', 'Ñ' => 'N', 'Ń' => 'N', 'Ĥ' => 'H', 'Ĝ' => 'G', 'Đ' => 'D', 'Ĵ' => 'J',
- 'Ÿ' => 'Y', 'Ũ' => 'U', 'Ŭ' => 'U', 'Ư' => 'U', 'Ţ' => 'T', 'Ý' => 'Y', 'Ő' => 'O',
- 'Â' => 'A', 'Ľ' => 'L', 'Ẅ' => 'W', 'Ż' => 'Z', 'Ī' => 'I', 'Ã' => 'A', 'Ġ' => 'G',
- 'Ṁ' => 'M', 'Ō' => 'O', 'Ĩ' => 'I', 'Ù' => 'U', 'Į' => 'I', 'Ź' => 'Z', 'Á' => 'A',
- 'Û' => 'U', 'Þ' => 'Th', 'Ð' => 'Dh', 'Æ' => 'Ae', 'Ĕ' => 'E',
-);
-
-/**
- * UTF-8 array of common special characters
- *
- * This array should contain all special characters (not a letter or digit)
- * defined in the various local charsets - it's not a complete list of non-alphanum
- * characters in UTF-8. It's not perfect but should match most cases of special
- * chars.
- *
- * The controlchars 0x00 to 0x19 are _not_ included in this array. The space 0x20 is!
- * These chars are _not_ in the array either: _ (0x5f), : 0x3a, . 0x2e, - 0x2d, * 0x2a
- *
- * @author Andreas Gohr <andi@splitbrain.org>
- * @see utf8_stripspecials()
- */
-global $UTF8_SPECIAL_CHARS;
-if(empty($UTF8_SPECIAL_CHARS)) $UTF8_SPECIAL_CHARS = array(
- 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, 0x0020, 0x0021, 0x0022, 0x0023,
- 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002b, 0x002c,
- 0x002f, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, 0x0040, 0x005b,
- 0x005c, 0x005d, 0x005e, 0x0060, 0x007b, 0x007c, 0x007d, 0x007e,
- 0x007f, 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, 0x0088,
- 0x0089, 0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f, 0x0090, 0x0091, 0x0092,
- 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, 0x0098, 0x0099, 0x009a, 0x009b, 0x009c,
- 0x009d, 0x009e, 0x009f, 0x00a0, 0x00a1, 0x00a2, 0x00a3, 0x00a4, 0x00a5, 0x00a6,
- 0x00a7, 0x00a8, 0x00a9, 0x00aa, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x00af, 0x00b0,
- 0x00b1, 0x00b2, 0x00b3, 0x00b4, 0x00b5, 0x00b6, 0x00b7, 0x00b8, 0x00b9, 0x00ba,
- 0x00bb, 0x00bc, 0x00bd, 0x00be, 0x00bf, 0x00d7, 0x00f7, 0x02c7, 0x02d8, 0x02d9,
- 0x02da, 0x02db, 0x02dc, 0x02dd, 0x0300, 0x0301, 0x0303, 0x0309, 0x0323, 0x0384,
- 0x0385, 0x0387, 0x03c6, 0x03d1, 0x03d2, 0x03d5, 0x03d6, 0x05b0, 0x05b1,
- 0x05b2, 0x05b3, 0x05b4, 0x05b5, 0x05b6, 0x05b7, 0x05b8, 0x05b9, 0x05bb, 0x05bc,
- 0x05bd, 0x05be, 0x05bf, 0x05c0, 0x05c1, 0x05c2, 0x05c3, 0x05f3, 0x05f4, 0x060c,
- 0x061b, 0x061f, 0x0640, 0x064b, 0x064c, 0x064d, 0x064e, 0x064f, 0x0650, 0x0651,
- 0x0652, 0x066a, 0x0e3f, 0x200c, 0x200d, 0x200e, 0x200f, 0x2013, 0x2014, 0x2015,
- 0x2017, 0x2018, 0x2019, 0x201a, 0x201c, 0x201d, 0x201e, 0x2020, 0x2021, 0x2022,
- 0x2026, 0x2030, 0x2032, 0x2033, 0x2039, 0x203a, 0x2044, 0x20a7, 0x20aa, 0x20ab,
- 0x20ac, 0x2116, 0x2118, 0x2122, 0x2126, 0x2135, 0x2190, 0x2191, 0x2192, 0x2193,
- 0x2194, 0x2195, 0x21b5, 0x21d0, 0x21d1, 0x21d2, 0x21d3, 0x21d4, 0x2200, 0x2202,
- 0x2203, 0x2205, 0x2206, 0x2207, 0x2208, 0x2209, 0x220b, 0x220f, 0x2211, 0x2212,
- 0x2215, 0x2217, 0x2219, 0x221a, 0x221d, 0x221e, 0x2220, 0x2227, 0x2228, 0x2229,
- 0x222a, 0x222b, 0x2234, 0x223c, 0x2245, 0x2248, 0x2260, 0x2261, 0x2264, 0x2265,
- 0x2282, 0x2283, 0x2284, 0x2286, 0x2287, 0x2295, 0x2297, 0x22a5, 0x22c5, 0x2310,
- 0x2320, 0x2321, 0x2329, 0x232a, 0x2469, 0x2500, 0x2502, 0x250c, 0x2510, 0x2514,
- 0x2518, 0x251c, 0x2524, 0x252c, 0x2534, 0x253c, 0x2550, 0x2551, 0x2552, 0x2553,
- 0x2554, 0x2555, 0x2556, 0x2557, 0x2558, 0x2559, 0x255a, 0x255b, 0x255c, 0x255d,
- 0x255e, 0x255f, 0x2560, 0x2561, 0x2562, 0x2563, 0x2564, 0x2565, 0x2566, 0x2567,
- 0x2568, 0x2569, 0x256a, 0x256b, 0x256c, 0x2580, 0x2584, 0x2588, 0x258c, 0x2590,
- 0x2591, 0x2592, 0x2593, 0x25a0, 0x25b2, 0x25bc, 0x25c6, 0x25ca, 0x25cf, 0x25d7,
- 0x2605, 0x260e, 0x261b, 0x261e, 0x2660, 0x2663, 0x2665, 0x2666, 0x2701, 0x2702,
- 0x2703, 0x2704, 0x2706, 0x2707, 0x2708, 0x2709, 0x270c, 0x270d, 0x270e, 0x270f,
- 0x2710, 0x2711, 0x2712, 0x2713, 0x2714, 0x2715, 0x2716, 0x2717, 0x2718, 0x2719,
- 0x271a, 0x271b, 0x271c, 0x271d, 0x271e, 0x271f, 0x2720, 0x2721, 0x2722, 0x2723,
- 0x2724, 0x2725, 0x2726, 0x2727, 0x2729, 0x272a, 0x272b, 0x272c, 0x272d, 0x272e,
- 0x272f, 0x2730, 0x2731, 0x2732, 0x2733, 0x2734, 0x2735, 0x2736, 0x2737, 0x2738,
- 0x2739, 0x273a, 0x273b, 0x273c, 0x273d, 0x273e, 0x273f, 0x2740, 0x2741, 0x2742,
- 0x2743, 0x2744, 0x2745, 0x2746, 0x2747, 0x2748, 0x2749, 0x274a, 0x274b, 0x274d,
- 0x274f, 0x2750, 0x2751, 0x2752, 0x2756, 0x2758, 0x2759, 0x275a, 0x275b, 0x275c,
- 0x275d, 0x275e, 0x2761, 0x2762, 0x2763, 0x2764, 0x2765, 0x2766, 0x2767, 0x277f,
- 0x2789, 0x2793, 0x2794, 0x2798, 0x2799, 0x279a, 0x279b, 0x279c, 0x279d, 0x279e,
- 0x279f, 0x27a0, 0x27a1, 0x27a2, 0x27a3, 0x27a4, 0x27a5, 0x27a6, 0x27a7, 0x27a8,
- 0x27a9, 0x27aa, 0x27ab, 0x27ac, 0x27ad, 0x27ae, 0x27af, 0x27b1, 0x27b2, 0x27b3,
- 0x27b4, 0x27b5, 0x27b6, 0x27b7, 0x27b8, 0x27b9, 0x27ba, 0x27bb, 0x27bc, 0x27bd,
- 0x27be, 0x3000, 0x3001, 0x3002, 0x3003, 0x3008, 0x3009, 0x300a, 0x300b, 0x300c,
- 0x300d, 0x300e, 0x300f, 0x3010, 0x3011, 0x3012, 0x3014, 0x3015, 0x3016, 0x3017,
- 0x3018, 0x3019, 0x301a, 0x301b, 0x3036,
- 0xf6d9, 0xf6da, 0xf6db, 0xf8d7, 0xf8d8, 0xf8d9, 0xf8da, 0xf8db, 0xf8dc,
- 0xf8dd, 0xf8de, 0xf8df, 0xf8e0, 0xf8e1, 0xf8e2, 0xf8e3, 0xf8e4, 0xf8e5, 0xf8e6,
- 0xf8e7, 0xf8e8, 0xf8e9, 0xf8ea, 0xf8eb, 0xf8ec, 0xf8ed, 0xf8ee, 0xf8ef, 0xf8f0,
- 0xf8f1, 0xf8f2, 0xf8f3, 0xf8f4, 0xf8f5, 0xf8f6, 0xf8f7, 0xf8f8, 0xf8f9, 0xf8fa,
- 0xf8fb, 0xf8fc, 0xf8fd, 0xf8fe, 0xfe7c, 0xfe7d,
- 0xff01, 0xff02, 0xff03, 0xff04, 0xff05, 0xff06, 0xff07, 0xff08, 0xff09,
- 0xff09, 0xff0a, 0xff0b, 0xff0c, 0xff0d, 0xff0e, 0xff0f, 0xff1a, 0xff1b, 0xff1c,
- 0xff1d, 0xff1e, 0xff1f, 0xff20, 0xff3b, 0xff3c, 0xff3d, 0xff3e, 0xff40, 0xff5b,
- 0xff5c, 0xff5d, 0xff5e, 0xff5f, 0xff60, 0xff61, 0xff62, 0xff63, 0xff64, 0xff65,
- 0xffe0, 0xffe1, 0xffe2, 0xffe3, 0xffe4, 0xffe5, 0xffe6, 0xffe8, 0xffe9, 0xffea,
- 0xffeb, 0xffec, 0xffed, 0xffee,
- 0x01d6fc, 0x01d6fd, 0x01d6fe, 0x01d6ff, 0x01d700, 0x01d701, 0x01d702, 0x01d703,
- 0x01d704, 0x01d705, 0x01d706, 0x01d707, 0x01d708, 0x01d709, 0x01d70a, 0x01d70b,
- 0x01d70c, 0x01d70d, 0x01d70e, 0x01d70f, 0x01d710, 0x01d711, 0x01d712, 0x01d713,
- 0x01d714, 0x01d715, 0x01d716, 0x01d717, 0x01d718, 0x01d719, 0x01d71a, 0x01d71b,
- 0xc2a0, 0xe28087, 0xe280af, 0xe281a0, 0xefbbbf,
-);
-
-// utf8 version of above data
-global $UTF8_SPECIAL_CHARS2;
-if(empty($UTF8_SPECIAL_CHARS2)) $UTF8_SPECIAL_CHARS2 =
- "\x1A".' !"#$%&\'()+,/;<=>?@[\]^`{|}~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•�'.
- '�—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½�'.
- '�¿×÷ˇ˘˙˚˛˜˝̣̀́̃̉΄΅·ϖְֱֲֳִֵֶַָֹֻּֽ־ֿ�'.
- '�ׁׂ׃׳״،؛؟ـًٌٍَُِّْ٪฿‌‍‎‏–—―‗‘’‚“”�'.
- '��†‡•…‰′″‹›⁄₧₪₫€№℘™Ωℵ←↑→↓↔↕↵'.
- '⇐⇑⇒⇓⇔∀∂∃∅∆∇∈∉∋∏∑−∕∗∙√∝∞∠∧∨�'.
- '�∪∫∴∼≅≈≠≡≤≥⊂⊃⊄⊆⊇⊕⊗⊥⋅⌐⌠⌡〈〉⑩─�'.
- '��┌┐└┘├┤┬┴┼═║╒╓╔╕╖╗╘╙╚╛╜╝╞╟╠'.
- '╡╢╣╤╥╦╧╨╩╪╫╬▀▄█▌▐░▒▓■▲▼◆◊●�'.
- '�★☎☛☞♠♣♥♦✁✂✃✄✆✇✈✉✌✍✎✏✐✑✒✓✔✕�'.
- '��✗✘✙✚✛✜✝✞✟✠✡✢✣✤✥✦✧✩✪✫✬✭✮✯✰✱'.
- '✲✳✴✵✶✷✸✹✺✻✼✽✾✿❀❁❂❃❄❅❆❇❈❉❊❋�'.
- '�❏❐❑❒❖❘❙❚❛❜❝❞❡❢❣❤❥❦❧❿➉➓➔➘➙➚�'.
- '��➜➝➞➟➠➡➢➣➤➥➦➧➨➩➪➫➬➭➮➯➱➲➳➴➵➶'.
- '➷➸➹➺➻➼➽➾'.
- ' 、。〃〈〉《》「」『』【】〒〔〕〖〗〘〙〚〛〶'.
- '�'.
- '�ﹼﹽ'.
- '!"#$%&'()*+,-./:;<=>?@[\]^`{|}~'.
- '⦅⦆。「」、・¢£¬ ̄¦¥₩│←↑→↓■○'.
- '𝛼𝛽𝛾𝛿𝜀𝜁𝜂𝜃𝜄𝜅𝜆𝜇𝜈𝜉𝜊𝜋𝜌𝜍𝜎𝜏𝜐𝜑𝜒𝜓𝜔𝜕𝜖𝜗𝜘𝜙𝜚𝜛'.
- '   ⁠';
-
-/**
- * Romanization lookup table
- *
- * This lookup tables provides a way to transform strings written in a language
- * different from the ones based upon latin letters into plain ASCII.
- *
- * Please note: this is not a scientific transliteration table. It only works
- * oneway from nonlatin to ASCII and it works by simple character replacement
- * only. Specialities of each language are not supported.
- *
- * @author Andreas Gohr <andi@splitbrain.org>
- * @author Vitaly Blokhin <vitinfo@vitn.com>
- * @link http://www.uconv.com/translit.htm
- * @author Bisqwit <bisqwit@iki.fi>
- * @link http://kanjidict.stc.cx/hiragana.php?src=2
- * @link http://www.translatum.gr/converter/greek-transliteration.htm
- * @link http://en.wikipedia.org/wiki/Royal_Thai_General_System_of_Transcription
- * @link http://www.btranslations.com/resources/romanization/korean.asp
- * @author Arthit Suriyawongkul <arthit@gmail.com>
- * @author Denis Scheither <amorphis@uni-bremen.de>
- * @author Eivind Morland <eivind.morland@gmail.com>
- */
-global $UTF8_ROMANIZATION;
-if(empty($UTF8_ROMANIZATION)) $UTF8_ROMANIZATION = array(
- // scandinavian - differs from what we do in deaccent
- 'å'=>'a','Å'=>'A','ä'=>'a','Ä'=>'A','ö'=>'o','Ö'=>'O',
-
- //russian cyrillic
- 'а'=>'a','А'=>'A','б'=>'b','Б'=>'B','в'=>'v','В'=>'V','г'=>'g','Г'=>'G',
- 'д'=>'d','Д'=>'D','е'=>'e','Е'=>'E','ё'=>'jo','Ё'=>'Jo','ж'=>'zh','Ж'=>'Zh',
- 'з'=>'z','З'=>'Z','и'=>'i','И'=>'I','й'=>'j','Й'=>'J','к'=>'k','К'=>'K',
- 'л'=>'l','Л'=>'L','м'=>'m','М'=>'M','н'=>'n','Н'=>'N','о'=>'o','О'=>'O',
- 'п'=>'p','П'=>'P','р'=>'r','Р'=>'R','с'=>'s','С'=>'S','т'=>'t','Т'=>'T',
- 'у'=>'u','У'=>'U','ф'=>'f','Ф'=>'F','х'=>'x','Х'=>'X','ц'=>'c','Ц'=>'C',
- 'ч'=>'ch','Ч'=>'Ch','ш'=>'sh','Ш'=>'Sh','щ'=>'sch','Щ'=>'Sch','ъ'=>'',
- 'Ъ'=>'','ы'=>'y','Ы'=>'Y','ь'=>'','Ь'=>'','э'=>'eh','Э'=>'Eh','ю'=>'ju',
- 'Ю'=>'Ju','я'=>'ja','Я'=>'Ja',
- // Ukrainian cyrillic
- 'Ґ'=>'Gh','ґ'=>'gh','Є'=>'Je','є'=>'je','І'=>'I','і'=>'i','Ї'=>'Ji','ї'=>'ji',
- // Georgian
- 'ა'=>'a','ბ'=>'b','გ'=>'g','დ'=>'d','ე'=>'e','ვ'=>'v','ზ'=>'z','თ'=>'th',
- 'ი'=>'i','კ'=>'p','ლ'=>'l','მ'=>'m','ნ'=>'n','ო'=>'o','პ'=>'p','ჟ'=>'zh',
- 'რ'=>'r','ს'=>'s','ტ'=>'t','უ'=>'u','ფ'=>'ph','ქ'=>'kh','ღ'=>'gh','ყ'=>'q',
- 'შ'=>'sh','ჩ'=>'ch','ც'=>'c','ძ'=>'dh','წ'=>'w','ჭ'=>'j','ხ'=>'x','ჯ'=>'jh',
- 'ჰ'=>'xh',
- //Sanskrit
- 'अ'=>'a','आ'=>'ah','इ'=>'i','ई'=>'ih','उ'=>'u','ऊ'=>'uh','ऋ'=>'ry',
- 'ॠ'=>'ryh','ऌ'=>'ly','ॡ'=>'lyh','ए'=>'e','ऐ'=>'ay','ओ'=>'o','औ'=>'aw',
- 'अं'=>'amh','अः'=>'aq','क'=>'k','ख'=>'kh','ग'=>'g','घ'=>'gh','ङ'=>'nh',
- 'च'=>'c','छ'=>'ch','ज'=>'j','झ'=>'jh','ञ'=>'ny','ट'=>'tq','ठ'=>'tqh',
- 'ड'=>'dq','ढ'=>'dqh','ण'=>'nq','त'=>'t','थ'=>'th','द'=>'d','ध'=>'dh',
- 'न'=>'n','प'=>'p','फ'=>'ph','ब'=>'b','भ'=>'bh','म'=>'m','य'=>'z','र'=>'r',
- 'ल'=>'l','व'=>'v','श'=>'sh','ष'=>'sqh','स'=>'s','ह'=>'x',
- //Sanskrit diacritics
- 'Ā'=>'A','Ī'=>'I','Ū'=>'U','Ṛ'=>'R','Ṝ'=>'R','Ṅ'=>'N','Ñ'=>'N','Ṭ'=>'T',
- 'Ḍ'=>'D','Ṇ'=>'N','Ś'=>'S','Ṣ'=>'S','Ṁ'=>'M','Ṃ'=>'M','Ḥ'=>'H','Ḷ'=>'L','Ḹ'=>'L',
- 'ā'=>'a','ī'=>'i','ū'=>'u','ṛ'=>'r','ṝ'=>'r','ṅ'=>'n','ñ'=>'n','ṭ'=>'t',
- 'ḍ'=>'d','ṇ'=>'n','ś'=>'s','ṣ'=>'s','ṁ'=>'m','ṃ'=>'m','ḥ'=>'h','ḷ'=>'l','ḹ'=>'l',
- //Hebrew
- 'א'=>'a', 'ב'=>'b','ג'=>'g','ד'=>'d','ה'=>'h','ו'=>'v','ז'=>'z','ח'=>'kh','ט'=>'th',
- 'י'=>'y','ך'=>'h','כ'=>'k','ל'=>'l','ם'=>'m','מ'=>'m','ן'=>'n','נ'=>'n',
- 'ס'=>'s','ע'=>'ah','ף'=>'f','פ'=>'p','ץ'=>'c','צ'=>'c','ק'=>'q','ר'=>'r',
- 'ש'=>'sh','ת'=>'t',
- //Arabic
- 'ا'=>'a','ب'=>'b','ت'=>'t','ث'=>'th','ج'=>'g','ح'=>'xh','خ'=>'x','د'=>'d',
- 'ذ'=>'dh','ر'=>'r','ز'=>'z','س'=>'s','ش'=>'sh','ص'=>'s\'','ض'=>'d\'',
- 'ط'=>'t\'','ظ'=>'z\'','ع'=>'y','غ'=>'gh','ف'=>'f','ق'=>'q','ك'=>'k',
- 'ل'=>'l','م'=>'m','ن'=>'n','ه'=>'x\'','و'=>'u','ي'=>'i',
-
- // Japanese characters (last update: 2008-05-09)
-
- // Japanese hiragana
-
- // 3 character syllables, っ doubles the consonant after
- 'っちゃ'=>'ccha','っちぇ'=>'cche','っちょ'=>'ccho','っちゅ'=>'cchu',
- 'っびゃ'=>'bbya','っびぇ'=>'bbye','っびぃ'=>'bbyi','っびょ'=>'bbyo','っびゅ'=>'bbyu',
- 'っぴゃ'=>'ppya','っぴぇ'=>'ppye','っぴぃ'=>'ppyi','っぴょ'=>'ppyo','っぴゅ'=>'ppyu',
- 'っちゃ'=>'ccha','っちぇ'=>'cche','っち'=>'cchi','っちょ'=>'ccho','っちゅ'=>'cchu',
- // 'っひゃ'=>'hya','っひぇ'=>'hye','っひぃ'=>'hyi','っひょ'=>'hyo','っひゅ'=>'hyu',
- 'っきゃ'=>'kkya','っきぇ'=>'kkye','っきぃ'=>'kkyi','っきょ'=>'kkyo','っきゅ'=>'kkyu',
- 'っぎゃ'=>'ggya','っぎぇ'=>'ggye','っぎぃ'=>'ggyi','っぎょ'=>'ggyo','っぎゅ'=>'ggyu',
- 'っみゃ'=>'mmya','っみぇ'=>'mmye','っみぃ'=>'mmyi','っみょ'=>'mmyo','っみゅ'=>'mmyu',
- 'っにゃ'=>'nnya','っにぇ'=>'nnye','っにぃ'=>'nnyi','っにょ'=>'nnyo','っにゅ'=>'nnyu',
- 'っりゃ'=>'rrya','っりぇ'=>'rrye','っりぃ'=>'rryi','っりょ'=>'rryo','っりゅ'=>'rryu',
- 'っしゃ'=>'ssha','っしぇ'=>'sshe','っし'=>'sshi','っしょ'=>'ssho','っしゅ'=>'sshu',
-
- // seperate hiragana 'n' ('n' + 'i' != 'ni', normally we would write "kon'nichi wa" but the apostrophe would be converted to _ anyway)
- 'んあ'=>'n_a','んえ'=>'n_e','んい'=>'n_i','んお'=>'n_o','んう'=>'n_u',
- 'んや'=>'n_ya','んよ'=>'n_yo','んゆ'=>'n_yu',
-
- // 2 character syllables - normal
- 'ふぁ'=>'fa','ふぇ'=>'fe','ふぃ'=>'fi','ふぉ'=>'fo',
- 'ちゃ'=>'cha','ちぇ'=>'che','ち'=>'chi','ちょ'=>'cho','ちゅ'=>'chu',
- 'ひゃ'=>'hya','ひぇ'=>'hye','ひぃ'=>'hyi','ひょ'=>'hyo','ひゅ'=>'hyu',
- 'びゃ'=>'bya','びぇ'=>'bye','びぃ'=>'byi','びょ'=>'byo','びゅ'=>'byu',
- 'ぴゃ'=>'pya','ぴぇ'=>'pye','ぴぃ'=>'pyi','ぴょ'=>'pyo','ぴゅ'=>'pyu',
- 'きゃ'=>'kya','きぇ'=>'kye','きぃ'=>'kyi','きょ'=>'kyo','きゅ'=>'kyu',
- 'ぎゃ'=>'gya','ぎぇ'=>'gye','ぎぃ'=>'gyi','ぎょ'=>'gyo','ぎゅ'=>'gyu',
- 'みゃ'=>'mya','みぇ'=>'mye','みぃ'=>'myi','みょ'=>'myo','みゅ'=>'myu',
- 'にゃ'=>'nya','にぇ'=>'nye','にぃ'=>'nyi','にょ'=>'nyo','にゅ'=>'nyu',
- 'りゃ'=>'rya','りぇ'=>'rye','りぃ'=>'ryi','りょ'=>'ryo','りゅ'=>'ryu',
- 'しゃ'=>'sha','しぇ'=>'she','し'=>'shi','しょ'=>'sho','しゅ'=>'shu',
- 'じゃ'=>'ja','じぇ'=>'je','じょ'=>'jo','じゅ'=>'ju',
- 'うぇ'=>'we','うぃ'=>'wi',
- 'いぇ'=>'ye',
-
- // 2 character syllables, っ doubles the consonant after
- 'っば'=>'bba','っべ'=>'bbe','っび'=>'bbi','っぼ'=>'bbo','っぶ'=>'bbu',
- 'っぱ'=>'ppa','っぺ'=>'ppe','っぴ'=>'ppi','っぽ'=>'ppo','っぷ'=>'ppu',
- 'った'=>'tta','って'=>'tte','っち'=>'cchi','っと'=>'tto','っつ'=>'ttsu',
- 'っだ'=>'dda','っで'=>'dde','っぢ'=>'ddi','っど'=>'ddo','っづ'=>'ddu',
- 'っが'=>'gga','っげ'=>'gge','っぎ'=>'ggi','っご'=>'ggo','っぐ'=>'ggu',
- 'っか'=>'kka','っけ'=>'kke','っき'=>'kki','っこ'=>'kko','っく'=>'kku',
- 'っま'=>'mma','っめ'=>'mme','っみ'=>'mmi','っも'=>'mmo','っむ'=>'mmu',
- 'っな'=>'nna','っね'=>'nne','っに'=>'nni','っの'=>'nno','っぬ'=>'nnu',
- 'っら'=>'rra','っれ'=>'rre','っり'=>'rri','っろ'=>'rro','っる'=>'rru',
- 'っさ'=>'ssa','っせ'=>'sse','っし'=>'sshi','っそ'=>'sso','っす'=>'ssu',
- 'っざ'=>'zza','っぜ'=>'zze','っじ'=>'jji','っぞ'=>'zzo','っず'=>'zzu',
-
- // 1 character syllabels
- 'あ'=>'a','え'=>'e','い'=>'i','お'=>'o','う'=>'u','ん'=>'n',
- 'は'=>'ha','へ'=>'he','ひ'=>'hi','ほ'=>'ho','ふ'=>'fu',
- 'ば'=>'ba','べ'=>'be','び'=>'bi','ぼ'=>'bo','ぶ'=>'bu',
- 'ぱ'=>'pa','ぺ'=>'pe','ぴ'=>'pi','ぽ'=>'po','ぷ'=>'pu',
- 'た'=>'ta','て'=>'te','ち'=>'chi','と'=>'to','つ'=>'tsu',
- 'だ'=>'da','で'=>'de','ぢ'=>'di','ど'=>'do','づ'=>'du',
- 'が'=>'ga','げ'=>'ge','ぎ'=>'gi','ご'=>'go','ぐ'=>'gu',
- 'か'=>'ka','け'=>'ke','き'=>'ki','こ'=>'ko','く'=>'ku',
- 'ま'=>'ma','め'=>'me','み'=>'mi','も'=>'mo','む'=>'mu',
- 'な'=>'na','ね'=>'ne','に'=>'ni','の'=>'no','ぬ'=>'nu',
- 'ら'=>'ra','れ'=>'re','り'=>'ri','ろ'=>'ro','る'=>'ru',
- 'さ'=>'sa','せ'=>'se','し'=>'shi','そ'=>'so','す'=>'su',
- 'わ'=>'wa','を'=>'wo',
- 'ざ'=>'za','ぜ'=>'ze','じ'=>'ji','ぞ'=>'zo','ず'=>'zu',
- 'や'=>'ya','よ'=>'yo','ゆ'=>'yu',
- // old characters
- 'ゑ'=>'we','ゐ'=>'wi',
-
- // convert what's left (probably only kicks in when something's missing above)
- // 'ぁ'=>'a','ぇ'=>'e','ぃ'=>'i','ぉ'=>'o','ぅ'=>'u',
- // 'ゃ'=>'ya','ょ'=>'yo','ゅ'=>'yu',
-
- // never seen one of those (disabled for the moment)
- // 'ヴぁ'=>'va','ヴぇ'=>'ve','ヴぃ'=>'vi','ヴぉ'=>'vo','ヴ'=>'vu',
- // 'でゃ'=>'dha','でぇ'=>'dhe','でぃ'=>'dhi','でょ'=>'dho','でゅ'=>'dhu',
- // 'どぁ'=>'dwa','どぇ'=>'dwe','どぃ'=>'dwi','どぉ'=>'dwo','どぅ'=>'dwu',
- // 'ぢゃ'=>'dya','ぢぇ'=>'dye','ぢぃ'=>'dyi','ぢょ'=>'dyo','ぢゅ'=>'dyu',
- // 'ふぁ'=>'fwa','ふぇ'=>'fwe','ふぃ'=>'fwi','ふぉ'=>'fwo','ふぅ'=>'fwu',
- // 'ふゃ'=>'fya','ふぇ'=>'fye','ふぃ'=>'fyi','ふょ'=>'fyo','ふゅ'=>'fyu',
- // 'すぁ'=>'swa','すぇ'=>'swe','すぃ'=>'swi','すぉ'=>'swo','すぅ'=>'swu',
- // 'てゃ'=>'tha','てぇ'=>'the','てぃ'=>'thi','てょ'=>'tho','てゅ'=>'thu',
- // 'つゃ'=>'tsa','つぇ'=>'tse','つぃ'=>'tsi','つょ'=>'tso','つ'=>'tsu',
- // 'とぁ'=>'twa','とぇ'=>'twe','とぃ'=>'twi','とぉ'=>'two','とぅ'=>'twu',
- // 'ヴゃ'=>'vya','ヴぇ'=>'vye','ヴぃ'=>'vyi','ヴょ'=>'vyo','ヴゅ'=>'vyu',
- // 'うぁ'=>'wha','うぇ'=>'whe','うぃ'=>'whi','うぉ'=>'who','うぅ'=>'whu',
- // 'じゃ'=>'zha','じぇ'=>'zhe','じぃ'=>'zhi','じょ'=>'zho','じゅ'=>'zhu',
- // 'じゃ'=>'zya','じぇ'=>'zye','じぃ'=>'zyi','じょ'=>'zyo','じゅ'=>'zyu',
-
- // 'spare' characters from other romanization systems
- // 'だ'=>'da','で'=>'de','ぢ'=>'di','ど'=>'do','づ'=>'du',
- // 'ら'=>'la','れ'=>'le','り'=>'li','ろ'=>'lo','る'=>'lu',
- // 'さ'=>'sa','せ'=>'se','し'=>'si','そ'=>'so','す'=>'su',
- // 'ちゃ'=>'cya','ちぇ'=>'cye','ちぃ'=>'cyi','ちょ'=>'cyo','ちゅ'=>'cyu',
- //'じゃ'=>'jya','じぇ'=>'jye','じぃ'=>'jyi','じょ'=>'jyo','じゅ'=>'jyu',
- //'りゃ'=>'lya','りぇ'=>'lye','りぃ'=>'lyi','りょ'=>'lyo','りゅ'=>'lyu',
- //'しゃ'=>'sya','しぇ'=>'sye','しぃ'=>'syi','しょ'=>'syo','しゅ'=>'syu',
- //'ちゃ'=>'tya','ちぇ'=>'tye','ちぃ'=>'tyi','ちょ'=>'tyo','ちゅ'=>'tyu',
- //'し'=>'ci',,い'=>'yi','ぢ'=>'dzi',
- //'っじゃ'=>'jja','っじぇ'=>'jje','っじ'=>'jji','っじょ'=>'jjo','っじゅ'=>'jju',
-
-
- // Japanese katakana
-
- // 4 character syllables: ッ doubles the consonant after, ー doubles the vowel before (usualy written with macron, but we don't want that in our URLs)
- 'ッビャー'=>'bbyaa','ッビェー'=>'bbyee','ッビィー'=>'bbyii','ッビョー'=>'bbyoo','ッビュー'=>'bbyuu',
- 'ッピャー'=>'ppyaa','ッピェー'=>'ppyee','ッピィー'=>'ppyii','ッピョー'=>'ppyoo','ッピュー'=>'ppyuu',
- 'ッキャー'=>'kkyaa','ッキェー'=>'kkyee','ッキィー'=>'kkyii','ッキョー'=>'kkyoo','ッキュー'=>'kkyuu',
- 'ッギャー'=>'ggyaa','ッギェー'=>'ggyee','ッギィー'=>'ggyii','ッギョー'=>'ggyoo','ッギュー'=>'ggyuu',
- 'ッミャー'=>'mmyaa','ッミェー'=>'mmyee','ッミィー'=>'mmyii','ッミョー'=>'mmyoo','ッミュー'=>'mmyuu',
- 'ッニャー'=>'nnyaa','ッニェー'=>'nnyee','ッニィー'=>'nnyii','ッニョー'=>'nnyoo','ッニュー'=>'nnyuu',
- 'ッリャー'=>'rryaa','ッリェー'=>'rryee','ッリィー'=>'rryii','ッリョー'=>'rryoo','ッリュー'=>'rryuu',
- 'ッシャー'=>'sshaa','ッシェー'=>'sshee','ッシー'=>'sshii','ッショー'=>'sshoo','ッシュー'=>'sshuu',
- 'ッチャー'=>'cchaa','ッチェー'=>'cchee','ッチー'=>'cchii','ッチョー'=>'cchoo','ッチュー'=>'cchuu',
- 'ッティー'=>'ttii',
- 'ッヂィー'=>'ddii',
-
- // 3 character syllables - doubled vowels
- 'ファー'=>'faa','フェー'=>'fee','フィー'=>'fii','フォー'=>'foo',
- 'フャー'=>'fyaa','フェー'=>'fyee','フィー'=>'fyii','フョー'=>'fyoo','フュー'=>'fyuu',
- 'ヒャー'=>'hyaa','ヒェー'=>'hyee','ヒィー'=>'hyii','ヒョー'=>'hyoo','ヒュー'=>'hyuu',
- 'ビャー'=>'byaa','ビェー'=>'byee','ビィー'=>'byii','ビョー'=>'byoo','ビュー'=>'byuu',
- 'ピャー'=>'pyaa','ピェー'=>'pyee','ピィー'=>'pyii','ピョー'=>'pyoo','ピュー'=>'pyuu',
- 'キャー'=>'kyaa','キェー'=>'kyee','キィー'=>'kyii','キョー'=>'kyoo','キュー'=>'kyuu',
- 'ギャー'=>'gyaa','ギェー'=>'gyee','ギィー'=>'gyii','ギョー'=>'gyoo','ギュー'=>'gyuu',
- 'ミャー'=>'myaa','ミェー'=>'myee','ミィー'=>'myii','ミョー'=>'myoo','ミュー'=>'myuu',
- 'ニャー'=>'nyaa','ニェー'=>'nyee','ニィー'=>'nyii','ニョー'=>'nyoo','ニュー'=>'nyuu',
- 'リャー'=>'ryaa','リェー'=>'ryee','リィー'=>'ryii','リョー'=>'ryoo','リュー'=>'ryuu',
- 'シャー'=>'shaa','シェー'=>'shee','シー'=>'shii','ショー'=>'shoo','シュー'=>'shuu',
- 'ジャー'=>'jaa','ジェー'=>'jee','ジー'=>'jii','ジョー'=>'joo','ジュー'=>'juu',
- 'スァー'=>'swaa','スェー'=>'swee','スィー'=>'swii','スォー'=>'swoo','スゥー'=>'swuu',
- 'デァー'=>'daa','デェー'=>'dee','ディー'=>'dii','デォー'=>'doo','デゥー'=>'duu',
- 'チャー'=>'chaa','チェー'=>'chee','チー'=>'chii','チョー'=>'choo','チュー'=>'chuu',
- 'ヂャー'=>'dyaa','ヂェー'=>'dyee','ヂィー'=>'dyii','ヂョー'=>'dyoo','ヂュー'=>'dyuu',
- 'ツャー'=>'tsaa','ツェー'=>'tsee','ツィー'=>'tsii','ツョー'=>'tsoo','ツー'=>'tsuu',
- 'トァー'=>'twaa','トェー'=>'twee','トィー'=>'twii','トォー'=>'twoo','トゥー'=>'twuu',
- 'ドァー'=>'dwaa','ドェー'=>'dwee','ドィー'=>'dwii','ドォー'=>'dwoo','ドゥー'=>'dwuu',
- 'ウァー'=>'whaa','ウェー'=>'whee','ウィー'=>'whii','ウォー'=>'whoo','ウゥー'=>'whuu',
- 'ヴャー'=>'vyaa','ヴェー'=>'vyee','ヴィー'=>'vyii','ヴョー'=>'vyoo','ヴュー'=>'vyuu',
- 'ヴァー'=>'vaa','ヴェー'=>'vee','ヴィー'=>'vii','ヴォー'=>'voo','ヴー'=>'vuu',
- 'ウェー'=>'wee','ウィー'=>'wii',
- 'イェー'=>'yee',
- 'ティー'=>'tii',
- 'ヂィー'=>'dii',
-
- // 3 character syllables - doubled consonants
- 'ッビャ'=>'bbya','ッビェ'=>'bbye','ッビィ'=>'bbyi','ッビョ'=>'bbyo','ッビュ'=>'bbyu',
- 'ッピャ'=>'ppya','ッピェ'=>'ppye','ッピィ'=>'ppyi','ッピョ'=>'ppyo','ッピュ'=>'ppyu',
- 'ッキャ'=>'kkya','ッキェ'=>'kkye','ッキィ'=>'kkyi','ッキョ'=>'kkyo','ッキュ'=>'kkyu',
- 'ッギャ'=>'ggya','ッギェ'=>'ggye','ッギィ'=>'ggyi','ッギョ'=>'ggyo','ッギュ'=>'ggyu',
- 'ッミャ'=>'mmya','ッミェ'=>'mmye','ッミィ'=>'mmyi','ッミョ'=>'mmyo','ッミュ'=>'mmyu',
- 'ッニャ'=>'nnya','ッニェ'=>'nnye','ッニィ'=>'nnyi','ッニョ'=>'nnyo','ッニュ'=>'nnyu',
- 'ッリャ'=>'rrya','ッリェ'=>'rrye','ッリィ'=>'rryi','ッリョ'=>'rryo','ッリュ'=>'rryu',
- 'ッシャ'=>'ssha','ッシェ'=>'sshe','ッシ'=>'sshi','ッショ'=>'ssho','ッシュ'=>'sshu',
- 'ッチャ'=>'ccha','ッチェ'=>'cche','ッチ'=>'cchi','ッチョ'=>'ccho','ッチュ'=>'cchu',
- 'ッティ'=>'tti',
- 'ッヂィ'=>'ddi',
-
- // 3 character syllables - doubled vowel and consonants
- 'ッバー'=>'bbaa','ッベー'=>'bbee','ッビー'=>'bbii','ッボー'=>'bboo','ッブー'=>'bbuu',
- 'ッパー'=>'ppaa','ッペー'=>'ppee','ッピー'=>'ppii','ッポー'=>'ppoo','ップー'=>'ppuu',
- 'ッケー'=>'kkee','ッキー'=>'kkii','ッコー'=>'kkoo','ックー'=>'kkuu','ッカー'=>'kkaa',
- 'ッガー'=>'ggaa','ッゲー'=>'ggee','ッギー'=>'ggii','ッゴー'=>'ggoo','ッグー'=>'gguu',
- 'ッマー'=>'maa','ッメー'=>'mee','ッミー'=>'mii','ッモー'=>'moo','ッムー'=>'muu',
- 'ッナー'=>'nnaa','ッネー'=>'nnee','ッニー'=>'nnii','ッノー'=>'nnoo','ッヌー'=>'nnuu',
- 'ッラー'=>'rraa','ッレー'=>'rree','ッリー'=>'rrii','ッロー'=>'rroo','ッルー'=>'rruu',
- 'ッサー'=>'ssaa','ッセー'=>'ssee','ッシー'=>'sshii','ッソー'=>'ssoo','ッスー'=>'ssuu',
- 'ッザー'=>'zzaa','ッゼー'=>'zzee','ッジー'=>'jjii','ッゾー'=>'zzoo','ッズー'=>'zzuu',
- 'ッター'=>'ttaa','ッテー'=>'ttee','ッチー'=>'chii','ットー'=>'ttoo','ッツー'=>'ttsuu',
- 'ッダー'=>'ddaa','ッデー'=>'ddee','ッヂー'=>'ddii','ッドー'=>'ddoo','ッヅー'=>'dduu',
-
- // 2 character syllables - normal
- 'ファ'=>'fa','フェ'=>'fe','フィ'=>'fi','フォ'=>'fo','フゥ'=>'fu',
- // 'フャ'=>'fya','フェ'=>'fye','フィ'=>'fyi','フョ'=>'fyo','フュ'=>'fyu',
- 'フャ'=>'fa','フェ'=>'fe','フィ'=>'fi','フョ'=>'fo','フュ'=>'fu',
- 'ヒャ'=>'hya','ヒェ'=>'hye','ヒィ'=>'hyi','ヒョ'=>'hyo','ヒュ'=>'hyu',
- 'ビャ'=>'bya','ビェ'=>'bye','ビィ'=>'byi','ビョ'=>'byo','ビュ'=>'byu',
- 'ピャ'=>'pya','ピェ'=>'pye','ピィ'=>'pyi','ピョ'=>'pyo','ピュ'=>'pyu',
- 'キャ'=>'kya','キェ'=>'kye','キィ'=>'kyi','キョ'=>'kyo','キュ'=>'kyu',
- 'ギャ'=>'gya','ギェ'=>'gye','ギィ'=>'gyi','ギョ'=>'gyo','ギュ'=>'gyu',
- 'ミャ'=>'mya','ミェ'=>'mye','ミィ'=>'myi','ミョ'=>'myo','ミュ'=>'myu',
- 'ニャ'=>'nya','ニェ'=>'nye','ニィ'=>'nyi','ニョ'=>'nyo','ニュ'=>'nyu',
- 'リャ'=>'rya','リェ'=>'rye','リィ'=>'ryi','リョ'=>'ryo','リュ'=>'ryu',
- 'シャ'=>'sha','シェ'=>'she','ショ'=>'sho','シュ'=>'shu',
- 'ジャ'=>'ja','ジェ'=>'je','ジョ'=>'jo','ジュ'=>'ju',
- 'スァ'=>'swa','スェ'=>'swe','スィ'=>'swi','スォ'=>'swo','スゥ'=>'swu',
- 'デァ'=>'da','デェ'=>'de','ディ'=>'di','デォ'=>'do','デゥ'=>'du',
- 'チャ'=>'cha','チェ'=>'che','チ'=>'chi','チョ'=>'cho','チュ'=>'chu',
- // 'ヂャ'=>'dya','ヂェ'=>'dye','ヂィ'=>'dyi','ヂョ'=>'dyo','ヂュ'=>'dyu',
- 'ツャ'=>'tsa','ツェ'=>'tse','ツィ'=>'tsi','ツョ'=>'tso','ツ'=>'tsu',
- 'トァ'=>'twa','トェ'=>'twe','トィ'=>'twi','トォ'=>'two','トゥ'=>'twu',
- 'ドァ'=>'dwa','ドェ'=>'dwe','ドィ'=>'dwi','ドォ'=>'dwo','ドゥ'=>'dwu',
- 'ウァ'=>'wha','ウェ'=>'whe','ウィ'=>'whi','ウォ'=>'who','ウゥ'=>'whu',
- 'ヴャ'=>'vya','ヴェ'=>'vye','ヴィ'=>'vyi','ヴョ'=>'vyo','ヴュ'=>'vyu',
- 'ヴァ'=>'va','ヴェ'=>'ve','ヴィ'=>'vi','ヴォ'=>'vo','ヴ'=>'vu',
- 'ウェ'=>'we','ウィ'=>'wi',
- 'イェ'=>'ye',
- 'ティ'=>'ti',
- 'ヂィ'=>'di',
-
- // 2 character syllables - doubled vocal
- 'アー'=>'aa','エー'=>'ee','イー'=>'ii','オー'=>'oo','ウー'=>'uu',
- 'ダー'=>'daa','デー'=>'dee','ヂー'=>'dii','ドー'=>'doo','ヅー'=>'duu',
- 'ハー'=>'haa','ヘー'=>'hee','ヒー'=>'hii','ホー'=>'hoo','フー'=>'fuu',
- 'バー'=>'baa','ベー'=>'bee','ビー'=>'bii','ボー'=>'boo','ブー'=>'buu',
- 'パー'=>'paa','ペー'=>'pee','ピー'=>'pii','ポー'=>'poo','プー'=>'puu',
- 'ケー'=>'kee','キー'=>'kii','コー'=>'koo','クー'=>'kuu','カー'=>'kaa',
- 'ガー'=>'gaa','ゲー'=>'gee','ギー'=>'gii','ゴー'=>'goo','グー'=>'guu',
- 'マー'=>'maa','メー'=>'mee','ミー'=>'mii','モー'=>'moo','ムー'=>'muu',
- 'ナー'=>'naa','ネー'=>'nee','ニー'=>'nii','ノー'=>'noo','ヌー'=>'nuu',
- 'ラー'=>'raa','レー'=>'ree','リー'=>'rii','ロー'=>'roo','ルー'=>'ruu',
- 'サー'=>'saa','セー'=>'see','シー'=>'shii','ソー'=>'soo','スー'=>'suu',
- 'ザー'=>'zaa','ゼー'=>'zee','ジー'=>'jii','ゾー'=>'zoo','ズー'=>'zuu',
- 'ター'=>'taa','テー'=>'tee','チー'=>'chii','トー'=>'too','ツー'=>'tsuu',
- 'ワー'=>'waa','ヲー'=>'woo',
- 'ヤー'=>'yaa','ヨー'=>'yoo','ユー'=>'yuu',
- 'ヵー'=>'kaa','ヶー'=>'kee',
- // old characters
- 'ヱー'=>'wee','ヰー'=>'wii',
-
- // seperate katakana 'n'
- 'ンア'=>'n_a','ンエ'=>'n_e','ンイ'=>'n_i','ンオ'=>'n_o','ンウ'=>'n_u',
- 'ンヤ'=>'n_ya','ンヨ'=>'n_yo','ンユ'=>'n_yu',
-
- // 2 character syllables - doubled consonants
- 'ッバ'=>'bba','ッベ'=>'bbe','ッビ'=>'bbi','ッボ'=>'bbo','ッブ'=>'bbu',
- 'ッパ'=>'ppa','ッペ'=>'ppe','ッピ'=>'ppi','ッポ'=>'ppo','ップ'=>'ppu',
- 'ッケ'=>'kke','ッキ'=>'kki','ッコ'=>'kko','ック'=>'kku','ッカ'=>'kka',
- 'ッガ'=>'gga','ッゲ'=>'gge','ッギ'=>'ggi','ッゴ'=>'ggo','ッグ'=>'ggu',
- 'ッマ'=>'ma','ッメ'=>'me','ッミ'=>'mi','ッモ'=>'mo','ッム'=>'mu',
- 'ッナ'=>'nna','ッネ'=>'nne','ッニ'=>'nni','ッノ'=>'nno','ッヌ'=>'nnu',
- 'ッラ'=>'rra','ッレ'=>'rre','ッリ'=>'rri','ッロ'=>'rro','ッル'=>'rru',
- 'ッサ'=>'ssa','ッセ'=>'sse','ッシ'=>'sshi','ッソ'=>'sso','ッス'=>'ssu',
- 'ッザ'=>'zza','ッゼ'=>'zze','ッジ'=>'jji','ッゾ'=>'zzo','ッズ'=>'zzu',
- 'ッタ'=>'tta','ッテ'=>'tte','ッチ'=>'cchi','ット'=>'tto','ッツ'=>'ttsu',
- 'ッダ'=>'dda','ッデ'=>'dde','ッヂ'=>'ddi','ッド'=>'ddo','ッヅ'=>'ddu',
-
- // 1 character syllables
- 'ア'=>'a','エ'=>'e','イ'=>'i','オ'=>'o','ウ'=>'u','ン'=>'n',
- 'ハ'=>'ha','ヘ'=>'he','ヒ'=>'hi','ホ'=>'ho','フ'=>'fu',
- 'バ'=>'ba','ベ'=>'be','ビ'=>'bi','ボ'=>'bo','ブ'=>'bu',
- 'パ'=>'pa','ペ'=>'pe','ピ'=>'pi','ポ'=>'po','プ'=>'pu',
- 'ケ'=>'ke','キ'=>'ki','コ'=>'ko','ク'=>'ku','カ'=>'ka',
- 'ガ'=>'ga','ゲ'=>'ge','ギ'=>'gi','ゴ'=>'go','グ'=>'gu',
- 'マ'=>'ma','メ'=>'me','ミ'=>'mi','モ'=>'mo','ム'=>'mu',
- 'ナ'=>'na','ネ'=>'ne','ニ'=>'ni','ノ'=>'no','ヌ'=>'nu',
- 'ラ'=>'ra','レ'=>'re','リ'=>'ri','ロ'=>'ro','ル'=>'ru',
- 'サ'=>'sa','セ'=>'se','シ'=>'shi','ソ'=>'so','ス'=>'su',
- 'ザ'=>'za','ゼ'=>'ze','ジ'=>'ji','ゾ'=>'zo','ズ'=>'zu',
- 'タ'=>'ta','テ'=>'te','チ'=>'chi','ト'=>'to','ツ'=>'tsu',
- 'ダ'=>'da','デ'=>'de','ヂ'=>'di','ド'=>'do','ヅ'=>'du',
- 'ワ'=>'wa','ヲ'=>'wo',
- 'ヤ'=>'ya','ヨ'=>'yo','ユ'=>'yu',
- 'ヵ'=>'ka','ヶ'=>'ke',
- // old characters
- 'ヱ'=>'we','ヰ'=>'wi',
-
- // convert what's left (probably only kicks in when something's missing above)
- 'ァ'=>'a','ェ'=>'e','ィ'=>'i','ォ'=>'o','ゥ'=>'u',
- 'ャ'=>'ya','ョ'=>'yo','ュ'=>'yu',
-
- // special characters
- '・'=>'_','、'=>'_',
- 'ー'=>'_', // when used with hiragana (seldom), this character would not be converted otherwise
-
- // 'ラ'=>'la','レ'=>'le','リ'=>'li','ロ'=>'lo','ル'=>'lu',
- // 'チャ'=>'cya','チェ'=>'cye','チィ'=>'cyi','チョ'=>'cyo','チュ'=>'cyu',
- //'デャ'=>'dha','デェ'=>'dhe','ディ'=>'dhi','デョ'=>'dho','デュ'=>'dhu',
- // 'リャ'=>'lya','リェ'=>'lye','リィ'=>'lyi','リョ'=>'lyo','リュ'=>'lyu',
- // 'テャ'=>'tha','テェ'=>'the','ティ'=>'thi','テョ'=>'tho','テュ'=>'thu',
- //'ファ'=>'fwa','フェ'=>'fwe','フィ'=>'fwi','フォ'=>'fwo','フゥ'=>'fwu',
- //'チャ'=>'tya','チェ'=>'tye','チィ'=>'tyi','チョ'=>'tyo','チュ'=>'tyu',
- // 'ジャ'=>'jya','ジェ'=>'jye','ジィ'=>'jyi','ジョ'=>'jyo','ジュ'=>'jyu',
- // 'ジャ'=>'zha','ジェ'=>'zhe','ジィ'=>'zhi','ジョ'=>'zho','ジュ'=>'zhu',
- //'ジャ'=>'zya','ジェ'=>'zye','ジィ'=>'zyi','ジョ'=>'zyo','ジュ'=>'zyu',
- //'シャ'=>'sya','シェ'=>'sye','シィ'=>'syi','ショ'=>'syo','シュ'=>'syu',
- //'シ'=>'ci','フ'=>'hu',シ'=>'si','チ'=>'ti','ツ'=>'tu','イ'=>'yi','ヂ'=>'dzi',
-
- // "Greeklish"
- 'Γ'=>'G','Δ'=>'E','Θ'=>'Th','Λ'=>'L','Ξ'=>'X','Π'=>'P','Σ'=>'S','Φ'=>'F','Ψ'=>'Ps',
- 'γ'=>'g','δ'=>'e','θ'=>'th','λ'=>'l','ξ'=>'x','π'=>'p','σ'=>'s','φ'=>'f','ψ'=>'ps',
-
- // Thai
- 'ก'=>'k','ข'=>'kh','ฃ'=>'kh','ค'=>'kh','ฅ'=>'kh','ฆ'=>'kh','ง'=>'ng','จ'=>'ch',
- 'ฉ'=>'ch','ช'=>'ch','ซ'=>'s','ฌ'=>'ch','ญ'=>'y','ฎ'=>'d','ฏ'=>'t','ฐ'=>'th',
- 'ฑ'=>'d','ฒ'=>'th','ณ'=>'n','ด'=>'d','ต'=>'t','ถ'=>'th','ท'=>'th','ธ'=>'th',
- 'น'=>'n','บ'=>'b','ป'=>'p','ผ'=>'ph','ฝ'=>'f','พ'=>'ph','ฟ'=>'f','ภ'=>'ph',
- 'ม'=>'m','ย'=>'y','ร'=>'r','ฤ'=>'rue','ฤๅ'=>'rue','ล'=>'l','ฦ'=>'lue',
- 'ฦๅ'=>'lue','ว'=>'w','ศ'=>'s','ษ'=>'s','ส'=>'s','ห'=>'h','ฬ'=>'l','ฮ'=>'h',
- 'ะ'=>'a','ั'=>'a','รร'=>'a','า'=>'a','ๅ'=>'a','ำ'=>'am','ํา'=>'am',
- 'ิ'=>'i','ี'=>'i','ึ'=>'ue','ี'=>'ue','ุ'=>'u','ู'=>'u',
- 'เ'=>'e','แ'=>'ae','โ'=>'o','อ'=>'o',
- 'ียะ'=>'ia','ีย'=>'ia','ือะ'=>'uea','ือ'=>'uea','ัวะ'=>'ua','ัว'=>'ua',
- 'ใ'=>'ai','ไ'=>'ai','ัย'=>'ai','าย'=>'ai','าว'=>'ao',
- 'ุย'=>'ui','อย'=>'oi','ือย'=>'ueai','วย'=>'uai',
- 'ิว'=>'io','็ว'=>'eo','ียว'=>'iao',
- '่'=>'','้'=>'','๊'=>'','๋'=>'','็'=>'',
- '์'=>'','๎'=>'','ํ'=>'','ฺ'=>'',
- 'ๆ'=>'2','๏'=>'o','ฯ'=>'-','๚'=>'-','๛'=>'-',
- '๐'=>'0','๑'=>'1','๒'=>'2','๓'=>'3','๔'=>'4',
- '๕'=>'5','๖'=>'6','๗'=>'7','๘'=>'8','๙'=>'9',
-
- // Korean
- 'ㄱ'=>'k','ㅋ'=>'kh','ㄲ'=>'kk','ㄷ'=>'t','ㅌ'=>'th','ㄸ'=>'tt','ㅂ'=>'p',
- 'ㅍ'=>'ph','ㅃ'=>'pp','ㅈ'=>'c','ㅊ'=>'ch','ㅉ'=>'cc','ㅅ'=>'s','ㅆ'=>'ss',
- 'ㅎ'=>'h','ㅇ'=>'ng','ㄴ'=>'n','ㄹ'=>'l','ㅁ'=>'m', 'ㅏ'=>'a','ㅓ'=>'e','ㅗ'=>'o',
- 'ㅜ'=>'wu','ㅡ'=>'u','ㅣ'=>'i','ㅐ'=>'ay','ㅔ'=>'ey','ㅚ'=>'oy','ㅘ'=>'wa','ㅝ'=>'we',
- 'ㅟ'=>'wi','ㅙ'=>'way','ㅞ'=>'wey','ㅢ'=>'uy','ㅑ'=>'ya','ㅕ'=>'ye','ㅛ'=>'oy',
- 'ㅠ'=>'yu','ㅒ'=>'yay','ㅖ'=>'yey',
-);
-
-
diff --git a/install.php b/install.php
index 64f60c51f..eecdac6d7 100644
--- a/install.php
+++ b/install.php
@@ -95,8 +95,11 @@ header('Content-Type: text/html; charset=utf-8');
print "</div>\n";
}
?>
- <a style="background: transparent url(data/dont-panic-if-you-see-this-in-your-logs-it-means-your-directory-permissions-are-correct.png) left top no-repeat;
- display: block; width:380px; height:73px; border:none; clear:both;"
+ <a style="
+ background: transparent
+ url(data/dont-panic-if-you-see-this-in-your-logs-it-means-your-directory-permissions-are-correct.png)
+ left top no-repeat;
+ display: block; width:380px; height:73px; border:none; clear:both;"
target="_blank"
href="http://www.dokuwiki.org/security#web_access_security"></a>
</div>
@@ -170,10 +173,12 @@ function print_form($d){
<fieldset id="acldep">
<label for="superuser"><?php echo $lang['i_superuser']?></label>
- <input class="text" type="text" name="d[superuser]" id="superuser" value="<?php echo $d['superuser'] ?>" />
+ <input class="text" type="text" name="d[superuser]" id="superuser"
+ value="<?php echo $d['superuser'] ?>" />
<label for="fullname"><?php echo $lang['fullname']?></label>
- <input class="text" type="text" name="d[fullname]" id="fullname" value="<?php echo $d['fullname'] ?>" />
+ <input class="text" type="text" name="d[fullname]" id="fullname"
+ value="<?php echo $d['fullname'] ?>" />
<label for="email"><?php echo $lang['email']?></label>
<input class="text" type="text" name="d[email]" id="email" value="<?php echo $d['email'] ?>" />
@@ -186,13 +191,17 @@ function print_form($d){
<label for="policy"><?php echo $lang['i_policy']?></label>
<select class="text" name="d[policy]" id="policy">
- <option value="0" <?php echo ($d['policy'] == 0)?'selected="selected"':'' ?>><?php echo $lang['i_pol0']?></option>
- <option value="1" <?php echo ($d['policy'] == 1)?'selected="selected"':'' ?>><?php echo $lang['i_pol1']?></option>
- <option value="2" <?php echo ($d['policy'] == 2)?'selected="selected"':'' ?>><?php echo $lang['i_pol2']?></option>
+ <option value="0" <?php echo ($d['policy'] == 0)?'selected="selected"':'' ?>><?php
+ echo $lang['i_pol0']?></option>
+ <option value="1" <?php echo ($d['policy'] == 1)?'selected="selected"':'' ?>><?php
+ echo $lang['i_pol1']?></option>
+ <option value="2" <?php echo ($d['policy'] == 2)?'selected="selected"':'' ?>><?php
+ echo $lang['i_pol2']?></option>
</select>
<label for="allowreg">
- <input type="checkbox" name="d[allowreg]" id="allowreg" <?php echo(($d['allowreg'] ? ' checked="checked"' : ''));?> />
+ <input type="checkbox" name="d[allowreg]" id="allowreg" <?php
+ echo(($d['allowreg'] ? ' checked="checked"' : ''));?> />
<?php echo $lang['i_allowreg']?>
</label>
</fieldset>
@@ -217,8 +226,10 @@ function print_form($d){
<fieldset>
<p><?php echo $lang['i_pop_field']?></p>
<label for="pop">
- <input type="checkbox" name="d[pop]" id="pop" <?php echo(($d['pop'] ? ' checked="checked"' : ''));?> />
- <?php echo $lang['i_pop_label']?> <a href="http://www.dokuwiki.org/popularity" target="_blank"><sup>[?]</sup></a>
+ <input type="checkbox" name="d[pop]" id="pop" <?php
+ echo(($d['pop'] ? ' checked="checked"' : ''));?> />
+ <?php echo $lang['i_pop_label']?>
+ <a href="http://www.dokuwiki.org/popularity" target="_blank"><sup>[?]</sup></a>
</label>
</fieldset>
@@ -366,7 +377,7 @@ EOT;
if ($d['acl']) {
// hash the password
- $phash = new PassHash();
+ $phash = new \dokuwiki\PassHash();
$pass = $phash->hash_smd5($d['password']);
// create users.auth.php
diff --git a/lib/exe/css.php b/lib/exe/css.php
index 19ae5570e..40de4b828 100644
--- a/lib/exe/css.php
+++ b/lib/exe/css.php
@@ -6,7 +6,10 @@
* @author Andreas Gohr <andi@splitbrain.org>
*/
-if(!defined('DOKU_INC')) define('DOKU_INC',dirname(__FILE__).'/../../');
+use dokuwiki\Cache\Cache;
+use dokuwiki\Extension\Event;
+
+if(!defined('DOKU_INC')) define('DOKU_INC', __DIR__ .'/../../');
if(!defined('NOSESSION')) define('NOSESSION',true); // we do not use a session or authentication here (better caching)
if(!defined('DOKU_DISABLE_GZIP_OUTPUT')) define('DOKU_DISABLE_GZIP_OUTPUT',1); // we gzip ourself here
if(!defined('NL')) define('NL',"\n");
@@ -67,7 +70,8 @@ function css_out(){
// load jQuery-UI theme
if ($mediatype == 'screen') {
- $files[DOKU_INC.'lib/scripts/jquery/jquery-ui-theme/smoothness.css'] = DOKU_BASE.'lib/scripts/jquery/jquery-ui-theme/';
+ $files[DOKU_INC.'lib/scripts/jquery/jquery-ui-theme/smoothness.css'] =
+ DOKU_BASE.'lib/scripts/jquery/jquery-ui-theme/';
}
// load plugin styles
$files = array_merge($files, css_pluginstyles($mediatype));
@@ -84,7 +88,7 @@ function css_out(){
// Let plugins decide to either put more styles here or to remove some
$media_files[$mediatype] = css_filewrapper($mediatype, $files);
- $CSSEvt = new Doku_Event('CSS_STYLES_INCLUDED', $media_files[$mediatype]);
+ $CSSEvt = new Event('CSS_STYLES_INCLUDED', $media_files[$mediatype]);
// Make it preventable.
if ( $CSSEvt->advise_before() ) {
@@ -99,8 +103,17 @@ function css_out(){
}
// The generated script depends on some dynamic options
- $cache = new cache('styles'.$_SERVER['HTTP_HOST'].$_SERVER['SERVER_PORT'].$INPUT->bool('preview').DOKU_BASE.$tpl.$type,'.css');
- $cache->_event = 'CSS_CACHE_USE';
+ $cache = new Cache(
+ 'styles' .
+ $_SERVER['HTTP_HOST'] .
+ $_SERVER['SERVER_PORT'] .
+ $INPUT->bool('preview') .
+ DOKU_BASE .
+ $tpl .
+ $type,
+ '.css'
+ );
+ $cache->setEvent('CSS_CACHE_USE');
// check cache age & handle conditional request
// This may exit if a cache can be used
@@ -114,7 +127,7 @@ function css_out(){
// plugins decide whether to include the DW default styles.
// This can be done by preventing the Default.
$media_files['DW_DEFAULT'] = css_filewrapper('DW_DEFAULT');
- trigger_event('CSS_STYLES_INCLUDED', $media_files['DW_DEFAULT'], 'css_defaultstyles');
+ Event::createAndTrigger('CSS_STYLES_INCLUDED', $media_files['DW_DEFAULT'], 'css_defaultstyles');
// build the stylesheet
foreach ($mediatypes as $mediatype) {
@@ -454,18 +467,13 @@ class DokuCssFile {
*/
public function replacements($match) {
- // not a relative url? - no adjustment required
- if (preg_match('#^(/|data:|https?://)#',$match[3])) {
+ if (preg_match('#^(/|data:|https?://)#', $match[3])) { // not a relative url? - no adjustment required
return $match[0];
- }
- // a less file import? - requires a file system location
- else if (substr($match[3],-5) == '.less') {
+ } elseif (substr($match[3], -5) == '.less') { // a less file import? - requires a file system location
if ($match[3]{0} != '/') {
$match[3] = $this->getRelativePath() . '/' . $match[3];
}
- }
- // everything else requires a url adjustment
- else {
+ } else { // everything else requires a url adjustment
$match[3] = $this->location . $match[3];
}
@@ -547,18 +555,50 @@ function css_compress($css){
$css = preg_replace('/ ?: /',':',$css);
// number compression
- $css = preg_replace('/([: ])0+(\.\d+?)0*((?:pt|pc|in|mm|cm|em|ex|px)\b|%)(?=[^\{]*[;\}])/', '$1$2$3', $css); // "0.1em" to ".1em", "1.10em" to "1.1em"
- $css = preg_replace('/([: ])\.(0)+((?:pt|pc|in|mm|cm|em|ex|px)\b|%)(?=[^\{]*[;\}])/', '$1$2', $css); // ".0em" to "0"
- $css = preg_replace('/([: ]0)0*(\.0*)?((?:pt|pc|in|mm|cm|em|ex|px)(?=[^\{]*[;\}])\b|%)/', '$1', $css); // "0.0em" to "0"
- $css = preg_replace('/([: ]\d+)(\.0*)((?:pt|pc|in|mm|cm|em|ex|px)(?=[^\{]*[;\}])\b|%)/', '$1$3', $css); // "1.0em" to "1em"
- $css = preg_replace('/([: ])0+(\d+|\d*\.\d+)((?:pt|pc|in|mm|cm|em|ex|px)(?=[^\{]*[;\}])\b|%)/', '$1$2$3', $css); // "001em" to "1em"
+ $css = preg_replace(
+ '/([: ])0+(\.\d+?)0*((?:pt|pc|in|mm|cm|em|ex|px)\b|%)(?=[^\{]*[;\}])/',
+ '$1$2$3',
+ $css
+ ); // "0.1em" to ".1em", "1.10em" to "1.1em"
+ $css = preg_replace(
+ '/([: ])\.(0)+((?:pt|pc|in|mm|cm|em|ex|px)\b|%)(?=[^\{]*[;\}])/',
+ '$1$2',
+ $css
+ ); // ".0em" to "0"
+ $css = preg_replace(
+ '/([: ]0)0*(\.0*)?((?:pt|pc|in|mm|cm|em|ex|px)(?=[^\{]*[;\}])\b|%)/',
+ '$1',
+ $css
+ ); // "0.0em" to "0"
+ $css = preg_replace(
+ '/([: ]\d+)(\.0*)((?:pt|pc|in|mm|cm|em|ex|px)(?=[^\{]*[;\}])\b|%)/',
+ '$1$3',
+ $css
+ ); // "1.0em" to "1em"
+ $css = preg_replace(
+ '/([: ])0+(\d+|\d*\.\d+)((?:pt|pc|in|mm|cm|em|ex|px)(?=[^\{]*[;\}])\b|%)/',
+ '$1$2$3',
+ $css
+ ); // "001em" to "1em"
// shorten attributes (1em 1em 1em 1em -> 1em)
- $css = preg_replace('/(?<![\w\-])((?:margin|padding|border|border-(?:width|radius)):)([\w\.]+)( \2)+(?=[;\}]| !)/', '$1$2', $css); // "1em 1em 1em 1em" to "1em"
- $css = preg_replace('/(?<![\w\-])((?:margin|padding|border|border-(?:width)):)([\w\.]+) ([\w\.]+) \2 \3(?=[;\}]| !)/', '$1$2 $3', $css); // "1em 2em 1em 2em" to "1em 2em"
+ $css = preg_replace(
+ '/(?<![\w\-])((?:margin|padding|border|border-(?:width|radius)):)([\w\.]+)( \2)+(?=[;\}]| !)/',
+ '$1$2',
+ $css
+ ); // "1em 1em 1em 1em" to "1em"
+ $css = preg_replace(
+ '/(?<![\w\-])((?:margin|padding|border|border-(?:width)):)([\w\.]+) ([\w\.]+) \2 \3(?=[;\}]| !)/',
+ '$1$2 $3',
+ $css
+ ); // "1em 2em 1em 2em" to "1em 2em"
// shorten colors
- $css = preg_replace("/#([0-9a-fA-F]{1})\\1([0-9a-fA-F]{1})\\2([0-9a-fA-F]{1})\\3(?=[^\{]*[;\}])/", "#\\1\\2\\3", $css);
+ $css = preg_replace(
+ "/#([0-9a-fA-F]{1})\\1([0-9a-fA-F]{1})\\2([0-9a-fA-F]{1})\\3(?=[^\{]*[;\}])/",
+ "#\\1\\2\\3",
+ $css
+ );
return $css;
}
diff --git a/lib/exe/detail.php b/lib/exe/detail.php
index ec1a9b874..a6cffa770 100644
--- a/lib/exe/detail.php
+++ b/lib/exe/detail.php
@@ -1,4 +1,7 @@
<?php
+
+use dokuwiki\Extension\Event;
+
if(!defined('DOKU_INC')) define('DOKU_INC',dirname(__FILE__).'/../../');
define('DOKU_MEDIADETAIL',1);
require_once(DOKU_INC.'inc/init.php');
@@ -12,31 +15,17 @@ $REV = $INPUT->int('rev');
$INFO = array_merge(pageinfo(),mediainfo());
$tmp = array();
-trigger_event('DETAIL_STARTED', $tmp);
+Event::createAndTrigger('DETAIL_STARTED', $tmp);
//close session
session_write_close();
-if($conf['allowdebug'] && $INPUT->has('debug')){
- print '<pre>';
- foreach(explode(' ','basedir userewrite baseurl useslash') as $x){
- print '$'."conf['$x'] = '".$conf[$x]."';\n";
- }
- foreach(explode(' ','DOCUMENT_ROOT HTTP_HOST SCRIPT_FILENAME PHP_SELF '.
- 'REQUEST_URI SCRIPT_NAME PATH_INFO PATH_TRANSLATED') as $x){
- print '$'."_SERVER['$x'] = '".$_SERVER[$x]."';\n";
- }
- print "getID('media'): ".getID('media')."\n";
- print "getID('media',false): ".getID('media',false)."\n";
- print '</pre>';
-}
-
$ERROR = false;
// check image permissions
$AUTH = auth_quickaclcheck($IMG);
if($AUTH >= AUTH_READ){
// check if image exists
- $SRC = mediaFN($IMG,$REV);
+ $SRC = mediaFN($IMG,$REV);
if(!file_exists($SRC)){
//doesn't exist!
http_status(404);
diff --git a/lib/exe/fetch.php b/lib/exe/fetch.php
index 933367e35..5c5ae899b 100644
--- a/lib/exe/fetch.php
+++ b/lib/exe/fetch.php
@@ -6,6 +6,8 @@
* @author Andreas Gohr <andi@splitbrain.org>
*/
+use dokuwiki\Extension\Event;
+
if(!defined('DOKU_INC')) define('DOKU_INC', dirname(__FILE__).'/../../');
if (!defined('DOKU_DISABLE_GZIP_OUTPUT')) define('DOKU_DISABLE_GZIP_OUTPUT', 1);
require_once(DOKU_INC.'inc/init.php');
@@ -14,7 +16,7 @@ session_write_close(); //close session
require_once(DOKU_INC.'inc/fetch.functions.php');
if (defined('SIMPLE_TEST')) {
- $INPUT = new Input();
+ $INPUT = new \dokuwiki\Input\Input();
}
// BEGIN main
@@ -56,7 +58,7 @@ if (defined('SIMPLE_TEST')) {
);
// handle the file status
- $evt = new Doku_Event('FETCH_MEDIA_STATUS', $data);
+ $evt = new Event('FETCH_MEDIA_STATUS', $data);
if($evt->advise_before()) {
// redirects
if($data['status'] > 300 && $data['status'] <= 304) {
@@ -87,7 +89,7 @@ if (defined('SIMPLE_TEST')) {
}
// finally send the file to the client
- $evt = new Doku_Event('MEDIA_SENDFILE', $data);
+ $evt = new Event('MEDIA_SENDFILE', $data);
if($evt->advise_before()) {
sendFile($data['file'], $data['mime'], $data['download'], $data['cache'], $data['ispublic'], $data['orig']);
}
diff --git a/lib/exe/jquery.php b/lib/exe/jquery.php
index f32aef7d3..13c0c1639 100644
--- a/lib/exe/jquery.php
+++ b/lib/exe/jquery.php
@@ -1,5 +1,7 @@
<?php
+use dokuwiki\Cache\Cache;
+
if(!defined('DOKU_INC')) define('DOKU_INC', dirname(__FILE__) . '/../../');
if(!defined('NOSESSION')) define('NOSESSION', true); // we do not use a session or authentication here (better caching)
if(!defined('NL')) define('NL', "\n");
@@ -19,7 +21,7 @@ jquery_out();
* uses cache or fills it
*/
function jquery_out() {
- $cache = new cache('jquery', '.js');
+ $cache = new Cache('jquery', '.js');
$files = array(
DOKU_INC . 'lib/scripts/jquery/jquery.min.js',
DOKU_INC . 'lib/scripts/jquery/jquery-ui.min.js',
diff --git a/lib/exe/js.php b/lib/exe/js.php
index 81afaf053..ae6a6366f 100644
--- a/lib/exe/js.php
+++ b/lib/exe/js.php
@@ -6,7 +6,10 @@
* @author Andreas Gohr <andi@splitbrain.org>
*/
-if(!defined('DOKU_INC')) define('DOKU_INC',dirname(__FILE__).'/../../');
+use dokuwiki\Cache\Cache;
+use dokuwiki\Extension\Event;
+
+if(!defined('DOKU_INC')) define('DOKU_INC', __DIR__ .'/../../');
if(!defined('NOSESSION')) define('NOSESSION',true); // we do not use a session or authentication here (better caching)
if(!defined('NL')) define('NL',"\n");
if(!defined('DOKU_DISABLE_GZIP_OUTPUT')) define('DOKU_DISABLE_GZIP_OUTPUT',1); // we gzip ourself here
@@ -73,11 +76,11 @@ function js_out(){
}
// Let plugins decide to either put more scripts here or to remove some
- trigger_event('JS_SCRIPT_LIST', $files);
+ Event::createAndTrigger('JS_SCRIPT_LIST', $files);
// The generated script depends on some dynamic options
- $cache = new cache('scripts'.$_SERVER['HTTP_HOST'].$_SERVER['SERVER_PORT'].md5(serialize($files)),'.js');
- $cache->_event = 'JS_CACHE_USE';
+ $cache = new Cache('scripts'.$_SERVER['HTTP_HOST'].$_SERVER['SERVER_PORT'].md5(serialize($files)),'.js');
+ $cache->setEvent('JS_CACHE_USE');
$cache_files = array_merge($files, getConfigFiles('main'));
$cache_files[] = __FILE__;
@@ -90,18 +93,21 @@ function js_out(){
// start output buffering and build the script
ob_start();
- $json = new JSON();
// add some global variables
print "var DOKU_BASE = '".DOKU_BASE."';";
print "var DOKU_TPL = '".tpl_basedir($tpl)."';";
- print "var DOKU_COOKIE_PARAM = " . $json->encode(
+ print "var DOKU_COOKIE_PARAM = " . json_encode(
array(
'path' => empty($conf['cookiedir']) ? DOKU_REL : $conf['cookiedir'],
'secure' => $conf['securecookie'] && is_ssl()
)).";";
// FIXME: Move those to JSINFO
- print "Object.defineProperty(window, 'DOKU_UHN', { get: function() { console.warn('Using DOKU_UHN is deprecated. Please use JSINFO.useHeadingNavigation instead'); return JSINFO.useHeadingNavigation; } });";
- print "Object.defineProperty(window, 'DOKU_UHC', { get: function() { console.warn('Using DOKU_UHC is deprecated. Please use JSINFO.useHeadingContent instead'); return JSINFO.useHeadingContent; } });";
+ print "Object.defineProperty(window, 'DOKU_UHN', { get: function() {".
+ "console.warn('Using DOKU_UHN is deprecated. Please use JSINFO.useHeadingNavigation instead');".
+ "return JSINFO.useHeadingNavigation; } });";
+ print "Object.defineProperty(window, 'DOKU_UHC', { get: function() {".
+ "console.warn('Using DOKU_UHC is deprecated. Please use JSINFO.useHeadingContent instead');".
+ "return JSINFO.useHeadingContent; } });";
// load JS specific translations
$lang['js']['plugins'] = js_pluginstrings();
@@ -109,7 +115,7 @@ function js_out(){
if(!empty($templatestrings)) {
$lang['js']['template'] = $templatestrings;
}
- echo 'LANG = '.$json->encode($lang['js']).";\n";
+ echo 'LANG = '.json_encode($lang['js']).";\n";
// load toolbar
toolbar_JSdefines('toolbar');
@@ -170,7 +176,7 @@ function js_load($file){
// is it a include_once?
if($match[1]){
- $base = utf8_basename($ifile);
+ $base = \dokuwiki\Utf8\PhpString::basename($ifile);
if(array_key_exists($base, $loaded) && $loaded[$base] === true){
$data = str_replace($match[0], '' ,$data);
continue;
diff --git a/lib/exe/mediamanager.php b/lib/exe/mediamanager.php
index 722254423..b43cff745 100644
--- a/lib/exe/mediamanager.php
+++ b/lib/exe/mediamanager.php
@@ -1,4 +1,7 @@
<?php
+
+use dokuwiki\Extension\Event;
+
if(!defined('DOKU_INC')) define('DOKU_INC',dirname(__FILE__).'/../../');
define('DOKU_MEDIAMANAGER',1);
@@ -38,7 +41,7 @@
$AUTH = $INFO['perm']; // shortcut for historical reasons
$tmp = array();
- trigger_event('MEDIAMANAGER_STARTED', $tmp);
+ Event::createAndTrigger('MEDIAMANAGER_STARTED', $tmp);
session_write_close(); //close session
// do not display the manager if user does not have read access
diff --git a/lib/exe/xmlrpc.php b/lib/exe/xmlrpc.php
index 3046f47e9..dc0438ee1 100644
--- a/lib/exe/xmlrpc.php
+++ b/lib/exe/xmlrpc.php
@@ -1,67 +1,15 @@
<?php
-if(!defined('DOKU_INC')) define('DOKU_INC',dirname(__FILE__).'/../../');
-
-require_once(DOKU_INC.'inc/init.php');
-session_write_close(); //close session
-
-if(!$conf['remote']) die((new IXR_Error(-32605, "XML-RPC server not enabled."))->getXml());
-
/**
- * Contains needed wrapper functions and registers all available
- * XMLRPC functions.
+ * XMLRPC API backend
*/
-class dokuwiki_xmlrpc_server extends IXR_Server {
- protected $remote;
-
- /**
- * Constructor. Register methods and run Server
- */
- public function __construct(){
- $this->remote = new RemoteAPI();
- $this->remote->setDateTransformation(array($this, 'toDate'));
- $this->remote->setFileTransformation(array($this, 'toFile'));
- parent::__construct();
- }
- /**
- * @param string $methodname
- * @param array $args
- * @return IXR_Error|mixed
- */
- public function call($methodname, $args){
- try {
- $result = $this->remote->call($methodname, $args);
- return $result;
- } catch (RemoteAccessDeniedException $e) {
- if (!isset($_SERVER['REMOTE_USER'])) {
- http_status(401);
- return new IXR_Error(-32603, "server error. not authorized to call method $methodname");
- } else {
- http_status(403);
- return new IXR_Error(-32604, "server error. forbidden to call the method $methodname");
- }
- } catch (RemoteException $e) {
- return new IXR_Error($e->getCode(), $e->getMessage());
- }
- }
+use dokuwiki\Remote\XmlRpcServer;
- /**
- * @param string|int $data iso date(yyyy[-]mm[-]dd[ hh:mm[:ss]]) or timestamp
- * @return IXR_Date
- */
- public function toDate($data) {
- return new IXR_Date($data);
- }
+if(!defined('DOKU_INC')) define('DOKU_INC', dirname(__FILE__).'/../../');
- /**
- * @param string $data
- * @return IXR_Base64
- */
- public function toFile($data) {
- return new IXR_Base64($data);
- }
-}
+require_once(DOKU_INC.'inc/init.php');
+session_write_close(); //close session
-$server = new dokuwiki_xmlrpc_server();
+if(!$conf['remote']) die((new IXR_Error(-32605, "XML-RPC server not enabled."))->getXml());
-// vim:ts=4:sw=4:et:
+$server = new XmlRpcServer();
diff --git a/lib/plugins/acl/action.php b/lib/plugins/acl/action.php
index 1d6d05b80..86e587093 100644
--- a/lib/plugins/acl/action.php
+++ b/lib/plugins/acl/action.php
@@ -6,13 +6,11 @@
* @author Andreas Gohr <andi@splitbrain.org>
*/
-// must be run within Dokuwiki
-if(!defined('DOKU_INC')) die();
-
/**
* Register handler
*/
-class action_plugin_acl extends DokuWiki_Action_Plugin {
+class action_plugin_acl extends DokuWiki_Action_Plugin
+{
/**
* Registers a callback function for a given event
@@ -20,10 +18,10 @@ class action_plugin_acl extends DokuWiki_Action_Plugin {
* @param Doku_Event_Handler $controller DokuWiki's event controller object
* @return void
*/
- public function register(Doku_Event_Handler $controller) {
-
- $controller->register_hook('AJAX_CALL_UNKNOWN', 'BEFORE', $this, 'handle_ajax_call_acl');
+ public function register(Doku_Event_Handler $controller)
+ {
+ $controller->register_hook('AJAX_CALL_UNKNOWN', 'BEFORE', $this, 'handleAjaxCallAcl');
}
/**
@@ -33,9 +31,9 @@ class action_plugin_acl extends DokuWiki_Action_Plugin {
* @param mixed $param empty
* @return void
*/
-
- public function handle_ajax_call_acl(Doku_Event $event, $param) {
- if($event->data !== 'plugin_acl') {
+ public function handleAjaxCallAcl(Doku_Event $event, $param)
+ {
+ if ($event->data !== 'plugin_acl') {
return;
}
$event->stopPropagation();
@@ -46,12 +44,11 @@ class action_plugin_acl extends DokuWiki_Action_Plugin {
/** @var $acl admin_plugin_acl */
$acl = plugin_load('admin', 'acl');
-
- if(!$acl->isAccessibleByCurrentUser()) {
+ if (!$acl->isAccessibleByCurrentUser()) {
echo 'for admins only';
return;
}
- if(!checkSecurityToken()) {
+ if (!checkSecurityToken()) {
echo 'CRSF Attack';
return;
}
@@ -62,26 +59,27 @@ class action_plugin_acl extends DokuWiki_Action_Plugin {
$ajax = $INPUT->str('ajax');
header('Content-Type: text/html; charset=utf-8');
- if($ajax == 'info') {
- $acl->_html_info();
- } elseif($ajax == 'tree') {
-
+ if ($ajax == 'info') {
+ $acl->printInfo();
+ } elseif ($ajax == 'tree') {
$ns = $INPUT->str('ns');
- if($ns == '*') {
+ if ($ns == '*') {
$ns = '';
}
$ns = cleanID($ns);
$lvl = count(explode(':', $ns));
$ns = utf8_encodeFN(str_replace(':', '/', $ns));
- $data = $acl->_get_tree($ns, $ns);
+ $data = $acl->makeTree($ns, $ns);
- foreach(array_keys($data) as $item) {
+ foreach (array_keys($data) as $item) {
$data[$item]['level'] = $lvl + 1;
}
echo html_buildlist(
- $data, 'acl', array($acl, '_html_list_acl'),
- array($acl, '_html_li_acl')
+ $data,
+ 'acl',
+ array($acl, 'makeTreeItem'),
+ array($acl, 'makeListItem')
);
}
}
diff --git a/lib/plugins/acl/admin.php b/lib/plugins/acl/admin.php
index 4ee0fde7e..b0b0ffc85 100644
--- a/lib/plugins/acl/admin.php
+++ b/lib/plugins/acl/admin.php
@@ -7,16 +7,15 @@
* @author Anika Henke <anika@selfthinker.org> (concepts)
* @author Frank Schubert <frank@schokilade.de> (old version)
*/
-// must be run within Dokuwiki
-if(!defined('DOKU_INC')) die();
/**
* All DokuWiki plugins to extend the admin function
* need to inherit from this class
*/
-class admin_plugin_acl extends DokuWiki_Admin_Plugin {
- var $acl = null;
- var $ns = null;
+class admin_plugin_acl extends DokuWiki_Admin_Plugin
+{
+ public $acl = null;
+ protected $ns = null;
/**
* The currently selected item, associative array with id and type.
* Populated from (in this order):
@@ -25,22 +24,24 @@ class admin_plugin_acl extends DokuWiki_Admin_Plugin {
* $ns
* $ID
*/
- var $current_item = null;
- var $who = '';
- var $usersgroups = array();
- var $specials = array();
+ protected $current_item = null;
+ protected $who = '';
+ protected $usersgroups = array();
+ protected $specials = array();
/**
* return prompt for admin menu
*/
- function getMenuText($language) {
+ public function getMenuText($language)
+ {
return $this->getLang('admin_acl');
}
/**
* return sort order for position in admin menu
*/
- function getMenuSort() {
+ public function getMenuSort()
+ {
return 1;
}
@@ -51,7 +52,8 @@ class admin_plugin_acl extends DokuWiki_Admin_Plugin {
*
* @author Andreas Gohr <andi@splitbrain.org>
*/
- function handle() {
+ public function handle()
+ {
global $AUTH_ACL;
global $ID;
global $auth;
@@ -62,9 +64,9 @@ class admin_plugin_acl extends DokuWiki_Admin_Plugin {
$AUTH_ACL = file($config_cascade['acl']['default']);
// namespace given?
- if($INPUT->str('ns') == '*'){
+ if ($INPUT->str('ns') == '*') {
$this->ns = '*';
- }else{
+ } else {
$this->ns = cleanID($INPUT->str('ns'));
}
@@ -80,78 +82,78 @@ class admin_plugin_acl extends DokuWiki_Admin_Plugin {
// user or group choosen?
$who = trim($INPUT->str('acl_w'));
- if($INPUT->str('acl_t') == '__g__' && $who){
- $this->who = '@'.ltrim($auth->cleanGroup($who),'@');
- }elseif($INPUT->str('acl_t') == '__u__' && $who){
- $this->who = ltrim($who,'@');
- if($this->who != '%USER%' && $this->who != '%GROUP%'){ #keep wildcard as is
+ if ($INPUT->str('acl_t') == '__g__' && $who) {
+ $this->who = '@'.ltrim($auth->cleanGroup($who), '@');
+ } elseif ($INPUT->str('acl_t') == '__u__' && $who) {
+ $this->who = ltrim($who, '@');
+ if ($this->who != '%USER%' && $this->who != '%GROUP%') { #keep wildcard as is
$this->who = $auth->cleanUser($this->who);
}
- }elseif($INPUT->str('acl_t') &&
+ } elseif ($INPUT->str('acl_t') &&
$INPUT->str('acl_t') != '__u__' &&
- $INPUT->str('acl_t') != '__g__'){
+ $INPUT->str('acl_t') != '__g__') {
$this->who = $INPUT->str('acl_t');
- }elseif($who){
+ } elseif ($who) {
$this->who = $who;
}
// handle modifications
- if($INPUT->has('cmd') && checkSecurityToken()){
+ if ($INPUT->has('cmd') && checkSecurityToken()) {
$cmd = $INPUT->extract('cmd')->str('cmd');
// scope for modifications
- if($this->ns){
- if($this->ns == '*'){
+ if ($this->ns) {
+ if ($this->ns == '*') {
$scope = '*';
- }else{
+ } else {
$scope = $this->ns.':*';
}
- }else{
+ } else {
$scope = $ID;
}
- if($cmd == 'save' && $scope && $this->who && $INPUT->has('acl')){
+ if ($cmd == 'save' && $scope && $this->who && $INPUT->has('acl')) {
// handle additions or single modifications
- $this->_acl_del($scope, $this->who);
- $this->_acl_add($scope, $this->who, $INPUT->int('acl'));
- }elseif($cmd == 'del' && $scope && $this->who){
+ $this->deleteACL($scope, $this->who);
+ $this->addACL($scope, $this->who, $INPUT->int('acl'));
+ } elseif ($cmd == 'del' && $scope && $this->who) {
// handle single deletions
- $this->_acl_del($scope, $this->who);
- }elseif($cmd == 'update'){
+ $this->deleteACL($scope, $this->who);
+ } elseif ($cmd == 'update') {
$acl = $INPUT->arr('acl');
// handle update of the whole file
- foreach($INPUT->arr('del') as $where => $names){
+ foreach ($INPUT->arr('del') as $where => $names) {
// remove all rules marked for deletion
- foreach($names as $who)
+ foreach ($names as $who)
unset($acl[$where][$who]);
}
// prepare lines
$lines = array();
// keep header
- foreach($AUTH_ACL as $line){
- if($line{0} == '#'){
+ foreach ($AUTH_ACL as $line) {
+ if ($line{0} == '#') {
$lines[] = $line;
- }else{
+ } else {
break;
}
}
// re-add all rules
- foreach($acl as $where => $opt){
- foreach($opt as $who => $perm){
+ foreach ($acl as $where => $opt) {
+ foreach ($opt as $who => $perm) {
if ($who[0]=='@') {
if ($who!='@ALL') {
- $who = '@'.ltrim($auth->cleanGroup($who),'@');
+ $who = '@'.ltrim($auth->cleanGroup($who), '@');
}
- } elseif ($who != '%USER%' && $who != '%GROUP%'){ #keep wildcard as is
+ } elseif ($who != '%USER%' && $who != '%GROUP%') { #keep wildcard as is
$who = $auth->cleanUser($who);
}
- $who = auth_nameencode($who,true);
+ $who = auth_nameencode($who, true);
$lines[] = "$where\t$who\t$perm\n";
}
}
// save it
- io_saveFile($config_cascade['acl']['default'], join('',$lines));
+ io_saveFile($config_cascade['acl']['default'], join('', $lines));
}
// reload ACL config
@@ -159,7 +161,7 @@ class admin_plugin_acl extends DokuWiki_Admin_Plugin {
}
// initialize ACL array
- $this->_init_acl_config();
+ $this->initAclConfig();
}
/**
@@ -171,24 +173,25 @@ class admin_plugin_acl extends DokuWiki_Admin_Plugin {
* @author Frank Schubert <frank@schokilade.de>
* @author Andreas Gohr <andi@splitbrain.org>
*/
- function html() {
+ public function html()
+ {
echo '<div id="acl_manager">'.NL;
echo '<h1>'.$this->getLang('admin_acl').'</h1>'.NL;
echo '<div class="level1">'.NL;
echo '<div id="acl__tree">'.NL;
- $this->_html_explorer();
+ $this->makeExplorer();
echo '</div>'.NL;
echo '<div id="acl__detail">'.NL;
- $this->_html_detail();
+ $this->printDetail();
echo '</div>'.NL;
echo '</div>'.NL;
echo '<div class="clearer"></div>';
echo '<h2>'.$this->getLang('current').'</h2>'.NL;
echo '<div class="level2">'.NL;
- $this->_html_table();
+ $this->printAclTable();
echo '</div>'.NL;
echo '<div class="footnotes"><div class="fn">'.NL;
@@ -204,15 +207,16 @@ class admin_plugin_acl extends DokuWiki_Admin_Plugin {
*
* @author Andreas Gohr <andi@splitbrain.org>
*/
- function _get_opts($addopts=null){
+ protected function getLinkOptions($addopts = null)
+ {
$opts = array(
'do'=>'admin',
'page'=>'acl',
);
- if($this->ns) $opts['ns'] = $this->ns;
- if($this->who) $opts['acl_w'] = $this->who;
+ if ($this->ns) $opts['ns'] = $this->ns;
+ if ($this->who) $opts['acl_w'] = $this->who;
- if(is_null($addopts)) return $opts;
+ if (is_null($addopts)) return $opts;
return array_merge($opts, $addopts);
}
@@ -221,54 +225,61 @@ class admin_plugin_acl extends DokuWiki_Admin_Plugin {
*
* @author Andreas Gohr <andi@splitbrain.org>
*/
- function _html_explorer(){
+ protected function makeExplorer()
+ {
global $conf;
global $ID;
global $lang;
$ns = $this->ns;
- if(empty($ns)){
- $ns = dirname(str_replace(':','/',$ID));
- if($ns == '.') $ns ='';
- }elseif($ns == '*'){
+ if (empty($ns)) {
+ $ns = dirname(str_replace(':', '/', $ID));
+ if ($ns == '.') $ns ='';
+ } elseif ($ns == '*') {
$ns ='';
}
- $ns = utf8_encodeFN(str_replace(':','/',$ns));
+ $ns = utf8_encodeFN(str_replace(':', '/', $ns));
- $data = $this->_get_tree($ns);
+ $data = $this->makeTree($ns);
// wrap a list with the root level around the other namespaces
array_unshift($data, array( 'level' => 0, 'id' => '*', 'type' => 'd',
'open' =>'true', 'label' => '['.$lang['mediaroot'].']'));
- echo html_buildlist($data,'acl',
- array($this,'_html_list_acl'),
- array($this,'_html_li_acl'));
-
+ echo html_buildlist(
+ $data,
+ 'acl',
+ array($this, 'makeTreeItem'),
+ array($this, 'makeListItem')
+ );
}
/**
* get a combined list of media and page files
*
+ * also called via AJAX
+ *
* @param string $folder an already converted filesystem folder of the current namespace
- * @param string $limit limit the search to this folder
+ * @param string $limit limit the search to this folder
+ * @return array
*/
- function _get_tree($folder,$limit=''){
+ public function makeTree($folder, $limit = '')
+ {
global $conf;
// read tree structure from pages and media
$data = array();
- search($data,$conf['datadir'],'search_index',array('ns' => $folder),$limit);
+ search($data, $conf['datadir'], 'search_index', array('ns' => $folder), $limit);
$media = array();
- search($media,$conf['mediadir'],'search_index',array('ns' => $folder, 'nofiles' => true),$limit);
- $data = array_merge($data,$media);
+ search($media, $conf['mediadir'], 'search_index', array('ns' => $folder, 'nofiles' => true), $limit);
+ $data = array_merge($data, $media);
unset($media);
// combine by sorting and removing duplicates
- usort($data,array($this,'_tree_sort'));
+ usort($data, array($this, 'treeSort'));
$count = count($data);
- if($count>0) for($i=1; $i<$count; $i++){
- if($data[$i-1]['id'] == $data[$i]['id'] && $data[$i-1]['type'] == $data[$i]['type']) {
+ if ($count>0) for ($i=1; $i<$count; $i++) {
+ if ($data[$i-1]['id'] == $data[$i]['id'] && $data[$i-1]['type'] == $data[$i]['type']) {
unset($data[$i]);
$i++; // duplicate found, next $i can't be a duplicate, so skip forward one
}
@@ -281,7 +292,8 @@ class admin_plugin_acl extends DokuWiki_Admin_Plugin {
*
* Sorts the combined trees of media and page files
*/
- function _tree_sort($a,$b){
+ public function treeSort($a, $b)
+ {
// handle the trivial cases first
if ($a['id'] == '') return -1;
if ($b['id'] == '') return 1;
@@ -315,6 +327,7 @@ class admin_plugin_acl extends DokuWiki_Admin_Plugin {
// before that other part.
if (empty($a_ids)) return ($a['type'] == 'd') ? -1 : 1;
if (empty($b_ids)) return ($b['type'] == 'd') ? 1 : -1;
+ return 0; //shouldn't happen
}
/**
@@ -323,20 +336,21 @@ class admin_plugin_acl extends DokuWiki_Admin_Plugin {
*
* @author Andreas Gohr <andi@splitbrain.org>
*/
- function _html_detail(){
+ protected function printDetail()
+ {
global $ID;
echo '<form action="'.wl().'" method="post" accept-charset="utf-8"><div class="no">'.NL;
echo '<div id="acl__user">';
echo $this->getLang('acl_perms').' ';
- $inl = $this->_html_select();
- echo '<input type="text" name="acl_w" class="edit" value="'.(($inl)?'':hsc(ltrim($this->who,'@'))).'" />'.NL;
+ $inl = $this->makeSelect();
+ echo '<input type="text" name="acl_w" class="edit" value="'.(($inl)?'':hsc(ltrim($this->who, '@'))).'" />'.NL;
echo '<button type="submit">'.$this->getLang('btn_select').'</button>'.NL;
echo '</div>'.NL;
echo '<div id="acl__info">';
- $this->_html_info();
+ $this->printInfo();
echo '</div>';
echo '<input type="hidden" name="ns" value="'.hsc($this->ns).'" />'.NL;
@@ -349,23 +363,26 @@ class admin_plugin_acl extends DokuWiki_Admin_Plugin {
/**
* Print info and editor
+ *
+ * also loaded via Ajax
*/
- function _html_info(){
+ public function printInfo()
+ {
global $ID;
- if($this->who){
- $current = $this->_get_exact_perm();
+ if ($this->who) {
+ $current = $this->getExactPermisson();
// explain current permissions
- $this->_html_explain($current);
+ $this->printExplanation($current);
// load editor
- $this->_html_acleditor($current);
- }else{
+ $this->printAclEditor($current);
+ } else {
echo '<p>';
- if($this->ns){
- printf($this->getLang('p_choose_ns'),hsc($this->ns));
- }else{
- printf($this->getLang('p_choose_id'),hsc($ID));
+ if ($this->ns) {
+ printf($this->getLang('p_choose_ns'), hsc($this->ns));
+ } else {
+ printf($this->getLang('p_choose_id'), hsc($ID));
}
echo '</p>';
@@ -378,21 +395,22 @@ class admin_plugin_acl extends DokuWiki_Admin_Plugin {
*
* @author Andreas Gohr <andi@splitbrain.org>
*/
- function _html_acleditor($current){
+ protected function printAclEditor($current)
+ {
global $lang;
echo '<fieldset>';
- if(is_null($current)){
+ if (is_null($current)) {
echo '<legend>'.$this->getLang('acl_new').'</legend>';
- }else{
+ } else {
echo '<legend>'.$this->getLang('acl_mod').'</legend>';
}
- echo $this->_html_checkboxes($current,empty($this->ns),'acl');
+ echo $this->makeCheckboxes($current, empty($this->ns), 'acl');
- if(is_null($current)){
+ if (is_null($current)) {
echo '<button type="submit" name="cmd[save]">'.$lang['btn_save'].'</button>'.NL;
- }else{
+ } else {
echo '<button type="submit" name="cmd[save]">'.$lang['btn_update'].'</button>'.NL;
echo '<button type="submit" name="cmd[del]">'.$lang['btn_delete'].'</button>'.NL;
}
@@ -405,7 +423,8 @@ class admin_plugin_acl extends DokuWiki_Admin_Plugin {
*
* @author Andreas Gohr <andi@splitbrain.org>
*/
- function _html_explain($current){
+ protected function printExplanation($current)
+ {
global $ID;
global $auth;
@@ -413,69 +432,69 @@ class admin_plugin_acl extends DokuWiki_Admin_Plugin {
$ns = $this->ns;
// prepare where to check
- if($ns){
- if($ns == '*'){
+ if ($ns) {
+ if ($ns == '*') {
$check='*';
- }else{
+ } else {
$check=$ns.':*';
}
- }else{
+ } else {
$check = $ID;
}
// prepare who to check
- if($who{0} == '@'){
+ if ($who{0} == '@') {
$user = '';
- $groups = array(ltrim($who,'@'));
- }else{
+ $groups = array(ltrim($who, '@'));
+ } else {
$user = $who;
$info = $auth->getUserData($user);
- if($info === false){
+ if ($info === false) {
$groups = array();
- }else{
+ } else {
$groups = $info['grps'];
}
}
// check the permissions
- $perm = auth_aclcheck($check,$user,$groups);
+ $perm = auth_aclcheck($check, $user, $groups);
// build array of named permissions
$names = array();
- if($perm){
- if($ns){
- if($perm >= AUTH_DELETE) $names[] = $this->getLang('acl_perm16');
- if($perm >= AUTH_UPLOAD) $names[] = $this->getLang('acl_perm8');
- if($perm >= AUTH_CREATE) $names[] = $this->getLang('acl_perm4');
+ if ($perm) {
+ if ($ns) {
+ if ($perm >= AUTH_DELETE) $names[] = $this->getLang('acl_perm16');
+ if ($perm >= AUTH_UPLOAD) $names[] = $this->getLang('acl_perm8');
+ if ($perm >= AUTH_CREATE) $names[] = $this->getLang('acl_perm4');
}
- if($perm >= AUTH_EDIT) $names[] = $this->getLang('acl_perm2');
- if($perm >= AUTH_READ) $names[] = $this->getLang('acl_perm1');
+ if ($perm >= AUTH_EDIT) $names[] = $this->getLang('acl_perm2');
+ if ($perm >= AUTH_READ) $names[] = $this->getLang('acl_perm1');
$names = array_reverse($names);
- }else{
+ } else {
$names[] = $this->getLang('acl_perm0');
}
// print permission explanation
echo '<p>';
- if($user){
- if($ns){
- printf($this->getLang('p_user_ns'),hsc($who),hsc($ns),join(', ',$names));
- }else{
- printf($this->getLang('p_user_id'),hsc($who),hsc($ID),join(', ',$names));
+ if ($user) {
+ if ($ns) {
+ printf($this->getLang('p_user_ns'), hsc($who), hsc($ns), join(', ', $names));
+ } else {
+ printf($this->getLang('p_user_id'), hsc($who), hsc($ID), join(', ', $names));
}
- }else{
- if($ns){
- printf($this->getLang('p_group_ns'),hsc(ltrim($who,'@')),hsc($ns),join(', ',$names));
- }else{
- printf($this->getLang('p_group_id'),hsc(ltrim($who,'@')),hsc($ID),join(', ',$names));
+ } else {
+ if ($ns) {
+ printf($this->getLang('p_group_ns'), hsc(ltrim($who, '@')), hsc($ns), join(', ', $names));
+ } else {
+ printf($this->getLang('p_group_id'), hsc(ltrim($who, '@')), hsc($ID), join(', ', $names));
}
}
echo '</p>';
// add note if admin
- if($perm == AUTH_ADMIN){
+ if ($perm == AUTH_ADMIN) {
echo '<p>'.$this->getLang('p_isadmin').'</p>';
- }elseif(is_null($current)){
+ } elseif (is_null($current)) {
echo '<p>'.$this->getLang('p_inherited').'</p>';
}
}
@@ -488,46 +507,57 @@ class admin_plugin_acl extends DokuWiki_Admin_Plugin {
*
* @author Andreas Gohr <andi@splitbrain.org>
*/
- function _html_list_acl($item){
+ protected function makeTreeItem($item)
+ {
$ret = '';
// what to display
- if(!empty($item['label'])){
+ if (!empty($item['label'])) {
$base = $item['label'];
- }else{
+ } else {
$base = ':'.$item['id'];
- $base = substr($base,strrpos($base,':')+1);
+ $base = substr($base, strrpos($base, ':')+1);
}
// highlight?
- if( ($item['type']== $this->current_item['type'] && $item['id'] == $this->current_item['id'])) {
+ if (($item['type']== $this->current_item['type'] && $item['id'] == $this->current_item['id'])) {
$cl = ' cur';
} else {
$cl = '';
}
// namespace or page?
- if($item['type']=='d'){
- if($item['open']){
+ if ($item['type']=='d') {
+ if ($item['open']) {
$img = DOKU_BASE.'lib/images/minus.gif';
$alt = '−';
- }else{
+ } else {
$img = DOKU_BASE.'lib/images/plus.gif';
$alt = '+';
}
$ret .= '<img src="'.$img.'" alt="'.$alt.'" />';
- $ret .= '<a href="'.wl('',$this->_get_opts(array('ns'=>$item['id'],'sectok'=>getSecurityToken()))).'" class="idx_dir'.$cl.'">';
+ $ret .= '<a href="'.
+ wl('', $this->getLinkOptions(array('ns'=> $item['id'], 'sectok'=>getSecurityToken()))).
+ '" class="idx_dir'.$cl.'">';
$ret .= $base;
$ret .= '</a>';
- }else{
- $ret .= '<a href="'.wl('',$this->_get_opts(array('id'=>$item['id'],'ns'=>'','sectok'=>getSecurityToken()))).'" class="wikilink1'.$cl.'">';
+ } else {
+ $ret .= '<a href="'.
+ wl('', $this->getLinkOptions(array('id'=> $item['id'], 'ns'=>'', 'sectok'=>getSecurityToken()))).
+ '" class="wikilink1'.$cl.'">';
$ret .= noNS($item['id']);
$ret .= '</a>';
}
return $ret;
}
-
- function _html_li_acl($item){
+ /**
+ * List Item formatter
+ *
+ * @param array $item
+ * @return string
+ */
+ public function makeListItem($item)
+ {
return '<li class="level' . $item['level'] . ' ' .
($item['open'] ? 'open' : 'closed') . '">';
}
@@ -538,7 +568,8 @@ class admin_plugin_acl extends DokuWiki_Admin_Plugin {
*
* @author Andreas Gohr <andi@splitbrain.org>
*/
- function _init_acl_config(){
+ public function initAclConfig()
+ {
global $AUTH_ACL;
global $conf;
$acl_config=array();
@@ -547,20 +578,24 @@ class admin_plugin_acl extends DokuWiki_Admin_Plugin {
// get special users and groups
$this->specials[] = '@ALL';
$this->specials[] = '@'.$conf['defaultgroup'];
- if($conf['manager'] != '!!not set!!'){
- $this->specials = array_merge($this->specials,
- array_map('trim',
- explode(',',$conf['manager'])));
+ if ($conf['manager'] != '!!not set!!') {
+ $this->specials = array_merge(
+ $this->specials,
+ array_map(
+ 'trim',
+ explode(',', $conf['manager'])
+ )
+ );
}
$this->specials = array_filter($this->specials);
$this->specials = array_unique($this->specials);
sort($this->specials);
- foreach($AUTH_ACL as $line){
- $line = trim(preg_replace('/#.*$/','',$line)); //ignore comments
- if(!$line) continue;
+ foreach ($AUTH_ACL as $line) {
+ $line = trim(preg_replace('/#.*$/', '', $line)); //ignore comments
+ if (!$line) continue;
- $acl = preg_split('/[ \t]+/',$line);
+ $acl = preg_split('/[ \t]+/', $line);
//0 is pagename, 1 is user, 2 is acl
$acl[1] = rawurldecode($acl[1]);
@@ -568,7 +603,7 @@ class admin_plugin_acl extends DokuWiki_Admin_Plugin {
// store non-special users and groups for later selection dialog
$ug = $acl[1];
- if(in_array($ug,$this->specials)) continue;
+ if (in_array($ug, $this->specials)) continue;
$usersgroups[] = $ug;
}
@@ -585,14 +620,15 @@ class admin_plugin_acl extends DokuWiki_Admin_Plugin {
*
* @author Andreas Gohr <andi@splitbrain.org>
*/
- function _html_table(){
+ protected function printAclTable()
+ {
global $lang;
global $ID;
echo '<form action="'.wl().'" method="post" accept-charset="utf-8"><div class="no">'.NL;
- if($this->ns){
+ if ($this->ns) {
echo '<input type="hidden" name="ns" value="'.hsc($this->ns).'" />'.NL;
- }else{
+ } else {
echo '<input type="hidden" name="id" value="'.hsc($ID).'" />'.NL;
}
echo '<input type="hidden" name="acl_w" value="'.hsc($this->who).'" />'.NL;
@@ -607,29 +643,29 @@ class admin_plugin_acl extends DokuWiki_Admin_Plugin {
echo '<th>'.$this->getLang('perm').'<sup><a id="fnt__1" class="fn_top" href="#fn__1">1)</a></sup></th>';
echo '<th>'.$lang['btn_delete'].'</th>';
echo '</tr>';
- foreach($this->acl as $where => $set){
- foreach($set as $who => $perm){
+ foreach ($this->acl as $where => $set) {
+ foreach ($set as $who => $perm) {
echo '<tr>';
echo '<td>';
- if(substr($where,-1) == '*'){
+ if (substr($where, -1) == '*') {
echo '<span class="aclns">'.hsc($where).'</span>';
$ispage = false;
- }else{
+ } else {
echo '<span class="aclpage">'.hsc($where).'</span>';
$ispage = true;
}
echo '</td>';
echo '<td>';
- if($who{0} == '@'){
+ if ($who{0} == '@') {
echo '<span class="aclgroup">'.hsc($who).'</span>';
- }else{
+ } else {
echo '<span class="acluser">'.hsc($who).'</span>';
}
echo '</td>';
echo '<td>';
- echo $this->_html_checkboxes($perm,$ispage,'acl['.$where.']['.$who.']');
+ echo $this->makeCheckboxes($perm, $ispage, 'acl['.$where.']['.$who.']');
echo '</td>';
echo '<td class="check">';
@@ -655,21 +691,22 @@ class admin_plugin_acl extends DokuWiki_Admin_Plugin {
*
* @author Andreas Gohr <andi@splitbrain.org>
*/
- function _get_exact_perm(){
+ protected function getExactPermisson()
+ {
global $ID;
- if($this->ns){
- if($this->ns == '*'){
+ if ($this->ns) {
+ if ($this->ns == '*') {
$check = '*';
- }else{
+ } else {
$check = $this->ns.':*';
}
- }else{
+ } else {
$check = $ID;
}
- if(isset($this->acl[$check][$this->who])){
+ if (isset($this->acl[$check][$this->who])) {
return $this->acl[$check][$this->who];
- }else{
+ } else {
return null;
}
}
@@ -679,13 +716,14 @@ class admin_plugin_acl extends DokuWiki_Admin_Plugin {
*
* @author Frank Schubert <frank@schokilade.de>
*/
- function _acl_add($acl_scope, $acl_user, $acl_level){
+ public function addACL($acl_scope, $acl_user, $acl_level)
+ {
global $config_cascade;
- $acl_user = auth_nameencode($acl_user,true);
+ $acl_user = auth_nameencode($acl_user, true);
// max level for pagenames is edit
- if(strpos($acl_scope,'*') === false) {
- if($acl_level > AUTH_EDIT) $acl_level = AUTH_EDIT;
+ if (strpos($acl_scope, '*') === false) {
+ if ($acl_level > AUTH_EDIT) $acl_level = AUTH_EDIT;
}
$new_acl = "$acl_scope\t$acl_user\t$acl_level\n";
@@ -698,11 +736,12 @@ class admin_plugin_acl extends DokuWiki_Admin_Plugin {
*
* @author Frank Schubert <frank@schokilade.de>
*/
- function _acl_del($acl_scope, $acl_user){
+ public function deleteACL($acl_scope, $acl_user)
+ {
global $config_cascade;
- $acl_user = auth_nameencode($acl_user,true);
+ $acl_user = auth_nameencode($acl_user, true);
- $acl_pattern = '^'.preg_quote($acl_scope,'/').'[ \t]+'.$acl_user.'[ \t]+[0-8].*$';
+ $acl_pattern = '^'.preg_quote($acl_scope, '/').'[ \t]+'.$acl_user.'[ \t]+[0-8].*$';
return io_deleteFromFile($config_cascade['acl']['default'], "/$acl_pattern/", true);
}
@@ -713,15 +752,16 @@ class admin_plugin_acl extends DokuWiki_Admin_Plugin {
* @author Frank Schubert <frank@schokilade.de>
* @author Andreas Gohr <andi@splitbrain.org>
*/
- function _html_checkboxes($setperm,$ispage,$name){
+ protected function makeCheckboxes($setperm, $ispage, $name)
+ {
global $lang;
static $label = 0; //number labels
$ret = '';
- if($ispage && $setperm > AUTH_EDIT) $setperm = AUTH_EDIT;
+ if ($ispage && $setperm > AUTH_EDIT) $setperm = AUTH_EDIT;
- foreach(array(AUTH_NONE,AUTH_READ,AUTH_EDIT,AUTH_CREATE,AUTH_UPLOAD,AUTH_DELETE) as $perm){
+ foreach (array(AUTH_NONE,AUTH_READ,AUTH_EDIT,AUTH_CREATE,AUTH_UPLOAD,AUTH_DELETE) as $perm) {
$label += 1;
//general checkbox attributes
@@ -730,11 +770,11 @@ class admin_plugin_acl extends DokuWiki_Admin_Plugin {
'name' => $name,
'value' => $perm );
//dynamic attributes
- if(!is_null($setperm) && $setperm == $perm) $atts['checked'] = 'checked';
- if($ispage && $perm > AUTH_EDIT){
+ if (!is_null($setperm) && $setperm == $perm) $atts['checked'] = 'checked';
+ if ($ispage && $perm > AUTH_EDIT) {
$atts['disabled'] = 'disabled';
$class = ' class="disabled"';
- }else{
+ } else {
$class = '';
}
@@ -752,21 +792,21 @@ class admin_plugin_acl extends DokuWiki_Admin_Plugin {
*
* @author Andreas Gohr <andi@splitbrain.org>
*/
- function _html_select(){
+ protected function makeSelect()
+ {
$inlist = false;
$usel = '';
$gsel = '';
- if($this->who &&
- !in_array($this->who,$this->usersgroups) &&
- !in_array($this->who,$this->specials)){
-
- if($this->who{0} == '@'){
+ if ($this->who &&
+ !in_array($this->who, $this->usersgroups) &&
+ !in_array($this->who, $this->specials)) {
+ if ($this->who{0} == '@') {
$gsel = ' selected="selected"';
- }else{
+ } else {
$usel = ' selected="selected"';
}
- }else{
+ } else {
$inlist = true;
}
@@ -775,17 +815,17 @@ class admin_plugin_acl extends DokuWiki_Admin_Plugin {
echo ' <option value="__u__" class="acluser"'.$usel.'>'.$this->getLang('acl_user').'</option>'.NL;
if (!empty($this->specials)) {
echo ' <optgroup label="&#160;">'.NL;
- foreach($this->specials as $ug){
- if($ug == $this->who){
+ foreach ($this->specials as $ug) {
+ if ($ug == $this->who) {
$sel = ' selected="selected"';
$inlist = true;
- }else{
+ } else {
$sel = '';
}
- if($ug{0} == '@'){
+ if ($ug{0} == '@') {
echo ' <option value="'.hsc($ug).'" class="aclgroup"'.$sel.'>'.hsc($ug).'</option>'.NL;
- }else{
+ } else {
echo ' <option value="'.hsc($ug).'" class="acluser"'.$sel.'>'.hsc($ug).'</option>'.NL;
}
}
@@ -793,17 +833,17 @@ class admin_plugin_acl extends DokuWiki_Admin_Plugin {
}
if (!empty($this->usersgroups)) {
echo ' <optgroup label="&#160;">'.NL;
- foreach($this->usersgroups as $ug){
- if($ug == $this->who){
+ foreach ($this->usersgroups as $ug) {
+ if ($ug == $this->who) {
$sel = ' selected="selected"';
$inlist = true;
- }else{
+ } else {
$sel = '';
}
- if($ug{0} == '@'){
+ if ($ug{0} == '@') {
echo ' <option value="'.hsc($ug).'" class="aclgroup"'.$sel.'>'.hsc($ug).'</option>'.NL;
- }else{
+ } else {
echo ' <option value="'.hsc($ug).'" class="acluser"'.$sel.'>'.hsc($ug).'</option>'.NL;
}
}
diff --git a/lib/plugins/acl/remote.php b/lib/plugins/acl/remote.php
index 27c5c162a..31a8cde53 100644
--- a/lib/plugins/acl/remote.php
+++ b/lib/plugins/acl/remote.php
@@ -1,16 +1,20 @@
<?php
+use dokuwiki\Remote\AccessDeniedException;
+
/**
* Class remote_plugin_acl
*/
-class remote_plugin_acl extends DokuWiki_Remote_Plugin {
+class remote_plugin_acl extends DokuWiki_Remote_Plugin
+{
/**
* Returns details about the remote plugin methods
*
- * @return array Information about all provided methods. {@see RemoteAPI}
+ * @return array Information about all provided methods. {@see dokuwiki\Remote\RemoteAPI}
*/
- public function _getMethods() {
+ public function _getMethods()
+ {
return array(
'listAcls' => array(
'args' => array(),
@@ -34,16 +38,20 @@ class remote_plugin_acl extends DokuWiki_Remote_Plugin {
/**
* List all ACL config entries
*
- * @throws RemoteAccessDeniedException
+ * @throws AccessDeniedException
* @return dictionary {Scope: ACL}, where ACL = dictionnary {user/group: permissions_int}
*/
- public function listAcls(){
- if(!auth_isadmin()) {
- throw new RemoteAccessDeniedException('You are not allowed to access ACLs, superuser permission is required', 114);
+ public function listAcls()
+ {
+ if (!auth_isadmin()) {
+ throw new AccessDeniedException(
+ 'You are not allowed to access ACLs, superuser permission is required',
+ 114
+ );
}
/** @var admin_plugin_acl $apa */
$apa = plugin_load('admin', 'acl');
- $apa->_init_acl_config();
+ $apa->initAclConfig();
return $apa->acl;
}
@@ -53,17 +61,21 @@ class remote_plugin_acl extends DokuWiki_Remote_Plugin {
* @param string $scope
* @param string $user
* @param int $level see also inc/auth.php
- * @throws RemoteAccessDeniedException
+ * @throws AccessDeniedException
* @return bool
*/
- public function addAcl($scope, $user, $level){
- if(!auth_isadmin()) {
- throw new RemoteAccessDeniedException('You are not allowed to access ACLs, superuser permission is required', 114);
+ public function addAcl($scope, $user, $level)
+ {
+ if (!auth_isadmin()) {
+ throw new AccessDeniedException(
+ 'You are not allowed to access ACLs, superuser permission is required',
+ 114
+ );
}
/** @var admin_plugin_acl $apa */
$apa = plugin_load('admin', 'acl');
- return $apa->_acl_add($scope, $user, $level);
+ return $apa->addACL($scope, $user, $level);
}
/**
@@ -71,17 +83,20 @@ class remote_plugin_acl extends DokuWiki_Remote_Plugin {
*
* @param string $scope
* @param string $user
- * @throws RemoteAccessDeniedException
+ * @throws AccessDeniedException
* @return bool
*/
- public function delAcl($scope, $user){
- if(!auth_isadmin()) {
- throw new RemoteAccessDeniedException('You are not allowed to access ACLs, superuser permission is required', 114);
+ public function delAcl($scope, $user)
+ {
+ if (!auth_isadmin()) {
+ throw new AccessDeniedException(
+ 'You are not allowed to access ACLs, superuser permission is required',
+ 114
+ );
}
/** @var admin_plugin_acl $apa */
$apa = plugin_load('admin', 'acl');
- return $apa->_acl_del($scope, $user);
+ return $apa->deleteACL($scope, $user);
}
}
-
diff --git a/lib/plugins/action.php b/lib/plugins/action.php
index 23d94a509..a3cbec722 100644
--- a/lib/plugins/action.php
+++ b/lib/plugins/action.php
@@ -1,25 +1,2 @@
<?php
-/**
- * Action Plugin Prototype
- *
- * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
- * @author Christopher Smith <chris@jalakai.co.uk>
- */
-// must be run within Dokuwiki
-if(!defined('DOKU_INC')) die();
-
-/**
- * All DokuWiki plugins to interfere with the event system
- * need to inherit from this class
- */
-class DokuWiki_Action_Plugin extends DokuWiki_Plugin {
-
- /**
- * Registers a callback function for a given event
- *
- * @param Doku_Event_Handler $controller
- */
- public function register(Doku_Event_Handler $controller) {
- trigger_error('register() not implemented in '.get_class($this), E_USER_WARNING);
- }
-}
+dbg_deprecated('Autoloading. Do not require() files yourself.');
diff --git a/lib/plugins/admin.php b/lib/plugins/admin.php
index 9554ce511..a3cbec722 100644
--- a/lib/plugins/admin.php
+++ b/lib/plugins/admin.php
@@ -1,119 +1,2 @@
<?php
-/**
- * Admin Plugin Prototype
- *
- * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
- * @author Christopher Smith <chris@jalakai.co.uk>
- */
-// must be run within Dokuwiki
-if(!defined('DOKU_INC')) die();
-
-/**
- * All DokuWiki plugins to extend the admin function
- * need to inherit from this class
- */
-class DokuWiki_Admin_Plugin extends DokuWiki_Plugin {
-
- /**
- * Return the text that is displayed at the main admin menu
- * (Default localized language string 'menu' is returned, override this function for setting another name)
- *
- * @param string $language language code
- * @return string menu string
- */
- public function getMenuText($language) {
- $menutext = $this->getLang('menu');
- if (!$menutext) {
- $info = $this->getInfo();
- $menutext = $info['name'].' ...';
- }
- return $menutext;
- }
-
- /**
- * Return the path to the icon being displayed in the main admin menu.
- * By default it tries to find an 'admin.svg' file in the plugin directory.
- * (Override this function for setting another image)
- *
- * Important: you have to return a single path, monochrome SVG icon! It has to be
- * under 2 Kilobytes!
- *
- * We recommend icons from https://materialdesignicons.com/ or to use a matching
- * style.
- *
- * @return string full path to the icon file
- */
- public function getMenuIcon() {
- $plugin = $this->getPluginName();
- return DOKU_PLUGIN . $plugin . '/admin.svg';
- }
-
- /**
- * Determine position in list in admin window
- * Lower values are sorted up
- *
- * @return int
- */
- public function getMenuSort() {
- return 1000;
- }
-
- /**
- * Carry out required processing
- */
- public function handle() {
- trigger_error('handle() not implemented in '.get_class($this), E_USER_WARNING);
- }
-
- /**
- * Output html of the admin page
- */
- public function html() {
- trigger_error('html() not implemented in '.get_class($this), E_USER_WARNING);
- }
-
- /**
- * Checks if access should be granted to this admin plugin
- *
- * @return bool true if the current user may access this admin plugin
- */
- public function isAccessibleByCurrentUser() {
- $data = [];
- $data['instance'] = $this;
- $data['hasAccess'] = false;
-
- $event = new Doku_Event('ADMINPLUGIN_ACCESS_CHECK', $data);
- if($event->advise_before()) {
- if ($this->forAdminOnly()) {
- $data['hasAccess'] = auth_isadmin();
- } else {
- $data['hasAccess'] = auth_ismanager();
- }
- }
- $event->advise_after();
-
- return $data['hasAccess'];
- }
-
- /**
- * Return true for access only by admins (config:superuser) or false if managers are allowed as well
- *
- * @return bool
- */
- public function forAdminOnly() {
- return true;
- }
-
- /**
- * Return array with ToC items. Items can be created with the html_mktocitem()
- *
- * @see html_mktocitem()
- * @see tpl_toc()
- *
- * @return array
- */
- public function getTOC(){
- return array();
- }
-}
-//Setup VIM: ex: et ts=4 :
+dbg_deprecated('Autoloading. Do not require() files yourself.');
diff --git a/lib/plugins/auth.php b/lib/plugins/auth.php
index 0cd965b72..a3cbec722 100644
--- a/lib/plugins/auth.php
+++ b/lib/plugins/auth.php
@@ -1,438 +1,2 @@
<?php
-// must be run within Dokuwiki
-if(!defined('DOKU_INC')) die();
-
-/**
- * Auth Plugin Prototype
- *
- * foundation authorisation class
- * all auth classes should inherit from this class
- *
- * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
- * @author Chris Smith <chris@jalakai.co.uk>
- * @author Jan Schumann <js@jschumann-it.com>
- */
-class DokuWiki_Auth_Plugin extends DokuWiki_Plugin {
- public $success = true;
-
- /**
- * Possible things an auth backend module may be able to
- * do. The things a backend can do need to be set to true
- * in the constructor.
- */
- protected $cando = array(
- 'addUser' => false, // can Users be created?
- 'delUser' => false, // can Users be deleted?
- 'modLogin' => false, // can login names be changed?
- 'modPass' => false, // can passwords be changed?
- 'modName' => false, // can real names be changed?
- 'modMail' => false, // can emails be changed?
- 'modGroups' => false, // can groups be changed?
- 'getUsers' => false, // can a (filtered) list of users be retrieved?
- 'getUserCount' => false, // can the number of users be retrieved?
- 'getGroups' => false, // can a list of available groups be retrieved?
- 'external' => false, // does the module do external auth checking?
- 'logout' => true, // can the user logout again? (eg. not possible with HTTP auth)
- );
-
- /**
- * Constructor.
- *
- * Carry out sanity checks to ensure the object is
- * able to operate. Set capabilities in $this->cando
- * array here
- *
- * For future compatibility, sub classes should always include a call
- * to parent::__constructor() in their constructors!
- *
- * Set $this->success to false if checks fail
- *
- * @author Christopher Smith <chris@jalakai.co.uk>
- */
- public function __construct() {
- // the base class constructor does nothing, derived class
- // constructors do the real work
- }
-
- /**
- * Available Capabilities. [ DO NOT OVERRIDE ]
- *
- * For introspection/debugging
- *
- * @author Christopher Smith <chris@jalakai.co.uk>
- * @return array
- */
- public function getCapabilities(){
- return array_keys($this->cando);
- }
-
- /**
- * Capability check. [ DO NOT OVERRIDE ]
- *
- * Checks the capabilities set in the $this->cando array and
- * some pseudo capabilities (shortcutting access to multiple
- * ones)
- *
- * ususal capabilities start with lowercase letter
- * shortcut capabilities start with uppercase letter
- *
- * @author Andreas Gohr <andi@splitbrain.org>
- * @param string $cap the capability to check
- * @return bool
- */
- public function canDo($cap) {
- switch($cap) {
- case 'Profile':
- // can at least one of the user's properties be changed?
- return ($this->cando['modPass'] ||
- $this->cando['modName'] ||
- $this->cando['modMail']);
- break;
- case 'UserMod':
- // can at least anything be changed?
- return ($this->cando['modPass'] ||
- $this->cando['modName'] ||
- $this->cando['modMail'] ||
- $this->cando['modLogin'] ||
- $this->cando['modGroups'] ||
- $this->cando['modMail']);
- break;
- default:
- // print a helping message for developers
- if(!isset($this->cando[$cap])) {
- msg("Check for unknown capability '$cap' - Do you use an outdated Plugin?", -1);
- }
- return $this->cando[$cap];
- }
- }
-
- /**
- * Trigger the AUTH_USERDATA_CHANGE event and call the modification function. [ DO NOT OVERRIDE ]
- *
- * You should use this function instead of calling createUser, modifyUser or
- * deleteUsers directly. The event handlers can prevent the modification, for
- * example for enforcing a user name schema.
- *
- * @author Gabriel Birke <birke@d-scribe.de>
- * @param string $type Modification type ('create', 'modify', 'delete')
- * @param array $params Parameters for the createUser, modifyUser or deleteUsers method. The content of this array depends on the modification type
- * @return bool|null|int Result from the modification function or false if an event handler has canceled the action
- */
- public function triggerUserMod($type, $params) {
- $validTypes = array(
- 'create' => 'createUser',
- 'modify' => 'modifyUser',
- 'delete' => 'deleteUsers'
- );
- if(empty($validTypes[$type])) {
- return false;
- }
-
- $result = false;
- $eventdata = array('type' => $type, 'params' => $params, 'modification_result' => null);
- $evt = new Doku_Event('AUTH_USER_CHANGE', $eventdata);
- if($evt->advise_before(true)) {
- $result = call_user_func_array(array($this, $validTypes[$type]), $evt->data['params']);
- $evt->data['modification_result'] = $result;
- }
- $evt->advise_after();
- unset($evt);
- return $result;
- }
-
- /**
- * Log off the current user [ OPTIONAL ]
- *
- * Is run in addition to the ususal logoff method. Should
- * only be needed when trustExternal is implemented.
- *
- * @see auth_logoff()
- * @author Andreas Gohr <andi@splitbrain.org>
- */
- public function logOff() {
- }
-
- /**
- * Do all authentication [ OPTIONAL ]
- *
- * Set $this->cando['external'] = true when implemented
- *
- * If this function is implemented it will be used to
- * authenticate a user - all other DokuWiki internals
- * will not be used for authenticating, thus
- * implementing the checkPass() function is not needed
- * anymore.
- *
- * The function can be used to authenticate against third
- * party cookies or Apache auth mechanisms and replaces
- * the auth_login() function
- *
- * The function will be called with or without a set
- * username. If the Username is given it was called
- * from the login form and the given credentials might
- * need to be checked. If no username was given it
- * the function needs to check if the user is logged in
- * by other means (cookie, environment).
- *
- * The function needs to set some globals needed by
- * DokuWiki like auth_login() does.
- *
- * @see auth_login()
- * @author Andreas Gohr <andi@splitbrain.org>
- *
- * @param string $user Username
- * @param string $pass Cleartext Password
- * @param bool $sticky Cookie should not expire
- * @return bool true on successful auth
- */
- public function trustExternal($user, $pass, $sticky = false) {
- /* some example:
-
- global $USERINFO;
- global $conf;
- $sticky ? $sticky = true : $sticky = false; //sanity check
-
- // do the checking here
-
- // set the globals if authed
- $USERINFO['name'] = 'FIXME';
- $USERINFO['mail'] = 'FIXME';
- $USERINFO['grps'] = array('FIXME');
- $_SERVER['REMOTE_USER'] = $user;
- $_SESSION[DOKU_COOKIE]['auth']['user'] = $user;
- $_SESSION[DOKU_COOKIE]['auth']['pass'] = $pass;
- $_SESSION[DOKU_COOKIE]['auth']['info'] = $USERINFO;
- return true;
-
- */
- }
-
- /**
- * Check user+password [ MUST BE OVERRIDDEN ]
- *
- * Checks if the given user exists and the given
- * plaintext password is correct
- *
- * May be ommited if trustExternal is used.
- *
- * @author Andreas Gohr <andi@splitbrain.org>
- * @param string $user the user name
- * @param string $pass the clear text password
- * @return bool
- */
- public function checkPass($user, $pass) {
- msg("no valid authorisation system in use", -1);
- return false;
- }
-
- /**
- * Return user info [ MUST BE OVERRIDDEN ]
- *
- * Returns info about the given user needs to contain
- * at least these fields:
- *
- * name string full name of the user
- * mail string email address of the user
- * grps array list of groups the user is in
- *
- * @author Andreas Gohr <andi@splitbrain.org>
- * @param string $user the user name
- * @param bool $requireGroups whether or not the returned data must include groups
- * @return false|array containing user data or false
- */
- public function getUserData($user, $requireGroups=true) {
- if(!$this->cando['external']) msg("no valid authorisation system in use", -1);
- return false;
- }
-
- /**
- * Create a new User [implement only where required/possible]
- *
- * Returns false if the user already exists, null when an error
- * occurred and true if everything went well.
- *
- * The new user HAS TO be added to the default group by this
- * function!
- *
- * Set addUser capability when implemented
- *
- * @author Andreas Gohr <andi@splitbrain.org>
- * @param string $user
- * @param string $pass
- * @param string $name
- * @param string $mail
- * @param null|array $grps
- * @return bool|null
- */
- public function createUser($user, $pass, $name, $mail, $grps = null) {
- msg("authorisation method does not allow creation of new users", -1);
- return null;
- }
-
- /**
- * Modify user data [implement only where required/possible]
- *
- * Set the mod* capabilities according to the implemented features
- *
- * @author Chris Smith <chris@jalakai.co.uk>
- * @param string $user nick of the user to be changed
- * @param array $changes array of field/value pairs to be changed (password will be clear text)
- * @return bool
- */
- public function modifyUser($user, $changes) {
- msg("authorisation method does not allow modifying of user data", -1);
- return false;
- }
-
- /**
- * Delete one or more users [implement only where required/possible]
- *
- * Set delUser capability when implemented
- *
- * @author Chris Smith <chris@jalakai.co.uk>
- * @param array $users
- * @return int number of users deleted
- */
- public function deleteUsers($users) {
- msg("authorisation method does not allow deleting of users", -1);
- return 0;
- }
-
- /**
- * Return a count of the number of user which meet $filter criteria
- * [should be implemented whenever retrieveUsers is implemented]
- *
- * Set getUserCount capability when implemented
- *
- * @author Chris Smith <chris@jalakai.co.uk>
- * @param array $filter array of field/pattern pairs, empty array for no filter
- * @return int
- */
- public function getUserCount($filter = array()) {
- msg("authorisation method does not provide user counts", -1);
- return 0;
- }
-
- /**
- * Bulk retrieval of user data [implement only where required/possible]
- *
- * Set getUsers capability when implemented
- *
- * @author Chris Smith <chris@jalakai.co.uk>
- * @param int $start index of first user to be returned
- * @param int $limit max number of users to be returned, 0 for unlimited
- * @param array $filter array of field/pattern pairs, null for no filter
- * @return array list of userinfo (refer getUserData for internal userinfo details)
- */
- public function retrieveUsers($start = 0, $limit = 0, $filter = null) {
- msg("authorisation method does not support mass retrieval of user data", -1);
- return array();
- }
-
- /**
- * Define a group [implement only where required/possible]
- *
- * Set addGroup capability when implemented
- *
- * @author Chris Smith <chris@jalakai.co.uk>
- * @param string $group
- * @return bool
- */
- public function addGroup($group) {
- msg("authorisation method does not support independent group creation", -1);
- return false;
- }
-
- /**
- * Retrieve groups [implement only where required/possible]
- *
- * Set getGroups capability when implemented
- *
- * @author Chris Smith <chris@jalakai.co.uk>
- * @param int $start
- * @param int $limit
- * @return array
- */
- public function retrieveGroups($start = 0, $limit = 0) {
- msg("authorisation method does not support group list retrieval", -1);
- return array();
- }
-
- /**
- * Return case sensitivity of the backend [OPTIONAL]
- *
- * When your backend is caseinsensitive (eg. you can login with USER and
- * user) then you need to overwrite this method and return false
- *
- * @return bool
- */
- public function isCaseSensitive() {
- return true;
- }
-
- /**
- * Sanitize a given username [OPTIONAL]
- *
- * This function is applied to any user name that is given to
- * the backend and should also be applied to any user name within
- * the backend before returning it somewhere.
- *
- * This should be used to enforce username restrictions.
- *
- * @author Andreas Gohr <andi@splitbrain.org>
- * @param string $user username
- * @return string the cleaned username
- */
- public function cleanUser($user) {
- return $user;
- }
-
- /**
- * Sanitize a given groupname [OPTIONAL]
- *
- * This function is applied to any groupname that is given to
- * the backend and should also be applied to any groupname within
- * the backend before returning it somewhere.
- *
- * This should be used to enforce groupname restrictions.
- *
- * Groupnames are to be passed without a leading '@' here.
- *
- * @author Andreas Gohr <andi@splitbrain.org>
- * @param string $group groupname
- * @return string the cleaned groupname
- */
- public function cleanGroup($group) {
- return $group;
- }
-
- /**
- * Check Session Cache validity [implement only where required/possible]
- *
- * DokuWiki caches user info in the user's session for the timespan defined
- * in $conf['auth_security_timeout'].
- *
- * This makes sure slow authentication backends do not slow down DokuWiki.
- * This also means that changes to the user database will not be reflected
- * on currently logged in users.
- *
- * To accommodate for this, the user manager plugin will touch a reference
- * file whenever a change is submitted. This function compares the filetime
- * of this reference file with the time stored in the session.
- *
- * This reference file mechanism does not reflect changes done directly in
- * the backend's database through other means than the user manager plugin.
- *
- * Fast backends might want to return always false, to force rechecks on
- * each page load. Others might want to use their own checking here. If
- * unsure, do not override.
- *
- * @param string $user - The username
- * @author Andreas Gohr <andi@splitbrain.org>
- * @return bool
- */
- public function useSessionCache($user) {
- global $conf;
- return ($_SESSION[DOKU_COOKIE]['auth']['time'] >= @filemtime($conf['cachedir'].'/sessionpurge'));
- }
-}
+dbg_deprecated('Autoloading. Do not require() files yourself.');
diff --git a/lib/plugins/authad/action.php b/lib/plugins/authad/action.php
index bc0f90c7e..a9fc01c1b 100644
--- a/lib/plugins/authad/action.php
+++ b/lib/plugins/authad/action.php
@@ -6,22 +6,20 @@
* @author Andreas Gohr <gohr@cosmocode.de>
*/
-// must be run within Dokuwiki
-if(!defined('DOKU_INC')) die();
-
/**
* Class action_plugin_addomain
*/
-class action_plugin_authad extends DokuWiki_Action_Plugin {
+class action_plugin_authad extends DokuWiki_Action_Plugin
+{
/**
* Registers a callback function for a given event
*/
- public function register(Doku_Event_Handler $controller) {
-
- $controller->register_hook('AUTH_LOGIN_CHECK', 'BEFORE', $this, 'handle_auth_login_check');
- $controller->register_hook('HTML_LOGINFORM_OUTPUT', 'BEFORE', $this, 'handle_html_loginform_output');
+ public function register(Doku_Event_Handler $controller)
+ {
+ $controller->register_hook('AUTH_LOGIN_CHECK', 'BEFORE', $this, 'handleAuthLoginCheck');
+ $controller->register_hook('HTML_LOGINFORM_OUTPUT', 'BEFORE', $this, 'handleHtmlLoginformOutput');
}
/**
@@ -30,17 +28,18 @@ class action_plugin_authad extends DokuWiki_Action_Plugin {
* @param Doku_Event $event
* @param array $param
*/
- public function handle_auth_login_check(Doku_Event &$event, $param) {
+ public function handleAuthLoginCheck(Doku_Event $event, $param)
+ {
global $INPUT;
/** @var auth_plugin_authad $auth */
global $auth;
- if(!is_a($auth, 'auth_plugin_authad')) return; // AD not even used
+ if (!is_a($auth, 'auth_plugin_authad')) return; // AD not even used
- if($INPUT->str('dom')) {
+ if ($INPUT->str('dom')) {
$usr = $auth->cleanUser($event->data['user']);
- $dom = $auth->_userDomain($usr);
- if(!$dom) {
+ $dom = $auth->getUserDomain($usr);
+ if (!$dom) {
$usr = "$usr@".$INPUT->str('dom');
}
$INPUT->post->set('u', $usr);
@@ -54,26 +53,27 @@ class action_plugin_authad extends DokuWiki_Action_Plugin {
* @param Doku_Event $event
* @param array $param
*/
- public function handle_html_loginform_output(Doku_Event &$event, $param) {
+ public function handleHtmlLoginformOutput(Doku_Event $event, $param)
+ {
global $INPUT;
/** @var auth_plugin_authad $auth */
global $auth;
- if(!is_a($auth, 'auth_plugin_authad')) return; // AD not even used
- $domains = $auth->_getConfiguredDomains();
- if(count($domains) <= 1) return; // no choice at all
+ if (!is_a($auth, 'auth_plugin_authad')) return; // AD not even used
+ $domains = $auth->getConfiguredDomains();
+ if (count($domains) <= 1) return; // no choice at all
/** @var Doku_Form $form */
$form =& $event->data;
// any default?
$dom = '';
- if($INPUT->has('u')) {
+ if ($INPUT->has('u')) {
$usr = $auth->cleanUser($INPUT->str('u'));
- $dom = $auth->_userDomain($usr);
+ $dom = $auth->getUserDomain($usr);
// update user field value
- if($dom) {
- $usr = $auth->_userName($usr);
+ if ($dom) {
+ $usr = $auth->getUserName($usr);
$pos = $form->findElementByAttribute('name', 'u');
$ele =& $form->getElementAt($pos);
$ele['value'] = $usr;
@@ -85,7 +85,6 @@ class action_plugin_authad extends DokuWiki_Action_Plugin {
$pos = $form->findElementByAttribute('name', 'p');
$form->insertElement($pos + 1, $element);
}
-
}
-// vim:ts=4:sw=4:et: \ No newline at end of file
+// vim:ts=4:sw=4:et:
diff --git a/lib/plugins/authad/auth.php b/lib/plugins/authad/auth.php
index 50f708456..684a6ed69 100644
--- a/lib/plugins/authad/auth.php
+++ b/lib/plugins/authad/auth.php
@@ -1,9 +1,4 @@
<?php
-// must be run within Dokuwiki
-if(!defined('DOKU_INC')) die();
-
-require_once(DOKU_PLUGIN.'authad/adLDAP/adLDAP.php');
-require_once(DOKU_PLUGIN.'authad/adLDAP/classes/adLDAPUtils.php');
/**
* Active Directory authentication backend for DokuWiki
@@ -41,7 +36,8 @@ require_once(DOKU_PLUGIN.'authad/adLDAP/classes/adLDAPUtils.php');
* @author Andreas Gohr <andi@splitbrain.org>
* @author Jan Schumann <js@schumann-it.com>
*/
-class auth_plugin_authad extends DokuWiki_Auth_Plugin {
+class auth_plugin_authad extends DokuWiki_Auth_Plugin
+{
/**
* @var array hold connection data for a specific AD domain
@@ -66,52 +62,55 @@ class auth_plugin_authad extends DokuWiki_Auth_Plugin {
/**
* @var array filter patterns for listing users
*/
- protected $_pattern = array();
+ protected $pattern = array();
- protected $_actualstart = 0;
+ protected $actualstart = 0;
- protected $_grpsusers = array();
+ protected $grpsusers = array();
/**
* Constructor
*/
- public function __construct() {
+ public function __construct()
+ {
global $INPUT;
parent::__construct();
+ require_once(DOKU_PLUGIN.'authad/adLDAP/adLDAP.php');
+ require_once(DOKU_PLUGIN.'authad/adLDAP/classes/adLDAPUtils.php');
+
// we load the config early to modify it a bit here
$this->loadConfig();
// additional information fields
- if(isset($this->conf['additional'])) {
+ if (isset($this->conf['additional'])) {
$this->conf['additional'] = str_replace(' ', '', $this->conf['additional']);
$this->conf['additional'] = explode(',', $this->conf['additional']);
} else $this->conf['additional'] = array();
// ldap extension is needed
- if(!function_exists('ldap_connect')) {
- if($this->conf['debug'])
+ if (!function_exists('ldap_connect')) {
+ if ($this->conf['debug'])
msg("AD Auth: PHP LDAP extension not found.", -1);
$this->success = false;
return;
}
// Prepare SSO
- if(!empty($_SERVER['REMOTE_USER'])) {
-
+ if (!empty($_SERVER['REMOTE_USER'])) {
// make sure the right encoding is used
- if($this->getConf('sso_charset')) {
+ if ($this->getConf('sso_charset')) {
$_SERVER['REMOTE_USER'] = iconv($this->getConf('sso_charset'), 'UTF-8', $_SERVER['REMOTE_USER']);
- } elseif(!utf8_check($_SERVER['REMOTE_USER'])) {
+ } elseif (!\dokuwiki\Utf8\Clean::isUtf8($_SERVER['REMOTE_USER'])) {
$_SERVER['REMOTE_USER'] = utf8_encode($_SERVER['REMOTE_USER']);
}
// trust the incoming user
- if($this->conf['sso']) {
+ if ($this->conf['sso']) {
$_SERVER['REMOTE_USER'] = $this->cleanUser($_SERVER['REMOTE_USER']);
// we need to simulate a login
- if(empty($_COOKIE[DOKU_COOKIE])) {
+ if (empty($_COOKIE[DOKU_COOKIE])) {
$INPUT->set('u', $_SERVER['REMOTE_USER']);
$INPUT->set('p', 'sso_only');
}
@@ -130,10 +129,11 @@ class auth_plugin_authad extends DokuWiki_Auth_Plugin {
* @param string $cap
* @return bool
*/
- public function canDo($cap) {
+ public function canDo($cap)
+ {
//capabilities depend on config, which may change depending on domain
- $domain = $this->_userDomain($_SERVER['REMOTE_USER']);
- $this->_loadServerConfig($domain);
+ $domain = $this->getUserDomain($_SERVER['REMOTE_USER']);
+ $this->loadServerConfig($domain);
return parent::canDo($cap);
}
@@ -149,16 +149,22 @@ class auth_plugin_authad extends DokuWiki_Auth_Plugin {
* @param string $pass
* @return bool
*/
- public function checkPass($user, $pass) {
- if($_SERVER['REMOTE_USER'] &&
+ public function checkPass($user, $pass)
+ {
+ if ($_SERVER['REMOTE_USER'] &&
$_SERVER['REMOTE_USER'] == $user &&
$this->conf['sso']
) return true;
- $adldap = $this->_adldap($this->_userDomain($user));
- if(!$adldap) return false;
+ $adldap = $this->initAdLdap($this->getUserDomain($user));
+ if (!$adldap) return false;
- return $adldap->authenticate($this->_userName($user), $pass);
+ try {
+ return $adldap->authenticate($this->getUserName($user), $pass);
+ } catch (adLDAPException $e) {
+ // shouldn't really happen
+ return false;
+ }
}
/**
@@ -186,14 +192,15 @@ class auth_plugin_authad extends DokuWiki_Auth_Plugin {
* @param bool $requireGroups (optional) - ignored, groups are always supplied by this plugin
* @return array
*/
- public function getUserData($user, $requireGroups=true) {
+ public function getUserData($user, $requireGroups = true)
+ {
global $conf;
global $lang;
global $ID;
- $adldap = $this->_adldap($this->_userDomain($user));
- if(!$adldap) return false;
+ $adldap = $this->initAdLdap($this->getUserDomain($user));
+ if (!$adldap) return array();
- if($user == '') return array();
+ if ($user == '') return array();
$fields = array('mail', 'displayname', 'samaccountname', 'lastpwd', 'pwdlastset', 'useraccountcontrol');
@@ -203,8 +210,8 @@ class auth_plugin_authad extends DokuWiki_Auth_Plugin {
$fields = array_filter($fields);
//get info for given user
- $result = $adldap->user()->info($this->_userName($user), $fields);
- if($result == false){
+ $result = $adldap->user()->info($this->getUserName($user), $fields);
+ if ($result == false) {
return array();
}
@@ -220,52 +227,56 @@ class auth_plugin_authad extends DokuWiki_Auth_Plugin {
$info['expires'] = !($result[0]['useraccountcontrol'][0] & 0x10000); //ADS_UF_DONT_EXPIRE_PASSWD
// additional information
- foreach($this->conf['additional'] as $field) {
- if(isset($result[0][strtolower($field)])) {
+ foreach ($this->conf['additional'] as $field) {
+ if (isset($result[0][strtolower($field)])) {
$info[$field] = $result[0][strtolower($field)][0];
}
}
// handle ActiveDirectory memberOf
- $info['grps'] = $adldap->user()->groups($this->_userName($user),(bool) $this->opts['recursive_groups']);
+ $info['grps'] = $adldap->user()->groups($this->getUserName($user), (bool) $this->opts['recursive_groups']);
- if(is_array($info['grps'])) {
- foreach($info['grps'] as $ndx => $group) {
+ if (is_array($info['grps'])) {
+ foreach ($info['grps'] as $ndx => $group) {
$info['grps'][$ndx] = $this->cleanGroup($group);
}
}
// always add the default group to the list of groups
- if(!is_array($info['grps']) || !in_array($conf['defaultgroup'], $info['grps'])) {
+ if (!is_array($info['grps']) || !in_array($conf['defaultgroup'], $info['grps'])) {
$info['grps'][] = $conf['defaultgroup'];
}
// add the user's domain to the groups
- $domain = $this->_userDomain($user);
- if($domain && !in_array("domain-$domain", (array) $info['grps'])) {
+ $domain = $this->getUserDomain($user);
+ if ($domain && !in_array("domain-$domain", (array) $info['grps'])) {
$info['grps'][] = $this->cleanGroup("domain-$domain");
}
// check expiry time
- if($info['expires'] && $this->conf['expirywarn']){
- $expiry = $adldap->user()->passwordExpiry($user);
- if(is_array($expiry)){
- $info['expiresat'] = $expiry['expiryts'];
- $info['expiresin'] = round(($info['expiresat'] - time())/(24*60*60));
-
- // if this is the current user, warn him (once per request only)
- if(($_SERVER['REMOTE_USER'] == $user) &&
- ($info['expiresin'] <= $this->conf['expirywarn']) &&
- !$this->msgshown
- ) {
- $msg = sprintf($this->getLang('authpwdexpire'), $info['expiresin']);
- if($this->canDo('modPass')) {
- $url = wl($ID, array('do'=> 'profile'));
- $msg .= ' <a href="'.$url.'">'.$lang['btn_profile'].'</a>';
+ if ($info['expires'] && $this->conf['expirywarn']) {
+ try {
+ $expiry = $adldap->user()->passwordExpiry($user);
+ if (is_array($expiry)) {
+ $info['expiresat'] = $expiry['expiryts'];
+ $info['expiresin'] = round(($info['expiresat'] - time())/(24*60*60));
+
+ // if this is the current user, warn him (once per request only)
+ if (($_SERVER['REMOTE_USER'] == $user) &&
+ ($info['expiresin'] <= $this->conf['expirywarn']) &&
+ !$this->msgshown
+ ) {
+ $msg = sprintf($this->getLang('authpwdexpire'), $info['expiresin']);
+ if ($this->canDo('modPass')) {
+ $url = wl($ID, array('do'=> 'profile'));
+ $msg .= ' <a href="'.$url.'">'.$lang['btn_profile'].'</a>';
+ }
+ msg($msg);
+ $this->msgshown = true;
}
- msg($msg);
- $this->msgshown = true;
}
+ } catch (adLDAPException $e) {
+ // ignore. should usually not happen
}
}
@@ -281,11 +292,12 @@ class auth_plugin_authad extends DokuWiki_Auth_Plugin {
* @param string $group
* @return string
*/
- public function cleanGroup($group) {
+ public function cleanGroup($group)
+ {
$group = str_replace('\\', '', $group);
$group = str_replace('#', '', $group);
$group = preg_replace('[\s]', '_', $group);
- $group = utf8_strtolower(trim($group));
+ $group = \dokuwiki\Utf8\PhpString::strtolower(trim($group));
return $group;
}
@@ -298,27 +310,28 @@ class auth_plugin_authad extends DokuWiki_Auth_Plugin {
* @param string $user
* @return string
*/
- public function cleanUser($user) {
+ public function cleanUser($user)
+ {
$domain = '';
// get NTLM or Kerberos domain part
list($dom, $user) = explode('\\', $user, 2);
- if(!$user) $user = $dom;
- if($dom) $domain = $dom;
+ if (!$user) $user = $dom;
+ if ($dom) $domain = $dom;
list($user, $dom) = explode('@', $user, 2);
- if($dom) $domain = $dom;
+ if ($dom) $domain = $dom;
// clean up both
- $domain = utf8_strtolower(trim($domain));
- $user = utf8_strtolower(trim($user));
+ $domain = \dokuwiki\Utf8\PhpString::strtolower(trim($domain));
+ $user = \dokuwiki\Utf8\PhpString::strtolower(trim($user));
// is this a known, valid domain? if not discard
- if(!is_array($this->conf[$domain])) {
+ if (!is_array($this->conf[$domain])) {
$domain = '';
}
// reattach domain
- if($domain) $user = "$user@$domain";
+ if ($domain) $user = "$user@$domain";
return $user;
}
@@ -327,7 +340,8 @@ class auth_plugin_authad extends DokuWiki_Auth_Plugin {
*
* @return bool
*/
- public function isCaseSensitive() {
+ public function isCaseSensitive()
+ {
return false;
}
@@ -337,11 +351,12 @@ class auth_plugin_authad extends DokuWiki_Auth_Plugin {
* @param array $filter
* @return string
*/
- protected function _constructSearchString($filter){
- if (!$filter){
+ protected function constructSearchString($filter)
+ {
+ if (!$filter) {
return '*';
}
- $adldapUtils = new adLDAPUtils($this->_adldap(null));
+ $adldapUtils = new adLDAPUtils($this->initAdLdap(null));
$result = '*';
if (isset($filter['name'])) {
$result .= ')(displayname=*' . $adldapUtils->ldapSlashes($filter['name']) . '*';
@@ -366,32 +381,41 @@ class auth_plugin_authad extends DokuWiki_Auth_Plugin {
* @param array $filter $filter array of field/pattern pairs, empty array for no filter
* @return int number of users
*/
- public function getUserCount($filter = array()) {
- $adldap = $this->_adldap(null);
- if(!$adldap) {
+ public function getUserCount($filter = array())
+ {
+ $adldap = $this->initAdLdap(null);
+ if (!$adldap) {
dbglog("authad/auth.php getUserCount(): _adldap not set.");
return -1;
}
if ($filter == array()) {
$result = $adldap->user()->all();
} else {
- $searchString = $this->_constructSearchString($filter);
+ $searchString = $this->constructSearchString($filter);
$result = $adldap->user()->all(false, $searchString);
if (isset($filter['grps'])) {
$this->users = array_fill_keys($result, false);
+ /** @var admin_plugin_usermanager $usermanager */
$usermanager = plugin_load("admin", "usermanager", false);
$usermanager->setLastdisabled(true);
- if (!isset($this->_grpsusers[$this->_filterToString($filter)])){
- $this->_fillGroupUserArray($filter,$usermanager->getStart() + 3*$usermanager->getPagesize());
- } elseif (count($this->_grpsusers[$this->_filterToString($filter)]) < $usermanager->getStart() + 3*$usermanager->getPagesize()) {
- $this->_fillGroupUserArray($filter,$usermanager->getStart() + 3*$usermanager->getPagesize() - count($this->_grpsusers[$this->_filterToString($filter)]));
+ if (!isset($this->grpsusers[$this->filterToString($filter)])) {
+ $this->fillGroupUserArray($filter, $usermanager->getStart() + 3*$usermanager->getPagesize());
+ } elseif (count($this->grpsusers[$this->filterToString($filter)]) <
+ $usermanager->getStart() + 3*$usermanager->getPagesize()
+ ) {
+ $this->fillGroupUserArray(
+ $filter,
+ $usermanager->getStart() +
+ 3*$usermanager->getPagesize() -
+ count($this->grpsusers[$this->filterToString($filter)])
+ );
}
- $result = $this->_grpsusers[$this->_filterToString($filter)];
+ $result = $this->grpsusers[$this->filterToString($filter)];
} else {
+ /** @var admin_plugin_usermanager $usermanager */
$usermanager = plugin_load("admin", "usermanager", false);
$usermanager->setLastdisabled(false);
}
-
}
if (!$result) {
@@ -407,7 +431,8 @@ class auth_plugin_authad extends DokuWiki_Auth_Plugin {
* @param array $filter
* @return string
*/
- protected function _filterToString ($filter) {
+ protected function filterToString($filter)
+ {
$result = '';
if (isset($filter['user'])) {
$result .= 'user-' . $filter['user'];
@@ -433,24 +458,25 @@ class auth_plugin_authad extends DokuWiki_Auth_Plugin {
* @param int $numberOfAdds additional number of users requested
* @return int number of Users actually add to Array
*/
- protected function _fillGroupUserArray($filter, $numberOfAdds){
- $this->_grpsusers[$this->_filterToString($filter)];
+ protected function fillGroupUserArray($filter, $numberOfAdds)
+ {
+ $this->grpsusers[$this->filterToString($filter)];
$i = 0;
$count = 0;
- $this->_constructPattern($filter);
+ $this->constructPattern($filter);
foreach ($this->users as $user => &$info) {
- if($i++ < $this->_actualstart) {
+ if ($i++ < $this->actualstart) {
continue;
}
- if($info === false) {
+ if ($info === false) {
$info = $this->getUserData($user);
}
- if($this->_filter($user, $info)) {
- $this->_grpsusers[$this->_filterToString($filter)][$user] = $info;
- if(($numberOfAdds > 0) && (++$count >= $numberOfAdds)) break;
+ if ($this->filter($user, $info)) {
+ $this->grpsusers[$this->filterToString($filter)][$user] = $info;
+ if (($numberOfAdds > 0) && (++$count >= $numberOfAdds)) break;
}
}
- $this->_actualstart = $i;
+ $this->actualstart = $i;
return $count;
}
@@ -464,13 +490,14 @@ class auth_plugin_authad extends DokuWiki_Auth_Plugin {
* @param array $filter array of field/pattern pairs, null for no filter
* @return array userinfo (refer getUserData for internal userinfo details)
*/
- public function retrieveUsers($start = 0, $limit = 0, $filter = array()) {
- $adldap = $this->_adldap(null);
- if(!$adldap) return false;
+ public function retrieveUsers($start = 0, $limit = 0, $filter = array())
+ {
+ $adldap = $this->initAdLdap(null);
+ if (!$adldap) return array();
- if(!$this->users) {
+ if (!$this->users) {
//get info for given user
- $result = $adldap->user()->all(false, $this->_constructSearchString($filter));
+ $result = $adldap->user()->all(false, $this->constructSearchString($filter));
if (!$result) return array();
$this->users = array_fill_keys($result, false);
}
@@ -480,34 +507,40 @@ class auth_plugin_authad extends DokuWiki_Auth_Plugin {
$result = array();
if (!isset($filter['grps'])) {
+ /** @var admin_plugin_usermanager $usermanager */
$usermanager = plugin_load("admin", "usermanager", false);
$usermanager->setLastdisabled(false);
- $this->_constructPattern($filter);
- foreach($this->users as $user => &$info) {
- if($i++ < $start) {
+ $this->constructPattern($filter);
+ foreach ($this->users as $user => &$info) {
+ if ($i++ < $start) {
continue;
}
- if($info === false) {
+ if ($info === false) {
$info = $this->getUserData($user);
}
$result[$user] = $info;
- if(($limit > 0) && (++$count >= $limit)) break;
+ if (($limit > 0) && (++$count >= $limit)) break;
}
} else {
+ /** @var admin_plugin_usermanager $usermanager */
$usermanager = plugin_load("admin", "usermanager", false);
$usermanager->setLastdisabled(true);
- if (!isset($this->_grpsusers[$this->_filterToString($filter)]) || count($this->_grpsusers[$this->_filterToString($filter)]) < ($start+$limit)) {
- $this->_fillGroupUserArray($filter,$start+$limit - count($this->_grpsusers[$this->_filterToString($filter)]) +1);
+ if (!isset($this->grpsusers[$this->filterToString($filter)]) ||
+ count($this->grpsusers[$this->filterToString($filter)]) < ($start+$limit)
+ ) {
+ $this->fillGroupUserArray(
+ $filter,
+ $start+$limit - count($this->grpsusers[$this->filterToString($filter)]) +1
+ );
}
- if (!$this->_grpsusers[$this->_filterToString($filter)]) return false;
- foreach($this->_grpsusers[$this->_filterToString($filter)] as $user => &$info) {
- if($i++ < $start) {
+ if (!$this->grpsusers[$this->filterToString($filter)]) return array();
+ foreach ($this->grpsusers[$this->filterToString($filter)] as $user => &$info) {
+ if ($i++ < $start) {
continue;
}
$result[$user] = $info;
- if(($limit > 0) && (++$count >= $limit)) break;
+ if (($limit > 0) && (++$count >= $limit)) break;
}
-
}
return $result;
}
@@ -519,45 +552,46 @@ class auth_plugin_authad extends DokuWiki_Auth_Plugin {
* @param array $changes array of field/value pairs to be changed
* @return bool
*/
- public function modifyUser($user, $changes) {
+ public function modifyUser($user, $changes)
+ {
$return = true;
- $adldap = $this->_adldap($this->_userDomain($user));
- if(!$adldap) {
+ $adldap = $this->initAdLdap($this->getUserDomain($user));
+ if (!$adldap) {
msg($this->getLang('connectfail'), -1);
return false;
}
// password changing
- if(isset($changes['pass'])) {
+ if (isset($changes['pass'])) {
try {
- $return = $adldap->user()->password($this->_userName($user),$changes['pass']);
+ $return = $adldap->user()->password($this->getUserName($user), $changes['pass']);
} catch (adLDAPException $e) {
if ($this->conf['debug']) msg('AD Auth: '.$e->getMessage(), -1);
$return = false;
}
- if(!$return) msg($this->getLang('passchangefail'), -1);
+ if (!$return) msg($this->getLang('passchangefail'), -1);
}
// changing user data
$adchanges = array();
- if(isset($changes['name'])) {
+ if (isset($changes['name'])) {
// get first and last name
$parts = explode(' ', $changes['name']);
$adchanges['surname'] = array_pop($parts);
$adchanges['firstname'] = join(' ', $parts);
$adchanges['display_name'] = $changes['name'];
}
- if(isset($changes['mail'])) {
+ if (isset($changes['mail'])) {
$adchanges['email'] = $changes['mail'];
}
- if(count($adchanges)) {
+ if (count($adchanges)) {
try {
- $return = $return & $adldap->user()->modify($this->_userName($user),$adchanges);
+ $return = $return & $adldap->user()->modify($this->getUserName($user), $adchanges);
} catch (adLDAPException $e) {
if ($this->conf['debug']) msg('AD Auth: '.$e->getMessage(), -1);
$return = false;
}
- if(!$return) msg($this->getLang('userchangefail'), -1);
+ if (!$return) msg($this->getLang('userchangefail'), -1);
}
return $return;
@@ -573,20 +607,21 @@ class auth_plugin_authad extends DokuWiki_Auth_Plugin {
* @param string|null $domain The AD domain to use
* @return adLDAP|bool true if a connection was established
*/
- protected function _adldap($domain) {
- if(is_null($domain) && is_array($this->opts)) {
+ protected function initAdLdap($domain)
+ {
+ if (is_null($domain) && is_array($this->opts)) {
$domain = $this->opts['domain'];
}
- $this->opts = $this->_loadServerConfig((string) $domain);
- if(isset($this->adldap[$domain])) return $this->adldap[$domain];
+ $this->opts = $this->loadServerConfig((string) $domain);
+ if (isset($this->adldap[$domain])) return $this->adldap[$domain];
// connect
try {
$this->adldap[$domain] = new adLDAP($this->opts);
return $this->adldap[$domain];
- } catch(adLDAPException $e) {
- if($this->conf['debug']) {
+ } catch (Exception $e) {
+ if ($this->conf['debug']) {
msg('AD Auth: '.$e->getMessage(), -1);
}
$this->success = false;
@@ -601,7 +636,8 @@ class auth_plugin_authad extends DokuWiki_Auth_Plugin {
* @param string $user
* @return string
*/
- public function _userDomain($user) {
+ public function getUserDomain($user)
+ {
list(, $domain) = explode('@', $user, 2);
return $domain;
}
@@ -612,7 +648,8 @@ class auth_plugin_authad extends DokuWiki_Auth_Plugin {
* @param string $user
* @return string
*/
- public function _userName($user) {
+ public function getUserName($user)
+ {
list($name) = explode('@', $user, 2);
return $name;
}
@@ -623,14 +660,15 @@ class auth_plugin_authad extends DokuWiki_Auth_Plugin {
* @param string $domain current AD domain
* @return array
*/
- protected function _loadServerConfig($domain) {
+ protected function loadServerConfig($domain)
+ {
// prepare adLDAP standard configuration
$opts = $this->conf;
$opts['domain'] = $domain;
// add possible domain specific configuration
- if($domain && is_array($this->conf[$domain])) foreach($this->conf[$domain] as $key => $val) {
+ if ($domain && is_array($this->conf[$domain])) foreach ($this->conf[$domain] as $key => $val) {
$opts[$key] = $val;
}
@@ -640,23 +678,27 @@ class auth_plugin_authad extends DokuWiki_Auth_Plugin {
$opts['domain_controllers'] = array_filter($opts['domain_controllers']);
// compatibility with old option name
- if(empty($opts['admin_username']) && !empty($opts['ad_username'])) $opts['admin_username'] = $opts['ad_username'];
- if(empty($opts['admin_password']) && !empty($opts['ad_password'])) $opts['admin_password'] = $opts['ad_password'];
+ if (empty($opts['admin_username']) && !empty($opts['ad_username'])) {
+ $opts['admin_username'] = $opts['ad_username'];
+ }
+ if (empty($opts['admin_password']) && !empty($opts['ad_password'])) {
+ $opts['admin_password'] = $opts['ad_password'];
+ }
$opts['admin_password'] = conf_decodeString($opts['admin_password']); // deobfuscate
// we can change the password if SSL is set
- if($opts['use_ssl'] || $opts['use_tls']) {
+ if ($opts['use_ssl'] || $opts['use_tls']) {
$this->cando['modPass'] = true;
} else {
$this->cando['modPass'] = false;
}
// adLDAP expects empty user/pass as NULL, we're less strict FS#2781
- if(empty($opts['admin_username'])) $opts['admin_username'] = null;
- if(empty($opts['admin_password'])) $opts['admin_password'] = null;
+ if (empty($opts['admin_username'])) $opts['admin_username'] = null;
+ if (empty($opts['admin_password'])) $opts['admin_password'] = null;
// user listing needs admin priviledges
- if(!empty($opts['admin_username']) && !empty($opts['admin_password'])) {
+ if (!empty($opts['admin_username']) && !empty($opts['admin_password'])) {
$this->cando['getUsers'] = true;
} else {
$this->cando['getUsers'] = false;
@@ -672,16 +714,17 @@ class auth_plugin_authad extends DokuWiki_Auth_Plugin {
*
* @return array associative array(key => domain)
*/
- public function _getConfiguredDomains() {
+ public function getConfiguredDomains()
+ {
$domains = array();
- if(empty($this->conf['account_suffix'])) return $domains; // not configured yet
+ if (empty($this->conf['account_suffix'])) return $domains; // not configured yet
// add default domain, using the name from account suffix
$domains[''] = ltrim($this->conf['account_suffix'], '@');
// find additional domains
- foreach($this->conf as $key => $val) {
- if(is_array($val) && isset($val['account_suffix'])) {
+ foreach ($this->conf as $key => $val) {
+ if (is_array($val) && isset($val['account_suffix'])) {
$domains[$key] = ltrim($val['account_suffix'], '@');
}
}
@@ -701,14 +744,15 @@ class auth_plugin_authad extends DokuWiki_Auth_Plugin {
* @param array $info
* @return bool
*/
- protected function _filter($user, $info) {
- foreach($this->_pattern as $item => $pattern) {
- if($item == 'user') {
- if(!preg_match($pattern, $user)) return false;
- } else if($item == 'grps') {
- if(!count(preg_grep($pattern, $info['grps']))) return false;
+ protected function filter($user, $info)
+ {
+ foreach ($this->pattern as $item => $pattern) {
+ if ($item == 'user') {
+ if (!preg_match($pattern, $user)) return false;
+ } elseif ($item == 'grps') {
+ if (!count(preg_grep($pattern, $info['grps']))) return false;
} else {
- if(!preg_match($pattern, $info[$item])) return false;
+ if (!preg_match($pattern, $info[$item])) return false;
}
}
return true;
@@ -721,10 +765,11 @@ class auth_plugin_authad extends DokuWiki_Auth_Plugin {
*
* @param array $filter
*/
- protected function _constructPattern($filter) {
- $this->_pattern = array();
- foreach($filter as $item => $pattern) {
- $this->_pattern[$item] = '/'.str_replace('/', '\/', $pattern).'/i'; // allow regex characters
+ protected function constructPattern($filter)
+ {
+ $this->pattern = array();
+ foreach ($filter as $item => $pattern) {
+ $this->pattern[$item] = '/'.str_replace('/', '\/', $pattern).'/i'; // allow regex characters
}
}
}
diff --git a/lib/plugins/authldap/auth.php b/lib/plugins/authldap/auth.php
index 059611052..68d1dad60 100644
--- a/lib/plugins/authldap/auth.php
+++ b/lib/plugins/authldap/auth.php
@@ -1,6 +1,4 @@
<?php
-// must be run within Dokuwiki
-if(!defined('DOKU_INC')) die();
/**
* LDAP authentication backend
@@ -10,8 +8,9 @@ if(!defined('DOKU_INC')) die();
* @author Chris Smith <chris@jalakaic.co.uk>
* @author Jan Schumann <js@schumann-it.com>
*/
-class auth_plugin_authldap extends DokuWiki_Auth_Plugin {
- /* @var resource $con holds the LDAP connection*/
+class auth_plugin_authldap extends DokuWiki_Auth_Plugin
+{
+ /* @var resource $con holds the LDAP connection */
protected $con = null;
/* @var int $bound What type of connection does already exist? */
@@ -20,18 +19,19 @@ class auth_plugin_authldap extends DokuWiki_Auth_Plugin {
/* @var array $users User data cache */
protected $users = null;
- /* @var array $_pattern User filter pattern */
- protected $_pattern = null;
+ /* @var array $pattern User filter pattern */
+ protected $pattern = null;
/**
* Constructor
*/
- public function __construct() {
+ public function __construct()
+ {
parent::__construct();
// ldap extension is needed
- if(!function_exists('ldap_connect')) {
- $this->_debug("LDAP err: PHP LDAP extension not found.", -1, __LINE__, __FILE__);
+ if (!function_exists('ldap_connect')) {
+ $this->debug("LDAP err: PHP LDAP extension not found.", -1, __LINE__, __FILE__);
$this->success = false;
return;
}
@@ -47,73 +47,72 @@ class auth_plugin_authldap extends DokuWiki_Auth_Plugin {
* plaintext password is correct by trying to bind
* to the LDAP server
*
- * @author Andreas Gohr <andi@splitbrain.org>
* @param string $user
* @param string $pass
* @return bool
+ * @author Andreas Gohr <andi@splitbrain.org>
*/
- public function checkPass($user, $pass) {
+ public function checkPass($user, $pass)
+ {
// reject empty password
- if(empty($pass)) return false;
- if(!$this->_openLDAP()) return false;
+ if (empty($pass)) return false;
+ if (!$this->openLDAP()) return false;
// indirect user bind
- if($this->getConf('binddn') && $this->getConf('bindpw')) {
+ if ($this->getConf('binddn') && $this->getConf('bindpw')) {
// use superuser credentials
- if(!@ldap_bind($this->con, $this->getConf('binddn'), conf_decodeString($this->getConf('bindpw')))) {
- $this->_debug('LDAP bind as superuser: '.htmlspecialchars(ldap_error($this->con)), 0, __LINE__, __FILE__);
+ if (!@ldap_bind($this->con, $this->getConf('binddn'), conf_decodeString($this->getConf('bindpw')))) {
+ $this->debug('LDAP bind as superuser: ' . hsc(ldap_error($this->con)), 0, __LINE__, __FILE__);
return false;
}
$this->bound = 2;
- } else if($this->getConf('binddn') &&
+ } elseif ($this->getConf('binddn') &&
$this->getConf('usertree') &&
$this->getConf('userfilter')
) {
// special bind string
- $dn = $this->_makeFilter(
+ $dn = $this->makeFilter(
$this->getConf('binddn'),
- array('user'=> $user, 'server'=> $this->getConf('server'))
+ array('user' => $user, 'server' => $this->getConf('server'))
);
-
- } else if(strpos($this->getConf('usertree'), '%{user}')) {
+ } elseif (strpos($this->getConf('usertree'), '%{user}')) {
// direct user bind
- $dn = $this->_makeFilter(
+ $dn = $this->makeFilter(
$this->getConf('usertree'),
- array('user'=> $user, 'server'=> $this->getConf('server'))
+ array('user' => $user, 'server' => $this->getConf('server'))
);
-
} else {
// Anonymous bind
- if(!@ldap_bind($this->con)) {
+ if (!@ldap_bind($this->con)) {
msg("LDAP: can not bind anonymously", -1);
- $this->_debug('LDAP anonymous bind: '.htmlspecialchars(ldap_error($this->con)), 0, __LINE__, __FILE__);
+ $this->debug('LDAP anonymous bind: ' . hsc(ldap_error($this->con)), 0, __LINE__, __FILE__);
return false;
}
}
// Try to bind to with the dn if we have one.
- if(!empty($dn)) {
+ if (!empty($dn)) {
// User/Password bind
- if(!@ldap_bind($this->con, $dn, $pass)) {
- $this->_debug("LDAP: bind with $dn failed", -1, __LINE__, __FILE__);
- $this->_debug('LDAP user dn bind: '.htmlspecialchars(ldap_error($this->con)), 0, __LINE__, __FILE__);
+ if (!@ldap_bind($this->con, $dn, $pass)) {
+ $this->debug("LDAP: bind with $dn failed", -1, __LINE__, __FILE__);
+ $this->debug('LDAP user dn bind: ' . hsc(ldap_error($this->con)), 0, __LINE__, __FILE__);
return false;
}
$this->bound = 1;
return true;
} else {
// See if we can find the user
- $info = $this->_getUserData($user, true);
- if(empty($info['dn'])) {
+ $info = $this->fetchUserData($user, true);
+ if (empty($info['dn'])) {
return false;
} else {
$dn = $info['dn'];
}
// Try to bind with the dn provided
- if(!@ldap_bind($this->con, $dn, $pass)) {
- $this->_debug("LDAP: bind with $dn failed", -1, __LINE__, __FILE__);
- $this->_debug('LDAP user bind: '.htmlspecialchars(ldap_error($this->con)), 0, __LINE__, __FILE__);
+ if (!@ldap_bind($this->con, $dn, $pass)) {
+ $this->debug("LDAP: bind with $dn failed", -1, __LINE__, __FILE__);
+ $this->debug('LDAP user bind: ' . hsc(ldap_error($this->con)), 0, __LINE__, __FILE__);
return false;
}
$this->bound = 1;
@@ -138,113 +137,119 @@ class auth_plugin_authldap extends DokuWiki_Auth_Plugin {
* uid string Posix User ID
* inbind bool for internal use - avoid loop in binding
*
- * @author Andreas Gohr <andi@splitbrain.org>
- * @author Trouble
- * @author Dan Allen <dan.j.allen@gmail.com>
+ * @param string $user
+ * @param bool $requireGroups (optional) - ignored, groups are always supplied by this plugin
+ * @return array containing user data or false
* @author <evaldas.auryla@pheur.org>
* @author Stephane Chazelas <stephane.chazelas@emerson.com>
* @author Steffen Schoch <schoch@dsb.net>
*
- * @param string $user
- * @param bool $requireGroups (optional) - ignored, groups are always supplied by this plugin
- * @return array containing user data or false
+ * @author Andreas Gohr <andi@splitbrain.org>
+ * @author Trouble
+ * @author Dan Allen <dan.j.allen@gmail.com>
*/
- public function getUserData($user, $requireGroups=true) {
- return $this->_getUserData($user);
+ public function getUserData($user, $requireGroups = true)
+ {
+ return $this->fetchUserData($user);
}
/**
- * @param string $user
- * @param bool $inbind authldap specific, true if in bind phase
+ * @param string $user
+ * @param bool $inbind authldap specific, true if in bind phase
* @return array containing user data or false
*/
- protected function _getUserData($user, $inbind = false) {
+ protected function fetchUserData($user, $inbind = false)
+ {
global $conf;
- if(!$this->_openLDAP()) return false;
+ if (!$this->openLDAP()) return array();
// force superuser bind if wanted and not bound as superuser yet
- if($this->getConf('binddn') && $this->getConf('bindpw') && $this->bound < 2) {
+ if ($this->getConf('binddn') && $this->getConf('bindpw') && $this->bound < 2) {
// use superuser credentials
- if(!@ldap_bind($this->con, $this->getConf('binddn'), conf_decodeString($this->getConf('bindpw')))) {
- $this->_debug('LDAP bind as superuser: '.htmlspecialchars(ldap_error($this->con)), 0, __LINE__, __FILE__);
- return false;
+ if (!@ldap_bind($this->con, $this->getConf('binddn'), conf_decodeString($this->getConf('bindpw')))) {
+ $this->debug('LDAP bind as superuser: ' . hsc(ldap_error($this->con)), 0, __LINE__, __FILE__);
+ return array();
}
$this->bound = 2;
- } elseif($this->bound == 0 && !$inbind) {
+ } elseif ($this->bound == 0 && !$inbind) {
// in some cases getUserData is called outside the authentication workflow
// eg. for sending email notification on subscribed pages. This data might not
// be accessible anonymously, so we try to rebind the current user here
list($loginuser, $loginsticky, $loginpass) = auth_getCookie();
- if($loginuser && $loginpass) {
+ if ($loginuser && $loginpass) {
$loginpass = auth_decrypt($loginpass, auth_cookiesalt(!$loginsticky, true));
$this->checkPass($loginuser, $loginpass);
}
}
$info = array();
- $info['user'] = $user;
- $this->_debug('LDAP user to find: '.htmlspecialchars($info['user']), 0, __LINE__, __FILE__);
+ $info['user'] = $user;
+ $this->debug('LDAP user to find: ' . hsc($info['user']), 0, __LINE__, __FILE__);
$info['server'] = $this->getConf('server');
- $this->_debug('LDAP Server: '.htmlspecialchars($info['server']), 0, __LINE__, __FILE__);
-
+ $this->debug('LDAP Server: ' . hsc($info['server']), 0, __LINE__, __FILE__);
//get info for given user
- $base = $this->_makeFilter($this->getConf('usertree'), $info);
- if($this->getConf('userfilter')) {
- $filter = $this->_makeFilter($this->getConf('userfilter'), $info);
+ $base = $this->makeFilter($this->getConf('usertree'), $info);
+ if ($this->getConf('userfilter')) {
+ $filter = $this->makeFilter($this->getConf('userfilter'), $info);
} else {
$filter = "(ObjectClass=*)";
}
- $this->_debug('LDAP Filter: '.htmlspecialchars($filter), 0, __LINE__, __FILE__);
+ $this->debug('LDAP Filter: ' . hsc($filter), 0, __LINE__, __FILE__);
+
+ $this->debug('LDAP user search: ' . hsc(ldap_error($this->con)), 0, __LINE__, __FILE__);
+ $this->debug('LDAP search at: ' . hsc($base . ' ' . $filter), 0, __LINE__, __FILE__);
+ $sr = $this->ldapSearch($this->con, $base, $filter, $this->getConf('userscope'), $this->getConf('attributes'));
- $this->_debug('LDAP user search: '.htmlspecialchars(ldap_error($this->con)), 0, __LINE__, __FILE__);
- $this->_debug('LDAP search at: '.htmlspecialchars($base.' '.$filter), 0, __LINE__, __FILE__);
- $sr = $this->_ldapsearch($this->con, $base, $filter, $this->getConf('userscope'), $this->getConf('attributes'));
- $result = @ldap_get_entries($this->con, $sr);
+ $result = @ldap_get_entries($this->con, $sr);
// if result is not an array
- if(!is_array($result)) {
- // no objects found
- $this->_debug('LDAP search returned non-array result: '.htmlspecialchars(print($result)), -1, __LINE__, __FILE__);
- return false;
+ if (!is_array($result)) {
+ // no objects found
+ $this->debug('LDAP search returned non-array result: ' . hsc(print($result)), -1, __LINE__, __FILE__);
+ return array();
}
- // Don't accept more or less than one response
- if ($result['count'] != 1) {
- $this->_debug('LDAP search returned '.htmlspecialchars($result['count']).' results while it should return 1!', -1, __LINE__, __FILE__);
- //for($i = 0; $i < $result["count"]; $i++) {
- //$this->_debug('result: '.htmlspecialchars(print_r($result[$i])), 0, __LINE__, __FILE__);
- //}
- return false;
- }
-
+ // Don't accept more or less than one response
+ if ($result['count'] != 1) {
+ $this->debug(
+ 'LDAP search returned ' . hsc($result['count']) . ' results while it should return 1!',
+ -1,
+ __LINE__,
+ __FILE__
+ );
+ //for($i = 0; $i < $result["count"]; $i++) {
+ //$this->_debug('result: '.hsc(print_r($result[$i])), 0, __LINE__, __FILE__);
+ //}
+ return array();
+ }
- $this->_debug('LDAP search found single result !', 0, __LINE__, __FILE__);
+ $this->debug('LDAP search found single result !', 0, __LINE__, __FILE__);
$user_result = $result[0];
ldap_free_result($sr);
// general user info
- $info['dn'] = $user_result['dn'];
- $info['gid'] = $user_result['gidnumber'][0];
+ $info['dn'] = $user_result['dn'];
+ $info['gid'] = $user_result['gidnumber'][0];
$info['mail'] = $user_result['mail'][0];
$info['name'] = $user_result['cn'][0];
$info['grps'] = array();
// overwrite if other attribs are specified.
- if(is_array($this->getConf('mapping'))) {
- foreach($this->getConf('mapping') as $localkey => $key) {
- if(is_array($key)) {
+ if (is_array($this->getConf('mapping'))) {
+ foreach ($this->getConf('mapping') as $localkey => $key) {
+ if (is_array($key)) {
// use regexp to clean up user_result
// $key = array($key=>$regexp), only handles the first key-value
$regexp = current($key);
$key = key($key);
- if($user_result[$key]) foreach($user_result[$key] as $grpkey => $grp) {
- if($grpkey !== 'count' && preg_match($regexp, $grp, $match)) {
- if($localkey == 'grps') {
+ if ($user_result[$key]) foreach ($user_result[$key] as $grpkey => $grp) {
+ if ($grpkey !== 'count' && preg_match($regexp, $grp, $match)) {
+ if ($localkey == 'grps') {
$info[$localkey][] = $match[1];
} else {
$info[$localkey] = $match[1];
@@ -259,38 +264,44 @@ class auth_plugin_authldap extends DokuWiki_Auth_Plugin {
$user_result = array_merge($info, $user_result);
//get groups for given user if grouptree is given
- if($this->getConf('grouptree') || $this->getConf('groupfilter')) {
- $base = $this->_makeFilter($this->getConf('grouptree'), $user_result);
- $filter = $this->_makeFilter($this->getConf('groupfilter'), $user_result);
- $sr = $this->_ldapsearch($this->con, $base, $filter, $this->getConf('groupscope'), array($this->getConf('groupkey')));
- $this->_debug('LDAP group search: '.htmlspecialchars(ldap_error($this->con)), 0, __LINE__, __FILE__);
- $this->_debug('LDAP search at: '.htmlspecialchars($base.' '.$filter), 0, __LINE__, __FILE__);
-
- if(!$sr) {
+ if ($this->getConf('grouptree') || $this->getConf('groupfilter')) {
+ $base = $this->makeFilter($this->getConf('grouptree'), $user_result);
+ $filter = $this->makeFilter($this->getConf('groupfilter'), $user_result);
+ $sr = $this->ldapSearch(
+ $this->con,
+ $base,
+ $filter,
+ $this->getConf('groupscope'),
+ array($this->getConf('groupkey'))
+ );
+ $this->debug('LDAP group search: ' . hsc(ldap_error($this->con)), 0, __LINE__, __FILE__);
+ $this->debug('LDAP search at: ' . hsc($base . ' ' . $filter), 0, __LINE__, __FILE__);
+
+ if (!$sr) {
msg("LDAP: Reading group memberships failed", -1);
- return false;
+ return array();
}
$result = ldap_get_entries($this->con, $sr);
ldap_free_result($sr);
- if(is_array($result)) foreach($result as $grp) {
- if(!empty($grp[$this->getConf('groupkey')])) {
+ if (is_array($result)) foreach ($result as $grp) {
+ if (!empty($grp[$this->getConf('groupkey')])) {
$group = $grp[$this->getConf('groupkey')];
- if(is_array($group)){
+ if (is_array($group)) {
$group = $group[0];
} else {
- $this->_debug('groupkey did not return a detailled result', 0, __LINE__, __FILE__);
+ $this->debug('groupkey did not return a detailled result', 0, __LINE__, __FILE__);
}
- if($group === '') continue;
+ if ($group === '') continue;
- $this->_debug('LDAP usergroup: '.htmlspecialchars($group), 0, __LINE__, __FILE__);
+ $this->debug('LDAP usergroup: ' . hsc($group), 0, __LINE__, __FILE__);
$info['grps'][] = $group;
}
}
}
// always add the default group to the list of groups
- if(!$info['grps'] or !in_array($conf['defaultgroup'], $info['grps'])) {
+ if (!$info['grps'] or !in_array($conf['defaultgroup'], $info['grps'])) {
$info['grps'][] = $conf['defaultgroup'];
}
return $info;
@@ -299,57 +310,66 @@ class auth_plugin_authldap extends DokuWiki_Auth_Plugin {
/**
* Definition of the function modifyUser in order to modify the password
*
- * @param string $user nick of the user to be changed
- * @param array $changes array of field/value pairs to be changed (password will be clear text)
+ * @param string $user nick of the user to be changed
+ * @param array $changes array of field/value pairs to be changed (password will be clear text)
* @return bool true on success, false on error
*/
-
- function modifyUser($user,$changes){
+ public function modifyUser($user, $changes)
+ {
// open the connection to the ldap
- if(!$this->_openLDAP()){
- $this->_debug('LDAP cannot connect: '. htmlspecialchars(ldap_error($this->con)), 0, __LINE__, __FILE__);
+ if (!$this->openLDAP()) {
+ $this->debug('LDAP cannot connect: ' . hsc(ldap_error($this->con)), 0, __LINE__, __FILE__);
return false;
}
// find the information about the user, in particular the "dn"
- $info = $this->getUserData($user,true);
- if(empty($info['dn'])) {
- $this->_debug('LDAP cannot find your user dn', 0, __LINE__, __FILE__);
+ $info = $this->getUserData($user, true);
+ if (empty($info['dn'])) {
+ $this->debug('LDAP cannot find your user dn', 0, __LINE__, __FILE__);
return false;
}
$dn = $info['dn'];
// find the old password of the user
- list($loginuser,$loginsticky,$loginpass) = auth_getCookie();
+ list($loginuser, $loginsticky, $loginpass) = auth_getCookie();
if ($loginuser !== null) { // the user is currently logged in
$secret = auth_cookiesalt(!$loginsticky, true);
- $pass = auth_decrypt($loginpass, $secret);
+ $pass = auth_decrypt($loginpass, $secret);
// bind with the ldap
- if(!@ldap_bind($this->con, $dn, $pass)){
- $this->_debug('LDAP user bind failed: '. htmlspecialchars($dn) .': '.htmlspecialchars(ldap_error($this->con)), 0, __LINE__, __FILE__);
+ if (!@ldap_bind($this->con, $dn, $pass)) {
+ $this->debug(
+ 'LDAP user bind failed: ' . hsc($dn) . ': ' . hsc(ldap_error($this->con)),
+ 0,
+ __LINE__,
+ __FILE__
+ );
return false;
}
} elseif ($this->getConf('binddn') && $this->getConf('bindpw')) {
// we are changing the password on behalf of the user (eg: forgotten password)
// bind with the superuser ldap
- if (!@ldap_bind($this->con, $this->getConf('binddn'), conf_decodeString($this->getConf('bindpw')))){
- $this->_debug('LDAP bind as superuser: '.htmlspecialchars(ldap_error($this->con)), 0, __LINE__, __FILE__);
+ if (!@ldap_bind($this->con, $this->getConf('binddn'), conf_decodeString($this->getConf('bindpw')))) {
+ $this->debug('LDAP bind as superuser: ' . hsc(ldap_error($this->con)), 0, __LINE__, __FILE__);
return false;
}
- }
- else {
+ } else {
return false; // no otherway
}
// Generate the salted hashed password for LDAP
- $phash = new PassHash();
+ $phash = new \dokuwiki\PassHash();
$hash = $phash->hash_ssha($changes['pass']);
// change the password
- if(!@ldap_mod_replace($this->con, $dn,array('userpassword' => $hash))){
- $this->_debug('LDAP mod replace failed: '. htmlspecialchars($dn) .': '.htmlspecialchars(ldap_error($this->con)), 0, __LINE__, __FILE__);
+ if (!@ldap_mod_replace($this->con, $dn, array('userpassword' => $hash))) {
+ $this->debug(
+ 'LDAP mod replace failed: ' . hsc($dn) . ': ' . hsc(ldap_error($this->con)),
+ 0,
+ __LINE__,
+ __FILE__
+ );
return false;
}
@@ -361,56 +381,58 @@ class auth_plugin_authldap extends DokuWiki_Auth_Plugin {
*
* @return bool
*/
- public function isCaseSensitive() {
+ public function isCaseSensitive()
+ {
return false;
}
/**
* Bulk retrieval of user data
*
- * @author Dominik Eckelmann <dokuwiki@cosmocode.de>
- * @param int $start index of first user to be returned
- * @param int $limit max number of users to be returned
- * @param array $filter array of field/pattern pairs, null for no filter
+ * @param int $start index of first user to be returned
+ * @param int $limit max number of users to be returned
+ * @param array $filter array of field/pattern pairs, null for no filter
* @return array of userinfo (refer getUserData for internal userinfo details)
+ * @author Dominik Eckelmann <dokuwiki@cosmocode.de>
*/
- function retrieveUsers($start = 0, $limit = 0, $filter = array()) {
- if(!$this->_openLDAP()) return false;
+ public function retrieveUsers($start = 0, $limit = 0, $filter = array())
+ {
+ if (!$this->openLDAP()) return array();
- if(is_null($this->users)) {
+ if (is_null($this->users)) {
// Perform the search and grab all their details
- if($this->getConf('userfilter')) {
+ if ($this->getConf('userfilter')) {
$all_filter = str_replace('%{user}', '*', $this->getConf('userfilter'));
} else {
$all_filter = "(ObjectClass=*)";
}
- $sr = ldap_search($this->con, $this->getConf('usertree'), $all_filter);
- $entries = ldap_get_entries($this->con, $sr);
+ $sr = ldap_search($this->con, $this->getConf('usertree'), $all_filter);
+ $entries = ldap_get_entries($this->con, $sr);
$users_array = array();
- $userkey = $this->getConf('userkey');
- for($i = 0; $i < $entries["count"]; $i++) {
+ $userkey = $this->getConf('userkey');
+ for ($i = 0; $i < $entries["count"]; $i++) {
array_push($users_array, $entries[$i][$userkey][0]);
}
asort($users_array);
$result = $users_array;
- if(!$result) return array();
+ if (!$result) return array();
$this->users = array_fill_keys($result, false);
}
- $i = 0;
+ $i = 0;
$count = 0;
- $this->_constructPattern($filter);
+ $this->constructPattern($filter);
$result = array();
- foreach($this->users as $user => &$info) {
- if($i++ < $start) {
+ foreach ($this->users as $user => &$info) {
+ if ($i++ < $start) {
continue;
}
- if($info === false) {
+ if ($info === false) {
$info = $this->getUserData($user);
}
- if($this->_filter($user, $info)) {
+ if ($this->filter($user, $info)) {
$result[$user] = $info;
- if(($limit > 0) && (++$count >= $limit)) break;
+ if (($limit > 0) && (++$count >= $limit)) break;
}
}
return $result;
@@ -422,23 +444,24 @@ class auth_plugin_authldap extends DokuWiki_Auth_Plugin {
* Used by auth_getUserData to make the filter
* strings for grouptree and groupfilter
*
- * @author Troels Liebe Bentsen <tlb@rapanden.dk>
- * @param string $filter ldap search filter with placeholders
- * @param array $placeholders placeholders to fill in
+ * @param string $filter ldap search filter with placeholders
+ * @param array $placeholders placeholders to fill in
* @return string
+ * @author Troels Liebe Bentsen <tlb@rapanden.dk>
*/
- protected function _makeFilter($filter, $placeholders) {
+ protected function makeFilter($filter, $placeholders)
+ {
preg_match_all("/%{([^}]+)/", $filter, $matches, PREG_PATTERN_ORDER);
//replace each match
- foreach($matches[1] as $match) {
+ foreach ($matches[1] as $match) {
//take first element if array
- if(is_array($placeholders[$match])) {
+ if (is_array($placeholders[$match])) {
$value = $placeholders[$match][0];
} else {
$value = $placeholders[$match];
}
- $value = $this->_filterEscape($value);
- $filter = str_replace('%{'.$match.'}', $value, $filter);
+ $value = $this->filterEscape($value);
+ $filter = str_replace('%{' . $match . '}', $value, $filter);
}
return $filter;
}
@@ -446,20 +469,21 @@ class auth_plugin_authldap extends DokuWiki_Auth_Plugin {
/**
* return true if $user + $info match $filter criteria, false otherwise
*
+ * @param string $user the user's login name
+ * @param array $info the user's userinfo array
+ * @return bool
* @author Chris Smith <chris@jalakai.co.uk>
*
- * @param string $user the user's login name
- * @param array $info the user's userinfo array
- * @return bool
*/
- protected function _filter($user, $info) {
- foreach($this->_pattern as $item => $pattern) {
- if($item == 'user') {
- if(!preg_match($pattern, $user)) return false;
- } else if($item == 'grps') {
- if(!count(preg_grep($pattern, $info['grps']))) return false;
+ protected function filter($user, $info)
+ {
+ foreach ($this->pattern as $item => $pattern) {
+ if ($item == 'user') {
+ if (!preg_match($pattern, $user)) return false;
+ } elseif ($item == 'grps') {
+ if (!count(preg_grep($pattern, $info['grps']))) return false;
} else {
- if(!preg_match($pattern, $info[$item])) return false;
+ if (!preg_match($pattern, $info[$item])) return false;
}
}
return true;
@@ -468,15 +492,16 @@ class auth_plugin_authldap extends DokuWiki_Auth_Plugin {
/**
* Set the filter pattern
*
- * @author Chris Smith <chris@jalakai.co.uk>
- *
* @param $filter
* @return void
+ * @author Chris Smith <chris@jalakai.co.uk>
+ *
*/
- protected function _constructPattern($filter) {
- $this->_pattern = array();
- foreach($filter as $item => $pattern) {
- $this->_pattern[$item] = '/'.str_replace('/', '\/', $pattern).'/i'; // allow regex characters
+ protected function constructPattern($filter)
+ {
+ $this->pattern = array();
+ foreach ($filter as $item => $pattern) {
+ $this->pattern[$item] = '/' . str_replace('/', '\/', $pattern) . '/i'; // allow regex characters
}
}
@@ -485,16 +510,17 @@ class auth_plugin_authldap extends DokuWiki_Auth_Plugin {
*
* Ported from Perl's Net::LDAP::Util escape_filter_value
*
- * @author Andreas Gohr
- * @param string $string
+ * @param string $string
* @return string
+ * @author Andreas Gohr
*/
- protected function _filterEscape($string) {
+ protected function filterEscape($string)
+ {
// see https://github.com/adldap/adLDAP/issues/22
return preg_replace_callback(
'/([\x00-\x1F\*\(\)\\\\])/',
function ($matches) {
- return "\\".join("", unpack("H2", $matches[1]));
+ return "\\" . join("", unpack("H2", $matches[1]));
},
$string
);
@@ -506,22 +532,23 @@ class auth_plugin_authldap extends DokuWiki_Auth_Plugin {
*
* @author Andreas Gohr <andi@splitbrain.org>
*/
- protected function _openLDAP() {
- if($this->con) return true; // connection already established
+ protected function openLDAP()
+ {
+ if ($this->con) return true; // connection already established
- if($this->getConf('debug')) {
- ldap_set_option(NULL, LDAP_OPT_DEBUG_LEVEL, 7);
+ if ($this->getConf('debug')) {
+ ldap_set_option(null, LDAP_OPT_DEBUG_LEVEL, 7);
}
$this->bound = 0;
- $port = $this->getConf('port');
- $bound = false;
+ $port = $this->getConf('port');
+ $bound = false;
$servers = explode(',', $this->getConf('server'));
- foreach($servers as $server) {
- $server = trim($server);
+ foreach ($servers as $server) {
+ $server = trim($server);
$this->con = @ldap_connect($server, $port);
- if(!$this->con) {
+ if (!$this->con) {
continue;
}
@@ -534,62 +561,64 @@ class auth_plugin_authldap extends DokuWiki_Auth_Plugin {
*/
//set protocol version and dependend options
- if($this->getConf('version')) {
- if(!@ldap_set_option(
- $this->con, LDAP_OPT_PROTOCOL_VERSION,
+ if ($this->getConf('version')) {
+ if (!@ldap_set_option(
+ $this->con,
+ LDAP_OPT_PROTOCOL_VERSION,
$this->getConf('version')
)
) {
- msg('Setting LDAP Protocol version '.$this->getConf('version').' failed', -1);
- $this->_debug('LDAP version set: '.htmlspecialchars(ldap_error($this->con)), 0, __LINE__, __FILE__);
+ msg('Setting LDAP Protocol version ' . $this->getConf('version') . ' failed', -1);
+ $this->debug('LDAP version set: ' . hsc(ldap_error($this->con)), 0, __LINE__, __FILE__);
} else {
//use TLS (needs version 3)
- if($this->getConf('starttls')) {
- if(!@ldap_start_tls($this->con)) {
+ if ($this->getConf('starttls')) {
+ if (!@ldap_start_tls($this->con)) {
msg('Starting TLS failed', -1);
- $this->_debug('LDAP TLS set: '.htmlspecialchars(ldap_error($this->con)), 0, __LINE__, __FILE__);
+ $this->debug('LDAP TLS set: ' . hsc(ldap_error($this->con)), 0, __LINE__, __FILE__);
}
}
// needs version 3
- if($this->getConf('referrals') > -1) {
- if(!@ldap_set_option(
- $this->con, LDAP_OPT_REFERRALS,
+ if ($this->getConf('referrals') > -1) {
+ if (!@ldap_set_option(
+ $this->con,
+ LDAP_OPT_REFERRALS,
$this->getConf('referrals')
)
) {
msg('Setting LDAP referrals failed', -1);
- $this->_debug('LDAP referal set: '.htmlspecialchars(ldap_error($this->con)), 0, __LINE__, __FILE__);
+ $this->debug('LDAP referal set: ' . hsc(ldap_error($this->con)), 0, __LINE__, __FILE__);
}
}
}
}
//set deref mode
- if($this->getConf('deref')) {
- if(!@ldap_set_option($this->con, LDAP_OPT_DEREF, $this->getConf('deref'))) {
- msg('Setting LDAP Deref mode '.$this->getConf('deref').' failed', -1);
- $this->_debug('LDAP deref set: '.htmlspecialchars(ldap_error($this->con)), 0, __LINE__, __FILE__);
+ if ($this->getConf('deref')) {
+ if (!@ldap_set_option($this->con, LDAP_OPT_DEREF, $this->getConf('deref'))) {
+ msg('Setting LDAP Deref mode ' . $this->getConf('deref') . ' failed', -1);
+ $this->debug('LDAP deref set: ' . hsc(ldap_error($this->con)), 0, __LINE__, __FILE__);
}
}
/* As of PHP 5.3.0 we can set timeout to speedup skipping of invalid servers */
- if(defined('LDAP_OPT_NETWORK_TIMEOUT')) {
+ if (defined('LDAP_OPT_NETWORK_TIMEOUT')) {
ldap_set_option($this->con, LDAP_OPT_NETWORK_TIMEOUT, 1);
}
- if($this->getConf('binddn') && $this->getConf('bindpw')) {
+ if ($this->getConf('binddn') && $this->getConf('bindpw')) {
$bound = @ldap_bind($this->con, $this->getConf('binddn'), conf_decodeString($this->getConf('bindpw')));
$this->bound = 2;
} else {
$bound = @ldap_bind($this->con);
}
- if($bound) {
+ if ($bound) {
break;
}
}
- if(!$bound) {
+ if (!$bound) {
msg("LDAP: couldn't connect to LDAP server", -1);
- $this->_debug(ldap_error($this->con), 0, __LINE__, __FILE__);
+ $this->debug(ldap_error($this->con), 0, __LINE__, __FILE__);
return false;
}
@@ -600,34 +629,54 @@ class auth_plugin_authldap extends DokuWiki_Auth_Plugin {
/**
* Wraps around ldap_search, ldap_list or ldap_read depending on $scope
*
- * @author Andreas Gohr <andi@splitbrain.org>
- * @param resource $link_identifier
- * @param string $base_dn
- * @param string $filter
- * @param string $scope can be 'base', 'one' or 'sub'
+ * @param resource $link_identifier
+ * @param string $base_dn
+ * @param string $filter
+ * @param string $scope can be 'base', 'one' or 'sub'
* @param null|array $attributes
- * @param int $attrsonly
- * @param int $sizelimit
+ * @param int $attrsonly
+ * @param int $sizelimit
* @return resource
+ * @author Andreas Gohr <andi@splitbrain.org>
*/
- protected function _ldapsearch($link_identifier, $base_dn, $filter, $scope = 'sub', $attributes = null,
- $attrsonly = 0, $sizelimit = 0) {
- if(is_null($attributes)) $attributes = array();
-
- if($scope == 'base') {
+ protected function ldapSearch(
+ $link_identifier,
+ $base_dn,
+ $filter,
+ $scope = 'sub',
+ $attributes = null,
+ $attrsonly = 0,
+ $sizelimit = 0
+ )
+ {
+ if (is_null($attributes)) $attributes = array();
+
+ if ($scope == 'base') {
return @ldap_read(
- $link_identifier, $base_dn, $filter, $attributes,
- $attrsonly, $sizelimit
+ $link_identifier,
+ $base_dn,
+ $filter,
+ $attributes,
+ $attrsonly,
+ $sizelimit
);
- } elseif($scope == 'one') {
+ } elseif ($scope == 'one') {
return @ldap_list(
- $link_identifier, $base_dn, $filter, $attributes,
- $attrsonly, $sizelimit
+ $link_identifier,
+ $base_dn,
+ $filter,
+ $attributes,
+ $attrsonly,
+ $sizelimit
);
} else {
return @ldap_search(
- $link_identifier, $base_dn, $filter, $attributes,
- $attrsonly, $sizelimit
+ $link_identifier,
+ $base_dn,
+ $filter,
+ $attributes,
+ $attrsonly,
+ $sizelimit
);
}
}
@@ -636,14 +685,14 @@ class auth_plugin_authldap extends DokuWiki_Auth_Plugin {
* Wrapper around msg() but outputs only when debug is enabled
*
* @param string $message
- * @param int $err
- * @param int $line
+ * @param int $err
+ * @param int $line
* @param string $file
* @return void
*/
- protected function _debug($message, $err, $line, $file) {
- if(!$this->getConf('debug')) return;
+ protected function debug($message, $err, $line, $file)
+ {
+ if (!$this->getConf('debug')) return;
msg($message, $err, $line, $file);
}
-
}
diff --git a/lib/plugins/authpdo/_test/sqlite.test.php b/lib/plugins/authpdo/_test/sqlite.test.php
index 35b612604..89cc9f60d 100644
--- a/lib/plugins/authpdo/_test/sqlite.test.php
+++ b/lib/plugins/authpdo/_test/sqlite.test.php
@@ -10,8 +10,8 @@ class testable_auth_plugin_authpdo extends auth_plugin_authpdo {
return 'authpdo';
}
- public function _selectGroups() {
- return parent::_selectGroups();
+ public function selectGroups() {
+ return parent::selectGroups();
}
public function addGroup($group) {
@@ -96,7 +96,7 @@ class sqlite_plugin_authpdo_test extends DokuWikiTest {
public function test_internals() {
$auth = new testable_auth_plugin_authpdo();
- $groups = $auth->_selectGroups();
+ $groups = $auth->selectGroups();
$this->assertArrayHasKey('user', $groups);
$this->assertEquals(1, $groups['user']['gid']);
$this->assertArrayHasKey('admin', $groups);
@@ -104,7 +104,7 @@ class sqlite_plugin_authpdo_test extends DokuWikiTest {
$ok = $auth->addGroup('test');
$this->assertTrue($ok);
- $groups = $auth->_selectGroups();
+ $groups = $auth->selectGroups();
$this->assertArrayHasKey('test', $groups);
$this->assertEquals(3, $groups['test']['gid']);
}
diff --git a/lib/plugins/authpdo/auth.php b/lib/plugins/authpdo/auth.php
index 12263b7b9..9c0968e30 100644
--- a/lib/plugins/authpdo/auth.php
+++ b/lib/plugins/authpdo/auth.php
@@ -6,13 +6,11 @@
* @author Andreas Gohr <andi@splitbrain.org>
*/
-// must be run within Dokuwiki
-if(!defined('DOKU_INC')) die();
-
/**
* Class auth_plugin_authpdo
*/
-class auth_plugin_authpdo extends DokuWiki_Auth_Plugin {
+class auth_plugin_authpdo extends DokuWiki_Auth_Plugin
+{
/** @var PDO */
protected $pdo;
@@ -23,17 +21,18 @@ class auth_plugin_authpdo extends DokuWiki_Auth_Plugin {
/**
* Constructor.
*/
- public function __construct() {
+ public function __construct()
+ {
parent::__construct(); // for compatibility
- if(!class_exists('PDO')) {
- $this->_debug('PDO extension for PHP not found.', -1, __LINE__);
+ if (!class_exists('PDO')) {
+ $this->debugMsg('PDO extension for PHP not found.', -1, __LINE__);
$this->success = false;
return;
}
- if(!$this->getConf('dsn')) {
- $this->_debug('No DSN specified', -1, __LINE__);
+ if (!$this->getConf('dsn')) {
+ $this->debugMsg('No DSN specified', -1, __LINE__);
$this->success = false;
return;
}
@@ -49,15 +48,15 @@ class auth_plugin_authpdo extends DokuWiki_Auth_Plugin {
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, // we want exceptions, not error codes
)
);
- } catch(PDOException $e) {
- $this->_debug($e);
+ } catch (PDOException $e) {
+ $this->debugMsg($e);
msg($this->getLang('connectfail'), -1);
$this->success = false;
return;
}
// can Users be created?
- $this->cando['addUser'] = $this->_chkcnf(
+ $this->cando['addUser'] = $this->checkConfig(
array(
'select-user',
'select-user-groups',
@@ -69,7 +68,7 @@ class auth_plugin_authpdo extends DokuWiki_Auth_Plugin {
);
// can Users be deleted?
- $this->cando['delUser'] = $this->_chkcnf(
+ $this->cando['delUser'] = $this->checkConfig(
array(
'select-user',
'select-user-groups',
@@ -80,7 +79,7 @@ class auth_plugin_authpdo extends DokuWiki_Auth_Plugin {
);
// can login names be changed?
- $this->cando['modLogin'] = $this->_chkcnf(
+ $this->cando['modLogin'] = $this->checkConfig(
array(
'select-user',
'select-user-groups',
@@ -89,7 +88,7 @@ class auth_plugin_authpdo extends DokuWiki_Auth_Plugin {
);
// can passwords be changed?
- $this->cando['modPass'] = $this->_chkcnf(
+ $this->cando['modPass'] = $this->checkConfig(
array(
'select-user',
'select-user-groups',
@@ -98,7 +97,7 @@ class auth_plugin_authpdo extends DokuWiki_Auth_Plugin {
);
// can real names be changed?
- $this->cando['modName'] = $this->_chkcnf(
+ $this->cando['modName'] = $this->checkConfig(
array(
'select-user',
'select-user-groups',
@@ -107,7 +106,7 @@ class auth_plugin_authpdo extends DokuWiki_Auth_Plugin {
);
// can real email be changed?
- $this->cando['modMail'] = $this->_chkcnf(
+ $this->cando['modMail'] = $this->checkConfig(
array(
'select-user',
'select-user-groups',
@@ -116,7 +115,7 @@ class auth_plugin_authpdo extends DokuWiki_Auth_Plugin {
);
// can groups be changed?
- $this->cando['modGroups'] = $this->_chkcnf(
+ $this->cando['modGroups'] = $this->checkConfig(
array(
'select-user',
'select-user-groups',
@@ -128,21 +127,21 @@ class auth_plugin_authpdo extends DokuWiki_Auth_Plugin {
);
// can a filtered list of users be retrieved?
- $this->cando['getUsers'] = $this->_chkcnf(
+ $this->cando['getUsers'] = $this->checkConfig(
array(
'list-users'
)
);
// can the number of users be retrieved?
- $this->cando['getUserCount'] = $this->_chkcnf(
+ $this->cando['getUserCount'] = $this->checkConfig(
array(
'count-users'
)
);
// can a list of available groups be retrieved?
- $this->cando['getGroups'] = $this->_chkcnf(
+ $this->cando['getGroups'] = $this->checkConfig(
array(
'select-groups'
)
@@ -154,28 +153,29 @@ class auth_plugin_authpdo extends DokuWiki_Auth_Plugin {
/**
* Check user+password
*
- * @param string $user the user name
- * @param string $pass the clear text password
+ * @param string $user the user name
+ * @param string $pass the clear text password
* @return bool
*/
- public function checkPass($user, $pass) {
+ public function checkPass($user, $pass)
+ {
- $userdata = $this->_selectUser($user);
- if($userdata == false) return false;
+ $userdata = $this->selectUser($user);
+ if ($userdata == false) return false;
// password checking done in SQL?
- if($this->_chkcnf(array('check-pass'))) {
+ if ($this->checkConfig(array('check-pass'))) {
$userdata['clear'] = $pass;
$userdata['hash'] = auth_cryptPassword($pass);
- $result = $this->_query($this->getConf('check-pass'), $userdata);
- if($result === false) return false;
+ $result = $this->query($this->getConf('check-pass'), $userdata);
+ if ($result === false) return false;
return (count($result) == 1);
}
// we do password checking on our own
- if(isset($userdata['hash'])) {
+ if (isset($userdata['hash'])) {
// hashed password
- $passhash = new PassHash();
+ $passhash = new \dokuwiki\PassHash();
return $passhash->verify_hash($pass, $userdata['hash']);
} else {
// clear text password in the database O_o
@@ -193,20 +193,21 @@ class auth_plugin_authpdo extends DokuWiki_Auth_Plugin {
* mail string email addres of the user
* grps array list of groups the user is in
*
- * @param string $user the user name
- * @param bool $requireGroups whether or not the returned data must include groups
+ * @param string $user the user name
+ * @param bool $requireGroups whether or not the returned data must include groups
* @return array|bool containing user data or false
*/
- public function getUserData($user, $requireGroups = true) {
- $data = $this->_selectUser($user);
- if($data == false) return false;
+ public function getUserData($user, $requireGroups = true)
+ {
+ $data = $this->selectUser($user);
+ if ($data == false) return false;
- if(isset($data['hash'])) unset($data['hash']);
- if(isset($data['clean'])) unset($data['clean']);
+ if (isset($data['hash'])) unset($data['hash']);
+ if (isset($data['clean'])) unset($data['clean']);
- if($requireGroups) {
- $data['grps'] = $this->_selectUserGroups($data);
- if($data['grps'] === false) return false;
+ if ($requireGroups) {
+ $data['grps'] = $this->selectUserGroups($data);
+ if ($data['grps'] === false) return false;
}
return $data;
@@ -223,23 +224,24 @@ class auth_plugin_authpdo extends DokuWiki_Auth_Plugin {
*
* Set addUser capability when implemented
*
- * @param string $user
- * @param string $clear
- * @param string $name
- * @param string $mail
- * @param null|array $grps
+ * @param string $user
+ * @param string $clear
+ * @param string $name
+ * @param string $mail
+ * @param null|array $grps
* @return bool|null
*/
- public function createUser($user, $clear, $name, $mail, $grps = null) {
+ public function createUser($user, $clear, $name, $mail, $grps = null)
+ {
global $conf;
- if(($info = $this->getUserData($user, false)) !== false) {
+ if (($info = $this->getUserData($user, false)) !== false) {
msg($this->getLang('userexists'), -1);
return false; // user already exists
}
// prepare data
- if($grps == null) $grps = array();
+ if ($grps == null) $grps = array();
array_unshift($grps, $conf['defaultgroup']);
$grps = array_unique($grps);
$hash = auth_cryptPassword($clear);
@@ -249,25 +251,25 @@ class auth_plugin_authpdo extends DokuWiki_Auth_Plugin {
$this->pdo->beginTransaction();
{
// insert the user
- $ok = $this->_query($this->getConf('insert-user'), $userdata);
- if($ok === false) goto FAIL;
+ $ok = $this->query($this->getConf('insert-user'), $userdata);
+ if ($ok === false) goto FAIL;
$userdata = $this->getUserData($user, false);
- if($userdata === false) goto FAIL;
+ if ($userdata === false) goto FAIL;
// create all groups that do not exist, the refetch the groups
- $allgroups = $this->_selectGroups();
- foreach($grps as $group) {
- if(!isset($allgroups[$group])) {
+ $allgroups = $this->selectGroups();
+ foreach ($grps as $group) {
+ if (!isset($allgroups[$group])) {
$ok = $this->addGroup($group);
- if($ok === false) goto FAIL;
+ if ($ok === false) goto FAIL;
}
}
- $allgroups = $this->_selectGroups();
+ $allgroups = $this->selectGroups();
// add user to the groups
- foreach($grps as $group) {
- $ok = $this->_joinGroup($userdata, $allgroups[$group]);
- if($ok === false) goto FAIL;
+ foreach ($grps as $group) {
+ $ok = $this->joinGroup($userdata, $allgroups[$group]);
+ if ($ok === false) goto FAIL;
}
}
$this->pdo->commit();
@@ -276,7 +278,7 @@ class auth_plugin_authpdo extends DokuWiki_Auth_Plugin {
// something went wrong, rollback
FAIL:
$this->pdo->rollBack();
- $this->_debug('Transaction rolled back', 0, __LINE__);
+ $this->debugMsg('Transaction rolled back', 0, __LINE__);
msg($this->getLang('writefail'), -1);
return null; // return error
}
@@ -284,11 +286,12 @@ class auth_plugin_authpdo extends DokuWiki_Auth_Plugin {
/**
* Modify user data
*
- * @param string $user nick of the user to be changed
- * @param array $changes array of field/value pairs to be changed (password will be clear text)
+ * @param string $user nick of the user to be changed
+ * @param array $changes array of field/value pairs to be changed (password will be clear text)
* @return bool
*/
- public function modifyUser($user, $changes) {
+ public function modifyUser($user, $changes)
+ {
// secure everything in transaction
$this->pdo->beginTransaction();
{
@@ -297,64 +300,64 @@ class auth_plugin_authpdo extends DokuWiki_Auth_Plugin {
unset($olddata['grps']);
// changing the user name?
- if(isset($changes['user'])) {
- if($this->getUserData($changes['user'], false)) goto FAIL;
+ if (isset($changes['user'])) {
+ if ($this->getUserData($changes['user'], false)) goto FAIL;
$params = $olddata;
$params['newlogin'] = $changes['user'];
- $ok = $this->_query($this->getConf('update-user-login'), $params);
- if($ok === false) goto FAIL;
+ $ok = $this->query($this->getConf('update-user-login'), $params);
+ if ($ok === false) goto FAIL;
}
// changing the password?
- if(isset($changes['pass'])) {
+ if (isset($changes['pass'])) {
$params = $olddata;
$params['clear'] = $changes['pass'];
$params['hash'] = auth_cryptPassword($changes['pass']);
- $ok = $this->_query($this->getConf('update-user-pass'), $params);
- if($ok === false) goto FAIL;
+ $ok = $this->query($this->getConf('update-user-pass'), $params);
+ if ($ok === false) goto FAIL;
}
// changing info?
- if(isset($changes['mail']) || isset($changes['name'])) {
+ if (isset($changes['mail']) || isset($changes['name'])) {
$params = $olddata;
- if(isset($changes['mail'])) $params['mail'] = $changes['mail'];
- if(isset($changes['name'])) $params['name'] = $changes['name'];
+ if (isset($changes['mail'])) $params['mail'] = $changes['mail'];
+ if (isset($changes['name'])) $params['name'] = $changes['name'];
- $ok = $this->_query($this->getConf('update-user-info'), $params);
- if($ok === false) goto FAIL;
+ $ok = $this->query($this->getConf('update-user-info'), $params);
+ if ($ok === false) goto FAIL;
}
// changing groups?
- if(isset($changes['grps'])) {
- $allgroups = $this->_selectGroups();
+ if (isset($changes['grps'])) {
+ $allgroups = $this->selectGroups();
// remove membership for previous groups
- foreach($oldgroups as $group) {
- if(!in_array($group, $changes['grps']) && isset($allgroups[$group])) {
- $ok = $this->_leaveGroup($olddata, $allgroups[$group]);
- if($ok === false) goto FAIL;
+ foreach ($oldgroups as $group) {
+ if (!in_array($group, $changes['grps']) && isset($allgroups[$group])) {
+ $ok = $this->leaveGroup($olddata, $allgroups[$group]);
+ if ($ok === false) goto FAIL;
}
}
// create all new groups that are missing
$added = 0;
- foreach($changes['grps'] as $group) {
- if(!isset($allgroups[$group])) {
+ foreach ($changes['grps'] as $group) {
+ if (!isset($allgroups[$group])) {
$ok = $this->addGroup($group);
- if($ok === false) goto FAIL;
+ if ($ok === false) goto FAIL;
$added++;
}
}
// reload group info
- if($added > 0) $allgroups = $this->_selectGroups();
+ if ($added > 0) $allgroups = $this->selectGroups();
// add membership for new groups
- foreach($changes['grps'] as $group) {
- if(!in_array($group, $oldgroups)) {
- $ok = $this->_joinGroup($olddata, $allgroups[$group]);
- if($ok === false) goto FAIL;
+ foreach ($changes['grps'] as $group) {
+ if (!in_array($group, $oldgroups)) {
+ $ok = $this->joinGroup($olddata, $allgroups[$group]);
+ if ($ok === false) goto FAIL;
}
}
}
@@ -366,7 +369,7 @@ class auth_plugin_authpdo extends DokuWiki_Auth_Plugin {
// something went wrong, rollback
FAIL:
$this->pdo->rollBack();
- $this->_debug('Transaction rolled back', 0, __LINE__);
+ $this->debugMsg('Transaction rolled back', 0, __LINE__);
msg($this->getLang('writefail'), -1);
return false; // return error
}
@@ -376,13 +379,14 @@ class auth_plugin_authpdo extends DokuWiki_Auth_Plugin {
*
* Set delUser capability when implemented
*
- * @param array $users
+ * @param array $users
* @return int number of users deleted
*/
- public function deleteUsers($users) {
+ public function deleteUsers($users)
+ {
$count = 0;
- foreach($users as $user) {
- if($this->_deleteUser($user)) $count++;
+ foreach ($users as $user) {
+ if ($this->deleteUser($user)) $count++;
}
return $count;
}
@@ -392,40 +396,41 @@ class auth_plugin_authpdo extends DokuWiki_Auth_Plugin {
*
* Set getUsers capability when implemented
*
- * @param int $start index of first user to be returned
- * @param int $limit max number of users to be returned
- * @param array $filter array of field/pattern pairs, null for no filter
+ * @param int $start index of first user to be returned
+ * @param int $limit max number of users to be returned
+ * @param array $filter array of field/pattern pairs, null for no filter
* @return array list of userinfo (refer getUserData for internal userinfo details)
*/
- public function retrieveUsers($start = 0, $limit = -1, $filter = null) {
- if($limit < 0) $limit = 10000; // we don't support no limit
- if(is_null($filter)) $filter = array();
-
- if(isset($filter['grps'])) $filter['group'] = $filter['grps'];
- foreach(array('user', 'name', 'mail', 'group') as $key) {
- if(!isset($filter[$key])) {
+ public function retrieveUsers($start = 0, $limit = -1, $filter = null)
+ {
+ if ($limit < 0) $limit = 10000; // we don't support no limit
+ if (is_null($filter)) $filter = array();
+
+ if (isset($filter['grps'])) $filter['group'] = $filter['grps'];
+ foreach (array('user', 'name', 'mail', 'group') as $key) {
+ if (!isset($filter[$key])) {
$filter[$key] = '%';
} else {
$filter[$key] = '%' . $filter[$key] . '%';
}
}
- $filter['start'] = (int) $start;
- $filter['end'] = (int) $start + $limit;
- $filter['limit'] = (int) $limit;
+ $filter['start'] = (int)$start;
+ $filter['end'] = (int)$start + $limit;
+ $filter['limit'] = (int)$limit;
- $result = $this->_query($this->getConf('list-users'), $filter);
- if(!$result) return array();
+ $result = $this->query($this->getConf('list-users'), $filter);
+ if (!$result) return array();
$users = array();
- if(is_array($result)){
- foreach($result as $row) {
- if(!isset($row['user'])) {
- $this->_debug("list-users statement did not return 'user' attribute", -1, __LINE__);
+ if (is_array($result)) {
+ foreach ($result as $row) {
+ if (!isset($row['user'])) {
+ $this->debugMsg("list-users statement did not return 'user' attribute", -1, __LINE__);
return array();
}
$users[] = $this->getUserData($row['user']);
}
- }else{
- $this->_debug("list-users statement did not return a list of result", -1, __LINE__);
+ } else {
+ $this->debugMsg("list-users statement did not return a list of result", -1, __LINE__);
}
return $users;
}
@@ -433,26 +438,27 @@ class auth_plugin_authpdo extends DokuWiki_Auth_Plugin {
/**
* Return a count of the number of user which meet $filter criteria
*
- * @param array $filter array of field/pattern pairs, empty array for no filter
+ * @param array $filter array of field/pattern pairs, empty array for no filter
* @return int
*/
- public function getUserCount($filter = array()) {
- if(is_null($filter)) $filter = array();
+ public function getUserCount($filter = array())
+ {
+ if (is_null($filter)) $filter = array();
- if(isset($filter['grps'])) $filter['group'] = $filter['grps'];
- foreach(array('user', 'name', 'mail', 'group') as $key) {
- if(!isset($filter[$key])) {
+ if (isset($filter['grps'])) $filter['group'] = $filter['grps'];
+ foreach (array('user', 'name', 'mail', 'group') as $key) {
+ if (!isset($filter[$key])) {
$filter[$key] = '%';
} else {
$filter[$key] = '%' . $filter[$key] . '%';
}
}
- $result = $this->_query($this->getConf('count-users'), $filter);
- if(!$result || !isset($result[0]['count'])) {
- $this->_debug("Statement did not return 'count' attribute", -1, __LINE__);
+ $result = $this->query($this->getConf('count-users'), $filter);
+ if (!$result || !isset($result[0]['count'])) {
+ $this->debugMsg("Statement did not return 'count' attribute", -1, __LINE__);
}
- return (int) $result[0]['count'];
+ return (int)$result[0]['count'];
}
/**
@@ -461,12 +467,13 @@ class auth_plugin_authpdo extends DokuWiki_Auth_Plugin {
* @param string $group
* @return bool
*/
- public function addGroup($group) {
+ public function addGroup($group)
+ {
$sql = $this->getConf('insert-group');
- $result = $this->_query($sql, array(':group' => $group));
- $this->_clearGroupCache();
- if($result === false) return false;
+ $result = $this->query($sql, array(':group' => $group));
+ $this->clearGroupCache();
+ if ($result === false) return false;
return true;
}
@@ -475,15 +482,16 @@ class auth_plugin_authpdo extends DokuWiki_Auth_Plugin {
*
* Set getGroups capability when implemented
*
- * @param int $start
- * @param int $limit
+ * @param int $start
+ * @param int $limit
* @return array
*/
- public function retrieveGroups($start = 0, $limit = 0) {
- $groups = array_keys($this->_selectGroups());
- if($groups === false) return array();
+ public function retrieveGroups($start = 0, $limit = 0)
+ {
+ $groups = array_keys($this->selectGroups());
+ if ($groups === false) return array();
- if(!$limit) {
+ if (!$limit) {
return array_splice($groups, $start);
} else {
return array_splice($groups, $start, $limit);
@@ -496,38 +504,39 @@ class auth_plugin_authpdo extends DokuWiki_Auth_Plugin {
* @param string $user the user name
* @return bool|array user data, false on error
*/
- protected function _selectUser($user) {
+ protected function selectUser($user)
+ {
$sql = $this->getConf('select-user');
- $result = $this->_query($sql, array(':user' => $user));
- if(!$result) return false;
+ $result = $this->query($sql, array(':user' => $user));
+ if (!$result) return false;
- if(count($result) > 1) {
- $this->_debug('Found more than one matching user', -1, __LINE__);
+ if (count($result) > 1) {
+ $this->debugMsg('Found more than one matching user', -1, __LINE__);
return false;
}
$data = array_shift($result);
$dataok = true;
- if(!isset($data['user'])) {
- $this->_debug("Statement did not return 'user' attribute", -1, __LINE__);
+ if (!isset($data['user'])) {
+ $this->debugMsg("Statement did not return 'user' attribute", -1, __LINE__);
$dataok = false;
}
- if(!isset($data['hash']) && !isset($data['clear']) && !$this->_chkcnf(array('check-pass'))) {
- $this->_debug("Statement did not return 'clear' or 'hash' attribute", -1, __LINE__);
+ if (!isset($data['hash']) && !isset($data['clear']) && !$this->checkConfig(array('check-pass'))) {
+ $this->debugMsg("Statement did not return 'clear' or 'hash' attribute", -1, __LINE__);
$dataok = false;
}
- if(!isset($data['name'])) {
- $this->_debug("Statement did not return 'name' attribute", -1, __LINE__);
+ if (!isset($data['name'])) {
+ $this->debugMsg("Statement did not return 'name' attribute", -1, __LINE__);
$dataok = false;
}
- if(!isset($data['mail'])) {
- $this->_debug("Statement did not return 'mail' attribute", -1, __LINE__);
+ if (!isset($data['mail'])) {
+ $this->debugMsg("Statement did not return 'mail' attribute", -1, __LINE__);
$dataok = false;
}
- if(!$dataok) return false;
+ if (!$dataok) return false;
return $data;
}
@@ -537,22 +546,23 @@ class auth_plugin_authpdo extends DokuWiki_Auth_Plugin {
* @param string $user
* @return bool true when the user was deleted
*/
- protected function _deleteUser($user) {
+ protected function deleteUser($user)
+ {
$this->pdo->beginTransaction();
{
$userdata = $this->getUserData($user);
- if($userdata === false) goto FAIL;
- $allgroups = $this->_selectGroups();
+ if ($userdata === false) goto FAIL;
+ $allgroups = $this->selectGroups();
// remove group memberships (ignore errors)
- foreach($userdata['grps'] as $group) {
- if(isset($allgroups[$group])) {
- $this->_leaveGroup($userdata, $allgroups[$group]);
+ foreach ($userdata['grps'] as $group) {
+ if (isset($allgroups[$group])) {
+ $this->leaveGroup($userdata, $allgroups[$group]);
}
}
- $ok = $this->_query($this->getConf('delete-user'), $userdata);
- if($ok === false) goto FAIL;
+ $ok = $this->query($this->getConf('delete-user'), $userdata);
+ if ($ok === false) goto FAIL;
}
$this->pdo->commit();
return true;
@@ -568,23 +578,24 @@ class auth_plugin_authpdo extends DokuWiki_Auth_Plugin {
* @param array $userdata The userdata as returned by _selectUser()
* @return array|bool list of group names, false on error
*/
- protected function _selectUserGroups($userdata) {
+ protected function selectUserGroups($userdata)
+ {
global $conf;
$sql = $this->getConf('select-user-groups');
- $result = $this->_query($sql, $userdata);
- if($result === false) return false;
+ $result = $this->query($sql, $userdata);
+ if ($result === false) return false;
$groups = array($conf['defaultgroup']); // always add default config
- if(is_array($result)){
- foreach($result as $row) {
- if(!isset($row['group'])) {
- $this->_debug("No 'group' field returned in select-user-groups statement");
+ if (is_array($result)) {
+ foreach ($result as $row) {
+ if (!isset($row['group'])) {
+ $this->debugMsg("No 'group' field returned in select-user-groups statement", -1, __LINE__);
return false;
}
$groups[] = $row['group'];
}
- }else{
- $this->_debug("select-user-groups statement did not return a list of result", -1, __LINE__);
+ } else {
+ $this->debugMsg("select-user-groups statement did not return a list of result", -1, __LINE__);
}
$groups = array_unique($groups);
@@ -597,18 +608,19 @@ class auth_plugin_authpdo extends DokuWiki_Auth_Plugin {
*
* @return array|bool list of all available groups and their properties
*/
- protected function _selectGroups() {
- if($this->groupcache) return $this->groupcache;
+ protected function selectGroups()
+ {
+ if ($this->groupcache) return $this->groupcache;
$sql = $this->getConf('select-groups');
- $result = $this->_query($sql);
- if($result === false) return false;
+ $result = $this->query($sql);
+ if ($result === false) return false;
$groups = array();
- if(is_array($result)){
- foreach($result as $row) {
- if(!isset($row['group'])) {
- $this->_debug("No 'group' field returned from select-groups statement", -1, __LINE__);
+ if (is_array($result)) {
+ foreach ($result as $row) {
+ if (!isset($row['group'])) {
+ $this->debugMsg("No 'group' field returned from select-groups statement", -1, __LINE__);
return false;
}
@@ -616,8 +628,8 @@ class auth_plugin_authpdo extends DokuWiki_Auth_Plugin {
$group = $row['group'];
$groups[$group] = $row;
}
- }else{
- $this->_debug("select-groups statement did not return a list of result", -1, __LINE__);
+ } else {
+ $this->debugMsg("select-groups statement did not return a list of result", -1, __LINE__);
}
ksort($groups);
@@ -627,7 +639,8 @@ class auth_plugin_authpdo extends DokuWiki_Auth_Plugin {
/**
* Remove all entries from the group cache
*/
- protected function _clearGroupCache() {
+ protected function clearGroupCache()
+ {
$this->groupcache = null;
}
@@ -638,11 +651,12 @@ class auth_plugin_authpdo extends DokuWiki_Auth_Plugin {
* @param array $groupdata all the group data
* @return bool
*/
- protected function _joinGroup($userdata, $groupdata) {
+ protected function joinGroup($userdata, $groupdata)
+ {
$data = array_merge($userdata, $groupdata);
$sql = $this->getConf('join-group');
- $result = $this->_query($sql, $data);
- if($result === false) return false;
+ $result = $this->query($sql, $data);
+ if ($result === false) return false;
return true;
}
@@ -653,11 +667,12 @@ class auth_plugin_authpdo extends DokuWiki_Auth_Plugin {
* @param array $groupdata all the group data
* @return bool
*/
- protected function _leaveGroup($userdata, $groupdata) {
+ protected function leaveGroup($userdata, $groupdata)
+ {
$data = array_merge($userdata, $groupdata);
$sql = $this->getConf('leave-group');
- $result = $this->_query($sql, $data);
- if($result === false) return false;
+ $result = $this->query($sql, $data);
+ if ($result === false) return false;
return true;
}
@@ -668,10 +683,11 @@ class auth_plugin_authpdo extends DokuWiki_Auth_Plugin {
* @param array $arguments Named parameters to be used in the statement
* @return array|int|bool The result as associative array for SELECTs, affected rows for others, false on error
*/
- protected function _query($sql, $arguments = array()) {
+ protected function query($sql, $arguments = array())
+ {
$sql = trim($sql);
- if(empty($sql)) {
- $this->_debug('No SQL query given', -1, __LINE__);
+ if (empty($sql)) {
+ $this->debugMsg('No SQL query given', -1, __LINE__);
return false;
}
@@ -681,13 +697,13 @@ class auth_plugin_authpdo extends DokuWiki_Auth_Plugin {
$result = false;
try {
// prepare parameters - we only use those that exist in the SQL
- foreach($arguments as $key => $value) {
- if(is_array($value)) continue;
- if(is_object($value)) continue;
- if($key[0] != ':') $key = ":$key"; // prefix with colon if needed
- if(strpos($sql, $key) === false) continue; // skip if parameter is missing
+ foreach ($arguments as $key => $value) {
+ if (is_array($value)) continue;
+ if (is_object($value)) continue;
+ if ($key[0] != ':') $key = ":$key"; // prefix with colon if needed
+ if (strpos($sql, $key) === false) continue; // skip if parameter is missing
- if(is_int($value)) {
+ if (is_int($value)) {
$sth->bindValue($key, $value, PDO::PARAM_INT);
} else {
$sth->bindValue($key, $value);
@@ -699,29 +715,29 @@ class auth_plugin_authpdo extends DokuWiki_Auth_Plugin {
// only report last line's result
$hasnextrowset = true;
$currentsql = $sql;
- while($hasnextrowset){
- if(strtolower(substr($currentsql, 0, 6)) == 'select') {
+ while ($hasnextrowset) {
+ if (strtolower(substr($currentsql, 0, 6)) == 'select') {
$result = $sth->fetchAll();
} else {
$result = $sth->rowCount();
}
$semi_pos = strpos($currentsql, ';');
- if($semi_pos){
- $currentsql = trim(substr($currentsql, $semi_pos+1));
+ if ($semi_pos) {
+ $currentsql = trim(substr($currentsql, $semi_pos + 1));
}
- try{
+ try {
$hasnextrowset = $sth->nextRowset(); // run next rowset
- }catch(PDOException $rowset_e){
+ } catch (PDOException $rowset_e) {
$hasnextrowset = false; // driver does not support multi-rowset, should be executed in one time
}
}
- } catch(Exception $e) {
+ } catch (Exception $e) {
// report the caller's line
$trace = debug_backtrace();
$line = $trace[0]['line'];
- $dsql = $this->_debugSQL($sql, $params, !defined('DOKU_UNITTEST'));
- $this->_debug($e, -1, $line);
- $this->_debug("SQL: <pre>$dsql</pre>", -1, $line);
+ $dsql = $this->debugSQL($sql, $params, !defined('DOKU_UNITTEST'));
+ $this->debugMsg($e, -1, $line);
+ $this->debugMsg("SQL: <pre>$dsql</pre>", -1, $line);
}
$sth->closeCursor();
$sth = null;
@@ -736,17 +752,18 @@ class auth_plugin_authpdo extends DokuWiki_Auth_Plugin {
* @param int $err
* @param int $line
*/
- protected function _debug($message, $err = 0, $line = 0) {
- if(!$this->getConf('debug')) return;
- if(is_a($message, 'Exception')) {
+ protected function debugMsg($message, $err = 0, $line = 0)
+ {
+ if (!$this->getConf('debug')) return;
+ if (is_a($message, 'Exception')) {
$err = -1;
$msg = $message->getMessage();
- if(!$line) $line = $message->getLine();
+ if (!$line) $line = $message->getLine();
} else {
$msg = $message;
}
- if(defined('DOKU_UNITTEST')) {
+ if (defined('DOKU_UNITTEST')) {
printf("\n%s, %s:%d\n", $msg, __FILE__, $line);
} else {
msg('authpdo: ' . $msg, $err, $line, __FILE__);
@@ -756,22 +773,23 @@ class auth_plugin_authpdo extends DokuWiki_Auth_Plugin {
/**
* Check if the given config strings are set
*
+ * @param string[] $keys
+ * @return bool
* @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
*
- * @param string[] $keys
- * @return bool
*/
- protected function _chkcnf($keys) {
- foreach($keys as $key) {
+ protected function checkConfig($keys)
+ {
+ foreach ($keys as $key) {
$params = explode(':', $key);
$key = array_shift($params);
$sql = trim($this->getConf($key));
// check if sql is set
- if(!$sql) return false;
+ if (!$sql) return false;
// check if needed params are there
- foreach($params as $param) {
- if(strpos($sql, ":$param") === false) return false;
+ foreach ($params as $param) {
+ if (strpos($sql, ":$param") === false) return false;
}
}
@@ -786,20 +804,21 @@ class auth_plugin_authpdo extends DokuWiki_Auth_Plugin {
* @param bool $htmlescape Should the result be escaped for output in HTML?
* @return string
*/
- protected function _debugSQL($sql, $params, $htmlescape = true) {
- foreach($params as $key => $val) {
- if(is_int($val)) {
+ protected function debugSQL($sql, $params, $htmlescape = true)
+ {
+ foreach ($params as $key => $val) {
+ if (is_int($val)) {
$val = $this->pdo->quote($val, PDO::PARAM_INT);
- } elseif(is_bool($val)) {
+ } elseif (is_bool($val)) {
$val = $this->pdo->quote($val, PDO::PARAM_BOOL);
- } elseif(is_null($val)) {
+ } elseif (is_null($val)) {
$val = 'NULL';
} else {
$val = $this->pdo->quote($val);
}
$sql = str_replace($key, $val, $sql);
}
- if($htmlescape) $sql = hsc($sql);
+ if ($htmlescape) $sql = hsc($sql);
return $sql;
}
}
diff --git a/lib/plugins/authpdo/conf/metadata.php b/lib/plugins/authpdo/conf/metadata.php
index 7c2ee8cdc..34e60a40e 100644
--- a/lib/plugins/authpdo/conf/metadata.php
+++ b/lib/plugins/authpdo/conf/metadata.php
@@ -23,5 +23,3 @@ $meta['update-user-pass'] = array('', '_caution' => 'danger');
$meta['insert-group'] = array('', '_caution' => 'danger');
$meta['join-group'] = array('', '_caution' => 'danger');
$meta['leave-group'] = array('', '_caution' => 'danger');
-
-
diff --git a/lib/plugins/authplain/_test/escaping.test.php b/lib/plugins/authplain/_test/escaping.test.php
index a38940e1a..be4d06b4e 100644
--- a/lib/plugins/authplain/_test/escaping.test.php
+++ b/lib/plugins/authplain/_test/escaping.test.php
@@ -114,14 +114,14 @@ class auth_plugin_authplainharness extends auth_plugin_authplain {
* @param boolean $bool
*/
public function setPregsplit_safe($bool) {
- $this->_pregsplit_safe = $bool;
+ $this->pregsplit_safe = $bool;
}
/**
* @return bool|mixed
*/
public function getPregsplit_safe(){
- return $this->_pregsplit_safe;
+ return $this->pregsplit_safe;
}
/**
@@ -129,6 +129,6 @@ class auth_plugin_authplainharness extends auth_plugin_authplain {
* @return array
*/
public function splitUserData($line){
- return $this->_splitUserData($line);
+ return parent::splitUserData($line);
}
}
diff --git a/lib/plugins/authplain/auth.php b/lib/plugins/authplain/auth.php
index ac1c5d5da..421af8847 100644
--- a/lib/plugins/authplain/auth.php
+++ b/lib/plugins/authplain/auth.php
@@ -1,6 +1,4 @@
<?php
-// must be run within Dokuwiki
-if(!defined('DOKU_INC')) die();
/**
* Plaintext authentication backend
@@ -10,15 +8,16 @@ if(!defined('DOKU_INC')) die();
* @author Chris Smith <chris@jalakai.co.uk>
* @author Jan Schumann <js@schumann-it.com>
*/
-class auth_plugin_authplain extends DokuWiki_Auth_Plugin {
+class auth_plugin_authplain extends DokuWiki_Auth_Plugin
+{
/** @var array user cache */
protected $users = null;
/** @var array filter pattern */
- protected $_pattern = array();
+ protected $pattern = array();
/** @var bool safe version of preg_split */
- protected $_pregsplit_safe = false;
+ protected $pregsplit_safe = false;
/**
* Constructor
@@ -28,14 +27,15 @@ class auth_plugin_authplain extends DokuWiki_Auth_Plugin {
*
* @author Christopher Smith <chris@jalakai.co.uk>
*/
- public function __construct() {
+ public function __construct()
+ {
parent::__construct();
global $config_cascade;
- if(!@is_readable($config_cascade['plainauth.users']['default'])) {
+ if (!@is_readable($config_cascade['plainauth.users']['default'])) {
$this->success = false;
} else {
- if(@is_writable($config_cascade['plainauth.users']['default'])) {
+ if (@is_writable($config_cascade['plainauth.users']['default'])) {
$this->cando['addUser'] = true;
$this->cando['delUser'] = true;
$this->cando['modLogin'] = true;
@@ -49,7 +49,7 @@ class auth_plugin_authplain extends DokuWiki_Auth_Plugin {
$this->cando['getGroups'] = true;
}
- $this->_pregsplit_safe = version_compare(PCRE_VERSION,'6.7','>=');
+ $this->pregsplit_safe = version_compare(PCRE_VERSION, '6.7', '>=');
}
/**
@@ -63,9 +63,10 @@ class auth_plugin_authplain extends DokuWiki_Auth_Plugin {
* @param string $pass
* @return bool
*/
- public function checkPass($user, $pass) {
+ public function checkPass($user, $pass)
+ {
$userinfo = $this->getUserData($user);
- if($userinfo === false) return false;
+ if ($userinfo === false) return false;
return auth_verifyPassword($pass, $this->users[$user]['pass']);
}
@@ -85,8 +86,9 @@ class auth_plugin_authplain extends DokuWiki_Auth_Plugin {
* @param bool $requireGroups (optional) ignored by this plugin, grps info always supplied
* @return array|false
*/
- public function getUserData($user, $requireGroups=true) {
- if($this->users === null) $this->_loadUserData();
+ public function getUserData($user, $requireGroups = true)
+ {
+ if ($this->users === null) $this->loadUserData();
return isset($this->users[$user]) ? $this->users[$user] : false;
}
@@ -102,7 +104,8 @@ class auth_plugin_authplain extends DokuWiki_Auth_Plugin {
* @param array $grps list of groups the user is in
* @return string
*/
- protected function _createUserLine($user, $pass, $name, $mail, $grps) {
+ protected function createUserLine($user, $pass, $name, $mail, $grps)
+ {
$groups = join(',', $grps);
$userline = array($user, $pass, $name, $mail, $groups);
$userline = str_replace('\\', '\\\\', $userline); // escape \ as \\
@@ -130,12 +133,13 @@ class auth_plugin_authplain extends DokuWiki_Auth_Plugin {
* @param array $grps
* @return bool|null|string
*/
- public function createUser($user, $pwd, $name, $mail, $grps = null) {
+ public function createUser($user, $pwd, $name, $mail, $grps = null)
+ {
global $conf;
global $config_cascade;
// user mustn't already exist
- if($this->getUserData($user) !== false) {
+ if ($this->getUserData($user) !== false) {
msg($this->getLang('userexists'), -1);
return false;
}
@@ -143,12 +147,12 @@ class auth_plugin_authplain extends DokuWiki_Auth_Plugin {
$pass = auth_cryptPassword($pwd);
// set default group if no groups specified
- if(!is_array($grps)) $grps = array($conf['defaultgroup']);
+ if (!is_array($grps)) $grps = array($conf['defaultgroup']);
// prepare user line
- $userline = $this->_createUserLine($user, $pass, $name, $mail, $grps);
+ $userline = $this->createUserLine($user, $pass, $name, $mail, $grps);
- if(!io_saveFile($config_cascade['plainauth.users']['default'], $userline, true)) {
+ if (!io_saveFile($config_cascade['plainauth.users']['default'], $userline, true)) {
msg($this->getLang('writefail'), -1);
return null;
}
@@ -165,38 +169,45 @@ class auth_plugin_authplain extends DokuWiki_Auth_Plugin {
* @param array $changes array of field/value pairs to be changed (password will be clear text)
* @return bool
*/
- public function modifyUser($user, $changes) {
+ public function modifyUser($user, $changes)
+ {
global $ACT;
global $config_cascade;
// sanity checks, user must already exist and there must be something to change
- if(($userinfo = $this->getUserData($user)) === false) {
+ if (($userinfo = $this->getUserData($user)) === false) {
msg($this->getLang('usernotexists'), -1);
return false;
}
// don't modify protected users
- if(!empty($userinfo['protected'])) {
+ if (!empty($userinfo['protected'])) {
msg(sprintf($this->getLang('protected'), hsc($user)), -1);
return false;
}
- if(!is_array($changes) || !count($changes)) return true;
+ if (!is_array($changes) || !count($changes)) return true;
// update userinfo with new data, remembering to encrypt any password
$newuser = $user;
- foreach($changes as $field => $value) {
- if($field == 'user') {
+ foreach ($changes as $field => $value) {
+ if ($field == 'user') {
$newuser = $value;
continue;
}
- if($field == 'pass') $value = auth_cryptPassword($value);
+ if ($field == 'pass') $value = auth_cryptPassword($value);
$userinfo[$field] = $value;
}
- $userline = $this->_createUserLine($newuser, $userinfo['pass'], $userinfo['name'], $userinfo['mail'], $userinfo['grps']);
+ $userline = $this->createUserLine(
+ $newuser,
+ $userinfo['pass'],
+ $userinfo['name'],
+ $userinfo['mail'],
+ $userinfo['grps']
+ );
- if(!io_replaceInFile($config_cascade['plainauth.users']['default'], '/^'.$user.':/', $userline, true)) {
+ if (!io_replaceInFile($config_cascade['plainauth.users']['default'], '/^'.$user.':/', $userline, true)) {
msg('There was an error modifying your user data. You may need to register again.', -1);
// FIXME, io functions should be fail-safe so existing data isn't lost
$ACT = 'register';
@@ -214,24 +225,25 @@ class auth_plugin_authplain extends DokuWiki_Auth_Plugin {
* @param array $users array of users to be deleted
* @return int the number of users deleted
*/
- public function deleteUsers($users) {
+ public function deleteUsers($users)
+ {
global $config_cascade;
- if(!is_array($users) || empty($users)) return 0;
+ if (!is_array($users) || empty($users)) return 0;
- if($this->users === null) $this->_loadUserData();
+ if ($this->users === null) $this->loadUserData();
$deleted = array();
- foreach($users as $user) {
+ foreach ($users as $user) {
// don't delete protected users
- if(!empty($this->users[$user]['protected'])) {
+ if (!empty($this->users[$user]['protected'])) {
msg(sprintf($this->getLang('protected'), hsc($user)), -1);
continue;
}
- if(isset($this->users[$user])) $deleted[] = preg_quote($user, '/');
+ if (isset($this->users[$user])) $deleted[] = preg_quote($user, '/');
}
- if(empty($deleted)) return 0;
+ if (empty($deleted)) return 0;
$pattern = '/^('.join('|', $deleted).'):/';
if (!io_deleteFromFile($config_cascade['plainauth.users']['default'], $pattern, true)) {
@@ -241,7 +253,7 @@ class auth_plugin_authplain extends DokuWiki_Auth_Plugin {
// reload the user list and count the difference
$count = count($this->users);
- $this->_loadUserData();
+ $this->loadUserData();
$count -= count($this->users);
return $count;
}
@@ -254,17 +266,18 @@ class auth_plugin_authplain extends DokuWiki_Auth_Plugin {
* @param array $filter
* @return int
*/
- public function getUserCount($filter = array()) {
+ public function getUserCount($filter = array())
+ {
- if($this->users === null) $this->_loadUserData();
+ if ($this->users === null) $this->loadUserData();
- if(!count($filter)) return count($this->users);
+ if (!count($filter)) return count($this->users);
$count = 0;
- $this->_constructPattern($filter);
+ $this->constructPattern($filter);
- foreach($this->users as $user => $info) {
- $count += $this->_filter($user, $info);
+ foreach ($this->users as $user => $info) {
+ $count += $this->filter($user, $info);
}
return $count;
@@ -280,23 +293,24 @@ class auth_plugin_authplain extends DokuWiki_Auth_Plugin {
* @param array $filter array of field/pattern pairs
* @return array userinfo (refer getUserData for internal userinfo details)
*/
- public function retrieveUsers($start = 0, $limit = 0, $filter = array()) {
+ public function retrieveUsers($start = 0, $limit = 0, $filter = array())
+ {
- if($this->users === null) $this->_loadUserData();
+ if ($this->users === null) $this->loadUserData();
ksort($this->users);
$i = 0;
$count = 0;
$out = array();
- $this->_constructPattern($filter);
+ $this->constructPattern($filter);
- foreach($this->users as $user => $info) {
- if($this->_filter($user, $info)) {
- if($i >= $start) {
+ foreach ($this->users as $user => $info) {
+ if ($this->filter($user, $info)) {
+ if ($i >= $start) {
$out[$user] = $info;
$count++;
- if(($limit > 0) && ($count >= $limit)) break;
+ if (($limit > 0) && ($count >= $limit)) break;
}
$i++;
}
@@ -317,7 +331,7 @@ class auth_plugin_authplain extends DokuWiki_Auth_Plugin {
{
$groups = [];
- if ($this->users === null) $this->_loadUserData();
+ if ($this->users === null) $this->loadUserData();
foreach($this->users as $user => $info) {
$groups = array_merge($groups, array_diff($info['grps'], $groups));
}
@@ -334,7 +348,8 @@ class auth_plugin_authplain extends DokuWiki_Auth_Plugin {
* @param string $user
* @return string
*/
- public function cleanUser($user) {
+ public function cleanUser($user)
+ {
global $conf;
return cleanID(str_replace(':', $conf['sepchar'], $user));
}
@@ -345,7 +360,8 @@ class auth_plugin_authplain extends DokuWiki_Auth_Plugin {
* @param string $group
* @return string
*/
- public function cleanGroup($group) {
+ public function cleanGroup($group)
+ {
global $conf;
return cleanID(str_replace(':', $conf['sepchar'], $group));
}
@@ -357,15 +373,16 @@ class auth_plugin_authplain extends DokuWiki_Auth_Plugin {
*
* @author Andreas Gohr <andi@splitbrain.org>
*/
- protected function _loadUserData() {
+ protected function loadUserData()
+ {
global $config_cascade;
- $this->users = $this->_readUserFile($config_cascade['plainauth.users']['default']);
+ $this->users = $this->readUserFile($config_cascade['plainauth.users']['default']);
// support protected users
- if(!empty($config_cascade['plainauth.users']['protected'])) {
- $protected = $this->_readUserFile($config_cascade['plainauth.users']['protected']);
- foreach(array_keys($protected) as $key) {
+ if (!empty($config_cascade['plainauth.users']['protected'])) {
+ $protected = $this->readUserFile($config_cascade['plainauth.users']['protected']);
+ foreach (array_keys($protected) as $key) {
$protected[$key]['protected'] = true;
}
$this->users = array_merge($this->users, $protected);
@@ -380,17 +397,18 @@ class auth_plugin_authplain extends DokuWiki_Auth_Plugin {
* @param string $file the file to load data from
* @return array
*/
- protected function _readUserFile($file) {
+ protected function readUserFile($file)
+ {
$users = array();
- if(!file_exists($file)) return $users;
+ if (!file_exists($file)) return $users;
$lines = file($file);
- foreach($lines as $line) {
+ foreach ($lines as $line) {
$line = preg_replace('/#.*$/', '', $line); //ignore comments
$line = trim($line);
- if(empty($line)) continue;
+ if (empty($line)) continue;
- $row = $this->_splitUserData($line);
+ $row = $this->splitUserData($line);
$row = str_replace('\\:', ':', $row);
$row = str_replace('\\\\', '\\', $row);
@@ -404,22 +422,29 @@ class auth_plugin_authplain extends DokuWiki_Auth_Plugin {
return $users;
}
- protected function _splitUserData($line){
+ /**
+ * Get the user line split into it's parts
+ *
+ * @param string $line
+ * @return string[]
+ */
+ protected function splitUserData($line)
+ {
// due to a bug in PCRE 6.6, preg_split will fail with the regex we use here
// refer github issues 877 & 885
- if ($this->_pregsplit_safe){
+ if ($this->pregsplit_safe) {
return preg_split('/(?<![^\\\\]\\\\)\:/', $line, 5); // allow for : escaped as \:
}
$row = array();
$piece = '';
$len = strlen($line);
- for($i=0; $i<$len; $i++){
- if ($line[$i]=='\\'){
+ for ($i=0; $i<$len; $i++) {
+ if ($line[$i]=='\\') {
$piece .= $line[$i];
$i++;
if ($i>=$len) break;
- } else if ($line[$i]==':'){
+ } elseif ($line[$i]==':') {
$row[] = $piece;
$piece = '';
continue;
@@ -440,14 +465,15 @@ class auth_plugin_authplain extends DokuWiki_Auth_Plugin {
* @param array $info User's userinfo array
* @return bool
*/
- protected function _filter($user, $info) {
- foreach($this->_pattern as $item => $pattern) {
- if($item == 'user') {
- if(!preg_match($pattern, $user)) return false;
- } else if($item == 'grps') {
- if(!count(preg_grep($pattern, $info['grps']))) return false;
+ protected function filter($user, $info)
+ {
+ foreach ($this->pattern as $item => $pattern) {
+ if ($item == 'user') {
+ if (!preg_match($pattern, $user)) return false;
+ } elseif ($item == 'grps') {
+ if (!count(preg_grep($pattern, $info['grps']))) return false;
} else {
- if(!preg_match($pattern, $info[$item])) return false;
+ if (!preg_match($pattern, $info[$item])) return false;
}
}
return true;
@@ -458,10 +484,11 @@ class auth_plugin_authplain extends DokuWiki_Auth_Plugin {
*
* @param array $filter
*/
- protected function _constructPattern($filter) {
- $this->_pattern = array();
- foreach($filter as $item => $pattern) {
- $this->_pattern[$item] = '/'.str_replace('/', '\/', $pattern).'/i'; // allow regex characters
+ protected function constructPattern($filter)
+ {
+ $this->pattern = array();
+ foreach ($filter as $item => $pattern) {
+ $this->pattern[$item] = '/'.str_replace('/', '\/', $pattern).'/i'; // allow regex characters
}
}
}
diff --git a/lib/plugins/cli.php b/lib/plugins/cli.php
index 721f54779..a3cbec722 100644
--- a/lib/plugins/cli.php
+++ b/lib/plugins/cli.php
@@ -1,11 +1,2 @@
<?php
-
-/**
- * Base class for CLI plugins
- *
- * Provides DokuWiki plugin functionality on top of phpcli
- */
-abstract class DokuWiki_CLI_Plugin extends \splitbrain\phpcli\CLI implements DokuWiki_PluginInterface {
- use DokuWiki_PluginTrait;
-
-}
+dbg_deprecated('Autoloading. Do not require() files yourself.');
diff --git a/lib/plugins/config/_test/configuration.test.php b/lib/plugins/config/_test/ConfigParserTest.php
index 7455461a4..b7e33a539 100644
--- a/lib/plugins/config/_test/configuration.test.php
+++ b/lib/plugins/config/_test/ConfigParserTest.php
@@ -1,31 +1,20 @@
<?php
+
+namespace dokuwiki\plugin\config\test;
+
+use dokuwiki\plugin\config\core\ConfigParser;
+
/**
* @group plugin_config
* @group admin_plugins
* @group plugins
* @group bundled_plugins
*/
-
-class plugin_config_configuration_test extends DokuWikiTest {
-
- private $config = '';
- private $meta = '';
-
- /**
- * Load config files
- */
- function __construct() {
- parent::__construct();
-
- $this->config = dirname(__FILE__).'/data/config.php';
- $this->meta = dirname(__FILE__).'/data/metadata.php';
- require_once(dirname(__FILE__).'/../settings/config.class.php');
- }
+class ConfigParserTest extends \DokuWikiTest {
function test_readconfig() {
- $confmgr = new configuration($this->meta);
-
- $conf = $confmgr->_read_config($this->config);
+ $parser = new ConfigParser();
+ $conf = $parser->parse(__DIR__ . '/data/config.php');
// var_dump($conf);
@@ -42,9 +31,8 @@ class plugin_config_configuration_test extends DokuWikiTest {
}
function test_readconfig_onoff() {
- $confmgr = new configuration($this->meta);
-
- $conf = $confmgr->_read_config($this->config);
+ $parser = new ConfigParser();
+ $conf = $parser->parse(__DIR__ . '/data/config.php');
// var_dump($conf);
diff --git a/lib/plugins/config/_test/LoaderTest.php b/lib/plugins/config/_test/LoaderTest.php
new file mode 100644
index 000000000..0c315842d
--- /dev/null
+++ b/lib/plugins/config/_test/LoaderTest.php
@@ -0,0 +1,79 @@
+<?php
+
+namespace dokuwiki\plugin\config\test;
+
+use dokuwiki\plugin\config\core\ConfigParser;
+use dokuwiki\plugin\config\core\Loader;
+
+/**
+ * @group plugin_config
+ * @group admin_plugins
+ * @group plugins
+ * @group bundled_plugins
+ */
+class LoaderTest extends \DokuWikiTest {
+
+ protected $pluginsEnabled = ['testing'];
+
+ /**
+ * Ensure loading the config meta data works
+ */
+ public function testMetaData() {
+ $loader = new Loader(new ConfigParser());
+
+ $meta = $loader->loadMeta();
+ $this->assertTrue(is_array($meta));
+
+ // there should be some defaults
+ $this->assertArrayHasKey('savedir', $meta);
+ $this->assertEquals(['savedir', '_caution' => 'danger'], $meta['savedir']);
+ $this->assertArrayHasKey('proxy____port', $meta);
+ $this->assertEquals(['numericopt'], $meta['proxy____port']);
+
+ // there should be plugin info
+ $this->assertArrayHasKey('plugin____testing____plugin_settings_name', $meta);
+ $this->assertEquals(['fieldset'], $meta['plugin____testing____plugin_settings_name']);
+ $this->assertArrayHasKey('plugin____testing____schnibble', $meta);
+ $this->assertEquals(['onoff'], $meta['plugin____testing____schnibble']);
+ }
+
+ /**
+ * Ensure loading the defaults work
+ */
+ public function testDefaults() {
+ $loader = new Loader(new ConfigParser());
+
+ $conf = $loader->loadDefaults();
+ $this->assertTrue(is_array($conf));
+
+ // basic defaults
+ $this->assertArrayHasKey('title', $conf);
+ $this->assertEquals('DokuWiki', $conf['title']);
+
+ // plugin defaults
+ $this->assertArrayHasKey('plugin____testing____schnibble', $conf);
+ $this->assertEquals(0, $conf['plugin____testing____schnibble']);
+ }
+
+ /**
+ * Ensure language loading works
+ */
+ public function testLangs() {
+ $loader = new Loader(new ConfigParser());
+
+ $lang = $loader->loadLangs();
+ $this->assertTrue(is_array($lang));
+
+ // basics are not included in the returned array!
+ $this->assertArrayNotHasKey('title', $lang);
+
+ // plugin strings
+ $this->assertArrayHasKey('plugin____testing____plugin_settings_name', $lang);
+ $this->assertEquals('Testing', $lang['plugin____testing____plugin_settings_name']);
+ $this->assertArrayHasKey('plugin____testing____schnibble', $lang);
+ $this->assertEquals(
+ 'Turns on the schnibble before the frobble is used',
+ $lang['plugin____testing____schnibble']
+ );
+ }
+}
diff --git a/lib/plugins/config/_test/Setting/AbstractSettingTest.php b/lib/plugins/config/_test/Setting/AbstractSettingTest.php
new file mode 100644
index 000000000..d18f0ec17
--- /dev/null
+++ b/lib/plugins/config/_test/Setting/AbstractSettingTest.php
@@ -0,0 +1,99 @@
+<?php
+
+namespace dokuwiki\plugin\config\test\Setting;
+
+use dokuwiki\plugin\config\core\Setting\Setting;
+
+abstract class AbstractSettingTest extends \DokuWikiTest {
+
+ /** @var string the class to test */
+ protected $class;
+
+ /**
+ * Sets up the proper class to test based on the test's class name
+ * @throws \Exception
+ */
+ public function setUp() {
+ parent::setUp();
+ $class = get_class($this);
+ $class = substr($class, strrpos($class, '\\') + 1, -4);
+ $class = 'dokuwiki\\plugin\\config\\core\\Setting\\' . $class;
+ $this->class = $class;
+ }
+
+ public function testInitialBasics() {
+ /** @var Setting $setting */
+ $setting = new $this->class('test');
+ $this->assertEquals('test', $setting->getKey());
+ $this->assertSame(false, $setting->isProtected());
+ $this->assertSame(true, $setting->isDefault());
+ $this->assertSame(false, $setting->hasError());
+ $this->assertSame(false, $setting->shouldBeSaved());
+ }
+
+ public function testShouldHaveDefault() {
+ /** @var Setting $setting */
+ $setting = new $this->class('test');
+ $this->assertSame(true, $setting->shouldHaveDefault());
+ }
+
+ public function testPrettyKey() {
+ /** @var Setting $setting */
+ $setting = new $this->class('test');
+ $this->assertEquals('test', $setting->getPrettyKey(false));
+
+ $setting = new $this->class('test____foo');
+ $this->assertEquals('test»foo', $setting->getPrettyKey(false));
+
+ $setting = new $this->class('test');
+ $this->assertEquals(
+ '<a href="http://www.dokuwiki.org/config:test">test</a>',
+ $setting->getPrettyKey(true)
+ );
+
+ $setting = new $this->class('test____foo');
+ $this->assertEquals('test»foo', $setting->getPrettyKey(true));
+
+ $setting = new $this->class('start');
+ $this->assertEquals(
+ '<a href="http://www.dokuwiki.org/config:startpage">start</a>',
+ $setting->getPrettyKey(true)
+ );
+ }
+
+ public function testType() {
+ /** @var Setting $setting */
+ $setting = new $this->class('test');
+ $this->assertEquals('dokuwiki', $setting->getType());
+
+ $setting = new $this->class('test_foo');
+ $this->assertEquals('dokuwiki', $setting->getType());
+
+ $setting = new $this->class('plugin____test');
+ $this->assertEquals('plugin', $setting->getType());
+
+ $setting = new $this->class('tpl____test');
+ $this->assertEquals('template', $setting->getType());
+ }
+
+ public function testCaution() {
+ /** @var Setting $setting */
+ $setting = new $this->class('test');
+ $this->assertEquals(false, $setting->caution());
+
+ $setting = new $this->class('test', ['_caution' => 'warning']);
+ $this->assertEquals('warning', $setting->caution());
+
+ $setting = new $this->class('test', ['_caution' => 'danger']);
+ $this->assertEquals('danger', $setting->caution());
+
+ $setting = new $this->class('test', ['_caution' => 'security']);
+ $this->assertEquals('security', $setting->caution());
+
+ $setting = new $this->class('test', ['_caution' => 'flargh']);
+ $this->expectException(\RuntimeException::class);
+ $setting->caution();
+ }
+
+
+}
diff --git a/lib/plugins/config/_test/Setting/SettingArrayTest.php b/lib/plugins/config/_test/Setting/SettingArrayTest.php
new file mode 100644
index 000000000..09dcf1421
--- /dev/null
+++ b/lib/plugins/config/_test/Setting/SettingArrayTest.php
@@ -0,0 +1,20 @@
+<?php
+
+namespace dokuwiki\plugin\config\test\Setting;
+
+/**
+ * @group plugin_config
+ * @group admin_plugins
+ * @group plugins
+ * @group bundled_plugins
+ */
+class SettingArrayTest extends SettingTest {
+
+ /** @inheritdoc */
+ public function dataOut() {
+ return [
+ [ ['foo','bar'], "\$conf['test'] = array('foo', 'bar');\n"]
+ ];
+ }
+
+}
diff --git a/lib/plugins/config/_test/Setting/SettingNumericTest.php b/lib/plugins/config/_test/Setting/SettingNumericTest.php
new file mode 100644
index 000000000..6248a06b7
--- /dev/null
+++ b/lib/plugins/config/_test/Setting/SettingNumericTest.php
@@ -0,0 +1,24 @@
+<?php
+
+namespace dokuwiki\plugin\config\test\Setting;
+
+/**
+ * @group plugin_config
+ * @group admin_plugins
+ * @group plugins
+ * @group bundled_plugins
+ */
+class SettingNumericTest extends SettingTest {
+
+ /** @inheritdoc */
+ public function dataOut() {
+ return [
+ [42, "\$conf['test'] = 42;\n"],
+ [0, "\$conf['test'] = 0;\n"],
+ [-42, "\$conf['test'] = -42;\n"],
+ [-42.13, "\$conf['test'] = -42.13;\n"],
+ ['12*13', "\$conf['test'] = 12*13;\n"],
+ ];
+ }
+
+}
diff --git a/lib/plugins/config/_test/Setting/SettingNumericoptTest.php b/lib/plugins/config/_test/Setting/SettingNumericoptTest.php
new file mode 100644
index 000000000..9d29f31e7
--- /dev/null
+++ b/lib/plugins/config/_test/Setting/SettingNumericoptTest.php
@@ -0,0 +1,23 @@
+<?php
+
+namespace dokuwiki\plugin\config\test\Setting;
+
+/**
+ * @group plugin_config
+ * @group admin_plugins
+ * @group plugins
+ * @group bundled_plugins
+ */
+class SettingNumericoptTest extends SettingNumericTest {
+
+ /** @inheritdoc */
+ public function dataOut() {
+ return array_merge(
+ parent::dataOut(),
+ [
+ ['', "\$conf['test'] = '';\n"],
+ ]
+ );
+ }
+
+}
diff --git a/lib/plugins/config/_test/Setting/SettingOnoffTest.php b/lib/plugins/config/_test/Setting/SettingOnoffTest.php
new file mode 100644
index 000000000..d6561bdf1
--- /dev/null
+++ b/lib/plugins/config/_test/Setting/SettingOnoffTest.php
@@ -0,0 +1,72 @@
+<?php
+
+namespace dokuwiki\plugin\config\test\Setting;
+
+/**
+ * @group plugin_config
+ * @group admin_plugins
+ * @group plugins
+ * @group bundled_plugins
+ */
+class SettingOnoffTest extends SettingTest {
+
+ /** @inheritdoc */
+ public function dataOut() {
+ return [
+ [1, "\$conf['test'] = 1;\n"],
+ [0, "\$conf['test'] = 0;\n"],
+
+ ['1', "\$conf['test'] = 1;\n"],
+ ['0', "\$conf['test'] = 0;\n"],
+
+ ['on', "\$conf['test'] = 1;\n"],
+ ['off', "\$conf['test'] = 0;\n"],
+
+ ['true', "\$conf['test'] = 1;\n"],
+ ['false', "\$conf['test'] = 0;\n"],
+
+ ['On', "\$conf['test'] = 1;\n"],
+ ['Off', "\$conf['test'] = 0;\n"],
+
+ ['True', "\$conf['test'] = 1;\n"],
+ ['False', "\$conf['test'] = 0;\n"],
+
+ [true, "\$conf['test'] = 1;\n"],
+ [false, "\$conf['test'] = 0;\n"],
+
+ [3, "\$conf['test'] = 1;\n"],
+ ['3', "\$conf['test'] = 1;\n"],
+
+ ['', "\$conf['test'] = 0;\n"],
+ [' ', "\$conf['test'] = 0;\n"],
+ ];
+ }
+
+ /** @inheritdoc */
+ public function dataShouldBeSaved() {
+ return [
+ [0, null, false],
+ [1, null, false],
+ [0, 0, false],
+ [1, 1, false],
+ [0, 1, true],
+ [1, 0, true],
+
+ ['0', '0', false],
+ ['1', '1', false],
+ ['0', '1', true],
+ ['1', '0', true],
+
+ ['0', 0, false],
+ ['1', 1, false],
+ ['0', 1, true],
+ ['1', 0, true],
+
+ [0, '0', false],
+ [1, '1', false],
+ [0, '1', true],
+ [1, '0', true],
+ ];
+ }
+
+}
diff --git a/lib/plugins/config/_test/Setting/SettingStringTest.php b/lib/plugins/config/_test/Setting/SettingStringTest.php
new file mode 100644
index 000000000..3d6a71c9d
--- /dev/null
+++ b/lib/plugins/config/_test/Setting/SettingStringTest.php
@@ -0,0 +1,13 @@
+<?php
+
+namespace dokuwiki\plugin\config\test\Setting;
+
+/**
+ * @group plugin_config
+ * @group admin_plugins
+ * @group plugins
+ * @group bundled_plugins
+ */
+class SettingStringTest extends SettingTest {
+
+}
diff --git a/lib/plugins/config/_test/Setting/SettingTest.php b/lib/plugins/config/_test/Setting/SettingTest.php
new file mode 100644
index 000000000..49e0662e0
--- /dev/null
+++ b/lib/plugins/config/_test/Setting/SettingTest.php
@@ -0,0 +1,70 @@
+<?php
+
+namespace dokuwiki\plugin\config\test\Setting;
+
+use dokuwiki\plugin\config\core\Setting\Setting;
+
+/**
+ * @group plugin_config
+ * @group admin_plugins
+ * @group plugins
+ * @group bundled_plugins
+ */
+class SettingTest extends AbstractSettingTest {
+
+ /**
+ * Dataprovider for testOut()
+ *
+ * @return array
+ */
+ public function dataOut() {
+ return [
+ ['bar', "\$conf['test'] = 'bar';\n"],
+ ["foo'bar", "\$conf['test'] = 'foo\\'bar';\n"],
+ ];
+ }
+
+ /**
+ * Check the output
+ *
+ * @param mixed $in The value to initialize the setting with
+ * @param string $out The expected output (for conf[test])
+ * @dataProvider dataOut
+ */
+ public function testOut($in, $out) {
+ /** @var Setting $setting */
+ $setting = new $this->class('test');
+ $setting->initialize('ignore', $in);
+
+ $this->assertEquals($out, $setting->out('conf'));
+ }
+
+ /**
+ * DataProvider for testShouldBeSaved()
+ *
+ * @return array
+ */
+ public function dataShouldBeSaved() {
+ return [
+ ['default', null, false],
+ ['default', 'default', false],
+ ['default', 'new', true],
+ ];
+ }
+
+ /**
+ * Check if shouldBeSaved works as expected
+ *
+ * @dataProvider dataShouldBeSaved
+ * @param mixed $default The default value
+ * @param mixed $local The current local value
+ * @param bool $expect The expected outcome
+ */
+ public function testShouldBeSaved($default, $local, $expect) {
+ /** @var Setting $setting */
+ $setting = new $this->class('test');
+ $setting->initialize($default, $local, null);
+ $this->assertSame($expect, $setting->shouldBeSaved());
+ }
+
+}
diff --git a/lib/plugins/config/_test/WriterTest.php b/lib/plugins/config/_test/WriterTest.php
new file mode 100644
index 000000000..62e4a56d5
--- /dev/null
+++ b/lib/plugins/config/_test/WriterTest.php
@@ -0,0 +1,63 @@
+<?php
+
+namespace dokuwiki\plugin\config\test;
+use dokuwiki\plugin\config\core\Setting\SettingString;
+use dokuwiki\plugin\config\core\Writer;
+
+/**
+ * @group plugin_config
+ * @group admin_plugins
+ * @group plugins
+ * @group bundled_plugins
+ */
+class WriterTest extends \DokuWikiTest {
+
+ public function testSave() {
+ global $config_cascade;
+ $config = end($config_cascade['main']['local']);
+
+ $set1 = new SettingString('test1');
+ $set1->initialize('foo','bar', null);
+ $set2 = new SettingString('test2');
+ $set2->initialize('foo','foo', null);
+ $settings = [$set1, $set2];
+ $writer = new Writer();
+
+ // before running, no backup should exist
+ $this->assertFileExists($config);
+ $this->assertFileNotExists("$config.bak");
+ $old = filesize($config);
+
+ /** @noinspection PhpUnhandledExceptionInspection */
+ $writer->save($settings);
+
+ // after running, both should exist
+ $this->assertFileExists($config);
+ $this->assertFileExists("$config.bak");
+ $this->assertEquals($old, filesize("$config.bak"), 'backup should have size of old file');
+
+ // check contents
+ $conf = [];
+ include $config;
+ $this->assertArrayHasKey('test1', $conf);
+ $this->assertEquals('bar', $conf['test1']);
+ $this->assertArrayNotHasKey('test2', $conf);
+
+ /** @noinspection PhpUnhandledExceptionInspection */
+ $writer->save($settings);
+ $this->assertEquals(filesize($config), filesize("$config.bak"));
+ }
+
+ public function testTouch() {
+ global $config_cascade;
+ $config = end($config_cascade['main']['local']);
+ $writer = new Writer();
+
+ $old = filemtime($config);
+ $this->waitForTick(true);
+ /** @noinspection PhpUnhandledExceptionInspection */
+ $writer->touch();
+ clearstatcache($config);
+ $this->assertGreaterThan($old, filemtime($config));
+ }
+}
diff --git a/lib/plugins/config/admin.php b/lib/plugins/config/admin.php
index 2ced6efbd..219612cf1 100644
--- a/lib/plugins/config/admin.php
+++ b/lib/plugins/config/admin.php
@@ -6,17 +6,11 @@
* @author Christopher Smith <chris@jalakai.co.uk>
* @author Ben Coburn <btcoburn@silicodon.net>
*/
-// must be run within Dokuwiki
-if(!defined('DOKU_INC')) die();
-define('CM_KEYMARKER','____'); // used for settings with multiple dimensions of array indices
-
-define('PLUGIN_SELF',dirname(__FILE__).'/');
-define('PLUGIN_METADATA',PLUGIN_SELF.'settings/config.metadata.php');
-if(!defined('DOKU_PLUGIN_IMAGES')) define('DOKU_PLUGIN_IMAGES',DOKU_BASE.'lib/plugins/config/images/');
-
-require_once(PLUGIN_SELF.'settings/config.class.php'); // main configuration class and generic settings classes
-require_once(PLUGIN_SELF.'settings/extra.class.php'); // settings classes specific to these settings
+use dokuwiki\plugin\config\core\Configuration;
+use dokuwiki\plugin\config\core\Setting\Setting;
+use dokuwiki\plugin\config\core\Setting\SettingFieldset;
+use dokuwiki\plugin\config\core\Setting\SettingHidden;
/**
* All DokuWiki plugins to extend the admin function
@@ -24,18 +18,17 @@ require_once(PLUGIN_SELF.'settings/extra.class.php'); // settings classes spec
*/
class admin_plugin_config extends DokuWiki_Admin_Plugin {
- protected $_file = PLUGIN_METADATA;
- protected $_config = null;
- protected $_input = null;
- protected $_changed = false; // set to true if configuration has altered
- protected $_error = false;
- protected $_session_started = false;
- protected $_localised_prompts = false;
+ const IMGDIR = DOKU_BASE . 'lib/plugins/config/images/';
+
+ /** @var Configuration */
+ protected $configuration;
+
+ /** @var bool were there any errors in the submitted data? */
+ protected $hasErrors = false;
+
+ /** @var bool have the settings translations been loaded? */
+ protected $promptsLocalized = false;
- /**
- * @return int
- */
- public function getMenuSort() { return 100; }
/**
* handle user request
@@ -43,44 +36,33 @@ class admin_plugin_config extends DokuWiki_Admin_Plugin {
public function handle() {
global $ID, $INPUT;
- if(!$this->_restore_session() || $INPUT->int('save') != 1 || !checkSecurityToken()) {
- $this->_close_session();
- return;
- }
+ // always initialize the configuration
+ $this->configuration = new Configuration();
- if(is_null($this->_config)) {
- $this->_config = new configuration($this->_file);
- }
-
- // don't go any further if the configuration is locked
- if($this->_config->locked) {
- $this->_close_session();
+ if(!$INPUT->bool('save') || !checkSecurityToken()) {
return;
}
- $this->_input = $INPUT->arr('config');
-
- foreach ($this->_config->setting as $key => $value){
- $input = isset($this->_input[$key]) ? $this->_input[$key] : null;
- if ($this->_config->setting[$key]->update($input)) {
- $this->_changed = true;
+ // don't go any further if the configuration is locked
+ if($this->configuration->isLocked()) return;
+
+ // update settings and redirect of successful
+ $ok = $this->configuration->updateSettings($INPUT->arr('config'));
+ if($ok) { // no errors
+ try {
+ if($this->configuration->hasChanged()) {
+ $this->configuration->save();
+ } else {
+ $this->configuration->touch();
+ }
+ msg($this->getLang('updated'), 1);
+ } catch(Exception $e) {
+ msg($this->getLang('error'), -1);
}
- if ($this->_config->setting[$key]->error()) $this->_error = true;
+ send_redirect(wl($ID, array('do' => 'admin', 'page' => 'config'), true, '&'));
+ } else {
+ $this->hasErrors = true;
}
-
- if ($this->_changed && !$this->_error) {
- $this->_config->save_settings($this->getPluginName());
-
- // save state & force a page reload to get the new settings to take effect
- $_SESSION['PLUGIN_CONFIG'] = array('state' => 'updated', 'time' => time());
- $this->_close_session();
- send_redirect(wl($ID, array('do'=>'admin','page'=>'config'), true, '&'));
- exit();
- } elseif(!$this->_error) {
- $this->_config->touch_settings(); // just touch to refresh cache
- }
-
- $this->_close_session();
}
/**
@@ -91,234 +73,137 @@ class admin_plugin_config extends DokuWiki_Admin_Plugin {
global $lang;
global $ID;
- if (is_null($this->_config)) { $this->_config = new configuration($this->_file); }
$this->setupLocale(true);
- print $this->locale_xhtml('intro');
+ echo $this->locale_xhtml('intro');
- ptln('<div id="config__manager">');
+ echo '<div id="config__manager">';
- if ($this->_config->locked)
- ptln('<div class="info">'.$this->getLang('locked').'</div>');
- elseif ($this->_error)
- ptln('<div class="error">'.$this->getLang('error').'</div>');
- elseif ($this->_changed)
- ptln('<div class="success">'.$this->getLang('updated').'</div>');
+ if($this->configuration->isLocked()) {
+ echo '<div class="info">' . $this->getLang('locked') . '</div>';
+ }
// POST to script() instead of wl($ID) so config manager still works if
// rewrite config is broken. Add $ID as hidden field to remember
// current ID in most cases.
- ptln('<form id="dw__configform" action="'.script().'" method="post">');
- ptln('<div class="no"><input type="hidden" name="id" value="'.$ID.'" /></div>');
+ echo '<form id="dw__configform" action="' . script() . '" method="post">';
+ echo '<div class="no"><input type="hidden" name="id" value="' . $ID . '" /></div>';
formSecurityToken();
- $this->_print_h1('dokuwiki_settings', $this->getLang('_header_dokuwiki'));
+ $this->printH1('dokuwiki_settings', $this->getLang('_header_dokuwiki'));
- /** @var setting[] $undefined_settings */
- $undefined_settings = array();
$in_fieldset = false;
$first_plugin_fieldset = true;
$first_template_fieldset = true;
- foreach($this->_config->setting as $setting) {
- if (is_a($setting, 'setting_hidden')) {
- // skip hidden (and undefined) settings
- if ($allow_debug && is_a($setting, 'setting_undefined')) {
- $undefined_settings[] = $setting;
- } else {
- continue;
- }
- } else if (is_a($setting, 'setting_fieldset')) {
+ foreach($this->configuration->getSettings() as $setting) {
+ if(is_a($setting, SettingHidden::class)) {
+ continue;
+ } else if(is_a($setting, settingFieldset::class)) {
// config setting group
- if ($in_fieldset) {
- ptln(' </table>');
- ptln(' </div>');
- ptln(' </fieldset>');
+ if($in_fieldset) {
+ echo '</table>';
+ echo '</div>';
+ echo '</fieldset>';
} else {
$in_fieldset = true;
}
- if ($first_plugin_fieldset && substr($setting->_key, 0, 10)=='plugin'.CM_KEYMARKER) {
- $this->_print_h1('plugin_settings', $this->getLang('_header_plugin'));
+ if($first_plugin_fieldset && $setting->getType() == 'plugin') {
+ $this->printH1('plugin_settings', $this->getLang('_header_plugin'));
$first_plugin_fieldset = false;
- } else if ($first_template_fieldset && substr($setting->_key, 0, 7)=='tpl'.CM_KEYMARKER) {
- $this->_print_h1('template_settings', $this->getLang('_header_template'));
+ } else if($first_template_fieldset && $setting->getType() == 'template') {
+ $this->printH1('template_settings', $this->getLang('_header_template'));
$first_template_fieldset = false;
}
- ptln(' <fieldset id="'.$setting->_key.'">');
- ptln(' <legend>'.$setting->prompt($this).'</legend>');
- ptln(' <div class="table">');
- ptln(' <table class="inline">');
+ echo '<fieldset id="' . $setting->getKey() . '">';
+ echo '<legend>' . $setting->prompt($this) . '</legend>';
+ echo '<div class="table">';
+ echo '<table class="inline">';
} else {
// config settings
- list($label,$input) = $setting->html($this, $this->_error);
-
- $class = $setting->is_default() ? ' class="default"' : ($setting->is_protected() ? ' class="protected"' : '');
- $error = $setting->error() ? ' class="value error"' : ' class="value"';
- $icon = $setting->caution() ? '<img src="'.DOKU_PLUGIN_IMAGES.$setting->caution().'.png" alt="'.$setting->caution().'" title="'.$this->getLang($setting->caution()).'" />' : '';
-
- ptln(' <tr'.$class.'>');
- ptln(' <td class="label">');
- ptln(' <span class="outkey">'.$setting->_out_key(true, true).'</span>');
- ptln(' '.$icon.$label);
- ptln(' </td>');
- ptln(' <td'.$error.'>'.$input.'</td>');
- ptln(' </tr>');
+ list($label, $input) = $setting->html($this, $this->hasErrors);
+
+ $class = $setting->isDefault()
+ ? ' class="default"'
+ : ($setting->isProtected() ? ' class="protected"' : '');
+ $error = $setting->hasError()
+ ? ' class="value error"'
+ : ' class="value"';
+ $icon = $setting->caution()
+ ? '<img src="' . self::IMGDIR . $setting->caution() . '.png" ' .
+ 'alt="' . $setting->caution() . '" title="' . $this->getLang($setting->caution()) . '" />'
+ : '';
+
+ echo '<tr' . $class . '>';
+ echo '<td class="label">';
+ echo '<span class="outkey">' . $setting->getPrettyKey() . '</span>';
+ echo $icon . $label;
+ echo '</td>';
+ echo '<td' . $error . '>' . $input . '</td>';
+ echo '</tr>';
}
}
- ptln(' </table>');
- ptln(' </div>');
- if ($in_fieldset) {
- ptln(' </fieldset>');
+ echo '</table>';
+ echo '</div>';
+ if($in_fieldset) {
+ echo '</fieldset>';
}
// show undefined settings list
- if ($allow_debug && !empty($undefined_settings)) {
+ $undefined_settings = $this->configuration->getUndefined();
+ if($allow_debug && !empty($undefined_settings)) {
/**
* Callback for sorting settings
*
- * @param setting $a
- * @param setting $b
+ * @param Setting $a
+ * @param Setting $b
* @return int if $a is lower/equal/higher than $b
*/
- function _setting_natural_comparison($a, $b) {
- return strnatcmp($a->_key, $b->_key);
+ function settingNaturalComparison($a, $b) {
+ return strnatcmp($a->getKey(), $b->getKey());
}
- usort($undefined_settings, '_setting_natural_comparison');
- $this->_print_h1('undefined_settings', $this->getLang('_header_undefined'));
- ptln('<fieldset>');
- ptln('<div class="table">');
- ptln('<table class="inline">');
- $undefined_setting_match = array();
+ usort($undefined_settings, 'settingNaturalComparison');
+ $this->printH1('undefined_settings', $this->getLang('_header_undefined'));
+ echo '<fieldset>';
+ echo '<div class="table">';
+ echo '<table class="inline">';
foreach($undefined_settings as $setting) {
- if (preg_match('/^(?:plugin|tpl)'.CM_KEYMARKER.'.*?'.CM_KEYMARKER.'(.*)$/', $setting->_key, $undefined_setting_match)) {
- $undefined_setting_key = $undefined_setting_match[1];
- } else {
- $undefined_setting_key = $setting->_key;
- }
- ptln(' <tr>');
- ptln(' <td class="label"><span title="$meta[\''.$undefined_setting_key.'\']">$'.$this->_config->_name.'[\''.$setting->_out_key().'\']</span></td>');
- ptln(' <td>'.$this->getLang('_msg_'.get_class($setting)).'</td>');
- ptln(' </tr>');
+ list($label, $input) = $setting->html($this);
+ echo '<tr>';
+ echo '<td class="label">' . $label . '</td>';
+ echo '<td>' . $input . '</td>';
+ echo '</tr>';
}
- ptln('</table>');
- ptln('</div>');
- ptln('</fieldset>');
+ echo '</table>';
+ echo '</div>';
+ echo '</fieldset>';
}
// finish up form
- ptln('<p>');
- ptln(' <input type="hidden" name="do" value="admin" />');
- ptln(' <input type="hidden" name="page" value="config" />');
-
- if (!$this->_config->locked) {
- ptln(' <input type="hidden" name="save" value="1" />');
- ptln(' <button type="submit" name="submit" accesskey="s">'.$lang['btn_save'].'</button>');
- ptln(' <button type="reset">'.$lang['btn_reset'].'</button>');
- }
-
- ptln('</p>');
-
- ptln('</form>');
- ptln('</div>');
- }
-
- /**
- * @return boolean true - proceed with handle, false - don't proceed
- */
- protected function _restore_session() {
-
- // dokuwiki closes the session before act_dispatch. $_SESSION variables are all set,
- // however they can't be changed without starting the session again
- if (!headers_sent()) {
- session_start();
- $this->_session_started = true;
+ echo '<p>';
+ echo '<input type="hidden" name="do" value="admin" />';
+ echo '<input type="hidden" name="page" value="config" />';
+
+ if(!$this->configuration->isLocked()) {
+ echo '<input type="hidden" name="save" value="1" />';
+ echo '<button type="submit" name="submit" accesskey="s">' . $lang['btn_save'] . '</button>';
+ echo '<button type="reset">' . $lang['btn_reset'] . '</button>';
}
- if (!isset($_SESSION['PLUGIN_CONFIG'])) return true;
+ echo '</p>';
- $session = $_SESSION['PLUGIN_CONFIG'];
- unset($_SESSION['PLUGIN_CONFIG']);
-
- // still valid?
- if (time() - $session['time'] > 120) return true;
-
- switch ($session['state']) {
- case 'updated' :
- $this->_changed = true;
- return false;
- }
-
- return true;
- }
-
- protected function _close_session() {
- if ($this->_session_started) session_write_close();
+ echo '</form>';
+ echo '</div>';
}
/**
* @param bool $prompts
*/
- public function setupLocale($prompts=false) {
-
+ public function setupLocale($prompts = false) {
parent::setupLocale();
- if (!$prompts || $this->_localised_prompts) return;
-
- $this->_setup_localised_plugin_prompts();
- $this->_localised_prompts = true;
-
- }
-
- /**
- * @return bool
- */
- protected function _setup_localised_plugin_prompts() {
- global $conf;
-
- $langfile = '/lang/'.$conf['lang'].'/settings.php';
- $enlangfile = '/lang/en/settings.php';
-
- if ($dh = opendir(DOKU_PLUGIN)) {
- while (false !== ($plugin = readdir($dh))) {
- if ($plugin == '.' || $plugin == '..' || $plugin == 'tmp' || $plugin == 'config') continue;
- if (is_file(DOKU_PLUGIN.$plugin)) continue;
-
- if (file_exists(DOKU_PLUGIN.$plugin.$enlangfile)){
- $lang = array();
- @include(DOKU_PLUGIN.$plugin.$enlangfile);
- if ($conf['lang'] != 'en') @include(DOKU_PLUGIN.$plugin.$langfile);
- foreach ($lang as $key => $value){
- $this->lang['plugin'.CM_KEYMARKER.$plugin.CM_KEYMARKER.$key] = $value;
- }
- }
-
- // fill in the plugin name if missing (should exist for plugins with settings)
- if (!isset($this->lang['plugin'.CM_KEYMARKER.$plugin.CM_KEYMARKER.'plugin_settings_name'])) {
- $this->lang['plugin'.CM_KEYMARKER.$plugin.CM_KEYMARKER.'plugin_settings_name'] =
- ucwords(str_replace('_', ' ', $plugin));
- }
- }
- closedir($dh);
- }
-
- // the same for the active template
- $tpl = $conf['template'];
-
- if (file_exists(tpl_incdir().$enlangfile)){
- $lang = array();
- @include(tpl_incdir().$enlangfile);
- if ($conf['lang'] != 'en') @include(tpl_incdir().$langfile);
- foreach ($lang as $key => $value){
- $this->lang['tpl'.CM_KEYMARKER.$tpl.CM_KEYMARKER.$key] = $value;
- }
- }
-
- // fill in the template name if missing (should exist for templates with settings)
- if (!isset($this->lang['tpl'.CM_KEYMARKER.$tpl.CM_KEYMARKER.'template_settings_name'])) {
- $this->lang['tpl'.CM_KEYMARKER.$tpl.CM_KEYMARKER.'template_settings_name'] =
- ucwords(str_replace('_', ' ', $tpl));
- }
-
- return true;
+ if(!$prompts || $this->promptsLocalized) return;
+ $this->lang = array_merge($this->lang, $this->configuration->getLangs());
+ $this->promptsLocalized = true;
}
/**
@@ -329,76 +214,69 @@ class admin_plugin_config extends DokuWiki_Admin_Plugin {
* @return array
*/
public function getTOC() {
- if (is_null($this->_config)) { $this->_config = new configuration($this->_file); }
$this->setupLocale(true);
$allow_debug = $GLOBALS['conf']['allowdebug']; // avoid global $conf; here.
+ $toc = array();
+ $check = false;
- // gather toc data
- $has_undefined = false;
- $toc = array('conf'=>array(), 'plugin'=>array(), 'template'=>null);
- foreach($this->_config->setting as $setting) {
- if (is_a($setting, 'setting_fieldset')) {
- if (substr($setting->_key, 0, 10)=='plugin'.CM_KEYMARKER) {
- $toc['plugin'][] = $setting;
- } else if (substr($setting->_key, 0, 7)=='tpl'.CM_KEYMARKER) {
- $toc['template'] = $setting;
- } else {
- $toc['conf'][] = $setting;
- }
- } else if (!$has_undefined && is_a($setting, 'setting_undefined')) {
- $has_undefined = true;
+ // gather settings data into three sub arrays
+ $labels = ['dokuwiki' => [], 'plugin' => [], 'template' => []];
+ foreach($this->configuration->getSettings() as $setting) {
+ if(is_a($setting, SettingFieldset::class)) {
+ $labels[$setting->getType()][] = $setting;
}
}
- // build toc
- $t = array();
-
- $check = false;
+ // top header
$title = $this->getLang('_configuration_manager');
- $t[] = html_mktocitem(sectionID($title, $check), $title, 1);
- $t[] = html_mktocitem('dokuwiki_settings', $this->getLang('_header_dokuwiki'), 1);
- /** @var setting $setting */
- foreach($toc['conf'] as $setting) {
- $name = $setting->prompt($this);
- $t[] = html_mktocitem($setting->_key, $name, 2);
- }
- if (!empty($toc['plugin'])) {
- $t[] = html_mktocitem('plugin_settings', $this->getLang('_header_plugin'), 1);
- }
- foreach($toc['plugin'] as $setting) {
- $name = $setting->prompt($this);
- $t[] = html_mktocitem($setting->_key, $name, 2);
- }
- if (isset($toc['template'])) {
- $t[] = html_mktocitem('template_settings', $this->getLang('_header_template'), 1);
- $setting = $toc['template'];
- $name = $setting->prompt($this);
- $t[] = html_mktocitem($setting->_key, $name, 2);
+ $toc[] = html_mktocitem(sectionID($title, $check), $title, 1);
+
+ // main entries
+ foreach(['dokuwiki', 'plugin', 'template'] as $section) {
+ if(empty($labels[$section])) continue; // no entries, skip
+
+ // create main header
+ $toc[] = html_mktocitem(
+ $section . '_settings',
+ $this->getLang('_header_' . $section),
+ 1
+ );
+
+ // create sub headers
+ foreach($labels[$section] as $setting) {
+ /** @var SettingFieldset $setting */
+ $name = $setting->prompt($this);
+ $toc[] = html_mktocitem($setting->getKey(), $name, 2);
+ }
}
- if ($has_undefined && $allow_debug) {
- $t[] = html_mktocitem('undefined_settings', $this->getLang('_header_undefined'), 1);
+
+ // undefined settings if allowed
+ if(count($this->configuration->getUndefined()) && $allow_debug) {
+ $toc[] = html_mktocitem('undefined_settings', $this->getLang('_header_undefined'), 1);
}
- return $t;
+ return $toc;
}
/**
* @param string $id
* @param string $text
*/
- protected function _print_h1($id, $text) {
- ptln('<h1 id="'.$id.'">'.$text.'</h1>');
+ protected function printH1($id, $text) {
+ echo '<h1 id="' . $id . '">' . $text . '</h1>';
}
/**
* Adds a translation to this plugin's language array
*
+ * Used by some settings to set up dynamic translations
+ *
* @param string $key
* @param string $value
*/
public function addLang($key, $value) {
- if (!$this->localised) $this->setupLocale();
+ if(!$this->localised) $this->setupLocale();
$this->lang[$key] = $value;
}
}
diff --git a/lib/plugins/config/core/ConfigParser.php b/lib/plugins/config/core/ConfigParser.php
new file mode 100644
index 000000000..9e79b96f3
--- /dev/null
+++ b/lib/plugins/config/core/ConfigParser.php
@@ -0,0 +1,90 @@
+<?php
+
+namespace dokuwiki\plugin\config\core;
+
+/**
+ * A naive PHP file parser
+ *
+ * This parses our very simple config file in PHP format. We use this instead of simply including
+ * the file, because we want to keep expressions such as 24*60*60 as is.
+ *
+ * @author Chris Smith <chris@jalakai.co.uk>
+ */
+class ConfigParser {
+ /** @var string variable to parse from the file */
+ protected $varname = 'conf';
+ /** @var string the key to mark sub arrays */
+ protected $keymarker = Configuration::KEYMARKER;
+
+ /**
+ * Parse the given PHP file into an array
+ *
+ * When the given files does not exist, this returns an empty array
+ *
+ * @param string $file
+ * @return array
+ */
+ public function parse($file) {
+ if(!file_exists($file)) return array();
+
+ $config = array();
+ $contents = @php_strip_whitespace($file);
+ $pattern = '/\$' . $this->varname . '\[[\'"]([^=]+)[\'"]\] ?= ?(.*?);(?=[^;]*(?:\$' . $this->varname . '|$))/s';
+ $matches = array();
+ preg_match_all($pattern, $contents, $matches, PREG_SET_ORDER);
+
+ for($i = 0; $i < count($matches); $i++) {
+ $value = $matches[$i][2];
+
+ // merge multi-dimensional array indices using the keymarker
+ $key = preg_replace('/.\]\[./', $this->keymarker, $matches[$i][1]);
+
+ // handle arrays
+ if(preg_match('/^array ?\((.*)\)/', $value, $match)) {
+ $arr = explode(',', $match[1]);
+
+ // remove quotes from quoted strings & unescape escaped data
+ $len = count($arr);
+ for($j = 0; $j < $len; $j++) {
+ $arr[$j] = trim($arr[$j]);
+ $arr[$j] = $this->readValue($arr[$j]);
+ }
+
+ $value = $arr;
+ } else {
+ $value = $this->readValue($value);
+ }
+
+ $config[$key] = $value;
+ }
+
+ return $config;
+ }
+
+ /**
+ * Convert php string into value
+ *
+ * @param string $value
+ * @return bool|string
+ */
+ protected function readValue($value) {
+ $removequotes_pattern = '/^(\'|")(.*)(?<!\\\\)\1$/s';
+ $unescape_pairs = array(
+ '\\\\' => '\\',
+ '\\\'' => '\'',
+ '\\"' => '"'
+ );
+
+ if($value == 'true') {
+ $value = true;
+ } elseif($value == 'false') {
+ $value = false;
+ } else {
+ // remove quotes from quoted strings & unescape escaped data
+ $value = preg_replace($removequotes_pattern, '$2', $value);
+ $value = strtr($value, $unescape_pairs);
+ }
+ return $value;
+ }
+
+}
diff --git a/lib/plugins/config/core/Configuration.php b/lib/plugins/config/core/Configuration.php
new file mode 100644
index 000000000..c58645c5b
--- /dev/null
+++ b/lib/plugins/config/core/Configuration.php
@@ -0,0 +1,219 @@
+<?php
+
+namespace dokuwiki\plugin\config\core;
+
+use dokuwiki\plugin\config\core\Setting\Setting;
+use dokuwiki\plugin\config\core\Setting\SettingNoClass;
+use dokuwiki\plugin\config\core\Setting\SettingNoDefault;
+use dokuwiki\plugin\config\core\Setting\SettingNoKnownClass;
+use dokuwiki\plugin\config\core\Setting\SettingUndefined;
+
+/**
+ * Holds all the current settings and proxies the Loader and Writer
+ *
+ * @author Chris Smith <chris@jalakai.co.uk>
+ * @author Ben Coburn <btcoburn@silicodon.net>
+ * @author Andreas Gohr <andi@splitbrain.org>
+ */
+class Configuration {
+
+ const KEYMARKER = '____';
+
+ /** @var Setting[] metadata as array of Settings objects */
+ protected $settings = array();
+ /** @var Setting[] undefined and problematic settings */
+ protected $undefined = array();
+
+ /** @var array all metadata */
+ protected $metadata;
+ /** @var array all default settings */
+ protected $default;
+ /** @var array all local settings */
+ protected $local;
+ /** @var array all protected settings */
+ protected $protected;
+
+ /** @var bool have the settings been changed since loading from disk? */
+ protected $changed = false;
+
+ /** @var Loader */
+ protected $loader;
+ /** @var Writer */
+ protected $writer;
+
+ /**
+ * ConfigSettings constructor.
+ */
+ public function __construct() {
+ $this->loader = new Loader(new ConfigParser());
+ $this->writer = new Writer();
+
+ $this->metadata = $this->loader->loadMeta();
+ $this->default = $this->loader->loadDefaults();
+ $this->local = $this->loader->loadLocal();
+ $this->protected = $this->loader->loadProtected();
+
+ $this->initSettings();
+ }
+
+ /**
+ * Get all settings
+ *
+ * @return Setting[]
+ */
+ public function getSettings() {
+ return $this->settings;
+ }
+
+ /**
+ * Get all unknown or problematic settings
+ *
+ * @return Setting[]
+ */
+ public function getUndefined() {
+ return $this->undefined;
+ }
+
+ /**
+ * Have the settings been changed since loading from disk?
+ *
+ * @return bool
+ */
+ public function hasChanged() {
+ return $this->changed;
+ }
+
+ /**
+ * Check if the config can be written
+ *
+ * @return bool
+ */
+ public function isLocked() {
+ return $this->writer->isLocked();
+ }
+
+ /**
+ * Update the settings using the data provided
+ *
+ * @param array $input as posted
+ * @return bool true if all updates went through, false on errors
+ */
+ public function updateSettings($input) {
+ $ok = true;
+
+ foreach($this->settings as $key => $obj) {
+ $value = isset($input[$key]) ? $input[$key] : null;
+ if($obj->update($value)) {
+ $this->changed = true;
+ }
+ if($obj->hasError()) $ok = false;
+ }
+
+ return $ok;
+ }
+
+ /**
+ * Save the settings
+ *
+ * This save the current state as defined in this object, including the
+ * undefined settings
+ *
+ * @throws \Exception
+ */
+ public function save() {
+ // only save the undefined settings that have not been handled in settings
+ $undefined = array_diff_key($this->undefined, $this->settings);
+ $this->writer->save(array_merge($this->settings, $undefined));
+ }
+
+ /**
+ * Touch the settings
+ *
+ * @throws \Exception
+ */
+ public function touch() {
+ $this->writer->touch();
+ }
+
+ /**
+ * Load the extension language strings
+ *
+ * @return array
+ */
+ public function getLangs() {
+ return $this->loader->loadLangs();
+ }
+
+ /**
+ * Initalizes the $settings and $undefined properties
+ */
+ protected function initSettings() {
+ $keys = array_merge(
+ array_keys($this->metadata),
+ array_keys($this->default),
+ array_keys($this->local),
+ array_keys($this->protected)
+ );
+ $keys = array_unique($keys);
+
+ foreach($keys as $key) {
+ $obj = $this->instantiateClass($key);
+
+ if($obj->shouldHaveDefault() && !isset($this->default[$key])) {
+ $this->undefined[$key] = new SettingNoDefault($key);
+ }
+
+ $d = isset($this->default[$key]) ? $this->default[$key] : null;
+ $l = isset($this->local[$key]) ? $this->local[$key] : null;
+ $p = isset($this->protected[$key]) ? $this->protected[$key] : null;
+
+ $obj->initialize($d, $l, $p);
+ }
+ }
+
+ /**
+ * Instantiates the proper class for the given config key
+ *
+ * The class is added to the $settings or $undefined arrays and returned
+ *
+ * @param string $key
+ * @return Setting
+ */
+ protected function instantiateClass($key) {
+ if(isset($this->metadata[$key])) {
+ $param = $this->metadata[$key];
+ $class = $this->determineClassName(array_shift($param), $key); // first param is class
+ $obj = new $class($key, $param);
+ $this->settings[$key] = $obj;
+ } else {
+ $obj = new SettingUndefined($key);
+ $this->undefined[$key] = $obj;
+ }
+ return $obj;
+ }
+
+ /**
+ * Return the class to load
+ *
+ * @param string $class the class name as given in the meta file
+ * @param string $key the settings key
+ * @return string
+ */
+ protected function determineClassName($class, $key) {
+ // try namespaced class first
+ if(is_string($class)) {
+ $modern = str_replace('_', '', ucwords($class, '_'));
+ $modern = '\\dokuwiki\\plugin\\config\\core\\Setting\\Setting' . $modern;
+ if($modern && class_exists($modern)) return $modern;
+ // try class as given
+ if(class_exists($class)) return $class;
+ // class wasn't found add to errors
+ $this->undefined[$key] = new SettingNoKnownClass($key);
+ } else {
+ // no class given, add to errors
+ $this->undefined[$key] = new SettingNoClass($key);
+ }
+ return '\\dokuwiki\\plugin\\config\\core\\Setting\\Setting';
+ }
+
+}
diff --git a/lib/plugins/config/core/Loader.php b/lib/plugins/config/core/Loader.php
new file mode 100644
index 000000000..90ad0f50e
--- /dev/null
+++ b/lib/plugins/config/core/Loader.php
@@ -0,0 +1,269 @@
+<?php
+
+namespace dokuwiki\plugin\config\core;
+
+use dokuwiki\Extension\Event;
+
+/**
+ * Configuration loader
+ *
+ * Loads configuration meta data and settings from the various files. Honors the
+ * configuration cascade and installed plugins.
+ */
+class Loader {
+ /** @var ConfigParser */
+ protected $parser;
+
+ /** @var string[] list of enabled plugins */
+ protected $plugins;
+ /** @var string current template */
+ protected $template;
+
+ /**
+ * Loader constructor.
+ * @param ConfigParser $parser
+ * @triggers PLUGIN_CONFIG_PLUGINLIST
+ */
+ public function __construct(ConfigParser $parser) {
+ global $conf;
+ $this->parser = $parser;
+ $this->plugins = plugin_list();
+ $this->template = $conf['template'];
+ // allow plugins to remove configurable plugins
+ Event::createAndTrigger('PLUGIN_CONFIG_PLUGINLIST', $this->plugins);
+ }
+
+ /**
+ * Read the settings meta data
+ *
+ * Reads the main file, plugins and template settings meta data
+ *
+ * @return array
+ */
+ public function loadMeta() {
+ // load main file
+ $meta = array();
+ include DOKU_PLUGIN . 'config/settings/config.metadata.php';
+
+ // plugins
+ foreach($this->plugins as $plugin) {
+ $meta = array_merge(
+ $meta,
+ $this->loadExtensionMeta(
+ DOKU_PLUGIN . $plugin . '/conf/metadata.php',
+ 'plugin',
+ $plugin
+ )
+ );
+ }
+
+ // current template
+ $meta = array_merge(
+ $meta,
+ $this->loadExtensionMeta(
+ tpl_incdir() . '/conf/metadata.php',
+ 'tpl',
+ $this->template
+ )
+ );
+
+ return $meta;
+ }
+
+ /**
+ * Read the default values
+ *
+ * Reads the main file, plugins and template defaults
+ *
+ * @return array
+ */
+ public function loadDefaults() {
+ // load main files
+ global $config_cascade;
+ $conf = $this->loadConfigs($config_cascade['main']['default']);
+
+ // plugins
+ foreach($this->plugins as $plugin) {
+ $conf = array_merge(
+ $conf,
+ $this->loadExtensionConf(
+ DOKU_PLUGIN . $plugin . '/conf/default.php',
+ 'plugin',
+ $plugin
+ )
+ );
+ }
+
+ // current template
+ $conf = array_merge(
+ $conf,
+ $this->loadExtensionConf(
+ tpl_incdir() . '/conf/default.php',
+ 'tpl',
+ $this->template
+ )
+ );
+
+ return $conf;
+ }
+
+ /**
+ * Reads the language strings
+ *
+ * Only reads extensions, main one is loaded the usual way
+ *
+ * @return array
+ */
+ public function loadLangs() {
+ $lang = array();
+
+ // plugins
+ foreach($this->plugins as $plugin) {
+ $lang = array_merge(
+ $lang,
+ $this->loadExtensionLang(
+ DOKU_PLUGIN . $plugin . '/',
+ 'plugin',
+ $plugin
+ )
+ );
+ }
+
+ // current template
+ $lang = array_merge(
+ $lang,
+ $this->loadExtensionLang(
+ tpl_incdir() . '/',
+ 'tpl',
+ $this->template
+ )
+ );
+
+ return $lang;
+ }
+
+ /**
+ * Read the local settings
+ *
+ * @return array
+ */
+ public function loadLocal() {
+ global $config_cascade;
+ return $this->loadConfigs($config_cascade['main']['local']);
+ }
+
+ /**
+ * Read the protected settings
+ *
+ * @return array
+ */
+ public function loadProtected() {
+ global $config_cascade;
+ return $this->loadConfigs($config_cascade['main']['protected']);
+ }
+
+ /**
+ * Read the config values from the given files
+ *
+ * @param string[] $files paths to config php's
+ * @return array
+ */
+ protected function loadConfigs($files) {
+ $conf = array();
+ foreach($files as $file) {
+ $conf = array_merge($conf, $this->parser->parse($file));
+ }
+ return $conf;
+ }
+
+ /**
+ * Read settings file from an extension
+ *
+ * This is used to read the settings.php files of plugins and templates
+ *
+ * @param string $file php file to read
+ * @param string $type should be 'plugin' or 'tpl'
+ * @param string $extname name of the extension
+ * @return array
+ */
+ protected function loadExtensionMeta($file, $type, $extname) {
+ if(!file_exists($file)) return array();
+ $prefix = $type . Configuration::KEYMARKER . $extname . Configuration::KEYMARKER;
+
+ // include file
+ $meta = array();
+ include $file;
+ if(empty($meta)) return array();
+
+ // read data
+ $data = array();
+ $data[$prefix . $type . '_settings_name'] = ['fieldset'];
+ foreach($meta as $key => $value) {
+ if($value[0] == 'fieldset') continue; //plugins only get one fieldset
+ $data[$prefix . $key] = $value;
+ }
+
+ return $data;
+ }
+
+ /**
+ * Read a default file from an extension
+ *
+ * This is used to read the default.php files of plugins and templates
+ *
+ * @param string $file php file to read
+ * @param string $type should be 'plugin' or 'tpl'
+ * @param string $extname name of the extension
+ * @return array
+ */
+ protected function loadExtensionConf($file, $type, $extname) {
+ if(!file_exists($file)) return array();
+ $prefix = $type . Configuration::KEYMARKER . $extname . Configuration::KEYMARKER;
+
+ // parse file
+ $conf = $this->parser->parse($file);
+ if(empty($conf)) return array();
+
+ // read data
+ $data = array();
+ foreach($conf as $key => $value) {
+ $data[$prefix . $key] = $value;
+ }
+
+ return $data;
+ }
+
+ /**
+ * Read the language file of an extension
+ *
+ * @param string $dir directory of the extension
+ * @param string $type should be 'plugin' or 'tpl'
+ * @param string $extname name of the extension
+ * @return array
+ */
+ protected function loadExtensionLang($dir, $type, $extname) {
+ global $conf;
+ $ll = $conf['lang'];
+ $prefix = $type . Configuration::KEYMARKER . $extname . Configuration::KEYMARKER;
+
+ // include files
+ $lang = array();
+ if(file_exists($dir . 'lang/en/settings.php')) {
+ include $dir . 'lang/en/settings.php';
+ }
+ if($ll != 'en' && file_exists($dir . 'lang/' . $ll . '/settings.php')) {
+ include $dir . 'lang/' . $ll . '/settings.php';
+ }
+
+ // set up correct keys
+ $strings = array();
+ foreach($lang as $key => $val) {
+ $strings[$prefix . $key] = $val;
+ }
+
+ // add fieldset key
+ $strings[$prefix . $type . '_settings_name'] = ucwords(str_replace('_', ' ', $extname));
+
+ return $strings;
+ }
+}
diff --git a/lib/plugins/config/core/Setting/Setting.php b/lib/plugins/config/core/Setting/Setting.php
new file mode 100644
index 000000000..d64f68417
--- /dev/null
+++ b/lib/plugins/config/core/Setting/Setting.php
@@ -0,0 +1,294 @@
+<?php
+
+namespace dokuwiki\plugin\config\core\Setting;
+
+use dokuwiki\plugin\config\core\Configuration;
+
+/**
+ * Class Setting
+ */
+class Setting {
+ /** @var string unique identifier of this setting */
+ protected $key = '';
+
+ /** @var mixed the default value of this setting */
+ protected $default = null;
+ /** @var mixed the local value of this setting */
+ protected $local = null;
+ /** @var mixed the protected value of this setting */
+ protected $protected = null;
+
+ /** @var array valid alerts, images matching the alerts are in the plugin's images directory */
+ static protected $validCautions = array('warning', 'danger', 'security');
+
+ protected $pattern = '';
+ protected $error = false; // only used by those classes which error check
+ protected $input = null; // only used by those classes which error check
+ protected $caution = null; // used by any setting to provide an alert along with the setting
+
+ /**
+ * Constructor.
+ *
+ * The given parameters will be set up as class properties
+ *
+ * @see initialize() to set the actual value of the setting
+ *
+ * @param string $key
+ * @param array|null $params array with metadata of setting
+ */
+ public function __construct($key, $params = null) {
+ $this->key = $key;
+
+ if(is_array($params)) {
+ foreach($params as $property => $value) {
+ $property = trim($property, '_'); // we don't use underscores anymore
+ $this->$property = $value;
+ }
+ }
+ }
+
+ /**
+ * Set the current values for the setting $key
+ *
+ * This is used to initialize the setting with the data read form the config files.
+ *
+ * @see update() to set a new value
+ * @param mixed $default default setting value
+ * @param mixed $local local setting value
+ * @param mixed $protected protected setting value
+ */
+ public function initialize($default = null, $local = null, $protected = null) {
+ $this->default = $this->cleanValue($default);
+ $this->local = $this->cleanValue($local);
+ $this->protected = $this->cleanValue($protected);
+ }
+
+ /**
+ * update changed setting with validated user provided value $input
+ * - if changed value fails validation check, save it to $this->input (to allow echoing later)
+ * - if changed value passes validation check, set $this->local to the new value
+ *
+ * @param mixed $input the new value
+ * @return boolean true if changed, false otherwise
+ */
+ public function update($input) {
+ if(is_null($input)) return false;
+ if($this->isProtected()) return false;
+ $input = $this->cleanValue($input);
+
+ $value = is_null($this->local) ? $this->default : $this->local;
+ if($value == $input) return false;
+
+ // validate new value
+ if($this->pattern && !preg_match($this->pattern, $input)) {
+ $this->error = true;
+ $this->input = $input;
+ return false;
+ }
+
+ // update local copy of this setting with new value
+ $this->local = $input;
+
+ // setting ready for update
+ return true;
+ }
+
+ /**
+ * Clean a value read from a config before using it internally
+ *
+ * Default implementation returns $value as is. Subclasses can override.
+ * Note: null should always be returned as null!
+ *
+ * This is applied in initialize() and update()
+ *
+ * @param mixed $value
+ * @return mixed
+ */
+ protected function cleanValue($value) {
+ return $value;
+ }
+
+ /**
+ * Should this type of config have a default?
+ *
+ * @return bool
+ */
+ public function shouldHaveDefault() {
+ return true;
+ }
+
+ /**
+ * Get this setting's unique key
+ *
+ * @return string
+ */
+ public function getKey() {
+ return $this->key;
+ }
+
+ /**
+ * Get the key of this setting marked up human readable
+ *
+ * @param bool $url link to dokuwiki.org manual?
+ * @return string
+ */
+ public function getPrettyKey($url = true) {
+ $out = str_replace(Configuration::KEYMARKER, "»", $this->key);
+ if($url && !strstr($out, '»')) {//provide no urls for plugins, etc.
+ if($out == 'start') {
+ // exception, because this config name is clashing with our actual start page
+ return '<a href="http://www.dokuwiki.org/config:startpage">' . $out . '</a>';
+ } else {
+ return '<a href="http://www.dokuwiki.org/config:' . $out . '">' . $out . '</a>';
+ }
+ }
+ return $out;
+ }
+
+ /**
+ * Returns setting key as an array key separator
+ *
+ * This is used to create form output
+ *
+ * @return string key
+ */
+ public function getArrayKey() {
+ return str_replace(Configuration::KEYMARKER, "']['", $this->key);
+ }
+
+ /**
+ * What type of configuration is this
+ *
+ * Returns one of
+ *
+ * 'plugin' for plugin configuration
+ * 'template' for template configuration
+ * 'dokuwiki' for core configuration
+ *
+ * @return string
+ */
+ public function getType() {
+ if(substr($this->getKey(), 0, 10) == 'plugin' . Configuration::KEYMARKER) {
+ return 'plugin';
+ } else if(substr($this->getKey(), 0, 7) == 'tpl' . Configuration::KEYMARKER) {
+ return 'template';
+ } else {
+ return 'dokuwiki';
+ }
+ }
+
+ /**
+ * Build html for label and input of setting
+ *
+ * @param \admin_plugin_config $plugin object of config plugin
+ * @param bool $echo true: show inputted value, when error occurred, otherwise the stored setting
+ * @return string[] with content array(string $label_html, string $input_html)
+ */
+ public function html(\admin_plugin_config $plugin, $echo = false) {
+ $disable = '';
+
+ if($this->isProtected()) {
+ $value = $this->protected;
+ $disable = 'disabled="disabled"';
+ } else {
+ if($echo && $this->error) {
+ $value = $this->input;
+ } else {
+ $value = is_null($this->local) ? $this->default : $this->local;
+ }
+ }
+
+ $key = htmlspecialchars($this->key);
+ $value = formText($value);
+
+ $label = '<label for="config___' . $key . '">' . $this->prompt($plugin) . '</label>';
+ $input = '<textarea rows="3" cols="40" id="config___' . $key .
+ '" name="config[' . $key . ']" class="edit" ' . $disable . '>' . $value . '</textarea>';
+ return array($label, $input);
+ }
+
+ /**
+ * Should the current local value be saved?
+ *
+ * @see out() to run when this returns true
+ * @return bool
+ */
+ public function shouldBeSaved() {
+ if($this->isProtected()) return false;
+ if($this->local === null) return false;
+ if($this->default == $this->local) return false;
+ return true;
+ }
+
+ /**
+ * Generate string to save local setting value to file according to $fmt
+ *
+ * @see shouldBeSaved() to check if this should be called
+ * @param string $var name of variable
+ * @param string $fmt save format
+ * @return string
+ */
+ public function out($var, $fmt = 'php') {
+ if($fmt != 'php') return '';
+
+ $tr = array("\\" => '\\\\', "'" => '\\\''); // escape the value
+ $out = '$' . $var . "['" . $this->getArrayKey() . "'] = '" . strtr(cleanText($this->local), $tr) . "';\n";
+
+ return $out;
+ }
+
+ /**
+ * Returns the localized prompt
+ *
+ * @param \admin_plugin_config $plugin object of config plugin
+ * @return string text
+ */
+ public function prompt(\admin_plugin_config $plugin) {
+ $prompt = $plugin->getLang($this->key);
+ if(!$prompt) $prompt = htmlspecialchars(str_replace(array('____', '_'), ' ', $this->key));
+ return $prompt;
+ }
+
+ /**
+ * Is setting protected
+ *
+ * @return bool
+ */
+ public function isProtected() {
+ return !is_null($this->protected);
+ }
+
+ /**
+ * Is setting the default?
+ *
+ * @return bool
+ */
+ public function isDefault() {
+ return !$this->isProtected() && is_null($this->local);
+ }
+
+ /**
+ * Has an error?
+ *
+ * @return bool
+ */
+ public function hasError() {
+ return $this->error;
+ }
+
+ /**
+ * Returns caution
+ *
+ * @return false|string caution string, otherwise false for invalid caution
+ */
+ public function caution() {
+ if(empty($this->caution)) return false;
+ if(!in_array($this->caution, Setting::$validCautions)) {
+ throw new \RuntimeException(
+ 'Invalid caution string (' . $this->caution . ') in metadata for setting "' . $this->key . '"'
+ );
+ }
+ return $this->caution;
+ }
+
+}
diff --git a/lib/plugins/config/core/Setting/SettingArray.php b/lib/plugins/config/core/Setting/SettingArray.php
new file mode 100644
index 000000000..c48dc760b
--- /dev/null
+++ b/lib/plugins/config/core/Setting/SettingArray.php
@@ -0,0 +1,105 @@
+<?php
+
+namespace dokuwiki\plugin\config\core\Setting;
+
+/**
+ * Class setting_array
+ */
+class SettingArray extends Setting {
+
+ /**
+ * Create an array from a string
+ *
+ * @param string $string
+ * @return array
+ */
+ protected function fromString($string) {
+ $array = explode(',', $string);
+ $array = array_map('trim', $array);
+ $array = array_filter($array);
+ $array = array_unique($array);
+ return $array;
+ }
+
+ /**
+ * Create a string from an array
+ *
+ * @param array $array
+ * @return string
+ */
+ protected function fromArray($array) {
+ return join(', ', (array) $array);
+ }
+
+ /**
+ * update setting with user provided value $input
+ * if value fails error check, save it
+ *
+ * @param string $input
+ * @return bool true if changed, false otherwise (incl. on error)
+ */
+ public function update($input) {
+ if(is_null($input)) return false;
+ if($this->isProtected()) return false;
+
+ $input = $this->fromString($input);
+
+ $value = is_null($this->local) ? $this->default : $this->local;
+ if($value == $input) return false;
+
+ foreach($input as $item) {
+ if($this->pattern && !preg_match($this->pattern, $item)) {
+ $this->error = true;
+ $this->input = $input;
+ return false;
+ }
+ }
+
+ $this->local = $input;
+ return true;
+ }
+
+ /**
+ * Escaping
+ *
+ * @param string $string
+ * @return string
+ */
+ protected function escape($string) {
+ $tr = array("\\" => '\\\\', "'" => '\\\'');
+ return "'" . strtr(cleanText($string), $tr) . "'";
+ }
+
+ /** @inheritdoc */
+ public function out($var, $fmt = 'php') {
+ if($fmt != 'php') return '';
+
+ $vals = array_map(array($this, 'escape'), $this->local);
+ $out = '$' . $var . "['" . $this->getArrayKey() . "'] = array(" . join(', ', $vals) . ");\n";
+ return $out;
+ }
+
+ /** @inheritdoc */
+ public function html(\admin_plugin_config $plugin, $echo = false) {
+ $disable = '';
+
+ if($this->isProtected()) {
+ $value = $this->protected;
+ $disable = 'disabled="disabled"';
+ } else {
+ if($echo && $this->error) {
+ $value = $this->input;
+ } else {
+ $value = is_null($this->local) ? $this->default : $this->local;
+ }
+ }
+
+ $key = htmlspecialchars($this->key);
+ $value = htmlspecialchars($this->fromArray($value));
+
+ $label = '<label for="config___' . $key . '">' . $this->prompt($plugin) . '</label>';
+ $input = '<input id="config___' . $key . '" name="config[' . $key .
+ ']" type="text" class="edit" value="' . $value . '" ' . $disable . '/>';
+ return array($label, $input);
+ }
+}
diff --git a/lib/plugins/config/core/Setting/SettingAuthtype.php b/lib/plugins/config/core/Setting/SettingAuthtype.php
new file mode 100644
index 000000000..3a6df6fe5
--- /dev/null
+++ b/lib/plugins/config/core/Setting/SettingAuthtype.php
@@ -0,0 +1,60 @@
+<?php
+
+namespace dokuwiki\plugin\config\core\Setting;
+
+/**
+ * Class setting_authtype
+ */
+class SettingAuthtype extends SettingMultichoice {
+
+ /** @inheritdoc */
+ public function initialize($default = null, $local = null, $protected = null) {
+ /** @var $plugin_controller \dokuwiki\Extension\PluginController */
+ global $plugin_controller;
+
+ // retrieve auth types provided by plugins
+ foreach($plugin_controller->getList('auth') as $plugin) {
+ $this->choices[] = $plugin;
+ }
+
+ parent::initialize($default, $local, $protected);
+ }
+
+ /** @inheritdoc */
+ public function update($input) {
+ /** @var $plugin_controller \dokuwiki\Extension\PluginController */
+ global $plugin_controller;
+
+ // is an update possible/requested?
+ $local = $this->local; // save this, parent::update() may change it
+ if(!parent::update($input)) return false; // nothing changed or an error caught by parent
+ $this->local = $local; // restore original, more error checking to come
+
+ // attempt to load the plugin
+ $auth_plugin = $plugin_controller->load('auth', $input);
+
+ // @TODO: throw an error in plugin controller instead of returning null
+ if(is_null($auth_plugin)) {
+ $this->error = true;
+ msg('Cannot load Auth Plugin "' . $input . '"', -1);
+ return false;
+ }
+
+ // verify proper instantiation (is this really a plugin?) @TODO use instanceof? implement interface?
+ if(is_object($auth_plugin) && !method_exists($auth_plugin, 'getPluginName')) {
+ $this->error = true;
+ msg('Cannot create Auth Plugin "' . $input . '"', -1);
+ return false;
+ }
+
+ // did we change the auth type? logout
+ global $conf;
+ if($conf['authtype'] != $input) {
+ msg('Authentication system changed. Please re-login.');
+ auth_logoff();
+ }
+
+ $this->local = $input;
+ return true;
+ }
+}
diff --git a/lib/plugins/config/core/Setting/SettingCompression.php b/lib/plugins/config/core/Setting/SettingCompression.php
new file mode 100644
index 000000000..f97d82801
--- /dev/null
+++ b/lib/plugins/config/core/Setting/SettingCompression.php
@@ -0,0 +1,21 @@
+<?php
+
+namespace dokuwiki\plugin\config\core\Setting;
+
+/**
+ * Class setting_compression
+ */
+class SettingCompression extends SettingMultichoice {
+
+ protected $choices = array('0'); // 0 = no compression, always supported
+
+ /** @inheritdoc */
+ public function initialize($default = null, $local = null, $protected = null) {
+
+ // populate _choices with the compression methods supported by this php installation
+ if(function_exists('gzopen')) $this->choices[] = 'gz';
+ if(function_exists('bzopen')) $this->choices[] = 'bz2';
+
+ parent::initialize($default, $local, $protected);
+ }
+}
diff --git a/lib/plugins/config/core/Setting/SettingDirchoice.php b/lib/plugins/config/core/Setting/SettingDirchoice.php
new file mode 100644
index 000000000..dfb27f5f4
--- /dev/null
+++ b/lib/plugins/config/core/Setting/SettingDirchoice.php
@@ -0,0 +1,33 @@
+<?php
+
+namespace dokuwiki\plugin\config\core\Setting;
+
+/**
+ * Class setting_dirchoice
+ */
+class SettingDirchoice extends SettingMultichoice {
+
+ protected $dir = '';
+
+ /** @inheritdoc */
+ public function initialize($default = null, $local = null, $protected = null) {
+
+ // populate $this->_choices with a list of directories
+ $list = array();
+
+ if($dh = @opendir($this->dir)) {
+ while(false !== ($entry = readdir($dh))) {
+ if($entry == '.' || $entry == '..') continue;
+ if($this->pattern && !preg_match($this->pattern, $entry)) continue;
+
+ $file = (is_link($this->dir . $entry)) ? readlink($this->dir . $entry) : $this->dir . $entry;
+ if(is_dir($file)) $list[] = $entry;
+ }
+ closedir($dh);
+ }
+ sort($list);
+ $this->choices = $list;
+
+ parent::initialize($default, $local, $protected);
+ }
+}
diff --git a/lib/plugins/config/core/Setting/SettingDisableactions.php b/lib/plugins/config/core/Setting/SettingDisableactions.php
new file mode 100644
index 000000000..2553175bd
--- /dev/null
+++ b/lib/plugins/config/core/Setting/SettingDisableactions.php
@@ -0,0 +1,23 @@
+<?php
+
+namespace dokuwiki\plugin\config\core\Setting;
+
+/**
+ * Class setting_disableactions
+ */
+class SettingDisableactions extends SettingMulticheckbox {
+
+ /** @inheritdoc */
+ public function html(\admin_plugin_config $plugin, $echo = false) {
+ global $lang;
+
+ // make some language adjustments (there must be a better way)
+ // transfer some DokuWiki language strings to the plugin
+ $plugin->addLang($this->key . '_revisions', $lang['btn_revs']);
+ foreach($this->choices as $choice) {
+ if(isset($lang['btn_' . $choice])) $plugin->addLang($this->key . '_' . $choice, $lang['btn_' . $choice]);
+ }
+
+ return parent::html($plugin, $echo);
+ }
+}
diff --git a/lib/plugins/config/core/Setting/SettingEmail.php b/lib/plugins/config/core/Setting/SettingEmail.php
new file mode 100644
index 000000000..25a0c0e75
--- /dev/null
+++ b/lib/plugins/config/core/Setting/SettingEmail.php
@@ -0,0 +1,58 @@
+<?php
+
+namespace dokuwiki\plugin\config\core\Setting;
+
+/**
+ * Class setting_email
+ */
+class SettingEmail extends SettingString {
+ protected $multiple = false;
+ protected $placeholders = false;
+
+ /** @inheritdoc */
+ public function update($input) {
+ if(is_null($input)) return false;
+ if($this->isProtected()) return false;
+
+ $value = is_null($this->local) ? $this->default : $this->local;
+ if($value == $input) return false;
+ if($input === '') {
+ $this->local = $input;
+ return true;
+ }
+ $mail = $input;
+
+ if($this->placeholders) {
+ // replace variables with pseudo values
+ $mail = str_replace('@USER@', 'joe', $mail);
+ $mail = str_replace('@NAME@', 'Joe Schmoe', $mail);
+ $mail = str_replace('@MAIL@', 'joe@example.com', $mail);
+ }
+
+ // multiple mail addresses?
+ if($this->multiple) {
+ $mails = array_filter(array_map('trim', explode(',', $mail)));
+ } else {
+ $mails = array($mail);
+ }
+
+ // check them all
+ foreach($mails as $mail) {
+ // only check the address part
+ if(preg_match('#(.*?)<(.*?)>#', $mail, $matches)) {
+ $addr = $matches[2];
+ } else {
+ $addr = $mail;
+ }
+
+ if(!mail_isvalid($addr)) {
+ $this->error = true;
+ $this->input = $input;
+ return false;
+ }
+ }
+
+ $this->local = $input;
+ return true;
+ }
+}
diff --git a/lib/plugins/config/core/Setting/SettingFieldset.php b/lib/plugins/config/core/Setting/SettingFieldset.php
new file mode 100644
index 000000000..4e8618967
--- /dev/null
+++ b/lib/plugins/config/core/Setting/SettingFieldset.php
@@ -0,0 +1,17 @@
+<?php
+
+namespace dokuwiki\plugin\config\core\Setting;
+
+/**
+ * A do-nothing class used to detect the 'fieldset' type.
+ *
+ * Used to start a new settings "display-group".
+ */
+class SettingFieldset extends Setting {
+
+ /** @inheritdoc */
+ public function shouldHaveDefault() {
+ return false;
+ }
+
+}
diff --git a/lib/plugins/config/core/Setting/SettingHidden.php b/lib/plugins/config/core/Setting/SettingHidden.php
new file mode 100644
index 000000000..ca8a03eb9
--- /dev/null
+++ b/lib/plugins/config/core/Setting/SettingHidden.php
@@ -0,0 +1,10 @@
+<?php
+
+namespace dokuwiki\plugin\config\core\Setting;
+
+/**
+ * Class setting_hidden
+ */
+class SettingHidden extends Setting {
+ // Used to explicitly ignore a setting in the configuration manager.
+}
diff --git a/lib/plugins/config/core/Setting/SettingImConvert.php b/lib/plugins/config/core/Setting/SettingImConvert.php
new file mode 100644
index 000000000..8740d94c8
--- /dev/null
+++ b/lib/plugins/config/core/Setting/SettingImConvert.php
@@ -0,0 +1,28 @@
+<?php
+
+namespace dokuwiki\plugin\config\core\Setting;
+
+/**
+ * Class setting_im_convert
+ */
+class SettingImConvert extends SettingString {
+
+ /** @inheritdoc */
+ public function update($input) {
+ if($this->isProtected()) return false;
+
+ $input = trim($input);
+
+ $value = is_null($this->local) ? $this->default : $this->local;
+ if($value == $input) return false;
+
+ if($input && !file_exists($input)) {
+ $this->error = true;
+ $this->input = $input;
+ return false;
+ }
+
+ $this->local = $input;
+ return true;
+ }
+}
diff --git a/lib/plugins/config/core/Setting/SettingLicense.php b/lib/plugins/config/core/Setting/SettingLicense.php
new file mode 100644
index 000000000..8dacf8e25
--- /dev/null
+++ b/lib/plugins/config/core/Setting/SettingLicense.php
@@ -0,0 +1,23 @@
+<?php
+
+namespace dokuwiki\plugin\config\core\Setting;
+
+/**
+ * Class setting_license
+ */
+class SettingLicense extends SettingMultichoice {
+
+ protected $choices = array(''); // none choosen
+
+ /** @inheritdoc */
+ public function initialize($default = null, $local = null, $protected = null) {
+ global $license;
+
+ foreach($license as $key => $data) {
+ $this->choices[] = $key;
+ $this->lang[$this->key . '_o_' . $key] = $data['name']; // stored in setting
+ }
+
+ parent::initialize($default, $local, $protected);
+ }
+}
diff --git a/lib/plugins/config/core/Setting/SettingMulticheckbox.php b/lib/plugins/config/core/Setting/SettingMulticheckbox.php
new file mode 100644
index 000000000..df212cca0
--- /dev/null
+++ b/lib/plugins/config/core/Setting/SettingMulticheckbox.php
@@ -0,0 +1,163 @@
+<?php
+
+namespace dokuwiki\plugin\config\core\Setting;
+
+/**
+ * Class setting_multicheckbox
+ */
+class SettingMulticheckbox extends SettingString {
+
+ protected $choices = array();
+ protected $combine = array();
+ protected $other = 'always';
+
+ /** @inheritdoc */
+ public function update($input) {
+ if($this->isProtected()) return false;
+
+ // split any combined values + convert from array to comma separated string
+ $input = ($input) ? $input : array();
+ $input = $this->array2str($input);
+
+ $value = is_null($this->local) ? $this->default : $this->local;
+ if($value == $input) return false;
+
+ if($this->pattern && !preg_match($this->pattern, $input)) {
+ $this->error = true;
+ $this->input = $input;
+ return false;
+ }
+
+ $this->local = $input;
+ return true;
+ }
+
+ /** @inheritdoc */
+ public function html(\admin_plugin_config $plugin, $echo = false) {
+
+ $disable = '';
+
+ if($this->isProtected()) {
+ $value = $this->protected;
+ $disable = 'disabled="disabled"';
+ } else {
+ if($echo && $this->error) {
+ $value = $this->input;
+ } else {
+ $value = is_null($this->local) ? $this->default : $this->local;
+ }
+ }
+
+ $key = htmlspecialchars($this->key);
+
+ // convert from comma separated list into array + combine complimentary actions
+ $value = $this->str2array($value);
+ $default = $this->str2array($this->default);
+
+ $input = '';
+ foreach($this->choices as $choice) {
+ $idx = array_search($choice, $value);
+ $idx_default = array_search($choice, $default);
+
+ $checked = ($idx !== false) ? 'checked="checked"' : '';
+
+ // @todo ideally this would be handled using a second class of "default"
+ $class = (($idx !== false) == (false !== $idx_default)) ? " selectiondefault" : "";
+
+ $prompt = ($plugin->getLang($this->key . '_' . $choice) ?
+ $plugin->getLang($this->key . '_' . $choice) : htmlspecialchars($choice));
+
+ $input .= '<div class="selection' . $class . '">' . "\n";
+ $input .= '<label for="config___' . $key . '_' . $choice . '">' . $prompt . "</label>\n";
+ $input .= '<input id="config___' . $key . '_' . $choice . '" name="config[' . $key .
+ '][]" type="checkbox" class="checkbox" value="' . $choice . '" ' . $disable . ' ' . $checked . "/>\n";
+ $input .= "</div>\n";
+
+ // remove this action from the disabledactions array
+ if($idx !== false) unset($value[$idx]);
+ if($idx_default !== false) unset($default[$idx_default]);
+ }
+
+ // handle any remaining values
+ if($this->other != 'never') {
+ $other = join(',', $value);
+ // test equivalent to ($this->_other == 'always' || ($other && $this->_other == 'exists')
+ // use != 'exists' rather than == 'always' to ensure invalid values default to 'always'
+ if($this->other != 'exists' || $other) {
+
+ $class = (
+ (count($default) == count($value)) &&
+ (count($value) == count(array_intersect($value, $default)))
+ ) ?
+ " selectiondefault" : "";
+
+ $input .= '<div class="other' . $class . '">' . "\n";
+ $input .= '<label for="config___' . $key . '_other">' .
+ $plugin->getLang($key . '_other') .
+ "</label>\n";
+ $input .= '<input id="config___' . $key . '_other" name="config[' . $key .
+ '][other]" type="text" class="edit" value="' . htmlspecialchars($other) .
+ '" ' . $disable . " />\n";
+ $input .= "</div>\n";
+ }
+ }
+ $label = '<label>' . $this->prompt($plugin) . '</label>';
+ return array($label, $input);
+ }
+
+ /**
+ * convert comma separated list to an array and combine any complimentary values
+ *
+ * @param string $str
+ * @return array
+ */
+ protected function str2array($str) {
+ $array = explode(',', $str);
+
+ if(!empty($this->combine)) {
+ foreach($this->combine as $key => $combinators) {
+ $idx = array();
+ foreach($combinators as $val) {
+ if(($idx[] = array_search($val, $array)) === false) break;
+ }
+
+ if(count($idx) && $idx[count($idx) - 1] !== false) {
+ foreach($idx as $i) unset($array[$i]);
+ $array[] = $key;
+ }
+ }
+ }
+
+ return $array;
+ }
+
+ /**
+ * convert array of values + other back to a comma separated list, incl. splitting any combined values
+ *
+ * @param array $input
+ * @return string
+ */
+ protected function array2str($input) {
+
+ // handle other
+ $other = trim($input['other']);
+ $other = !empty($other) ? explode(',', str_replace(' ', '', $input['other'])) : array();
+ unset($input['other']);
+
+ $array = array_unique(array_merge($input, $other));
+
+ // deconstruct any combinations
+ if(!empty($this->combine)) {
+ foreach($this->combine as $key => $combinators) {
+
+ $idx = array_search($key, $array);
+ if($idx !== false) {
+ unset($array[$idx]);
+ $array = array_merge($array, $combinators);
+ }
+ }
+ }
+
+ return join(',', array_unique($array));
+ }
+}
diff --git a/lib/plugins/config/core/Setting/SettingMultichoice.php b/lib/plugins/config/core/Setting/SettingMultichoice.php
new file mode 100644
index 000000000..3a50857e0
--- /dev/null
+++ b/lib/plugins/config/core/Setting/SettingMultichoice.php
@@ -0,0 +1,71 @@
+<?php
+
+namespace dokuwiki\plugin\config\core\Setting;
+
+/**
+ * Class setting_multichoice
+ */
+class SettingMultichoice extends SettingString {
+ protected $choices = array();
+ public $lang; //some custom language strings are stored in setting
+
+ /** @inheritdoc */
+ public function html(\admin_plugin_config $plugin, $echo = false) {
+ $disable = '';
+ $nochoice = '';
+
+ if($this->isProtected()) {
+ $value = $this->protected;
+ $disable = ' disabled="disabled"';
+ } else {
+ $value = is_null($this->local) ? $this->default : $this->local;
+ }
+
+ // ensure current value is included
+ if(!in_array($value, $this->choices)) {
+ $this->choices[] = $value;
+ }
+ // disable if no other choices
+ if(!$this->isProtected() && count($this->choices) <= 1) {
+ $disable = ' disabled="disabled"';
+ $nochoice = $plugin->getLang('nochoice');
+ }
+
+ $key = htmlspecialchars($this->key);
+
+ $label = '<label for="config___' . $key . '">' . $this->prompt($plugin) . '</label>';
+
+ $input = "<div class=\"input\">\n";
+ $input .= '<select class="edit" id="config___' . $key . '" name="config[' . $key . ']"' . $disable . '>' . "\n";
+ foreach($this->choices as $choice) {
+ $selected = ($value == $choice) ? ' selected="selected"' : '';
+ $option = $plugin->getLang($this->key . '_o_' . $choice);
+ if(!$option && isset($this->lang[$this->key . '_o_' . $choice])) {
+ $option = $this->lang[$this->key . '_o_' . $choice];
+ }
+ if(!$option) $option = $choice;
+
+ $choice = htmlspecialchars($choice);
+ $option = htmlspecialchars($option);
+ $input .= ' <option value="' . $choice . '"' . $selected . ' >' . $option . '</option>' . "\n";
+ }
+ $input .= "</select> $nochoice \n";
+ $input .= "</div>\n";
+
+ return array($label, $input);
+ }
+
+ /** @inheritdoc */
+ public function update($input) {
+ if(is_null($input)) return false;
+ if($this->isProtected()) return false;
+
+ $value = is_null($this->local) ? $this->default : $this->local;
+ if($value == $input) return false;
+
+ if(!in_array($input, $this->choices)) return false;
+
+ $this->local = $input;
+ return true;
+ }
+}
diff --git a/lib/plugins/config/core/Setting/SettingNoClass.php b/lib/plugins/config/core/Setting/SettingNoClass.php
new file mode 100644
index 000000000..8efff216a
--- /dev/null
+++ b/lib/plugins/config/core/Setting/SettingNoClass.php
@@ -0,0 +1,12 @@
+<?php
+
+namespace dokuwiki\plugin\config\core\Setting;
+
+/**
+ * Class setting_no_class
+ * A do-nothing class used to detect settings with a missing setting class.
+ * Used internaly to hide undefined settings, and generate the undefined settings list.
+ */
+class SettingNoClass extends SettingUndefined {
+ protected $errorMessage = '_msg_setting_no_class';
+}
diff --git a/lib/plugins/config/core/Setting/SettingNoDefault.php b/lib/plugins/config/core/Setting/SettingNoDefault.php
new file mode 100644
index 000000000..07b8412dd
--- /dev/null
+++ b/lib/plugins/config/core/Setting/SettingNoDefault.php
@@ -0,0 +1,13 @@
+<?php
+
+namespace dokuwiki\plugin\config\core\Setting;
+
+/**
+ * Class setting_no_default
+ *
+ * A do-nothing class used to detect settings with no default value.
+ * Used internaly to hide undefined settings, and generate the undefined settings list.
+ */
+class SettingNoDefault extends SettingUndefined {
+ protected $errorMessage = '_msg_setting_no_default';
+}
diff --git a/lib/plugins/config/core/Setting/SettingNoKnownClass.php b/lib/plugins/config/core/Setting/SettingNoKnownClass.php
new file mode 100644
index 000000000..3c527e1ee
--- /dev/null
+++ b/lib/plugins/config/core/Setting/SettingNoKnownClass.php
@@ -0,0 +1,11 @@
+<?php
+
+namespace dokuwiki\plugin\config\core\Setting;
+
+/**
+ * A do-nothing class used to detect settings with a missing setting class.
+ * Used internaly to hide undefined settings, and generate the undefined settings list.
+ */
+class SettingNoKnownClass extends SettingUndefined {
+ protected $errorMessage = '_msg_setting_no_known_class';
+}
diff --git a/lib/plugins/config/core/Setting/SettingNumeric.php b/lib/plugins/config/core/Setting/SettingNumeric.php
new file mode 100644
index 000000000..8a6b17956
--- /dev/null
+++ b/lib/plugins/config/core/Setting/SettingNumeric.php
@@ -0,0 +1,42 @@
+<?php
+
+namespace dokuwiki\plugin\config\core\Setting;
+
+/**
+ * Class setting_numeric
+ */
+class SettingNumeric extends SettingString {
+ // This allows for many PHP syntax errors...
+ // var $_pattern = '/^[-+\/*0-9 ]*$/';
+ // much more restrictive, but should eliminate syntax errors.
+ protected $pattern = '/^[-+]? *[0-9]+ *(?:[-+*] *[0-9]+ *)*$/';
+ protected $min = null;
+ protected $max = null;
+
+ /** @inheritdoc */
+ public function update($input) {
+ $local = $this->local;
+ $valid = parent::update($input);
+ if($valid && !(is_null($this->min) && is_null($this->max))) {
+ $numeric_local = (int) eval('return ' . $this->local . ';');
+ if((!is_null($this->min) && $numeric_local < $this->min) ||
+ (!is_null($this->max) && $numeric_local > $this->max)) {
+ $this->error = true;
+ $this->input = $input;
+ $this->local = $local;
+ $valid = false;
+ }
+ }
+ return $valid;
+ }
+
+ /** @inheritdoc */
+ public function out($var, $fmt = 'php') {
+ if($fmt != 'php') return '';
+
+ $local = $this->local === '' ? "''" : $this->local;
+ $out = '$' . $var . "['" . $this->getArrayKey() . "'] = " . $local . ";\n";
+
+ return $out;
+ }
+}
diff --git a/lib/plugins/config/core/Setting/SettingNumericopt.php b/lib/plugins/config/core/Setting/SettingNumericopt.php
new file mode 100644
index 000000000..a486e187f
--- /dev/null
+++ b/lib/plugins/config/core/Setting/SettingNumericopt.php
@@ -0,0 +1,25 @@
+<?php
+
+namespace dokuwiki\plugin\config\core\Setting;
+
+/**
+ * Class setting_numericopt
+ */
+class SettingNumericopt extends SettingNumeric {
+ // just allow an empty config
+ protected $pattern = '/^(|[-]?[0-9]+(?:[-+*][0-9]+)*)$/';
+
+ /**
+ * @inheritdoc
+ * Empty string is valid for numericopt
+ */
+ public function update($input) {
+ if($input === '') {
+ if($input == $this->local) return false;
+ $this->local = $input;
+ return true;
+ }
+
+ return parent::update($input);
+ }
+}
diff --git a/lib/plugins/config/core/Setting/SettingOnoff.php b/lib/plugins/config/core/Setting/SettingOnoff.php
new file mode 100644
index 000000000..780778b48
--- /dev/null
+++ b/lib/plugins/config/core/Setting/SettingOnoff.php
@@ -0,0 +1,57 @@
+<?php
+
+namespace dokuwiki\plugin\config\core\Setting;
+
+/**
+ * Class setting_onoff
+ */
+class SettingOnoff extends SettingNumeric {
+
+ /**
+ * We treat the strings 'false' and 'off' as false
+ * @inheritdoc
+ */
+ protected function cleanValue($value) {
+ if($value === null) return null;
+
+ if(is_string($value)) {
+ if(strtolower($value) === 'false') return 0;
+ if(strtolower($value) === 'off') return 0;
+ if(trim($value) === '') return 0;
+ }
+
+ return (int) (bool) $value;
+ }
+
+ /** @inheritdoc */
+ public function html(\admin_plugin_config $plugin, $echo = false) {
+ $disable = '';
+
+ if($this->isProtected()) {
+ $value = $this->protected;
+ $disable = ' disabled="disabled"';
+ } else {
+ $value = is_null($this->local) ? $this->default : $this->local;
+ }
+
+ $key = htmlspecialchars($this->key);
+ $checked = ($value) ? ' checked="checked"' : '';
+
+ $label = '<label for="config___' . $key . '">' . $this->prompt($plugin) . '</label>';
+ $input = '<div class="input"><input id="config___' . $key . '" name="config[' . $key .
+ ']" type="checkbox" class="checkbox" value="1"' . $checked . $disable . '/></div>';
+ return array($label, $input);
+ }
+
+ /** @inheritdoc */
+ public function update($input) {
+ if($this->isProtected()) return false;
+
+ $input = ($input) ? 1 : 0;
+ $value = is_null($this->local) ? $this->default : $this->local;
+ if($value == $input) return false;
+
+ $this->local = $input;
+ return true;
+ }
+}
diff --git a/lib/plugins/config/core/Setting/SettingPassword.php b/lib/plugins/config/core/Setting/SettingPassword.php
new file mode 100644
index 000000000..9d9c53377
--- /dev/null
+++ b/lib/plugins/config/core/Setting/SettingPassword.php
@@ -0,0 +1,39 @@
+<?php
+
+namespace dokuwiki\plugin\config\core\Setting;
+
+/**
+ * Class setting_password
+ */
+class SettingPassword extends SettingString {
+
+ protected $code = 'plain'; // mechanism to be used to obscure passwords
+
+ /** @inheritdoc */
+ public function update($input) {
+ if($this->isProtected()) return false;
+ if(!$input) return false;
+
+ if($this->pattern && !preg_match($this->pattern, $input)) {
+ $this->error = true;
+ $this->input = $input;
+ return false;
+ }
+
+ $this->local = conf_encodeString($input, $this->code);
+ return true;
+ }
+
+ /** @inheritdoc */
+ public function html(\admin_plugin_config $plugin, $echo = false) {
+
+ $disable = $this->isProtected() ? 'disabled="disabled"' : '';
+
+ $key = htmlspecialchars($this->key);
+
+ $label = '<label for="config___' . $key . '">' . $this->prompt($plugin) . '</label>';
+ $input = '<input id="config___' . $key . '" name="config[' . $key .
+ ']" autocomplete="off" type="password" class="edit" value="" ' . $disable . ' />';
+ return array($label, $input);
+ }
+}
diff --git a/lib/plugins/config/core/Setting/SettingRegex.php b/lib/plugins/config/core/Setting/SettingRegex.php
new file mode 100644
index 000000000..b38f0a560
--- /dev/null
+++ b/lib/plugins/config/core/Setting/SettingRegex.php
@@ -0,0 +1,34 @@
+<?php
+
+namespace dokuwiki\plugin\config\core\Setting;
+
+/**
+ * Class setting_regex
+ */
+class SettingRegex extends SettingString {
+
+ protected $delimiter = '/'; // regex delimiter to be used in testing input
+ protected $pregflags = 'ui'; // regex pattern modifiers to be used in testing input
+
+ /** @inheritdoc */
+ public function update($input) {
+
+ // let parent do basic checks, value, not changed, etc.
+ $local = $this->local;
+ if(!parent::update($input)) return false;
+ $this->local = $local;
+
+ // see if the regex compiles and runs (we don't check for effectiveness)
+ $regex = $this->delimiter . $input . $this->delimiter . $this->pregflags;
+ $lastError = error_get_last();
+ @preg_match($regex, 'testdata');
+ if(preg_last_error() != PREG_NO_ERROR || error_get_last() != $lastError) {
+ $this->input = $input;
+ $this->error = true;
+ return false;
+ }
+
+ $this->local = $input;
+ return true;
+ }
+}
diff --git a/lib/plugins/config/core/Setting/SettingRenderer.php b/lib/plugins/config/core/Setting/SettingRenderer.php
new file mode 100644
index 000000000..37ba9c70a
--- /dev/null
+++ b/lib/plugins/config/core/Setting/SettingRenderer.php
@@ -0,0 +1,56 @@
+<?php
+/**
+ * additional setting classes specific to these settings
+ *
+ * @author Chris Smith <chris@jalakai.co.uk>
+ */
+
+namespace dokuwiki\plugin\config\core\Setting;
+
+/**
+ * Class setting_renderer
+ */
+class SettingRenderer extends SettingMultichoice {
+ protected $prompts = array();
+ protected $format = null;
+
+ /** @inheritdoc */
+ public function initialize($default = null, $local = null, $protected = null) {
+ $format = $this->format;
+
+ foreach(plugin_list('renderer') as $plugin) {
+ $renderer = plugin_load('renderer', $plugin);
+ if(method_exists($renderer, 'canRender') && $renderer->canRender($format)) {
+ $this->choices[] = $plugin;
+
+ $info = $renderer->getInfo();
+ $this->prompts[$plugin] = $info['name'];
+ }
+ }
+
+ parent::initialize($default, $local, $protected);
+ }
+
+ /** @inheritdoc */
+ public function html(\admin_plugin_config $plugin, $echo = false) {
+
+ // make some language adjustments (there must be a better way)
+ // transfer some plugin names to the config plugin
+ foreach($this->choices as $choice) {
+ if(!$plugin->getLang($this->key . '_o_' . $choice)) {
+ if(!isset($this->prompts[$choice])) {
+ $plugin->addLang(
+ $this->key . '_o_' . $choice,
+ sprintf($plugin->getLang('renderer__core'), $choice)
+ );
+ } else {
+ $plugin->addLang(
+ $this->key . '_o_' . $choice,
+ sprintf($plugin->getLang('renderer__plugin'), $this->prompts[$choice])
+ );
+ }
+ }
+ }
+ return parent::html($plugin, $echo);
+ }
+}
diff --git a/lib/plugins/config/core/Setting/SettingSavedir.php b/lib/plugins/config/core/Setting/SettingSavedir.php
new file mode 100644
index 000000000..43e428dd3
--- /dev/null
+++ b/lib/plugins/config/core/Setting/SettingSavedir.php
@@ -0,0 +1,26 @@
+<?php
+
+namespace dokuwiki\plugin\config\core\Setting;
+
+/**
+ * Class setting_savedir
+ */
+class SettingSavedir extends SettingString {
+
+ /** @inheritdoc */
+ public function update($input) {
+ if($this->isProtected()) return false;
+
+ $value = is_null($this->local) ? $this->default : $this->local;
+ if($value == $input) return false;
+
+ if(!init_path($input)) {
+ $this->error = true;
+ $this->input = $input;
+ return false;
+ }
+
+ $this->local = $input;
+ return true;
+ }
+}
diff --git a/lib/plugins/config/core/Setting/SettingSepchar.php b/lib/plugins/config/core/Setting/SettingSepchar.php
new file mode 100644
index 000000000..2d64eb08b
--- /dev/null
+++ b/lib/plugins/config/core/Setting/SettingSepchar.php
@@ -0,0 +1,18 @@
+<?php
+
+namespace dokuwiki\plugin\config\core\Setting;
+
+/**
+ * Class setting_sepchar
+ */
+class SettingSepchar extends SettingMultichoice {
+
+ /** @inheritdoc */
+ public function __construct($key, $param = null) {
+ $str = '_-.';
+ for($i = 0; $i < strlen($str); $i++) $this->choices[] = $str{$i};
+
+ // call foundation class constructor
+ parent::__construct($key, $param);
+ }
+}
diff --git a/lib/plugins/config/core/Setting/SettingString.php b/lib/plugins/config/core/Setting/SettingString.php
new file mode 100644
index 000000000..b819407b7
--- /dev/null
+++ b/lib/plugins/config/core/Setting/SettingString.php
@@ -0,0 +1,32 @@
+<?php
+
+namespace dokuwiki\plugin\config\core\Setting;
+
+/**
+ * Class setting_string
+ */
+class SettingString extends Setting {
+ /** @inheritdoc */
+ public function html(\admin_plugin_config $plugin, $echo = false) {
+ $disable = '';
+
+ if($this->isProtected()) {
+ $value = $this->protected;
+ $disable = 'disabled="disabled"';
+ } else {
+ if($echo && $this->error) {
+ $value = $this->input;
+ } else {
+ $value = is_null($this->local) ? $this->default : $this->local;
+ }
+ }
+
+ $key = htmlspecialchars($this->key);
+ $value = htmlspecialchars($value);
+
+ $label = '<label for="config___' . $key . '">' . $this->prompt($plugin) . '</label>';
+ $input = '<input id="config___' . $key . '" name="config[' . $key .
+ ']" type="text" class="edit" value="' . $value . '" ' . $disable . '/>';
+ return array($label, $input);
+ }
+}
diff --git a/lib/plugins/config/core/Setting/SettingUndefined.php b/lib/plugins/config/core/Setting/SettingUndefined.php
new file mode 100644
index 000000000..fa46a9f1d
--- /dev/null
+++ b/lib/plugins/config/core/Setting/SettingUndefined.php
@@ -0,0 +1,40 @@
+<?php
+
+namespace dokuwiki\plugin\config\core\Setting;
+
+use dokuwiki\plugin\config\core\Configuration;
+
+/**
+ * A do-nothing class used to detect settings with no metadata entry.
+ * Used internaly to hide undefined settings, and generate the undefined settings list.
+ */
+class SettingUndefined extends SettingHidden {
+
+ protected $errorMessage = '_msg_setting_undefined';
+
+ /** @inheritdoc */
+ public function shouldHaveDefault() {
+ return false;
+ }
+
+ /** @inheritdoc */
+ public function html(\admin_plugin_config $plugin, $echo = false) {
+ // determine the name the meta key would be called
+ if(preg_match(
+ '/^(?:plugin|tpl)' . Configuration::KEYMARKER . '.*?' . Configuration::KEYMARKER . '(.*)$/',
+ $this->getKey(),
+ $undefined_setting_match
+ )) {
+ $undefined_setting_key = $undefined_setting_match[1];
+ } else {
+ $undefined_setting_key = $this->getKey();
+ }
+
+ $label = '<span title="$meta[\'' . $undefined_setting_key . '\']">$' .
+ 'conf' . '[\'' . $this->getArrayKey() . '\']</span>';
+ $input = $plugin->getLang($this->errorMessage);
+
+ return array($label, $input);
+ }
+
+}
diff --git a/lib/plugins/config/core/Writer.php b/lib/plugins/config/core/Writer.php
new file mode 100644
index 000000000..6dee223ac
--- /dev/null
+++ b/lib/plugins/config/core/Writer.php
@@ -0,0 +1,116 @@
+<?php
+
+namespace dokuwiki\plugin\config\core;
+use dokuwiki\plugin\config\core\Setting\Setting;
+
+/**
+ * Writes the settings to the correct local file
+ */
+class Writer {
+ /** @var string header info */
+ protected $header = 'Dokuwiki\'s Main Configuration File - Local Settings';
+
+ /** @var string the file where the config will be saved to */
+ protected $savefile;
+
+ /**
+ * Writer constructor.
+ */
+ public function __construct() {
+ global $config_cascade;
+ $this->savefile = end($config_cascade['main']['local']);
+ }
+
+ /**
+ * Save the given settings
+ *
+ * @param Setting[] $settings
+ * @throws \Exception
+ */
+ public function save($settings) {
+ global $conf;
+ if($this->isLocked()) throw new \Exception('no save');
+
+ // backup current file (remove any existing backup)
+ if(file_exists($this->savefile)) {
+ if(file_exists($this->savefile . '.bak')) @unlink($this->savefile . '.bak');
+ if(!io_rename($this->savefile, $this->savefile . '.bak')) throw new \Exception('no backup');
+ }
+
+ if(!$fh = @fopen($this->savefile, 'wb')) {
+ io_rename($this->savefile . '.bak', $this->savefile); // problem opening, restore the backup
+ throw new \Exception('no save');
+ }
+
+ $out = $this->getHeader();
+ foreach($settings as $setting) {
+ if($setting->shouldBeSaved()) {
+ $out .= $setting->out('conf', 'php');
+ }
+ }
+
+ fwrite($fh, $out);
+ fclose($fh);
+ if($conf['fperm']) chmod($this->savefile, $conf['fperm']);
+ $this->opcacheUpdate($this->savefile);
+ }
+
+ /**
+ * Update last modified time stamp of the config file
+ *
+ * Will invalidate all DokuWiki caches
+ *
+ * @throws \Exception when the config isn't writable
+ */
+ public function touch() {
+ if($this->isLocked()) throw new \Exception('no save');
+ @touch($this->savefile);
+ $this->opcacheUpdate($this->savefile);
+ }
+
+ /**
+ * Invalidate the opcache of the given file
+ *
+ * @todo this should probably be moved to core
+ * @param string $file
+ */
+ protected function opcacheUpdate($file) {
+ if(!function_exists('opcache_invalidate')) return;
+ opcache_invalidate($file);
+ }
+
+ /**
+ * Configuration is considered locked if there is no local settings filename
+ * or the directory its in is not writable or the file exists and is not writable
+ *
+ * @return bool true: locked, false: writable
+ */
+ public function isLocked() {
+ if(!$this->savefile) return true;
+ if(!is_writable(dirname($this->savefile))) return true;
+ if(file_exists($this->savefile) && !is_writable($this->savefile)) return true;
+ return false;
+ }
+
+ /**
+ * Returns the PHP intro header for the config file
+ *
+ * @return string
+ */
+ protected function getHeader() {
+ return join(
+ "\n",
+ array(
+ '<?php',
+ '/*',
+ ' * ' . $this->header,
+ ' * Auto-generated by config plugin',
+ ' * Run for user: ' . $_SERVER['REMOTE_USER'],
+ ' * Date: ' . date('r'),
+ ' */',
+ '',
+ ''
+ )
+ );
+ }
+}
diff --git a/lib/plugins/config/lang/en/lang.php b/lib/plugins/config/lang/en/lang.php
index 63a49e36b..c48885c8d 100644
--- a/lib/plugins/config/lang/en/lang.php
+++ b/lib/plugins/config/lang/en/lang.php
@@ -46,6 +46,7 @@ $lang['_network'] = 'Network';
/* --- Undefined Setting Messages --- */
$lang['_msg_setting_undefined'] = 'No setting metadata.';
$lang['_msg_setting_no_class'] = 'No setting class.';
+$lang['_msg_setting_no_known_class'] = 'Setting class not available.';
$lang['_msg_setting_no_default'] = 'No default value.';
/* -------------------- Config Options --------------------------- */
diff --git a/lib/plugins/config/settings/config.class.php b/lib/plugins/config/settings/config.class.php
deleted file mode 100644
index 09b9a2bec..000000000
--- a/lib/plugins/config/settings/config.class.php
+++ /dev/null
@@ -1,1431 +0,0 @@
-<?php
-/**
- * Configuration Class and generic setting classes
- *
- * @author Chris Smith <chris@jalakai.co.uk>
- * @author Ben Coburn <btcoburn@silicodon.net>
- */
-
-
-if(!defined('CM_KEYMARKER')) define('CM_KEYMARKER','____');
-
-if (!class_exists('configuration')) {
- /**
- * Class configuration
- */
- class configuration {
-
- var $_name = 'conf'; // name of the config variable found in the files (overridden by $config['varname'])
- var $_format = 'php'; // format of the config file, supported formats - php (overridden by $config['format'])
- var $_heading = ''; // heading string written at top of config file - don't include comment indicators
- var $_loaded = false; // set to true after configuration files are loaded
- var $_metadata = array(); // holds metadata describing the settings
- /** @var setting[] */
- var $setting = array(); // array of setting objects
- var $locked = false; // configuration is considered locked if it can't be updated
- var $show_disabled_plugins = false;
-
- // configuration filenames
- var $_default_files = array();
- var $_local_files = array(); // updated configuration is written to the first file
- var $_protected_files = array();
-
- var $_plugin_list = null;
-
- /**
- * constructor
- *
- * @param string $datafile path to config metadata file
- */
- public function __construct($datafile) {
- global $conf, $config_cascade;
-
- if (!file_exists($datafile)) {
- msg('No configuration metadata found at - '.htmlspecialchars($datafile),-1);
- return;
- }
- $meta = array();
- include($datafile);
-
- if (isset($config['varname'])) $this->_name = $config['varname'];
- if (isset($config['format'])) $this->_format = $config['format'];
- if (isset($config['heading'])) $this->_heading = $config['heading'];
-
- $this->_default_files = $config_cascade['main']['default'];
- $this->_local_files = $config_cascade['main']['local'];
- $this->_protected_files = $config_cascade['main']['protected'];
-
- $this->locked = $this->_is_locked();
- $this->_metadata = array_merge($meta, $this->get_plugintpl_metadata($conf['template']));
- $this->retrieve_settings();
- }
-
- /**
- * Retrieve and stores settings in setting[] attribute
- */
- public function retrieve_settings() {
- global $conf;
- $no_default_check = array('setting_fieldset', 'setting_undefined', 'setting_no_class');
-
- if (!$this->_loaded) {
- $default = array_merge($this->get_plugintpl_default($conf['template']), $this->_read_config_group($this->_default_files));
- $local = $this->_read_config_group($this->_local_files);
- $protected = $this->_read_config_group($this->_protected_files);
-
- $keys = array_merge(array_keys($this->_metadata),array_keys($default), array_keys($local), array_keys($protected));
- $keys = array_unique($keys);
-
- $param = null;
- foreach ($keys as $key) {
- if (isset($this->_metadata[$key])) {
- $class = $this->_metadata[$key][0];
-
- if($class && class_exists('setting_'.$class)){
- $class = 'setting_'.$class;
- } else {
- if($class != '') {
- $this->setting[] = new setting_no_class($key,$param);
- }
- $class = 'setting';
- }
-
- $param = $this->_metadata[$key];
- array_shift($param);
- } else {
- $class = 'setting_undefined';
- $param = null;
- }
-
- if (!in_array($class, $no_default_check) && !isset($default[$key])) {
- $this->setting[] = new setting_no_default($key,$param);
- }
-
- $this->setting[$key] = new $class($key,$param);
-
- $d = array_key_exists($key, $default) ? $default[$key] : null;
- $l = array_key_exists($key, $local) ? $local[$key] : null;
- $p = array_key_exists($key, $protected) ? $protected[$key] : null;
-
- $this->setting[$key]->initialize($d,$l,$p);
- }
-
- $this->_loaded = true;
- }
- }
-
- /**
- * Stores setting[] array to file
- *
- * @param string $id Name of plugin, which saves the settings
- * @param string $header Text at the top of the rewritten settings file
- * @param bool $backup backup current file? (remove any existing backup)
- * @return bool succesful?
- */
- public function save_settings($id, $header='', $backup=true) {
- global $conf;
-
- if ($this->locked) return false;
-
- // write back to the last file in the local config cascade
- $file = end($this->_local_files);
-
- // backup current file (remove any existing backup)
- if (file_exists($file) && $backup) {
- if (file_exists($file.'.bak')) @unlink($file.'.bak');
- if (!io_rename($file, $file.'.bak')) return false;
- }
-
- if (!$fh = @fopen($file, 'wb')) {
- io_rename($file.'.bak', $file); // problem opening, restore the backup
- return false;
- }
-
- if (empty($header)) $header = $this->_heading;
-
- $out = $this->_out_header($id,$header);
-
- foreach ($this->setting as $setting) {
- $out .= $setting->out($this->_name, $this->_format);
- }
-
- $out .= $this->_out_footer();
-
- @fwrite($fh, $out);
- fclose($fh);
- if($conf['fperm']) chmod($file, $conf['fperm']);
- return true;
- }
-
- /**
- * Update last modified time stamp of the config file
- *
- * @return bool
- */
- public function touch_settings(){
- if ($this->locked) return false;
- $file = end($this->_local_files);
- return @touch($file);
- }
-
- /**
- * Read and merge given config files
- *
- * @param array $files file paths
- * @return array config settings
- */
- protected function _read_config_group($files) {
- $config = array();
- foreach ($files as $file) {
- $config = array_merge($config, $this->_read_config($file));
- }
-
- return $config;
- }
-
- /**
- * Return an array of config settings
- *
- * @param string $file file path
- * @return array config settings
- */
- function _read_config($file) {
-
- if (!$file) return array();
-
- $config = array();
-
- if ($this->_format == 'php') {
-
- if(file_exists($file)){
- $contents = @php_strip_whitespace($file);
- }else{
- $contents = '';
- }
- $pattern = '/\$'.$this->_name.'\[[\'"]([^=]+)[\'"]\] ?= ?(.*?);(?=[^;]*(?:\$'.$this->_name.'|$))/s';
- $matches=array();
- preg_match_all($pattern,$contents,$matches,PREG_SET_ORDER);
-
- for ($i=0; $i<count($matches); $i++) {
- $value = $matches[$i][2];
-
- // correct issues with the incoming data
- // FIXME ... for now merge multi-dimensional array indices using ____
- $key = preg_replace('/.\]\[./',CM_KEYMARKER,$matches[$i][1]);
-
- // handle arrays
- if(preg_match('/^array ?\((.*)\)/', $value, $match)){
- $arr = explode(',', $match[1]);
-
- // remove quotes from quoted strings & unescape escaped data
- $len = count($arr);
- for($j=0; $j<$len; $j++){
- $arr[$j] = trim($arr[$j]);
- $arr[$j] = $this->_readValue($arr[$j]);
- }
-
- $value = $arr;
- }else{
- $value = $this->_readValue($value);
- }
-
- $config[$key] = $value;
- }
- }
-
- return $config;
- }
-
- /**
- * Convert php string into value
- *
- * @param string $value
- * @return bool|string
- */
- protected function _readValue($value) {
- $removequotes_pattern = '/^(\'|")(.*)(?<!\\\\)\1$/s';
- $unescape_pairs = array(
- '\\\\' => '\\',
- '\\\'' => '\'',
- '\\"' => '"'
- );
-
- if($value == 'true') {
- $value = true;
- } elseif($value == 'false') {
- $value = false;
- } else {
- // remove quotes from quoted strings & unescape escaped data
- $value = preg_replace($removequotes_pattern,'$2',$value);
- $value = strtr($value, $unescape_pairs);
- }
- return $value;
- }
-
- /**
- * Returns header of rewritten settings file
- *
- * @param string $id plugin name of which generated this output
- * @param string $header additional text for at top of the file
- * @return string text of header
- */
- protected function _out_header($id, $header) {
- $out = '';
- if ($this->_format == 'php') {
- $out .= '<'.'?php'."\n".
- "/*\n".
- " * ".$header."\n".
- " * Auto-generated by ".$id." plugin\n".
- " * Run for user: ".$_SERVER['REMOTE_USER']."\n".
- " * Date: ".date('r')."\n".
- " */\n\n";
- }
-
- return $out;
- }
-
- /**
- * Returns footer of rewritten settings file
- *
- * @return string text of footer
- */
- protected function _out_footer() {
- $out = '';
- if ($this->_format == 'php') {
- $out .= "\n// end auto-generated content\n";
- }
-
- return $out;
- }
-
- /**
- * Configuration is considered locked if there is no local settings filename
- * or the directory its in is not writable or the file exists and is not writable
- *
- * @return bool true: locked, false: writable
- */
- protected function _is_locked() {
- if (!$this->_local_files) return true;
-
- $local = $this->_local_files[0];
-
- if (!is_writable(dirname($local))) return true;
- if (file_exists($local) && !is_writable($local)) return true;
-
- return false;
- }
-
- /**
- * not used ... conf's contents are an array!
- * reduce any multidimensional settings to one dimension using CM_KEYMARKER
- *
- * @param $conf
- * @param string $prefix
- * @return array
- */
- protected function _flatten($conf,$prefix='') {
-
- $out = array();
-
- foreach($conf as $key => $value) {
- if (!is_array($value)) {
- $out[$prefix.$key] = $value;
- continue;
- }
-
- $tmp = $this->_flatten($value,$prefix.$key.CM_KEYMARKER);
- $out = array_merge($out,$tmp);
- }
-
- return $out;
- }
-
- /**
- * Returns array of plugin names
- *
- * @return array plugin names
- * @triggers PLUGIN_CONFIG_PLUGINLIST event
- */
- function get_plugin_list() {
- if (is_null($this->_plugin_list)) {
- $list = plugin_list('',$this->show_disabled_plugins);
-
- // remove this plugin from the list
- $idx = array_search('config',$list);
- unset($list[$idx]);
- sort($list); // Sort plugin list alphabetically for display
-
- trigger_event('PLUGIN_CONFIG_PLUGINLIST',$list);
- $this->_plugin_list = $list;
- }
-
- return $this->_plugin_list;
- }
-
- /**
- * load metadata for plugin and template settings
- *
- * @param string $tpl name of active template
- * @return array metadata of settings
- */
- function get_plugintpl_metadata($tpl){
- $file = '/conf/metadata.php';
- $class = '/conf/settings.class.php';
- $metadata = array();
-
- foreach ($this->get_plugin_list() as $plugin) {
- $plugin_dir = plugin_directory($plugin);
- if (file_exists(DOKU_PLUGIN.$plugin_dir.$file)){
- $meta = array();
- @include(DOKU_PLUGIN.$plugin_dir.$file);
- @include(DOKU_PLUGIN.$plugin_dir.$class);
- if (!empty($meta)) {
- $metadata['plugin'.CM_KEYMARKER.$plugin.CM_KEYMARKER.'plugin_settings_name'] = array('fieldset');
- }
- foreach ($meta as $key => $value){
- if ($value[0]=='fieldset') { continue; } //plugins only get one fieldset
- $metadata['plugin'.CM_KEYMARKER.$plugin.CM_KEYMARKER.$key] = $value;
- }
- }
- }
-
- // the same for the active template
- if (file_exists(tpl_incdir().$file)){
- $meta = array();
- @include(tpl_incdir().$file);
- @include(tpl_incdir().$class);
- if (!empty($meta)) {
- $metadata['tpl'.CM_KEYMARKER.$tpl.CM_KEYMARKER.'template_settings_name'] = array('fieldset');
- }
- foreach ($meta as $key => $value){
- if ($value[0]=='fieldset') { continue; } //template only gets one fieldset
- $metadata['tpl'.CM_KEYMARKER.$tpl.CM_KEYMARKER.$key] = $value;
- }
- }
-
- return $metadata;
- }
-
- /**
- * Load default settings for plugins and templates
- *
- * @param string $tpl name of active template
- * @return array default settings
- */
- function get_plugintpl_default($tpl){
- $file = '/conf/default.php';
- $default = array();
-
- foreach ($this->get_plugin_list() as $plugin) {
- $plugin_dir = plugin_directory($plugin);
- if (file_exists(DOKU_PLUGIN.$plugin_dir.$file)){
- $conf = $this->_read_config(DOKU_PLUGIN.$plugin_dir.$file);
- foreach ($conf as $key => $value){
- $default['plugin'.CM_KEYMARKER.$plugin.CM_KEYMARKER.$key] = $value;
- }
- }
- }
-
- // the same for the active template
- if (file_exists(tpl_incdir().$file)){
- $conf = $this->_read_config(tpl_incdir().$file);
- foreach ($conf as $key => $value){
- $default['tpl'.CM_KEYMARKER.$tpl.CM_KEYMARKER.$key] = $value;
- }
- }
-
- return $default;
- }
-
- }
-}
-
-if (!class_exists('setting')) {
- /**
- * Class setting
- */
- class setting {
-
- var $_key = '';
- var $_default = null;
- var $_local = null;
- var $_protected = null;
-
- var $_pattern = '';
- var $_error = false; // only used by those classes which error check
- var $_input = null; // only used by those classes which error check
- var $_caution = null; // used by any setting to provide an alert along with the setting
- // valid alerts, 'warning', 'danger', 'security'
- // images matching the alerts are in the plugin's images directory
-
- static protected $_validCautions = array('warning','danger','security');
-
- /**
- * @param string $key
- * @param array|null $params array with metadata of setting
- */
- public function __construct($key, $params=null) {
- $this->_key = $key;
-
- if (is_array($params)) {
- foreach($params as $property => $value) {
- $this->$property = $value;
- }
- }
- }
-
- /**
- * Receives current values for the setting $key
- *
- * @param mixed $default default setting value
- * @param mixed $local local setting value
- * @param mixed $protected protected setting value
- */
- public function initialize($default, $local, $protected) {
- if (isset($default)) $this->_default = $default;
- if (isset($local)) $this->_local = $local;
- if (isset($protected)) $this->_protected = $protected;
- }
-
- /**
- * update changed setting with user provided value $input
- * - if changed value fails error check, save it to $this->_input (to allow echoing later)
- * - if changed value passes error check, set $this->_local to the new value
- *
- * @param mixed $input the new value
- * @return boolean true if changed, false otherwise (also on error)
- */
- public function update($input) {
- if (is_null($input)) return false;
- if ($this->is_protected()) return false;
-
- $value = is_null($this->_local) ? $this->_default : $this->_local;
- if ($value == $input) return false;
-
- if ($this->_pattern && !preg_match($this->_pattern,$input)) {
- $this->_error = true;
- $this->_input = $input;
- return false;
- }
-
- $this->_local = $input;
- return true;
- }
-
- /**
- * Build html for label and input of setting
- *
- * @param admin_plugin_config $plugin object of config plugin
- * @param bool $echo true: show inputted value, when error occurred, otherwise the stored setting
- * @return string[] with content array(string $label_html, string $input_html)
- */
- public function html(admin_plugin_config $plugin, $echo=false) {
- $disable = '';
-
- if ($this->is_protected()) {
- $value = $this->_protected;
- $disable = 'disabled="disabled"';
- } else {
- if ($echo && $this->_error) {
- $value = $this->_input;
- } else {
- $value = is_null($this->_local) ? $this->_default : $this->_local;
- }
- }
-
- $key = htmlspecialchars($this->_key);
- $value = formText($value);
-
- $label = '<label for="config___'.$key.'">'.$this->prompt($plugin).'</label>';
- $input = '<textarea rows="3" cols="40" id="config___'.$key.'" name="config['.$key.']" class="edit" '.$disable.'>'.$value.'</textarea>';
- return array($label,$input);
- }
-
- /**
- * Generate string to save setting value to file according to $fmt
- *
- * @param string $var name of variable
- * @param string $fmt save format
- * @return string
- */
- public function out($var, $fmt='php') {
-
- if ($this->is_protected()) return '';
- if (is_null($this->_local) || ($this->_default == $this->_local)) return '';
-
- $out = '';
-
- if ($fmt=='php') {
- $tr = array("\\" => '\\\\', "'" => '\\\'');
-
- $out = '$'.$var."['".$this->_out_key()."'] = '".strtr( cleanText($this->_local), $tr)."';\n";
- }
-
- return $out;
- }
-
- /**
- * Returns the localized prompt
- *
- * @param admin_plugin_config $plugin object of config plugin
- * @return string text
- */
- public function prompt(admin_plugin_config $plugin) {
- $prompt = $plugin->getLang($this->_key);
- if (!$prompt) $prompt = htmlspecialchars(str_replace(array('____','_'),' ',$this->_key));
- return $prompt;
- }
-
- /**
- * Is setting protected
- *
- * @return bool
- */
- public function is_protected() { return !is_null($this->_protected); }
-
- /**
- * Is setting the default?
- *
- * @return bool
- */
- public function is_default() { return !$this->is_protected() && is_null($this->_local); }
-
- /**
- * Has an error?
- *
- * @return bool
- */
- public function error() { return $this->_error; }
-
- /**
- * Returns caution
- *
- * @return false|string caution string, otherwise false for invalid caution
- */
- public function caution() {
- if (!empty($this->_caution)) {
- if (!in_array($this->_caution, setting::$_validCautions)) {
- trigger_error('Invalid caution string ('.$this->_caution.') in metadata for setting "'.$this->_key.'"', E_USER_WARNING);
- return false;
- }
- return $this->_caution;
- }
- // compatibility with previous cautionList
- // TODO: check if any plugins use; remove
- if (!empty($this->_cautionList[$this->_key])) {
- $this->_caution = $this->_cautionList[$this->_key];
- unset($this->_cautionList);
-
- return $this->caution();
- }
- return false;
- }
-
- /**
- * Returns setting key, eventually with referer to config: namespace at dokuwiki.org
- *
- * @param bool $pretty create nice key
- * @param bool $url provide url to config: namespace
- * @return string key
- */
- public function _out_key($pretty=false,$url=false) {
- if($pretty){
- $out = str_replace(CM_KEYMARKER,"»",$this->_key);
- if ($url && !strstr($out,'»')) {//provide no urls for plugins, etc.
- if ($out == 'start') //one exception
- return '<a href="http://www.dokuwiki.org/config:startpage">'.$out.'</a>';
- else
- return '<a href="http://www.dokuwiki.org/config:'.$out.'">'.$out.'</a>';
- }
- return $out;
- }else{
- return str_replace(CM_KEYMARKER,"']['",$this->_key);
- }
- }
- }
-}
-
-
-if (!class_exists('setting_array')) {
- /**
- * Class setting_array
- */
- class setting_array extends setting {
-
- /**
- * Create an array from a string
- *
- * @param string $string
- * @return array
- */
- protected function _from_string($string){
- $array = explode(',', $string);
- $array = array_map('trim', $array);
- $array = array_filter($array);
- $array = array_unique($array);
- return $array;
- }
-
- /**
- * Create a string from an array
- *
- * @param array $array
- * @return string
- */
- protected function _from_array($array){
- return join(', ', (array) $array);
- }
-
- /**
- * update setting with user provided value $input
- * if value fails error check, save it
- *
- * @param string $input
- * @return bool true if changed, false otherwise (incl. on error)
- */
- function update($input) {
- if (is_null($input)) return false;
- if ($this->is_protected()) return false;
-
- $input = $this->_from_string($input);
-
- $value = is_null($this->_local) ? $this->_default : $this->_local;
- if ($value == $input) return false;
-
- foreach($input as $item){
- if ($this->_pattern && !preg_match($this->_pattern,$item)) {
- $this->_error = true;
- $this->_input = $input;
- return false;
- }
- }
-
- $this->_local = $input;
- return true;
- }
-
- /**
- * Escaping
- *
- * @param string $string
- * @return string
- */
- protected function _escape($string) {
- $tr = array("\\" => '\\\\', "'" => '\\\'');
- return "'".strtr( cleanText($string), $tr)."'";
- }
-
- /**
- * Generate string to save setting value to file according to $fmt
- *
- * @param string $var name of variable
- * @param string $fmt save format
- * @return string
- */
- function out($var, $fmt='php') {
-
- if ($this->is_protected()) return '';
- if (is_null($this->_local) || ($this->_default == $this->_local)) return '';
-
- $out = '';
-
- if ($fmt=='php') {
- $vals = array_map(array($this, '_escape'), $this->_local);
- $out = '$'.$var."['".$this->_out_key()."'] = array(".join(', ',$vals).");\n";
- }
-
- return $out;
- }
-
- /**
- * Build html for label and input of setting
- *
- * @param admin_plugin_config $plugin object of config plugin
- * @param bool $echo true: show inputted value, when error occurred, otherwise the stored setting
- * @return string[] with content array(string $label_html, string $input_html)
- */
- function html(admin_plugin_config $plugin, $echo=false) {
- $disable = '';
-
- if ($this->is_protected()) {
- $value = $this->_protected;
- $disable = 'disabled="disabled"';
- } else {
- if ($echo && $this->_error) {
- $value = $this->_input;
- } else {
- $value = is_null($this->_local) ? $this->_default : $this->_local;
- }
- }
-
- $key = htmlspecialchars($this->_key);
- $value = htmlspecialchars($this->_from_array($value));
-
- $label = '<label for="config___'.$key.'">'.$this->prompt($plugin).'</label>';
- $input = '<input id="config___'.$key.'" name="config['.$key.']" type="text" class="edit" value="'.$value.'" '.$disable.'/>';
- return array($label,$input);
- }
- }
-}
-
-if (!class_exists('setting_string')) {
- /**
- * Class setting_string
- */
- class setting_string extends setting {
- /**
- * Build html for label and input of setting
- *
- * @param admin_plugin_config $plugin object of config plugin
- * @param bool $echo true: show inputted value, when error occurred, otherwise the stored setting
- * @return string[] with content array(string $label_html, string $input_html)
- */
- function html(admin_plugin_config $plugin, $echo=false) {
- $disable = '';
-
- if ($this->is_protected()) {
- $value = $this->_protected;
- $disable = 'disabled="disabled"';
- } else {
- if ($echo && $this->_error) {
- $value = $this->_input;
- } else {
- $value = is_null($this->_local) ? $this->_default : $this->_local;
- }
- }
-
- $key = htmlspecialchars($this->_key);
- $value = htmlspecialchars($value);
-
- $label = '<label for="config___'.$key.'">'.$this->prompt($plugin).'</label>';
- $input = '<input id="config___'.$key.'" name="config['.$key.']" type="text" class="edit" value="'.$value.'" '.$disable.'/>';
- return array($label,$input);
- }
- }
-}
-
-if (!class_exists('setting_password')) {
- /**
- * Class setting_password
- */
- class setting_password extends setting_string {
-
- var $_code = 'plain'; // mechanism to be used to obscure passwords
-
- /**
- * update changed setting with user provided value $input
- * - if changed value fails error check, save it to $this->_input (to allow echoing later)
- * - if changed value passes error check, set $this->_local to the new value
- *
- * @param mixed $input the new value
- * @return boolean true if changed, false otherwise (also on error)
- */
- function update($input) {
- if ($this->is_protected()) return false;
- if (!$input) return false;
-
- if ($this->_pattern && !preg_match($this->_pattern,$input)) {
- $this->_error = true;
- $this->_input = $input;
- return false;
- }
-
- $this->_local = conf_encodeString($input,$this->_code);
- return true;
- }
-
- /**
- * Build html for label and input of setting
- *
- * @param admin_plugin_config $plugin object of config plugin
- * @param bool $echo true: show inputted value, when error occurred, otherwise the stored setting
- * @return string[] with content array(string $label_html, string $input_html)
- */
- function html(admin_plugin_config $plugin, $echo=false) {
-
- $disable = $this->is_protected() ? 'disabled="disabled"' : '';
-
- $key = htmlspecialchars($this->_key);
-
- $label = '<label for="config___'.$key.'">'.$this->prompt($plugin).'</label>';
- $input = '<input id="config___'.$key.'" name="config['.$key.']" autocomplete="off" type="password" class="edit" value="" '.$disable.' />';
- return array($label,$input);
- }
- }
-}
-
-if (!class_exists('setting_email')) {
- /**
- * Class setting_email
- */
- class setting_email extends setting_string {
- var $_multiple = false;
- var $_placeholders = false;
-
- /**
- * update setting with user provided value $input
- * if value fails error check, save it
- *
- * @param mixed $input
- * @return boolean true if changed, false otherwise (incl. on error)
- */
- function update($input) {
- if (is_null($input)) return false;
- if ($this->is_protected()) return false;
-
- $value = is_null($this->_local) ? $this->_default : $this->_local;
- if ($value == $input) return false;
- if($input === ''){
- $this->_local = $input;
- return true;
- }
- $mail = $input;
-
- if($this->_placeholders){
- // replace variables with pseudo values
- $mail = str_replace('@USER@','joe',$mail);
- $mail = str_replace('@NAME@','Joe Schmoe',$mail);
- $mail = str_replace('@MAIL@','joe@example.com',$mail);
- }
-
- // multiple mail addresses?
- if ($this->_multiple) {
- $mails = array_filter(array_map('trim', explode(',', $mail)));
- } else {
- $mails = array($mail);
- }
-
- // check them all
- foreach ($mails as $mail) {
- // only check the address part
- if(preg_match('#(.*?)<(.*?)>#', $mail, $matches)){
- $addr = $matches[2];
- }else{
- $addr = $mail;
- }
-
- if (!mail_isvalid($addr)) {
- $this->_error = true;
- $this->_input = $input;
- return false;
- }
- }
-
- $this->_local = $input;
- return true;
- }
- }
-}
-
-if (!class_exists('setting_numeric')) {
- /**
- * Class setting_numeric
- */
- class setting_numeric extends setting_string {
- // This allows for many PHP syntax errors...
- // var $_pattern = '/^[-+\/*0-9 ]*$/';
- // much more restrictive, but should eliminate syntax errors.
- var $_pattern = '/^[-+]? *[0-9]+ *(?:[-+*] *[0-9]+ *)*$/';
- var $_min = null;
- var $_max = null;
-
- /**
- * update changed setting with user provided value $input
- * - if changed value fails error check, save it to $this->_input (to allow echoing later)
- * - if changed value passes error check, set $this->_local to the new value
- *
- * @param mixed $input the new value
- * @return boolean true if changed, false otherwise (also on error)
- */
- function update($input) {
- $local = $this->_local;
- $valid = parent::update($input);
- if ($valid && !(is_null($this->_min) && is_null($this->_max))) {
- $numeric_local = (int) eval('return '.$this->_local.';');
- if ((!is_null($this->_min) && $numeric_local < $this->_min) ||
- (!is_null($this->_max) && $numeric_local > $this->_max)) {
- $this->_error = true;
- $this->_input = $input;
- $this->_local = $local;
- $valid = false;
- }
- }
- return $valid;
- }
-
- /**
- * Generate string to save setting value to file according to $fmt
- *
- * @param string $var name of variable
- * @param string $fmt save format
- * @return string
- */
- function out($var, $fmt='php') {
-
- if ($this->is_protected()) return '';
- if (is_null($this->_local) || ($this->_default == $this->_local)) return '';
-
- $out = '';
-
- if ($fmt=='php') {
- $local = $this->_local === '' ? "''" : $this->_local;
- $out .= '$'.$var."['".$this->_out_key()."'] = ".$local.";\n";
- }
-
- return $out;
- }
- }
-}
-
-if (!class_exists('setting_numericopt')) {
- /**
- * Class setting_numericopt
- */
- class setting_numericopt extends setting_numeric {
- // just allow an empty config
- var $_pattern = '/^(|[-]?[0-9]+(?:[-+*][0-9]+)*)$/';
-
-
- /**
- * Empty string is valid for numericopt
- *
- * @param mixed $input
- *
- * @return bool
- */
- function update($input) {
- if ($input === '') {
- return true;
- }
-
- return parent::update($input);
- }
- }
-}
-
-if (!class_exists('setting_onoff')) {
- /**
- * Class setting_onoff
- */
- class setting_onoff extends setting_numeric {
- /**
- * Build html for label and input of setting
- *
- * @param admin_plugin_config $plugin object of config plugin
- * @param bool $echo true: show inputted value, when error occurred, otherwise the stored setting
- * @return string[] with content array(string $label_html, string $input_html)
- */
- function html(admin_plugin_config $plugin, $echo = false) {
- $disable = '';
-
- if ($this->is_protected()) {
- $value = $this->_protected;
- $disable = ' disabled="disabled"';
- } else {
- $value = is_null($this->_local) ? $this->_default : $this->_local;
- }
-
- $key = htmlspecialchars($this->_key);
- $checked = ($value) ? ' checked="checked"' : '';
-
- $label = '<label for="config___'.$key.'">'.$this->prompt($plugin).'</label>';
- $input = '<div class="input"><input id="config___'.$key.'" name="config['.$key.']" type="checkbox" class="checkbox" value="1"'.$checked.$disable.'/></div>';
- return array($label,$input);
- }
-
- /**
- * update changed setting with user provided value $input
- * - if changed value fails error check, save it to $this->_input (to allow echoing later)
- * - if changed value passes error check, set $this->_local to the new value
- *
- * @param mixed $input the new value
- * @return boolean true if changed, false otherwise (also on error)
- */
- function update($input) {
- if ($this->is_protected()) return false;
-
- $input = ($input) ? 1 : 0;
- $value = is_null($this->_local) ? $this->_default : $this->_local;
- if ($value == $input) return false;
-
- $this->_local = $input;
- return true;
- }
- }
-}
-
-if (!class_exists('setting_multichoice')) {
- /**
- * Class setting_multichoice
- */
- class setting_multichoice extends setting_string {
- var $_choices = array();
- var $lang; //some custom language strings are stored in setting
-
- /**
- * Build html for label and input of setting
- *
- * @param admin_plugin_config $plugin object of config plugin
- * @param bool $echo true: show inputted value, when error occurred, otherwise the stored setting
- * @return string[] with content array(string $label_html, string $input_html)
- */
- function html(admin_plugin_config $plugin, $echo = false) {
- $disable = '';
- $nochoice = '';
-
- if ($this->is_protected()) {
- $value = $this->_protected;
- $disable = ' disabled="disabled"';
- } else {
- $value = is_null($this->_local) ? $this->_default : $this->_local;
- }
-
- // ensure current value is included
- if (!in_array($value, $this->_choices)) {
- $this->_choices[] = $value;
- }
- // disable if no other choices
- if (!$this->is_protected() && count($this->_choices) <= 1) {
- $disable = ' disabled="disabled"';
- $nochoice = $plugin->getLang('nochoice');
- }
-
- $key = htmlspecialchars($this->_key);
-
- $label = '<label for="config___'.$key.'">'.$this->prompt($plugin).'</label>';
-
- $input = "<div class=\"input\">\n";
- $input .= '<select class="edit" id="config___'.$key.'" name="config['.$key.']"'.$disable.'>'."\n";
- foreach ($this->_choices as $choice) {
- $selected = ($value == $choice) ? ' selected="selected"' : '';
- $option = $plugin->getLang($this->_key.'_o_'.$choice);
- if (!$option && isset($this->lang[$this->_key.'_o_'.$choice])) $option = $this->lang[$this->_key.'_o_'.$choice];
- if (!$option) $option = $choice;
-
- $choice = htmlspecialchars($choice);
- $option = htmlspecialchars($option);
- $input .= ' <option value="'.$choice.'"'.$selected.' >'.$option.'</option>'."\n";
- }
- $input .= "</select> $nochoice \n";
- $input .= "</div>\n";
-
- return array($label,$input);
- }
-
- /**
- * update changed setting with user provided value $input
- * - if changed value fails error check, save it to $this->_input (to allow echoing later)
- * - if changed value passes error check, set $this->_local to the new value
- *
- * @param mixed $input the new value
- * @return boolean true if changed, false otherwise (also on error)
- */
- function update($input) {
- if (is_null($input)) return false;
- if ($this->is_protected()) return false;
-
- $value = is_null($this->_local) ? $this->_default : $this->_local;
- if ($value == $input) return false;
-
- if (!in_array($input, $this->_choices)) return false;
-
- $this->_local = $input;
- return true;
- }
- }
-}
-
-
-if (!class_exists('setting_dirchoice')) {
- /**
- * Class setting_dirchoice
- */
- class setting_dirchoice extends setting_multichoice {
-
- var $_dir = '';
-
- /**
- * Receives current values for the setting $key
- *
- * @param mixed $default default setting value
- * @param mixed $local local setting value
- * @param mixed $protected protected setting value
- */
- function initialize($default,$local,$protected) {
-
- // populate $this->_choices with a list of directories
- $list = array();
-
- if ($dh = @opendir($this->_dir)) {
- while (false !== ($entry = readdir($dh))) {
- if ($entry == '.' || $entry == '..') continue;
- if ($this->_pattern && !preg_match($this->_pattern,$entry)) continue;
-
- $file = (is_link($this->_dir.$entry)) ? readlink($this->_dir.$entry) : $this->_dir.$entry;
- if (is_dir($file)) $list[] = $entry;
- }
- closedir($dh);
- }
- sort($list);
- $this->_choices = $list;
-
- parent::initialize($default,$local,$protected);
- }
- }
-}
-
-
-if (!class_exists('setting_hidden')) {
- /**
- * Class setting_hidden
- */
- class setting_hidden extends setting {
- // Used to explicitly ignore a setting in the configuration manager.
- }
-}
-
-if (!class_exists('setting_fieldset')) {
- /**
- * Class setting_fieldset
- */
- class setting_fieldset extends setting {
- // A do-nothing class used to detect the 'fieldset' type.
- // Used to start a new settings "display-group".
- }
-}
-
-if (!class_exists('setting_undefined')) {
- /**
- * Class setting_undefined
- */
- class setting_undefined extends setting_hidden {
- // A do-nothing class used to detect settings with no metadata entry.
- // Used internaly to hide undefined settings, and generate the undefined settings list.
- }
-}
-
-if (!class_exists('setting_no_class')) {
- /**
- * Class setting_no_class
- */
- class setting_no_class extends setting_undefined {
- // A do-nothing class used to detect settings with a missing setting class.
- // Used internaly to hide undefined settings, and generate the undefined settings list.
- }
-}
-
-if (!class_exists('setting_no_default')) {
- /**
- * Class setting_no_default
- */
- class setting_no_default extends setting_undefined {
- // A do-nothing class used to detect settings with no default value.
- // Used internaly to hide undefined settings, and generate the undefined settings list.
- }
-}
-
-if (!class_exists('setting_multicheckbox')) {
- /**
- * Class setting_multicheckbox
- */
- class setting_multicheckbox extends setting_string {
-
- var $_choices = array();
- var $_combine = array();
- var $_other = 'always';
-
- /**
- * update changed setting with user provided value $input
- * - if changed value fails error check, save it to $this->_input (to allow echoing later)
- * - if changed value passes error check, set $this->_local to the new value
- *
- * @param mixed $input the new value
- * @return boolean true if changed, false otherwise (also on error)
- */
- function update($input) {
- if ($this->is_protected()) return false;
-
- // split any combined values + convert from array to comma separated string
- $input = ($input) ? $input : array();
- $input = $this->_array2str($input);
-
- $value = is_null($this->_local) ? $this->_default : $this->_local;
- if ($value == $input) return false;
-
- if ($this->_pattern && !preg_match($this->_pattern,$input)) {
- $this->_error = true;
- $this->_input = $input;
- return false;
- }
-
- $this->_local = $input;
- return true;
- }
-
- /**
- * Build html for label and input of setting
- *
- * @param admin_plugin_config $plugin object of config plugin
- * @param bool $echo true: show input value, when error occurred, otherwise the stored setting
- * @return string[] with content array(string $label_html, string $input_html)
- */
- function html(admin_plugin_config $plugin, $echo=false) {
-
- $disable = '';
-
- if ($this->is_protected()) {
- $value = $this->_protected;
- $disable = 'disabled="disabled"';
- } else {
- if ($echo && $this->_error) {
- $value = $this->_input;
- } else {
- $value = is_null($this->_local) ? $this->_default : $this->_local;
- }
- }
-
- $key = htmlspecialchars($this->_key);
-
- // convert from comma separated list into array + combine complimentary actions
- $value = $this->_str2array($value);
- $default = $this->_str2array($this->_default);
-
- $input = '';
- foreach ($this->_choices as $choice) {
- $idx = array_search($choice, $value);
- $idx_default = array_search($choice,$default);
-
- $checked = ($idx !== false) ? 'checked="checked"' : '';
-
- // @todo ideally this would be handled using a second class of "default"
- $class = (($idx !== false) == (false !== $idx_default)) ? " selectiondefault" : "";
-
- $prompt = ($plugin->getLang($this->_key.'_'.$choice) ?
- $plugin->getLang($this->_key.'_'.$choice) : htmlspecialchars($choice));
-
- $input .= '<div class="selection'.$class.'">'."\n";
- $input .= '<label for="config___'.$key.'_'.$choice.'">'.$prompt."</label>\n";
- $input .= '<input id="config___'.$key.'_'.$choice.'" name="config['.$key.'][]" type="checkbox" class="checkbox" value="'.$choice.'" '.$disable.' '.$checked."/>\n";
- $input .= "</div>\n";
-
- // remove this action from the disabledactions array
- if ($idx !== false) unset($value[$idx]);
- if ($idx_default !== false) unset($default[$idx_default]);
- }
-
- // handle any remaining values
- if ($this->_other != 'never'){
- $other = join(',',$value);
- // test equivalent to ($this->_other == 'always' || ($other && $this->_other == 'exists')
- // use != 'exists' rather than == 'always' to ensure invalid values default to 'always'
- if ($this->_other != 'exists' || $other) {
-
- $class = ((count($default) == count($value)) && (count($value) == count(array_intersect($value,$default)))) ?
- " selectiondefault" : "";
-
- $input .= '<div class="other'.$class.'">'."\n";
- $input .= '<label for="config___'.$key.'_other">'.$plugin->getLang($key.'_other')."</label>\n";
- $input .= '<input id="config___'.$key.'_other" name="config['.$key.'][other]" type="text" class="edit" value="'.htmlspecialchars($other).'" '.$disable." />\n";
- $input .= "</div>\n";
- }
- }
- $label = '<label>'.$this->prompt($plugin).'</label>';
- return array($label,$input);
- }
-
- /**
- * convert comma separated list to an array and combine any complimentary values
- *
- * @param string $str
- * @return array
- */
- function _str2array($str) {
- $array = explode(',',$str);
-
- if (!empty($this->_combine)) {
- foreach ($this->_combine as $key => $combinators) {
- $idx = array();
- foreach ($combinators as $val) {
- if (($idx[] = array_search($val, $array)) === false) break;
- }
-
- if (count($idx) && $idx[count($idx)-1] !== false) {
- foreach ($idx as $i) unset($array[$i]);
- $array[] = $key;
- }
- }
- }
-
- return $array;
- }
-
- /**
- * convert array of values + other back to a comma separated list, incl. splitting any combined values
- *
- * @param array $input
- * @return string
- */
- function _array2str($input) {
-
- // handle other
- $other = trim($input['other']);
- $other = !empty($other) ? explode(',',str_replace(' ','',$input['other'])) : array();
- unset($input['other']);
-
- $array = array_unique(array_merge($input, $other));
-
- // deconstruct any combinations
- if (!empty($this->_combine)) {
- foreach ($this->_combine as $key => $combinators) {
-
- $idx = array_search($key,$array);
- if ($idx !== false) {
- unset($array[$idx]);
- $array = array_merge($array, $combinators);
- }
- }
- }
-
- return join(',',array_unique($array));
- }
- }
-}
-
-if (!class_exists('setting_regex')){
- /**
- * Class setting_regex
- */
- class setting_regex extends setting_string {
-
- var $_delimiter = '/'; // regex delimiter to be used in testing input
- var $_pregflags = 'ui'; // regex pattern modifiers to be used in testing input
-
- /**
- * update changed setting with user provided value $input
- * - if changed value fails error check, save it to $this->_input (to allow echoing later)
- * - if changed value passes error check, set $this->_local to the new value
- *
- * @param mixed $input the new value
- * @return boolean true if changed, false otherwise (incl. on error)
- */
- function update($input) {
-
- // let parent do basic checks, value, not changed, etc.
- $local = $this->_local;
- if (!parent::update($input)) return false;
- $this->_local = $local;
-
- // see if the regex compiles and runs (we don't check for effectiveness)
- $regex = $this->_delimiter . $input . $this->_delimiter . $this->_pregflags;
- $lastError = error_get_last();
- @preg_match($regex,'testdata');
- if (preg_last_error() != PREG_NO_ERROR || error_get_last() != $lastError) {
- $this->_input = $input;
- $this->_error = true;
- return false;
- }
-
- $this->_local = $input;
- return true;
- }
- }
-}
diff --git a/lib/plugins/config/settings/config.metadata.php b/lib/plugins/config/settings/config.metadata.php
index 1d7eea9a5..9a9b6d901 100644
--- a/lib/plugins/config/settings/config.metadata.php
+++ b/lib/plugins/config/settings/config.metadata.php
@@ -2,16 +2,15 @@
/**
* Metadata for configuration manager plugin
*
- * Note: This file should be included within a function to ensure it
- * doesn't clash with the settings it is describing.
+ * Note: This file is loaded in Loader::loadMeta().
*
* Format:
* $meta[<setting name>] = array(<handler class id>,<param name> => <param value>);
*
* <handler class id> is the handler class name without the "setting_" prefix
*
- * Defined classes:
- * Generic (source: settings/config.class.php)
+ * Defined classes (see core/Setting/*):
+ * Generic
* -------------------------------------------
* '' - default class ('setting'), textarea, minimal input validation, setting output in quotes
* 'string' - single line text input, minimal input validation, setting output in quotes
@@ -38,7 +37,7 @@
* to see if will compile & run as a regex. in addition to _pattern, also accepts _delimiter
* (default '/') and _pregflags (default 'ui')
*
- * Single Setting (source: settings/extra.class.php)
+ * Single Setting
* -------------------------------------------------
* 'savedir' - as 'setting', input tested against initpath() (inc/init.php)
* 'sepchar' - as multichoice, selection constructed from string of valid values
@@ -76,26 +75,10 @@
* 'never' as it will not discard unknown/other values.
* optional for 'multicheckbox', ignored by others
*
+ * The order of the settings influences the order in which they apppear in the config manager
*
* @author Chris Smith <chris@jalakai.co.uk>
*/
-// ---------------[ settings for settings ]------------------------------
-$config['format'] = 'php'; // format of setting files, supported formats: php
-$config['varname'] = 'conf'; // name of the config variable, sans $
-
-// this string is written at the top of the rewritten settings file,
-// !! do not include any comment indicators !!
-// this value can be overriden when calling save_settings() method
-$config['heading'] = 'Dokuwiki\'s Main Configuration File - Local Settings';
-
-// test value (FIXME, remove before publishing)
-//$meta['test'] = array('multichoice','_choices' => array(''));
-
-// --------------[ setting metadata ]------------------------------------
-// - for description of format and fields see top of file
-// - order the settings in the order you wish them to appear
-// - any settings not mentioned will come after the last setting listed and
-// will use the default class with no parameters
$meta['_basic'] = array('fieldset');
$meta['title'] = array('string');
@@ -122,7 +105,10 @@ $meta['fullpath'] = array('onoff','_caution' => 'security');
$meta['typography'] = array('multichoice','_choices' => array(0,1,2));
$meta['dformat'] = array('string');
$meta['signature'] = array('string');
-$meta['showuseras'] = array('multichoice','_choices' => array('loginname','username','username_link','email','email_link'));
+$meta['showuseras'] = array(
+ 'multichoice',
+ '_choices' => array('loginname', 'username', 'username_link', 'email', 'email_link')
+);
$meta['toptoclevel'] = array('multichoice','_choices' => array(1,2,3,4,5)); // 5 toc levels
$meta['tocminheads'] = array('multichoice','_choices' => array(0,1,2,3,4,5,10,15,20));
$meta['maxtoclevel'] = array('multichoice','_choices' => array(0,1,2,3,4,5));
@@ -146,9 +132,29 @@ $meta['superuser'] = array('string','_caution' => 'danger');
$meta['manager'] = array('string');
$meta['profileconfirm'] = array('onoff');
$meta['rememberme'] = array('onoff');
-$meta['disableactions'] = array('disableactions',
- '_choices' => array('backlink','index','recent','revisions','search','subscription','register','resendpwd','profile','profile_delete','edit','wikicode','check', 'rss'),
- '_combine' => array('subscription' => array('subscribe','unsubscribe'), 'wikicode' => array('source','export_raw')));
+$meta['disableactions'] = array(
+ 'disableactions',
+ '_choices' => array(
+ 'backlink',
+ 'index',
+ 'recent',
+ 'revisions',
+ 'search',
+ 'subscription',
+ 'register',
+ 'resendpwd',
+ 'profile',
+ 'profile_delete',
+ 'edit',
+ 'wikicode',
+ 'check',
+ 'rss'
+ ),
+ '_combine' => array(
+ 'subscription' => array('subscribe', 'unsubscribe'),
+ 'wikicode' => array('source', 'export_raw')
+ )
+);
$meta['auth_security_timeout'] = array('numeric');
$meta['securecookie'] = array('onoff');
$meta['remote'] = array('onoff','_caution' => 'security');
diff --git a/lib/plugins/config/settings/extra.class.php b/lib/plugins/config/settings/extra.class.php
deleted file mode 100644
index 41af42247..000000000
--- a/lib/plugins/config/settings/extra.class.php
+++ /dev/null
@@ -1,309 +0,0 @@
-<?php
-/**
- * additional setting classes specific to these settings
- *
- * @author Chris Smith <chris@jalakai.co.uk>
- */
-
-if (!class_exists('setting_sepchar')) {
- /**
- * Class setting_sepchar
- */
- class setting_sepchar extends setting_multichoice {
-
- /**
- * @param string $key
- * @param array|null $param array with metadata of setting
- */
- function __construct($key,$param=null) {
- $str = '_-.';
- for ($i=0;$i<strlen($str);$i++) $this->_choices[] = $str{$i};
-
- // call foundation class constructor
- parent::__construct($key,$param);
- }
- }
-}
-
-if (!class_exists('setting_savedir')) {
- /**
- * Class setting_savedir
- */
- class setting_savedir extends setting_string {
-
- /**
- * update changed setting with user provided value $input
- * - if changed value fails error check, save it to $this->_input (to allow echoing later)
- * - if changed value passes error check, set $this->_local to the new value
- *
- * @param mixed $input the new value
- * @return boolean true if changed, false otherwise (also on error)
- */
- function update($input) {
- if ($this->is_protected()) return false;
-
- $value = is_null($this->_local) ? $this->_default : $this->_local;
- if ($value == $input) return false;
-
- if (!init_path($input)) {
- $this->_error = true;
- $this->_input = $input;
- return false;
- }
-
- $this->_local = $input;
- return true;
- }
- }
-}
-
-if (!class_exists('setting_authtype')) {
- /**
- * Class setting_authtype
- */
- class setting_authtype extends setting_multichoice {
-
- /**
- * Receives current values for the setting $key
- *
- * @param mixed $default default setting value
- * @param mixed $local local setting value
- * @param mixed $protected protected setting value
- */
- function initialize($default,$local,$protected) {
- /** @var $plugin_controller Doku_Plugin_Controller */
- global $plugin_controller;
-
- // retrieve auth types provided by plugins
- foreach ($plugin_controller->getList('auth') as $plugin) {
- $this->_choices[] = $plugin;
- }
-
- parent::initialize($default,$local,$protected);
- }
-
- /**
- * update changed setting with user provided value $input
- * - if changed value fails error check, save it to $this->_input (to allow echoing later)
- * - if changed value passes error check, set $this->_local to the new value
- *
- * @param mixed $input the new value
- * @return boolean true if changed, false otherwise (also on error)
- */
- function update($input) {
- /** @var $plugin_controller Doku_Plugin_Controller */
- global $plugin_controller;
-
- // is an update possible/requested?
- $local = $this->_local; // save this, parent::update() may change it
- if (!parent::update($input)) return false; // nothing changed or an error caught by parent
- $this->_local = $local; // restore original, more error checking to come
-
- // attempt to load the plugin
- $auth_plugin = $plugin_controller->load('auth', $input);
-
- // @TODO: throw an error in plugin controller instead of returning null
- if (is_null($auth_plugin)) {
- $this->_error = true;
- msg('Cannot load Auth Plugin "' . $input . '"', -1);
- return false;
- }
-
- // verify proper instantiation (is this really a plugin?) @TODO use instanceof? implement interface?
- if (is_object($auth_plugin) && !method_exists($auth_plugin, 'getPluginName')) {
- $this->_error = true;
- msg('Cannot create Auth Plugin "' . $input . '"', -1);
- return false;
- }
-
- // did we change the auth type? logout
- global $conf;
- if($conf['authtype'] != $input) {
- msg('Authentication system changed. Please re-login.');
- auth_logoff();
- }
-
- $this->_local = $input;
- return true;
- }
- }
-}
-
-if (!class_exists('setting_im_convert')) {
- /**
- * Class setting_im_convert
- */
- class setting_im_convert extends setting_string {
-
- /**
- * update changed setting with user provided value $input
- * - if changed value fails error check, save it to $this->_input (to allow echoing later)
- * - if changed value passes error check, set $this->_local to the new value
- *
- * @param mixed $input the new value
- * @return boolean true if changed, false otherwise (also on error)
- */
- function update($input) {
- if ($this->is_protected()) return false;
-
- $input = trim($input);
-
- $value = is_null($this->_local) ? $this->_default : $this->_local;
- if ($value == $input) return false;
-
- if ($input && !file_exists($input)) {
- $this->_error = true;
- $this->_input = $input;
- return false;
- }
-
- $this->_local = $input;
- return true;
- }
- }
-}
-
-if (!class_exists('setting_disableactions')) {
- /**
- * Class setting_disableactions
- */
- class setting_disableactions extends setting_multicheckbox {
-
- /**
- * Build html for label and input of setting
- *
- * @param admin_plugin_config $plugin object of config plugin
- * @param bool $echo true: show inputted value, when error occurred, otherwise the stored setting
- * @return array with content array(string $label_html, string $input_html)
- */
- function html(admin_plugin_config $plugin, $echo=false) {
- global $lang;
-
- // make some language adjustments (there must be a better way)
- // transfer some DokuWiki language strings to the plugin
- $plugin->addLang($this->_key.'_revisions', $lang['btn_revs']);
- foreach ($this->_choices as $choice) {
- if (isset($lang['btn_'.$choice])) $plugin->addLang($this->_key.'_'.$choice, $lang['btn_'.$choice]);
- }
-
- return parent::html($plugin, $echo);
- }
- }
-}
-
-if (!class_exists('setting_compression')) {
- /**
- * Class setting_compression
- */
- class setting_compression extends setting_multichoice {
-
- var $_choices = array('0'); // 0 = no compression, always supported
-
- /**
- * Receives current values for the setting $key
- *
- * @param mixed $default default setting value
- * @param mixed $local local setting value
- * @param mixed $protected protected setting value
- */
- function initialize($default,$local,$protected) {
-
- // populate _choices with the compression methods supported by this php installation
- if (function_exists('gzopen')) $this->_choices[] = 'gz';
- if (function_exists('bzopen')) $this->_choices[] = 'bz2';
-
- parent::initialize($default,$local,$protected);
- }
- }
-}
-
-if (!class_exists('setting_license')) {
- /**
- * Class setting_license
- */
- class setting_license extends setting_multichoice {
-
- var $_choices = array(''); // none choosen
-
- /**
- * Receives current values for the setting $key
- *
- * @param mixed $default default setting value
- * @param mixed $local local setting value
- * @param mixed $protected protected setting value
- */
- function initialize($default,$local,$protected) {
- global $license;
-
- foreach($license as $key => $data){
- $this->_choices[] = $key;
- $this->lang[$this->_key.'_o_'.$key] = $data['name']; // stored in setting
- }
-
- parent::initialize($default,$local,$protected);
- }
- }
-}
-
-
-if (!class_exists('setting_renderer')) {
- /**
- * Class setting_renderer
- */
- class setting_renderer extends setting_multichoice {
- var $_prompts = array();
- var $_format = null;
-
- /**
- * Receives current values for the setting $key
- *
- * @param mixed $default default setting value
- * @param mixed $local local setting value
- * @param mixed $protected protected setting value
- */
- function initialize($default,$local,$protected) {
- $format = $this->_format;
-
- foreach (plugin_list('renderer') as $plugin) {
- $renderer = plugin_load('renderer',$plugin);
- if (method_exists($renderer,'canRender') && $renderer->canRender($format)) {
- $this->_choices[] = $plugin;
-
- $info = $renderer->getInfo();
- $this->_prompts[$plugin] = $info['name'];
- }
- }
-
- parent::initialize($default,$local,$protected);
- }
-
- /**
- * Build html for label and input of setting
- *
- * @param admin_plugin_config $plugin object of config plugin
- * @param bool $echo true: show inputted value, when error occurred, otherwise the stored setting
- * @return array with content array(string $label_html, string $input_html)
- */
- function html(admin_plugin_config $plugin, $echo=false) {
-
- // make some language adjustments (there must be a better way)
- // transfer some plugin names to the config plugin
- foreach($this->_choices as $choice) {
- if(!$plugin->getLang($this->_key . '_o_' . $choice)) {
- if(!isset($this->_prompts[$choice])) {
- $plugin->addLang(
- $this->_key . '_o_' . $choice,
- sprintf($plugin->getLang('renderer__core'), $choice)
- );
- } else {
- $plugin->addLang(
- $this->_key . '_o_' . $choice,
- sprintf($plugin->getLang('renderer__plugin'), $this->_prompts[$choice])
- );
- }
- }
- }
- return parent::html($plugin, $echo);
- }
- }
-}
diff --git a/lib/plugins/extension/_test/extension.test.php b/lib/plugins/extension/_test/extension.test.php
index d4f13201d..1f8e2fca7 100644
--- a/lib/plugins/extension/_test/extension.test.php
+++ b/lib/plugins/extension/_test/extension.test.php
@@ -6,8 +6,8 @@
* makes protected methods accessible
*/
class mock_helper_plugin_extension_extension extends helper_plugin_extension_extension {
- public function find_folders(&$result, $base, $default_type = 'plugin', $dir = '') {
- return parent::find_folders($result, $base, $default_type, $dir);
+ public function findFolders(&$result, $base, $default_type = 'plugin', $dir = '') {
+ return parent::findFolders($result, $base, $default_type, $dir);
}
}
@@ -78,7 +78,7 @@ class helper_plugin_extension_extension_test extends DokuWikiTest {
$tdir = dirname(__FILE__).'/testdata';
$result = array('old' => array(), 'new' => array());
- $ok = $extension->find_folders($result, "$tdir/plugin1", 'plugin');
+ $ok = $extension->findFolders($result, "$tdir/plugin1", 'plugin');
$this->assertTrue($ok);
$this->assertEquals(0, count($result['new']));
$this->assertEquals(1, count($result['old']));
@@ -86,7 +86,7 @@ class helper_plugin_extension_extension_test extends DokuWikiTest {
$this->assertEquals('plugin1', $this->extdir($result['old'][0]['tmp']));
$result = array('old' => array(), 'new' => array());
- $ok = $extension->find_folders($result, "$tdir/plugin2", 'plugin');
+ $ok = $extension->findFolders($result, "$tdir/plugin2", 'plugin');
$this->assertTrue($ok);
$this->assertEquals(1, count($result['new']));
$this->assertEquals('plugin', $result['new'][0]['type']);
@@ -94,7 +94,7 @@ class helper_plugin_extension_extension_test extends DokuWikiTest {
$this->assertEquals('plugin2', $this->extdir($result['new'][0]['tmp']));
$result = array('old' => array(), 'new' => array());
- $ok = $extension->find_folders($result, "$tdir/plgsub3", 'plugin');
+ $ok = $extension->findFolders($result, "$tdir/plgsub3", 'plugin');
$this->assertTrue($ok);
$this->assertEquals(0, count($result['new']));
$this->assertEquals(1, count($result['old']));
@@ -102,7 +102,7 @@ class helper_plugin_extension_extension_test extends DokuWikiTest {
$this->assertEquals('plgsub3/plugin3', $this->extdir($result['old'][0]['tmp']));
$result = array('old' => array(), 'new' => array());
- $ok = $extension->find_folders($result, "$tdir/plgsub4", 'plugin');
+ $ok = $extension->findFolders($result, "$tdir/plgsub4", 'plugin');
$this->assertTrue($ok);
$this->assertEquals(1, count($result['new']));
$this->assertEquals('plugin', $result['new'][0]['type']);
@@ -110,7 +110,7 @@ class helper_plugin_extension_extension_test extends DokuWikiTest {
$this->assertEquals('plgsub4/plugin4', $this->extdir($result['new'][0]['tmp']));
$result = array('old' => array(), 'new' => array());
- $ok = $extension->find_folders($result, "$tdir/plgfoo5", 'plugin');
+ $ok = $extension->findFolders($result, "$tdir/plgfoo5", 'plugin');
$this->assertTrue($ok);
$this->assertEquals(1, count($result['new']));
$this->assertEquals('plugin', $result['new'][0]['type']);
@@ -118,7 +118,7 @@ class helper_plugin_extension_extension_test extends DokuWikiTest {
$this->assertEquals('plgfoo5', $this->extdir($result['new'][0]['tmp']));
$result = array('old' => array(), 'new' => array());
- $ok = $extension->find_folders($result, "$tdir/plgsub6/plgfoo6", 'plugin');
+ $ok = $extension->findFolders($result, "$tdir/plgsub6/plgfoo6", 'plugin');
$this->assertTrue($ok);
$this->assertEquals(1, count($result['new']));
$this->assertEquals('plugin', $result['new'][0]['type']);
@@ -126,7 +126,7 @@ class helper_plugin_extension_extension_test extends DokuWikiTest {
$this->assertEquals('plgsub6/plgfoo6', $this->extdir($result['new'][0]['tmp']));
$result = array('old' => array(), 'new' => array());
- $ok = $extension->find_folders($result, "$tdir/either1", 'plugin');
+ $ok = $extension->findFolders($result, "$tdir/either1", 'plugin');
$this->assertTrue($ok);
$this->assertEquals(0, count($result['new']));
$this->assertEquals(1, count($result['old']));
@@ -134,7 +134,7 @@ class helper_plugin_extension_extension_test extends DokuWikiTest {
$this->assertEquals('either1', $this->extdir($result['old'][0]['tmp']));
$result = array('old' => array(), 'new' => array());
- $ok = $extension->find_folders($result, "$tdir/eithersub2/either2", 'plugin');
+ $ok = $extension->findFolders($result, "$tdir/eithersub2/either2", 'plugin');
$this->assertTrue($ok);
$this->assertEquals(0, count($result['new']));
$this->assertEquals(1, count($result['old']));
@@ -147,7 +147,7 @@ class helper_plugin_extension_extension_test extends DokuWikiTest {
$tdir = dirname(__FILE__).'/testdata';
$result = array('old' => array(), 'new' => array());
- $ok = $extension->find_folders($result, "$tdir/template1", 'template');
+ $ok = $extension->findFolders($result, "$tdir/template1", 'template');
$this->assertTrue($ok);
$this->assertEquals(0, count($result['new']));
$this->assertEquals(1, count($result['old']));
@@ -155,7 +155,7 @@ class helper_plugin_extension_extension_test extends DokuWikiTest {
$this->assertEquals('template1', $this->extdir($result['old'][0]['tmp']));
$result = array('old' => array(), 'new' => array());
- $ok = $extension->find_folders($result, "$tdir/template2", 'template');
+ $ok = $extension->findFolders($result, "$tdir/template2", 'template');
$this->assertTrue($ok);
$this->assertEquals(1, count($result['new']));
$this->assertEquals('template', $result['new'][0]['type']);
@@ -163,7 +163,7 @@ class helper_plugin_extension_extension_test extends DokuWikiTest {
$this->assertEquals('template2', $this->extdir($result['new'][0]['tmp']));
$result = array('old' => array(), 'new' => array());
- $ok = $extension->find_folders($result, "$tdir/tplsub3", 'template');
+ $ok = $extension->findFolders($result, "$tdir/tplsub3", 'template');
$this->assertTrue($ok);
$this->assertEquals(0, count($result['new']));
$this->assertEquals(1, count($result['old']));
@@ -171,7 +171,7 @@ class helper_plugin_extension_extension_test extends DokuWikiTest {
$this->assertEquals('tplsub3/template3', $this->extdir($result['old'][0]['tmp']));
$result = array('old' => array(), 'new' => array());
- $ok = $extension->find_folders($result, "$tdir/tplsub4", 'template');
+ $ok = $extension->findFolders($result, "$tdir/tplsub4", 'template');
$this->assertTrue($ok);
$this->assertEquals(1, count($result['new']));
$this->assertEquals('template', $result['new'][0]['type']);
@@ -179,7 +179,7 @@ class helper_plugin_extension_extension_test extends DokuWikiTest {
$this->assertEquals('tplsub4/template4', $this->extdir($result['new'][0]['tmp']));
$result = array('old' => array(), 'new' => array());
- $ok = $extension->find_folders($result, "$tdir/tplfoo5", 'template');
+ $ok = $extension->findFolders($result, "$tdir/tplfoo5", 'template');
$this->assertTrue($ok);
$this->assertEquals(1, count($result['new']));
$this->assertEquals('template', $result['new'][0]['type']);
@@ -187,7 +187,7 @@ class helper_plugin_extension_extension_test extends DokuWikiTest {
$this->assertEquals('tplfoo5', $this->extdir($result['new'][0]['tmp']));
$result = array('old' => array(), 'new' => array());
- $ok = $extension->find_folders($result, "$tdir/tplsub6/tplfoo6", 'template');
+ $ok = $extension->findFolders($result, "$tdir/tplsub6/tplfoo6", 'template');
$this->assertTrue($ok);
$this->assertEquals(1, count($result['new']));
$this->assertEquals('template', $result['new'][0]['type']);
@@ -195,7 +195,7 @@ class helper_plugin_extension_extension_test extends DokuWikiTest {
$this->assertEquals('tplsub6/tplfoo6', $this->extdir($result['new'][0]['tmp']));
$result = array('old' => array(), 'new' => array());
- $ok = $extension->find_folders($result, "$tdir/either1", 'template');
+ $ok = $extension->findFolders($result, "$tdir/either1", 'template');
$this->assertTrue($ok);
$this->assertEquals(0, count($result['new']));
$this->assertEquals(1, count($result['old']));
@@ -203,7 +203,7 @@ class helper_plugin_extension_extension_test extends DokuWikiTest {
$this->assertEquals('either1', $this->extdir($result['old'][0]['tmp']));
$result = array('old' => array(), 'new' => array());
- $ok = $extension->find_folders($result, "$tdir/eithersub2/either2", 'template');
+ $ok = $extension->findFolders($result, "$tdir/eithersub2/either2", 'template');
$this->assertTrue($ok);
$this->assertEquals(0, count($result['new']));
$this->assertEquals(1, count($result['old']));
@@ -216,7 +216,7 @@ class helper_plugin_extension_extension_test extends DokuWikiTest {
$tdir = dirname(__FILE__).'/testdata';
$result = array('old' => array(), 'new' => array());
- $ok = $extension->find_folders($result, "$tdir/template1");
+ $ok = $extension->findFolders($result, "$tdir/template1");
$this->assertTrue($ok);
$this->assertEquals(0, count($result['new']));
$this->assertEquals(1, count($result['old']));
@@ -224,7 +224,7 @@ class helper_plugin_extension_extension_test extends DokuWikiTest {
$this->assertEquals('template1', $this->extdir($result['old'][0]['tmp']));
$result = array('old' => array(), 'new' => array());
- $ok = $extension->find_folders($result, "$tdir/template2");
+ $ok = $extension->findFolders($result, "$tdir/template2");
$this->assertTrue($ok);
$this->assertEquals(1, count($result['new']));
$this->assertEquals('template', $result['new'][0]['type']);
@@ -232,7 +232,7 @@ class helper_plugin_extension_extension_test extends DokuWikiTest {
$this->assertEquals('template2', $this->extdir($result['new'][0]['tmp']));
$result = array('old' => array(), 'new' => array());
- $ok = $extension->find_folders($result, "$tdir/tplsub3");
+ $ok = $extension->findFolders($result, "$tdir/tplsub3");
$this->assertTrue($ok);
$this->assertEquals(0, count($result['new']));
$this->assertEquals(1, count($result['old']));
@@ -240,7 +240,7 @@ class helper_plugin_extension_extension_test extends DokuWikiTest {
$this->assertEquals('tplsub3/template3', $this->extdir($result['old'][0]['tmp']));
$result = array('old' => array(), 'new' => array());
- $ok = $extension->find_folders($result, "$tdir/tplsub4");
+ $ok = $extension->findFolders($result, "$tdir/tplsub4");
$this->assertTrue($ok);
$this->assertEquals(1, count($result['new']));
$this->assertEquals('template', $result['new'][0]['type']);
@@ -248,7 +248,7 @@ class helper_plugin_extension_extension_test extends DokuWikiTest {
$this->assertEquals('tplsub4/template4', $this->extdir($result['new'][0]['tmp']));
$result = array('old' => array(), 'new' => array());
- $ok = $extension->find_folders($result, "$tdir/tplfoo5");
+ $ok = $extension->findFolders($result, "$tdir/tplfoo5");
$this->assertTrue($ok);
$this->assertEquals(1, count($result['new']));
$this->assertEquals('template', $result['new'][0]['type']);
@@ -256,7 +256,7 @@ class helper_plugin_extension_extension_test extends DokuWikiTest {
$this->assertEquals('tplfoo5', $this->extdir($result['new'][0]['tmp']));
$result = array('old' => array(), 'new' => array());
- $ok = $extension->find_folders($result, "$tdir/tplsub6/tplfoo6");
+ $ok = $extension->findFolders($result, "$tdir/tplsub6/tplfoo6");
$this->assertTrue($ok);
$this->assertEquals(1, count($result['new']));
$this->assertEquals('template', $result['new'][0]['type']);
@@ -264,7 +264,7 @@ class helper_plugin_extension_extension_test extends DokuWikiTest {
$this->assertEquals('tplsub6/tplfoo6', $this->extdir($result['new'][0]['tmp']));
$result = array('old' => array(), 'new' => array());
- $ok = $extension->find_folders($result, "$tdir/either1");
+ $ok = $extension->findFolders($result, "$tdir/either1");
$this->assertTrue($ok);
$this->assertEquals(0, count($result['new']));
$this->assertEquals(1, count($result['old']));
@@ -272,7 +272,7 @@ class helper_plugin_extension_extension_test extends DokuWikiTest {
$this->assertEquals('either1', $this->extdir($result['old'][0]['tmp']));
$result = array('old' => array(), 'new' => array());
- $ok = $extension->find_folders($result, "$tdir/eithersub2/either2");
+ $ok = $extension->findFolders($result, "$tdir/eithersub2/either2");
$this->assertTrue($ok);
$this->assertEquals(0, count($result['new']));
$this->assertEquals(1, count($result['old']));
@@ -292,4 +292,4 @@ class helper_plugin_extension_extension_test extends DokuWikiTest {
$dir = trim(substr($dir, $len), '/');
return $dir;
}
-} \ No newline at end of file
+}
diff --git a/lib/plugins/extension/action.php b/lib/plugins/extension/action.php
index 4af84f8df..3255f24b0 100644
--- a/lib/plugins/extension/action.php
+++ b/lib/plugins/extension/action.php
@@ -5,10 +5,8 @@
* @author Andreas Gohr <andi@splitbrain.org>
*/
-// must be run within Dokuwiki
-if(!defined('DOKU_INC')) die();
-
-class action_plugin_extension extends DokuWiki_Action_Plugin {
+class action_plugin_extension extends DokuWiki_Action_Plugin
+{
/**
* Registers a callback function for a given event
@@ -16,10 +14,10 @@ class action_plugin_extension extends DokuWiki_Action_Plugin {
* @param Doku_Event_Handler $controller DokuWiki's event controller object
* @return void
*/
- public function register(Doku_Event_Handler $controller) {
+ public function register(Doku_Event_Handler $controller)
+ {
$controller->register_hook('AJAX_CALL_UNKNOWN', 'BEFORE', $this, 'info');
-
}
/**
@@ -28,24 +26,25 @@ class action_plugin_extension extends DokuWiki_Action_Plugin {
* @param Doku_Event $event
* @param $param
*/
- public function info(Doku_Event &$event, $param) {
+ public function info(Doku_Event &$event, $param)
+ {
global $USERINFO;
global $INPUT;
- if($event->data != 'plugin_extension') return;
+ if ($event->data != 'plugin_extension') return;
$event->preventDefault();
$event->stopPropagation();
/** @var admin_plugin_extension $admin */
$admin = plugin_load('admin', 'extension');
- if(!$admin->isAccessibleByCurrentUser()) {
+ if (!$admin->isAccessibleByCurrentUser()) {
http_status(403);
echo 'Forbidden';
exit;
}
$ext = $INPUT->str('ext');
- if(!$ext) {
+ if (!$ext) {
http_status(400);
echo 'no extension given';
return;
@@ -56,10 +55,9 @@ class action_plugin_extension extends DokuWiki_Action_Plugin {
$extension->setExtension($ext);
$act = $INPUT->str('act');
- switch($act) {
+ switch ($act) {
case 'enable':
case 'disable':
- $json = new JSON();
$extension->$act(); //enables/disables
$reverse = ($act == 'disable') ? 'enable' : 'disable';
@@ -71,7 +69,7 @@ class action_plugin_extension extends DokuWiki_Action_Plugin {
);
header('Content-Type: application/json');
- echo $json->encode($return);
+ json_encode($return);
break;
case 'info':
@@ -79,9 +77,7 @@ class action_plugin_extension extends DokuWiki_Action_Plugin {
/** @var helper_plugin_extension_list $list */
$list = plugin_load('helper', 'extension_list');
header('Content-Type: text/html; charset=utf-8');
- echo $list->make_info($extension);
+ echo $list->makeInfo($extension);
}
}
-
}
-
diff --git a/lib/plugins/extension/admin.php b/lib/plugins/extension/admin.php
index 1f1d4b513..421b7138f 100644
--- a/lib/plugins/extension/admin.php
+++ b/lib/plugins/extension/admin.php
@@ -6,13 +6,11 @@
* @author Michael Hamann <michael@content-space.de>
*/
-// must be run within Dokuwiki
-if(!defined('DOKU_INC')) die();
-
/**
* Admin part of the extension manager
*/
-class admin_plugin_extension extends DokuWiki_Admin_Plugin {
+class admin_plugin_extension extends DokuWiki_Admin_Plugin
+{
protected $infoFor = null;
/** @var helper_plugin_extension_gui */
protected $gui;
@@ -22,28 +20,32 @@ class admin_plugin_extension extends DokuWiki_Admin_Plugin {
*
* loads additional helpers
*/
- public function __construct() {
+ public function __construct()
+ {
$this->gui = plugin_load('helper', 'extension_gui');
}
/**
* @return int sort number in admin menu
*/
- public function getMenuSort() {
+ public function getMenuSort()
+ {
return 0;
}
/**
* @return bool true if only access for superuser, false is for superusers and moderators
*/
- public function forAdminOnly() {
+ public function forAdminOnly()
+ {
return true;
}
/**
* Execute the requested action(s) and initialize the plugin repository
*/
- public function handle() {
+ public function handle()
+ {
global $INPUT;
// initialize the remote repository
/* @var helper_plugin_extension_repository $repository */
@@ -54,7 +56,7 @@ class admin_plugin_extension extends DokuWiki_Admin_Plugin {
msg($this->getLang('repo_error').' [<a href="'.$url.'">'.$this->getLang('repo_retry').'</a>]', -1);
}
- if(!in_array('ssl', stream_get_transports())) {
+ if (!in_array('ssl', stream_get_transports())) {
msg($this->getLang('nossl'), -1);
}
@@ -62,42 +64,60 @@ class admin_plugin_extension extends DokuWiki_Admin_Plugin {
$extension = $this->loadHelper('extension_extension');
try {
- if($INPUT->post->has('fn') && checkSecurityToken()) {
+ if ($INPUT->post->has('fn') && checkSecurityToken()) {
$actions = $INPUT->post->arr('fn');
- foreach($actions as $action => $extensions) {
- foreach($extensions as $extname => $label) {
- switch($action) {
+ foreach ($actions as $action => $extensions) {
+ foreach ($extensions as $extname => $label) {
+ switch ($action) {
case 'install':
case 'reinstall':
case 'update':
$extension->setExtension($extname);
$installed = $extension->installOrUpdate();
- foreach($installed as $ext => $info) {
- msg(sprintf($this->getLang('msg_'.$info['type'].'_'.$info['action'].'_success'), $info['base']), 1);
+ foreach ($installed as $ext => $info) {
+ msg(
+ sprintf(
+ $this->getLang('msg_' . $info['type'] . '_' . $info['action'] . '_success'),
+ $info['base']
+ ),
+ 1
+ );
}
break;
case 'uninstall':
$extension->setExtension($extname);
$status = $extension->uninstall();
- if($status) {
- msg(sprintf($this->getLang('msg_delete_success'), hsc($extension->getDisplayName())), 1);
+ if ($status) {
+ msg(
+ sprintf(
+ $this->getLang('msg_delete_success'),
+ hsc($extension->getDisplayName())
+ ),
+ 1
+ );
} else {
- msg(sprintf($this->getLang('msg_delete_failed'), hsc($extension->getDisplayName())), -1);
+ msg(
+ sprintf(
+ $this->getLang('msg_delete_failed'),
+ hsc($extension->getDisplayName())
+ ),
+ -1
+ );
}
break;
- case 'enable';
+ case 'enable':
$extension->setExtension($extname);
$status = $extension->enable();
- if($status !== true) {
+ if ($status !== true) {
msg($status, -1);
} else {
msg(sprintf($this->getLang('msg_enabled'), hsc($extension->getDisplayName())), 1);
}
break;
- case 'disable';
+ case 'disable':
$extension->setExtension($extname);
$status = $extension->disable();
- if($status !== true) {
+ if ($status !== true) {
msg($status, -1);
} else {
msg(sprintf($this->getLang('msg_disabled'), hsc($extension->getDisplayName())), 1);
@@ -107,37 +127,36 @@ class admin_plugin_extension extends DokuWiki_Admin_Plugin {
}
}
send_redirect($this->gui->tabURL('', array(), '&', true));
- } elseif($INPUT->post->str('installurl') && checkSecurityToken()) {
+ } elseif ($INPUT->post->str('installurl') && checkSecurityToken()) {
$installed = $extension->installFromURL($INPUT->post->str('installurl'));
- foreach($installed as $ext => $info) {
+ foreach ($installed as $ext => $info) {
msg(sprintf($this->getLang('msg_'.$info['type'].'_'.$info['action'].'_success'), $info['base']), 1);
}
send_redirect($this->gui->tabURL('', array(), '&', true));
- } elseif(isset($_FILES['installfile']) && checkSecurityToken()) {
+ } elseif (isset($_FILES['installfile']) && checkSecurityToken()) {
$installed = $extension->installFromUpload('installfile');
- foreach($installed as $ext => $info) {
+ foreach ($installed as $ext => $info) {
msg(sprintf($this->getLang('msg_'.$info['type'].'_'.$info['action'].'_success'), $info['base']), 1);
}
send_redirect($this->gui->tabURL('', array(), '&', true));
}
-
- } catch(Exception $e) {
+ } catch (Exception $e) {
msg($e->getMessage(), -1);
send_redirect($this->gui->tabURL('', array(), '&', true));
}
-
}
/**
* Render HTML output
*/
- public function html() {
+ public function html()
+ {
ptln('<h1>'.$this->getLang('menu').'</h1>');
ptln('<div id="extension__manager">');
$this->gui->tabNavigation();
- switch($this->gui->currentTab()) {
+ switch ($this->gui->currentTab()) {
case 'search':
$this->gui->tabSearch();
break;
diff --git a/lib/plugins/extension/helper/extension.php b/lib/plugins/extension/helper/extension.php
index 7266ed8e6..0186620d0 100644
--- a/lib/plugins/extension/helper/extension.php
+++ b/lib/plugins/extension/helper/extension.php
@@ -6,14 +6,14 @@
* @author Michael Hamann <michael@content-space.de>
*/
-// must be run within Dokuwiki
-if(!defined('DOKU_INC')) die();
-if(!defined('DOKU_TPLLIB')) define('DOKU_TPLLIB', DOKU_INC.'lib/tpl/');
+use dokuwiki\HTTP\DokuHTTPClient;
+use dokuwiki\Extension\PluginController;
/**
* Class helper_plugin_extension_extension represents a single extension (plugin or template)
*/
-class helper_plugin_extension_extension extends DokuWiki_Plugin {
+class helper_plugin_extension_extension extends DokuWiki_Plugin
+{
private $id;
private $base;
private $is_template = false;
@@ -26,13 +26,25 @@ class helper_plugin_extension_extension extends DokuWiki_Plugin {
/** @var array list of temporary directories */
private $temporary = array();
+ /** @var string where templates are installed to */
+ private $tpllib = '';
+
+ /**
+ * helper_plugin_extension_extension constructor.
+ */
+ public function __construct()
+ {
+ $this->tpllib = dirname(tpl_incdir()).'/';
+ }
+
/**
* Destructor
*
* deletes any dangling temporary directories
*/
- public function __destruct() {
- foreach($this->temporary as $dir){
+ public function __destruct()
+ {
+ foreach ($this->temporary as $dir) {
io_rmdir($dir, true);
}
}
@@ -40,7 +52,8 @@ class helper_plugin_extension_extension extends DokuWiki_Plugin {
/**
* @return bool false, this component is not a singleton
*/
- public function isSingleton() {
+ public function isSingleton()
+ {
return false;
}
@@ -50,12 +63,13 @@ class helper_plugin_extension_extension extends DokuWiki_Plugin {
* @param string $id The id of the extension (prefixed with template: for templates)
* @return bool If some (local or remote) data was found
*/
- public function setExtension($id) {
+ public function setExtension($id)
+ {
$id = cleanID($id);
$this->id = $id;
$this->base = $id;
- if(substr($id, 0 , 9) == 'template:'){
+ if (substr($id, 0, 9) == 'template:') {
$this->base = substr($id, 9);
$this->is_template = true;
} else {
@@ -85,7 +99,8 @@ class helper_plugin_extension_extension extends DokuWiki_Plugin {
*
* @return bool If the extension is installed locally
*/
- public function isInstalled() {
+ public function isInstalled()
+ {
return is_dir($this->getInstallDir());
}
@@ -94,8 +109,9 @@ class helper_plugin_extension_extension extends DokuWiki_Plugin {
*
* @return bool
*/
- public function isGitControlled() {
- if(!$this->isInstalled()) return false;
+ public function isGitControlled()
+ {
+ if (!$this->isInstalled()) return false;
return is_dir($this->getInstallDir().'/.git');
}
@@ -104,12 +120,16 @@ class helper_plugin_extension_extension extends DokuWiki_Plugin {
*
* @return bool If the extension is bundled
*/
- public function isBundled() {
+ public function isBundled()
+ {
if (!empty($this->remoteInfo['bundled'])) return $this->remoteInfo['bundled'];
- return in_array($this->id,
- array(
- 'authad', 'authldap', 'authmysql', 'authpdo', 'authpgsql', 'authplain', 'acl', 'info', 'extension',
- 'revert', 'popularity', 'config', 'safefnrecode', 'styling', 'testing', 'template:dokuwiki'
+ return in_array(
+ $this->id,
+ array(
+ 'authad', 'authldap', 'authmysql', 'authpdo',
+ 'authpgsql', 'authplain', 'acl', 'info', 'extension',
+ 'revert', 'popularity', 'config', 'safefnrecode', 'styling',
+ 'testing', 'template:dokuwiki'
)
);
}
@@ -119,12 +139,13 @@ class helper_plugin_extension_extension extends DokuWiki_Plugin {
*
* @return bool if the extension is protected
*/
- public function isProtected() {
+ public function isProtected()
+ {
// never allow deinstalling the current auth plugin:
global $conf;
if ($this->id == $conf['authtype']) return true;
- /** @var Doku_Plugin_Controller $plugin_controller */
+ /** @var PluginController $plugin_controller */
global $plugin_controller;
$cascade = $plugin_controller->getCascade();
return (isset($cascade['protected'][$this->id]) && $cascade['protected'][$this->id]);
@@ -135,7 +156,8 @@ class helper_plugin_extension_extension extends DokuWiki_Plugin {
*
* @return bool If the extension is installed in the correct directory
*/
- public function isInWrongFolder() {
+ public function isInWrongFolder()
+ {
return $this->base != $this->getBase();
}
@@ -144,13 +166,14 @@ class helper_plugin_extension_extension extends DokuWiki_Plugin {
*
* @return bool If the extension is enabled
*/
- public function isEnabled() {
+ public function isEnabled()
+ {
global $conf;
- if($this->isTemplate()){
+ if ($this->isTemplate()) {
return ($conf['template'] == $this->getBase());
}
- /* @var Doku_Plugin_Controller $plugin_controller */
+ /* @var PluginController $plugin_controller */
global $plugin_controller;
return !$plugin_controller->isdisabled($this->base);
}
@@ -160,9 +183,10 @@ class helper_plugin_extension_extension extends DokuWiki_Plugin {
*
* @return bool If an update is available
*/
- public function updateAvailable() {
- if(!$this->isInstalled()) return false;
- if($this->isBundled()) return false;
+ public function updateAvailable()
+ {
+ if (!$this->isInstalled()) return false;
+ if ($this->isBundled()) return false;
$lastupdate = $this->getLastUpdate();
if ($lastupdate === false) return false;
$installed = $this->getInstalledVersion();
@@ -175,7 +199,8 @@ class helper_plugin_extension_extension extends DokuWiki_Plugin {
*
* @return bool If this extension is a template
*/
- public function isTemplate() {
+ public function isTemplate()
+ {
return $this->is_template;
}
@@ -186,7 +211,8 @@ class helper_plugin_extension_extension extends DokuWiki_Plugin {
*
* @return string
*/
- public function getID() {
+ public function getID()
+ {
return $this->id;
}
@@ -195,7 +221,8 @@ class helper_plugin_extension_extension extends DokuWiki_Plugin {
*
* @return string The name of the installation directory
*/
- public function getInstallName() {
+ public function getInstallName()
+ {
return $this->base;
}
@@ -205,7 +232,8 @@ class helper_plugin_extension_extension extends DokuWiki_Plugin {
*
* @return string The basename
*/
- public function getBase() {
+ public function getBase()
+ {
if (!empty($this->localInfo['base'])) return $this->localInfo['base'];
return $this->base;
}
@@ -215,7 +243,8 @@ class helper_plugin_extension_extension extends DokuWiki_Plugin {
*
* @return string The display name
*/
- public function getDisplayName() {
+ public function getDisplayName()
+ {
if (!empty($this->localInfo['name'])) return $this->localInfo['name'];
if (!empty($this->remoteInfo['name'])) return $this->remoteInfo['name'];
return $this->base;
@@ -226,7 +255,8 @@ class helper_plugin_extension_extension extends DokuWiki_Plugin {
*
* @return string|bool The name of the author or false if there is none
*/
- public function getAuthor() {
+ public function getAuthor()
+ {
if (!empty($this->localInfo['author'])) return $this->localInfo['author'];
if (!empty($this->remoteInfo['author'])) return $this->remoteInfo['author'];
return false;
@@ -237,7 +267,8 @@ class helper_plugin_extension_extension extends DokuWiki_Plugin {
*
* @return string|bool The email address or false if there is none
*/
- public function getEmail() {
+ public function getEmail()
+ {
// email is only in the local data
if (!empty($this->localInfo['email'])) return $this->localInfo['email'];
return false;
@@ -248,7 +279,8 @@ class helper_plugin_extension_extension extends DokuWiki_Plugin {
*
* @return string|bool The md5sum of the email if there is any, false otherwise
*/
- public function getEmailID() {
+ public function getEmailID()
+ {
if (!empty($this->remoteInfo['emailid'])) return $this->remoteInfo['emailid'];
if (!empty($this->localInfo['email'])) return md5($this->localInfo['email']);
return false;
@@ -259,7 +291,8 @@ class helper_plugin_extension_extension extends DokuWiki_Plugin {
*
* @return string The description
*/
- public function getDescription() {
+ public function getDescription()
+ {
if (!empty($this->localInfo['desc'])) return $this->localInfo['desc'];
if (!empty($this->remoteInfo['description'])) return $this->remoteInfo['description'];
return '';
@@ -270,7 +303,8 @@ class helper_plugin_extension_extension extends DokuWiki_Plugin {
*
* @return string The URL
*/
- public function getURL() {
+ public function getURL()
+ {
if (!empty($this->localInfo['url'])) return $this->localInfo['url'];
return 'https://www.dokuwiki.org/'.($this->isTemplate() ? 'template' : 'plugin').':'.$this->getBase();
}
@@ -280,7 +314,8 @@ class helper_plugin_extension_extension extends DokuWiki_Plugin {
*
* @return string|bool The version, usually in the form yyyy-mm-dd if there is any
*/
- public function getInstalledVersion() {
+ public function getInstalledVersion()
+ {
if (!empty($this->localInfo['date'])) return $this->localInfo['date'];
if ($this->isInstalled()) return $this->getLang('unknownversion');
return false;
@@ -291,7 +326,8 @@ class helper_plugin_extension_extension extends DokuWiki_Plugin {
*
* @return string|bool The date of the last update or false if not available
*/
- public function getUpdateDate() {
+ public function getUpdateDate()
+ {
if (!empty($this->managerData['updated'])) return $this->managerData['updated'];
return $this->getInstallDate();
}
@@ -301,7 +337,8 @@ class helper_plugin_extension_extension extends DokuWiki_Plugin {
*
* @return string|bool The date of the installation or false if not available
*/
- public function getInstallDate() {
+ public function getInstallDate()
+ {
if (!empty($this->managerData['installed'])) return $this->managerData['installed'];
return false;
}
@@ -311,7 +348,8 @@ class helper_plugin_extension_extension extends DokuWiki_Plugin {
*
* @return array The base names of the dependencies
*/
- public function getDependencies() {
+ public function getDependencies()
+ {
if (!empty($this->remoteInfo['dependencies'])) return $this->remoteInfo['dependencies'];
return array();
}
@@ -321,8 +359,9 @@ class helper_plugin_extension_extension extends DokuWiki_Plugin {
*
* @return array The base names of the missing dependencies
*/
- public function getMissingDependencies() {
- /* @var Doku_Plugin_Controller $plugin_controller */
+ public function getMissingDependencies()
+ {
+ /* @var PluginController $plugin_controller */
global $plugin_controller;
$dependencies = $this->getDependencies();
$missing_dependencies = array();
@@ -339,7 +378,8 @@ class helper_plugin_extension_extension extends DokuWiki_Plugin {
*
* @return array The names of the conflicting extensions
*/
- public function getConflicts() {
+ public function getConflicts()
+ {
if (!empty($this->remoteInfo['conflicts'])) return $this->remoteInfo['conflicts'];
return array();
}
@@ -349,7 +389,8 @@ class helper_plugin_extension_extension extends DokuWiki_Plugin {
*
* @return array The names of similar extensions
*/
- public function getSimilarExtensions() {
+ public function getSimilarExtensions()
+ {
if (!empty($this->remoteInfo['similar'])) return $this->remoteInfo['similar'];
return array();
}
@@ -359,7 +400,8 @@ class helper_plugin_extension_extension extends DokuWiki_Plugin {
*
* @return array The names of the tags of the extension
*/
- public function getTags() {
+ public function getTags()
+ {
if (!empty($this->remoteInfo['tags'])) return $this->remoteInfo['tags'];
return array();
}
@@ -369,7 +411,8 @@ class helper_plugin_extension_extension extends DokuWiki_Plugin {
*
* @return float|bool The popularity information or false if it isn't available
*/
- public function getPopularity() {
+ public function getPopularity()
+ {
if (!empty($this->remoteInfo['popularity'])) return $this->remoteInfo['popularity'];
return false;
}
@@ -380,7 +423,8 @@ class helper_plugin_extension_extension extends DokuWiki_Plugin {
*
* @return string|bool The security warning if there is any, false otherwise
*/
- public function getSecurityWarning() {
+ public function getSecurityWarning()
+ {
if (!empty($this->remoteInfo['securitywarning'])) return $this->remoteInfo['securitywarning'];
return false;
}
@@ -390,7 +434,8 @@ class helper_plugin_extension_extension extends DokuWiki_Plugin {
*
* @return string|bool The security issue if there is any, false otherwise
*/
- public function getSecurityIssue() {
+ public function getSecurityIssue()
+ {
if (!empty($this->remoteInfo['securityissue'])) return $this->remoteInfo['securityissue'];
return false;
}
@@ -400,7 +445,8 @@ class helper_plugin_extension_extension extends DokuWiki_Plugin {
*
* @return string|bool The screenshot URL if there is any, false otherwise
*/
- public function getScreenshotURL() {
+ public function getScreenshotURL()
+ {
if (!empty($this->remoteInfo['screenshoturl'])) return $this->remoteInfo['screenshoturl'];
return false;
}
@@ -410,7 +456,8 @@ class helper_plugin_extension_extension extends DokuWiki_Plugin {
*
* @return string|bool The thumbnail URL if there is any, false otherwise
*/
- public function getThumbnailURL() {
+ public function getThumbnailURL()
+ {
if (!empty($this->remoteInfo['thumbnailurl'])) return $this->remoteInfo['thumbnailurl'];
return false;
}
@@ -419,7 +466,8 @@ class helper_plugin_extension_extension extends DokuWiki_Plugin {
*
* @return string|bool The previously used download URL, false if the extension has been installed manually
*/
- public function getLastDownloadURL() {
+ public function getLastDownloadURL()
+ {
if (!empty($this->managerData['downloadurl'])) return $this->managerData['downloadurl'];
return false;
}
@@ -429,7 +477,8 @@ class helper_plugin_extension_extension extends DokuWiki_Plugin {
*
* @return string|bool The download URL if there is any, false otherwise
*/
- public function getDownloadURL() {
+ public function getDownloadURL()
+ {
if (!empty($this->remoteInfo['downloadurl'])) return $this->remoteInfo['downloadurl'];
return false;
}
@@ -439,7 +488,8 @@ class helper_plugin_extension_extension extends DokuWiki_Plugin {
*
* @return bool If the download URL has changed
*/
- public function hasDownloadURLChanged() {
+ public function hasDownloadURLChanged()
+ {
$lasturl = $this->getLastDownloadURL();
$currenturl = $this->getDownloadURL();
return ($lasturl && $currenturl && $lasturl != $currenturl);
@@ -450,7 +500,8 @@ class helper_plugin_extension_extension extends DokuWiki_Plugin {
*
* @return string|bool The bug tracker URL if there is any, false otherwise
*/
- public function getBugtrackerURL() {
+ public function getBugtrackerURL()
+ {
if (!empty($this->remoteInfo['bugtracker'])) return $this->remoteInfo['bugtracker'];
return false;
}
@@ -460,7 +511,8 @@ class helper_plugin_extension_extension extends DokuWiki_Plugin {
*
* @return string|bool The URL of the source repository if there is any, false otherwise
*/
- public function getSourcerepoURL() {
+ public function getSourcerepoURL()
+ {
if (!empty($this->remoteInfo['sourcerepo'])) return $this->remoteInfo['sourcerepo'];
return false;
}
@@ -470,7 +522,8 @@ class helper_plugin_extension_extension extends DokuWiki_Plugin {
*
* @return string|bool The donation URL if there is any, false otherwise
*/
- public function getDonationURL() {
+ public function getDonationURL()
+ {
if (!empty($this->remoteInfo['donationurl'])) return $this->remoteInfo['donationurl'];
return false;
}
@@ -480,7 +533,8 @@ class helper_plugin_extension_extension extends DokuWiki_Plugin {
*
* @return array The type(s) as array of strings
*/
- public function getTypes() {
+ public function getTypes()
+ {
if (!empty($this->remoteInfo['types'])) return $this->remoteInfo['types'];
if ($this->isTemplate()) return array(32 => 'template');
return array();
@@ -491,7 +545,8 @@ class helper_plugin_extension_extension extends DokuWiki_Plugin {
*
* @return array The versions in the form yyyy-mm-dd => ('label' => label, 'implicit' => implicit)
*/
- public function getCompatibleVersions() {
+ public function getCompatibleVersions()
+ {
if (!empty($this->remoteInfo['compatible'])) return $this->remoteInfo['compatible'];
return array();
}
@@ -501,7 +556,8 @@ class helper_plugin_extension_extension extends DokuWiki_Plugin {
*
* @return string|bool The last available update in the form yyyy-mm-dd if there is any, false otherwise
*/
- public function getLastUpdate() {
+ public function getLastUpdate()
+ {
if (!empty($this->remoteInfo['lastupdate'])) return $this->remoteInfo['lastupdate'];
return false;
}
@@ -511,9 +567,10 @@ class helper_plugin_extension_extension extends DokuWiki_Plugin {
*
* @return string The base path of the extension
*/
- public function getInstallDir() {
+ public function getInstallDir()
+ {
if ($this->isTemplate()) {
- return DOKU_TPLLIB.$this->base;
+ return $this->tpllib.$this->base;
} else {
return DOKU_PLUGIN.$this->base;
}
@@ -524,7 +581,8 @@ class helper_plugin_extension_extension extends DokuWiki_Plugin {
*
* @return string One of "none", "manual", "git" or "automatic"
*/
- public function getInstallType() {
+ public function getInstallType()
+ {
if (!$this->isInstalled()) return 'none';
if (!empty($this->managerData)) return 'automatic';
if (is_dir($this->getInstallDir().'/.git')) return 'git';
@@ -536,17 +594,17 @@ class helper_plugin_extension_extension extends DokuWiki_Plugin {
*
* @return bool|string True or error string
*/
- public function canModify() {
- if($this->isInstalled()) {
- if(!is_writable($this->getInstallDir())) {
+ public function canModify()
+ {
+ if ($this->isInstalled()) {
+ if (!is_writable($this->getInstallDir())) {
return 'noperms';
}
}
- if($this->isTemplate() && !is_writable(DOKU_TPLLIB)) {
+ if ($this->isTemplate() && !is_writable($this->tpllib)) {
return 'notplperms';
-
- } elseif(!is_writable(DOKU_PLUGIN)) {
+ } elseif (!is_writable(DOKU_PLUGIN)) {
return 'nopluginperms';
}
return true;
@@ -559,20 +617,21 @@ class helper_plugin_extension_extension extends DokuWiki_Plugin {
* @throws Exception when something goes wrong
* @return array The list of installed extensions
*/
- public function installFromUpload($field){
- if($_FILES[$field]['error']){
+ public function installFromUpload($field)
+ {
+ if ($_FILES[$field]['error']) {
throw new Exception($this->getLang('msg_upload_failed').' ('.$_FILES[$field]['error'].')');
}
$tmp = $this->mkTmpDir();
- if(!$tmp) throw new Exception($this->getLang('error_dircreate'));
+ if (!$tmp) throw new Exception($this->getLang('error_dircreate'));
// filename may contain the plugin name for old style plugins...
$basename = basename($_FILES[$field]['name']);
$basename = preg_replace('/\.(tar\.gz|tar\.bz|tar\.bz2|tar|tgz|tbz|zip)$/', '', $basename);
$basename = preg_replace('/[\W]+/', '', $basename);
- if(!move_uploaded_file($_FILES[$field]['tmp_name'], "$tmp/upload.archive")){
+ if (!move_uploaded_file($_FILES[$field]['tmp_name'], "$tmp/upload.archive")) {
throw new Exception($this->getLang('msg_upload_failed'));
}
@@ -582,7 +641,7 @@ class helper_plugin_extension_extension extends DokuWiki_Plugin {
$this->removeDeletedfiles($installed);
// purge cache
$this->purgeCache();
- }catch (Exception $e){
+ } catch (Exception $e) {
throw $e;
}
return $installed;
@@ -595,7 +654,8 @@ class helper_plugin_extension_extension extends DokuWiki_Plugin {
* @throws Exception when something goes wrong
* @return array The list of installed extensions
*/
- public function installFromURL($url){
+ public function installFromURL($url)
+ {
try {
$path = $this->download($url);
$installed = $this->installArchive($path, true);
@@ -604,7 +664,7 @@ class helper_plugin_extension_extension extends DokuWiki_Plugin {
// purge cache
$this->purgeCache();
- }catch (Exception $e){
+ } catch (Exception $e) {
throw $e;
}
return $installed;
@@ -616,7 +676,8 @@ class helper_plugin_extension_extension extends DokuWiki_Plugin {
* @throws \Exception when something goes wrong
* @return array The list of installed extensions
*/
- public function installOrUpdate() {
+ public function installOrUpdate()
+ {
$url = $this->getDownloadURL();
$path = $this->download($url);
$installed = $this->installArchive($path, $this->isInstalled(), $this->getBase());
@@ -637,7 +698,8 @@ class helper_plugin_extension_extension extends DokuWiki_Plugin {
*
* @return bool If the plugin was sucessfully uninstalled
*/
- public function uninstall() {
+ public function uninstall()
+ {
$this->purgeCache();
return io_rmdir($this->getInstallDir(), true);
}
@@ -647,12 +709,13 @@ class helper_plugin_extension_extension extends DokuWiki_Plugin {
*
* @return bool|string True or an error message
*/
- public function enable() {
+ public function enable()
+ {
if ($this->isTemplate()) return $this->getLang('notimplemented');
if (!$this->isInstalled()) return $this->getLang('notinstalled');
if ($this->isEnabled()) return $this->getLang('alreadyenabled');
- /* @var Doku_Plugin_Controller $plugin_controller */
+ /* @var PluginController $plugin_controller */
global $plugin_controller;
if ($plugin_controller->enable($this->base)) {
$this->purgeCache();
@@ -667,10 +730,11 @@ class helper_plugin_extension_extension extends DokuWiki_Plugin {
*
* @return bool|string True or an error message
*/
- public function disable() {
+ public function disable()
+ {
if ($this->isTemplate()) return $this->getLang('notimplemented');
- /* @var Doku_Plugin_Controller $plugin_controller */
+ /* @var PluginController $plugin_controller */
global $plugin_controller;
if (!$this->isInstalled()) return $this->getLang('notinstalled');
if (!$this->isEnabled()) return $this->getLang('alreadydisabled');
@@ -685,7 +749,8 @@ class helper_plugin_extension_extension extends DokuWiki_Plugin {
/**
* Purge the cache by touching the main configuration file
*/
- protected function purgeCache() {
+ protected function purgeCache()
+ {
global $config_cascade;
// expire dokuwiki caches
@@ -696,7 +761,8 @@ class helper_plugin_extension_extension extends DokuWiki_Plugin {
/**
* Read local extension data either from info.txt or getInfo()
*/
- protected function readLocalData() {
+ protected function readLocalData()
+ {
if ($this->isTemplate()) {
$infopath = $this->getInstallDir().'/template.info.txt';
} else {
@@ -706,19 +772,18 @@ class helper_plugin_extension_extension extends DokuWiki_Plugin {
if (is_readable($infopath)) {
$this->localInfo = confToHash($infopath);
} elseif (!$this->isTemplate() && $this->isEnabled()) {
- global $plugin_types;
$path = $this->getInstallDir().'/';
$plugin = null;
- foreach($plugin_types as $type) {
- if(file_exists($path.$type.'.php')) {
+ foreach (PluginController::PLUGIN_TYPES as $type) {
+ if (file_exists($path.$type.'.php')) {
$plugin = plugin_load($type, $this->base);
if ($plugin) break;
}
- if($dh = @opendir($path.$type.'/')) {
- while(false !== ($cp = readdir($dh))) {
- if($cp == '.' || $cp == '..' || strtolower(substr($cp, -4)) != '.php') continue;
+ if ($dh = @opendir($path.$type.'/')) {
+ while (false !== ($cp = readdir($dh))) {
+ if ($cp == '.' || $cp == '..' || strtolower(substr($cp, -4)) != '.php') continue;
$plugin = plugin_load($type, $this->base.'_'.substr($cp, 0, -4));
if ($plugin) break;
@@ -741,21 +806,22 @@ class helper_plugin_extension_extension extends DokuWiki_Plugin {
* @param string $url Where the extension was downloaded from. (empty for manual installs via upload)
* @param array $installed Optional list of installed plugins
*/
- protected function updateManagerData($url = '', $installed = null) {
+ protected function updateManagerData($url = '', $installed = null)
+ {
$origID = $this->getID();
- if(is_null($installed)) {
+ if (is_null($installed)) {
$installed = array($origID);
}
- foreach($installed as $ext => $info) {
- if($this->getID() != $ext) $this->setExtension($ext);
- if($url) {
+ foreach ($installed as $ext => $info) {
+ if ($this->getID() != $ext) $this->setExtension($ext);
+ if ($url) {
$this->managerData['downloadurl'] = $url;
- } elseif(isset($this->managerData['downloadurl'])) {
+ } elseif (isset($this->managerData['downloadurl'])) {
unset($this->managerData['downloadurl']);
}
- if(isset($this->managerData['installed'])) {
+ if (isset($this->managerData['installed'])) {
$this->managerData['updated'] = date('r');
} else {
$this->managerData['installed'] = date('r');
@@ -763,23 +829,24 @@ class helper_plugin_extension_extension extends DokuWiki_Plugin {
$this->writeManagerData();
}
- if($this->getID() != $origID) $this->setExtension($origID);
+ if ($this->getID() != $origID) $this->setExtension($origID);
}
/**
* Read the manager.dat file
*/
- protected function readManagerData() {
+ protected function readManagerData()
+ {
$managerpath = $this->getInstallDir().'/manager.dat';
if (is_readable($managerpath)) {
$file = @file($managerpath);
- if(!empty($file)) {
- foreach($file as $line) {
+ if (!empty($file)) {
+ foreach ($file as $line) {
list($key, $value) = explode('=', trim($line, DOKU_LF), 2);
$key = trim($key);
$value = trim($value);
// backwards compatible with old plugin manager
- if($key == 'url') $key = 'downloadurl';
+ if ($key == 'url') $key = 'downloadurl';
$this->managerData[$key] = $value;
}
}
@@ -789,7 +856,8 @@ class helper_plugin_extension_extension extends DokuWiki_Plugin {
/**
* Write the manager.data file
*/
- protected function writeManagerData() {
+ protected function writeManagerData()
+ {
$managerpath = $this->getInstallDir().'/manager.dat';
$data = '';
foreach ($this->managerData as $k => $v) {
@@ -805,9 +873,10 @@ class helper_plugin_extension_extension extends DokuWiki_Plugin {
*
* @return false|string
*/
- protected function mkTmpDir(){
+ protected function mkTmpDir()
+ {
$dir = io_mktmpdir();
- if(!$dir) return false;
+ if (!$dir) return false;
$this->temporary[] = $dir;
return $dir;
}
@@ -844,7 +913,7 @@ class helper_plugin_extension_extension extends DokuWiki_Plugin {
if (is_string($content_disposition) &&
preg_match('/attachment;\s*filename\s*=\s*"([^"]*)"/i', $content_disposition, $match)) {
- $name = utf8_basename($match[1]);
+ $name = \dokuwiki\Utf8\PhpString::basename($match[1]);
}
}
@@ -872,27 +941,28 @@ class helper_plugin_extension_extension extends DokuWiki_Plugin {
* @throws Exception when something goes wrong
* @return string The path where the archive was saved
*/
- public function download($url) {
+ public function download($url)
+ {
// check the url
- if(!preg_match('/https?:\/\//i', $url)){
+ if (!preg_match('/https?:\/\//i', $url)) {
throw new Exception($this->getLang('error_badurl'));
}
// try to get the file from the path (used as plugin name fallback)
$file = parse_url($url, PHP_URL_PATH);
- if(is_null($file)){
+ if (is_null($file)) {
$file = md5($url);
- }else{
- $file = utf8_basename($file);
+ } else {
+ $file = \dokuwiki\Utf8\PhpString::basename($file);
}
// create tmp directory for download
- if(!($tmp = $this->mkTmpDir())) {
+ if (!($tmp = $this->mkTmpDir())) {
throw new Exception($this->getLang('error_dircreate'));
}
// download
- if(!$file = $this->downloadToFile($url, $tmp.'/', $file)) {
+ if (!$file = $this->downloadToFile($url, $tmp.'/', $file)) {
io_rmdir($tmp, true);
throw new Exception(sprintf($this->getLang('error_download'), '<bdi>'.hsc($url).'</bdi>'));
}
@@ -907,16 +977,17 @@ class helper_plugin_extension_extension extends DokuWiki_Plugin {
* @throws Exception when something went wrong
* @return array list of installed extensions
*/
- public function installArchive($file, $overwrite=false, $base = '') {
+ public function installArchive($file, $overwrite = false, $base = '')
+ {
$installed_extensions = array();
// create tmp directory for decompression
- if(!($tmp = $this->mkTmpDir())) {
+ if (!($tmp = $this->mkTmpDir())) {
throw new Exception($this->getLang('error_dircreate'));
}
// add default base folder if specified to handle case where zip doesn't contain this
- if($base && !@mkdir($tmp.'/'.$base)) {
+ if ($base && !@mkdir($tmp.'/'.$base)) {
throw new Exception($this->getLang('error_dircreate'));
}
@@ -927,33 +998,33 @@ class helper_plugin_extension_extension extends DokuWiki_Plugin {
// move the folder(s) to lib/..
$result = array('old'=>array(), 'new'=>array());
$default = ($this->isTemplate() ? 'template' : 'plugin');
- if(!$this->find_folders($result, $tmp.'/'.$base, $default)) {
+ if (!$this->findFolders($result, $tmp.'/'.$base, $default)) {
throw new Exception($this->getLang('error_findfolder'));
}
// choose correct result array
- if(count($result['new'])) {
+ if (count($result['new'])) {
$install = $result['new'];
- }else{
+ } else {
$install = $result['old'];
}
- if(!count($install)){
+ if (!count($install)) {
throw new Exception($this->getLang('error_findfolder'));
}
// now install all found items
- foreach($install as $item) {
+ foreach ($install as $item) {
// where to install?
- if($item['type'] == 'template') {
- $target_base_dir = DOKU_TPLLIB;
- }else{
+ if ($item['type'] == 'template') {
+ $target_base_dir = $this->tpllib;
+ } else {
$target_base_dir = DOKU_PLUGIN;
}
- if(!empty($item['base'])) {
+ if (!empty($item['base'])) {
// use base set in info.txt
- } elseif($base && count($install) == 1) {
+ } elseif ($base && count($install) == 1) {
$item['base'] = $base;
} else {
// default - use directory as found in zip
@@ -964,7 +1035,7 @@ class helper_plugin_extension_extension extends DokuWiki_Plugin {
// check to make sure we aren't overwriting anything
$target = $target_base_dir.$item['base'];
- if(!$overwrite && file_exists($target)) {
+ if (!$overwrite && file_exists($target)) {
// TODO remember our settings, ask the user to confirm overwrite
continue;
}
@@ -972,10 +1043,10 @@ class helper_plugin_extension_extension extends DokuWiki_Plugin {
$action = file_exists($target) ? 'update' : 'install';
// copy action
- if($this->dircopy($item['tmp'], $target)) {
+ if ($this->dircopy($item['tmp'], $target)) {
// return info
$id = $item['base'];
- if($item['type'] == 'template') {
+ if ($item['type'] == 'template') {
$id = 'template:'.$id;
}
$installed_extensions[$id] = array(
@@ -989,7 +1060,7 @@ class helper_plugin_extension_extension extends DokuWiki_Plugin {
}
// cleanup
- if($tmp) io_rmdir($tmp, true);
+ if ($tmp) io_rmdir($tmp, true);
return $installed_extensions;
}
@@ -1015,20 +1086,20 @@ class helper_plugin_extension_extension extends DokuWiki_Plugin {
* @param string $subdir - a subdirectory. do not set. used by recursion
* @return bool - false on error
*/
- protected function find_folders(&$result, $directory, $default_type='plugin', $subdir='') {
+ protected function findFolders(&$result, $directory, $default_type = 'plugin', $subdir = '')
+ {
$this_dir = "$directory$subdir";
$dh = @opendir($this_dir);
- if(!$dh) return false;
+ if (!$dh) return false;
$found_dirs = array();
$found_files = 0;
$found_template_parts = 0;
while (false !== ($f = readdir($dh))) {
- if($f == '.' || $f == '..') continue;
+ if ($f == '.' || $f == '..') continue;
- if(is_dir("$this_dir/$f")) {
+ if (is_dir("$this_dir/$f")) {
$found_dirs[] = "$subdir/$f";
-
} else {
// it's a file -> check for config
$found_files++;
@@ -1057,11 +1128,11 @@ class helper_plugin_extension_extension extends DokuWiki_Plugin {
closedir($dh);
// files where found but no info.txt - use old method
- if($found_files){
+ if ($found_files) {
$info = array();
$info['tmp'] = $this_dir;
// does this look like a template or should we use the default type?
- if($found_template_parts >= 2) {
+ if ($found_template_parts >= 2) {
$info['type'] = 'template';
} else {
$info['type'] = $default_type;
@@ -1073,7 +1144,7 @@ class helper_plugin_extension_extension extends DokuWiki_Plugin {
// we have no files yet -> recurse
foreach ($found_dirs as $found_dir) {
- $this->find_folders($result, $directory, $default_type, "$found_dir");
+ $this->findFolders($result, $directory, $default_type, "$found_dir");
}
return true;
}
@@ -1088,13 +1159,13 @@ class helper_plugin_extension_extension extends DokuWiki_Plugin {
* @throws Exception
* @return bool
*/
- private function decompress($file, $target) {
+ private function decompress($file, $target)
+ {
// decompression library doesn't like target folders ending in "/"
- if(substr($target, -1) == "/") $target = substr($target, 0, -1);
-
- $ext = $this->guess_archive($file);
- if(in_array($ext, array('tar', 'bz', 'gz'))) {
+ if (substr($target, -1) == "/") $target = substr($target, 0, -1);
+ $ext = $this->guessArchiveType($file);
+ if (in_array($ext, array('tar', 'bz', 'gz'))) {
try {
$tar = new \splitbrain\PHPArchive\Tar();
$tar->open($file);
@@ -1104,8 +1175,7 @@ class helper_plugin_extension_extension extends DokuWiki_Plugin {
}
return true;
- } elseif($ext == 'zip') {
-
+ } elseif ($ext == 'zip') {
try {
$zip = new \splitbrain\PHPArchive\Zip();
$zip->open($file);
@@ -1131,15 +1201,16 @@ class helper_plugin_extension_extension extends DokuWiki_Plugin {
* @param string $file The file to analyze
* @return string|false false if the file can't be read, otherwise an "extension"
*/
- private function guess_archive($file) {
+ private function guessArchiveType($file)
+ {
$fh = fopen($file, 'rb');
- if(!$fh) return false;
+ if (!$fh) return false;
$magic = fread($fh, 5);
fclose($fh);
- if(strpos($magic, "\x42\x5a") === 0) return 'bz';
- if(strpos($magic, "\x1f\x8b") === 0) return 'gz';
- if(strpos($magic, "\x50\x4b\x03\x04") === 0) return 'zip';
+ if (strpos($magic, "\x42\x5a") === 0) return 'bz';
+ if (strpos($magic, "\x1f\x8b") === 0) return 'gz';
+ if (strpos($magic, "\x50\x4b\x03\x04") === 0) return 'zip';
return 'tar';
}
@@ -1150,27 +1221,27 @@ class helper_plugin_extension_extension extends DokuWiki_Plugin {
* @param string $dst filename path to file
* @return bool|int|string
*/
- private function dircopy($src, $dst) {
+ private function dircopy($src, $dst)
+ {
global $conf;
- if(is_dir($src)) {
- if(!$dh = @opendir($src)) return false;
+ if (is_dir($src)) {
+ if (!$dh = @opendir($src)) return false;
- if($ok = io_mkdir_p($dst)) {
+ if ($ok = io_mkdir_p($dst)) {
while ($ok && (false !== ($f = readdir($dh)))) {
- if($f == '..' || $f == '.') continue;
+ if ($f == '..' || $f == '.') continue;
$ok = $this->dircopy("$src/$f", "$dst/$f");
}
}
closedir($dh);
return $ok;
-
} else {
$exists = file_exists($dst);
- if(!@copy($src, $dst)) return false;
- if(!$exists && !empty($conf['fperm'])) chmod($dst, $conf['fperm']);
+ if (!@copy($src, $dst)) return false;
+ if (!$exists && !empty($conf['fperm'])) chmod($dst, $conf['fperm']);
@touch($dst, filemtime($src));
}
@@ -1182,29 +1253,30 @@ class helper_plugin_extension_extension extends DokuWiki_Plugin {
*
* @param array $installed
*/
- private function removeDeletedfiles($installed) {
- foreach($installed as $id => $extension) {
+ private function removeDeletedfiles($installed)
+ {
+ foreach ($installed as $id => $extension) {
// only on update
- if($extension['action'] == 'install') continue;
+ if ($extension['action'] == 'install') continue;
// get definition file
- if($extension['type'] == 'template') {
- $extensiondir = DOKU_TPLLIB;
- }else{
+ if ($extension['type'] == 'template') {
+ $extensiondir = $this->tpllib;
+ } else {
$extensiondir = DOKU_PLUGIN;
}
$extensiondir = $extensiondir . $extension['base'] .'/';
$definitionfile = $extensiondir . 'deleted.files';
- if(!file_exists($definitionfile)) continue;
+ if (!file_exists($definitionfile)) continue;
// delete the old files
$list = file($definitionfile);
- foreach($list as $line) {
+ foreach ($list as $line) {
$line = trim(preg_replace('/#.*$/', '', $line));
- if(!$line) continue;
+ if (!$line) continue;
$file = $extensiondir . $line;
- if(!file_exists($file)) continue;
+ if (!file_exists($file)) continue;
io_rmdir($file, true);
}
diff --git a/lib/plugins/extension/helper/gui.php b/lib/plugins/extension/helper/gui.php
index 4ec6fec85..aa9e2ec45 100644
--- a/lib/plugins/extension/helper/gui.php
+++ b/lib/plugins/extension/helper/gui.php
@@ -6,13 +6,13 @@
* @author Andreas Gohr <andi@splitbrain.org>
*/
-// must be run within Dokuwiki
-if(!defined('DOKU_INC')) die();
+use dokuwiki\Extension\PluginController;
/**
* Class helper_plugin_extension_list takes care of the overall GUI
*/
-class helper_plugin_extension_gui extends DokuWiki_Plugin {
+class helper_plugin_extension_gui extends DokuWiki_Plugin
+{
protected $tabs = array('plugins', 'templates', 'search', 'install');
@@ -24,7 +24,8 @@ class helper_plugin_extension_gui extends DokuWiki_Plugin {
*
* initializes requested info window
*/
- public function __construct() {
+ public function __construct()
+ {
global $INPUT;
$this->infoFor = $INPUT->str('info');
}
@@ -32,8 +33,9 @@ class helper_plugin_extension_gui extends DokuWiki_Plugin {
/**
* display the plugin tab
*/
- public function tabPlugins() {
- /* @var Doku_Plugin_Controller $plugin_controller */
+ public function tabPlugins()
+ {
+ /* @var PluginController $plugin_controller */
global $plugin_controller;
echo '<div class="panelHeader">';
@@ -46,19 +48,20 @@ class helper_plugin_extension_gui extends DokuWiki_Plugin {
$extension = $this->loadHelper('extension_extension');
/* @var helper_plugin_extension_list $list */
$list = $this->loadHelper('extension_list');
- $list->start_form();
- foreach($pluginlist as $name) {
+ $list->startForm();
+ foreach ($pluginlist as $name) {
$extension->setExtension($name);
- $list->add_row($extension, $extension->getID() == $this->infoFor);
+ $list->addRow($extension, $extension->getID() == $this->infoFor);
}
- $list->end_form();
+ $list->endForm();
$list->render();
}
/**
* Display the template tab
*/
- public function tabTemplates() {
+ public function tabTemplates()
+ {
echo '<div class="panelHeader">';
echo $this->locale_xhtml('intro_templates');
echo '</div>';
@@ -72,19 +75,20 @@ class helper_plugin_extension_gui extends DokuWiki_Plugin {
$extension = $this->loadHelper('extension_extension');
/* @var helper_plugin_extension_list $list */
$list = $this->loadHelper('extension_list');
- $list->start_form();
- foreach($tpllist as $name) {
+ $list->startForm();
+ foreach ($tpllist as $name) {
$extension->setExtension("template:$name");
- $list->add_row($extension, $extension->getID() == $this->infoFor);
+ $list->addRow($extension, $extension->getID() == $this->infoFor);
}
- $list->end_form();
+ $list->endForm();
$list->render();
}
/**
* Display the search tab
*/
- public function tabSearch() {
+ public function tabSearch()
+ {
global $INPUT;
echo '<div class="panelHeader">';
echo $this->locale_xhtml('intro_search');
@@ -95,7 +99,7 @@ class helper_plugin_extension_gui extends DokuWiki_Plugin {
$form->addElement(form_makeButton('submit', '', $this->getLang('search')));
$form->printForm();
- if(!$INPUT->bool('q')) return;
+ if (!$INPUT->bool('q')) return;
/* @var helper_plugin_extension_repository $repository FIXME should we use some gloabl instance? */
$repository = $this->loadHelper('extension_repository');
@@ -105,29 +109,35 @@ class helper_plugin_extension_gui extends DokuWiki_Plugin {
$extension = $this->loadHelper('extension_extension');
/* @var helper_plugin_extension_list $list */
$list = $this->loadHelper('extension_list');
- $list->start_form();
- if($result){
- foreach($result as $name) {
+ $list->startForm();
+ if ($result) {
+ foreach ($result as $name) {
$extension->setExtension($name);
- $list->add_row($extension, $extension->getID() == $this->infoFor);
+ $list->addRow($extension, $extension->getID() == $this->infoFor);
}
} else {
- $list->nothing_found();
+ $list->nothingFound();
}
- $list->end_form();
+ $list->endForm();
$list->render();
-
}
/**
* Display the template tab
*/
- public function tabInstall() {
+ public function tabInstall()
+ {
echo '<div class="panelHeader">';
echo $this->locale_xhtml('intro_install');
echo '</div>';
- $form = new Doku_Form(array('action' => $this->tabURL('', array(), '&'), 'enctype' => 'multipart/form-data', 'class' => 'install'));
+ $form = new Doku_Form(
+ array(
+ 'action' => $this->tabURL('', array(), '&'),
+ 'enctype' => 'multipart/form-data',
+ 'class' => 'install'
+ )
+ );
$form->addElement(form_makeTextField('installurl', '', $this->getLang('install_url'), '', 'block'));
$form->addElement(form_makeFileField('installfile', $this->getLang('install_upload'), '', 'block'));
$form->addElement(form_makeButton('submit', '', $this->getLang('btn_install')));
@@ -139,11 +149,12 @@ class helper_plugin_extension_gui extends DokuWiki_Plugin {
*
* @fixme style active one
*/
- public function tabNavigation() {
+ public function tabNavigation()
+ {
echo '<ul class="tabs">';
- foreach($this->tabs as $tab) {
+ foreach ($this->tabs as $tab) {
$url = $this->tabURL($tab);
- if($this->currentTab() == $tab) {
+ if ($this->currentTab() == $tab) {
$class = ' active';
} else {
$class = '';
@@ -158,11 +169,12 @@ class helper_plugin_extension_gui extends DokuWiki_Plugin {
*
* @return string
*/
- public function currentTab() {
+ public function currentTab()
+ {
global $INPUT;
$tab = $INPUT->str('tab', 'plugins', true);
- if(!in_array($tab, $this->tabs)) $tab = 'plugins';
+ if (!in_array($tab, $this->tabs)) $tab = 'plugins';
return $tab;
}
@@ -175,19 +187,19 @@ class helper_plugin_extension_gui extends DokuWiki_Plugin {
* @param bool $absolute create absolute URLs?
* @return string
*/
- public function tabURL($tab = '', $params = array(), $sep = '&amp;', $absolute = false) {
+ public function tabURL($tab = '', $params = array(), $sep = '&amp;', $absolute = false)
+ {
global $ID;
global $INPUT;
- if(!$tab) $tab = $this->currentTab();
+ if (!$tab) $tab = $this->currentTab();
$defaults = array(
'do' => 'admin',
'page' => 'extension',
'tab' => $tab,
);
- if($tab == 'search') $defaults['q'] = $INPUT->str('q');
+ if ($tab == 'search') $defaults['q'] = $INPUT->str('q');
return wl($ID, array_merge($defaults, $params), $absolute, $sep);
}
-
}
diff --git a/lib/plugins/extension/helper/list.php b/lib/plugins/extension/helper/list.php
index 656b4ea09..d895941cb 100644
--- a/lib/plugins/extension/helper/list.php
+++ b/lib/plugins/extension/helper/list.php
@@ -6,13 +6,11 @@
* @author Michael Hamann <michael@content-space.de>
*/
-// must be run within Dokuwiki
-if(!defined('DOKU_INC')) die();
-
/**
* Class helper_plugin_extension_list takes care of creating a HTML list of extensions
*/
-class helper_plugin_extension_list extends DokuWiki_Plugin {
+class helper_plugin_extension_list extends DokuWiki_Plugin
+{
protected $form = '';
/** @var helper_plugin_extension_gui */
protected $gui;
@@ -22,30 +20,38 @@ class helper_plugin_extension_list extends DokuWiki_Plugin {
*
* loads additional helpers
*/
- public function __construct(){
+ public function __construct()
+ {
$this->gui = plugin_load('helper', 'extension_gui');
}
- function start_form() {
+ /**
+ * Initialize the extension table form
+ */
+ public function startForm()
+ {
$this->form .= '<form id="extension__list" accept-charset="utf-8" method="post" action="">';
$hidden = array(
'do'=>'admin',
'page'=>'extension',
'sectok'=>getSecurityToken()
);
- $this->add_hidden($hidden);
+ $this->addHidden($hidden);
$this->form .= '<ul class="extensionList">';
}
+
/**
* Build single row of extension table
+ *
* @param helper_plugin_extension_extension $extension The extension that shall be added
* @param bool $showinfo Show the info area
*/
- function add_row(helper_plugin_extension_extension $extension, $showinfo = false) {
- $this->start_row($extension);
- $this->populate_column('legend', $this->make_legend($extension, $showinfo));
- $this->populate_column('actions', $this->make_actions($extension));
- $this->end_row();
+ public function addRow(helper_plugin_extension_extension $extension, $showinfo = false)
+ {
+ $this->startRow($extension);
+ $this->populateColumn('legend', $this->makeLegend($extension, $showinfo));
+ $this->populateColumn('actions', $this->makeActions($extension));
+ $this->endRow();
}
/**
@@ -55,7 +61,8 @@ class helper_plugin_extension_list extends DokuWiki_Plugin {
* @param string $header The content of the header
* @param int $level The level of the header
*/
- function add_header($id, $header, $level = 2) {
+ public function addHeader($id, $header, $level = 2)
+ {
$this->form .='<h'.$level.' id="'.$id.'">'.hsc($header).'</h'.$level.'>'.DOKU_LF;
}
@@ -64,17 +71,20 @@ class helper_plugin_extension_list extends DokuWiki_Plugin {
*
* @param string $data The content
*/
- function add_p($data) {
+ public function addParagraph($data)
+ {
$this->form .= '<p>'.hsc($data).'</p>'.DOKU_LF;
}
/**
* Add hidden fields to the form with the given data
- * @param array $array
+ *
+ * @param array $data key-value list of fields and their values to add
*/
- function add_hidden(array $array) {
+ public function addHidden(array $data)
+ {
$this->form .= '<div class="no">';
- foreach ($array as $key => $value) {
+ foreach ($data as $key => $value) {
$this->form .= '<input type="hidden" name="'.hsc($key).'" value="'.hsc($value).'" />';
}
$this->form .= '</div>'.DOKU_LF;
@@ -83,7 +93,8 @@ class helper_plugin_extension_list extends DokuWiki_Plugin {
/**
* Add closing tags
*/
- function end_form() {
+ public function endForm()
+ {
$this->form .= '</ul>';
$this->form .= '</form>'.DOKU_LF;
}
@@ -91,7 +102,8 @@ class helper_plugin_extension_list extends DokuWiki_Plugin {
/**
* Show message when no results are found
*/
- function nothing_found() {
+ public function nothingFound()
+ {
global $lang;
$this->form .= '<li class="notfound">'.$lang['nothingfound'].'</li>';
}
@@ -99,7 +111,8 @@ class helper_plugin_extension_list extends DokuWiki_Plugin {
/**
* Print the form
*/
- function render() {
+ public function render()
+ {
echo $this->form;
}
@@ -108,8 +121,10 @@ class helper_plugin_extension_list extends DokuWiki_Plugin {
*
* @param helper_plugin_extension_extension $extension The extension
*/
- private function start_row(helper_plugin_extension_extension $extension) {
- $this->form .= '<li id="extensionplugin__'.hsc($extension->getID()).'" class="'.$this->make_class($extension).'">';
+ private function startRow(helper_plugin_extension_extension $extension)
+ {
+ $this->form .= '<li id="extensionplugin__'.hsc($extension->getID()).
+ '" class="'.$this->makeClass($extension).'">';
}
/**
@@ -117,14 +132,16 @@ class helper_plugin_extension_list extends DokuWiki_Plugin {
* @param string $class The class name
* @param string $html The content
*/
- private function populate_column($class, $html) {
+ private function populateColumn($class, $html)
+ {
$this->form .= '<div class="'.$class.' col">'.$html.'</div>'.DOKU_LF;
}
/**
* End the row
*/
- private function end_row() {
+ private function endRow()
+ {
$this->form .= '</li>'.DOKU_LF;
}
@@ -134,7 +151,8 @@ class helper_plugin_extension_list extends DokuWiki_Plugin {
* @param helper_plugin_extension_extension $extension The extension
* @return string The HTML code
*/
- function make_homepagelink(helper_plugin_extension_extension $extension) {
+ public function makeHomepageLink(helper_plugin_extension_extension $extension)
+ {
$text = $this->getLang('homepage_link');
$url = hsc($extension->getURL());
return '<a href="'.$url.'" title="'.$url.'" class ="urlextern">'.$text.'</a> ';
@@ -146,15 +164,16 @@ class helper_plugin_extension_list extends DokuWiki_Plugin {
* @param helper_plugin_extension_extension $extension The extension object
* @return string The class name
*/
- function make_class(helper_plugin_extension_extension $extension) {
+ public function makeClass(helper_plugin_extension_extension $extension)
+ {
$class = ($extension->isTemplate()) ? 'template' : 'plugin';
- if($extension->isInstalled()) {
+ if ($extension->isInstalled()) {
$class.=' installed';
$class.= ($extension->isEnabled()) ? ' enabled':' disabled';
- if($extension->updateAvailable()) $class .= ' updatable';
+ if ($extension->updateAvailable()) $class .= ' updatable';
}
- if(!$extension->canModify()) $class.= ' notselect';
- if($extension->isProtected()) $class.= ' protected';
+ if (!$extension->canModify()) $class.= ' notselect';
+ if ($extension->isProtected()) $class.= ' protected';
//if($this->showinfo) $class.= ' showinfo';
return $class;
}
@@ -165,17 +184,16 @@ class helper_plugin_extension_list extends DokuWiki_Plugin {
* @param helper_plugin_extension_extension $extension The extension object
* @return string The HTML code of the link
*/
- function make_author(helper_plugin_extension_extension $extension) {
- global $ID;
-
- if($extension->getAuthor()) {
-
+ public function makeAuthor(helper_plugin_extension_extension $extension)
+ {
+ if ($extension->getAuthor()) {
$mailid = $extension->getEmailID();
- if($mailid){
+ if ($mailid) {
$url = $this->gui->tabURL('search', array('q' => 'authorid:'.$mailid));
- return '<bdi><a href="'.$url.'" class="author" title="'.$this->getLang('author_hint').'" ><img src="//www.gravatar.com/avatar/'.$mailid.'?s=20&amp;d=mm" width="20" height="20" alt="" /> '.hsc($extension->getAuthor()).'</a></bdi>';
-
- }else{
+ return '<bdi><a href="'.$url.'" class="author" title="'.$this->getLang('author_hint').'" >'.
+ '<img src="//www.gravatar.com/avatar/'.$mailid.'?s=20&amp;d=mm" width="20" height="20" alt="" /> '.
+ hsc($extension->getAuthor()).'</a></bdi>';
+ } else {
return '<bdi><span class="author">'.hsc($extension->getAuthor()).'</span></bdi>';
}
}
@@ -188,11 +206,12 @@ class helper_plugin_extension_list extends DokuWiki_Plugin {
* @param helper_plugin_extension_extension $extension The extension object
* @return string The HTML code
*/
- function make_screenshot(helper_plugin_extension_extension $extension) {
+ public function makeScreenshot(helper_plugin_extension_extension $extension)
+ {
$screen = $extension->getScreenshotURL();
$thumb = $extension->getThumbnailURL();
- if($screen) {
+ if ($screen) {
// use protocol independent URLs for images coming from us #595
$screen = str_replace('http://www.dokuwiki.org', '//www.dokuwiki.org', $screen);
$thumb = str_replace('http://www.dokuwiki.org', '//www.dokuwiki.org', $thumb);
@@ -201,11 +220,12 @@ class helper_plugin_extension_list extends DokuWiki_Plugin {
$img = '<a href="'.hsc($screen).'" target="_blank" class="extension_screenshot">'.
'<img alt="'.$title.'" width="120" height="70" src="'.hsc($thumb).'" />'.
'</a>';
- } elseif($extension->isTemplate()) {
- $img = '<img alt="" width="120" height="70" src="'.DOKU_BASE.'lib/plugins/extension/images/template.png" />';
-
+ } elseif ($extension->isTemplate()) {
+ $img = '<img alt="" width="120" height="70" src="'.DOKU_BASE.
+ 'lib/plugins/extension/images/template.png" />';
} else {
- $img = '<img alt="" width="120" height="70" src="'.DOKU_BASE.'lib/plugins/extension/images/plugin.png" />';
+ $img = '<img alt="" width="120" height="70" src="'.DOKU_BASE.
+ 'lib/plugins/extension/images/plugin.png" />';
}
return '<div class="screenshot" >'.$img.'<span></span></div>'.DOKU_LF;
}
@@ -217,41 +237,51 @@ class helper_plugin_extension_list extends DokuWiki_Plugin {
* @param bool $showinfo Show the info section
* @return string The HTML code
*/
- function make_legend(helper_plugin_extension_extension $extension, $showinfo = false) {
+ public function makeLegend(helper_plugin_extension_extension $extension, $showinfo = false)
+ {
$return = '<div>';
$return .= '<h2>';
- $return .= sprintf($this->getLang('extensionby'), '<bdi>'.hsc($extension->getDisplayName()).'</bdi>', $this->make_author($extension));
+ $return .= sprintf(
+ $this->getLang('extensionby'),
+ '<bdi>'.hsc($extension->getDisplayName()).'</bdi>',
+ $this->makeAuthor($extension)
+ );
$return .= '</h2>'.DOKU_LF;
- $return .= $this->make_screenshot($extension);
+ $return .= $this->makeScreenshot($extension);
$popularity = $extension->getPopularity();
if ($popularity !== false && !$extension->isBundled()) {
$popularityText = sprintf($this->getLang('popularity'), round($popularity*100, 2));
- $return .= '<div class="popularity" title="'.$popularityText.'"><div style="width: '.($popularity * 100).'%;"><span class="a11y">'.$popularityText.'</span></div></div>'.DOKU_LF;
+ $return .= '<div class="popularity" title="'.$popularityText.'">'.
+ '<div style="width: '.($popularity * 100).'%;">'.
+ '<span class="a11y">'.$popularityText.'</span>'.
+ '</div></div>'.DOKU_LF;
}
- if($extension->getDescription()) {
+ if ($extension->getDescription()) {
$return .= '<p><bdi>';
$return .= hsc($extension->getDescription()).' ';
$return .= '</bdi></p>'.DOKU_LF;
}
- $return .= $this->make_linkbar($extension);
+ $return .= $this->makeLinkbar($extension);
- if($showinfo){
+ if ($showinfo) {
$url = $this->gui->tabURL('');
$class = 'close';
- }else{
+ } else {
$url = $this->gui->tabURL('', array('info' => $extension->getID()));
$class = '';
}
- $return .= ' <a href="'.$url.'#extensionplugin__'.$extension->getID().'" class="info '.$class.'" title="'.$this->getLang('btn_info').'" data-extid="'.$extension->getID().'">'.$this->getLang('btn_info').'</a>';
+ $return .= ' <a href="'.$url.'#extensionplugin__'.$extension->getID().
+ '" class="info '.$class.'" title="'.$this->getLang('btn_info').
+ '" data-extid="'.$extension->getID().'">'.$this->getLang('btn_info').'</a>';
if ($showinfo) {
- $return .= $this->make_info($extension);
+ $return .= $this->makeInfo($extension);
}
- $return .= $this->make_noticearea($extension);
+ $return .= $this->makeNoticeArea($extension);
$return .= '</div>'.DOKU_LF;
return $return;
}
@@ -262,17 +292,20 @@ class helper_plugin_extension_list extends DokuWiki_Plugin {
* @param helper_plugin_extension_extension $extension The extension instance
* @return string The HTML code
*/
- function make_linkbar(helper_plugin_extension_extension $extension) {
+ public function makeLinkbar(helper_plugin_extension_extension $extension)
+ {
$return = '<div class="linkbar">';
- $return .= $this->make_homepagelink($extension);
+ $return .= $this->makeHomepageLink($extension);
if ($extension->getBugtrackerURL()) {
- $return .= ' <a href="'.hsc($extension->getBugtrackerURL()).'" title="'.hsc($extension->getBugtrackerURL()).'" class ="bugs">'.$this->getLang('bugs_features').'</a> ';
+ $return .= ' <a href="'.hsc($extension->getBugtrackerURL()).
+ '" title="'.hsc($extension->getBugtrackerURL()).'" class ="bugs">'.
+ $this->getLang('bugs_features').'</a> ';
}
- if ($extension->getTags()){
+ if ($extension->getTags()) {
$first = true;
$return .= '<span class="tags">'.$this->getLang('tags').' ';
foreach ($extension->getTags() as $tag) {
- if (!$first){
+ if (!$first) {
$return .= ', ';
} else {
$first = false;
@@ -292,37 +325,49 @@ class helper_plugin_extension_list extends DokuWiki_Plugin {
* @param helper_plugin_extension_extension $extension The extension
* @return string The HTML code
*/
- function make_noticearea(helper_plugin_extension_extension $extension) {
+ public function makeNoticeArea(helper_plugin_extension_extension $extension)
+ {
$return = '';
$missing_dependencies = $extension->getMissingDependencies();
- if(!empty($missing_dependencies)) {
- $return .= '<div class="msg error">'.
- sprintf($this->getLang('missing_dependency'), '<bdi>'.implode(', ', /*array_map(array($this->helper, 'make_extensionsearchlink'),*/ $missing_dependencies).'</bdi>').
+ if (!empty($missing_dependencies)) {
+ $return .= '<div class="msg error">' .
+ sprintf(
+ $this->getLang('missing_dependency'),
+ '<bdi>' . implode(', ', $missing_dependencies) . '</bdi>'
+ ) .
'</div>';
}
- if($extension->isInWrongFolder()) {
- $return .= '<div class="msg error">'.
- sprintf($this->getLang('wrong_folder'), '<bdi>'.hsc($extension->getInstallName()).'</bdi>', '<bdi>'.hsc($extension->getBase()).'</bdi>').
+ if ($extension->isInWrongFolder()) {
+ $return .= '<div class="msg error">' .
+ sprintf(
+ $this->getLang('wrong_folder'),
+ '<bdi>' . hsc($extension->getInstallName()) . '</bdi>',
+ '<bdi>' . hsc($extension->getBase()) . '</bdi>'
+ ) .
'</div>';
}
- if(($securityissue = $extension->getSecurityIssue()) !== false) {
+ if (($securityissue = $extension->getSecurityIssue()) !== false) {
$return .= '<div class="msg error">'.
sprintf($this->getLang('security_issue'), '<bdi>'.hsc($securityissue).'</bdi>').
'</div>';
}
- if(($securitywarning = $extension->getSecurityWarning()) !== false) {
+ if (($securitywarning = $extension->getSecurityWarning()) !== false) {
$return .= '<div class="msg notify">'.
sprintf($this->getLang('security_warning'), '<bdi>'.hsc($securitywarning).'</bdi>').
'</div>';
}
- if($extension->updateAvailable()) {
+ if ($extension->updateAvailable()) {
$return .= '<div class="msg notify">'.
sprintf($this->getLang('update_available'), hsc($extension->getLastUpdate())).
'</div>';
}
- if($extension->hasDownloadURLChanged()) {
- $return .= '<div class="msg notify">'.
- sprintf($this->getLang('url_change'), '<bdi>'.hsc($extension->getDownloadURL()).'</bdi>', '<bdi>'.hsc($extension->getLastDownloadURL()).'</bdi>').
+ if ($extension->hasDownloadURLChanged()) {
+ $return .= '<div class="msg notify">' .
+ sprintf(
+ $this->getLang('url_change'),
+ '<bdi>' . hsc($extension->getDownloadURL()) . '</bdi>',
+ '<bdi>' . hsc($extension->getLastDownloadURL()) . '</bdi>'
+ ) .
'</div>';
}
return $return.DOKU_LF;
@@ -336,13 +381,14 @@ class helper_plugin_extension_list extends DokuWiki_Plugin {
* @param string $url
* @return string HTML link
*/
- function shortlink($url){
+ public function shortlink($url)
+ {
$link = parse_url($url);
$base = $link['host'];
- if(!empty($link['port'])) $base .= $base.':'.$link['port'];
+ if (!empty($link['port'])) $base .= $base.':'.$link['port'];
$long = $link['path'];
- if(!empty($link['query'])) $long .= $link['query'];
+ if (!empty($link['query'])) $long .= $link['query'];
$name = shorten($base, $long, 55);
@@ -355,17 +401,19 @@ class helper_plugin_extension_list extends DokuWiki_Plugin {
* @param helper_plugin_extension_extension $extension The extension
* @return string The HTML code
*/
- function make_info(helper_plugin_extension_extension $extension) {
+ public function makeInfo(helper_plugin_extension_extension $extension)
+ {
$default = $this->getLang('unknown');
$return = '<dl class="details">';
$return .= '<dt>'.$this->getLang('status').'</dt>';
- $return .= '<dd>'.$this->make_status($extension).'</dd>';
+ $return .= '<dd>'.$this->makeStatus($extension).'</dd>';
if ($extension->getDonationURL()) {
$return .= '<dt>'.$this->getLang('donate').'</dt>';
$return .= '<dd>';
- $return .= '<a href="'.$extension->getDonationURL().'" class="donate">'.$this->getLang('donate_action').'</a>';
+ $return .= '<a href="'.$extension->getDonationURL().'" class="donate">'.
+ $this->getLang('donate_action').'</a>';
$return .= '</dd>';
}
@@ -407,7 +455,7 @@ class helper_plugin_extension_list extends DokuWiki_Plugin {
$return .= ($extension->getTypes() ? hsc(implode(', ', $extension->getTypes())) : $default);
$return .= '</bdi></dd>';
- if(!$extension->isBundled() && $extension->getCompatibleVersions()) {
+ if (!$extension->isBundled() && $extension->getCompatibleVersions()) {
$return .= '<dt>'.$this->getLang('compatible').'</dt>';
$return .= '<dd>';
foreach ($extension->getCompatibleVersions() as $date => $version) {
@@ -416,24 +464,24 @@ class helper_plugin_extension_list extends DokuWiki_Plugin {
$return = rtrim($return, ', ');
$return .= '</dd>';
}
- if($extension->getDependencies()) {
+ if ($extension->getDependencies()) {
$return .= '<dt>'.$this->getLang('depends').'</dt>';
$return .= '<dd>';
- $return .= $this->make_linklist($extension->getDependencies());
+ $return .= $this->makeLinkList($extension->getDependencies());
$return .= '</dd>';
}
- if($extension->getSimilarExtensions()) {
+ if ($extension->getSimilarExtensions()) {
$return .= '<dt>'.$this->getLang('similar').'</dt>';
$return .= '<dd>';
- $return .= $this->make_linklist($extension->getSimilarExtensions());
+ $return .= $this->makeLinkList($extension->getSimilarExtensions());
$return .= '</dd>';
}
- if($extension->getConflicts()) {
+ if ($extension->getConflicts()) {
$return .= '<dt>'.$this->getLang('conflicts').'</dt>';
$return .= '<dd>';
- $return .= $this->make_linklist($extension->getConflicts());
+ $return .= $this->makeLinkList($extension->getConflicts());
$return .= '</dd>';
}
$return .= '</dl>'.DOKU_LF;
@@ -446,10 +494,12 @@ class helper_plugin_extension_list extends DokuWiki_Plugin {
* @param array $ext The extensions
* @return string The HTML code
*/
- function make_linklist($ext) {
+ public function makeLinkList($ext)
+ {
$return = '';
foreach ($ext as $link) {
- $return .= '<bdi><a href="'.$this->gui->tabURL('search', array('q'=>'ext:'.$link)).'">'.hsc($link).'</a></bdi>, ';
+ $return .= '<bdi><a href="'.
+ $this->gui->tabURL('search', array('q'=>'ext:'.$link)).'">'.hsc($link).'</a></bdi>, ';
}
return rtrim($return, ', ');
}
@@ -460,7 +510,8 @@ class helper_plugin_extension_list extends DokuWiki_Plugin {
* @param helper_plugin_extension_extension $extension The extension
* @return string The HTML code
*/
- function make_actions(helper_plugin_extension_extension $extension) {
+ public function makeActions(helper_plugin_extension_extension $extension)
+ {
global $conf;
$return = '';
$errors = '';
@@ -468,48 +519,52 @@ class helper_plugin_extension_list extends DokuWiki_Plugin {
if ($extension->isInstalled()) {
if (($canmod = $extension->canModify()) === true) {
if (!$extension->isProtected()) {
- $return .= $this->make_action('uninstall', $extension);
+ $return .= $this->makeAction('uninstall', $extension);
}
if ($extension->getDownloadURL()) {
if ($extension->updateAvailable()) {
- $return .= $this->make_action('update', $extension);
+ $return .= $this->makeAction('update', $extension);
} else {
- $return .= $this->make_action('reinstall', $extension);
+ $return .= $this->makeAction('reinstall', $extension);
}
}
- }else{
+ } else {
$errors .= '<p class="permerror">'.$this->getLang($canmod).'</p>';
}
if (!$extension->isProtected() && !$extension->isTemplate()) { // no enable/disable for templates
if ($extension->isEnabled()) {
- $return .= $this->make_action('disable', $extension);
+ $return .= $this->makeAction('disable', $extension);
} else {
- $return .= $this->make_action('enable', $extension);
+ $return .= $this->makeAction('enable', $extension);
}
}
- if ($extension->isGitControlled()){
+ if ($extension->isGitControlled()) {
$errors .= '<p class="permerror">'.$this->getLang('git').'</p>';
}
- if ($extension->isEnabled() && in_array('Auth', $extension->getTypes()) && $conf['authtype'] != $extension->getID()) {
+ if ($extension->isEnabled() &&
+ in_array('Auth', $extension->getTypes()) &&
+ $conf['authtype'] != $extension->getID()
+ ) {
$errors .= '<p class="permerror">'.$this->getLang('auth').'</p>';
}
-
- }else{
+ } else {
if (($canmod = $extension->canModify()) === true) {
if ($extension->getDownloadURL()) {
- $return .= $this->make_action('install', $extension);
+ $return .= $this->makeAction('install', $extension);
}
- }else{
+ } else {
$errors .= '<div class="permerror">'.$this->getLang($canmod).'</div>';
}
}
if (!$extension->isInstalled() && $extension->getDownloadURL()) {
$return .= ' <span class="version">'.$this->getLang('available_version').' ';
- $return .= ($extension->getLastUpdate() ? hsc($extension->getLastUpdate()) : $this->getLang('unknown')).'</span>';
+ $return .= ($extension->getLastUpdate()
+ ? hsc($extension->getLastUpdate())
+ : $this->getLang('unknown')).'</span>';
}
return $return.' '.$errors.DOKU_LF;
@@ -522,7 +577,8 @@ class helper_plugin_extension_list extends DokuWiki_Plugin {
* @param helper_plugin_extension_extension $extension The extension
* @return string The HTML code
*/
- function make_action($action, $extension) {
+ public function makeAction($action, $extension)
+ {
$title = '';
switch ($action) {
@@ -535,7 +591,8 @@ class helper_plugin_extension_list extends DokuWiki_Plugin {
$classes = 'button '.$action;
$name = 'fn['.$action.']['.hsc($extension->getID()).']';
- return '<button class="'.$classes.'" name="'.$name.'" type="submit" '.$title.'>'.$this->getLang('btn_'.$action).'</button> ';
+ return '<button class="'.$classes.'" name="'.$name.'" type="submit" '.$title.'>'.
+ $this->getLang('btn_'.$action).'</button> ';
}
/**
@@ -544,7 +601,8 @@ class helper_plugin_extension_list extends DokuWiki_Plugin {
* @param helper_plugin_extension_extension $extension The extension
* @return string The description of all relevant statusses
*/
- function make_status(helper_plugin_extension_extension $extension) {
+ public function makeStatus(helper_plugin_extension_extension $extension)
+ {
$status = array();
@@ -553,15 +611,16 @@ class helper_plugin_extension_list extends DokuWiki_Plugin {
if ($extension->isProtected()) {
$status[] = $this->getLang('status_protected');
} else {
- $status[] = $extension->isEnabled() ? $this->getLang('status_enabled') : $this->getLang('status_disabled');
+ $status[] = $extension->isEnabled()
+ ? $this->getLang('status_enabled')
+ : $this->getLang('status_disabled');
}
} else {
$status[] = $this->getLang('status_not_installed');
}
- if(!$extension->canModify()) $status[] = $this->getLang('status_unmodifiable');
- if($extension->isBundled()) $status[] = $this->getLang('status_bundled');
+ if (!$extension->canModify()) $status[] = $this->getLang('status_unmodifiable');
+ if ($extension->isBundled()) $status[] = $this->getLang('status_bundled');
$status[] = $extension->isTemplate() ? $this->getLang('status_template') : $this->getLang('status_plugin');
return join(', ', $status);
}
-
}
diff --git a/lib/plugins/extension/helper/repository.php b/lib/plugins/extension/helper/repository.php
index 99deb5b27..712baa05c 100644
--- a/lib/plugins/extension/helper/repository.php
+++ b/lib/plugins/extension/helper/repository.php
@@ -6,34 +6,39 @@
* @author Michael Hamann <michael@content-space.de>
*/
-#define('EXTENSION_REPOSITORY_API', 'http://localhost/dokuwiki/lib/plugins/pluginrepo/api.php');
-
-if (!defined('EXTENSION_REPOSITORY_API_ENDPOINT'))
- define('EXTENSION_REPOSITORY_API', 'http://www.dokuwiki.org/lib/plugins/pluginrepo/api.php');
-
-// must be run within Dokuwiki
-if(!defined('DOKU_INC')) die();
+use dokuwiki\Cache\Cache;
+use dokuwiki\HTTP\DokuHTTPClient;
+use dokuwiki\Extension\PluginController;
/**
* Class helper_plugin_extension_repository provides access to the extension repository on dokuwiki.org
*/
-class helper_plugin_extension_repository extends DokuWiki_Plugin {
+class helper_plugin_extension_repository extends DokuWiki_Plugin
+{
+
+ const EXTENSION_REPOSITORY_API = 'http://www.dokuwiki.org/lib/plugins/pluginrepo/api.php';
+
private $loaded_extensions = array();
private $has_access = null;
+
/**
* Initialize the repository (cache), fetches data for all installed plugins
*/
- public function init() {
- /* @var Doku_Plugin_Controller $plugin_controller */
+ public function init()
+ {
+ /* @var PluginController $plugin_controller */
global $plugin_controller;
if ($this->hasAccess()) {
$list = $plugin_controller->getList('', true);
$request_data = array('fmt' => 'php');
$request_needed = false;
foreach ($list as $name) {
- $cache = new cache('##extension_manager##'.$name, '.repo');
+ $cache = new Cache('##extension_manager##'.$name, '.repo');
- if (!isset($this->loaded_extensions[$name]) && $this->hasAccess() && !$cache->useCache(array('age' => 3600 * 24))) {
+ if (!isset($this->loaded_extensions[$name]) &&
+ $this->hasAccess() &&
+ !$cache->useCache(array('age' => 3600 * 24))
+ ) {
$this->loaded_extensions[$name] = true;
$request_data['ext'][] = $name;
$request_needed = true;
@@ -42,11 +47,11 @@ class helper_plugin_extension_repository extends DokuWiki_Plugin {
if ($request_needed) {
$httpclient = new DokuHTTPClient();
- $data = $httpclient->post(EXTENSION_REPOSITORY_API, $request_data);
+ $data = $httpclient->post(self::EXTENSION_REPOSITORY_API, $request_data);
if ($data !== false) {
$extensions = unserialize($data);
foreach ($extensions as $extension) {
- $cache = new cache('##extension_manager##'.$extension['plugin'], '.repo');
+ $cache = new Cache('##extension_manager##'.$extension['plugin'], '.repo');
$cache->storeCache(serialize($extension));
}
} else {
@@ -64,12 +69,12 @@ class helper_plugin_extension_repository extends DokuWiki_Plugin {
*/
public function hasAccess($usecache = true) {
if ($this->has_access === null) {
- $cache = new cache('##extension_manager###hasAccess', '.repo');
+ $cache = new Cache('##extension_manager###hasAccess', '.repo');
if (!$cache->useCache(array('age' => 60*10, 'purge' => !$usecache))) {
$httpclient = new DokuHTTPClient();
$httpclient->timeout = 5;
- $data = $httpclient->get(EXTENSION_REPOSITORY_API.'?cmd=ping');
+ $data = $httpclient->get(self::EXTENSION_REPOSITORY_API.'?cmd=ping');
if ($data !== false) {
$this->has_access = true;
$cache->storeCache(1);
@@ -90,13 +95,17 @@ class helper_plugin_extension_repository extends DokuWiki_Plugin {
* @param string $name The plugin name to get the data for, template names need to be prefix by 'template:'
* @return array The data or null if nothing was found (possibly no repository access)
*/
- public function getData($name) {
- $cache = new cache('##extension_manager##'.$name, '.repo');
-
- if (!isset($this->loaded_extensions[$name]) && $this->hasAccess() && !$cache->useCache(array('age' => 3600 * 24))) {
+ public function getData($name)
+ {
+ $cache = new Cache('##extension_manager##'.$name, '.repo');
+
+ if (!isset($this->loaded_extensions[$name]) &&
+ $this->hasAccess() &&
+ !$cache->useCache(array('age' => 3600 * 24))
+ ) {
$this->loaded_extensions[$name] = true;
$httpclient = new DokuHTTPClient();
- $data = $httpclient->get(EXTENSION_REPOSITORY_API.'?fmt=php&ext[]='.urlencode($name));
+ $data = $httpclient->get(self::EXTENSION_REPOSITORY_API.'?fmt=php&ext[]='.urlencode($name));
if ($data !== false) {
$result = unserialize($data);
$cache->storeCache(serialize($result[0]));
@@ -117,21 +126,22 @@ class helper_plugin_extension_repository extends DokuWiki_Plugin {
* @param string $q the query string
* @return array a list of matching extensions
*/
- public function search($q){
- $query = $this->parse_query($q);
+ public function search($q)
+ {
+ $query = $this->parseQuery($q);
$query['fmt'] = 'php';
$httpclient = new DokuHTTPClient();
- $data = $httpclient->post(EXTENSION_REPOSITORY_API, $query);
+ $data = $httpclient->post(self::EXTENSION_REPOSITORY_API, $query);
if ($data === false) return array();
$result = unserialize($data);
$ids = array();
// store cache info for each extension
- foreach($result as $ext){
+ foreach ($result as $ext) {
$name = $ext['plugin'];
- $cache = new cache('##extension_manager##'.$name, '.repo');
+ $cache = new Cache('##extension_manager##'.$name, '.repo');
$cache->storeCache(serialize($ext));
$ids[] = $name;
}
@@ -145,7 +155,8 @@ class helper_plugin_extension_repository extends DokuWiki_Plugin {
* @param string $q
* @return array
*/
- protected function parse_query($q){
+ protected function parseQuery($q)
+ {
$parameters = array(
'tag' => array(),
'mail' => array(),
@@ -154,29 +165,29 @@ class helper_plugin_extension_repository extends DokuWiki_Plugin {
);
// extract tags
- if(preg_match_all('/(^|\s)(tag:([\S]+))/', $q, $matches, PREG_SET_ORDER)){
- foreach($matches as $m){
+ if (preg_match_all('/(^|\s)(tag:([\S]+))/', $q, $matches, PREG_SET_ORDER)) {
+ foreach ($matches as $m) {
$q = str_replace($m[2], '', $q);
$parameters['tag'][] = $m[3];
}
}
// extract author ids
- if(preg_match_all('/(^|\s)(authorid:([\S]+))/', $q, $matches, PREG_SET_ORDER)){
- foreach($matches as $m){
+ if (preg_match_all('/(^|\s)(authorid:([\S]+))/', $q, $matches, PREG_SET_ORDER)) {
+ foreach ($matches as $m) {
$q = str_replace($m[2], '', $q);
$parameters['mail'][] = $m[3];
}
}
// extract extensions
- if(preg_match_all('/(^|\s)(ext:([\S]+))/', $q, $matches, PREG_SET_ORDER)){
- foreach($matches as $m){
+ if (preg_match_all('/(^|\s)(ext:([\S]+))/', $q, $matches, PREG_SET_ORDER)) {
+ foreach ($matches as $m) {
$q = str_replace($m[2], '', $q);
$parameters['ext'][] = $m[3];
}
}
// extract types
- if(preg_match_all('/(^|\s)(type:([\S]+))/', $q, $matches, PREG_SET_ORDER)){
- foreach($matches as $m){
+ if (preg_match_all('/(^|\s)(type:([\S]+))/', $q, $matches, PREG_SET_ORDER)) {
+ foreach ($matches as $m) {
$q = str_replace($m[2], '', $q);
$parameters['type'][] = $m[3];
}
diff --git a/lib/plugins/info/syntax.php b/lib/plugins/info/syntax.php
index 773256faf..3fa35e733 100644
--- a/lib/plugins/info/syntax.php
+++ b/lib/plugins/info/syntax.php
@@ -6,33 +6,30 @@
* @author Andreas Gohr <andi@splitbrain.org>
* @author Esther Brunner <wikidesign@gmail.com>
*/
-// must be run within Dokuwiki
-if(!defined('DOKU_INC')) die();
-
-/**
- * All DokuWiki plugins to extend the parser/rendering mechanism
- * need to inherit from this class
- */
-class syntax_plugin_info extends DokuWiki_Syntax_Plugin {
+class syntax_plugin_info extends DokuWiki_Syntax_Plugin
+{
/**
* What kind of syntax are we?
*/
- function getType(){
+ public function getType()
+ {
return 'substition';
}
/**
* What about paragraphs?
*/
- function getPType(){
+ public function getPType()
+ {
return 'block';
}
/**
* Where to sort in?
*/
- function getSort(){
+ public function getSort()
+ {
return 155;
}
@@ -40,8 +37,9 @@ class syntax_plugin_info extends DokuWiki_Syntax_Plugin {
/**
* Connect pattern to lexer
*/
- function connectTo($mode) {
- $this->Lexer->addSpecialPattern('~~INFO:\w+~~',$mode,'plugin_info');
+ public function connectTo($mode)
+ {
+ $this->Lexer->addSpecialPattern('~~INFO:\w+~~', $mode, 'plugin_info');
}
/**
@@ -53,8 +51,9 @@ class syntax_plugin_info extends DokuWiki_Syntax_Plugin {
* @param Doku_Handler $handler The Doku_Handler object
* @return array Return an array with all data you want to use in render
*/
- function handle($match, $state, $pos, Doku_Handler $handler){
- $match = substr($match,7,-2); //strip ~~INFO: from start and ~~ from end
+ public function handle($match, $state, $pos, Doku_Handler $handler)
+ {
+ $match = substr($match, 7, -2); //strip ~~INFO: from start and ~~ from end
return array(strtolower($match));
}
@@ -66,40 +65,41 @@ class syntax_plugin_info extends DokuWiki_Syntax_Plugin {
* @param array $data data created by handler()
* @return boolean rendered correctly?
*/
- function render($format, Doku_Renderer $renderer, $data) {
- if($format == 'xhtml'){
+ public function render($format, Doku_Renderer $renderer, $data)
+ {
+ if ($format == 'xhtml') {
/** @var Doku_Renderer_xhtml $renderer */
//handle various info stuff
- switch ($data[0]){
+ switch ($data[0]) {
case 'syntaxmodes':
- $renderer->doc .= $this->_syntaxmodes_xhtml();
+ $renderer->doc .= $this->renderSyntaxModes();
break;
case 'syntaxtypes':
- $renderer->doc .= $this->_syntaxtypes_xhtml();
+ $renderer->doc .= $this->renderSyntaxTypes();
break;
case 'syntaxplugins':
- $this->_plugins_xhtml('syntax', $renderer);
+ $this->renderPlugins('syntax', $renderer);
break;
case 'adminplugins':
- $this->_plugins_xhtml('admin', $renderer);
+ $this->renderPlugins('admin', $renderer);
break;
case 'actionplugins':
- $this->_plugins_xhtml('action', $renderer);
+ $this->renderPlugins('action', $renderer);
break;
case 'rendererplugins':
- $this->_plugins_xhtml('renderer', $renderer);
+ $this->renderPlugins('renderer', $renderer);
break;
case 'helperplugins':
- $this->_plugins_xhtml('helper', $renderer);
+ $this->renderPlugins('helper', $renderer);
break;
case 'authplugins':
- $this->_plugins_xhtml('auth', $renderer);
+ $this->renderPlugins('auth', $renderer);
break;
case 'remoteplugins':
- $this->_plugins_xhtml('remote', $renderer);
+ $this->renderPlugins('remote', $renderer);
break;
case 'helpermethods':
- $this->_helpermethods_xhtml($renderer);
+ $this->renderHelperMethods($renderer);
break;
default:
$renderer->doc .= "no info about ".htmlspecialchars($data[0]);
@@ -117,7 +117,8 @@ class syntax_plugin_info extends DokuWiki_Syntax_Plugin {
* @param string $type
* @param Doku_Renderer_xhtml $renderer
*/
- function _plugins_xhtml($type, Doku_Renderer_xhtml $renderer){
+ protected function renderPlugins($type, Doku_Renderer_xhtml $renderer)
+ {
global $lang;
$renderer->doc .= '<ul>';
@@ -125,24 +126,24 @@ class syntax_plugin_info extends DokuWiki_Syntax_Plugin {
$plginfo = array();
// remove subparts
- foreach($plugins as $p){
- if (!$po = plugin_load($type,$p)) continue;
- list($name,/* $part */) = explode('_',$p,2);
+ foreach ($plugins as $p) {
+ if (!$po = plugin_load($type, $p)) continue;
+ list($name,/* $part */) = explode('_', $p, 2);
$plginfo[$name] = $po->getInfo();
}
// list them
- foreach($plginfo as $info){
+ foreach ($plginfo as $info) {
$renderer->doc .= '<li><div class="li">';
- $renderer->externallink($info['url'],$info['name']);
+ $renderer->externallink($info['url'], $info['name']);
$renderer->doc .= ' ';
$renderer->doc .= '<em>'.$info['date'].'</em>';
$renderer->doc .= ' ';
$renderer->doc .= $lang['by'];
$renderer->doc .= ' ';
- $renderer->emaillink($info['email'],$info['author']);
+ $renderer->emaillink($info['email'], $info['author']);
$renderer->doc .= '<br />';
- $renderer->doc .= strtr(hsc($info['desc']),array("\n"=>"<br />"));
+ $renderer->doc .= strtr(hsc($info['desc']), array("\n"=>"<br />"));
$renderer->doc .= '</div></li>';
unset($po);
}
@@ -157,39 +158,40 @@ class syntax_plugin_info extends DokuWiki_Syntax_Plugin {
*
* @param Doku_Renderer_xhtml $renderer
*/
- function _helpermethods_xhtml(Doku_Renderer_xhtml $renderer){
+ protected function renderHelperMethods(Doku_Renderer_xhtml $renderer)
+ {
$plugins = plugin_list('helper');
- foreach($plugins as $p){
- if (!$po = plugin_load('helper',$p)) continue;
+ foreach ($plugins as $p) {
+ if (!$po = plugin_load('helper', $p)) continue;
if (!method_exists($po, 'getMethods')) continue;
$methods = $po->getMethods();
$info = $po->getInfo();
- $hid = $this->_addToTOC($info['name'], 2, $renderer);
+ $hid = $this->addToToc($info['name'], 2, $renderer);
$doc = '<h2><a name="'.$hid.'" id="'.$hid.'">'.hsc($info['name']).'</a></h2>';
$doc .= '<div class="level2">';
$doc .= '<p>'.strtr(hsc($info['desc']), array("\n"=>"<br />")).'</p>';
$doc .= '<pre class="code">$'.$p." = plugin_load('helper', '".$p."');</pre>";
$doc .= '</div>';
- foreach ($methods as $method){
+ foreach ($methods as $method) {
$title = '$'.$p.'->'.$method['name'].'()';
- $hid = $this->_addToTOC($title, 3, $renderer);
+ $hid = $this->addToToc($title, 3, $renderer);
$doc .= '<h3><a name="'.$hid.'" id="'.$hid.'">'.hsc($title).'</a></h3>';
$doc .= '<div class="level3">';
$doc .= '<div class="table"><table class="inline"><tbody>';
$doc .= '<tr><th>Description</th><td colspan="2">'.$method['desc'].
'</td></tr>';
- if ($method['params']){
+ if ($method['params']) {
$c = count($method['params']);
$doc .= '<tr><th rowspan="'.$c.'">Parameters</th><td>';
$params = array();
- foreach ($method['params'] as $desc => $type){
+ foreach ($method['params'] as $desc => $type) {
$params[] = hsc($desc).'</td><td>'.hsc($type);
}
$doc .= join($params, '</td></tr><tr><td>').'</td></tr>';
}
- if ($method['return']){
+ if ($method['return']) {
$doc .= '<tr><th>Return value</th><td>'.hsc(key($method['return'])).
'</td><td>'.hsc(current($method['return'])).'</td></tr>';
}
@@ -207,18 +209,19 @@ class syntax_plugin_info extends DokuWiki_Syntax_Plugin {
*
* @return string
*/
- function _syntaxtypes_xhtml(){
+ protected function renderSyntaxTypes()
+ {
global $PARSER_MODES;
$doc = '';
$doc .= '<div class="table"><table class="inline"><tbody>';
- foreach($PARSER_MODES as $mode => $modes){
+ foreach ($PARSER_MODES as $mode => $modes) {
$doc .= '<tr>';
$doc .= '<td class="leftalign">';
$doc .= $mode;
$doc .= '</td>';
$doc .= '<td class="leftalign">';
- $doc .= join(', ',$modes);
+ $doc .= join(', ', $modes);
$doc .= '</td>';
$doc .= '</tr>';
}
@@ -231,29 +234,30 @@ class syntax_plugin_info extends DokuWiki_Syntax_Plugin {
*
* @return string
*/
- function _syntaxmodes_xhtml(){
+ protected function renderSyntaxModes()
+ {
$modes = p_get_parsermodes();
$compactmodes = array();
- foreach($modes as $mode){
+ foreach ($modes as $mode) {
$compactmodes[$mode['sort']][] = $mode['mode'];
}
$doc = '';
$doc .= '<div class="table"><table class="inline"><tbody>';
- foreach($compactmodes as $sort => $modes){
+ foreach ($compactmodes as $sort => $modes) {
$rowspan = '';
- if(count($modes) > 1) {
+ if (count($modes) > 1) {
$rowspan = ' rowspan="'.count($modes).'"';
}
- foreach($modes as $index => $mode) {
+ foreach ($modes as $index => $mode) {
$doc .= '<tr>';
$doc .= '<td class="leftalign">';
$doc .= $mode;
$doc .= '</td>';
- if($index === 0) {
+ if ($index === 0) {
$doc .= '<td class="rightalign" '.$rowspan.'>';
$doc .= $sort;
$doc .= '</td>';
@@ -274,11 +278,12 @@ class syntax_plugin_info extends DokuWiki_Syntax_Plugin {
* @param Doku_Renderer_xhtml $renderer
* @return string
*/
- protected function _addToTOC($text, $level, Doku_Renderer_xhtml $renderer){
+ protected function addToToc($text, $level, Doku_Renderer_xhtml $renderer)
+ {
global $conf;
$hid = '';
- if (($level >= $conf['toptoclevel']) && ($level <= $conf['maxtoclevel'])){
+ if (($level >= $conf['toptoclevel']) && ($level <= $conf['maxtoclevel'])) {
$hid = $renderer->_headerToLink($text, true);
$renderer->toc[] = array(
'hid' => $hid,
diff --git a/lib/plugins/popularity/action.php b/lib/plugins/popularity/action.php
index d5ec0f5c5..fac610735 100644
--- a/lib/plugins/popularity/action.php
+++ b/lib/plugins/popularity/action.php
@@ -5,44 +5,49 @@
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
*/
-require_once(DOKU_PLUGIN.'action.php');
-require_once(DOKU_PLUGIN.'popularity/admin.php');
-
-class action_plugin_popularity extends Dokuwiki_Action_Plugin {
+class action_plugin_popularity extends DokuWiki_Action_Plugin
+{
/**
* @var helper_plugin_popularity
*/
- var $helper;
+ protected $helper;
- function __construct(){
+ public function __construct()
+ {
$this->helper = $this->loadHelper('popularity', false);
}
- /**
- * Register its handlers with the dokuwiki's event controller
- */
- function register(Doku_Event_Handler $controller) {
- $controller->register_hook('INDEXER_TASKS_RUN', 'AFTER', $this, '_autosubmit', array());
+ /** @inheritdoc */
+ public function register(Doku_Event_Handler $controller)
+ {
+ $controller->register_hook('INDEXER_TASKS_RUN', 'AFTER', $this, 'autosubmit', array());
}
- function _autosubmit(Doku_Event &$event, $param){
+ /**
+ * Event handler
+ *
+ * @param Doku_Event $event
+ * @param $param
+ */
+ public function autosubmit(Doku_Event &$event, $param)
+ {
//Do we have to send the data now
- if ( !$this->helper->isAutosubmitEnabled() || $this->_isTooEarlyToSubmit() ){
+ if (!$this->helper->isAutosubmitEnabled() || $this->isTooEarlyToSubmit()) {
return;
}
//Actually send it
- $status = $this->helper->sendData( $this->helper->gatherAsString() );
+ $status = $this->helper->sendData($this->helper->gatherAsString());
- if ( $status !== '' ){
+ if ($status !== '') {
//If an error occured, log it
- io_saveFile( $this->helper->autosubmitErrorFile, $status );
+ io_saveFile($this->helper->autosubmitErrorFile, $status);
} else {
//If the data has been sent successfully, previous log of errors are useless
@unlink($this->helper->autosubmitErrorFile);
//Update the last time we sent data
- touch ( $this->helper->autosubmitFile );
+ touch($this->helper->autosubmitFile);
}
$event->stopPropagation();
@@ -53,7 +58,8 @@ class action_plugin_popularity extends Dokuwiki_Action_Plugin {
* Check if it's time to send autosubmit data
* (we should have check if autosubmit is enabled first)
*/
- function _isTooEarlyToSubmit(){
+ protected function isTooEarlyToSubmit()
+ {
$lastSubmit = $this->helper->lastSentTime();
return $lastSubmit + 24*60*60*30 > time();
}
diff --git a/lib/plugins/popularity/admin.php b/lib/plugins/popularity/admin.php
index 0cf174e0d..61d8cc3bf 100644
--- a/lib/plugins/popularity/admin.php
+++ b/lib/plugins/popularity/admin.php
@@ -5,43 +5,44 @@
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
* @author Andreas Gohr <andi@splitbrain.org>
*/
-// must be run within Dokuwiki
-if(!defined('DOKU_INC')) die();
+class admin_plugin_popularity extends DokuWiki_Admin_Plugin
+{
-/**
- * All DokuWiki plugins to extend the admin function
- * need to inherit from this class
- */
-class admin_plugin_popularity extends DokuWiki_Admin_Plugin {
+ /** @var helper_plugin_popularity */
+ protected $helper;
+ protected $sentStatus = null;
/**
- * @var helper_plugin_popularity
+ * admin_plugin_popularity constructor.
*/
- var $helper;
- var $sentStatus = null;
-
- function __construct(){
+ public function __construct()
+ {
$this->helper = $this->loadHelper('popularity', false);
}
/**
* return prompt for admin menu
+ * @param $language
+ * @return string
*/
- function getMenuText($language) {
+ public function getMenuText($language)
+ {
return $this->getLang('name');
}
/**
* return sort order for position in admin menu
*/
- function getMenuSort() {
+ public function getMenuSort()
+ {
return 2000;
}
/**
* Accessible for managers
*/
- function forAdminOnly() {
+ public function forAdminOnly()
+ {
return false;
}
@@ -49,18 +50,19 @@ class admin_plugin_popularity extends DokuWiki_Admin_Plugin {
/**
* handle user request
*/
- function handle() {
+ public function handle()
+ {
global $INPUT;
//Send the data
- if ( $INPUT->has('data') ){
- $this->sentStatus = $this->helper->sendData( $INPUT->str('data') );
- if ( $this->sentStatus === '' ){
+ if ($INPUT->has('data')) {
+ $this->sentStatus = $this->helper->sendData($INPUT->str('data'));
+ if ($this->sentStatus === '') {
//Update the last time we sent the data
- touch ( $this->helper->popularityLastSubmitFile );
+ touch($this->helper->popularityLastSubmitFile);
}
//Deal with the autosubmit option
- $this->_enableAutosubmit( $INPUT->has('autosubmit') );
+ $this->enableAutosubmit($INPUT->has('autosubmit'));
}
}
@@ -68,9 +70,10 @@ class admin_plugin_popularity extends DokuWiki_Admin_Plugin {
* Enable or disable autosubmit
* @param bool $enable If TRUE, it will enable autosubmit. Else, it will disable it.
*/
- function _enableAutosubmit( $enable ){
- if ( $enable ){
- io_saveFile( $this->helper->autosubmitFile, ' ');
+ protected function enableAutosubmit($enable)
+ {
+ if ($enable) {
+ io_saveFile($this->helper->autosubmitFile, ' ');
} else {
@unlink($this->helper->autosubmitFile);
}
@@ -79,17 +82,18 @@ class admin_plugin_popularity extends DokuWiki_Admin_Plugin {
/**
* Output HTML form
*/
- function html() {
+ public function html()
+ {
global $INPUT;
- if ( ! $INPUT->has('data') ){
+ if (! $INPUT->has('data')) {
echo $this->locale_xhtml('intro');
//If there was an error the last time we tried to autosubmit, warn the user
- if ( $this->helper->isAutoSubmitEnabled() ){
- if ( file_exists($this->helper->autosubmitErrorFile) ){
+ if ($this->helper->isAutoSubmitEnabled()) {
+ if (file_exists($this->helper->autosubmitErrorFile)) {
echo $this->getLang('autosubmitError');
- echo io_readFile( $this->helper->autosubmitErrorFile );
+ echo io_readFile($this->helper->autosubmitErrorFile);
}
}
@@ -98,12 +102,12 @@ class admin_plugin_popularity extends DokuWiki_Admin_Plugin {
//Print the last time the data was sent
$lastSent = $this->helper->lastSentTime();
- if ( $lastSent !== 0 ){
+ if ($lastSent !== 0) {
echo $this->getLang('lastSent') . ' ' . datetime_h($lastSent);
}
} else {
//If we just submitted the form
- if ( $this->sentStatus === '' ){
+ if ($this->sentStatus === '') {
//If we successfully sent the data
echo $this->locale_xhtml('submitted');
} else {
@@ -122,9 +126,10 @@ class admin_plugin_popularity extends DokuWiki_Admin_Plugin {
* @param string $data The popularity data, if it has already been computed. NULL otherwise.
* @return string The form, as an html string
*/
- function buildForm($submissionMode, $data = null){
+ protected function buildForm($submissionMode, $data = null)
+ {
$url = ($submissionMode === 'browser' ? $this->helper->submitUrl : script());
- if ( is_null($data) ){
+ if (is_null($data)) {
$data = $this->helper->gatherAsString();
}
@@ -135,7 +140,7 @@ class admin_plugin_popularity extends DokuWiki_Admin_Plugin {
.'</textarea><br />';
//If we submit via the server, we give the opportunity to suscribe to the autosubmission option
- if ( $submissionMode !== 'browser' ){
+ if ($submissionMode !== 'browser') {
$form .= '<label for="autosubmit">'
.'<input type="checkbox" name="autosubmit" id="autosubmit" '
.($this->helper->isAutosubmitEnabled() ? 'checked' : '' )
diff --git a/lib/plugins/popularity/helper.php b/lib/plugins/popularity/helper.php
index b81ab7005..4537976ae 100644
--- a/lib/plugins/popularity/helper.php
+++ b/lib/plugins/popularity/helper.php
@@ -1,36 +1,43 @@
<?php
+
+use dokuwiki\HTTP\DokuHTTPClient;
+use dokuwiki\Extension\Event;
+
/**
* Popularity Feedback Plugin
*
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
*/
-
-class helper_plugin_popularity extends Dokuwiki_Plugin {
+class helper_plugin_popularity extends Dokuwiki_Plugin
+{
/**
* The url where the data should be sent
*/
- var $submitUrl = 'http://update.dokuwiki.org/popularity.php';
+ public $submitUrl = 'http://update.dokuwiki.org/popularity.php';
/**
* Name of the file which determine if the the autosubmit is enabled,
* and when it was submited for the last time
*/
- var $autosubmitFile;
+ public $autosubmitFile;
/**
* File where the last error which happened when we tried to autosubmit, will be log
*/
- var $autosubmitErrorFile;
+ public $autosubmitErrorFile;
/**
* Name of the file which determine when the popularity data was manually
* submitted for the last time
* (If this file doesn't exist, the data has never been sent)
*/
- var $popularityLastSubmitFile;
+ public $popularityLastSubmitFile;
-
- function __construct(){
+ /**
+ * helper_plugin_popularity constructor.
+ */
+ public function __construct()
+ {
global $conf;
$this->autosubmitFile = $conf['cachedir'].'/autosubmit.txt';
$this->autosubmitErrorFile = $conf['cachedir'].'/autosubmitError.txt';
@@ -38,46 +45,12 @@ class helper_plugin_popularity extends Dokuwiki_Plugin {
}
/**
- * Return methods of this helper
- *
- * @return array with methods description
- */
- function getMethods(){
- $result = array();
- $result[] = array(
- 'name' => 'isAutoSubmitEnabled',
- 'desc' => 'Check if autosubmit is enabled',
- 'params' => array(),
- 'return' => array('result' => 'bool')
- );
- $result[] = array(
- 'name' => 'sendData',
- 'desc' => 'Send the popularity data',
- 'params' => array('data' => 'string'),
- 'return' => array()
- );
- $result[] = array(
- 'name' => 'gatherAsString',
- 'desc' => 'Gather the popularity data',
- 'params' => array(),
- 'return' => array('data' => 'string')
- );
- $result[] = array(
- 'name' => 'lastSentTime',
- 'desc' => 'Compute the last time popularity data was sent',
- 'params' => array(),
- 'return' => array('data' => 'int')
- );
- return $result;
-
- }
-
- /**
* Check if autosubmit is enabled
*
* @return boolean TRUE if we should send data once a month, FALSE otherwise
*/
- function isAutoSubmitEnabled(){
+ public function isAutoSubmitEnabled()
+ {
return file_exists($this->autosubmitFile);
}
@@ -87,11 +60,12 @@ class helper_plugin_popularity extends Dokuwiki_Plugin {
* @param string $data The popularity data
* @return string An empty string if everything worked fine, a string describing the error otherwise
*/
- function sendData($data){
+ public function sendData($data)
+ {
$error = '';
$httpClient = new DokuHTTPClient();
$status = $httpClient->sendRequest($this->submitUrl, array('data' => $data), 'POST');
- if ( ! $status ){
+ if (! $status) {
$error = $httpClient->error;
}
return $error;
@@ -102,7 +76,8 @@ class helper_plugin_popularity extends Dokuwiki_Plugin {
*
* @return int
*/
- function lastSentTime(){
+ public function lastSentTime()
+ {
$manualSubmission = @filemtime($this->popularityLastSubmitFile);
$autoSubmission = @filemtime($this->autosubmitFile);
@@ -114,13 +89,14 @@ class helper_plugin_popularity extends Dokuwiki_Plugin {
*
* @return string The popularity data as a string
*/
- function gatherAsString(){
- $data = $this->_gather();
+ public function gatherAsString()
+ {
+ $data = $this->gather();
$string = '';
- foreach($data as $key => $val){
- if(is_array($val)) foreach($val as $v){
+ foreach ($data as $key => $val) {
+ if (is_array($val)) foreach ($val as $v) {
$string .= hsc($key)."\t".hsc($v)."\n";
- }else{
+ } else {
$string .= hsc($key)."\t".hsc($val)."\n";
}
}
@@ -132,7 +108,8 @@ class helper_plugin_popularity extends Dokuwiki_Plugin {
*
* @return array The popularity data as an array
*/
- function _gather(){
+ protected function gather()
+ {
global $conf;
/** @var $auth DokuWiki_Auth_Plugin */
global $auth;
@@ -156,81 +133,81 @@ class helper_plugin_popularity extends Dokuwiki_Plugin {
// number and size of pages
$list = array();
- search($list,$conf['datadir'],array($this,'_search_count'),array('all'=>false),'');
+ search($list, $conf['datadir'], array($this, 'searchCountCallback'), array('all'=>false), '');
$data['page_count'] = $list['file_count'];
$data['page_size'] = $list['file_size'];
$data['page_biggest'] = $list['file_max'];
$data['page_smallest'] = $list['file_min'];
$data['page_nscount'] = $list['dir_count'];
$data['page_nsnest'] = $list['dir_nest'];
- if($list['file_count']) $data['page_avg'] = $list['file_size'] / $list['file_count'];
+ if ($list['file_count']) $data['page_avg'] = $list['file_size'] / $list['file_count'];
$data['page_oldest'] = $list['file_oldest'];
unset($list);
// number and size of media
$list = array();
- search($list,$conf['mediadir'],array($this,'_search_count'),array('all'=>true));
+ search($list, $conf['mediadir'], array($this, 'searchCountCallback'), array('all'=>true));
$data['media_count'] = $list['file_count'];
$data['media_size'] = $list['file_size'];
$data['media_biggest'] = $list['file_max'];
$data['media_smallest'] = $list['file_min'];
$data['media_nscount'] = $list['dir_count'];
$data['media_nsnest'] = $list['dir_nest'];
- if($list['file_count']) $data['media_avg'] = $list['file_size'] / $list['file_count'];
+ if ($list['file_count']) $data['media_avg'] = $list['file_size'] / $list['file_count'];
unset($list);
// number and size of cache
$list = array();
- search($list,$conf['cachedir'],array($this,'_search_count'),array('all'=>true));
+ search($list, $conf['cachedir'], array($this, 'searchCountCallback'), array('all'=>true));
$data['cache_count'] = $list['file_count'];
$data['cache_size'] = $list['file_size'];
$data['cache_biggest'] = $list['file_max'];
$data['cache_smallest'] = $list['file_min'];
- if($list['file_count']) $data['cache_avg'] = $list['file_size'] / $list['file_count'];
+ if ($list['file_count']) $data['cache_avg'] = $list['file_size'] / $list['file_count'];
unset($list);
// number and size of index
$list = array();
- search($list,$conf['indexdir'],array($this,'_search_count'),array('all'=>true));
+ search($list, $conf['indexdir'], array($this, 'searchCountCallback'), array('all'=>true));
$data['index_count'] = $list['file_count'];
$data['index_size'] = $list['file_size'];
$data['index_biggest'] = $list['file_max'];
$data['index_smallest'] = $list['file_min'];
- if($list['file_count']) $data['index_avg'] = $list['file_size'] / $list['file_count'];
+ if ($list['file_count']) $data['index_avg'] = $list['file_size'] / $list['file_count'];
unset($list);
// number and size of meta
$list = array();
- search($list,$conf['metadir'],array($this,'_search_count'),array('all'=>true));
+ search($list, $conf['metadir'], array($this, 'searchCountCallback'), array('all'=>true));
$data['meta_count'] = $list['file_count'];
$data['meta_size'] = $list['file_size'];
$data['meta_biggest'] = $list['file_max'];
$data['meta_smallest'] = $list['file_min'];
- if($list['file_count']) $data['meta_avg'] = $list['file_size'] / $list['file_count'];
+ if ($list['file_count']) $data['meta_avg'] = $list['file_size'] / $list['file_count'];
unset($list);
// number and size of attic
$list = array();
- search($list,$conf['olddir'],array($this,'_search_count'),array('all'=>true));
+ search($list, $conf['olddir'], array($this, 'searchCountCallback'), array('all'=>true));
$data['attic_count'] = $list['file_count'];
$data['attic_size'] = $list['file_size'];
$data['attic_biggest'] = $list['file_max'];
$data['attic_smallest'] = $list['file_min'];
- if($list['file_count']) $data['attic_avg'] = $list['file_size'] / $list['file_count'];
+ if ($list['file_count']) $data['attic_avg'] = $list['file_size'] / $list['file_count'];
$data['attic_oldest'] = $list['file_oldest'];
unset($list);
// user count
- if($auth && $auth->canDo('getUserCount')){
+ if ($auth && $auth->canDo('getUserCount')) {
$data['user_count'] = $auth->getUserCount();
}
// calculate edits per day
$list = @file($conf['metadir'].'/_dokuwiki.changes');
$count = count($list);
- if($count > 2){
- $first = (int) substr(array_shift($list),0,10);
- $last = (int) substr(array_pop($list),0,10);
+ if ($count > 2) {
+ $first = (int) substr(array_shift($list), 0, 10);
+ $last = (int) substr(array_pop($list), 0, 10);
$dur = ($last - $first)/(60*60*24); // number of days in the changelog
$data['edits_per_day'] = $count/$dur;
}
@@ -240,7 +217,7 @@ class helper_plugin_popularity extends Dokuwiki_Plugin {
$data['plugin'] = plugin_list();
// pcre info
- if(defined('PCRE_VERSION')) $data['pcre_version'] = PCRE_VERSION;
+ if (defined('PCRE_VERSION')) $data['pcre_version'] = PCRE_VERSION;
$data['pcre_backtrack'] = ini_get('pcre.backtrack_limit');
$data['pcre_recursion'] = ini_get('pcre.recursion_limit');
@@ -249,27 +226,33 @@ class helper_plugin_popularity extends Dokuwiki_Plugin {
$data['webserver'] = $_SERVER['SERVER_SOFTWARE'];
$data['php_version'] = phpversion();
$data['php_sapi'] = php_sapi_name();
- $data['php_memory'] = $this->_to_byte(ini_get('memory_limit'));
+ $data['php_memory'] = php_to_byte(ini_get('memory_limit'));
$data['php_exectime'] = $phptime;
$data['php_extension'] = get_loaded_extensions();
// plugin usage data
- $this->_add_plugin_usage_data($data);
+ $this->addPluginUsageData($data);
return $data;
}
- protected function _add_plugin_usage_data(&$data){
+ /**
+ * Triggers event to let plugins add their own data
+ *
+ * @param $data
+ */
+ protected function addPluginUsageData(&$data)
+ {
$pluginsData = array();
- trigger_event('PLUGIN_POPULARITY_DATA_SETUP', $pluginsData);
- foreach($pluginsData as $plugin => $d){
- if ( is_array($d) ) {
- foreach($d as $key => $value){
- $data['plugin_' . $plugin . '_' . $key] = $value;
- }
- } else {
- $data['plugin_' . $plugin] = $d;
- }
+ Event::createAndTrigger('PLUGIN_POPULARITY_DATA_SETUP', $pluginsData);
+ foreach ($pluginsData as $plugin => $d) {
+ if (is_array($d)) {
+ foreach ($d as $key => $value) {
+ $data['plugin_' . $plugin . '_' . $key] = $value;
+ }
+ } else {
+ $data['plugin_' . $plugin] = $d;
+ }
}
}
@@ -284,57 +267,26 @@ class helper_plugin_popularity extends Dokuwiki_Plugin {
* @param array $opts option array as given to search()
* @return bool
*/
- function _search_count(&$data,$base,$file,$type,$lvl,$opts){
+ public function searchCountCallback(&$data, $base, $file, $type, $lvl, $opts)
+ {
// traverse
- if($type == 'd'){
- if($data['dir_nest'] < $lvl) $data['dir_nest'] = $lvl;
+ if ($type == 'd') {
+ if ($data['dir_nest'] < $lvl) $data['dir_nest'] = $lvl;
$data['dir_count']++;
return true;
}
//only search txt files if 'all' option not set
- if($opts['all'] || substr($file,-4) == '.txt'){
+ if ($opts['all'] || substr($file, -4) == '.txt') {
$size = filesize($base.'/'.$file);
$date = filemtime($base.'/'.$file);
$data['file_count']++;
$data['file_size'] += $size;
- if(!isset($data['file_min']) || $data['file_min'] > $size) $data['file_min'] = $size;
- if($data['file_max'] < $size) $data['file_max'] = $size;
- if(!isset($data['file_oldest']) || $data['file_oldest'] > $date) $data['file_oldest'] = $date;
+ if (!isset($data['file_min']) || $data['file_min'] > $size) $data['file_min'] = $size;
+ if ($data['file_max'] < $size) $data['file_max'] = $size;
+ if (!isset($data['file_oldest']) || $data['file_oldest'] > $date) $data['file_oldest'] = $date;
}
return false;
}
-
- /**
- * Convert php.ini shorthands to byte
- *
- * @author <gilthans dot NO dot SPAM at gmail dot com>
- * @link http://php.net/manual/en/ini.core.php#79564
- *
- * @param string $v
- * @return int|string
- */
- function _to_byte($v){
- $l = substr($v, -1);
- $ret = substr($v, 0, -1);
- switch(strtoupper($l)){
- /** @noinspection PhpMissingBreakStatementInspection */
- case 'P':
- $ret *= 1024;
- /** @noinspection PhpMissingBreakStatementInspection */
- case 'T':
- $ret *= 1024;
- /** @noinspection PhpMissingBreakStatementInspection */
- case 'G':
- $ret *= 1024;
- /** @noinspection PhpMissingBreakStatementInspection */
- case 'M':
- $ret *= 1024;
- case 'K':
- $ret *= 1024;
- break;
- }
- return $ret;
- }
}
diff --git a/lib/plugins/remote.php b/lib/plugins/remote.php
index c2253dbd5..a3cbec722 100644
--- a/lib/plugins/remote.php
+++ b/lib/plugins/remote.php
@@ -1,104 +1,2 @@
<?php
-
-/**
- * Class DokuWiki_Remote_Plugin
- */
-abstract class DokuWiki_Remote_Plugin extends DokuWiki_Plugin {
-
- private $api;
-
- /**
- * Constructor
- */
- public function __construct() {
- $this->api = new RemoteAPI();
- }
-
- /**
- * Get all available methods with remote access.
- *
- * By default it exports all public methods of a remote plugin. Methods beginning
- * with an underscore are skipped.
- *
- * @return array Information about all provided methods. {@see RemoteAPI}.
- */
- public function _getMethods() {
- $result = array();
-
- $reflection = new \ReflectionClass($this);
- foreach($reflection->getMethods(ReflectionMethod::IS_PUBLIC) as $method) {
- // skip parent methods, only methods further down are exported
- $declaredin = $method->getDeclaringClass()->name;
- if($declaredin == 'DokuWiki_Plugin' || $declaredin == 'DokuWiki_Remote_Plugin') continue;
- $method_name = $method->name;
- if(substr($method_name, 0, 1) == '_') continue;
-
- // strip asterisks
- $doc = $method->getDocComment();
- $doc = preg_replace(
- array('/^[ \t]*\/\*+[ \t]*/m', '/[ \t]*\*+[ \t]*/m', '/\*+\/\s*$/m','/\s*\/\s*$/m'),
- array('', '', '', ''),
- $doc
- );
-
- // prepare data
- $data = array();
- $data['name'] = $method_name;
- $data['public'] = 0;
- $data['doc'] = $doc;
- $data['args'] = array();
-
- // get parameter type from doc block type hint
- foreach($method->getParameters() as $parameter) {
- $name = $parameter->name;
- $type = 'string'; // we default to string
- if(preg_match('/^@param[ \t]+([\w|\[\]]+)[ \t]\$'.$name.'/m', $doc, $m)){
- $type = $this->cleanTypeHint($m[1]);
- }
- $data['args'][] = $type;
- }
-
- // get return type from doc block type hint
- if(preg_match('/^@return[ \t]+([\w|\[\]]+)/m', $doc, $m)){
- $data['return'] = $this->cleanTypeHint($m[1]);
- } else {
- $data['return'] = 'string';
- }
-
- // add to result
- $result[$method_name] = $data;
- }
-
- return $result;
- }
-
- /**
- * Matches the given type hint against the valid options for the remote API
- *
- * @param string $hint
- * @return string
- */
- protected function cleanTypeHint($hint) {
- $types = explode('|', $hint);
- foreach($types as $t) {
- if(substr($t, -2) == '[]') {
- return 'array';
- }
- if($t == 'boolean') {
- return 'bool';
- }
- if(in_array($t, array('array', 'string', 'int', 'double', 'bool', 'null', 'date', 'file'))) {
- return $t;
- }
- }
- return 'string';
- }
-
- /**
- * @return RemoteAPI
- */
- protected function getApi() {
- return $this->api;
- }
-
-}
+dbg_deprecated('Autoloading. Do not require() files yourself.');
diff --git a/lib/plugins/revert/admin.php b/lib/plugins/revert/admin.php
index 1a0300585..2d11dc05a 100644
--- a/lib/plugins/revert/admin.php
+++ b/lib/plugins/revert/admin.php
@@ -1,66 +1,73 @@
<?php
-// must be run within Dokuwiki
-if(!defined('DOKU_INC')) die();
+
+use dokuwiki\ChangeLog\PageChangeLog;
/**
* All DokuWiki plugins to extend the admin function
* need to inherit from this class
*/
-class admin_plugin_revert extends DokuWiki_Admin_Plugin {
- var $cmd;
+class admin_plugin_revert extends DokuWiki_Admin_Plugin
+{
+ protected $cmd;
// some vars which might need tuning later
- var $max_lines = 800; // lines to read from changelog
- var $max_revs = 20; // numer of old revisions to check
+ protected $max_lines = 800; // lines to read from changelog
+ protected $max_revs = 20; // numer of old revisions to check
/**
* Constructor
*/
- function __construct(){
+ public function __construct()
+ {
$this->setupLocale();
}
/**
* access for managers
*/
- function forAdminOnly(){
+ public function forAdminOnly()
+ {
return false;
}
/**
* return sort order for position in admin menu
*/
- function getMenuSort() {
+ public function getMenuSort()
+ {
return 40;
}
/**
* handle user request
*/
- function handle() {
+ public function handle()
+ {
}
/**
* output appropriate html
*/
- function html() {
+ public function html()
+ {
global $INPUT;
echo $this->locale_xhtml('intro');
- $this->_searchform();
+ $this->printSearchForm();
- if(is_array($INPUT->param('revert')) && checkSecurityToken()){
- $this->_revert($INPUT->arr('revert'),$INPUT->str('filter'));
- }elseif($INPUT->has('filter')){
- $this->_list($INPUT->str('filter'));
+ if (is_array($INPUT->param('revert')) && checkSecurityToken()) {
+ $this->revertEdits($INPUT->arr('revert'), $INPUT->str('filter'));
+ } elseif ($INPUT->has('filter')) {
+ $this->listEdits($INPUT->str('filter'));
}
}
/**
* Display the form for searching spam pages
*/
- function _searchform(){
+ protected function printSearchForm()
+ {
global $lang, $INPUT;
echo '<form action="" method="post"><div class="no">';
echo '<label>'.$this->getLang('filter').': </label>';
@@ -73,31 +80,32 @@ class admin_plugin_revert extends DokuWiki_Admin_Plugin {
/**
* Start the reversion process
*/
- function _revert($revert,$filter){
+ protected function revertEdits($revert, $filter)
+ {
echo '<hr /><br />';
echo '<p>'.$this->getLang('revstart').'</p>';
echo '<ul>';
- foreach($revert as $id){
+ foreach ($revert as $id) {
global $REV;
// find the last non-spammy revision
$data = '';
$pagelog = new PageChangeLog($id);
$old = $pagelog->getRevisions(0, $this->max_revs);
- if(count($old)){
- foreach($old as $REV){
- $data = rawWiki($id,$REV);
- if(strpos($data,$filter) === false) break;
+ if (count($old)) {
+ foreach ($old as $REV) {
+ $data = rawWiki($id, $REV);
+ if (strpos($data, $filter) === false) break;
}
}
- if($data){
- saveWikiText($id,$data,'old revision restored',false);
- printf('<li><div class="li">'.$this->getLang('reverted').'</div></li>',$id,$REV);
- }else{
- saveWikiText($id,'','',false);
- printf('<li><div class="li">'.$this->getLang('removed').'</div></li>',$id);
+ if ($data) {
+ saveWikiText($id, $data, 'old revision restored', false);
+ printf('<li><div class="li">'.$this->getLang('reverted').'</div></li>', $id, $REV);
+ } else {
+ saveWikiText($id, '', '', false);
+ printf('<li><div class="li">'.$this->getLang('removed').'</div></li>', $id);
}
@set_time_limit(10);
flush();
@@ -110,7 +118,8 @@ class admin_plugin_revert extends DokuWiki_Admin_Plugin {
/**
* List recent edits matching the given filter
*/
- function _list($filter){
+ protected function listEdits($filter)
+ {
global $conf;
global $lang;
echo '<hr /><br />';
@@ -118,13 +127,13 @@ class admin_plugin_revert extends DokuWiki_Admin_Plugin {
echo '<input type="hidden" name="filter" value="'.hsc($filter).'" />';
formSecurityToken();
- $recents = getRecents(0,$this->max_lines);
+ $recents = getRecents(0, $this->max_lines);
echo '<ul>';
$cnt = 0;
- foreach($recents as $recent){
- if($filter){
- if(strpos(rawWiki($recent['id']),$filter) === false) continue;
+ foreach ($recents as $recent) {
+ if ($filter) {
+ if (strpos(rawWiki($recent['id']), $filter) === false) continue;
}
$cnt++;
@@ -132,10 +141,11 @@ class admin_plugin_revert extends DokuWiki_Admin_Plugin {
echo ($recent['type']===DOKU_CHANGE_TYPE_MINOR_EDIT) ? '<li class="minor">' : '<li>';
echo '<div class="li">';
- echo '<input type="checkbox" name="revert[]" value="'.hsc($recent['id']).'" checked="checked" id="revert__'.$cnt.'" />';
+ echo '<input type="checkbox" name="revert[]" value="'.hsc($recent['id']).
+ '" checked="checked" id="revert__'.$cnt.'" />';
echo ' <label for="revert__'.$cnt.'">'.$date.'</label> ';
- echo '<a href="'.wl($recent['id'],"do=diff").'">';
+ echo '<a href="'.wl($recent['id'], "do=diff").'">';
$p = array();
$p['src'] = DOKU_BASE.'lib/images/diff.png';
$p['width'] = 15;
@@ -146,7 +156,7 @@ class admin_plugin_revert extends DokuWiki_Admin_Plugin {
echo "<img $att />";
echo '</a> ';
- echo '<a href="'.wl($recent['id'],"do=revisions").'">';
+ echo '<a href="'.wl($recent['id'], "do=revisions").'">';
$p = array();
$p['src'] = DOKU_BASE.'lib/images/history.png';
$p['width'] = 12;
@@ -157,7 +167,7 @@ class admin_plugin_revert extends DokuWiki_Admin_Plugin {
echo "<img $att />";
echo '</a> ';
- echo html_wikilink(':'.$recent['id'],(useHeading('navigation'))?null:$recent['id']);
+ echo html_wikilink(':'.$recent['id'], (useHeading('navigation'))?null:$recent['id']);
echo ' – '.htmlspecialchars($recent['sum']);
echo ' <span class="user">';
@@ -174,11 +184,10 @@ class admin_plugin_revert extends DokuWiki_Admin_Plugin {
echo '<p>';
echo '<button type="submit">'.$this->getLang('revert').'</button> ';
- printf($this->getLang('note2'),hsc($filter));
+ printf($this->getLang('note2'), hsc($filter));
echo '</p>';
echo '</div></form>';
}
-
}
//Setup VIM: ex: et ts=4 :
diff --git a/lib/plugins/safefnrecode/action.php b/lib/plugins/safefnrecode/action.php
index 9127f8df2..952d95c90 100644
--- a/lib/plugins/safefnrecode/action.php
+++ b/lib/plugins/safefnrecode/action.php
@@ -6,63 +6,63 @@
* @author Andreas Gohr <andi@splitbrain.org>
*/
-// must be run within Dokuwiki
-if (!defined('DOKU_INC')) die();
-
-require_once DOKU_PLUGIN.'action.php';
-
-class action_plugin_safefnrecode extends DokuWiki_Action_Plugin {
-
- public function register(Doku_Event_Handler $controller) {
-
- $controller->register_hook('INDEXER_TASKS_RUN', 'BEFORE', $this, 'handle_indexer_tasks_run');
+class action_plugin_safefnrecode extends DokuWiki_Action_Plugin
+{
+ /** @inheritdoc */
+ public function register(Doku_Event_Handler $controller)
+ {
+ $controller->register_hook('INDEXER_TASKS_RUN', 'BEFORE', $this, 'handleIndexerTasksRun');
}
- public function handle_indexer_tasks_run(Doku_Event &$event, $param) {
+ /**
+ * Handle indexer event
+ *
+ * @param Doku_Event $event
+ * @param $param
+ */
+ public function handleIndexerTasksRun(Doku_Event $event, $param)
+ {
global $conf;
- if($conf['fnencode'] != 'safe') return;
+ if ($conf['fnencode'] != 'safe') return;
- if(!file_exists($conf['datadir'].'_safefn.recoded')){
+ if (!file_exists($conf['datadir'].'_safefn.recoded')) {
$this->recode($conf['datadir']);
touch($conf['datadir'].'_safefn.recoded');
}
- if(!file_exists($conf['olddir'].'_safefn.recoded')){
+ if (!file_exists($conf['olddir'].'_safefn.recoded')) {
$this->recode($conf['olddir']);
touch($conf['olddir'].'_safefn.recoded');
}
- if(!file_exists($conf['metadir'].'_safefn.recoded')){
+ if (!file_exists($conf['metadir'].'_safefn.recoded')) {
$this->recode($conf['metadir']);
touch($conf['metadir'].'_safefn.recoded');
}
- if(!file_exists($conf['mediadir'].'_safefn.recoded')){
+ if (!file_exists($conf['mediadir'].'_safefn.recoded')) {
$this->recode($conf['mediadir']);
touch($conf['mediadir'].'_safefn.recoded');
}
-
}
/**
* Recursive function to rename all safe encoded files to use the new
* square bracket post indicator
*/
- private function recode($dir){
+ private function recode($dir)
+ {
$dh = opendir($dir);
- if(!$dh) return;
+ if (!$dh) return;
while (($file = readdir($dh)) !== false) {
- if($file == '.' || $file == '..') continue; # cur and upper dir
- if(is_dir("$dir/$file")) $this->recode("$dir/$file"); #recurse
- if(strpos($file,'%') === false) continue; # no encoding used
- $new = preg_replace('/(%[^\]]*?)\./','\1]',$file); # new post indicator
- if(preg_match('/%[^\]]+$/',$new)) $new .= ']'; # fix end FS#2122
- rename("$dir/$file","$dir/$new"); # rename it
+ if ($file == '.' || $file == '..') continue; # cur and upper dir
+ if (is_dir("$dir/$file")) $this->recode("$dir/$file"); #recurse
+ if (strpos($file, '%') === false) continue; # no encoding used
+ $new = preg_replace('/(%[^\]]*?)\./', '\1]', $file); # new post indicator
+ if (preg_match('/%[^\]]+$/', $new)) $new .= ']'; # fix end FS#2122
+ rename("$dir/$file", "$dir/$new"); # rename it
}
closedir($dh);
}
-
}
-
-// vim:ts=4:sw=4:et:
diff --git a/lib/plugins/styling/action.php b/lib/plugins/styling/action.php
index 2190fd61d..46245ca75 100644
--- a/lib/plugins/styling/action.php
+++ b/lib/plugins/styling/action.php
@@ -5,19 +5,8 @@
* @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html
* @author Andreas Gohr <andi@splitbrain.org>
*/
-
-// must be run within Dokuwiki
-if(!defined('DOKU_INC')) die();
-
-/**
- * Class action_plugin_styling
- *
- * This handles all the save actions and loading the interface
- *
- * All this usually would be done within an admin plugin, but we want to have this available outside
- * the admin interface using our floating dialog.
- */
-class action_plugin_styling extends DokuWiki_Action_Plugin {
+class action_plugin_styling extends DokuWiki_Action_Plugin
+{
/**
* Registers a callback functions
@@ -25,8 +14,9 @@ class action_plugin_styling extends DokuWiki_Action_Plugin {
* @param Doku_Event_Handler $controller DokuWiki's event controller object
* @return void
*/
- public function register(Doku_Event_Handler $controller) {
- $controller->register_hook('TPL_METAHEADER_OUTPUT', 'BEFORE', $this, 'handle_header');
+ public function register(Doku_Event_Handler $controller)
+ {
+ $controller->register_hook('TPL_METAHEADER_OUTPUT', 'BEFORE', $this, 'handleHeader');
}
/**
@@ -37,26 +27,25 @@ class action_plugin_styling extends DokuWiki_Action_Plugin {
* handler was registered]
* @return void
*/
- public function handle_header(Doku_Event &$event, $param) {
+ public function handleHeader(Doku_Event &$event, $param)
+ {
global $ACT;
global $INPUT;
- if($ACT != 'admin' || $INPUT->str('page') != 'styling') return;
+ if ($ACT != 'admin' || $INPUT->str('page') != 'styling') return;
/** @var admin_plugin_styling $admin */
$admin = plugin_load('admin', 'styling');
- if(!$admin->isAccessibleByCurrentUser()) return;
+ if (!$admin->isAccessibleByCurrentUser()) return;
// set preview
$len = count($event->data['link']);
- for($i = 0; $i < $len; $i++) {
- if(
- $event->data['link'][$i]['rel'] == 'stylesheet' &&
+ for ($i = 0; $i < $len; $i++) {
+ if ($event->data['link'][$i]['rel'] == 'stylesheet' &&
strpos($event->data['link'][$i]['href'], 'lib/exe/css.php') !== false
) {
$event->data['link'][$i]['href'] .= '&preview=1&tseed='.time();
}
}
}
-
}
// vim:ts=4:sw=4:et:
diff --git a/lib/plugins/styling/admin.php b/lib/plugins/styling/admin.php
index e02f06604..41d7d1adf 100644
--- a/lib/plugins/styling/admin.php
+++ b/lib/plugins/styling/admin.php
@@ -5,45 +5,46 @@
* @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html
* @author Andreas Gohr <andi@splitbrain.org>
*/
-
-// must be run within Dokuwiki
-if(!defined('DOKU_INC')) die();
-
-class admin_plugin_styling extends DokuWiki_Admin_Plugin {
+class admin_plugin_styling extends DokuWiki_Admin_Plugin
+{
public $ispopup = false;
/**
* @return int sort number in admin menu
*/
- public function getMenuSort() {
+ public function getMenuSort()
+ {
return 1000;
}
/**
* @return bool true if only access for superuser, false is for superusers and moderators
*/
- public function forAdminOnly() {
+ public function forAdminOnly()
+ {
return true;
}
/**
* handle the different actions (also called from ajax)
*/
- public function handle() {
+ public function handle()
+ {
global $INPUT;
$run = $INPUT->extract('run')->str('run');
- if(!$run) return;
- $run = "run_$run";
+ if (!$run) return;
+ $run = 'run'.ucfirst($run);
$this->$run();
}
/**
* Render HTML output, e.g. helpful text and a form
*/
- public function html() {
+ public function html()
+ {
$class = 'nopopup';
- if($this->ispopup) $class = 'ispopup page';
+ if ($this->ispopup) $class = 'ispopup page';
echo '<div id="plugin__styling" class="'.$class.'">';
ptln('<h1>'.$this->getLang('menu').'</h1>');
@@ -54,7 +55,8 @@ class admin_plugin_styling extends DokuWiki_Admin_Plugin {
/**
* Create the actual editing form
*/
- public function form() {
+ public function form()
+ {
global $conf;
global $ID;
@@ -62,13 +64,13 @@ class admin_plugin_styling extends DokuWiki_Admin_Plugin {
$styleini = $styleUtil->cssStyleini();
$replacements = $styleini['replacements'];
- if($this->ispopup) {
+ if ($this->ispopup) {
$target = DOKU_BASE.'lib/plugins/styling/popup.php';
} else {
$target = wl($ID, array('do' => 'admin', 'page' => 'styling'));
}
- if(empty($replacements)) {
+ if (empty($replacements)) {
echo '<p class="error">'.$this->getLang('error').'</p>';
} else {
echo $this->locale_xhtml('intro');
@@ -76,21 +78,24 @@ class admin_plugin_styling extends DokuWiki_Admin_Plugin {
echo '<form class="styling" method="post" action="'.$target.'">';
echo '<table><tbody>';
- foreach($replacements as $key => $value) {
+ foreach ($replacements as $key => $value) {
$name = tpl_getLang($key);
- if(empty($name)) $name = $this->getLang($key);
- if(empty($name)) $name = $key;
+ if (empty($name)) $name = $this->getLang($key);
+ if (empty($name)) $name = $key;
echo '<tr>';
echo '<td><label for="tpl__'.hsc($key).'">'.$name.'</label></td>';
- echo '<td><input type="text" name="tpl['.hsc($key).']" id="tpl__'.hsc($key).'" value="'.hsc($value).'" '.$this->colorClass($key).' dir="ltr" /></td>';
+ echo '<td><input type="text" name="tpl['.hsc($key).']" id="tpl__'.hsc($key).'"
+ value="'.hsc($value).'" '.$this->colorClass($key).' dir="ltr" /></td>';
echo '</tr>';
}
echo '</tbody></table>';
echo '<p>';
- echo '<button type="submit" name="run[preview]" class="btn_preview primary">'.$this->getLang('btn_preview').'</button> ';
- echo '<button type="submit" name="run[reset]">'.$this->getLang('btn_reset').'</button>'; #FIXME only if preview.ini exists
+ echo '<button type="submit" name="run[preview]" class="btn_preview primary">'.
+ $this->getLang('btn_preview').'</button> ';
+ #FIXME only if preview.ini exists:
+ echo '<button type="submit" name="run[reset]">'.$this->getLang('btn_reset').'</button>';
echo '</p>';
echo '<p>';
@@ -98,20 +103,21 @@ class admin_plugin_styling extends DokuWiki_Admin_Plugin {
echo '</p>';
echo '<p>';
- echo '<button type="submit" name="run[revert]">'.$this->getLang('btn_revert').'</button>'; #FIXME only if local.ini exists
+ #FIXME only if local.ini exists:
+ echo '<button type="submit" name="run[revert]">'.$this->getLang('btn_revert').'</button>';
echo '</p>';
echo '</form>';
echo tpl_locale_xhtml('style');
-
}
}
/**
* set the color class attribute
*/
- protected function colorClass($key) {
+ protected function colorClass($key)
+ {
static $colors = array(
'text',
'background',
@@ -127,7 +133,7 @@ class admin_plugin_styling extends DokuWiki_Admin_Plugin {
'missing',
);
- if(preg_match('/colou?r/', $key) || in_array(trim($key,'_'), $colors)) {
+ if (preg_match('/colou?r/', $key) || in_array(trim($key, '_'), $colors)) {
return 'class="color"';
} else {
return '';
@@ -137,7 +143,8 @@ class admin_plugin_styling extends DokuWiki_Admin_Plugin {
/**
* saves the preview.ini (alos called from ajax directly)
*/
- public function run_preview() {
+ public function runPreview()
+ {
global $conf;
$ini = $conf['cachedir'].'/preview.ini';
io_saveFile($ini, $this->makeini());
@@ -146,7 +153,8 @@ class admin_plugin_styling extends DokuWiki_Admin_Plugin {
/**
* deletes the preview.ini
*/
- protected function run_reset() {
+ protected function runReset()
+ {
global $conf;
$ini = $conf['cachedir'].'/preview.ini';
io_saveFile($ini, '');
@@ -155,17 +163,19 @@ class admin_plugin_styling extends DokuWiki_Admin_Plugin {
/**
* deletes the local style.ini replacements
*/
- protected function run_revert() {
- $this->replaceini('');
- $this->run_reset();
+ protected function runRevert()
+ {
+ $this->replaceIni('');
+ $this->runReset();
}
/**
* save the local style.ini replacements
*/
- protected function run_save() {
- $this->replaceini($this->makeini());
- $this->run_reset();
+ protected function runSave()
+ {
+ $this->replaceIni($this->makeini());
+ $this->runReset();
}
/**
@@ -173,13 +183,14 @@ class admin_plugin_styling extends DokuWiki_Admin_Plugin {
*
* @return string
*/
- protected function makeini() {
+ protected function makeini()
+ {
global $INPUT;
$ini = "[replacements]\n";
$ini .= ";These overwrites have been generated from the Template styling Admin interface\n";
$ini .= ";Any values in this section will be overwritten by that tool again\n";
- foreach($INPUT->arr('tpl') as $key => $val) {
+ foreach ($INPUT->arr('tpl') as $key => $val) {
$ini .= $key.' = "'.addslashes($val).'"'."\n";
}
@@ -191,10 +202,11 @@ class admin_plugin_styling extends DokuWiki_Admin_Plugin {
*
* @param string $new the new ini contents
*/
- protected function replaceini($new) {
+ protected function replaceIni($new)
+ {
global $conf;
$ini = DOKU_CONF."tpl/".$conf['template']."/style.ini";
- if(file_exists($ini)) {
+ if (file_exists($ini)) {
$old = io_readFile($ini);
$old = preg_replace('/\[replacements\]\n.*?(\n\[.*]|$)/s', '\\1', $old);
$old = trim($old);
@@ -205,7 +217,6 @@ class admin_plugin_styling extends DokuWiki_Admin_Plugin {
io_makeFileDir($ini);
io_saveFile($ini, "$old\n\n$new");
}
-
}
// vim:ts=4:sw=4:et:
diff --git a/lib/plugins/styling/popup.php b/lib/plugins/styling/popup.php
index 4a1735ccc..079062e43 100644
--- a/lib/plugins/styling/popup.php
+++ b/lib/plugins/styling/popup.php
@@ -1,5 +1,6 @@
<?php
-if(!defined('DOKU_INC')) define('DOKU_INC', dirname(__FILE__) . '/../../../');
+// phpcs:disable PSR1.Files.SideEffects
+if (!defined('DOKU_INC')) define('DOKU_INC', dirname(__FILE__) . '/../../../');
require_once(DOKU_INC . 'inc/init.php');
//close session
session_write_close();
@@ -8,7 +9,7 @@ header('X-UA-Compatible: IE=edge,chrome=1');
/** @var admin_plugin_styling $plugin */
$plugin = plugin_load('admin', 'styling');
-if(!$plugin->isAccessibleByCurrentUser()) die('only admins allowed');
+if (!$plugin->isAccessibleByCurrentUser()) die('only admins allowed');
$plugin->ispopup = true;
// handle posts
diff --git a/lib/plugins/syntax.php b/lib/plugins/syntax.php
index 9e2913d78..a3cbec722 100644
--- a/lib/plugins/syntax.php
+++ b/lib/plugins/syntax.php
@@ -1,134 +1,2 @@
<?php
-/**
- * Syntax Plugin Prototype
- *
- * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
- * @author Andreas Gohr <andi@splitbrain.org>
- */
-// must be run within Dokuwiki
-if(!defined('DOKU_INC')) die();
-
-/**
- * All DokuWiki plugins to extend the parser/rendering mechanism
- * need to inherit from this class
- */
-class DokuWiki_Syntax_Plugin extends Doku_Parser_Mode_Plugin {
-
- var $allowedModesSetup = false;
-
- /**
- * Syntax Type
- *
- * Needs to return one of the mode types defined in $PARSER_MODES in parser.php
- *
- * @return string
- */
- function getType(){
- trigger_error('getType() not implemented in '.get_class($this), E_USER_WARNING);
- return '';
- }
-
- /**
- * Allowed Mode Types
- *
- * Defines the mode types for other dokuwiki markup that maybe nested within the
- * plugin's own markup. Needs to return an array of one or more of the mode types
- * defined in $PARSER_MODES in parser.php
- *
- * @return array
- */
- function getAllowedTypes() {
- return array();
- }
-
- /**
- * Paragraph Type
- *
- * Defines how this syntax is handled regarding paragraphs. This is important
- * for correct XHTML nesting. Should return one of the following:
- *
- * 'normal' - The plugin can be used inside paragraphs
- * 'block' - Open paragraphs need to be closed before plugin output
- * 'stack' - Special case. Plugin wraps other paragraphs.
- *
- * @see Doku_Handler_Block
- *
- * @return string
- */
- function getPType(){
- return 'normal';
- }
-
- /**
- * Handler to prepare matched data for the rendering process
- *
- * This function can only pass data to render() via its return value - render()
- * may be not be run during the object's current life.
- *
- * Usually you should only need the $match param.
- *
- * @param string $match The text matched by the patterns
- * @param int $state The lexer state for the match
- * @param int $pos The character position of the matched text
- * @param Doku_Handler $handler The Doku_Handler object
- * @return bool|array Return an array with all data you want to use in render, false don't add an instruction
- */
- function handle($match, $state, $pos, Doku_Handler $handler){
- trigger_error('handle() not implemented in '.get_class($this), E_USER_WARNING);
- }
-
- /**
- * Handles the actual output creation.
- *
- * The function must not assume any other of the classes methods have been run
- * during the object's current life. The only reliable data it receives are its
- * parameters.
- *
- * The function should always check for the given output format and return false
- * when a format isn't supported.
- *
- * $renderer contains a reference to the renderer object which is
- * currently handling the rendering. You need to use it for writing
- * the output. How this is done depends on the renderer used (specified
- * by $format
- *
- * The contents of the $data array depends on what the handler() function above
- * created
- *
- * @param string $format output format being rendered
- * @param Doku_Renderer $renderer the current renderer object
- * @param array $data data created by handler()
- * @return boolean rendered correctly? (however, returned value is not used at the moment)
- */
- function render($format, Doku_Renderer $renderer, $data) {
- trigger_error('render() not implemented in '.get_class($this), E_USER_WARNING);
-
- }
-
- /**
- * There should be no need to override this function
- *
- * @param string $mode
- * @return bool
- */
- function accepts($mode) {
-
- if (!$this->allowedModesSetup) {
- global $PARSER_MODES;
-
- $allowedModeTypes = $this->getAllowedTypes();
- foreach($allowedModeTypes as $mt) {
- $this->allowedModes = array_merge($this->allowedModes, $PARSER_MODES[$mt]);
- }
-
- $idx = array_search(substr(get_class($this), 7), (array) $this->allowedModes);
- if ($idx !== false) {
- unset($this->allowedModes[$idx]);
- }
- $this->allowedModesSetup = true;
- }
-
- return parent::accepts($mode);
- }
-}
-//Setup VIM: ex: et ts=4 :
+dbg_deprecated('Autoloading. Do not require() files yourself.');
diff --git a/lib/plugins/testing/action.php b/lib/plugins/testing/action.php
index a242ab0b7..09b84262e 100644
--- a/lib/plugins/testing/action.php
+++ b/lib/plugins/testing/action.php
@@ -1,4 +1,7 @@
<?php
+
+use dokuwiki\Extension\Event;
+
/**
* Plugin for testing the test system
*
@@ -8,13 +11,14 @@
*/
class action_plugin_testing extends DokuWiki_Action_Plugin {
- function register(Doku_Event_Handler $controller) {
+ /** @inheritdoc */
+ public function register(Doku_Event_Handler $controller) {
$controller->register_hook('DOKUWIKI_STARTED', 'AFTER', $this, 'dokuwikiStarted');
}
- function dokuwikiStarted() {
+ public function dokuwikiStarted() {
$param = array();
- trigger_event('TESTING_PLUGIN_INSTALLED', $param);
+ Event::createAndTrigger('TESTING_PLUGIN_INSTALLED', $param);
msg('The testing plugin is enabled and should be disabled.',-1);
}
}
diff --git a/lib/plugins/testing/conf/default.php b/lib/plugins/testing/conf/default.php
new file mode 100644
index 000000000..392233dd8
--- /dev/null
+++ b/lib/plugins/testing/conf/default.php
@@ -0,0 +1,7 @@
+<?php
+/**
+ * Default options
+ *
+ * They don't do anything and are just there for testing config reading
+ */
+$conf['schnibble'] = 0;
diff --git a/lib/plugins/testing/conf/metadata.php b/lib/plugins/testing/conf/metadata.php
new file mode 100644
index 000000000..377da63eb
--- /dev/null
+++ b/lib/plugins/testing/conf/metadata.php
@@ -0,0 +1,7 @@
+<?php
+/**
+ * Option Metadata
+ *
+ * They don't do anything and are just there for testing config reading
+ */
+$meta['schnibble'] = array('onoff');
diff --git a/lib/plugins/testing/lang/en/settings.php b/lib/plugins/testing/lang/en/settings.php
new file mode 100644
index 000000000..e717c9021
--- /dev/null
+++ b/lib/plugins/testing/lang/en/settings.php
@@ -0,0 +1,5 @@
+<?php
+/**
+ * Default options texts
+ */
+$lang['schnibble'] = 'Turns on the schnibble before the frobble is used';
diff --git a/lib/plugins/usermanager/_test/mocks.class.php b/lib/plugins/usermanager/_test/mocks.class.php
index e524e451b..75ac51422 100644
--- a/lib/plugins/usermanager/_test/mocks.class.php
+++ b/lib/plugins/usermanager/_test/mocks.class.php
@@ -16,30 +16,30 @@ class admin_mock_usermanager extends admin_plugin_usermanager {
public $lang;
public function getImportFailures() {
- return $this->_import_failures;
+ return $this->import_failures;
}
public function tryExport() {
ob_start();
- $this->_export();
+ $this->exportCSV();
return ob_get_clean();
}
public function tryImport() {
- return $this->_import();
+ return $this->importCSV();
}
// no need to send email notifications (mostly)
- protected function _notifyUser($user, $password, $status_alert=true) {
+ protected function notifyUser($user, $password, $status_alert=true) {
if ($this->mock_email_notifications) {
$this->mock_email_notifications_sent++;
return true;
} else {
- return parent::_notifyUser($user, $password, $status_alert);
+ return parent::notifyUser($user, $password, $status_alert);
}
}
- protected function _isUploadedFile($file) {
+ protected function isUploadedFile($file) {
return file_exists($file);
}
}
diff --git a/lib/plugins/usermanager/admin.php b/lib/plugins/usermanager/admin.php
index 3148971ce..423467133 100644
--- a/lib/plugins/usermanager/admin.php
+++ b/lib/plugins/usermanager/admin.php
@@ -10,52 +10,49 @@
* @author neolao <neolao@neolao.com>
* @author Chris Smith <chris@jalakai.co.uk>
*/
-// must be run within Dokuwiki
-if(!defined('DOKU_INC')) die();
-
-if(!defined('DOKU_PLUGIN_IMAGES')) define('DOKU_PLUGIN_IMAGES',DOKU_BASE.'lib/plugins/usermanager/images/');
/**
* All DokuWiki plugins to extend the admin function
* need to inherit from this class
*/
-class admin_plugin_usermanager extends DokuWiki_Admin_Plugin {
-
- protected $_auth = null; // auth object
- protected $_user_total = 0; // number of registered users
- protected $_filter = array(); // user selection filter(s)
- protected $_start = 0; // index of first user to be displayed
- protected $_last = 0; // index of the last user to be displayed
- protected $_pagesize = 20; // number of users to list on one page
- protected $_edit_user = ''; // set to user selected for editing
- protected $_edit_userdata = array();
- protected $_disabled = ''; // if disabled set to explanatory string
- protected $_import_failures = array();
- protected $_lastdisabled = false; // set to true if last user is unknown and last button is hence buggy
+class admin_plugin_usermanager extends DokuWiki_Admin_Plugin
+{
+ const IMAGE_DIR = DOKU_BASE.'lib/plugins/usermanager/images/';
+
+ protected $auth = null; // auth object
+ protected $users_total = 0; // number of registered users
+ protected $filter = array(); // user selection filter(s)
+ protected $start = 0; // index of first user to be displayed
+ protected $last = 0; // index of the last user to be displayed
+ protected $pagesize = 20; // number of users to list on one page
+ protected $edit_user = ''; // set to user selected for editing
+ protected $edit_userdata = array();
+ protected $disabled = ''; // if disabled set to explanatory string
+ protected $import_failures = array();
+ protected $lastdisabled = false; // set to true if last user is unknown and last button is hence buggy
/**
* Constructor
*/
- public function __construct(){
+ public function __construct()
+ {
/** @var DokuWiki_Auth_Plugin $auth */
global $auth;
$this->setupLocale();
if (!isset($auth)) {
- $this->_disabled = $this->lang['noauth'];
- } else if (!$auth->canDo('getUsers')) {
- $this->_disabled = $this->lang['nosupport'];
+ $this->disabled = $this->lang['noauth'];
+ } elseif (!$auth->canDo('getUsers')) {
+ $this->disabled = $this->lang['nosupport'];
} else {
-
// we're good to go
- $this->_auth = & $auth;
-
+ $this->auth = & $auth;
}
// attempt to retrieve any import failures from the session
- if (!empty($_SESSION['import_failures'])){
- $this->_import_failures = $_SESSION['import_failures'];
+ if (!empty($_SESSION['import_failures'])) {
+ $this->import_failures = $_SESSION['import_failures'];
}
}
@@ -65,12 +62,13 @@ class admin_plugin_usermanager extends DokuWiki_Admin_Plugin {
* @param string $language
* @return string
*/
- public function getMenuText($language) {
+ public function getMenuText($language)
+ {
- if (!is_null($this->_auth))
+ if (!is_null($this->auth))
return parent::getMenuText($language);
- return $this->getLang('menu').' '.$this->_disabled;
+ return $this->getLang('menu').' '.$this->disabled;
}
/**
@@ -78,29 +76,33 @@ class admin_plugin_usermanager extends DokuWiki_Admin_Plugin {
*
* @return int
*/
- public function getMenuSort() {
+ public function getMenuSort()
+ {
return 2;
}
/**
* @return int current start value for pageination
*/
- public function getStart() {
- return $this->_start;
+ public function getStart()
+ {
+ return $this->start;
}
/**
* @return int number of users per page
*/
- public function getPagesize() {
- return $this->_pagesize;
+ public function getPagesize()
+ {
+ return $this->pagesize;
}
/**
* @param boolean $lastdisabled
*/
- public function setLastdisabled($lastdisabled) {
- $this->_lastdisabled = $lastdisabled;
+ public function setLastdisabled($lastdisabled)
+ {
+ $this->lastdisabled = $lastdisabled;
}
/**
@@ -108,9 +110,10 @@ class admin_plugin_usermanager extends DokuWiki_Admin_Plugin {
*
* @return bool
*/
- public function handle() {
+ public function handle()
+ {
global $INPUT;
- if (is_null($this->_auth)) return false;
+ if (is_null($this->auth)) return false;
// extract the command and any specific parameters
// submit button name is of the form - fn[cmd][param(s)]
@@ -125,33 +128,56 @@ class admin_plugin_usermanager extends DokuWiki_Admin_Plugin {
}
if ($cmd != "search") {
- $this->_start = $INPUT->int('start', 0);
- $this->_filter = $this->_retrieveFilter();
+ $this->start = $INPUT->int('start', 0);
+ $this->filter = $this->retrieveFilter();
}
- switch($cmd){
- case "add" : $this->_addUser(); break;
- case "delete" : $this->_deleteUser(); break;
- case "modify" : $this->_modifyUser(); break;
- case "edit" : $this->_editUser($param); break;
- case "search" : $this->_setFilter($param);
- $this->_start = 0;
- break;
- case "export" : $this->_export(); break;
- case "import" : $this->_import(); break;
- case "importfails" : $this->_downloadImportFailures(); break;
+ switch ($cmd) {
+ case "add":
+ $this->addUser();
+ break;
+ case "delete":
+ $this->deleteUser();
+ break;
+ case "modify":
+ $this->modifyUser();
+ break;
+ case "edit":
+ $this->editUser($param);
+ break;
+ case "search":
+ $this->setFilter($param);
+ $this->start = 0;
+ break;
+ case "export":
+ $this->exportCSV();
+ break;
+ case "import":
+ $this->importCSV();
+ break;
+ case "importfails":
+ $this->downloadImportFailures();
+ break;
}
- $this->_user_total = $this->_auth->canDo('getUserCount') ? $this->_auth->getUserCount($this->_filter) : -1;
+ $this->users_total = $this->auth->canDo('getUserCount') ? $this->auth->getUserCount($this->filter) : -1;
// page handling
- switch($cmd){
- case 'start' : $this->_start = 0; break;
- case 'prev' : $this->_start -= $this->_pagesize; break;
- case 'next' : $this->_start += $this->_pagesize; break;
- case 'last' : $this->_start = $this->_user_total; break;
+ switch ($cmd) {
+ case 'start':
+ $this->start = 0;
+ break;
+ case 'prev':
+ $this->start -= $this->pagesize;
+ break;
+ case 'next':
+ $this->start += $this->pagesize;
+ break;
+ case 'last':
+ $this->start = $this->users_total;
+ break;
}
- $this->_validatePagination();
+ $this->validatePagination();
return true;
}
@@ -160,21 +186,22 @@ class admin_plugin_usermanager extends DokuWiki_Admin_Plugin {
*
* @return bool
*/
- public function html() {
+ public function html()
+ {
global $ID;
- if(is_null($this->_auth)) {
+ if (is_null($this->auth)) {
print $this->lang['badauth'];
return false;
}
- $user_list = $this->_auth->retrieveUsers($this->_start, $this->_pagesize, $this->_filter);
+ $user_list = $this->auth->retrieveUsers($this->start, $this->pagesize, $this->filter);
- $page_buttons = $this->_pagination();
- $delete_disable = $this->_auth->canDo('delUser') ? '' : 'disabled="disabled"';
+ $page_buttons = $this->pagination();
+ $delete_disable = $this->auth->canDo('delUser') ? '' : 'disabled="disabled"';
- $editable = $this->_auth->canDo('UserMod');
- $export_label = empty($this->_filter) ? $this->lang['export_all'] : $this->lang['export_filtered'];
+ $editable = $this->auth->canDo('UserMod');
+ $export_label = empty($this->filter) ? $this->lang['export_all'] : $this->lang['export_filtered'];
print $this->locale_xhtml('intro');
print $this->locale_xhtml('list');
@@ -182,13 +209,21 @@ class admin_plugin_usermanager extends DokuWiki_Admin_Plugin {
ptln("<div id=\"user__manager\">");
ptln("<div class=\"level2\">");
- if ($this->_user_total > 0) {
- ptln("<p>".sprintf($this->lang['summary'],$this->_start+1,$this->_last,$this->_user_total,$this->_auth->getUserCount())."</p>");
+ if ($this->users_total > 0) {
+ ptln(
+ "<p>" . sprintf(
+ $this->lang['summary'],
+ $this->start + 1,
+ $this->last,
+ $this->users_total,
+ $this->auth->getUserCount()
+ ) . "</p>"
+ );
} else {
- if($this->_user_total < 0) {
+ if ($this->users_total < 0) {
$allUserTotal = 0;
} else {
- $allUserTotal = $this->_auth->getUserCount();
+ $allUserTotal = $this->auth->getUserCount();
}
ptln("<p>".sprintf($this->lang['nonefound'], $allUserTotal)."</p>");
}
@@ -198,19 +233,29 @@ class admin_plugin_usermanager extends DokuWiki_Admin_Plugin {
ptln(" <table class=\"inline\">");
ptln(" <thead>");
ptln(" <tr>");
- ptln(" <th>&#160;</th><th>".$this->lang["user_id"]."</th><th>".$this->lang["user_name"]."</th><th>".$this->lang["user_mail"]."</th><th>".$this->lang["user_groups"]."</th>");
+ ptln(" <th>&#160;</th>
+ <th>".$this->lang["user_id"]."</th>
+ <th>".$this->lang["user_name"]."</th>
+ <th>".$this->lang["user_mail"]."</th>
+ <th>".$this->lang["user_groups"]."</th>");
ptln(" </tr>");
ptln(" <tr>");
- ptln(" <td class=\"rightalign\"><input type=\"image\" src=\"".DOKU_PLUGIN_IMAGES."search.png\" name=\"fn[search][new]\" title=\"".$this->lang['search_prompt']."\" alt=\"".$this->lang['search']."\" class=\"button\" /></td>");
- ptln(" <td><input type=\"text\" name=\"userid\" class=\"edit\" value=\"".$this->_htmlFilter('user')."\" /></td>");
- ptln(" <td><input type=\"text\" name=\"username\" class=\"edit\" value=\"".$this->_htmlFilter('name')."\" /></td>");
- ptln(" <td><input type=\"text\" name=\"usermail\" class=\"edit\" value=\"".$this->_htmlFilter('mail')."\" /></td>");
- ptln(" <td><input type=\"text\" name=\"usergroups\" class=\"edit\" value=\"".$this->_htmlFilter('grps')."\" /></td>");
+ ptln(" <td class=\"rightalign\"><input type=\"image\" src=\"".
+ self::IMAGE_DIR."search.png\" name=\"fn[search][new]\" title=\"".
+ $this->lang['search_prompt']."\" alt=\"".$this->lang['search']."\" class=\"button\" /></td>");
+ ptln(" <td><input type=\"text\" name=\"userid\" class=\"edit\" value=\"".
+ $this->htmlFilter('user')."\" /></td>");
+ ptln(" <td><input type=\"text\" name=\"username\" class=\"edit\" value=\"".
+ $this->htmlFilter('name')."\" /></td>");
+ ptln(" <td><input type=\"text\" name=\"usermail\" class=\"edit\" value=\"".
+ $this->htmlFilter('mail')."\" /></td>");
+ ptln(" <td><input type=\"text\" name=\"usergroups\" class=\"edit\" value=\"".
+ $this->htmlFilter('grps')."\" /></td>");
ptln(" </tr>");
ptln(" </thead>");
- if ($this->_user_total) {
+ if ($this->users_total) {
ptln(" <tbody>");
foreach ($user_list as $user => $userinfo) {
extract($userinfo);
@@ -220,11 +265,12 @@ class admin_plugin_usermanager extends DokuWiki_Admin_Plugin {
* @var string $mail
* @var array $grps
*/
- $groups = join(', ',$grps);
+ $groups = join(', ', $grps);
ptln(" <tr class=\"user_info\">");
- ptln(" <td class=\"centeralign\"><input type=\"checkbox\" name=\"delete[".hsc($user)."]\" ".$delete_disable." /></td>");
+ ptln(" <td class=\"centeralign\"><input type=\"checkbox\" name=\"delete[".hsc($user).
+ "]\" ".$delete_disable." /></td>");
if ($editable) {
- ptln(" <td><a href=\"".wl($ID,array('fn[edit]['.$user.']' => 1,
+ ptln(" <td><a href=\"".wl($ID, array('fn[edit]['.$user.']' => 1,
'do' => 'admin',
'page' => 'usermanager',
'sectok' => getSecurityToken())).
@@ -241,22 +287,27 @@ class admin_plugin_usermanager extends DokuWiki_Admin_Plugin {
ptln(" <tbody>");
ptln(" <tr><td colspan=\"5\" class=\"centeralign\">");
ptln(" <span class=\"medialeft\">");
- ptln(" <button type=\"submit\" name=\"fn[delete]\" id=\"usrmgr__del\" ".$delete_disable.">".$this->lang['delete_selected']."</button>");
+ ptln(" <button type=\"submit\" name=\"fn[delete]\" id=\"usrmgr__del\" ".$delete_disable.">".
+ $this->lang['delete_selected']."</button>");
ptln(" </span>");
ptln(" <span class=\"mediaright\">");
- ptln(" <button type=\"submit\" name=\"fn[start]\" ".$page_buttons['start'].">".$this->lang['start']."</button>");
- ptln(" <button type=\"submit\" name=\"fn[prev]\" ".$page_buttons['prev'].">".$this->lang['prev']."</button>");
- ptln(" <button type=\"submit\" name=\"fn[next]\" ".$page_buttons['next'].">".$this->lang['next']."</button>");
- ptln(" <button type=\"submit\" name=\"fn[last]\" ".$page_buttons['last'].">".$this->lang['last']."</button>");
+ ptln(" <button type=\"submit\" name=\"fn[start]\" ".$page_buttons['start'].">".
+ $this->lang['start']."</button>");
+ ptln(" <button type=\"submit\" name=\"fn[prev]\" ".$page_buttons['prev'].">".
+ $this->lang['prev']."</button>");
+ ptln(" <button type=\"submit\" name=\"fn[next]\" ".$page_buttons['next'].">".
+ $this->lang['next']."</button>");
+ ptln(" <button type=\"submit\" name=\"fn[last]\" ".$page_buttons['last'].">".
+ $this->lang['last']."</button>");
ptln(" </span>");
- if (!empty($this->_filter)) {
+ if (!empty($this->filter)) {
ptln(" <button type=\"submit\" name=\"fn[search][clear]\">".$this->lang['clear']."</button>");
}
ptln(" <button type=\"submit\" name=\"fn[export]\">".$export_label."</button>");
ptln(" <input type=\"hidden\" name=\"do\" value=\"admin\" />");
ptln(" <input type=\"hidden\" name=\"page\" value=\"usermanager\" />");
- $this->_htmlFilterSettings(2);
+ $this->htmlFilterSettings(2);
ptln(" </td></tr>");
ptln(" </tbody>");
@@ -266,32 +317,32 @@ class admin_plugin_usermanager extends DokuWiki_Admin_Plugin {
ptln("</form>");
ptln("</div>");
- $style = $this->_edit_user ? " class=\"edit_user\"" : "";
+ $style = $this->edit_user ? " class=\"edit_user\"" : "";
- if ($this->_auth->canDo('addUser')) {
+ if ($this->auth->canDo('addUser')) {
ptln("<div".$style.">");
print $this->locale_xhtml('add');
ptln(" <div class=\"level2\">");
- $this->_htmlUserForm('add',null,array(),4);
+ $this->htmlUserForm('add', null, array(), 4);
ptln(" </div>");
ptln("</div>");
}
- if($this->_edit_user && $this->_auth->canDo('UserMod')){
+ if ($this->edit_user && $this->auth->canDo('UserMod')) {
ptln("<div".$style." id=\"scroll__here\">");
print $this->locale_xhtml('edit');
ptln(" <div class=\"level2\">");
- $this->_htmlUserForm('modify',$this->_edit_user,$this->_edit_userdata,4);
+ $this->htmlUserForm('modify', $this->edit_user, $this->edit_userdata, 4);
ptln(" </div>");
ptln("</div>");
}
- if ($this->_auth->canDo('addUser')) {
- $this->_htmlImportForm();
+ if ($this->auth->canDo('addUser')) {
+ $this->htmlImportForm();
}
ptln("</div>");
return true;
@@ -323,7 +374,8 @@ class admin_plugin_usermanager extends DokuWiki_Admin_Plugin {
* @param array $userdata array with name, mail, pass and grps
* @param int $indent
*/
- protected function _htmlUserForm($cmd,$user='',$userdata=array(),$indent=0) {
+ protected function htmlUserForm($cmd, $user = '', $userdata = array(), $indent = 0)
+ {
global $conf;
global $ID;
global $lang;
@@ -333,28 +385,76 @@ class admin_plugin_usermanager extends DokuWiki_Admin_Plugin {
if ($user) {
extract($userdata);
- if (!empty($grps)) $groups = join(',',$grps);
+ if (!empty($grps)) $groups = join(',', $grps);
} else {
- $notes[] = sprintf($this->lang['note_group'],$conf['defaultgroup']);
+ $notes[] = sprintf($this->lang['note_group'], $conf['defaultgroup']);
}
- ptln("<form action=\"".wl($ID)."\" method=\"post\">",$indent);
+ ptln("<form action=\"".wl($ID)."\" method=\"post\">", $indent);
formSecurityToken();
- ptln(" <div class=\"table\">",$indent);
- ptln(" <table class=\"inline\">",$indent);
- ptln(" <thead>",$indent);
- ptln(" <tr><th>".$this->lang["field"]."</th><th>".$this->lang["value"]."</th></tr>",$indent);
- ptln(" </thead>",$indent);
- ptln(" <tbody>",$indent);
-
- $this->_htmlInputField($cmd."_userid", "userid", $this->lang["user_id"], $user, $this->_auth->canDo("modLogin"), true, $indent+6);
- $this->_htmlInputField($cmd."_userpass", "userpass", $this->lang["user_pass"], "", $this->_auth->canDo("modPass"), false, $indent+6);
- $this->_htmlInputField($cmd."_userpass2", "userpass2", $lang["passchk"], "", $this->_auth->canDo("modPass"), false, $indent+6);
- $this->_htmlInputField($cmd."_username", "username", $this->lang["user_name"], $name, $this->_auth->canDo("modName"), true, $indent+6);
- $this->_htmlInputField($cmd."_usermail", "usermail", $this->lang["user_mail"], $mail, $this->_auth->canDo("modMail"), true, $indent+6);
- $this->_htmlInputField($cmd."_usergroups","usergroups",$this->lang["user_groups"],$groups,$this->_auth->canDo("modGroups"), false, $indent+6);
-
- if ($this->_auth->canDo("modPass")) {
+ ptln(" <div class=\"table\">", $indent);
+ ptln(" <table class=\"inline\">", $indent);
+ ptln(" <thead>", $indent);
+ ptln(" <tr><th>".$this->lang["field"]."</th><th>".$this->lang["value"]."</th></tr>", $indent);
+ ptln(" </thead>", $indent);
+ ptln(" <tbody>", $indent);
+
+ $this->htmlInputField(
+ $cmd . "_userid",
+ "userid",
+ $this->lang["user_id"],
+ $user,
+ $this->auth->canDo("modLogin"),
+ true,
+ $indent + 6
+ );
+ $this->htmlInputField(
+ $cmd . "_userpass",
+ "userpass",
+ $this->lang["user_pass"],
+ "",
+ $this->auth->canDo("modPass"),
+ false,
+ $indent + 6
+ );
+ $this->htmlInputField(
+ $cmd . "_userpass2",
+ "userpass2",
+ $lang["passchk"],
+ "",
+ $this->auth->canDo("modPass"),
+ false,
+ $indent + 6
+ );
+ $this->htmlInputField(
+ $cmd . "_username",
+ "username",
+ $this->lang["user_name"],
+ $name,
+ $this->auth->canDo("modName"),
+ true,
+ $indent + 6
+ );
+ $this->htmlInputField(
+ $cmd . "_usermail",
+ "usermail",
+ $this->lang["user_mail"],
+ $mail,
+ $this->auth->canDo("modMail"),
+ true,
+ $indent + 6
+ );
+ $this->htmlInputField(
+ $cmd . "_usergroups",
+ "usergroups",
+ $this->lang["user_groups"],
+ $groups,
+ $this->auth->canDo("modGroups"),
+ false,
+ $indent + 6
+ );
+
+ if ($this->auth->canDo("modPass")) {
if ($cmd == 'add') {
$notes[] = $this->lang['note_pass'];
}
@@ -362,37 +462,40 @@ class admin_plugin_usermanager extends DokuWiki_Admin_Plugin {
$notes[] = $this->lang['note_notify'];
}
- ptln("<tr><td><label for=\"".$cmd."_usernotify\" >".$this->lang["user_notify"].": </label></td><td><input type=\"checkbox\" id=\"".$cmd."_usernotify\" name=\"usernotify\" value=\"1\" /></td></tr>", $indent);
+ ptln("<tr><td><label for=\"".$cmd."_usernotify\" >".
+ $this->lang["user_notify"].": </label></td>
+ <td><input type=\"checkbox\" id=\"".$cmd."_usernotify\" name=\"usernotify\" value=\"1\" />
+ </td></tr>", $indent);
}
- ptln(" </tbody>",$indent);
- ptln(" <tbody>",$indent);
- ptln(" <tr>",$indent);
- ptln(" <td colspan=\"2\">",$indent);
- ptln(" <input type=\"hidden\" name=\"do\" value=\"admin\" />",$indent);
- ptln(" <input type=\"hidden\" name=\"page\" value=\"usermanager\" />",$indent);
+ ptln(" </tbody>", $indent);
+ ptln(" <tbody>", $indent);
+ ptln(" <tr>", $indent);
+ ptln(" <td colspan=\"2\">", $indent);
+ ptln(" <input type=\"hidden\" name=\"do\" value=\"admin\" />", $indent);
+ ptln(" <input type=\"hidden\" name=\"page\" value=\"usermanager\" />", $indent);
// save current $user, we need this to access details if the name is changed
if ($user)
- ptln(" <input type=\"hidden\" name=\"userid_old\" value=\"".hsc($user)."\" />",$indent);
+ ptln(" <input type=\"hidden\" name=\"userid_old\" value=\"".hsc($user)."\" />", $indent);
- $this->_htmlFilterSettings($indent+10);
+ $this->htmlFilterSettings($indent+10);
- ptln(" <button type=\"submit\" name=\"fn[".$cmd."]\">".$this->lang[$cmd]."</button>",$indent);
- ptln(" </td>",$indent);
- ptln(" </tr>",$indent);
- ptln(" </tbody>",$indent);
- ptln(" </table>",$indent);
+ ptln(" <button type=\"submit\" name=\"fn[".$cmd."]\">".$this->lang[$cmd]."</button>", $indent);
+ ptln(" </td>", $indent);
+ ptln(" </tr>", $indent);
+ ptln(" </tbody>", $indent);
+ ptln(" </table>", $indent);
if ($notes) {
ptln(" <ul class=\"notes\">");
foreach ($notes as $note) {
- ptln(" <li><span class=\"li\">".$note."</li>",$indent);
+ ptln(" <li><span class=\"li\">".$note."</li>", $indent);
}
ptln(" </ul>");
}
- ptln(" </div>",$indent);
- ptln("</form>",$indent);
+ ptln(" </div>", $indent);
+ ptln("</form>", $indent);
}
/**
@@ -406,17 +509,18 @@ class admin_plugin_usermanager extends DokuWiki_Admin_Plugin {
* @param bool $required is this field required?
* @param int $indent
*/
- protected function _htmlInputField($id, $name, $label, $value, $cando, $required, $indent=0) {
+ protected function htmlInputField($id, $name, $label, $value, $cando, $required, $indent = 0)
+ {
$class = $cando ? '' : ' class="disabled"';
- echo str_pad('',$indent);
+ echo str_pad('', $indent);
- if($name == 'userpass' || $name == 'userpass2'){
+ if ($name == 'userpass' || $name == 'userpass2') {
$fieldtype = 'password';
$autocomp = 'autocomplete="off"';
- }elseif($name == 'usermail'){
+ } elseif ($name == 'usermail') {
$fieldtype = 'email';
$autocomp = '';
- }else{
+ } else {
$fieldtype = 'text';
$autocomp = '';
}
@@ -425,13 +529,15 @@ class admin_plugin_usermanager extends DokuWiki_Admin_Plugin {
echo "<tr $class>";
echo "<td><label for=\"$id\" >$label: </label></td>";
echo "<td>";
- if($cando){
+ if ($cando) {
$req = '';
- if($required) $req = 'required="required"';
- echo "<input type=\"$fieldtype\" id=\"$id\" name=\"$name\" value=\"$value\" class=\"edit\" $autocomp $req />";
- }else{
+ if ($required) $req = 'required="required"';
+ echo "<input type=\"$fieldtype\" id=\"$id\" name=\"$name\"
+ value=\"$value\" class=\"edit\" $autocomp $req />";
+ } else {
echo "<input type=\"hidden\" name=\"$name\" value=\"$value\" />";
- echo "<input type=\"$fieldtype\" id=\"$id\" name=\"$name\" value=\"$value\" class=\"edit disabled\" disabled=\"disabled\" />";
+ echo "<input type=\"$fieldtype\" id=\"$id\" name=\"$name\"
+ value=\"$value\" class=\"edit disabled\" disabled=\"disabled\" />";
}
echo "</td>";
echo "</tr>";
@@ -443,9 +549,10 @@ class admin_plugin_usermanager extends DokuWiki_Admin_Plugin {
* @param string $key name of search field
* @return string html escaped value
*/
- protected function _htmlFilter($key) {
- if (empty($this->_filter)) return '';
- return (isset($this->_filter[$key]) ? hsc($this->_filter[$key]) : '');
+ protected function htmlFilter($key)
+ {
+ if (empty($this->filter)) return '';
+ return (isset($this->filter[$key]) ? hsc($this->filter[$key]) : '');
}
/**
@@ -453,12 +560,13 @@ class admin_plugin_usermanager extends DokuWiki_Admin_Plugin {
*
* @param int $indent
*/
- protected function _htmlFilterSettings($indent=0) {
+ protected function htmlFilterSettings($indent = 0)
+ {
- ptln("<input type=\"hidden\" name=\"start\" value=\"".$this->_start."\" />",$indent);
+ ptln("<input type=\"hidden\" name=\"start\" value=\"".$this->start."\" />", $indent);
- foreach ($this->_filter as $key => $filter) {
- ptln("<input type=\"hidden\" name=\"filter[".$key."]\" value=\"".hsc($filter)."\" />",$indent);
+ foreach ($this->filter as $key => $filter) {
+ ptln("<input type=\"hidden\" name=\"filter[".$key."]\" value=\"".hsc($filter)."\" />", $indent);
}
}
@@ -467,57 +575,57 @@ class admin_plugin_usermanager extends DokuWiki_Admin_Plugin {
*
* @param int $indent
*/
- protected function _htmlImportForm($indent=0) {
+ protected function htmlImportForm($indent = 0)
+ {
global $ID;
- $failure_download_link = wl($ID,array('do'=>'admin','page'=>'usermanager','fn[importfails]'=>1));
+ $failure_download_link = wl($ID, array('do'=>'admin','page'=>'usermanager','fn[importfails]'=>1));
- ptln('<div class="level2 import_users">',$indent);
+ ptln('<div class="level2 import_users">', $indent);
print $this->locale_xhtml('import');
- ptln(' <form action="'.wl($ID).'" method="post" enctype="multipart/form-data">',$indent);
+ ptln(' <form action="'.wl($ID).'" method="post" enctype="multipart/form-data">', $indent);
formSecurityToken();
- ptln(' <label>'.$this->lang['import_userlistcsv'].'<input type="file" name="import" /></label>',$indent);
- ptln(' <button type="submit" name="fn[import]">'.$this->lang['import'].'</button>',$indent);
- ptln(' <input type="hidden" name="do" value="admin" />',$indent);
- ptln(' <input type="hidden" name="page" value="usermanager" />',$indent);
+ ptln(' <label>'.$this->lang['import_userlistcsv'].'<input type="file" name="import" /></label>', $indent);
+ ptln(' <button type="submit" name="fn[import]">'.$this->lang['import'].'</button>', $indent);
+ ptln(' <input type="hidden" name="do" value="admin" />', $indent);
+ ptln(' <input type="hidden" name="page" value="usermanager" />', $indent);
- $this->_htmlFilterSettings($indent+4);
- ptln(' </form>',$indent);
+ $this->htmlFilterSettings($indent+4);
+ ptln(' </form>', $indent);
ptln('</div>');
// list failures from the previous import
- if ($this->_import_failures) {
- $digits = strlen(count($this->_import_failures));
- ptln('<div class="level3 import_failures">',$indent);
+ if ($this->import_failures) {
+ $digits = strlen(count($this->import_failures));
+ ptln('<div class="level3 import_failures">', $indent);
ptln(' <h3>'.$this->lang['import_header'].'</h3>');
- ptln(' <table class="import_failures">',$indent);
- ptln(' <thead>',$indent);
- ptln(' <tr>',$indent);
- ptln(' <th class="line">'.$this->lang['line'].'</th>',$indent);
- ptln(' <th class="error">'.$this->lang['error'].'</th>',$indent);
- ptln(' <th class="userid">'.$this->lang['user_id'].'</th>',$indent);
- ptln(' <th class="username">'.$this->lang['user_name'].'</th>',$indent);
- ptln(' <th class="usermail">'.$this->lang['user_mail'].'</th>',$indent);
- ptln(' <th class="usergroups">'.$this->lang['user_groups'].'</th>',$indent);
- ptln(' </tr>',$indent);
- ptln(' </thead>',$indent);
- ptln(' <tbody>',$indent);
- foreach ($this->_import_failures as $line => $failure) {
- ptln(' <tr>',$indent);
- ptln(' <td class="lineno"> '.sprintf('%0'.$digits.'d',$line).' </td>',$indent);
+ ptln(' <table class="import_failures">', $indent);
+ ptln(' <thead>', $indent);
+ ptln(' <tr>', $indent);
+ ptln(' <th class="line">'.$this->lang['line'].'</th>', $indent);
+ ptln(' <th class="error">'.$this->lang['error'].'</th>', $indent);
+ ptln(' <th class="userid">'.$this->lang['user_id'].'</th>', $indent);
+ ptln(' <th class="username">'.$this->lang['user_name'].'</th>', $indent);
+ ptln(' <th class="usermail">'.$this->lang['user_mail'].'</th>', $indent);
+ ptln(' <th class="usergroups">'.$this->lang['user_groups'].'</th>', $indent);
+ ptln(' </tr>', $indent);
+ ptln(' </thead>', $indent);
+ ptln(' <tbody>', $indent);
+ foreach ($this->import_failures as $line => $failure) {
+ ptln(' <tr>', $indent);
+ ptln(' <td class="lineno"> '.sprintf('%0'.$digits.'d', $line).' </td>', $indent);
ptln(' <td class="error">' .$failure['error'].' </td>', $indent);
- ptln(' <td class="field userid"> '.hsc($failure['user'][0]).' </td>',$indent);
- ptln(' <td class="field username"> '.hsc($failure['user'][2]).' </td>',$indent);
- ptln(' <td class="field usermail"> '.hsc($failure['user'][3]).' </td>',$indent);
- ptln(' <td class="field usergroups"> '.hsc($failure['user'][4]).' </td>',$indent);
- ptln(' </tr>',$indent);
+ ptln(' <td class="field userid"> '.hsc($failure['user'][0]).' </td>', $indent);
+ ptln(' <td class="field username"> '.hsc($failure['user'][2]).' </td>', $indent);
+ ptln(' <td class="field usermail"> '.hsc($failure['user'][3]).' </td>', $indent);
+ ptln(' <td class="field usergroups"> '.hsc($failure['user'][4]).' </td>', $indent);
+ ptln(' </tr>', $indent);
}
- ptln(' </tbody>',$indent);
- ptln(' </table>',$indent);
+ ptln(' </tbody>', $indent);
+ ptln(' </table>', $indent);
ptln(' <p><a href="'.$failure_download_link.'">'.$this->lang['import_downloadfailures'].'</a></p>');
ptln('</div>');
}
-
}
/**
@@ -525,17 +633,18 @@ class admin_plugin_usermanager extends DokuWiki_Admin_Plugin {
*
* @return bool whether succesful
*/
- protected function _addUser(){
+ protected function addUser()
+ {
global $INPUT;
if (!checkSecurityToken()) return false;
- if (!$this->_auth->canDo('addUser')) return false;
+ if (!$this->auth->canDo('addUser')) return false;
- list($user,$pass,$name,$mail,$grps,$passconfirm) = $this->_retrieveUser();
+ list($user,$pass,$name,$mail,$grps,$passconfirm) = $this->retrieveUser();
if (empty($user)) return false;
- if ($this->_auth->canDo('modPass')){
- if (empty($pass)){
- if($INPUT->has('usernotify')){
+ if ($this->auth->canDo('modPass')) {
+ if (empty($pass)) {
+ if ($INPUT->has('usernotify')) {
$pass = auth_pwgen($user);
} else {
msg($this->lang['add_fail'], -1);
@@ -543,54 +652,53 @@ class admin_plugin_usermanager extends DokuWiki_Admin_Plugin {
return false;
}
} else {
- if (!$this->_verifyPassword($pass,$passconfirm)) {
+ if (!$this->verifyPassword($pass, $passconfirm)) {
msg($this->lang['add_fail'], -1);
msg($this->lang['addUser_error_pass_not_identical'], -1);
return false;
}
}
} else {
- if (!empty($pass)){
+ if (!empty($pass)) {
msg($this->lang['add_fail'], -1);
msg($this->lang['addUser_error_modPass_disabled'], -1);
return false;
}
}
- if ($this->_auth->canDo('modName')){
- if (empty($name)){
+ if ($this->auth->canDo('modName')) {
+ if (empty($name)) {
msg($this->lang['add_fail'], -1);
msg($this->lang['addUser_error_name_missing'], -1);
return false;
}
} else {
- if (!empty($name)){
+ if (!empty($name)) {
msg($this->lang['add_fail'], -1);
msg($this->lang['addUser_error_modName_disabled'], -1);
return false;
}
}
- if ($this->_auth->canDo('modMail')){
- if (empty($mail)){
+ if ($this->auth->canDo('modMail')) {
+ if (empty($mail)) {
msg($this->lang['add_fail'], -1);
msg($this->lang['addUser_error_mail_missing'], -1);
return false;
}
} else {
- if (!empty($mail)){
+ if (!empty($mail)) {
msg($this->lang['add_fail'], -1);
msg($this->lang['addUser_error_modMail_disabled'], -1);
return false;
}
}
- if ($ok = $this->_auth->triggerUserMod('create', array($user,$pass,$name,$mail,$grps))) {
-
+ if ($ok = $this->auth->triggerUserMod('create', array($user, $pass, $name, $mail, $grps))) {
msg($this->lang['add_ok'], 1);
if ($INPUT->has('usernotify') && $pass) {
- $this->_notifyUser($user,$pass);
+ $this->notifyUser($user, $pass);
}
} else {
msg($this->lang['add_fail'], -1);
@@ -605,33 +713,34 @@ class admin_plugin_usermanager extends DokuWiki_Admin_Plugin {
*
* @return bool whether succesful
*/
- protected function _deleteUser(){
+ protected function deleteUser()
+ {
global $conf, $INPUT;
if (!checkSecurityToken()) return false;
- if (!$this->_auth->canDo('delUser')) return false;
+ if (!$this->auth->canDo('delUser')) return false;
$selected = $INPUT->arr('delete');
if (empty($selected)) return false;
$selected = array_keys($selected);
- if(in_array($_SERVER['REMOTE_USER'], $selected)) {
+ if (in_array($_SERVER['REMOTE_USER'], $selected)) {
msg("You can't delete yourself!", -1);
return false;
}
- $count = $this->_auth->triggerUserMod('delete', array($selected));
+ $count = $this->auth->triggerUserMod('delete', array($selected));
if ($count == count($selected)) {
$text = str_replace('%d', $count, $this->lang['delete_ok']);
msg("$text.", 1);
} else {
$part1 = str_replace('%d', $count, $this->lang['delete_ok']);
$part2 = str_replace('%d', (count($selected)-$count), $this->lang['delete_fail']);
- msg("$part1, $part2",-1);
+ msg("$part1, $part2", -1);
}
// invalidate all sessions
- io_saveFile($conf['cachedir'].'/sessionpurge',time());
+ io_saveFile($conf['cachedir'].'/sessionpurge', time());
return true;
}
@@ -642,20 +751,21 @@ class admin_plugin_usermanager extends DokuWiki_Admin_Plugin {
* @param string $param id of the user
* @return bool whether succesful
*/
- protected function _editUser($param) {
+ protected function editUser($param)
+ {
if (!checkSecurityToken()) return false;
- if (!$this->_auth->canDo('UserMod')) return false;
- $user = $this->_auth->cleanUser(preg_replace('/.*[:\/]/','',$param));
- $userdata = $this->_auth->getUserData($user);
+ if (!$this->auth->canDo('UserMod')) return false;
+ $user = $this->auth->cleanUser(preg_replace('/.*[:\/]/', '', $param));
+ $userdata = $this->auth->getUserData($user);
// no user found?
if (!$userdata) {
- msg($this->lang['edit_usermissing'],-1);
+ msg($this->lang['edit_usermissing'], -1);
return false;
}
- $this->_edit_user = $user;
- $this->_edit_userdata = $userdata;
+ $this->edit_user = $user;
+ $this->edit_userdata = $userdata;
return true;
}
@@ -665,39 +775,39 @@ class admin_plugin_usermanager extends DokuWiki_Admin_Plugin {
*
* @return bool whether succesful
*/
- protected function _modifyUser(){
+ protected function modifyUser()
+ {
global $conf, $INPUT;
if (!checkSecurityToken()) return false;
- if (!$this->_auth->canDo('UserMod')) return false;
+ if (!$this->auth->canDo('UserMod')) return false;
// get currently valid user data
- $olduser = $this->_auth->cleanUser(preg_replace('/.*[:\/]/','',$INPUT->str('userid_old')));
- $oldinfo = $this->_auth->getUserData($olduser);
+ $olduser = $this->auth->cleanUser(preg_replace('/.*[:\/]/', '', $INPUT->str('userid_old')));
+ $oldinfo = $this->auth->getUserData($olduser);
// get new user data subject to change
- list($newuser,$newpass,$newname,$newmail,$newgrps,$passconfirm) = $this->_retrieveUser();
+ list($newuser,$newpass,$newname,$newmail,$newgrps,$passconfirm) = $this->retrieveUser();
if (empty($newuser)) return false;
$changes = array();
if ($newuser != $olduser) {
-
- if (!$this->_auth->canDo('modLogin')) { // sanity check, shouldn't be possible
- msg($this->lang['update_fail'],-1);
+ if (!$this->auth->canDo('modLogin')) { // sanity check, shouldn't be possible
+ msg($this->lang['update_fail'], -1);
return false;
}
// check if $newuser already exists
- if ($this->_auth->getUserData($newuser)) {
- msg(sprintf($this->lang['update_exists'],$newuser),-1);
+ if ($this->auth->getUserData($newuser)) {
+ msg(sprintf($this->lang['update_exists'], $newuser), -1);
$re_edit = true;
} else {
$changes['user'] = $newuser;
}
}
- if ($this->_auth->canDo('modPass')) {
+ if ($this->auth->canDo('modPass')) {
if ($newpass || $passconfirm) {
- if ($this->_verifyPassword($newpass,$passconfirm)) {
+ if ($this->verifyPassword($newpass, $passconfirm)) {
$changes['pass'] = $newpass;
} else {
return false;
@@ -710,33 +820,32 @@ class admin_plugin_usermanager extends DokuWiki_Admin_Plugin {
}
}
- if (!empty($newname) && $this->_auth->canDo('modName') && $newname != $oldinfo['name']) {
+ if (!empty($newname) && $this->auth->canDo('modName') && $newname != $oldinfo['name']) {
$changes['name'] = $newname;
}
- if (!empty($newmail) && $this->_auth->canDo('modMail') && $newmail != $oldinfo['mail']) {
+ if (!empty($newmail) && $this->auth->canDo('modMail') && $newmail != $oldinfo['mail']) {
$changes['mail'] = $newmail;
}
- if (!empty($newgrps) && $this->_auth->canDo('modGroups') && $newgrps != $oldinfo['grps']) {
+ if (!empty($newgrps) && $this->auth->canDo('modGroups') && $newgrps != $oldinfo['grps']) {
$changes['grps'] = $newgrps;
}
- if ($ok = $this->_auth->triggerUserMod('modify', array($olduser, $changes))) {
- msg($this->lang['update_ok'],1);
+ if ($ok = $this->auth->triggerUserMod('modify', array($olduser, $changes))) {
+ msg($this->lang['update_ok'], 1);
if ($INPUT->has('usernotify') && !empty($changes['pass'])) {
$notify = empty($changes['user']) ? $olduser : $newuser;
- $this->_notifyUser($notify,$changes['pass']);
+ $this->notifyUser($notify, $changes['pass']);
}
// invalidate all sessions
- io_saveFile($conf['cachedir'].'/sessionpurge',time());
-
+ io_saveFile($conf['cachedir'].'/sessionpurge', time());
} else {
- msg($this->lang['update_fail'],-1);
+ msg($this->lang['update_fail'], -1);
}
if (!empty($re_edit)) {
- $this->_editUser($olduser);
+ $this->editUser($olduser);
}
return $ok;
@@ -750,9 +859,10 @@ class admin_plugin_usermanager extends DokuWiki_Admin_Plugin {
* @param bool $status_alert whether status alert should be shown
* @return bool whether succesful
*/
- protected function _notifyUser($user, $password, $status_alert=true) {
+ protected function notifyUser($user, $password, $status_alert = true)
+ {
- if ($sent = auth_sendPassword($user,$password)) {
+ if ($sent = auth_sendPassword($user, $password)) {
if ($status_alert) {
msg($this->lang['notify_ok'], 1);
}
@@ -773,7 +883,8 @@ class admin_plugin_usermanager extends DokuWiki_Admin_Plugin {
* @param string $confirm repeated password for confirmation
* @return bool true if meets requirements, false otherwise
*/
- protected function _verifyPassword($password, $confirm) {
+ protected function verifyPassword($password, $confirm)
+ {
global $lang;
if (empty($password) && empty($confirm)) {
@@ -797,7 +908,8 @@ class admin_plugin_usermanager extends DokuWiki_Admin_Plugin {
* @param bool $clean whether the cleanUser method of the authentication backend is applied
* @return array (user, password, full name, email, array(groups))
*/
- protected function _retrieveUser($clean=true) {
+ protected function retrieveUser($clean = true)
+ {
/** @var DokuWiki_Auth_Plugin $auth */
global $auth;
global $INPUT;
@@ -807,14 +919,14 @@ class admin_plugin_usermanager extends DokuWiki_Admin_Plugin {
$user[1] = $INPUT->str('userpass');
$user[2] = $INPUT->str('username');
$user[3] = $INPUT->str('usermail');
- $user[4] = explode(',',$INPUT->str('usergroups'));
+ $user[4] = explode(',', $INPUT->str('usergroups'));
$user[5] = $INPUT->str('userpass2'); // repeated password for confirmation
- $user[4] = array_map('trim',$user[4]);
- if($clean) $user[4] = array_map(array($auth,'cleanGroup'),$user[4]);
+ $user[4] = array_map('trim', $user[4]);
+ if ($clean) $user[4] = array_map(array($auth,'cleanGroup'), $user[4]);
$user[4] = array_filter($user[4]);
$user[4] = array_unique($user[4]);
- if(!count($user[4])) $user[4] = null;
+ if (!count($user[4])) $user[4] = null;
return $user;
}
@@ -824,17 +936,18 @@ class admin_plugin_usermanager extends DokuWiki_Admin_Plugin {
*
* @param string $op 'new' or 'clear'
*/
- protected function _setFilter($op) {
+ protected function setFilter($op)
+ {
- $this->_filter = array();
+ $this->filter = array();
if ($op == 'new') {
- list($user,/* $pass */,$name,$mail,$grps) = $this->_retrieveUser(false);
+ list($user,/* $pass */,$name,$mail,$grps) = $this->retrieveUser(false);
- if (!empty($user)) $this->_filter['user'] = $user;
- if (!empty($name)) $this->_filter['name'] = $name;
- if (!empty($mail)) $this->_filter['mail'] = $mail;
- if (!empty($grps)) $this->_filter['grps'] = join('|',$grps);
+ if (!empty($user)) $this->filter['user'] = $user;
+ if (!empty($name)) $this->filter['name'] = $name;
+ if (!empty($mail)) $this->filter['mail'] = $mail;
+ if (!empty($grps)) $this->filter['grps'] = join('|', $grps);
}
}
@@ -843,7 +956,8 @@ class admin_plugin_usermanager extends DokuWiki_Admin_Plugin {
*
* @return array
*/
- protected function _retrieveFilter() {
+ protected function retrieveFilter()
+ {
global $INPUT;
$t_filter = $INPUT->arr('filter');
@@ -862,14 +976,15 @@ class admin_plugin_usermanager extends DokuWiki_Admin_Plugin {
/**
* Validate and improve the pagination values
*/
- protected function _validatePagination() {
+ protected function validatePagination()
+ {
- if ($this->_start >= $this->_user_total) {
- $this->_start = $this->_user_total - $this->_pagesize;
+ if ($this->start >= $this->users_total) {
+ $this->start = $this->users_total - $this->pagesize;
}
- if ($this->_start < 0) $this->_start = 0;
+ if ($this->start < 0) $this->start = 0;
- $this->_last = min($this->_user_total, $this->_start + $this->_pagesize);
+ $this->last = min($this->users_total, $this->start + $this->pagesize);
}
/**
@@ -877,21 +992,23 @@ class admin_plugin_usermanager extends DokuWiki_Admin_Plugin {
*
* @return array with enable/disable attributes
*/
- protected function _pagination() {
+ protected function pagination()
+ {
$disabled = 'disabled="disabled"';
$buttons = array();
- $buttons['start'] = $buttons['prev'] = ($this->_start == 0) ? $disabled : '';
+ $buttons['start'] = $buttons['prev'] = ($this->start == 0) ? $disabled : '';
- if ($this->_user_total == -1) {
+ if ($this->users_total == -1) {
$buttons['last'] = $disabled;
$buttons['next'] = '';
} else {
- $buttons['last'] = $buttons['next'] = (($this->_start + $this->_pagesize) >= $this->_user_total) ? $disabled : '';
+ $buttons['last'] = $buttons['next'] =
+ (($this->start + $this->pagesize) >= $this->users_total) ? $disabled : '';
}
- if ($this->_lastdisabled) {
+ if ($this->lastdisabled) {
$buttons['last'] = $disabled;
}
@@ -901,9 +1018,10 @@ class admin_plugin_usermanager extends DokuWiki_Admin_Plugin {
/**
* Export a list of users in csv format using the current filter criteria
*/
- protected function _export() {
+ protected function exportCSV()
+ {
// list of users for export - based on current filter criteria
- $user_list = $this->_auth->retrieveUsers(0, 0, $this->_filter);
+ $user_list = $this->auth->retrieveUsers(0, 0, $this->filter);
$column_headings = array(
$this->lang["user_id"],
$this->lang["user_name"],
@@ -920,14 +1038,16 @@ class admin_plugin_usermanager extends DokuWiki_Admin_Plugin {
# header('Content-type: text/plain;charset=utf-8');
// output the csv
- $fd = fopen('php://output','w');
+ $fd = fopen('php://output', 'w');
fputcsv($fd, $column_headings);
foreach ($user_list as $user => $info) {
- $line = array($user, $info['name'], $info['mail'], join(',',$info['grps']));
+ $line = array($user, $info['name'], $info['mail'], join(',', $info['grps']));
fputcsv($fd, $line);
}
fclose($fd);
- if (defined('DOKU_UNITTEST')){ return; }
+ if (defined('DOKU_UNITTEST')) {
+ return;
+ }
die;
}
@@ -939,25 +1059,28 @@ class admin_plugin_usermanager extends DokuWiki_Admin_Plugin {
*
* @return bool whether successful
*/
- protected function _import() {
+ protected function importCSV()
+ {
// check we are allowed to add users
if (!checkSecurityToken()) return false;
- if (!$this->_auth->canDo('addUser')) return false;
+ if (!$this->auth->canDo('addUser')) return false;
// check file uploaded ok.
- if (empty($_FILES['import']['size']) || !empty($_FILES['import']['error']) && $this->_isUploadedFile($_FILES['import']['tmp_name'])) {
- msg($this->lang['import_error_upload'],-1);
+ if (empty($_FILES['import']['size']) ||
+ !empty($_FILES['import']['error']) && $this->isUploadedFile($_FILES['import']['tmp_name'])
+ ) {
+ msg($this->lang['import_error_upload'], -1);
return false;
}
// retrieve users from the file
- $this->_import_failures = array();
+ $this->import_failures = array();
$import_success_count = 0;
$import_fail_count = 0;
$line = 0;
- $fd = fopen($_FILES['import']['tmp_name'],'r');
+ $fd = fopen($_FILES['import']['tmp_name'], 'r');
if ($fd) {
- while($csv = fgets($fd)){
- if (!utf8_check($csv)) {
+ while ($csv = fgets($fd)) {
+ if (!\dokuwiki\Utf8\Clean::isUtf8($csv)) {
$csv = utf8_encode($csv);
}
$raw = str_getcsv($csv);
@@ -969,35 +1092,42 @@ class admin_plugin_usermanager extends DokuWiki_Admin_Plugin {
if (count($raw) < 4) { // need at least four fields
$import_fail_count++;
$error = sprintf($this->lang['import_error_fields'], count($raw));
- $this->_import_failures[$line] = array('error' => $error, 'user' => $raw, 'orig' => $csv);
+ $this->import_failures[$line] = array('error' => $error, 'user' => $raw, 'orig' => $csv);
continue;
}
- array_splice($raw,1,0,auth_pwgen()); // splice in a generated password
- $clean = $this->_cleanImportUser($raw, $error);
- if ($clean && $this->_addImportUser($clean, $error)) {
- $sent = $this->_notifyUser($clean[0],$clean[1],false);
- if (!$sent){
- msg(sprintf($this->lang['import_notify_fail'],$clean[0],$clean[3]),-1);
+ array_splice($raw, 1, 0, auth_pwgen()); // splice in a generated password
+ $clean = $this->cleanImportUser($raw, $error);
+ if ($clean && $this->importUser($clean, $error)) {
+ $sent = $this->notifyUser($clean[0], $clean[1], false);
+ if (!$sent) {
+ msg(sprintf($this->lang['import_notify_fail'], $clean[0], $clean[3]), -1);
}
$import_success_count++;
} else {
$import_fail_count++;
array_splice($raw, 1, 1); // remove the spliced in password
- $this->_import_failures[$line] = array('error' => $error, 'user' => $raw, 'orig' => $csv);
+ $this->import_failures[$line] = array('error' => $error, 'user' => $raw, 'orig' => $csv);
}
}
- msg(sprintf($this->lang['import_success_count'], ($import_success_count+$import_fail_count), $import_success_count),($import_success_count ? 1 : -1));
+ msg(
+ sprintf(
+ $this->lang['import_success_count'],
+ ($import_success_count + $import_fail_count),
+ $import_success_count
+ ),
+ ($import_success_count ? 1 : -1)
+ );
if ($import_fail_count) {
- msg(sprintf($this->lang['import_failure_count'], $import_fail_count),-1);
+ msg(sprintf($this->lang['import_failure_count'], $import_fail_count), -1);
}
} else {
- msg($this->lang['import_error_readfail'],-1);
+ msg($this->lang['import_error_readfail'], -1);
}
// save import failures into the session
if (!headers_sent()) {
session_start();
- $_SESSION['import_failures'] = $this->_import_failures;
+ $_SESSION['import_failures'] = $this->import_failures;
session_write_close();
}
return true;
@@ -1010,17 +1140,18 @@ class admin_plugin_usermanager extends DokuWiki_Admin_Plugin {
* @param string $error
* @return array|false cleaned data or false
*/
- protected function _cleanImportUser($candidate, & $error){
+ protected function cleanImportUser($candidate, & $error)
+ {
global $INPUT;
- // kludgy ....
+ // FIXME kludgy ....
$INPUT->set('userid', $candidate[0]);
$INPUT->set('userpass', $candidate[1]);
$INPUT->set('username', $candidate[2]);
$INPUT->set('usermail', $candidate[3]);
$INPUT->set('usergroups', $candidate[4]);
- $cleaned = $this->_retrieveUser();
+ $cleaned = $this->retrieveUser();
list($user,/* $pass */,$name,$mail,/* $grps */) = $cleaned;
if (empty($user)) {
$error = $this->lang['import_error_baduserid'];
@@ -1029,12 +1160,12 @@ class admin_plugin_usermanager extends DokuWiki_Admin_Plugin {
// no need to check password, handled elsewhere
- if (!($this->_auth->canDo('modName') xor empty($name))){
+ if (!($this->auth->canDo('modName') xor empty($name))) {
$error = $this->lang['import_error_badname'];
return false;
}
- if ($this->_auth->canDo('modMail')) {
+ if ($this->auth->canDo('modMail')) {
if (empty($mail) || !mail_isvalid($mail)) {
$error = $this->lang['import_error_badmail'];
return false;
@@ -1058,8 +1189,9 @@ class admin_plugin_usermanager extends DokuWiki_Admin_Plugin {
* @param string &$error reference catched error message
* @return bool whether successful
*/
- protected function _addImportUser($user, & $error){
- if (!$this->_auth->triggerUserMod('create', $user)) {
+ protected function importUser($user, &$error)
+ {
+ if (!$this->auth->triggerUserMod('create', $user)) {
$error = $this->lang['import_error_create'];
return false;
}
@@ -1070,7 +1202,8 @@ class admin_plugin_usermanager extends DokuWiki_Admin_Plugin {
/**
* Downloads failures as csv file
*/
- protected function _downloadImportFailures(){
+ protected function downloadImportFailures()
+ {
// ==============================================================================================
// GENERATE OUTPUT
@@ -1081,8 +1214,8 @@ class admin_plugin_usermanager extends DokuWiki_Admin_Plugin {
# header('Content-type: text/plain;charset=utf-8');
// output the csv
- $fd = fopen('php://output','w');
- foreach ($this->_import_failures as $fail) {
+ $fd = fopen('php://output', 'w');
+ foreach ($this->import_failures as $fail) {
fputs($fd, $fail['orig']);
}
fclose($fd);
@@ -1095,7 +1228,8 @@ class admin_plugin_usermanager extends DokuWiki_Admin_Plugin {
* @param string $file filename
* @return bool
*/
- protected function _isUploadedFile($file) {
+ protected function isUploadedFile($file)
+ {
return is_uploaded_file($file);
}
}
diff --git a/lib/tpl/dokuwiki/images/pagetools-build.php b/lib/tpl/dokuwiki/images/pagetools-build.php
index eaceeb257..e19d750c7 100644
--- a/lib/tpl/dokuwiki/images/pagetools-build.php
+++ b/lib/tpl/dokuwiki/images/pagetools-build.php
@@ -1,4 +1,5 @@
<?php
+// phpcs:ignoreFile -- deprecated and will be removed
/**
* This script generates a sprite from the unprocessed pagetool icons by combining them
* and overlaying a color layer for the active state.
@@ -10,6 +11,7 @@
* The final sprite is optimized with optipng if available.
*
* @author Andreas Gohr <andi@splitbrain.org>
+ * @deprecated 2018-06-15 we no longer use PNG based icons
* @todo Maybe add some more error checking
*/
$GAMMA = 0.8;
diff --git a/lib/tpl/dokuwiki/tpl_footer.php b/lib/tpl/dokuwiki/tpl_footer.php
index 34e8b90f6..c7a04e155 100644
--- a/lib/tpl/dokuwiki/tpl_footer.php
+++ b/lib/tpl/dokuwiki/tpl_footer.php
@@ -25,7 +25,8 @@ if (!defined('DOKU_INC')) die();
<a href="//jigsaw.w3.org/css-validator/check/referer?profile=css3" title="Valid CSS" <?php echo $target?>><img
src="<?php echo tpl_basedir(); ?>images/button-css.png" width="80" height="15" alt="Valid CSS" /></a>
<a href="https://dokuwiki.org/" title="Driven by DokuWiki" <?php echo $target?>><img
- src="<?php echo tpl_basedir(); ?>images/button-dw.png" width="80" height="15" alt="Driven by DokuWiki" /></a>
+ src="<?php echo tpl_basedir(); ?>images/button-dw.png" width="80" height="15"
+ alt="Driven by DokuWiki" /></a>
</div>
</div></div><!-- /footer -->
diff --git a/lib/tpl/index.php b/lib/tpl/index.php
index 8b021511c..a3e9a8849 100644
--- a/lib/tpl/index.php
+++ b/lib/tpl/index.php
@@ -8,6 +8,7 @@
* @author Andreas Gohr <andi@splitbrain.org>
* @author Anika Henke <anika@selfthinker.org>
*/
+// phpcs:disable PSR1.Files.SideEffects
if(!defined('DOKU_INC')) define('DOKU_INC',dirname(__FILE__).'/../../');
if(!defined('NOSESSION')) define('NOSESSION',1);
require_once(DOKU_INC.'inc/init.php');
@@ -44,8 +45,6 @@ require_once(DOKU_INC.'inc/init.php');
<body>
<?php
// get merged style.ini
-define('SIMPLE_TEST', true); // hack to prevent css output and headers
-require_once(DOKU_INC.'lib/exe/css.php');
$styleUtils = new \dokuwiki\StyleUtils($conf['template']);
$ini = $styleUtils->cssStyleini();