aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-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();