Merge branch 'master' into refactorResolving

* master: (142 commits)
  authPDO: extend mysql test to ensure multiple groups are read
  update DokuWiki install URL
  update smtp plugin URL
  update flashplayer URL
  Revert "Merge pull request #3039 from takuy/video-attributes"
  Revert "fixed video attribute handling in php8"
  Revert "more php8 fixes for the video attributes"
  guard against unsert user name. fixes #3455
  remove remaining X-UA-Compatible headers. fixes #3434
  more php8 fixes for the video attributes
  fixed video attribute handling in php8
  fix test for draft file
  fix security problems in draft handling. fixes #3565
  fix handling of loading auth backend
  check CSRF token in draftdel action. fixes #3563
  ignore another PSR12 style check for now
  authplain: properly clean user names
  Removes use of deprecated create_function() in teests. Replaces them with anonymous functions. Refs #3545
  check security token on logout. fixes #3561
  create SECURITY.md fixes #3558
  ...
This commit is contained in:
Andreas Gohr 2022-01-02 11:09:43 +01:00
commit b469737aef
119 changed files with 3499 additions and 2229 deletions

16
SECURITY.md Normal file
View File

@ -0,0 +1,16 @@
# Security Policy
Security vulnerabilities can be reported for the current stable release (branch `stable`) and the `master` branch.
We try to fix vulnerabilites as fast as possible, but please keep in mind that this is a project run by volunteers. Depending on the severity we may release hotfixes for the current stable release or may simply incorporate the fix in the next proper release.
**This policy only applies to DokuWiki and the bundled plugins. Do not report issues about 3rd party plugins here.**
## Reporting a Vulnerability
You have multiple options on reporting vulnerabilities
* Use [huntr.dev](https://www.huntr.dev/bounties/disclose/?target=https%3A%2F%2Fgithub.com%2Fsplitbrain%2Fdokuwiki%2F)
* Send an e-mail to [Andi](mailto:andi@splitbrain.org)
* Open a [Github Issue](https://github.com/splitbrain/dokuwiki/issues)
* Send a mail to the [Mailing List](https://www.dokuwiki.org/mailinglist)

View File

@ -195,7 +195,7 @@ abstract class DokuWikiTest extends PHPUnit\Framework\TestCase {
* Waits until a new second has passed
*
* This tried to be clever about the passing of time and return early if possible. Unfortunately
* this never worked reliably fo unknown reasons. To avoid flaky tests, this now always simply
* this never worked reliably for unknown reasons. To avoid flaky tests, this now always simply
* sleeps for a full second on every call.
*
* @param bool $init no longer used

View File

@ -1022,20 +1022,7 @@ class Callback
// return new Callback($this->callback, $this->params+$params);
// }
}
/**
* Shorthand for new Callback(create_function(...), ...);
*
* @author Tobiasz Cudnik <tobiasz.cudnik/gmail.com>
*/
class CallbackBody extends Callback {
public function __construct($paramList, $code, $param1 = null, $param2 = null,
$param3 = null) {
$params = func_get_args();
$params = array_slice($params, 2);
$this->callback = create_function($paramList, $code);
$this->params = $params;
}
}
/**
* Callback type which on execution returns reference passed during creation.
*
@ -2083,16 +2070,18 @@ class phpQueryObject
break;
case 'parent':
$this->elements = $this->map(
create_function('$node', '
function ($node) {
return $node instanceof DOMELEMENT && $node->childNodes->length
? $node : null;')
? $node : null;
}
)->elements;
break;
case 'empty':
$this->elements = $this->map(
create_function('$node', '
function ($node) {
return $node instanceof DOMELEMENT && $node->childNodes->length
? null : $node;')
? null : $node;
}
)->elements;
break;
case 'disabled':
@ -2105,19 +2094,21 @@ class phpQueryObject
break;
case 'enabled':
$this->elements = $this->map(
create_function('$node', '
return pq($node)->not(":disabled") ? $node : null;')
function ($node) {
return pq($node)->not(":disabled") ? $node : null;
}
)->elements;
break;
case 'header':
$this->elements = $this->map(
create_function('$node',
'$isHeader = isset($node->tagName) && in_array($node->tagName, array(
"h1", "h2", "h3", "h4", "h5", "h6", "h7"
));
function ($node) {
$isHeader = isset($node->tagName) && in_array($node->tagName, array(
"h1", "h2", "h3", "h4", "h5", "h6", "h7"
));
return $isHeader
? $node
: null;')
: null;
}
)->elements;
// $this->elements = $this->map(
// create_function('$node', '$node = pq($node);
@ -2134,18 +2125,23 @@ class phpQueryObject
break;
case 'only-child':
$this->elements = $this->map(
create_function('$node',
'return pq($node)->siblings()->size() == 0 ? $node : null;')
function ($node) {
return pq($node)->siblings()->size() == 0 ? $node : null;
}
)->elements;
break;
case 'first-child':
$this->elements = $this->map(
create_function('$node', 'return pq($node)->prevAll()->size() == 0 ? $node : null;')
function ($node) {
return pq($node)->prevAll()->size() == 0 ? $node : null;
}
)->elements;
break;
case 'last-child':
$this->elements = $this->map(
create_function('$node', 'return pq($node)->nextAll()->size() == 0 ? $node : null;')
function ($node) {
return pq($node)->nextAll()->size() == 0 ? $node : null;
}
)->elements;
break;
case 'nth-child':
@ -2158,45 +2154,46 @@ class phpQueryObject
// :nth-child(index/even/odd/equation)
if ($param == 'even' || $param == 'odd')
$mapped = $this->map(
create_function('$node, $param',
'$index = pq($node)->prevAll()->size()+1;
if ($param == "even" && ($index%2) == 0)
function ($node, $param) {
$index = pq($node)->prevAll()->size() + 1;
if ($param == "even" && ($index % 2) == 0)
return $node;
else if ($param == "odd" && $index%2 == 1)
else if ($param == "odd" && $index % 2 == 1)
return $node;
else
return null;'),
new CallbackParam(), $param
return null;
}, new CallbackParam(), $param
);
else if (mb_strlen($param) > 1 && $param[1] == 'n')
// an+b
$mapped = $this->map(
create_function('$node, $param',
'$prevs = pq($node)->prevAll()->size();
$index = 1+$prevs;
function ($node, $param) {
$prevs = pq($node)->prevAll()->size();
$index = 1 + $prevs;
$b = mb_strlen($param) > 3
? $param{3}
? $param[3]
: 0;
$a = $param{0};
if ($b && $param{2} == "-")
$a = $param[0];
if ($b && $param[2] == "-")
$b = -$b;
if ($a > 0) {
return ($index-$b)%$a == 0
return ($index - $b) % $a == 0
? $node
: null;
phpQuery::debug($a."*".floor($index/$a)."+$b-1 == ".($a*floor($index/$a)+$b-1)." ?= $prevs");
return $a*floor($index/$a)+$b-1 == $prevs
? $node
: null;
} else if ($a == 0)
phpQuery::debug($a . "*" . floor($index / $a) . "+$b-1 == " . ($a * floor($index / $a) + $b - 1) . " ?= $prevs");
return $a * floor($index / $a) + $b - 1 == $prevs
? $node
: null;
} else if ($a == 0) {
return $index == $b
? $node
: null;
else
? $node
: null;
} else {
// negative value
return $index <= $b
? $node
: null;
? $node
: null;
}
// if (! $b)
// return $index%$a == 0
// ? $node
@ -2205,20 +2202,21 @@ class phpQueryObject
// return ($index-$b)%$a == 0
// ? $node
// : null;
'),
},
new CallbackParam(), $param
);
else
// index
$mapped = $this->map(
create_function('$node, $index',
'$prevs = pq($node)->prevAll()->size();
if ($prevs && $prevs == $index-1)
function ($node, $index) {
$prevs = pq($node)->prevAll()->size();
if ($prevs && $prevs == $index - 1)
return $node;
else if (! $prevs && $index == 1)
else if (!$prevs && $index == 1)
return $node;
else
return null;'),
return null;
},
new CallbackParam(), $param
);
$this->elements = $mapped->elements;
@ -4742,15 +4740,15 @@ abstract class phpQuery {
while (preg_match($regex, $content))
$content = preg_replace_callback(
$regex,
create_function('$m',
'return $m[1].$m[2].$m[3]."<?php "
.str_replace(
function ($m) {
return $m[1] . $m[2] . $m[3] . '<?php '
. str_replace(
array("%20", "%3E", "%09", "&#10;", "&#9;", "%7B", "%24", "%7D", "%22", "%5B", "%5D"),
array(" ", ">", " ", "\n", " ", "{", "$", "}", \'"\', "[", "]"),
array(" ", ">", " ", "\n", " ", "{", "$", "}", '"', "[", "]"),
htmlspecialchars_decode($m[4])
)
." ?>".$m[5].$m[2];'
),
. " ?>" . $m[5] . $m[2];
},
$content
);
return $content;

View File

@ -67,6 +67,7 @@
<exclude name="PSR2.Namespaces.UseDeclaration.SpaceAfterLastUse"/>
<exclude name="PSR12.Classes.ClassInstantiation.MissingParentheses"/>
<exclude name="PSR12.Classes.OpeningBraceSpace.Found"/>
<exclude name="PSR12.ControlStructures.BooleanOperatorPlacement.FoundMixed"/>
<exclude name="PSR12.ControlStructures.ControlStructureSpacing.FirstExpressionLine"/>
<exclude name="PSR12.ControlStructures.ControlStructureSpacing.CloseParenthesisLine"/>
@ -76,7 +77,6 @@
<exclude name="PSR12.Files.FileHeader.SpacingAfterBlock"/>
<exclude name="PSR12.Operators.OperatorSpacing.NoSpaceBefore"/>
<exclude name="PSR12.Operators.OperatorSpacing.NoSpaceAfter"/>
<exclude name="PSR12.Properties.ConstantVisibility.NotFound"/>
</rule>

View File

@ -34,6 +34,7 @@ class XmlRpcServerTest extends DokuWikiTest
$file = wikiFN($pageName);
$timestamp = filemtime($file);
$ixrModifiedTime = (new DateTime('@' . $timestamp))->format(DateTime::ATOM);
$author = '127.0.0.1'; // read from changelog, $info['user'] or $info['ip']
$request = <<<EOD
<?xml version="1.0"?>
@ -54,7 +55,7 @@ EOD;
<struct>
<member><name>name</name><value><string>wiki:dokuwiki</string></value></member>
<member><name>lastModified</name><value><dateTime.iso8601>$ixrModifiedTime</dateTime.iso8601></value></member>
<member><name>author</name><value><string></string></value></member>
<member><name>author</name><value><string>$author</string></value></member>
<member><name>version</name><value><int>$timestamp</int></value></member>
</struct>
</value>

View File

@ -1,30 +0,0 @@
<?php
class auth_browseruid_test extends DokuWikiTest {
/**
* regression test to ensure correct browser id on IE9.
*
* IE9 send different HTTP_ACCEPT_LANGUAGE header on ajax request.
*/
function testIE9JsVsDefault() {
// javascript request
$_SERVER['HTTP_USER_AGENT'] = 'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)';
$_SERVER['HTTP_ACCEPT_ENCODING'] = 'gzip, deflate';
$_SERVER['HTTP_ACCEPT_LANGUAGE'] = 'de';
unset($_SERVER['HTTP_ACCEPT_CHARSET']);
$javascriptId = auth_browseruid();
// default request
$_SERVER['HTTP_USER_AGENT'] = 'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)';
$_SERVER['HTTP_ACCEPT_ENCODING'] = 'gzip, deflate';
$_SERVER['HTTP_ACCEPT_LANGUAGE'] = 'de-DE';
$normalId = auth_browseruid();
$this->assertEquals($normalId, $javascriptId);
}
}

View File

@ -35,12 +35,10 @@ class changelog_getrevisionsaround_test extends DokuWikiTest {
parent::setup();
global $cache_revinfo;
$cache =& $cache_revinfo;
if(isset($cache['nonexist'])) {
unset($cache['nonexist']);
}
if(isset($cache['mailinglist'])) {
unset($cache['mailinglist']);
}
unset($cache['nonexist']);
unset($cache['mailinglist']);
// fix filemtime of page source
touch(wikiFN($this->pageid), $this->revsexpected[0]);
}
/**

View File

@ -18,12 +18,8 @@ class changelog_getlastrevisionat_test extends DokuWikiTest {
parent::setup();
global $cache_revinfo;
$cache =& $cache_revinfo;
if(isset($cache['nonexist'])) {
unset($cache['nonexist']);
}
if(isset($cache['mailinglist'])) {
unset($cache['mailinglist']);
}
unset($cache['nonexist']);
unset($cache['mailinglist']);
}

View File

@ -18,12 +18,8 @@ class changelog_getrelativerevision_test extends DokuWikiTest {
parent::setup();
global $cache_revinfo;
$cache =& $cache_revinfo;
if(isset($cache['nonexist'])) {
unset($cache['nonexist']);
}
if(isset($cache['mailinglist'])) {
unset($cache['mailinglist']);
}
unset($cache['nonexist']);
unset($cache['mailinglist']);
}
/**

View File

@ -19,12 +19,8 @@ class changelog_getrevisionsinfo_test extends DokuWikiTest {
parent::setup();
global $cache_revinfo;
$cache =& $cache_revinfo;
if(isset($cache['nonexist'])) {
unset($cache['nonexist']);
}
if(isset($cache['mailinglist'])) {
unset($cache['mailinglist']);
}
unset($cache['nonexist']);
unset($cache['mailinglist']);
}
/**

View File

@ -35,12 +35,10 @@ class changelog_getrevisions_test extends DokuWikiTest {
parent::setup();
global $cache_revinfo;
$cache =& $cache_revinfo;
if(isset($cache['nonexist'])) {
unset($cache['nonexist']);
}
if(isset($cache['mailinglist'])) {
unset($cache['mailinglist']);
}
unset($cache['nonexist']);
unset($cache['mailinglist']);
// fix filemtime of page source
touch(wikiFN($this->pageid), $this->revsexpected[0]);
}
/**

View File

@ -13,7 +13,7 @@ class changelog_hasrevisions_test extends DokuWikiTest {
*/
function test_hasrevisions() {
$id = 'mailinglist';
$pagelog = new PageChangeLog($id);
$result = $pagelog->hasRevisions();
$this->assertTrue($result);
@ -24,7 +24,7 @@ class changelog_hasrevisions_test extends DokuWikiTest {
*/
function test_norevisions() {
$id = 'nonexist';
$pagelog = new PageChangeLog($id);
$result = $pagelog->hasRevisions();
$this->assertFalse($result);

View File

@ -201,6 +201,25 @@ class common_clientIP_test extends DokuWikiTest {
$this->assertEquals($out, clientIP());
}
// IPv6
function test_simple_single_ipv6(){
$_SERVER['REMOTE_ADDR'] = '1234:1234:1234:1234:1234:1234:1234:1234';
$_SERVER['HTTP_X_REAL_IP'] = '';
$_SERVER['HTTP_X_FORWARDED_FOR'] = '';
$out = '1234:1234:1234:1234:1234:1234:1234:1234';
$this->assertEquals($out, clientIP(true));
}
function test_proxyhops_garbage_all_ipv4_and_ipv6(){
$_SERVER['REMOTE_ADDR'] = '1234:1234:1234:1234:1234:1234:1234:1234';
$_SERVER['HTTP_X_REAL_IP'] = '1.1.1.1';
$_SERVER['HTTP_X_FORWARDED_FOR'] = '777:777:777:777:777:777:777:777,::1,skipme,66.66.66.66';
$out = '1234:1234:1234:1234:1234:1234:1234:1234,777:777:777:777:777:777:777:777,::1,66.66.66.66,1.1.1.1';
$this->assertEquals($out, clientIP());
}
}
//Setup VIM: ex: et ts=4 :

View File

@ -51,7 +51,7 @@ class common_pageinfo_test extends DokuWikiTest {
/**
* check info keys and values for a non-existent page & admin user
*/
function test_basic_nonexistentpage(){
function test_basic_nonexistentpage() {
global $ID,$conf;
$ID = 'wiki:start';
@ -66,12 +66,16 @@ class common_pageinfo_test extends DokuWikiTest {
/**
* check info keys and values for a existing page & admin user
*/
function test_basic_existingpage(){
function test_basic_existingpage() {
global $ID,$conf;
$ID = 'wiki:syntax';
$filename = $conf['datadir'].'/wiki/syntax.txt';
$rev = filemtime($filename);
// run once to prepare meta/wiki/syntax.change file for existing page
// because pageinfo() set $info['meta']['last_change'] entry
pageinfo();
$info = $this->_get_expected_pageinfo();
$info['id'] = 'wiki:syntax';
$info['namespace'] = 'wiki';
@ -80,6 +84,13 @@ class common_pageinfo_test extends DokuWikiTest {
$info['lastmod'] = $rev;
$info['currentrev'] = $rev;
$info['meta'] = p_get_metadata($ID);
// set from revinfo, $pagelog->getRevisionInfo($info['lastmod'])
$info = array_merge($info, array(
'ip' => '127.0.0.1',
'user' => '',
'sum' => 'created - external edit',
));
$info['editor'] = '127.0.0.1';
$this->assertEquals($info, pageinfo());
}
@ -87,7 +98,7 @@ class common_pageinfo_test extends DokuWikiTest {
/**
* check info keys and values for anonymous user
*/
function test_anonymoususer(){
function test_anonymoususer() {
global $ID,$conf,$REV;
unset($_SERVER['REMOTE_USER']);
@ -106,7 +117,15 @@ class common_pageinfo_test extends DokuWikiTest {
$info['currentrev'] = $rev;
$info['meta'] = p_get_metadata($ID);
$info['rev'] = '';
// set from revinfo, $pagelog->getRevisionInfo($info['lastmod'])
$info = array_merge($info, array(
'ip' => '127.0.0.1',
'user' => '',
'sum' => 'created - external edit',
));
$info['editor'] = '127.0.0.1';
// anonymous user
$info = array_merge($info, array(
'isadmin' => false,
'ismanager' => false,
@ -114,6 +133,7 @@ class common_pageinfo_test extends DokuWikiTest {
'client' => '1.2.3.4',
));
unset($info['userinfo']);
$this->assertEquals($info, pageinfo());
}
@ -121,7 +141,7 @@ class common_pageinfo_test extends DokuWikiTest {
* check info keys and values with $REV
* (also see $RANGE tests)
*/
function test_rev(){
function test_rev() {
global $ID,$conf,$REV;
$ID = 'wiki:syntax';
@ -129,7 +149,8 @@ class common_pageinfo_test extends DokuWikiTest {
$rev = filemtime($filename);
$REV = $rev - 100;
$ext = '.txt';
if($conf['compression']) { //compression in $info['filepath'] determined by wikiFN depends also on if the page exist
if ($conf['compression']) {
//compression in $info['filepath'] determined by wikiFN depends also on if the page exist
$ext .= "." . $conf['compression']; //.gz or .bz2
}
@ -148,7 +169,7 @@ class common_pageinfo_test extends DokuWikiTest {
/**
* check info keys and values with $RANGE
*/
function test_range(){
function test_range() {
global $ID,$conf,$REV,$RANGE;
$ID = 'wiki:syntax';
@ -164,6 +185,13 @@ class common_pageinfo_test extends DokuWikiTest {
$info['currentrev'] = $rev;
$info['meta'] = p_get_metadata($ID);
$info['filepath'] = $filename;
// set from revinfo, $pagelog->getRevisionInfo($info['lastmod'])
$info = array_merge($info, array(
'ip' => '127.0.0.1',
'user' => '',
'sum' => 'created - external edit',
));
$info['editor'] = '127.0.0.1';
// check $RANGE without $REV
// expected result $RANGE unchanged
@ -171,7 +199,7 @@ class common_pageinfo_test extends DokuWikiTest {
$this->assertEquals($info, pageinfo());
$this->assertFalse(isset($REV));
$this->assertEquals($range,$RANGE);
$this->assertEquals($range, $RANGE);
// check $RANGE with $REV = current
// expected result: $RANGE unchanged, $REV cleared
@ -180,21 +208,21 @@ class common_pageinfo_test extends DokuWikiTest {
$this->assertEquals($info, pageinfo());
$this->assertEquals('',$REV);
$this->assertEquals($range,$RANGE);
$this->assertEquals($range, $RANGE);
// check with a real $REV
// expected result: $REV and $RANGE are cleared
$REV = $rev - 100;
$this->assertEquals($info, pageinfo());
$this->assertEquals('',$REV);
$this->assertEquals('',$RANGE);
$this->assertEquals('', $REV);
$this->assertEquals('', $RANGE);
}
/**
* test editor entry and external edit
*/
function test_editor_and_externaledits(){
function test_editor_and_externaledits() {
global $ID,$conf;
$ID = 'wiki:syntax';
$filename = $conf['datadir'].'/wiki/syntax.txt';
@ -216,24 +244,24 @@ class common_pageinfo_test extends DokuWikiTest {
addLogEntry($rev, $ID);
$info['meta'] = p_get_metadata($ID);
$info['editor'] = $_SERVER['REMOTE_USER'];
$info['user'] = $_SERVER['REMOTE_USER'];
$info['ip'] = $_SERVER['REMOTE_ADDR'];
$info['user'] = $_SERVER['REMOTE_USER'];
$info['sum'] = '';
$info['editor'] = $info['user'];
// with an editor ...
$this->assertEquals($info, pageinfo());
// clear the meta['last_change'] value, pageinfo should restore it
p_set_metadata($ID,array('last_change' => false));
p_set_metadata($ID, array('last_change' => false));
$this->assertEquals($info, pageinfo());
$this->assertEquals($info['meta']['last_change'], p_get_metadata($ID,'last_change'));
// fake an external edit, pageinfo should clear the last change from meta data
// and not return any editor data
$now = time()+10;
touch($filename,$now);
$now = time() + 10;
touch($filename, $now);
$info['lastmod'] = $now;
$info['currentrev'] = $now;
@ -250,12 +278,16 @@ class common_pageinfo_test extends DokuWikiTest {
/**
* check draft
*/
function test_draft(){
function test_draft() {
global $ID,$conf;
$ID = 'wiki:syntax';
$filename = $conf['datadir'].'/wiki/syntax.txt';
$rev = filemtime($filename);
// run once to prepare meta/wiki/syntax.change file for existing page
// because pageinfo() set $info['meta']['last_change'] entry
pageinfo();
$info = $this->_get_expected_pageinfo();
$info['id'] = 'wiki:syntax';
$info['namespace'] = 'wiki';
@ -264,11 +296,23 @@ class common_pageinfo_test extends DokuWikiTest {
$info['lastmod'] = $rev;
$info['currentrev'] = $rev;
$info['meta'] = p_get_metadata($ID);
// $info['ip'] = $_SERVER['REMOTE_ADDR'];
// $info['user'] = $_SERVER['REMOTE_USER'];
// $info['sum'] = '';
// $info['editor'] = $info['user'];
// set from revinfo, $pagelog->getRevisionInfo($info['lastmod'])
$info = array_merge($info, array(
'ip' => '127.0.0.1',
'user' => '',
'sum' => 'external edit',
));
$info['editor'] = '127.0.0.1';
// setup a draft, make it more recent than the current page
// - pageinfo should recognise it and keep it
$draft = getCacheName($info['client'].$ID,'.draft');
touch($draft,$rev + 10);
$draft = getCacheName($info['client']."\n".$ID,'.draft');
touch($draft, $rev + 10);
$info['draft'] = $draft;
@ -287,7 +331,7 @@ class common_pageinfo_test extends DokuWikiTest {
/**
* check ismobile
*/
function test_ismobile(){
function test_ismobile() {
global $ID,$conf;
$ID = 'wiki:start';

View File

@ -2,7 +2,11 @@
use dokuwiki\ChangeLog\PageChangeLog;
/**
* saveWikiText() stores files in pages/, attic/ and adds entries to changelog
*/
class common_saveWikiText_test extends DokuWikiTest {
/** Delay writes of old revisions by a second. */
public function handle_write(Doku_Event $event, $param) {
if ($event->data[3] !== false) {
@ -11,161 +15,266 @@ class common_saveWikiText_test extends DokuWikiTest {
}
/**
* Execute a whole bunch of saves on the same page and check the results
* assertions against changelog entries and attic after saveWikiText()
*/
function test_savesequence() {
private function checkChangeLogAfterNormalSave(
PageChangeLog $pagelog,
$expectedRevs, // @param int
&$expectedLastEntry, // @param array, pass by reference
$expected2ndLastEntry = null // @param array (optional)
) {
$revisions = $pagelog->getRevisions(-1, 200);
$this->assertCount($expectedRevs, $revisions);
$this->assertCount($expectedRevs, array_unique($revisions), 'date duplicated in changelog');
// last revision
$lastRevInfo = $pagelog->getRevisionInfo($revisions[0]);
$expectedLastEntry += $lastRevInfo;
$this->assertEquals($expectedLastEntry, $lastRevInfo);
// current revision
$currentRevInfo = $pagelog->getCurrentRevisionInfo();
$this->assertEquals($currentRevInfo, $lastRevInfo, 'current & last revs should be identical');
// attic
$attic = wikiFN($lastRevInfo['id'], $lastRevInfo['date']);
$this->assertFileExists($attic, 'file missing in attic');
$files = count(glob(dirname($attic).'/'.noNS($lastRevInfo['id']).'.*'));
$this->assertLessThanOrEqual($expectedRevs, $files, 'detectExternalEdit() should not add too often old revs');
// second to last revision (optional), intended to check logline of previous external edits
if ($expected2ndLastEntry && count($revisions) > 1) {
$prevRevInfo = $pagelog->getRevisionInfo($revisions[1]);
unset($expected2ndLastEntry['timestamp']); // drop timestamp key
$this->assertEquals($expected2ndLastEntry, $prevRevInfo);
}
}
/**
* assertions against changelog entries and attic after external edit, create or deletion of page
*/
private function checkChangeLogAfterExternalEdit(
PageChangeLog $pagelog,
$expectedRevs, // @param int
$expectedLastEntry, // @param array
&$expectedCurrentEntry // @param array, pass by reference
) {
$revisions = $pagelog->getRevisions(-1, 200);
$this->assertCount($expectedRevs, $revisions);
$this->assertCount($expectedRevs, array_unique($revisions), 'date duplicated in changelog');
// last revision
if ($expectedRevs > 0) {
$lastRevInfo = $pagelog->getRevisionInfo($revisions[0]);
$expectedLastEntry += $lastRevInfo;
$this->assertEquals($expectedLastEntry, $lastRevInfo);
} else {
$this->assertFalse($pagelog->lastRevision(), 'changelog file does not yet exist');
}
// current revision
$currentRevInfo = $pagelog->getCurrentRevisionInfo();
$this->assertArrayHasKey('timestamp', $currentRevInfo, 'should be external revision');
$expectedCurrentEntry += $currentRevInfo;
if ($expectedRevs > 0) {
$this->assertEquals($expectedCurrentEntry, $currentRevInfo);
}
// attic
$attic = wikiFN($currentRevInfo['id'], $currentRevInfo['date']);
$this->assertFileNotExists($attic, 'page does not yet exist in attic');
}
/**
* Execute a whole bunch of saves on the same page and check the results
* TEST 1
* 1.1 create a page
* 1.2 save with same content should be ignored
* 1.3 update the page with new text
* 1.4 add a minor edit (unauthenticated, minor not allowable)
* 1.5 add a minor edit (authenticated)
* 1.6 delete
* 1.7 restore
* 1.8 external edit
* 1.9 edit and save on top of external edit
*/
function test_savesequence1() {
global $REV;
$page = 'page';
$file = wikiFN($page);
// create the page
$this->assertFileNotExists($file);
saveWikiText($page, 'teststring', 'first save', false);
// 1.1 create a page
saveWikiText($page, 'teststring', '1st save', false);
clearstatcache(false, $file);
$this->assertFileExists($file);
$lastmod = filemtime($file);
$expectedRevs = 1;
$expect = array(
'date' => $lastmod,
'type' => DOKU_CHANGE_TYPE_CREATE,
'sum' => '1st save',
'sizechange' => 10, // = strlen('teststring')
);
$pagelog = new PageChangeLog($page);
$revisions = $pagelog->getRevisions(-1, 200);
$this->assertEquals(1, count($revisions));
$revinfo = $pagelog->getRevisionInfo($revisions[0]);
$this->assertEquals('first save', $revinfo['sum']);
$this->assertEquals(DOKU_CHANGE_TYPE_CREATE, $revinfo['type']);
$this->assertEquals(10, $revinfo['sizechange']);
$this->assertFileExists(wikiFN($page, $revinfo['date']));
$this->checkChangeLogAfterNormalSave($pagelog, $expectedRevs, $expect);
$this->waitForTick(true); // wait for new revision ID
// save with same content should be ignored
saveWikiText($page, 'teststring', 'second save', false);
// 1.2 save with same content should be ignored
saveWikiText($page, 'teststring', '2nd save', false);
clearstatcache(false, $file);
$this->assertEquals($lastmod, filemtime($file));
$pagelog = new PageChangeLog($page);
$revisions = $pagelog->getRevisions(-1, 200);
$this->assertEquals(1, count($revisions));
$this->assertCount(1, $revisions);
// update the page with new text
saveWikiText($page, 'teststring2long', 'third save', false);
// 1.3 update the page with new text
saveWikiText($page, 'teststring2long', '3rd save', false);
clearstatcache(false, $file);
$newmod = filemtime($file);
$this->assertNotEquals($lastmod, $newmod);
$lastmod = $newmod;
$expectedRevs = 2;
$expectPrev = $expect;
$expect = array(
'date' => $lastmod,
'type' => DOKU_CHANGE_TYPE_EDIT,
'sum' => '3rd save',
'sizechange' => 5,
);
$pagelog = new PageChangeLog($page);
$revisions = $pagelog->getRevisions(-1, 200);
$this->assertEquals(2, count($revisions));
$revinfo = $pagelog->getRevisionInfo($revisions[0]);
$this->assertEquals('third save', $revinfo['sum']);
$this->assertEquals(DOKU_CHANGE_TYPE_EDIT, $revinfo['type']);
$this->assertEquals(5, $revinfo['sizechange']);
$this->checkChangeLogAfterNormalSave($pagelog, $expectedRevs, $expect, $expectPrev);
$this->waitForTick(); // wait for new revision ID
// add a minor edit (unauthenticated)
saveWikiText($page, 'teststring3long', 'fourth save', true);
// 1.4 add a minor edit (unauthenticated, minor not allowable)
saveWikiText($page, 'teststring3long', '4th save', true);
clearstatcache(false, $file);
$newmod = filemtime($file);
$this->assertNotEquals($lastmod, $newmod);
$lastmod = $newmod;
$expectedRevs = 3;
$expect = array(
'date' => $lastmod,
'type' => DOKU_CHANGE_TYPE_EDIT,
'sum' => '4th save',
'sizechange' => 0,
);
$pagelog = new PageChangeLog($page);
$revisions = $pagelog->getRevisions(-1, 200);
$this->assertEquals(3, count($revisions));
$revinfo = $pagelog->getRevisionInfo($revisions[0]);
$this->assertEquals('fourth save', $revinfo['sum']);
$this->assertEquals(DOKU_CHANGE_TYPE_EDIT, $revinfo['type']);
$this->assertEquals(0, $revinfo['sizechange']);
$this->checkChangeLogAfterNormalSave($pagelog, $expectedRevs, $expect);
$this->waitForTick(); // wait for new revision ID
// add a minor edit (authenticated)
// 1.5 add a minor edit (authenticated)
$_SERVER['REMOTE_USER'] = 'user';
saveWikiText($page, 'teststring4', 'fifth save', true);
saveWikiText($page, 'teststring4', '5th save', true);
clearstatcache(false, $file);
$newmod = filemtime($file);
$this->assertNotEquals($lastmod, $newmod);
$lastmod = $newmod;
$expectedRevs = 4;
$expect = array(
'date' => $lastmod,
'type' => DOKU_CHANGE_TYPE_MINOR_EDIT,
'sum' => '5th save',
'sizechange' => -4,
);
$pagelog = new PageChangeLog($page);
$revisions = $pagelog->getRevisions(-1, 200);
$this->assertEquals(4, count($revisions));
$revinfo = $pagelog->getRevisionInfo($revisions[0]);
$this->assertEquals('fifth save', $revinfo['sum']);
$this->assertEquals(DOKU_CHANGE_TYPE_MINOR_EDIT, $revinfo['type']);
$this->assertEquals(-4, $revinfo['sizechange']);
$this->checkChangeLogAfterNormalSave($pagelog, $expectedRevs, $expect);
$this->waitForTick(); // wait for new revision ID
// delete
saveWikiText($page, '', 'sixth save', false);
// 1.6 delete
saveWikiText($page, '', '6th save', false);
clearstatcache(false, $file);
$this->assertFileNotExists($file);
$expectedRevs = 5;
$expect = array(
//'date' => $lastmod, // ignore from lastRev assertion, but confirm attic file existence
'type' => DOKU_CHANGE_TYPE_DELETE,
'sum' => '6th save',
'sizechange' => -11,
);
$pagelog = new PageChangeLog($page);
$revisions = $pagelog->getRevisions(-1, 200);
$this->assertEquals(5, count($revisions));
$revinfo = $pagelog->getRevisionInfo($revisions[0]);
$this->assertEquals('sixth save', $revinfo['sum']);
$this->assertEquals(DOKU_CHANGE_TYPE_DELETE, $revinfo['type']);
$this->assertEquals(-11, $revinfo['sizechange']);
$this->assertFileExists(wikiFN($page, $revinfo['date']));
$this->checkChangeLogAfterNormalSave($pagelog, $expectedRevs, $expect);
$this->waitForTick(); // wait for new revision ID
// restore
// 1.7 restore
$REV = $lastmod;
saveWikiText($page, 'teststring4', 'seventh save', true);
saveWikiText($page, 'teststring4', '7th save', true);
clearstatcache(false, $file);
$this->assertFileExists($file);
$newmod = filemtime($file);
$this->assertNotEquals($lastmod, $newmod);
$lastmod = $newmod;
$expectedRevs = 6;
$expect = array(
'date' => $lastmod,
'type' => DOKU_CHANGE_TYPE_REVERT,
'sum' => '7th save',
'sizechange' => 11,
);
$pagelog = new PageChangeLog($page);
$revisions = $pagelog->getRevisions(-1, 200);
$this->assertEquals(6, count($revisions));
$revinfo = $pagelog->getRevisionInfo($revisions[0]);
$this->assertEquals('seventh save', $revinfo['sum']);
$this->assertEquals(DOKU_CHANGE_TYPE_REVERT, $revinfo['type']);
$this->assertEquals($REV, $revinfo['extra']);
$this->assertEquals(11, $revinfo['sizechange']);
$this->assertFileExists(wikiFN($page, $revinfo['date']));
$this->checkChangeLogAfterNormalSave($pagelog, $expectedRevs, $expect);
$REV = '';
$this->waitForTick(); // wait for new revision ID
// create external edit
file_put_contents($file, 'teststring5');
$this->waitForTick(); // wait for new revision ID
// save on top of external edit
saveWikiText($page, 'teststring6', 'eigth save', false);
// 1.8 external edit
file_put_contents($file, 'teststring5 external edit');
clearstatcache(false, $file);
$newmod = filemtime($file);
$this->assertNotEquals($lastmod, $newmod);
$lastmod = $newmod;
$expectedRevs = 6; // external edit is not yet in changelog
$expectExternal = array(
'date' => $lastmod,
'type' => DOKU_CHANGE_TYPE_EDIT,
'sum' => 'external edit',
'sizechange' => 14,
);
$pagelog = new PageChangeLog($page);
$revisions = $pagelog->getRevisions(-1, 200);
$this->assertEquals(8, count($revisions)); // two more revisions now!
$revinfo = $pagelog->getRevisionInfo($revisions[0]);
$this->assertEquals('eigth save', $revinfo['sum']);
$this->assertEquals(DOKU_CHANGE_TYPE_EDIT, $revinfo['type']);
$this->assertEquals(0, $revinfo['sizechange']);
$this->checkChangeLogAfterExternalEdit($pagelog, $expectedRevs, $expect, $expectExternal);
$revinfo = $pagelog->getRevisionInfo($revisions[1]);
$this->assertEquals('external edit', $revinfo['sum']);
$this->assertEquals(DOKU_CHANGE_TYPE_EDIT, $revinfo['type']);
$this->assertEquals(0, $revinfo['sizechange']);
$this->waitForTick(); // wait for new revision ID
// 1.9 save on top of external edit
saveWikiText($page, 'teststring6', '8th save', false);
clearstatcache(false, $file);
$newmod = filemtime($file);
$this->assertNotEquals($lastmod, $newmod);
$lastmod = $newmod;
$expectedRevs = 8;
$expect = array(
'date' => $lastmod,
'type' => DOKU_CHANGE_TYPE_EDIT,
'sum' => '8th save',
'sizechange' => -14,
);
$pagelog = new PageChangeLog($page);
$this->checkChangeLogAfterNormalSave($pagelog, $expectedRevs, $expect, $expectExternal);
}
/**
* Execute a whole bunch of saves on the same page and check the results
* using $this->handle_write() in event IO_WIKIPAGE_WRITE
* TEST 2 - create a page externally in 2.3, while external edit in Test 1.8
* 2.1 create a page
* 2.2 delete
* 2.3 externally create the page
* 2.4 edit and save on top of external edit
* 2.5 external edit
* 2.6 edit and save on top of external edit, again
*/
function test_savesequencedeleteexternalrevision() {
function test_savesequence2() {
// add an additional delay when saving files to make sure
// nobody relies on the saving happening in the same second
/** @var $EVENT_HANDLER \dokuwiki\Extension\EventHandler */
@ -174,251 +283,405 @@ class common_saveWikiText_test extends DokuWikiTest {
$page = 'page2';
$file = wikiFN($page);
// create the page
$this->assertFileNotExists($file);
saveWikiText($page, 'teststring', 'first save', false);
// 2.1 create a page
saveWikiText($page, 'teststring', 'Test 2, 1st save', false);
clearstatcache(false, $file);
$this->assertFileExists($file);
$lastmod = filemtime($file);
$expectedRevs = 1;
$expect = array(
'date' => $lastmod,
'type' => DOKU_CHANGE_TYPE_CREATE,
'sum' => 'Test 2, 1st save',
'sizechange' => 10, // = strlen('teststring')
);
$pagelog = new PageChangeLog($page);
$revisions = $pagelog->getRevisions(-1, 200);
$this->assertEquals(1, count($revisions));
$revinfo = $pagelog->getRevisionInfo($revisions[0]);
$this->assertEquals('first save', $revinfo['sum']);
$this->assertEquals(DOKU_CHANGE_TYPE_CREATE, $revinfo['type']);
$this->assertEquals(10, $revinfo['sizechange']);
$this->assertFileExists(wikiFN($page, $revinfo['date']));
$this->checkChangeLogAfterNormalSave($pagelog, $expectedRevs, $expect);
$this->waitForTick(true); // wait for new revision ID
// delete
saveWikiText($page, '', 'second save', false);
// 2.2 delete
saveWikiText($page, '', 'Test 2, 2nd save', false);
clearstatcache(false, $file);
$this->assertFileNotExists($file);
$expectedRevs = 2;
$expect = array(
//'date' => $lastmod, // ignore from lastRev assertion, but confirm attic file existence
'type' => DOKU_CHANGE_TYPE_DELETE,
'sum' => 'Test 2, 2nd save',
'sizechange' => -10,
);
$pagelog = new PageChangeLog($page);
$revisions = $pagelog->getRevisions(-1, 200);
$this->assertEquals(2, count($revisions));
$revinfo = $pagelog->getRevisionInfo($revisions[0]);
$this->assertEquals('second save', $revinfo['sum']);
$this->assertEquals(DOKU_CHANGE_TYPE_DELETE, $revinfo['type']);
$this->assertEquals(-10, $revinfo['sizechange']);
$this->assertFileExists(wikiFN($page, $revinfo['date']));
$this->checkChangeLogAfterNormalSave($pagelog, $expectedRevs, $expect);
$this->waitForTick(); // wait for new revision ID
// create external edit
// 2.3 externally create the page
file_put_contents($file, 'teststring5');
clearstatcache(false, $file);
$lastmod = filemtime($file);
$expectedRevs = 2; // external edit is not yet in changelog
$expectExternal = array(
'date' => $lastmod,
'type' => DOKU_CHANGE_TYPE_CREATE,
'sum' => 'created - external edit',
'sizechange' => 11,
);
$pagelog = new PageChangeLog($page);
$this->checkChangeLogAfterExternalEdit($pagelog, $expectedRevs, $expect, $expectExternal);
$this->waitForTick(); // wait for new revision ID
// save on top of external edit
saveWikiText($page, 'teststring6', 'third save', false);
// 2.4 save on top of external edit
saveWikiText($page, 'teststring6', 'Test 2, 3rd save', false);
clearstatcache(false, $file);
$newmod = filemtime($file);
$this->assertNotEquals($lastmod, $newmod);
$lastmod = $newmod;
$expectedRevs = 4; // two more revisions now!
$expect = array(
'date' => $lastmod,
'type' => DOKU_CHANGE_TYPE_EDIT,
'sum' => 'Test 2, 3rd save',
'sizechange' => 0,
);
$pagelog = new PageChangeLog($page);
$revisions = $pagelog->getRevisions(-1, 200);
$this->assertEquals(4, count($revisions)); // two more revisions now!
$revinfo = $pagelog->getRevisionInfo($revisions[0]);
$this->assertEquals('third save', $revinfo['sum']);
$this->assertEquals(DOKU_CHANGE_TYPE_EDIT, $revinfo['type']);
$this->assertEquals(0, $revinfo['sizechange']);
$this->assertFileExists(wikiFN($page, $revinfo['date']));
$this->checkChangeLogAfterNormalSave($pagelog, $expectedRevs, $expect, $expectExternal);
$revinfo = $pagelog->getRevisionInfo($revisions[1]);
$this->assertEquals('external edit', $revinfo['sum']);
$this->assertEquals(DOKU_CHANGE_TYPE_EDIT, $revinfo['type']);
$this->assertEquals(11, $revinfo['sizechange']);
$this->assertFileExists(wikiFN($page, $revinfo['date']));
$this->waitForTick(); // wait for new revision ID
// 2.5 external edit
file_put_contents($file, 'teststring7 external edit2');
clearstatcache(false, $file);
$newmod = filemtime($file);
$this->assertNotEquals($lastmod, $newmod);
$lastmod = $newmod;
$expectedRevs = 4; // external edit is not yet in changelog
$expectExternal = array(
'date' => $lastmod,
'type' => DOKU_CHANGE_TYPE_EDIT,
'sum' => 'external edit',
'sizechange' => 15,
);
$pagelog = new PageChangeLog($page);
$this->checkChangeLogAfterExternalEdit($pagelog, $expectedRevs, $expect, $expectExternal);
$this->waitForTick(); // wait for new revision ID
// 2.6 save on top of external edit, again
saveWikiText($page, 'teststring8', 'Test 2, 4th save', false);
clearstatcache(false, $file);
$newmod = filemtime($file);
$this->assertNotEquals($lastmod, $newmod);
$lastmod = $newmod;
$expectedRevs = 6; // two more revisions now!
$expect = array(
'date' => $lastmod,
'type' => DOKU_CHANGE_TYPE_EDIT,
'sum' => 'Test 2, 4th save',
'sizechange' => -15,
);
$pagelog = new PageChangeLog($page);
$this->checkChangeLogAfterNormalSave($pagelog, $expectedRevs, $expect, $expectExternal);
}
/**
* Execute a whole bunch of saves on the same page and check the results
* TEST 3 - typical page life of bundled page such as wiki:syntax
* 3.1 externally create a page
* 3.2 external edit
* 3.3 edit and save on top of external edit
* 3.4 externally delete the page
*/
function test_saveexternalasfirst() {
function test_savesequence3() {
$page = 'page3';
$file = wikiFN($page);
// create the page
// 3.1 externally create a page
$this->assertFileNotExists($file);
// create external edit
file_put_contents($file, 'teststring');
clearstatcache(false, $file);
$lastmod = filemtime($file);
$expectedRevs = 0; // external edit is not yet in changelog
$expect = false;
$expectExternal = array(
'date' => $lastmod,
'type' => DOKU_CHANGE_TYPE_CREATE,
'sum' => 'created - external edit',
'sizechange' => 10,
);
$pagelog = new PageChangeLog($page);
$this->checkChangeLogAfterExternalEdit($pagelog, $expectedRevs, $expect, $expectExternal);
$this->waitForTick(true); // wait for new revision ID
// save on top of external edit
saveWikiText($page, 'teststring6', 'first save', false);
// 3.2 external edit (repeated, still no changelog exists)
file_put_contents($file, 'teststring external edit');
clearstatcache(false, $file);
$newmod = filemtime($file);
$this->assertNotEquals($lastmod, $newmod);
$lastmod = $newmod;
$expectedRevs = 0; // external edit is not yet in changelog
$expectExternal = array(
'date' => $lastmod,
'type' => DOKU_CHANGE_TYPE_CREATE, // not DOKU_CHANGE_TYPE_EDIT
'sum' => 'created - external edit',
'sizechange' => 24,
);
$pagelog = new PageChangeLog($page);
$revisions = $pagelog->getRevisions(-1, 200);
$this->assertEquals(2, count($revisions)); // two more revisions now!
$revinfo = $pagelog->getRevisionInfo($revisions[0]);
$this->assertEquals('first save', $revinfo['sum']);
$this->assertEquals(DOKU_CHANGE_TYPE_EDIT, $revinfo['type']);
$this->assertEquals(1, $revinfo['sizechange']);
$this->checkChangeLogAfterExternalEdit($pagelog, $expectedRevs, $expect, $expectExternal);
$revinfo = $pagelog->getRevisionInfo($revisions[1]);
$this->assertEquals('external edit', $revinfo['sum']);
$this->assertEquals(DOKU_CHANGE_TYPE_EDIT, $revinfo['type']);
$this->assertEquals(10, $revinfo['sizechange']);
$this->waitForTick(true); // wait for new revision ID
// 3.3 save on top of external edit
saveWikiText($page, 'teststring1', 'Test 3, first save', false);
clearstatcache(false, $file);
$newmod = filemtime($file);
$this->assertNotEquals($lastmod, $newmod);
$lastmod = $newmod;
$expectedRevs = 2; // two more revisions now!
$expect = array(
'date' => $lastmod,
'type' => DOKU_CHANGE_TYPE_EDIT,
'sum' => 'Test 3, first save',
'sizechange' => -13,
);
$pagelog = new PageChangeLog($page);
$this->checkChangeLogAfterNormalSave($pagelog, $expectedRevs, $expect, $expectExternal);
$this->waitForTick(true); // wait for new revision ID
// 3.4 externally delete the page
unlink($file);
$expectedRevs = 2;
$expectExternal = array(
//'date' => $lastmod,
'type' => DOKU_CHANGE_TYPE_DELETE,
'sum' => 'removed - external edit (Unknown date)',
'sizechange' => -11,
);
$pagelog = new PageChangeLog($page);
$this->checkChangeLogAfterExternalEdit($pagelog, $expectedRevs, $expect, $expectExternal);
}
/**
* Execute a whole bunch of saves on the same page and check the results
* TEST 4 - typical page life of bundled page such as wiki:syntax
* 4.1 externally create a page
* 4.2 edit and save
* 4.3 externally edit as a result of a file which has older timestamp than last revision
*/
function test_savesequenceexternaldeleteedit() {
function test_savesequence4() {
$page = 'page4';
$file = wikiFN($page);
// create the page
// 4.1 externally create a page
$this->assertFileNotExists($file);
saveWikiText($page, 'teststring', 'first save', false);
$this->assertFileExists($file);
file_put_contents($file, 'teststring');
clearstatcache(false, $file);
$lastmod = filemtime($file);
$expectedRevs = 0; // external edit is not yet in changelog
$expect = false;
$expectExternal = array(
'date' => $lastmod,
'type' => DOKU_CHANGE_TYPE_CREATE,
'sum' => 'created - external edit',
'sizechange' => 10,
);
$pagelog = new PageChangeLog($page);
$revisions = $pagelog->getRevisions(-1, 200);
$this->assertEquals(1, count($revisions));
$revinfo = $pagelog->getRevisionInfo($revisions[0]);
$this->assertEquals('first save', $revinfo['sum']);
$this->assertEquals(DOKU_CHANGE_TYPE_CREATE, $revinfo['type']);
$this->assertEquals(10, $revinfo['sizechange']);
$this->checkChangeLogAfterExternalEdit($pagelog, $expectedRevs, $expect, $expectExternal);
$this->waitForTick(true); // wait for new revision ID
// create external delete
unlink($file);
clearstatcache(false, $file);
$this->waitForTick(); // wait for new revision ID
// save on top of external delete. save is seen as creation
saveWikiText($page, 'teststring6', 'second save', false);
// 4.2 edit and save
saveWikiText($page, 'teststring1', 'Test 4, first save', false);
clearstatcache(false, $file);
$newmod = filemtime($file);
$this->assertNotEquals($lastmod, $newmod);
$lastmod = $newmod;
$expectedRevs = 2; // two more revisions now!
$expect = array(
'date' => $lastmod,
'type' => DOKU_CHANGE_TYPE_EDIT,
'sum' => 'Test 4, first save',
'sizechange' => 1,
);
$pagelog = new PageChangeLog($page);
$revisions = $pagelog->getRevisions(-1, 200);
$this->assertEquals(2, count($revisions)); // one more revisions now!
$revinfo = $pagelog->getRevisionInfo($revisions[0]);
$this->assertEquals('second save', $revinfo['sum']);
$this->assertEquals(DOKU_CHANGE_TYPE_CREATE, $revinfo['type']);
$this->assertEquals(11, $revinfo['sizechange']);
$this->checkChangeLogAfterNormalSave($pagelog, $expectedRevs, $expect, $expectExternal);
$revinfo = $pagelog->getRevisionInfo($revisions[1]);
$this->assertEquals('first save', $revinfo['sum']);
$this->waitForTick(true); // wait for new revision ID
// 4.3 externally edit as a result of a file which has older timestamp than last revision
unlink($file);
file_put_contents($file, 'teststring fake 1 hout past');
touch($file, filemtime($file) -3600); // change file modification time to 1 hour past
clearstatcache();
$newmod = filemtime($file);
$this->assertLessThan($lastmod, $newmod); // file must be older than previous for this test
$expectedRevs = 2; // external edit is not yet in changelog
$expectExternal = array(
'date' => $lastmod + 1,
'type' => DOKU_CHANGE_TYPE_EDIT,
'sum' => 'external edit (Unknown date)',
'sizechange' => 16,
);
$pagelog = new PageChangeLog($page);
$this->checkChangeLogAfterExternalEdit($pagelog, $expectedRevs, $expect, $expectExternal);
}
/**
* Execute a whole bunch of saves on the same page and check the results
* TEST 5 - page creation and deletion
* 5.1 create a page
* 5.2 external edit
* 5.3 edit and save on top of external edit
* 5.4 delete
* 5.5 create a page, second time
* 5.6 externally delete
* 5.7 create a page, third time
*/
function test_savesequencerevert() {
global $REV;
function test_savesequence5() {
$page = 'page5';
$file = wikiFN($page);
// create the page
$this->assertFileNotExists($file);
saveWikiText($page, 'teststring', 'first save', false);
// 5.1 create a page
saveWikiText($page, 'teststring', 'Test 5, 1st save', false);
$this->assertFileExists($file);
$lastmod = filemtime($file);
$expectedRevs = 1;
$expect = array(
'date' => $lastmod,
'type' => DOKU_CHANGE_TYPE_CREATE,
'sum' => 'Test 5, 1st save',
'sizechange' => 10, // = strlen('teststring')
);
$pagelog = new PageChangeLog($page);
$revisions = $pagelog->getRevisions(-1, 200);
$this->assertEquals(1, count($revisions));
$revinfo = $pagelog->getRevisionInfo($revisions[0]);
$this->assertEquals('first save', $revinfo['sum']);
$this->assertEquals(DOKU_CHANGE_TYPE_CREATE, $revinfo['type']);
$this->assertEquals(10, $revinfo['sizechange']);
$this->checkChangeLogAfterNormalSave($pagelog, $expectedRevs, $expect);
$this->waitForTick(true); // wait for new revision ID
// save with same content should be ignored
saveWikiText($page, 'teststring', 'second save', false);
clearstatcache(false, $file);
$this->assertEquals($lastmod, filemtime($file));
$pagelog = new PageChangeLog($page);
$revisions = $pagelog->getRevisions(-1, 200);
$this->assertEquals(1, count($revisions));
// update the page with new text
saveWikiText($page, 'teststring2long', 'third save', false);
// 5.2 external edit
file_put_contents($file, 'teststring external edit');
clearstatcache(false, $file);
$newmod = filemtime($file);
$this->assertNotEquals($lastmod, $newmod);
$lastmod = $newmod;
$revertrev = $newmod;
$expectedRevs = 1; // external edit is not yet in changelog
$expectExternal = array(
'date' => $lastmod,
'type' => DOKU_CHANGE_TYPE_EDIT,
'sum' => 'external edit',
'sizechange' => 14,
);
$pagelog = new PageChangeLog($page);
$revisions = $pagelog->getRevisions(-1, 200);
$this->assertEquals(2, count($revisions));
$revinfo = $pagelog->getRevisionInfo($revisions[0]);
$this->assertEquals('third save', $revinfo['sum']);
$this->assertEquals(DOKU_CHANGE_TYPE_EDIT, $revinfo['type']);
$this->assertEquals(5, $revinfo['sizechange']);
$this->checkChangeLogAfterExternalEdit($pagelog, $expectedRevs, $expect, $expectExternal);
$this->waitForTick(); // wait for new revision ID
// add a minor edit (unauthenticated)
saveWikiText($page, 'teststring3long', 'fourth save', true);
// 5.3 edit and save on top of external edit
saveWikiText($page, 'teststring normal edit', 'Test 5, 2nd save', false);
clearstatcache(false, $file);
$newmod = filemtime($file);
$this->assertNotEquals($lastmod, $newmod);
$lastmod = $newmod;
$expectedRevs = 3; // two more revisions now!
$expect = array(
'date' => $lastmod,
'type' => DOKU_CHANGE_TYPE_EDIT,
'sum' => 'Test 5, 2nd save',
'sizechange' => -2,
);
$pagelog = new PageChangeLog($page);
$revisions = $pagelog->getRevisions(-1, 200);
$this->assertEquals(3, count($revisions));
$revinfo = $pagelog->getRevisionInfo($revisions[0]);
$this->assertEquals('fourth save', $revinfo['sum']);
$this->assertEquals(DOKU_CHANGE_TYPE_EDIT, $revinfo['type']);
$this->assertEquals(0, $revinfo['sizechange']);
$this->checkChangeLogAfterNormalSave($pagelog, $expectedRevs, $expect, $expectExternal);
$this->waitForTick(); // wait for new revision ID
// add a minor edit (authenticated)
$_SERVER['REMOTE_USER'] = 'user';
saveWikiText($page, 'teststring4', 'fifth save', true);
// 5.4 delete
saveWikiText($page, '', 'Test 5 3rd save', false);
clearstatcache(false, $file);
$newmod = filemtime($file);
$this->assertNotEquals($lastmod, $newmod);
$lastmod = $newmod;
$this->assertFileNotExists($file);
$expectedRevs = 4;
$expect = array(
//'date' => $lastmod, // ignore from lastRev assertion, but confirm attic file existence
'type' => DOKU_CHANGE_TYPE_DELETE,
'sum' => 'Test 5 3rd save',
'sizechange' => -22,
);
$pagelog = new PageChangeLog($page);
$revisions = $pagelog->getRevisions(-1, 200);
$this->assertEquals(4, count($revisions));
$revinfo = $pagelog->getRevisionInfo($revisions[0]);
$this->assertEquals('fifth save', $revinfo['sum']);
$this->assertEquals(DOKU_CHANGE_TYPE_MINOR_EDIT, $revinfo['type']);
$this->assertEquals(-4, $revinfo['sizechange']);
$this->checkChangeLogAfterNormalSave($pagelog, $expectedRevs, $expect);
$this->waitForTick(); // wait for new revision ID
// restore
$REV = $revertrev;
saveWikiText($page, 'teststring2long', 'sixth save', true);
// 5.5 create a page, second time
$this->assertFileNotExists($file);
saveWikiText($page, 'teststring revived', 'Test 5, 4th save', false);
$this->assertFileExists($file);
$lastmod = filemtime($file);
$expectedRevs = 5;
$expect = array(
'date' => $lastmod,
'type' => DOKU_CHANGE_TYPE_CREATE,
'sum' => 'Test 5, 4th save',
'sizechange' => 18, // = strlen('teststring revived')
);
$pagelog = new PageChangeLog($page);
$this->checkChangeLogAfterNormalSave($pagelog, $expectedRevs, $expect);
$this->waitForTick(true); // wait for new revision ID
// 5.6 externally delete
unlink($file);
$this->assertFileNotExists($file);
$expectedRevs = 5;
$expectExternal = array(
//'date' => $lastmod,
'type' => DOKU_CHANGE_TYPE_DELETE,
'sum' => 'removed - external edit (Unknown date)',
'sizechange' => -18,
);
$pagelog = new PageChangeLog($page);
$this->checkChangeLogAfterExternalEdit($pagelog, $expectedRevs, $expect, $expectExternal);
$this->waitForTick(true); // wait for new revision ID
// 5.7 create a page, third time
$this->assertFileNotExists($file);
saveWikiText($page, 'teststring revived 2', 'Test 5, 5th save', false);
clearstatcache(false, $file);
$this->assertFileExists($file);
$newmod = filemtime($file);
$this->assertNotEquals($lastmod, $newmod);
$lastmod = filemtime($file);
$expectedRevs = 7;
$expect = array(
'date' => $lastmod,
'type' => DOKU_CHANGE_TYPE_CREATE,
'sum' => 'Test 5, 5th save',
'sizechange' => 20, // = strlen('teststring revived 2')
);
$pagelog = new PageChangeLog($page);
$revisions = $pagelog->getRevisions(-1, 200);
$this->assertEquals(5, count($revisions));
$revinfo = $pagelog->getRevisionInfo($revisions[0]);
$this->assertEquals('sixth save', $revinfo['sum']);
$this->assertEquals(DOKU_CHANGE_TYPE_REVERT, $revinfo['type']);
$this->assertEquals($REV, $revinfo['extra']);
$this->assertEquals(4, $revinfo['sizechange']);
$REV = '';
$this->checkChangeLogAfterNormalSave($pagelog, $expectedRevs, $expect, $expectExternal);
}
}

View File

@ -11,7 +11,7 @@ use dokuwiki\Ui;
*
* @package dokuwiki\Action
*/
class Denied extends AbstractAclAction
class Denied extends AbstractAction
{
/** @inheritdoc */
public function minimumPermission()

View File

@ -34,7 +34,8 @@ class Diff extends AbstractAction
/** @inheritdoc */
public function tplContent()
{
(new Ui\Diff())->show();
global $INFO;
(new Ui\PageDiff($INFO['id']))->preference('showIntro', true)->show();
}
}

View File

@ -28,7 +28,7 @@ class Draftdel extends AbstractAction {
public function preProcess() {
global $INFO, $ID;
$draft = new \dokuwiki\Draft($ID, $INFO['client']);
if ($draft->isDraftAvailable()) {
if ($draft->isDraftAvailable() && checkSecurityToken()) {
$draft->deleteDraft();
}

View File

@ -33,6 +33,8 @@ class Logout extends AbstractUserAction {
global $ID;
global $INPUT;
if (!checkSecurityToken()) throw new ActionException();
// when logging out during an edit session, unlock the page
$lockedby = checklock($ID);
if($lockedby == $INPUT->server->str('REMOTE_USER')) {

View File

@ -22,7 +22,7 @@ class Revisions extends AbstractAction
/** @inheritdoc */
public function tplContent()
{
global $INPUT;
(new Ui\Revisions($INPUT->int('first')))->show();
global $INFO, $INPUT;
(new Ui\PageRevisions($INFO['id']))->show($INPUT->int('first'));
}
}

View File

@ -156,6 +156,7 @@ class ActionRouter {
if(defined('DOKU_UNITTEST')) {
throw $e;
}
ErrorHandler::logException($e);
$msg = 'Something unforeseen has happened: ' . $e->getMessage();
nice_die(hsc($msg));
}

View File

@ -168,8 +168,10 @@ class Ajax {
$client = $_SERVER['REMOTE_USER'];
if(!$client) $client = clientIP(true);
$cname = getCacheName($client . $id, '.draft');
@unlink($cname);
$draft = new Draft($id, $client);
if ($draft->isDraftAvailable() && checkSecurityToken()) {
$draft->deleteDraft();
}
}
/**
@ -241,14 +243,11 @@ class Ajax {
* @author Kate Arzamastseva <pshns@ukr.net>
*/
protected function callMediadiff() {
global $NS;
global $INPUT;
$image = '';
if($INPUT->has('image')) $image = cleanID($INPUT->str('image'));
$NS = getNS($image);
$auth = auth_quickaclcheck("$NS:*");
media_diff($image, $NS, $auth, true);
(new Ui\MediaDiff($image))->preference('fromAjax', true)->show();
}
/**

View File

@ -2,16 +2,19 @@
namespace dokuwiki\ChangeLog;
use dokuwiki\Logger;
/**
* methods for handling of changelog of pages or media files
* ChangeLog Prototype; methods for handling changelog
*/
abstract class ChangeLog
{
use ChangeLogTrait;
/** @var string */
protected $id;
/** @var int */
protected $chunk_size;
protected $currentRevision;
/** @var array */
protected $cache;
@ -32,29 +35,10 @@ abstract class ChangeLog
$this->id = $id;
$this->setChunkSize($chunk_size);
// set property currentRevision and cache prior to getRevisionInfo($currentRev) call
$this->getCurrentRevisionInfo();
}
/**
* 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
*
@ -63,7 +47,74 @@ abstract class ChangeLog
abstract protected function getFilename();
/**
* Get the changelog information for a specific page id and revision (timestamp)
* 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 == $this->currentRevision();
}
/**
* Checks if the revision is last revision
*
* @param int $rev revision timestamp
* @return bool true if $rev is last revision, otherwise false
*/
public function isLastRevision($rev = null)
{
return $rev === $this->lastRevision();
}
/**
* Return the current revision identifer
*
* The "current" revision means current version of the page or media file. It is either
* identical with or newer than the "last" revision, that depends on whether the file
* has modified, created or deleted outside of DokuWiki.
* The value of identifier can be determined by timestamp as far as the file exists,
* otherwise it must be assigned larger than any other revisions to keep them sortable.
*
* @return int|false revision timestamp
*/
public function currentRevision()
{
if (!isset($this->currentRevision)) {
// set ChangeLog::currentRevision property
$this->getCurrentRevisionInfo();
}
return $this->currentRevision;
}
/**
* Return the last revision identifer, date value of the last entry of the changelog
*
* @return int|false revision timestamp
*/
public function lastRevision()
{
$revs = $this->getRevisions(-1, 1);
return empty($revs) ? false : $revs[0];
}
/**
* Save revision info to the cache pool
*
* @param array $info Revision info structure
* @return bool
*/
protected function cacheRevisionInfo($info)
{
if (!is_array($info)) return false;
//$this->cache[$this->id][$info['date']] ??= $info; // since php 7.4
$this->cache[$this->id][$info['date']] = $this->cache[$this->id][$info['date']] ?? $info;
return true;
}
/**
* Get the changelog information for a specific revision (timestamp)
*
* Adjacent changelog lines are optimistically parsed and cached to speed up
* consecutive calls to getRevisionInfo. For large changelog files, only the chunk
@ -78,13 +129,15 @@ abstract class ChangeLog
* - user: user name
* - sum: edit summary (or action reason)
* - extra: extra data (varies by line type)
* - sizechange: change of filesize
*
* @author Ben Coburn <btcoburn@silicodon.net>
* @author Kate Arzamastseva <pshns@ukr.net>
*/
public function getRevisionInfo($rev)
{
$rev = max($rev, 0);
$rev = max(0, $rev);
if (!$rev) return false;
// check if it's already in the memory cache
if (isset($this->cache[$this->id]) && isset($this->cache[$this->id][$rev])) {
@ -100,10 +153,8 @@ abstract class ChangeLog
// parse and cache changelog lines
foreach ($lines as $value) {
$tmp = parseChangelogLine($value);
if ($tmp !== false) {
$this->cache[$this->id][$tmp['date']] = $tmp;
}
$info = $this->parseLogLine($value);
$this->cacheRevisionInfo($info);
}
if (!isset($this->cache[$this->id][$rev])) {
return false;
@ -140,6 +191,9 @@ abstract class ChangeLog
$lines = array();
$count = 0;
$logfile = $this->getChangelogFilename();
if (!file_exists($logfile)) return $revs;
$num = max($num, 0);
if ($num == 0) {
return $revs;
@ -148,26 +202,22 @@ abstract class ChangeLog
if ($first < 0) {
$first = 0;
} else {
if (file_exists($this->getFilename())) {
// skip current revision if the page exists
$fileLastMod = $this->getFilename();
if (file_exists($fileLastMod) && $this->isLastRevision(filemtime($fileLastMod))) {
// skip last 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) {
if (filesize($logfile) < $this->chunk_size || $this->chunk_size == 0) {
// read whole file
$lines = file($file);
$lines = file($logfile);
if ($lines === false) {
return $revs;
}
} else {
// read chunks backwards
$fp = fopen($file, 'rb'); // "file pointer"
$fp = fopen($logfile, 'rb'); // "file pointer"
if ($fp === false) {
return $revs;
}
@ -221,20 +271,17 @@ abstract class ChangeLog
$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));
}
} elseif ($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'];
$info = $this->parseLogLine($lines[$i]);
if ($this->cacheRevisionInfo($info)) {
$revs[] = $info['date'];
}
}
@ -250,8 +297,10 @@ abstract class ChangeLog
* 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
* @param int $rev revision timestamp used as startdate
* (doesn't need to be exact revision number)
* @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
@ -270,13 +319,13 @@ abstract class 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
// look for revisions later/earlier than $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();
$info = array();
//parse in normal or reverse order
$count = count($lines);
if ($direction > 0) {
@ -287,14 +336,13 @@ abstract class ChangeLog
$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;
$info = $this->parseLogLine($lines[$i]);
if ($this->cacheRevisionInfo($info)) {
//look for revs older/earlier then reference $rev and select $direction-th one
if (($direction > 0 && $tmp['date'] > $rev) || ($direction < 0 && $tmp['date'] < $rev)) {
if (($direction > 0 && $info['date'] > $rev) || ($direction < 0 && $info['date'] < $rev)) {
$revcounter++;
if ($revcounter == abs($direction)) {
$relativerev = $tmp['date'];
$relativerev = $info['date'];
}
}
}
@ -302,7 +350,7 @@ abstract class ChangeLog
//true when $rev is found, but not the wanted follow-up.
$checkotherchunck = $fp
&& ($tmp['date'] == $rev || ($revcounter > 0 && !$relativerev))
&& ($info['date'] == $rev || ($revcounter > 0 && !$relativerev))
&& !(($tail == $eof && $direction > 0) || ($head == 0 && $direction < 0));
if ($checkotherchunck) {
@ -329,7 +377,7 @@ abstract class ChangeLog
*/
public function getRevisionsAround($rev1, $rev2, $max = 50)
{
$max = floor(abs($max) / 2) * 2 + 1;
$max = intval(abs($max) / 2) * 2 + 1;
$rev1 = max($rev1, 0);
$rev2 = max($rev2, 0);
@ -341,8 +389,7 @@ abstract class ChangeLog
}
} else {
//empty right side means a removed page. Look up last revision.
$revs = $this->getRevisions(-1, 1);
$rev2 = $revs[0];
$rev2 = $this->currentRevision();
}
//collect revisions around rev2
list($revs2, $allrevs, $fp, $lines, $head, $tail) = $this->retrieveRevisionsAround($rev2, $max);
@ -357,171 +404,31 @@ abstract class ChangeLog
if (empty($revs1)) $revs1 = array();
} else {
//revisions overlaps, reuse revisions around rev2
$lastrev = array_pop($allrevs); //keep last entry that could be external edit
$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'];
$info = $this->parseLogLine($lines[$i]);
if ($this->cacheRevisionInfo($info)) {
$revs1[] = $info['date'];
$index++;
if ($index > floor($max / 2)) break 2;
if ($index > intval($max / 2)) break 2;
}
}
list($lines, $head, $tail) = $this->readAdjacentChunk($fp, $head, $tail, -1);
}
sort($revs1);
$revs1[] = $lastrev; //push back last entry
//return wanted selection
$revs1 = array_slice($revs1, max($index - floor($max / 2), 0), $max);
$revs1 = array_slice($revs1, max($index - intval($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
@ -531,8 +438,9 @@ abstract class ChangeLog
*/
public function getLastRevisionAt($date_at)
{
$fileLastMod = $this->getFilename();
//requested date_at(timestamp) younger or equal then modified_time($this->id) => load current
if (file_exists($this->getFilename()) && $date_at >= @filemtime($this->getFilename())) {
if (file_exists($fileLastMod) && $date_at >= @filemtime($fileLastMod)) {
return '';
} else {
if ($rev = $this->getRelativeRevision($date_at + 1, -1)) { //+1 to get also the requested date revision
@ -543,51 +451,13 @@ abstract class ChangeLog
}
}
/**
* 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
*
* Ideally, half of retrieved timestamps are older than $rev, another half are newer.
* The returned array $requestedrevs may not contain the reference timestamp $rev
* when it does not match any revision value recorded in changelog.
*
* @param int $rev revision timestamp
* @param int $max maximum number of revisions to be returned
* @return bool|array
@ -602,38 +472,49 @@ abstract class ChangeLog
*/
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;
//get lines from changelog
list($fp, $lines, $starthead, $starttail, $eof) = $this->readloglines($rev);
if (empty($lines)) return false;
//parse changelog lines in chunk, and read forward more chunks until $max/2 is reached
$head = $starthead;
$tail = $starttail;
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) {
$info = $this->parseLogLine($line);
if ($this->cacheRevisionInfo($info)) {
$revs[] = $info['date'];
if ($info['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;
if ($aftercount > intval($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
// add a possible revision of external edit, create or deletion
if ($lasttail == $eof && $aftercount <= intval($max / 2) &&
count($revs) && !$this->isCurrentRevision($revs[count($revs)-1])
) {
$revs[] = $this->currentRevision;
$aftercount++;
}
if ($aftercount == 0) {
//given timestamp $rev is newer than the most recent line in chunk
return false; //FIXME: or proceed to collect older revisions?
}
//read more chunks backward until $max/2 is reached and total number of revs is equal to $max
$lines = array();
$i = 0;
if ($aftercount > 0) {
@ -643,24 +524,138 @@ abstract class ChangeLog
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'];
$info = $this->parseLogLine($lines[$i]);
if ($this->cacheRevisionInfo($info)) {
$revs[] = $info['date'];
$beforecount++;
//enough revs before reference $rev?
if ($beforecount > max(floor($max / 2), $max - $aftercount)) break 2;
if ($beforecount > max(intval($max / 2), $max - $aftercount)) break 2;
}
}
}
}
sort($revs);
//keep only non-parsed lines
$lines = array_slice($lines, 0, $i);
sort($revs);
//trunk desired selection
$requestedrevs = array_slice($revs, -$max, $max);
return array($requestedrevs, $revs, $fp, $lines, $head, $lasttail);
}
/**
* Get the current revision information, considering external edit, create or deletion
*
* When the file has not modified since its last revision, the infomation of the last
* change that had already recorded in the changelog is returned as current change info.
* Otherwise, the change infomation since the last revision caused outside DokuWiki
* should be returned, which is referred as "external revision".
*
* The change date of the file can be determined by timestamp as far as the file exists,
* however this is not possible when the file has already deleted outside of DokuWiki.
* In such case we assign 1 sec before current time() for the external deletion.
* As a result, the value of current revision identifier may change each time because:
* 1) the file has again modified outside of DokuWiki, or
* 2) the value is essentially volatile for deleted but once existed files.
*
* @return bool|array false when page had never existed or array with entries:
* - date: revision identifier (timestamp or last revision +1)
* - ip: IPv4 address (127.0.0.1)
* - type: log line type
* - id: id of page or media
* - user: user name
* - sum: edit summary (or action reason)
* - extra: extra data (varies by line type)
* - sizechange: change of filesize
* - timestamp: unix timestamp or false (key set only for external edit occurred)
*
* @author Satoshi Sahara <sahara.satoshi@gmail.com>
*/
public function getCurrentRevisionInfo()
{
global $lang;
if (isset($this->currentRevision)) return $this->getRevisionInfo($this->currentRevision);
// get revision id from the item file timestamp and chagelog
$fileLastMod = $this->getFilename();
$fileRev = @filemtime($fileLastMod); // false when the file not exist
$lastRev = $this->lastRevision(); // false when no changelog
if (!$fileRev && !$lastRev) { // has never existed
$this->currentRevision = false;
return false;
} elseif ($fileRev === $lastRev) { // not external edit
$this->currentRevision = $lastRev;
return $this->getRevisionInfo($lastRev);
}
if (!$fileRev && $lastRev) { // item file does not exist
// check consistency against changelog
$revInfo = $this->getRevisionInfo($lastRev);
if ($revInfo['type'] == DOKU_CHANGE_TYPE_DELETE) {
$this->currentRevision = $lastRev;
return $this->getRevisionInfo($lastRev);
}
// externally deleted, set revision date as late as possible
$revInfo = [
'date' => max($lastRev +1, time() -1), // 1 sec before now or new page save
'ip' => '127.0.0.1',
'type' => DOKU_CHANGE_TYPE_DELETE,
'id' => $this->id,
'user' => '',
'sum' => $lang['deleted'].' - '.$lang['external_edit'].' ('.$lang['unknowndate'].')',
'extra' => '',
'sizechange' => -io_getSizeFile($this->getFilename($lastRev)),
'timestamp' => false,
];
} elseif ($fileRev) { // item file exist
// here, file timestamp is different with last revision in changelog
$isJustCreated = $lastRev === false || (
$fileRev > $lastRev &&
$this->getRevisionInfo($lastRev)['type'] == DOKU_CHANGE_TYPE_DELETE
);
$filesize_new = filesize($this->getFilename());
$filesize_old = $isJustCreated ? 0 : io_getSizeFile($this->getFilename($lastRev));
$sizechange = $filesize_new - $filesize_old;
if ($isJustCreated) {
$timestamp = $fileRev;
$sum = $lang['created'].' - '.$lang['external_edit'];
} elseif ($fileRev > $lastRev) {
$timestamp = $fileRev;
$sum = $lang['external_edit'];
} else {
// $fileRev is older than $lastRev, that is erroneous/incorrect occurence.
$msg = "Warning: current file modification time is older than last revision date";
$details = 'File revision: '.$fileRev.' '.strftime("%Y-%m-%d %H:%M:%S", $fileRev)."\n"
.'Last revision: '.$lastRev.' '.strftime("%Y-%m-%d %H:%M:%S", $lastRev);
Logger::error($msg, $details, $this->getFilename());
$timestamp = false;
$sum = $lang['external_edit'].' ('.$lang['unknowndate'].')';
}
// externally created or edited
$revInfo = [
'date' => $timestamp ?: $lastRev +1,
'ip' => '127.0.0.1',
'type' => $isJustCreated ? DOKU_CHANGE_TYPE_CREATE : DOKU_CHANGE_TYPE_EDIT,
'id' => $this->id,
'user' => '',
'sum' => $sum,
'extra' => '',
'sizechange' => $sizechange,
'timestamp' => $timestamp,
];
}
// cache current revision information of external edition
$this->currentRevision = $revInfo['date'];
$this->cache[$this->id][$this->currentRevision] = $revInfo;
return $this->getRevisionInfo($this->currentRevision);
}
}

View File

@ -0,0 +1,268 @@
<?php
namespace dokuwiki\ChangeLog;
/**
* Provides methods for handling of changelog
*/
trait ChangeLogTrait
{
/**
* Adds an entry to the changelog file
*
* @return array added logline as revision info
*/
abstract public function addLogEntry(array $info, $timestamp = null);
/**
* Parses a changelog line into it's components
*
* @author Ben Coburn <btcoburn@silicodon.net>
*
* @param string $line changelog line
* @return array|bool parsed line or false
*/
public static function parseLogLine($line)
{
$info = explode("\t", rtrim($line, "\n"));
if ($info !== false && count($info) > 1) {
return $entry = array(
'date' => (int)$info[0], // unix timestamp
'ip' => $info[1], // IPv4 address (127.0.0.1)
'type' => $info[2], // log line type
'id' => $info[3], // page id
'user' => $info[4], // user name
'sum' => $info[5], // edit summary (or action reason)
'extra' => $info[6], // extra data (varies by line type)
'sizechange' => (isset($info[7]) && $info[7] !== '') ? (int)$info[7] : null, //
);
} else {
return false;
}
}
/**
* Build a changelog line from it's components
*
* @param array $info Revision info structure
* @param int $timestamp logline date (optional)
* @return string changelog line
*/
public static function buildLogLine(array &$info, $timestamp = null)
{
$strip = ["\t", "\n"];
$entry = array(
'date' => $timestamp ?? $info['date'],
'ip' => $info['ip'],
'type' => str_replace($strip, '', $info['type']),
'id' => $info['id'],
'user' => $info['user'],
'sum' => \dokuwiki\Utf8\PhpString::substr(str_replace($strip, '', $info['sum']), 0, 255),
'extra' => str_replace($strip, '', $info['extra']),
'sizechange' => $info['sizechange'],
);
$info = $entry;
return $line = implode("\t", $entry) ."\n";
}
/**
* Returns path to changelog
*
* @return string path to file
*/
abstract protected function getChangelogFilename();
/**
* Checks if the ID has old revisons
* @return boolean
*/
public function hasRevisions()
{
$logfile = $this->getChangelogFilename();
return file_exists($logfile);
}
/** @var int */
protected $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 lines from changelog.
* If file larger than $chuncksize, only chunck is read that could contain $rev.
*
* When reference timestamp $rev is outside time range of changelog, readloglines() will return
* lines in first or last chunk, but they obviously does not 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 + intval(($tail - $head) / 2);
$finger = $this->getNewlinepointer($fp, $finger);
$tmp = fgets($fp);
if ($finger == $head || $finger == $tail) {
break;
}
$info = $this->parseLogLine($tmp);
$finger_rev = $info['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;
}
/**
* 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 + intval($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);
}
}

View File

@ -3,7 +3,7 @@
namespace dokuwiki\ChangeLog;
/**
* handles changelog of a media file
* Class MediaChangeLog; handles changelog of a media file
*/
class MediaChangeLog extends ChangeLog
{
@ -21,10 +21,40 @@ class MediaChangeLog extends ChangeLog
/**
* Returns path to current page/media
*
* @param string|int $rev empty string or revision timestamp
* @return string path to file
*/
protected function getFilename()
protected function getFilename($rev = '')
{
return mediaFN($this->id);
return mediaFN($this->id, $rev);
}
/**
* Adds an entry to the changelog
*
* @param array $info Revision info structure of a media file
* @param int $timestamp logline date (optional)
* @return array revision info of added logline
*
* @see also addMediaLogEntry() in inc/changelog.php file
*/
public function addLogEntry(array $info, $timestamp = null)
{
global $conf;
if (isset($timestamp)) unset($this->cache[$this->id][$info['date']]);
// add changelog lines
$logline = $this->buildLogLine($info, $timestamp);
io_saveFile(mediaMetaFN($this->id,'.changes'), $logline, $append = true);
io_saveFile($conf['media_changelog'], $logline, $append = true); //global changelog cache
// update cache
$this->currentRevision = $info['date'];
$this->cache[$this->id][$this->currentRevision] = $info;
return $info;
}
}

View File

@ -3,7 +3,7 @@
namespace dokuwiki\ChangeLog;
/**
* handles changelog of a wiki page
* Class PageChangeLog; handles changelog of a wiki page
*/
class PageChangeLog extends ChangeLog
{
@ -21,10 +21,40 @@ class PageChangeLog extends ChangeLog
/**
* Returns path to current page/media
*
* @param string|int $rev empty string or revision timestamp
* @return string path to file
*/
protected function getFilename()
protected function getFilename($rev = '')
{
return wikiFN($this->id);
return wikiFN($this->id, $rev);
}
/**
* Adds an entry to the changelog
*
* @param array $info Revision info structure of a page
* @param int $timestamp logline date (optional)
* @return array revision info of added logline
*
* @see also addLogEntry() in inc/changelog.php file
*/
public function addLogEntry(array $info, $timestamp = null)
{
global $conf;
if (isset($timestamp)) unset($this->cache[$this->id][$info['date']]);
// add changelog lines
$logline = $this->buildLogLine($info, $timestamp);
io_saveFile(metaFN($this->id,'.changes'), $logline, $append = true);
io_saveFile($conf['changelog'], $logline, $append = true); //global changelog cache
// update cache
$this->currentRevision = $info['date'];
$this->cache[$this->id][$this->currentRevision] = $info;
return $info;
}
}

View File

@ -25,7 +25,7 @@ class Draft
{
$this->id = $ID;
$this->client = $client;
$this->cname = getCacheName($client.$ID, '.draft');
$this->cname = getCacheName("$client\n$ID", '.draft');
if(file_exists($this->cname) && file_exists(wikiFN($ID))) {
if (filemtime($this->cname) < filemtime(wikiFN($ID))) {
// remove stale draft

332
inc/File/PageFile.php Normal file
View File

@ -0,0 +1,332 @@
<?php
namespace dokuwiki\File;
use dokuwiki\Cache\CacheInstructions;
use dokuwiki\ChangeLog\PageChangeLog;
use dokuwiki\Extension\Event;
use dokuwiki\Logger;
/**
* Class PageFile : handles wiki text file and its change management for specific page
*/
class PageFile
{
protected $id;
/* @var PageChangeLog $changelog */
public $changelog;
/* @var array $data initial data when event COMMON_WIKIPAGE_SAVE triggered */
protected $data;
/**
* PageFile constructor.
*
* @param string $id
*/
public function __construct($id)
{
$this->id = $id;
$this->changelog = new PageChangeLog($this->id);
}
/** @return string */
public function getId()
{
return $this->id;
}
/** @return string */
public function getPath($rev = '')
{
return wikiFN($this->id, $rev);
}
/**
* Get raw WikiText of the page, considering change type at revision date
* similar to function rawWiki($id, $rev = '')
*
* @param int|false $rev timestamp when a revision of wikitext is desired
* @return string
*/
public function rawWikiText($rev = null)
{
if ($rev !== null) {
$revInfo = $rev ? $this->changelog->getRevisionInfo($rev) : false;
return (!$revInfo || $revInfo['type'] == DOKU_CHANGE_TYPE_DELETE)
? '' // attic stores complete last page version for a deleted page
: io_readWikiPage($this->getPath($rev), $this->id, $rev); // retrieve from attic
} else {
return io_readWikiPage($this->getPath(), $this->id, '');
}
}
/**
* Saves a wikitext by calling io_writeWikiPage.
* Also directs changelog and attic updates.
*
* @author Andreas Gohr <andi@splitbrain.org>
* @author Ben Coburn <btcoburn@silicodon.net>
*
* @param string $text wikitext being saved
* @param string $summary summary of text update
* @param bool $minor mark this saved version as minor update
* @return array data of event COMMON_WIKIPAGE_SAVE
*/
public function saveWikiText($text, $summary, $minor = false)
{
/* Note to developers:
This code is subtle and delicate. Test the behavior of
the attic and changelog with dokuwiki and external edits
after any changes. External edits change the wiki page
directly without using php or dokuwiki.
*/
global $conf;
global $lang;
global $REV;
/* @var Input $INPUT */
global $INPUT;
// prevent recursive call
if (isset($this->data)) return;
$pagefile = $this->getPath();
$currentRevision = @filemtime($pagefile); // int or false
$currentContent = $this->rawWikiText();
$currentSize = file_exists($pagefile) ? filesize($pagefile) : 0;
// prepare data for event COMMON_WIKIPAGE_SAVE
$data = array(
'id' => $this->id, // should not be altered by any handlers
'file' => $pagefile, // same above
'changeType' => null, // set prior to event, and confirm later
'revertFrom' => $REV,
'oldRevision' => $currentRevision,
'oldContent' => $currentContent,
'newRevision' => 0, // only available in the after hook
'newContent' => $text,
'summary' => $summary,
'contentChanged' => (bool)($text != $currentContent), // confirm later
'changeInfo' => '', // automatically determined by revertFrom
'sizechange' => strlen($text) - strlen($currentContent), // TBD
);
// determine tentatively change type and relevant elements of event data
if ($data['revertFrom']) {
// new text may differ from exact revert revision
$data['changeType'] = DOKU_CHANGE_TYPE_REVERT;
$data['changeInfo'] = $REV;
} elseif (trim($data['newContent']) == '') {
// empty or whitespace only content deletes
$data['changeType'] = DOKU_CHANGE_TYPE_DELETE;
} elseif (!file_exists($pagefile)) {
$data['changeType'] = DOKU_CHANGE_TYPE_CREATE;
} else {
// minor edits allowable only for logged in users
$is_minor_change = ($minor && $conf['useacl'] && $INPUT->server->str('REMOTE_USER'));
$data['changeType'] = $is_minor_change
? DOKU_CHANGE_TYPE_MINOR_EDIT
: DOKU_CHANGE_TYPE_EDIT;
}
$this->data = $data;
$data['page'] = $this; // allow event handlers to use this class methods
$event = new Event('COMMON_WIKIPAGE_SAVE', $data);
if (!$event->advise_before()) return;
// if the content has not been changed, no save happens (plugins may override this)
if (!$data['contentChanged']) return;
// Check whether the pagefile has modified during $event->advise_before()
clearstatcache();
$fileRev = @filemtime($pagefile);
if ($fileRev === $currentRevision) {
// pagefile has not touched by plugin's event handler
// add a potential external edit entry to changelog and store it into attic
$this->detectExternalEdit();
$filesize_old = $currentSize;
} else {
// pagefile has modified by plugin's event handler, confirm sizechange
$filesize_old = (
$data['changeType'] == DOKU_CHANGE_TYPE_CREATE || (
$data['changeType'] == DOKU_CHANGE_TYPE_REVERT && !file_exists($pagefile))
) ? 0 : filesize($pagefile);
}
// make change to the current file
if ($data['changeType'] == DOKU_CHANGE_TYPE_DELETE) {
// nothing to do when the file has already deleted
if (!file_exists($pagefile)) return;
// autoset summary on deletion
if (blank($data['summary'])) {
$data['summary'] = $lang['deleted'];
}
// send "update" event with empty data, so plugins can react to page deletion
$ioData = array([$pagefile, '', false], getNS($this->id), noNS($this->id), false);
Event::createAndTrigger('IO_WIKIPAGE_WRITE', $ioData);
// pre-save deleted revision
@touch($pagefile);
clearstatcache();
$data['newRevision'] = $this->saveOldRevision();
// remove empty file
@unlink($pagefile);
$filesize_new = 0;
// 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($this->id);
// remove empty namespaces
io_sweepNS($this->id, 'datadir');
io_sweepNS($this->id, 'mediadir');
} else {
// save file (namespace dir is created in io_writeWikiPage)
io_writeWikiPage($pagefile, $data['newContent'], $this->id);
// pre-save the revision, to keep the attic in sync
$data['newRevision'] = $this->saveOldRevision();
$filesize_new = filesize($pagefile);
}
$data['sizechange'] = $filesize_new - $filesize_old;
$event->advise_after();
unset($data['page']);
// adds an entry to the changelog and saves the metadata for the page
$logEntry = $this->changelog->addLogEntry([
'date' => $data['newRevision'],
'ip' => clientIP(true),
'type' => $data['changeType'],
'id' => $this->id,
'user' => $INPUT->server->str('REMOTE_USER'),
'sum' => $data['summary'],
'extra' => $data['changeInfo'],
'sizechange' => $data['sizechange'],
]);
// update metadata
$this->updateMetadata($logEntry);
// update the purgefile (timestamp of the last time anything within the wiki was changed)
io_saveFile($conf['cachedir'].'/purgefile', time());
return $data;
}
/**
* Checks if the current page version is newer than the last entry in the page's changelog.
* If so, we assume it has been an external edit and we create an attic copy and add a proper
* changelog line.
*
* This check is only executed when the page is about to be saved again from the wiki,
* triggered in @see saveWikiText()
*/
public function detectExternalEdit()
{
$revInfo = $this->changelog->getCurrentRevisionInfo();
// only interested in external revision
if (empty($revInfo) || !array_key_exists('timestamp', $revInfo)) return;
if ($revInfo['type'] != DOKU_CHANGE_TYPE_DELETE && !$revInfo['timestamp']) {
// file is older than last revision, that is erroneous/incorrect occurence.
// try to change file modification time
$fileLastMod = $this->getPath();
$wrong_timestamp = filemtime($fileLastMod);
if (touch($fileLastMod, $revInfo['date'])) {
clearstatcache();
$msg = "detectExternalEdit($id): timestamp successfully modified";
$details = '('.$wrong_timestamp.' -> '.$revInfo['date'].')';
Logger::error($msg, $details, $fileLastMod);
} else {
// runtime error
$msg = "detectExternalEdit($id): page file should be newer than last revision "
.'('.filemtime($fileLastMod).' < '. $this->changelog->lastRevision() .')';
throw new \RuntimeException($msg);
}
}
// keep at least 1 sec before new page save
if ($revInfo['date'] == time()) sleep(1); // wait a tick
// store externally edited file to the attic folder
$this->saveOldRevision();
// add a changelog entry for externally edited file
$revInfo = $this->changelog->addLogEntry($revInfo);
// remove soon to be stale instructions
$cache = new CacheInstructions($this->id, $this->getPath());
$cache->removeCache();
}
/**
* Moves the current version to the attic and returns its revision date
*
* @author Andreas Gohr <andi@splitbrain.org>
*
* @return int|string revision timestamp
*/
public function saveOldRevision()
{
$oldfile = $this->getPath();
if (!file_exists($oldfile)) return '';
$date = filemtime($oldfile);
$newfile = $this->getPath($date);
io_writeWikiPage($newfile, $this->rawWikiText(), $this->id, $date);
return $date;
}
/**
* Update metadata of changed page
*
* @param array $logEntry changelog entry
*/
public function updateMetadata(array $logEntry)
{
global $INFO;
list(
'date' => $date,
'type' => $changeType,
'user' => $user,
) = $logEntry;
$wasRemoved = ($changeType === DOKU_CHANGE_TYPE_DELETE);
$wasCreated = ($changeType === DOKU_CHANGE_TYPE_CREATE);
$wasReverted = ($changeType === DOKU_CHANGE_TYPE_REVERT);
$wasMinorEdit = ($changeType === DOKU_CHANGE_TYPE_MINOR_EDIT);
$createdDate = @filectime($this->getPath());
if ($wasRemoved) return;
$oldmeta = p_read_metadata($this->id)['persistent'];
$meta = array();
if ($wasCreated &&
(empty($oldmeta['date']['created']) || $oldmeta['date']['created'] === $createdDate)
) {
// newly created
$meta['date']['created'] = $createdDate;
if ($user) {
$meta['creator'] = $INFO['userinfo']['name'] ?? null;
$meta['user'] = $user;
}
} elseif (($wasCreated || $wasReverted) && !empty($oldmeta['date']['created'])) {
// re-created / restored
$meta['date']['created'] = $oldmeta['date']['created'];
$meta['date']['modified'] = $createdDate; // use the files ctime here
$meta['creator'] = $oldmeta['creator'] ?? null;
if ($user) {
$meta['contributor'][$user] = $INFO['userinfo']['name'] ?? null;
}
} elseif (!$wasMinorEdit) { // non-minor modification
$meta['date']['modified'] = $date;
if ($user) {
$meta['contributor'][$user] = $INFO['userinfo']['name'] ?? null;
}
}
$meta['last_change'] = $logEntry;
p_set_metadata($this->id, $meta);
}
}

View File

@ -87,7 +87,8 @@ class BulkSubscriptionSender extends SubscriptionSender
$n = 0;
while (!is_null($rev) && $rev['date'] >= $lastupdate &&
($INPUT->server->str('REMOTE_USER') === $rev['user'] ||
$rev['type'] === DOKU_CHANGE_TYPE_MINOR_EDIT)) {
$rev['type'] === DOKU_CHANGE_TYPE_MINOR_EDIT)
) {
$pagelog = new PageChangeLog($rev['id']);
$rev = $pagelog->getRevisions($n++, 1);
$rev = (count($rev) > 0) ? $rev[0] : null;

View File

@ -5,6 +5,7 @@ namespace dokuwiki;
use dokuwiki\Extension\Event;
use dokuwiki\Sitemap\Mapper;
use dokuwiki\Subscriptions\BulkSubscriptionSender;
use dokuwiki\ChangeLog\ChangeLog;
/**
* Class TaskRunner
@ -120,7 +121,7 @@ class TaskRunner
$out_lines = [];
$old_lines = [];
for ($i = 0; $i < count($lines); $i++) {
$log = parseChangelogLine($lines[$i]);
$log = ChangeLog::parseLogLine($lines[$i]);
if ($log === false) {
continue; // discard junk
}

View File

@ -2,502 +2,137 @@
namespace dokuwiki\Ui;
use dokuwiki\ChangeLog\PageChangeLog;
use dokuwiki\ChangeLog\MediaChangeLog;
use dokuwiki\Extension\Event;
use dokuwiki\Form\Form;
use dokuwiki\ChangeLog\ChangeLog;
/**
* DokuWiki Diff Interface
* parent class of PageDiff and MediaDiff
*
* @package dokuwiki\Ui
*/
class Diff extends Ui
abstract class Diff extends Ui
{
protected $text;
protected $showIntro;
protected $difftype;
/* @var string */
protected $id; // page id or media id
/* @var int */
protected $oldRev; // timestamp of older revision
protected $newRev; // timestamp of newer revision
/* @var array */
protected $preference = [];
/* @var ChangeLog */
protected $changelog; // PageChangeLog or MediaChangeLog object
/**
* Diff Ui constructor
*
* @param string $text when non-empty: compare with this text with most current version
* @param bool $showIntro display the intro text
* @param string $difftype diff view type (inline or sidebyside)
* @param string $id page id or media id
*/
public function __construct($text = '', $showIntro = true, $difftype = null)
public function __construct($id)
{
$this->text = $text;
$this->showIntro = $showIntro;
// determine diff view type
if (isset($difftype)) {
$this->difftype = $difftype;
} else {
global $INPUT;
global $INFO;
$this->difftype = $INPUT->str('difftype') ?: get_doku_pref('difftype', $difftype);
if (empty($this->difftype) && $INFO['ismobile']) {
$this->difftype = 'inline';
}
}
if ($this->difftype !== 'inline') $this->difftype = 'sidebyside';
$this->id = $id;
$this->setChangeLog();
}
/**
* Show diff
* between current page version and provided $text
* or between the revisions provided via GET or POST
* set class property changelog
*/
abstract protected function setChangeLog();
/**
* Prepare revision info of comparison pair
*/
abstract protected function preProcess();
/**
* Set a pair of revisions to be compared
*
* @author Andreas Gohr <andi@splitbrain.org>
* @param int $oldRev
* @param int $newRev
* @return $this
*/
public function compare($oldRev, $newRev)
{
if ($oldRev < $newRev) {
[$this->oldRev, $this->newRev] = [$oldRev, $newRev];
} else {
[$this->oldRev, $this->newRev] = [$newRev, $oldRev];
}
return $this;
}
/**
* Gets or Sets preference of the Ui\Diff object
*
* @param string|array $prefs a key name or key-value pair(s)
* @param mixed $value value used when the first args is string
* @return array|$this
*/
public function preference($prefs = null, $value = null)
{
// set
if (is_string($prefs) && isset($value)) {
$this->preference[$prefs] = $value;
return $this;
} elseif (is_array($prefs)) {
foreach ($prefs as $name => $value) {
$this->preference[$name] = $value;
}
return $this;
}
// get
return $this->preference;
}
/**
* Handle requested revision(s)
*
* @return void
*/
public function show()
protected function handle()
{
global $ID;
global $REV;
global $lang;
global $INPUT;
global $INFO;
$pagelog = new PageChangeLog($ID);
/*
* Determine requested revision(s)
*/
// we're trying to be clever here, revisions to compare can be either
// given as rev and rev2 parameters, with rev2 being optional. Or in an
// array in rev2.
$rev1 = $REV;
$rev2 = $INPUT->ref('rev2');
if (is_array($rev2)) {
$rev1 = (int) $rev2[0];
$rev2 = (int) $rev2[1];
if (!$rev1) {
$rev1 = $rev2;
unset($rev2);
}
} else {
$rev2 = $INPUT->int('rev2');
// difflink icon click, eg. ?rev=123456789&do=diff
if ($INPUT->has('rev')) {
$this->oldRev = $INPUT->int('rev');
$this->newRev = $this->changelog->currentRevision();
}
/*
* Determine left and right revision, its texts and the header
*/
$r_minor = '';
$l_minor = '';
if ($this->text) { // compare text to the most current revision
$l_rev = '';
$l_text = rawWiki($ID, '');
$l_head = '<a class="wikilink1" href="'. wl($ID) .'">'
. $ID .' '. dformat((int) @filemtime(wikiFN($ID))) .'</a> '
. $lang['current'];
$r_rev = '';
$r_text = cleanText($this->text);
$r_head = $lang['yours'];
} else {
if ($rev1 && isset($rev2) && $rev2) { // two specific revisions wanted
// make sure order is correct (older on the left)
if ($rev1 < $rev2) {
$l_rev = $rev1;
$r_rev = $rev2;
} else {
$l_rev = $rev2;
$r_rev = $rev1;
}
} elseif ($rev1) { // single revision given, compare to current
$r_rev = '';
$l_rev = $rev1;
} else { // no revision was given, compare previous to current
$r_rev = '';
$revs = $pagelog->getRevisions(0, 1);
$l_rev = $revs[0];
$REV = $l_rev; // store revision back in $REV
}
// when both revisions are empty then the page was created just now
if (!$l_rev && !$r_rev) {
$l_text = '';
// submit button with two checked boxes
$rev2 = $INPUT->arr('rev2', []);
if (count($rev2) > 1) {
if ($rev2[0] < $rev2[1]) {
[$this->oldRev, $this->newRev] = [$rev2[0], $rev2[1]];
} else {
$l_text = rawWiki($ID, $l_rev);
[$this->oldRev, $this->newRev] = [$rev2[1], $rev2[0]];
}
$r_text = rawWiki($ID, $r_rev);
list($l_head, $r_head, $l_minor, $r_minor) = $this->diffHead(
$l_rev, $r_rev, null, false, ($this->difftype == 'inline')
);
}
/*
* Build navigation
*/
$l_nav = '';
$r_nav = '';
if (!$this->text) {
list($l_nav, $r_nav) = $this->diffNavigation($pagelog, $l_rev, $r_rev);
if (!isset($this->oldRev, $this->newRev)) {
// no revision was given, compare previous to current
$revs = $this->changelog->getRevisions(-1, 2);
$this->newRev = $this->changelog->currentRevision();
$this->oldRev = ($revs[0] == $this->newRev) ? $revs[1] : $revs[0];
}
/*
* Create diff object and the formatter
*/
$diff = new \Diff(explode("\n", $l_text), explode("\n", $r_text));
if ($this->difftype == 'inline') {
$diffformatter = new \InlineDiffFormatter();
} else {
$diffformatter = new \TableDiffFormatter();
}
/*
* Display intro
*/
if ($this->showIntro) print p_locale_xhtml('diff');
/*
* Display type and exact reference
*/
if (!$this->text) {
print '<div class="diffoptions group">';
// create the form to select difftype
$form = new Form(['action' => wl()]);
$form->setHiddenField('id', $ID);
$form->setHiddenField('rev2[0]', $l_rev);
$form->setHiddenField('rev2[1]', $r_rev);
$form->setHiddenField('do', 'diff');
$options = array(
'sidebyside' => $lang['diff_side'],
'inline' => $lang['diff_inline']
);
$input = $form->addDropdown('difftype', $options, $lang['diff_type'])
->val($this->difftype)->addClass('quickselect');
$input->useInput(false); // inhibit prefillInput() during toHTML() process
$form->addButton('do[diff]', 'Go')->attr('type','submit');
print $form->toHTML();
print '<p>';
// link to exactly this view FS#2835
print $this->diffViewlink('difflink', $l_rev, ($r_rev ?: $INFO['currentrev']));
print '</p>';
print '</div>'; // .diffoptions
}
/*
* Display diff view table
*/
print '<div class="table">';
print '<table class="diff diff_'. $this->difftype .'">';
//navigation and header
if ($this->difftype == 'inline') {
if (!$this->text) {
print '<tr>'
. '<td class="diff-lineheader">-</td>'
. '<td class="diffnav">'. $l_nav .'</td>'
. '</tr>';
print '<tr>'
. '<th class="diff-lineheader">-</th>'
. '<th '. $l_minor .'>'. $l_head .'</th>'
.'</tr>';
}
print '<tr>'
. '<td class="diff-lineheader">+</td>'
. '<td class="diffnav">'. $r_nav .'</td>'
.'</tr>';
print '<tr>'
. '<th class="diff-lineheader">+</th>'
. '<th '. $r_minor .'>'. $r_head .'</th>'
. '</tr>';
} else {
if (!$this->text) {
print '<tr>'
. '<td colspan="2" class="diffnav">'. $l_nav .'</td>'
. '<td colspan="2" class="diffnav">'. $r_nav .'</td>'
. '</tr>';
}
print '<tr>'
. '<th colspan="2" '. $l_minor .'>'. $l_head .'</th>'
. '<th colspan="2" '. $r_minor .'>'. $r_head .'</th>'
. '</tr>';
}
//diff view
print $this->insertSoftbreaks($diffformatter->format($diff));
print '</table>';
print '</div>';
}
/**
* Get header of diff HTML
* Build header of diff HTML
*
* @param string $l_rev Left revisions
* @param string $r_rev Right revision
* @param string $id Page id, if null $ID is used
* @param bool $media If it is for media files
* @param bool $inline Return the header on a single line
* @return string[] HTML snippets for diff header
* @deprecated 2020-12-31
*/
public function diffHead($l_rev, $r_rev, $id = null, $media = false, $inline = false)
public function buildDiffHead($l_rev, $r_rev)
{
global $lang;
if ($id === null) {
global $ID;
$id = $ID;
}
$head_separator = $inline ? ' ' : '<br />';
$media_or_wikiFN = $media ? 'mediaFN' : 'wikiFN';
$ml_or_wl = $media ? 'ml' : 'wl';
$l_minor = $r_minor = '';
if ($media) {
$changelog = new MediaChangeLog($id);
} else {
$changelog = new PageChangeLog($id);
}
if (!$l_rev) {
$l_head = '&mdash;';
} else {
$l_info = $changelog->getRevisionInfo($l_rev);
if ($l_info['user']) {
$l_user = '<bdi>'.editorinfo($l_info['user']).'</bdi>';
if (auth_ismanager()) $l_user .= ' <bdo dir="ltr">('.$l_info['ip'].')</bdo>';
} else {
$l_user = '<bdo dir="ltr">'.$l_info['ip'].'</bdo>';
}
$l_user = '<span class="user">'.$l_user.'</span>';
$l_sum = ($l_info['sum']) ? '<span class="sum"><bdi>'.hsc($l_info['sum']).'</bdi></span>' : '';
if ($l_info['type'] === DOKU_CHANGE_TYPE_MINOR_EDIT) $l_minor = 'class="minor"';
$l_head_title = ($media) ? dformat($l_rev) : $id.' ['.dformat($l_rev).']';
$l_head = '<bdi><a class="wikilink1" href="'.$ml_or_wl($id,"rev=$l_rev").'">'
. $l_head_title.'</a></bdi>'.$head_separator.$l_user.' '.$l_sum;
}
if ($r_rev) {
$r_info = $changelog->getRevisionInfo($r_rev);
if ($r_info['user']) {
$r_user = '<bdi>'.editorinfo($r_info['user']).'</bdi>';
if (auth_ismanager()) $r_user .= ' <bdo dir="ltr">('.$r_info['ip'].')</bdo>';
} else {
$r_user = '<bdo dir="ltr">'.$r_info['ip'].'</bdo>';
}
$r_user = '<span class="user">'.$r_user.'</span>';
$r_sum = ($r_info['sum']) ? '<span class="sum"><bdi>'.hsc($r_info['sum']).'</bdi></span>' : '';
if ($r_info['type'] === DOKU_CHANGE_TYPE_MINOR_EDIT) $r_minor = 'class="minor"';
$r_head_title = ($media) ? dformat($r_rev) : $id.' ['.dformat($r_rev).']';
$r_head = '<bdi><a class="wikilink1" href="'.$ml_or_wl($id,"rev=$r_rev").'">'
. $r_head_title.'</a></bdi>'.$head_separator.$r_user.' '.$r_sum;
} elseif ($_rev = @filemtime($media_or_wikiFN($id))) {
$_info = $changelog->getRevisionInfo($_rev);
if ($_info['user']) {
$_user = '<bdi>'.editorinfo($_info['user']).'</bdi>';
if (auth_ismanager()) $_user .= ' <bdo dir="ltr">('.$_info['ip'].')</bdo>';
} else {
$_user = '<bdo dir="ltr">'.$_info['ip'].'</bdo>';
}
$_user = '<span class="user">'.$_user.'</span>';
$_sum = ($_info['sum']) ? '<span class="sum"><bdi>'.hsc($_info['sum']).'</span></bdi>' : '';
if ($_info['type'] === DOKU_CHANGE_TYPE_MINOR_EDIT) $r_minor = 'class="minor"';
$r_head_title = ($media) ? dformat($_rev) : $id.' ['.dformat($_rev).']';
$r_head = '<bdi><a class="wikilink1" href="'.$ml_or_wl($id).'">'
. $r_head_title.'</a></bdi> '.'('.$lang['current'].')'.$head_separator.$_user.' '.$_sum;
}else{
$r_head = '&mdash; ('.$lang['current'].')';
}
return array($l_head, $r_head, $l_minor, $r_minor);
}
/**
* Create html for revision navigation
*
* @param PageChangeLog $pagelog changelog object of current page
* @param int $l_rev left revision timestamp
* @param int $r_rev right revision timestamp
* @return string[] html of left and right navigation elements
*/
protected function diffNavigation($pagelog, $l_rev, $r_rev)
{
global $INFO, $ID;
// last timestamp is not in changelog, retrieve timestamp from metadata
// note: when page is removed, the metadata timestamp is zero
if (!$r_rev) {
if (isset($INFO['meta']['last_change']['date'])) {
$r_rev = $INFO['meta']['last_change']['date'];
} else {
$r_rev = 0;
}
}
//retrieve revisions with additional info
list($l_revs, $r_revs) = $pagelog->getRevisionsAround($l_rev, $r_rev);
$l_revisions = array();
if (!$l_rev) {
//no left revision given, add dummy
$l_revisions[0]= array('label' => '', 'attrs' => []);
}
foreach ($l_revs as $rev) {
$info = $pagelog->getRevisionInfo($rev);
$l_revisions[$rev] = array(
'label' => dformat($info['date']) .' '. editorinfo($info['user'], true) .' '. $info['sum'],
'attrs' => ['title' => $rev],
);
if ($r_rev ? $rev >= $r_rev : false) $l_revisions[$rev]['attrs']['disabled'] = 'disabled';
}
$r_revisions = array();
if (!$r_rev) {
//no right revision given, add dummy
$r_revisions[0] = array('label' => '', 'attrs' => []);
}
foreach ($r_revs as $rev) {
$info = $pagelog->getRevisionInfo($rev);
$r_revisions[$rev] = array(
'label' => dformat($info['date']) .' '. editorinfo($info['user'], true) .' '. $info['sum'],
'attrs' => ['title' => $rev],
);
if ($rev <= $l_rev) $r_revisions[$rev]['attrs']['disabled'] = 'disabled';
}
//determine previous/next revisions
$l_index = array_search($l_rev, $l_revs);
$l_prev = $l_index < count($l_revs) - 1 ? $l_revs[$l_index + 1] : null;
$l_next = $l_index > 1 ? $l_revs[$l_index - 1] : null;
if ($r_rev) {
$r_index = array_search($r_rev, $r_revs);
$r_prev = $r_index < count($r_revs) - 1 ? $r_revs[$r_index + 1] : null;
$r_next = $r_index > 1 ? $r_revs[$r_index - 1] : null;
} else {
//removed page
if ($l_next) {
$r_prev = $r_revs[0];
} else {
$r_prev = null;
}
$r_next = null;
}
/*
* Left side:
*/
$l_nav = '';
//move back
if ($l_prev) {
$l_nav .= $this->diffViewlink('diffbothprevrev', $l_prev, $r_prev);
$l_nav .= $this->diffViewlink('diffprevrev', $l_prev, $r_rev);
}
//dropdown
$form = new Form(['action' => wl()]);
$form->setHiddenField('id', $ID);
$form->setHiddenField('difftype', $this->difftype);
$form->setHiddenField('rev2[1]', $r_rev);
$form->setHiddenField('do', 'diff');
$input = $form->addDropdown('rev2[0]', $l_revisions)->val($l_rev)->addClass('quickselect');
$input->useInput(false); // inhibit prefillInput() during toHTML() process
$form->addButton('do[diff]', 'Go')->attr('type','submit');
$l_nav .= $form->toHTML();
//move forward
if ($l_next && ($l_next < $r_rev || !$r_rev)) {
$l_nav .= $this->diffViewlink('diffnextrev', $l_next, $r_rev);
}
/*
* Right side:
*/
$r_nav = '';
//move back
if ($l_rev < $r_prev) {
$r_nav .= $this->diffViewlink('diffprevrev', $l_rev, $r_prev);
}
//dropdown
$form = new Form(['action' => wl()]);
$form->setHiddenField('id', $ID);
$form->setHiddenField('rev2[0]', $l_rev);
$form->setHiddenField('difftype', $this->difftype);
$form->setHiddenField('do', 'diff');
$input = $form->addDropdown('rev2[1]', $r_revisions)->val($r_rev)->addClass('quickselect');
$input->useInput(false); // inhibit prefillInput() during toHTML() process
$form->addButton('do[diff]', 'Go')->attr('type','submit');
$r_nav .= $form->toHTML();
//move forward
if ($r_next) {
if ($pagelog->isCurrentRevision($r_next)) {
//last revision is diff with current page
$r_nav .= $this->diffViewlink('difflastrev', $l_rev);
} else {
$r_nav .= $this->diffViewlink('diffnextrev', $l_rev, $r_next);
}
} else {
$r_nav .= $this->diffViewlink('diffbothnextrev', $l_next, $r_next);
}
return array($l_nav, $r_nav);
}
/**
* Create html link to a diff view defined by two revisions
*
* @param string $linktype
* @param int $lrev oldest revision
* @param int $rrev newest revision or null for diff with current revision
* @return string html of link to a diff view
*/
protected function diffViewlink($linktype, $lrev, $rrev = null)
{
global $ID, $lang;
if ($rrev === null) {
$urlparam = array(
'do' => 'diff',
'rev' => $lrev,
'difftype' => $this->difftype,
);
} else {
$urlparam = array(
'do' => 'diff',
'rev2[0]' => $lrev,
'rev2[1]' => $rrev,
'difftype' => $this->difftype,
);
}
return '<a class="'. $linktype .'" href="'. wl($ID, $urlparam) .'" title="'. $lang[$linktype] .'">'
. '<span>'. $lang[$linktype] .'</span>'
. '</a>';
}
/**
* Insert soft breaks in diff html
*
* @param string $diffhtml
* @return string
*/
public function insertSoftbreaks($diffhtml)
{
// search the diff html string for both:
// - html tags, so these can be ignored
// - long strings of characters without breaking characters
return preg_replace_callback('/<[^>]*>|[^<> ]{12,}/', function ($match) {
// if match is an html tag, return it intact
if ($match[0][0] == '<') return $match[0];
// its a long string without a breaking character,
// 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
|
[?/,&\#;:] # 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]);
}, $diffhtml);
dbg_deprecated('not used see '. \dokuwiki\Ui\PageDiff::class .'::show()');
}
}

351
inc/Ui/MediaDiff.php Normal file
View File

@ -0,0 +1,351 @@
<?php
namespace dokuwiki\Ui;
use dokuwiki\ChangeLog\MediaChangeLog;
use dokuwiki\Ui\MediaRevisions;
use dokuwiki\Extension\Event;
use dokuwiki\Form\Form;
use JpegMeta;
/**
* DokuWiki MediaDiff Interface
*
* @package dokuwiki\Ui
*/
class MediaDiff extends Diff
{
/* @var MediaChangeLog */
protected $changelog;
/* @var array */
protected $oldRevInfo;
protected $newRevInfo;
/* @var bool */
protected $is_img;
/**
* MediaDiff Ui constructor
*
* @param string $id media id
*/
public function __construct($id)
{
if (!isset($id)) {
throw new \InvalidArgumentException('media id should not be empty!');
}
// init preference
$this->preference['fromAjax'] = false; // see dokuwiki\Ajax::callMediadiff()
$this->preference['showIntro'] = false;
$this->preference['difftype'] = 'both'; // diff view type: both, opacity or portions
parent::__construct($id);
}
/** @inheritdoc */
protected function setChangeLog()
{
$this->changelog = new MediaChangeLog($this->id);
}
/**
* Handle requested revision(s) and diff view preferences
*
* @return void
*/
protected function handle()
{
global $INPUT;
// requested rev or rev2
parent::handle();
// requested diff view type
if ($INPUT->has('difftype')) {
$this->preference['difftype'] = $INPUT->str('difftype');
}
}
/**
* Prepare revision info of comparison pair
*/
protected function preProcess()
{
$changelog =& $this->changelog;
// revision info of older file (left side)
$this->oldRevInfo = $changelog->getRevisionInfo($this->oldRev);
// revision info of newer file (right side)
$this->newRevInfo = $changelog->getRevisionInfo($this->newRev);
$this->is_img = preg_match('/\.(jpe?g|gif|png)$/', $this->id);
foreach ([&$this->oldRevInfo, &$this->newRevInfo] as &$revInfo) {
// use timestamp and '' properly as $rev for the current file
$isCurrent = $changelog->isCurrentRevision($revInfo['date']);
$revInfo += [
'current' => $isCurrent,
'rev' => $isCurrent ? '' : $revInfo['date'],
];
// headline in the Diff view navigation
$revInfo['navTitle'] = $this->revisionTitle($revInfo);
if ($this->is_img) {
$rev = $revInfo['rev'];
$meta = new JpegMeta(mediaFN($this->id, $rev));
// get image width and height for the mediamanager preview panel
$revInfo['previewSize'] = media_image_preview_size($this->id, $rev, $meta);
}
}
unset($revInfo);
// re-check image, ensure minimum image width for showImageDiff()
$this->is_img = ($this->is_img
&& ($this->oldRevInfo['previewSize'][0] ?? 0) >= 30
&& ($this->newRevInfo['previewSize'][0] ?? 0) >= 30
);
// adjust requested diff view type
if (!$this->is_img) {
$this->preference['difftype'] = 'both';
}
}
/**
* Shows difference between two revisions of media
*
* @author Kate Arzamastseva <pshns@ukr.net>
*/
public function show()
{
global $conf;
$ns = getNS($this->id);
$auth = auth_quickaclcheck("$ns:*");
if ($auth < AUTH_READ || !$this->id || !$conf['mediarevisions']) return '';
// retrieve form parameters: rev, rev2, difftype
$this->handle();
// prepare revision info of comparison pair
$this->preProcess();
// display intro
if ($this->preference['showIntro']) echo p_locale_xhtml('diff');
// print form to choose diff view type
if ($this->is_img && !$this->preference['fromAjax']) {
$this->showDiffViewSelector();
echo '<div id="mediamanager__diff" >';
}
switch ($this->preference['difftype']) {
case 'opacity':
case 'portions':
$this->showImageDiff();
break;
case 'both':
default:
$this->showFileDiff();
break;
}
if ($this->is_img && !$this->preference['fromAjax']) {
echo '</div>';
}
}
/**
* Print form to choose diff view type
* the dropdown is to be added through JavaScript, see lib/scripts/media.js
*/
protected function showDiffViewSelector()
{
// use timestamp for current revision
[$oldRev, $newRev] = [(int)$this->oldRevInfo['date'], (int)$this->newRevInfo['date']];
echo '<div class="diffoptions group">';
$form = new Form([
'id' => 'mediamanager__form_diffview',
'action' => media_managerURL([], '&'),
'method' => 'get',
'class' => 'diffView',
]);
$form->addTagOpen('div')->addClass('no');
$form->setHiddenField('sectok', null);
$form->setHiddenField('mediado', 'diff');
$form->setHiddenField('rev2[0]', $oldRev);
$form->setHiddenField('rev2[1]', $newRev);
$form->addTagClose('div');
echo $form->toHTML();
echo '</div>'; // .diffoptions
}
/**
* Prints two images side by side
* and slider
*
* @author Kate Arzamastseva <pshns@ukr.net>
*/
protected function showImageDiff()
{
// diff view type: opacity or portions
$type = $this->preference['difftype'];
// use '' for current revision
[$oldRev, $newRev] = [$this->oldRevInfo['rev'], $this->newRevInfo['rev']];
// adjust image width, right side (newer) has priority
$oldRevSize = $this->oldRevInfo['previewSize'];
$newRevSize = $this->newRevInfo['previewSize'];
if ($oldRevSize != $newRevSize) {
if ($newRevSize[0] > $oldRevSize[0]) {
$oldRevSize = $newRevSize;
}
}
$oldRevSrc = ml($this->id, ['rev' => $oldRev, 'h' => $oldRevSize[1], 'w' => $oldRevSize[0]]);
$newRevSrc = ml($this->id, ['rev' => $newRev, 'h' => $oldRevSize[1], 'w' => $oldRevSize[0]]);
// slider
echo '<div class="slider" style="max-width: '.($oldRevSize[0]-20).'px;" ></div>';
// two images in divs
echo '<div class="imageDiff '.$type.'">';
echo '<div class="image1" style="max-width: '.$oldRevSize[0].'px;">';
echo '<img src="'.$oldRevSrc.'" alt="" />';
echo '</div>';
echo '<div class="image2" style="max-width: '.$oldRevSize[0].'px;">';
echo '<img src="'.$newRevSrc.'" alt="" />';
echo '</div>';
echo '</div>';
}
/**
* Shows difference between two revisions of media file
*
* @author Kate Arzamastseva <pshns@ukr.net>
*/
protected function showFileDiff()
{
global $lang;
$changelog =& $this->changelog;
$ns = getNS($this->id);
$auth = auth_quickaclcheck("$ns:*");
// use '' for current revision
[$oldRev, $newRev] = [$this->oldRevInfo['rev'], $this->newRevInfo['rev']];
$oldRevMeta = new JpegMeta(mediaFN($this->id, $oldRev));
$newRevMeta = new JpegMeta(mediaFN($this->id, $newRev));
// display diff view table
echo '<div class="table">';
echo '<table>';
echo '<tr>';
echo '<th>'. $this->oldRevInfo['navTitle'] .'</th>';
echo '<th>'. $this->newRevInfo['navTitle'] .'</th>';
echo '</tr>';
echo '<tr class="image">';
echo '<td>';
media_preview($this->id, $auth, $oldRev, $oldRevMeta); // $auth not used in media_preview()?
echo '</td>';
echo '<td>';
media_preview($this->id, $auth, $newRev, $newRevMeta);
echo '</td>';
echo '</tr>';
echo '<tr class="actions">';
echo '<td>';
media_preview_buttons($this->id, $auth, $oldRev); // $auth used in media_preview_buttons()
echo '</td>';
echo '<td>';
media_preview_buttons($this->id, $auth, $newRev);
echo '</td>';
echo '</tr>';
$l_tags = media_file_tags($oldRevMeta);
$r_tags = media_file_tags($newRevMeta);
// FIXME r_tags-only stuff
foreach ($l_tags as $key => $l_tag) {
if ($l_tag['value'] != $r_tags[$key]['value']) {
$r_tags[$key]['highlighted'] = true;
$l_tags[$key]['highlighted'] = true;
} elseif (!$l_tag['value'] || !$r_tags[$key]['value']) {
unset($r_tags[$key]);
unset($l_tags[$key]);
}
}
echo '<tr>';
foreach (array($l_tags, $r_tags) as $tags) {
echo '<td>';
echo '<dl class="img_tags">';
foreach ($tags as $tag) {
$value = cleanText($tag['value']);
if (!$value) $value = '-';
echo '<dt>'.$lang[$tag['tag'][1]].'</dt>';
echo '<dd>';
if ($tag['highlighted']) echo '<strong>';
if ($tag['tag'][2] == 'date') {
echo dformat($value);
} else {
echo hsc($value);
}
if ($tag['highlighted']) echo '</strong>';
echo '</dd>';
}
echo '</dl>';
echo '</td>';
}
echo '</tr>';
echo '</table>';
echo '</div>';
}
/**
* Revision Title for MediaDiff table headline
*
* @param array $info Revision info structure of a media file
* @return string
*/
protected function revisionTitle(array $info)
{
global $lang, $INFO;
if (isset($info['date'])) {
$rev = $info['date'];
$title = '<bdi><a class="wikilink1" href="'.ml($this->id, ['rev' => $rev]).'">'
. dformat($rev).'</a></bdi>';
} else {
$rev = false;
$title = '&mdash;';
}
if (isset($info['current']) || ($rev && $rev == $INFO['currentrev'])) {
$title .= '&nbsp;('.$lang['current'].')';
}
// append separator
$title .= ($this->preference['difftype'] === 'inline') ? ' ' : '<br />';
// supplement
if (isset($info['date'])) {
$objRevInfo = (new MediaRevisions($this->id))->getObjRevInfo($info);
$title .= $objRevInfo->editSummary().' '.$objRevInfo->editor();
}
return $title;
}
}

118
inc/Ui/MediaRevisions.php Normal file
View File

@ -0,0 +1,118 @@
<?php
namespace dokuwiki\Ui;
use dokuwiki\ChangeLog\MediaChangeLog;
use dokuwiki\Form\Form;
/**
* DokuWiki MediaRevisions Interface
*
* @package dokuwiki\Ui
*/
class MediaRevisions extends Revisions
{
/* @var MediaChangeLog */
protected $changelog;
/**
* MediaRevisions Ui constructor
*
* @param string $id id of media
*/
public function __construct($id)
{
if (!$id) {
throw new \InvalidArgumentException('media id should not be empty!');
}
parent::__construct($id);
}
/** @inheritdoc */
protected function setChangeLog()
{
$this->changelog = new MediaChangeLog($this->id);
}
/**
* Display a list of Media Revisions in the MediaManager
*
* @author Andreas Gohr <andi@splitbrain.org>
* @author Ben Coburn <btcoburn@silicodon.net>
* @author Kate Arzamastseva <pshns@ukr.net>
* @author Satoshi Sahara <sahara.satoshi@gmail.com>
*
* @param int $first skip the first n changelog lines
* @return void
*/
public function show($first = 0)
{
global $lang;
$changelog =& $this->changelog;
// get revisions, and set correct pagenation parameters (first, hasNext)
if ($first === null) $first = 0;
$hasNext = false;
$revisions = $this->getRevisions($first, $hasNext);
// create the form
$form = new Form([
'id' => 'page__revisions', // must not be "media__revisions"
'action' => media_managerURL(['image' => $this->id], '&'),
'class' => 'changes',
]);
$form->setHiddenField('mediado', 'diff'); // required for media revisions
$form->addTagOpen('div')->addClass('no');
// start listing
$form->addTagOpen('ul');
foreach ($revisions as $info) {
$rev = $info['date'];
$info['current'] = $changelog->isCurrentRevision($rev);
$class = ($info['type'] === DOKU_CHANGE_TYPE_MINOR_EDIT) ? 'minor' : '';
$form->addTagOpen('li')->addClass($class);
$form->addTagOpen('div')->addClass('li');
if (isset($info['current'])) {
$form->addCheckbox('rev2[]')->val($rev);
} elseif (file_exists(mediaFN($this->id, $rev))) {
$form->addCheckbox('rev2[]')->val($rev);
} else {
$form->addCheckbox('')->val($rev)->attr('disabled','disabled');
}
$form->addHTML(' ');
$objRevInfo = $this->getObjRevInfo($info);
$html = implode(' ', [
$objRevInfo->editDate(), // edit date and time
$objRevInfo->difflink(), // link to diffview icon
$objRevInfo->itemName(), // name of page or media
'<div>',
$objRevInfo->editSummary(), // edit summary
$objRevInfo->editor(), // editor info
$objRevInfo->sizechange(), // size change indicator
$objRevInfo->currentIndicator(), // current indicator (only when k=1)
'</div>',
]);
$form->addHTML($html);
$form->addTagClose('div');
$form->addTagClose('li');
}
$form->addTagClose('ul'); // end of revision list
// show button for diff view
$form->addButton('do[diff]', $lang['diff2'])->attr('type', 'submit');
$form->addTagClose('div'); // close div class=no
print $form->toHTML('Revisions');
// provide navigation for pagenated revision list (of pages and/or media files)
print $this->navigation($first, $hasNext, function ($n) {
return media_managerURL(['first' => $n], '&', false, true);
});
}
}

View File

@ -35,7 +35,7 @@ class PageConflict extends Ui
*/
public function show()
{
global $ID;
global $INFO;
global $lang;
// print intro
@ -44,7 +44,7 @@ class PageConflict extends Ui
// create the form
$form = new Form(['id' => 'dw__editform']);
$form->addTagOpen('div')->addClass('no');
$form->setHiddenField('id', $ID);
$form->setHiddenField('id', $INFO['id']);
$form->setHiddenField('wikitext', $this->text);
$form->setHiddenField('summary', $this->summary);
@ -56,7 +56,8 @@ class PageConflict extends Ui
print '<br /><br /><br /><br />';
(new Diff($this->text, false))->show();
// print difference
(new PageDiff($INFO['id']))->compareWith($this->text)->preference('showIntro', false)->show();
}
}

554
inc/Ui/PageDiff.php Normal file
View File

@ -0,0 +1,554 @@
<?php
namespace dokuwiki\Ui;
use dokuwiki\ChangeLog\PageChangeLog;
use dokuwiki\Form\Form;
/**
* DokuWiki PageDiff Interface
*
* @author Andreas Gohr <andi@splitbrain.org>
* @author Satoshi Sahara <sahara.satoshi@gmail.com>
* @package dokuwiki\Ui
*/
class PageDiff extends Diff
{
/* @var PageChangeLog */
protected $changelog;
/* @var array */
protected $oldRevInfo;
protected $newRevInfo;
/* @var string */
protected $text;
/**
* PageDiff Ui constructor
*
* @param string $id page id
*/
public function __construct($id = null)
{
global $INFO;
if (!isset($id)) $id = $INFO['id'];
// init preference
$this->preference['showIntro'] = true;
$this->preference['difftype'] = 'sidebyside'; // diff view type: inline or sidebyside
parent::__construct($id);
}
/** @inheritdoc */
protected function setChangeLog()
{
$this->changelog = new PageChangeLog($this->id);
}
/**
* Set text to be compared with most current version
* when it has been externally edited
* exclusively use of the compare($old, $new) method
*
* @param string $text
* @return $this
*/
public function compareWith($text = null)
{
global $lang;
if (isset($text)) {
$this->text = $text;
$changelog =& $this->changelog;
// revision info of older file (left side)
$this->oldRevInfo = $changelog->getCurrentRevisionInfo() + [
'current' => true,
'rev' => '',
'navTitle' => $this->revisionTitle($changelog->getCurrentRevisionInfo()),
'text' => rawWiki($this->id, ''),
];
// revision info of newer file (right side)
$this->newRevInfo = [
'date' => null,
//'ip' => '127.0.0.1',
//'type' => DOKU_CHANGE_TYPE_CREATE,
'id' => $this->id,
//'user' => '',
//'sum' => '',
//'extra' => '',
'sizechange' => strlen($this->text) - io_getSizeFile(wikiFN($this->id, '')),
'timestamp' => false,
'current' => false,
'rev' => false,
'navTitle' => $lang['yours'],
'text' => cleanText($this->text),
];
}
return $this;
}
/**
* Handle requested revision(s) and diff view preferences
*
* @return void
*/
protected function handle()
{
global $INPUT;
// requested rev or rev2
if (!isset($this->oldRevInfo, $this->newRevInfo)) {
parent::handle();
}
// requested diff view type
if ($INPUT->has('difftype')) {
$this->preference['difftype'] = $INPUT->str('difftype');
} else {
// read preference from DokuWiki cookie. PageDiff only
$mode = get_doku_pref('difftype', $mode = null);
if (isset($mode)) $this->preference['difftype'] = $mode;
}
if (!$INPUT->has('rev') && !$INPUT->has('rev2')) {
global $INFO, $REV;
if ($this->id == $INFO['id'])
$REV = $this->oldRev; // store revision back in $REV
}
}
/**
* Prepare revision info of comparison pair
*/
protected function preProcess()
{
$changelog =& $this->changelog;
// revision info of older file (left side)
$this->oldRevInfo = $changelog->getRevisionInfo($this->oldRev);
// revision info of newer file (right side)
$this->newRevInfo = $changelog->getRevisionInfo($this->newRev);
foreach ([&$this->oldRevInfo, &$this->newRevInfo] as &$revInfo) {
// use timestamp and '' properly as $rev for the current file
$isCurrent = $changelog->isCurrentRevision($revInfo['date']);
$revInfo += [
'current' => $isCurrent,
'rev' => $isCurrent ? '' : $revInfo['date'],
];
// headline in the Diff view navigation
$revInfo['navTitle'] = $this->revisionTitle($revInfo);
if ($revInfo['type'] == DOKU_CHANGE_TYPE_DELETE) {
//attic stores complete last page version for a deleted page
$revInfo['text'] = '';
} else {
$revInfo['text'] = rawWiki($this->id, $revInfo['rev']);
}
}
}
/**
* Show diff
* between current page version and provided $text
* or between the revisions provided via GET or POST
*
* @author Andreas Gohr <andi@splitbrain.org>
*
* @return void
*/
public function show()
{
$changelog =& $this->changelog;
if (!isset($this->oldRevInfo, $this->newRevInfo)) {
// retrieve form parameters: rev, rev2, difftype
$this->handle();
// prepare revision info of comparison pair, except PageConfrict or PageDraft
$this->preProcess();
}
// create difference engine object
$Difference = new \Diff(
explode("\n", $this->oldRevInfo['text']),
explode("\n", $this->newRevInfo['text'])
);
// build paired navigation
[$navOlderRevisions, $navNewerRevisions] = $this->buildRevisionsNavigation();
// display intro
if ($this->preference['showIntro']) echo p_locale_xhtml('diff');
// print form to choose diff view type, and exact url reference to the view
if ($this->newRevInfo['rev'] !== false) {
$this->showDiffViewSelector();
}
// assign minor edit checker to the variable
$classEditType = function ($info) {
return ($info['type'] === DOKU_CHANGE_TYPE_MINOR_EDIT) ? ' class="minor"' : '';
};
// display diff view table
echo '<div class="table">';
echo '<table class="diff diff_'.$this->preference['difftype'] .'">';
//navigation and header
switch ($this->preference['difftype']) {
case 'inline':
if ($this->newRevInfo['rev'] !== false) {
echo '<tr>'
.'<td class="diff-lineheader">-</td>'
.'<td class="diffnav">'. $navOlderRevisions .'</td>'
.'</tr>';
echo '<tr>'
.'<th class="diff-lineheader">-</th>'
.'<th'.$classEditType($this->oldRevInfo).'>'.$this->oldRevInfo['navTitle'].'</th>'
.'</tr>';
}
echo '<tr>'
.'<td class="diff-lineheader">+</td>'
.'<td class="diffnav">'. $navNewerRevisions .'</td>'
.'</tr>';
echo '<tr>'
.'<th class="diff-lineheader">+</th>'
.'<th'.$classEditType($this->newRevInfo).'>'.$this->newRevInfo['navTitle'].'</th>'
.'</tr>';
// create formatter object
$DiffFormatter = new \InlineDiffFormatter();
break;
case 'sidebyside':
default:
if ($this->newRevInfo['rev'] !== false) {
echo '<tr>'
.'<td colspan="2" class="diffnav">'. $navOlderRevisions .'</td>'
.'<td colspan="2" class="diffnav">'. $navNewerRevisions .'</td>'
.'</tr>';
}
echo '<tr>'
.'<th colspan="2"'.$classEditType($this->oldRevInfo).'>'.$this->oldRevInfo['navTitle'].'</th>'
.'<th colspan="2"'.$classEditType($this->newRevInfo).'>'.$this->newRevInfo['navTitle'].'</th>'
.'</tr>';
// create formatter object
$DiffFormatter = new \TableDiffFormatter();
break;
}
// output formatted difference
echo $this->insertSoftbreaks($DiffFormatter->format($Difference));
echo '</table>';
echo '</div>';
}
/**
* Revision Title for PageDiff table headline
*
* @param array $info Revision info structure of a page
* @return string
*/
protected function revisionTitle(array $info)
{
global $lang;
// use designated title when compare current page source with given text
if (array_key_exists('date', $info) && is_null($info['date'])) {
return $lang['yours'];
}
// revision info may have timestamp key when external edits occurred
$info['timestamp'] = $info['timestamp'] ?? true;
if (isset($info['date'])) {
$rev = $info['date'];
if ($info['timestamp'] === false) {
// exteranlly deleted or older file restored
$title = '<bdi><a class="wikilink2" href="'.wl($this->id).'">'
. $this->id .' ['. $lang['unknowndate'] .']'.'</a></bdi>';
} else {
$title = '<bdi><a class="wikilink1" href="'.wl($this->id, ['rev' => $rev]).'">'
. $this->id .' ['. dformat($rev) .']'.'</a></bdi>';
}
} else {
$rev = false;
$title = '&mdash;';
}
if ($info['current']) {
$title .= '&nbsp;('.$lang['current'].')';
}
// append separator
$title .= ($this->preference['difftype'] === 'inline') ? ' ' : '<br />';
// supplement
if (isset($info['date'])) {
$objRevInfo = (new PageRevisions($this->id))->getObjRevInfo($info);
$title .= $objRevInfo->editSummary().' '.$objRevInfo->editor();
}
return $title;
}
/**
* Print form to choose diff view type, and exact url reference to the view
*/
protected function showDiffViewSelector()
{
global $lang;
// use timestamp for current revision
[$oldRev, $newRev] = [(int)$this->oldRevInfo['date'], (int)$this->newRevInfo['date']];
echo '<div class="diffoptions group">';
// create the form to select difftype
$form = new Form(['action' => wl()]);
$form->setHiddenField('id', $this->id);
$form->setHiddenField('rev2[0]', $oldRev);
$form->setHiddenField('rev2[1]', $newRev);
$form->setHiddenField('do', 'diff');
$options = array(
'sidebyside' => $lang['diff_side'],
'inline' => $lang['diff_inline'],
);
$input = $form->addDropdown('difftype', $options, $lang['diff_type'])
->val($this->preference['difftype'])
->addClass('quickselect');
$input->useInput(false); // inhibit prefillInput() during toHTML() process
$form->addButton('do[diff]', 'Go')->attr('type','submit');
echo $form->toHTML();
// show exact url reference to the view when it is meaningful
echo '<p>';
if ($oldRev && $newRev) {
// link to exactly this view FS#2835
$viewUrl = $this->diffViewlink('difflink', $oldRev, $newRev);
}
echo $viewUrl ?? '<br />';
echo '</p>';
echo '</div>'; // .diffoptions
}
/**
* Create html for revision navigation
*
* The navigation consists of older and newer revisions selectors, each
* state mutually depends on the selected revision of opposite side.
*
* @return string[] html of navigation for both older and newer sides
*/
protected function buildRevisionsNavigation()
{
$changelog =& $this->changelog;
if ($this->newRevInfo['rev'] === false) {
// no revisions selector for PageConflict or PageDraft
return array('', '');
}
// use timestamp for current revision
[$oldRev, $newRev] = [(int)$this->oldRevInfo['date'], (int)$this->newRevInfo['date']];
// retrieve revisions with additional info
[$oldRevs, $newRevs] = $changelog->getRevisionsAround($oldRev, $newRev);
// build options for dropdown selector
$olderRevisions = $this->buildRevisionOptions('older', $oldRevs);
$newerRevisions = $this->buildRevisionOptions('newer', $newRevs);
// determine previous/next revisions
$index = array_search($oldRev, $oldRevs);
$oldPrevRev = ($index +1 < count($oldRevs)) ? $oldRevs[$index +1] : false;
$oldNextRev = ($index > 0) ? $oldRevs[$index -1] : false;
$index = array_search($newRev, $newRevs);
$newPrevRev = ($index +1 < count($newRevs)) ? $newRevs[$index +1] : false;
$newNextRev = ($index > 0) ? $newRevs[$index -1] : false;
/*
* navigation UI for older revisions / Left side:
*/
$navOlderRevs = '';
// move backward both side: ◀◀
if ($oldPrevRev && $newPrevRev)
$navOlderRevs .= $this->diffViewlink('diffbothprevrev', $oldPrevRev, $newPrevRev);
// move backward left side: ◀
if ($oldPrevRev)
$navOlderRevs .= $this->diffViewlink('diffprevrev', $oldPrevRev, $newRev);
// dropdown
$navOlderRevs .= $this->buildDropdownSelector('older', $olderRevisions);
// move forward left side: ▶
if ($oldNextRev && ($oldNextRev < $newRev))
$navOlderRevs .= $this->diffViewlink('diffnextrev', $oldNextRev, $newRev);
/*
* navigation UI for newer revisions / Right side:
*/
$navNewerRevs = '';
// move backward right side: ◀
if ($newPrevRev && ($oldRev < $newPrevRev))
$navNewerRevs .= $this->diffViewlink('diffprevrev', $oldRev, $newPrevRev);
// dropdown
$navNewerRevs .= $this->buildDropdownSelector('newer', $newerRevisions);
// move forward right side: ▶
if ($newNextRev) {
if ($changelog->isCurrentRevision($newNextRev)) {
$navNewerRevs .= $this->diffViewlink('difflastrev', $oldRev, $newNextRev);
} else {
$navNewerRevs .= $this->diffViewlink('diffnextrev', $oldRev, $newNextRev);
}
}
// move forward both side: ▶▶
if ($oldNextRev && $newNextRev)
$navNewerRevs .= $this->diffViewlink('diffbothnextrev', $oldNextRev, $newNextRev);
return array($navOlderRevs, $navNewerRevs);
}
/**
* prepare options for dropdwon selector
*
* @params string $side "older" or "newer"
* @params array $revs list of revsion
* @return array
*/
protected function buildRevisionOptions($side, $revs)
{
global $lang;
$changelog =& $this->changelog;
$revisions = array();
// use timestamp for current revision
[$oldRev, $newRev] = [(int)$this->oldRevInfo['date'], (int)$this->newRevInfo['date']];
foreach ($revs as $rev) {
$info = $changelog->getRevisionInfo($rev);
// revision info may have timestamp key when external edits occurred
$info['timestamp'] = $info['timestamp'] ?? true;
$date = dformat($info['date']);
if ($info['timestamp'] === false) {
// exteranlly deleted or older file restored
$date = preg_replace('/[0-9a-zA-Z]/','_', $date);
}
$revisions[$rev] = array(
'label' => implode(' ', [
$date,
editorinfo($info['user'], true),
$info['sum'],
]),
'attrs' => ['title' => $rev],
);
if (($side == 'older' && ($newRev && $rev >= $newRev))
||($side == 'newer' && ($rev <= $oldRev))
) {
$revisions[$rev]['attrs']['disabled'] = 'disabled';
}
}
return $revisions;
}
/**
* build Dropdown form for revisions navigation
*
* @params string $side "older" or "newer"
* @params array $options dropdown options
* @return string
*/
protected function buildDropdownSelector($side, $options)
{
$form = new Form(['action' => wl($this->id)]);
$form->setHiddenField('id', $this->id);
$form->setHiddenField('do', 'diff');
$form->setHiddenField('difftype', $this->preference['difftype']);
// use timestamp for current revision
[$oldRev, $newRev] = [(int)$this->oldRevInfo['date'], (int)$this->newRevInfo['date']];
switch ($side) {
case 'older': // left side
$form->setHiddenField('rev2[1]', $newRev);
$input = $form->addDropdown('rev2[0]', $options)
->val($oldRev)->addClass('quickselect');
$input->useInput(false); // inhibit prefillInput() during toHTML() process
break;
case 'newer': // right side
$form->setHiddenField('rev2[0]', $oldRev);
$input = $form->addDropdown('rev2[1]', $options)
->val($newRev)->addClass('quickselect');
$input->useInput(false); // inhibit prefillInput() during toHTML() process
break;
}
$form->addButton('do[diff]', 'Go')->attr('type','submit');
return $form->toHTML();
}
/**
* Create html link to a diff view defined by two revisions
*
* @param string $linktype
* @param int $oldRev older revision
* @param int $newRev newer revision or null for diff with current revision
* @return string html of link to a diff view
*/
protected function diffViewlink($linktype, $oldRev, $newRev = null)
{
global $lang;
if ($newRev === null) {
$urlparam = array(
'do' => 'diff',
'rev' => $oldRev,
'difftype' => $this->preference['difftype'],
);
} else {
$urlparam = array(
'do' => 'diff',
'rev2[0]' => $oldRev,
'rev2[1]' => $newRev,
'difftype' => $this->preference['difftype'],
);
}
$attr = array(
'class' => $linktype,
'href' => wl($this->id, $urlparam, true, '&'),
'title' => $lang[$linktype],
);
return '<a '. buildAttributes($attr) .'><span>'. $lang[$linktype] .'</span></a>';
}
/**
* Insert soft breaks in diff html
*
* @param string $diffhtml
* @return string
*/
public function insertSoftbreaks($diffhtml)
{
// search the diff html string for both:
// - html tags, so these can be ignored
// - long strings of characters without breaking characters
return preg_replace_callback('/<[^>]*>|[^<> ]{12,}/', function ($match) {
// if match is an html tag, return it intact
if ($match[0][0] == '<') return $match[0];
// its a long string without a breaking character,
// 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
|
[?/,&\#;:] # 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]);
}, $diffhtml);
}
}

View File

@ -22,21 +22,21 @@ class PageDraft extends Ui
public function show()
{
global $INFO;
global $ID;
global $lang;
$draft = new \dokuwiki\Draft($ID, $INFO['client']);
$draft = new \dokuwiki\Draft($INFO['id'], $INFO['client']);
$text = $draft->getDraftText();
// print intro
print p_locale_xhtml('draft');
(new Diff($text, false))->show();
// print difference
(new PageDiff($INFO['id']))->compareWith($text)->preference('showIntro', false)->show();
// create the draft form
$form = new Form(['id' => 'dw__editform']);
$form->addTagOpen('div')->addClass('no');
$form->setHiddenField('id', $ID);
$form->setHiddenField('id', $INFO['id']);
$form->setHiddenField('date', $draft->getDraftDate());
$form->setHiddenField('wikitext', $text);

116
inc/Ui/PageRevisions.php Normal file
View File

@ -0,0 +1,116 @@
<?php
namespace dokuwiki\Ui;
use dokuwiki\ChangeLog\PageChangeLog;
use dokuwiki\Form\Form;
/**
* DokuWiki PageRevisions Interface
*
* @package dokuwiki\Ui
*/
class PageRevisions extends Revisions
{
/* @var PageChangeLog */
protected $changelog;
/**
* PageRevisions Ui constructor
*
* @param string $id id of page
*/
public function __construct($id = null)
{
global $INFO;
if (!isset($id)) $id = $INFO['id'];
parent::__construct($id);
}
/** @inheritdoc */
protected function setChangeLog()
{
$this->changelog = new PageChangeLog($this->id);
}
/**
* Display list of old revisions of the page
*
* @author Andreas Gohr <andi@splitbrain.org>
* @author Ben Coburn <btcoburn@silicodon.net>
* @author Kate Arzamastseva <pshns@ukr.net>
* @author Satoshi Sahara <sahara.satoshi@gmail.com>
*
* @param int $first skip the first n changelog lines
* @return void
*/
public function show($first = 0)
{
global $lang, $REV;
$changelog =& $this->changelog;
// get revisions, and set correct pagenation parameters (first, hasNext)
if ($first === null) $first = 0;
$hasNext = false;
$revisions = $this->getRevisions($first, $hasNext);
// print intro
print p_locale_xhtml('revisions');
// create the form
$form = new Form([
'id' => 'page__revisions',
'class' => 'changes',
]);
$form->addTagOpen('div')->addClass('no');
// start listing
$form->addTagOpen('ul');
foreach ($revisions as $info) {
$rev = $info['date'];
$info['current'] = $changelog->isCurrentRevision($rev);
$class = ($info['type'] === DOKU_CHANGE_TYPE_MINOR_EDIT) ? 'minor' : '';
$form->addTagOpen('li')->addClass($class);
$form->addTagOpen('div')->addClass('li');
if (isset($info['current'])) {
$form->addCheckbox('rev2[]')->val($rev);
} elseif ($rev == $REV) {
$form->addCheckbox('rev2[]')->val($rev)->attr('checked','checked');
} elseif (page_exists($this->id, $rev)) {
$form->addCheckbox('rev2[]')->val($rev);
} else {
$form->addCheckbox('')->val($rev)->attr('disabled','disabled');
}
$form->addHTML(' ');
$objRevInfo = $this->getObjRevInfo($info);
$html = implode(' ', [
$objRevInfo->editDate(), // edit date and time
$objRevInfo->difflink(), // link to diffview icon
$objRevInfo->itemName(), // name of page or media
$objRevInfo->editSummary(), // edit summary
$objRevInfo->editor(), // editor info
$objRevInfo->sizechange(), // size change indicator
$objRevInfo->currentIndicator(), // current indicator (only when k=1)
]);
$form->addHTML($html);
$form->addTagClose('div');
$form->addTagClose('li');
}
$form->addTagClose('ul'); // end of revision list
// show button for diff view
$form->addButton('do[diff]', $lang['diff2'])->attr('type', 'submit');
$form->addTagClose('div'); // close div class=no
print $form->toHTML('Revisions');
// provide navigation for paginated revision list (of pages and/or media files)
print $this->navigation($first, $hasNext, function ($n) {
return array('do' => 'revisions', 'first' => $n);
});
}
}

View File

@ -2,6 +2,7 @@
namespace dokuwiki\Ui;
use dokuwiki\ChangeLog\PageChangeLog;
use dokuwiki\ChangeLog\MediaChangeLog;
use dokuwiki\Form\Form;
@ -72,6 +73,10 @@ class Recent extends Ui
// start listing of recent items
$form->addTagOpen('ul');
foreach ($recents as $recent) {
// check possible external edition for current page or media
$this->checkCurrentRevision($recent);
$recent['current'] = true;
$objRevInfo = $this->getObjRevInfo($recent);
$class = ($recent['type'] === DOKU_CHANGE_TYPE_MINOR_EDIT) ? 'minor': '';
$form->addTagOpen('li')->addClass($class);
@ -140,6 +145,31 @@ class Recent extends Ui
return $recents;
}
/**
* Check possible external deletion for current page or media
*
* To keep sort order in the recent list, we ignore externally modification.
* It is not possible to know when external deletion had happened,
* $info['date'] is to be incremented 1 second when such deletion detected.
*/
protected function checkCurrentRevision(array &$info)
{
$itemType = strrpos($info['id'], '.') ? 'media' : 'page';
if ($itemType == 'page') {
$changelog = new PageChangelog($info['id']);
} else {
$changelog = new MediaChangelog($info['id']);
}
if (!$changelog->isCurrentRevision($info['date'])) {
$currentRevInfo = $changelog->getCurrentRevisionInfo();
if ($currentRevInfo['type'] == DOKU_CHANGE_TYPE_DELETE) {
// the page or media file was externally deleted
$info = array_merge($info, $currentRevInfo);
}
}
unset($changelog);
}
/**
* Navigation buttons for Pagenation (prev/next)
*
@ -209,6 +239,8 @@ class Recent extends Ui
public function __construct(array $info)
{
$info['item'] = strrpos($info['id'], '.') ? 'media' : 'page';
$info['current'] = $info['current'] ?? false;
$this->info = $info;
}
@ -216,10 +248,12 @@ class Recent extends Ui
public function itemIcon()
{
$id = $this->info['id'];
if (isset($this->info['media'])) {
$html = media_printicon($id);
} else {
$html = '<img class="icon" src="'.DOKU_BASE.'lib/images/fileicons/file.png" alt="'.$id.'" />';
switch ($this->info['item']) {
case 'media': // media file revision
$html = media_printicon($id);
break;
case 'page': // page revision
$html = '<img class="icon" src="'.DOKU_BASE.'lib/images/fileicons/file.png" alt="'.$id.'" />';
}
return $html;
}
@ -254,14 +288,17 @@ class Recent extends Ui
public function itemName()
{
$id = $this->info['id'];
if (isset($this->info['media'])) {
$href = media_managerURL(['tab_details'=>'view', 'image'=> $id, 'ns'=> getNS($id)], '&');
$class = file_exists(mediaFN($id)) ? 'wikilink1' : 'wikilink2';
$html = '<a href="'.$href.'" class="'.$class.'">'.$id.'</a>';
} else {
$html = html_wikilink(':'.$id, (useHeading('navigation') ? null : $id));
switch ($this->info['item']) {
case 'media': // media file revision
$href = media_managerURL(['tab_details'=>'view', 'image'=> $id, 'ns'=> getNS($id)], '&');
$class = file_exists(mediaFN($id)) ? 'wikilink1' : 'wikilink2';
$html = '<a href="'.$href.'" class="'.$class.'">'.$id.'</a>';
return $html;
case 'page': // page revision
$html = html_wikilink(':'.$id, (useHeading('navigation') ? null : $id));
return $html;
}
return $html;
return '';
}
// icon difflink
@ -270,18 +307,20 @@ class Recent extends Ui
global $lang;
$id = $this->info['id'];
if (isset($this->info['media'])) {
$revs = (new MediaChangeLog($id))->getRevisions(0, 1);
$diff = (count($revs) && file_exists(mediaFN($id)));
if ($diff) {
$href = media_managerURL(
['tab_details'=>'history', 'mediado'=>'diff', 'image'=> $id, 'ns'=> getNS($id)], '&'
);
} else {
$href = '';
}
} else {
$href = wl($id, "do=diff", false, '&');
switch ($this->info['item']) {
case 'media': // media file revision
$revs = (new MediaChangeLog($id))->getRevisions(0, 1);
$diff = (count($revs) && file_exists(mediaFN($id)));
if ($diff) {
$href = media_managerURL(
['tab_details'=>'history', 'mediado'=>'diff', 'image'=> $id, 'ns'=> getNS($id)], '&'
);
} else {
$href = '';
}
break;
case 'page': // page revision
$href = wl($id, "do=diff", false, '&');
}
if ($href) {
@ -300,10 +339,12 @@ class Recent extends Ui
{
global $lang;
$id = $this->info['id'];
if (isset($this->info['media'])) {
$href = media_managerURL(['tab_details'=>'history', 'image'=> $id, 'ns'=> getNS($id)], '&');
} else {
$href = wl($id, "do=revisions", false, '&');
switch ($this->info['item']) {
case 'media': // media file revision
$href = media_managerURL(['tab_details'=>'history', 'image'=> $id, 'ns'=> getNS($id)], '&');
break;
case 'page': // page revision
$href = wl($id, "do=revisions", false, '&');
}
$html = '<a href="'.$href.'" class="revisions_link">'
. '<img src="'.DOKU_BASE.'lib/images/history.png" width="12" height="14"'

View File

@ -2,193 +2,40 @@
namespace dokuwiki\Ui;
use dokuwiki\ChangeLog\PageChangeLog;
use dokuwiki\ChangeLog\MediaChangeLog;
use dokuwiki\Form\Form;
use dokuwiki\ChangeLog\ChangeLog;
/**
* DokuWiki Revisions Interface
* parent class of PageRevisions and MediaRevisions
*
* @package dokuwiki\Ui
*/
class Revisions extends Ui
abstract class Revisions extends Ui
{
protected $first;
protected $media_id;
/* @var string */
protected $id; // page id or media id
/* @var ChangeLog */
protected $changelog; // PageChangeLog or MediaChangeLog object
/**
* Revisions Ui constructor
*
* @param int $first skip the first n changelog lines
* @param bool|string $media_id id of media, or false for current page
* @param string $id page id or media id
*/
public function __construct($first = 0, $media_id = false)
public function __construct($id)
{
$this->first = $first;
$this->media_id = $media_id;
$this->id = $id;
$this->setChangeLog();
}
/**
* Display list of old revisions
*
* @author Andreas Gohr <andi@splitbrain.org>
* @author Ben Coburn <btcoburn@silicodon.net>
* @author Kate Arzamastseva <pshns@ukr.net>
* @author Satoshi Sahara <sahara.satoshi@gmail.com>
*
* @return void
* set class property changelog
*/
public function show()
{
global $ID;
if ($this->media_id) {
return $this->showMediaRevisions($this->media_id);
} else {
return $this->showPageRevisions($ID);
}
}
abstract protected function setChangeLog();
/**
* Display a list of Media Revisions in the MediaManager
*
* @param string $id media id
* @return void
*/
protected function showMediaRevisions($id)
{
global $lang;
// get revisions, and set correct pagenation parameters (first, hasNext)
$first = $this->first;
$hasNext = false;
$revisions = $this->getRevisions($first, $hasNext);
// create the form
$form = new Form([
'id' => 'page__revisions', // must not be "media__revisions"
'action' => media_managerURL(['image' => $id], '&'),
'class' => 'changes',
]);
$form->setHiddenField('mediado', 'diff'); // required for media revisions
$form->addTagOpen('div')->addClass('no');
// start listing
$form->addTagOpen('ul');
foreach ($revisions as $info) {
$rev = $info['date'];
$class = ($info['type'] === DOKU_CHANGE_TYPE_MINOR_EDIT) ? 'minor' : '';
$form->addTagOpen('li')->addClass($class);
$form->addTagOpen('div')->addClass('li');
if (isset($info['current'])) {
$form->addCheckbox('rev2[]')->val('current');
} elseif (file_exists(mediaFN($id, $rev))) {
$form->addCheckbox('rev2[]')->val($rev);
} else {
$form->addCheckbox('')->val($rev)->attr('disabled','disabled');
}
$form->addHTML(' ');
$objRevInfo = $this->getObjRevInfo($info);
$html = implode(' ', [
$objRevInfo->editDate(), // edit date and time
$objRevInfo->difflink(), // link to diffview icon
$objRevInfo->itemName(), // name of page or media
'<div>',
$objRevInfo->editSummary(), // edit summary
$objRevInfo->editor(), // editor info
html_sizechange($info['sizechange']), // size change indicator
$objRevInfo->currentIndicator(), // current indicator (only when k=1)
'</div>',
]);
$form->addHTML($html);
$form->addTagClose('div');
$form->addTagClose('li');
}
$form->addTagClose('ul'); // end of revision list
// show button for diff view
$form->addButton('do[diff]', $lang['diff2'])->attr('type', 'submit');
$form->addTagClose('div'); // close div class=no
print $form->toHTML('Revisions');
// provide navigation for pagenated revision list (of pages and/or media files)
print $this->htmlNavigation($id, $first, $hasNext);
}
/**
* Display a list of Page Revisions
*
* @return void
*/
protected function showPageRevisions($id)
{
global $lang;
// get revisions, and set correct pagenation parameters (first, hasNext)
$first = $this->first;
$hasNext = false;
$revisions = $this->getRevisions($first, $hasNext);
// print intro
print p_locale_xhtml('revisions');
// create the form
$form = new Form([
'id' => 'page__revisions',
'class' => 'changes',
]);
$form->addTagOpen('div')->addClass('no');
// start listing
$form->addTagOpen('ul');
foreach ($revisions as $info) {
$rev = $info['date'];
$class = ($info['type'] === DOKU_CHANGE_TYPE_MINOR_EDIT) ? 'minor' : '';
$form->addTagOpen('li')->addClass($class);
$form->addTagOpen('div')->addClass('li');
if (page_exists($id, $rev)) {
$form->addCheckbox('rev2[]')->val($rev);
} else {
$form->addCheckbox('')->val($rev)->attr('disabled','disabled');
}
$form->addHTML(' ');
$objRevInfo = $this->getObjRevInfo($info);
$html = implode(' ', [
$objRevInfo->editDate(), // edit date and time
$objRevInfo->difflink(), // link to diffview icon
$objRevInfo->itemName(), // name of page or media
$objRevInfo->editSummary(), // edit summary
$objRevInfo->editor(), // editor info
$objRevInfo->sizechange(), // size change indicator
$objRevInfo->currentIndicator(), // current indicator (only when k=1)
]);
$form->addHTML($html);
$form->addTagClose('div');
$form->addTagClose('li');
}
$form->addTagClose('ul'); // end of revision list
// show button for diff view
$form->addButton('do[diff]', $lang['diff2'])->attr('type', 'submit');
$form->addTagClose('div'); // close div class=no
print $form->toHTML('Revisions');
// provide navigation for pagenated revision list (of pages and/or media files)
print $this->htmlNavigation($id, $first, $hasNext);
}
/**
* Get revisions, and set correct pagenation parameters (first, hasNext)
* Get revisions, and set correct pagination parameters (first, hasNext)
*
* @param int $first
* @param bool $hasNext
@ -197,81 +44,46 @@ class Revisions extends Ui
*/
protected function getRevisions(&$first, &$hasNext)
{
global $INFO, $conf;
if ($this->media_id) {
$changelog = new MediaChangeLog($this->media_id);
} else {
$changelog = new PageChangeLog($INFO['id']);
}
global $conf;
$changelog =& $this->changelog;
$revisions = [];
$currentRevInfo = $changelog->getCurrentRevisionInfo();
if (!$currentRevInfo) return $revisions;
$num = $conf['recent'];
if ($first == 0) {
// add extrenal or existing last revision that is excluded from $changelog->getRevisions()
if (array_key_exists('timestamp', $currentRevInfo) || (
$currentRevInfo['type'] != DOKU_CHANGE_TYPE_DELETE &&
$currentRevInfo['date'] == $changelog->lastRevision() )
) {
$revisions[] = $currentRevInfo;
$num = $num - 1;
}
}
/* we need to get one additional log entry to be able to
* decide if this is the last page or is there another one.
* see also Ui\Recent::getRecents()
*/
$revlist = $changelog->getRevisions($first, $conf['recent'] +1);
if (count($revlist) == 0 && $first != 0) {
$revlist = $changelog->getRevisions($first, $num + 1);
if (count($revlist) == 0 && $first > 0) {
// resets to zero if $first requested a too high number
$first = 0;
$revlist = $changelog->getRevisions($first, $conf['recent'] +1);
}
$exists = ($this->media_id) ? file_exists(mediaFN($this->media_id)) : $INFO['exists'];
if ($first === 0 && $exists) {
// add current page or media as revision[0]
if ($this->media_id) {
$rev = filemtime(fullpath(mediaFN($this->media_id)));
$changelog->setChunkSize(1024);
$revinfo = $changelog->getRevisionInfo($rev) ?: array(
'date' => $rev,
'ip' => null,
'type' => null,
'id' => $this->media_id,
'user' => null,
'sum' => null,
'extra' => null,
'sizechange' => null,
);
$revisions[] = $revinfo + array(
'media' => true,
'current' => true,
);
} else {
if (isset($INFO['meta']['last_change'])) {
$type = $INFO['meta']['last_change']['type'];
$sizechange = $INFO['meta']['last_change']['sizechange'];
} else {
$type = $sizechange = null;
}
$revisions[] = array(
'date' => $INFO['lastmod'],
'ip' => null,
'type' => $type,
'id' => $INFO['id'],
'user' => $INFO['editor'],
'sum' => $INFO['sum'],
'extra' => null,
'sizechange' => $sizechange,
'current' => true,
);
}
return $this->getRevisions($first, $hasNext);
}
// decide if this is the last page or is there another one
$hasNext = false;
if (count($revlist) > $conf['recent']) {
if (count($revlist) > $num) {
$hasNext = true;
array_pop($revlist); // remove one additional log entry
}
// append each revison info array to the revisions
foreach ($revlist as $rev) {
if ($this->media_id) {
$revisions[] = $changelog->getRevisionInfo($rev) + array('media' => true);
} else {
$revisions[] = $changelog->getRevisionInfo($rev);
}
$revisions[] = $changelog->getRevisionInfo($rev);
}
return $revisions;
}
@ -279,12 +91,12 @@ class Revisions extends Ui
/**
* Navigation buttons for Pagenation (prev/next)
*
* @param string $id page id or media id
* @param int $first
* @param bool $hasNext
* @return array html
* @param callable $callback returns array of hidden fields for the form button
* @return string html
*/
protected function htmlNavigation($id, $first, $hasNext)
protected function navigation($first, $hasNext, $callback)
{
global $conf;
@ -293,20 +105,12 @@ class Revisions extends Ui
if ($first > 0) {
$first = max($first - $conf['recent'], 0);
$html.= '<div class="pagenav-prev">';
if ($this->media_id) {
$html.= html_btn('newer', $id, "p", media_managerURL(['first' => $first], '&', false, true));
} else {
$html.= html_btn('newer', $id, "p" ,['do' => 'revisions', 'first' => $first]);
}
$html.= html_btn('newer', $this->id, "p", $callback($first));
$html.= '</div>';
}
if ($hasNext) {
$html.= '<div class="pagenav-next">';
if ($this->media_id) {
$html.= html_btn('older', $id, "n", media_managerURL(['first' => $last], '&', false, true));
} else {
$html.= html_btn('older', $id, "n", ['do' => 'revisions', 'first' => $last]);
}
$html.= html_btn('older', $this->id, "n", $callback($last));
$html.= '</div>';
}
$html.= '</div>';
@ -319,7 +123,7 @@ class Revisions extends Ui
* @param array $info Revision info structure of a page or media file
* @return objRevInfo object (anonymous class)
*/
protected function getObjRevInfo(array $info)
public function getObjRevInfo(array $info)
{
return new class ($info) // anonymous class (objRevInfo)
{
@ -327,9 +131,10 @@ class Revisions extends Ui
public function __construct(array $info)
{
if (!isset($info['current'])) {
$info['current'] = false;
}
$info['item'] = strrpos($info['id'], '.') ? 'media' : 'page';
$info['current'] = $info['current'] ?? false;
// revision info may have timestamp key when external edits occurred
$info['timestamp'] = $info['timestamp'] ?? true;
$this->info = $info;
}
@ -343,7 +148,13 @@ class Revisions extends Ui
// edit date and time of the page or media file
public function editDate()
{
return '<span class="date">'. dformat($this->info['date']) .'</span>';
global $lang;
$date = dformat($this->info['date']);
if ($this->info['timestamp'] === false) {
// externally deleted or older file restored
$date = preg_replace('/[0-9a-zA-Z]/','_', $date);
}
return '<span class="date">'. $date .'</span>';
}
// edit summary
@ -377,30 +188,34 @@ class Revisions extends Ui
$id = $this->info['id'];
$rev = $this->info['date'];
if (isset($this->info['media'])) {
// media file revision
if (isset($this->info['current'])) {
$href = media_managerURL(['image'=> $id, 'tab_details'=> 'view'], '&');
$html = '<a href="'.$href.'" class="wikilink1">'.$id.'</a>';
} elseif (file_exists(mediaFN($id, $rev))) {
$href = media_managerURL(['image'=> $id, 'tab_details'=> 'view', 'rev'=> $rev], '&');
$html = '<a href="'.$href.'" class="wikilink1">'.$id.'</a>';
} else {
$html = $id;
}
return $html;
} else {
// page revision
$display_name = useHeading('navigation') ? hsc(p_get_first_heading($id)) : $id;
if (!$display_name) $display_name = $id;
if ($this->info['current'] || page_exists($id, $rev)) {
$href = wl($id, "rev=$rev", false, '&');
$html = '<a href="'.$href.'" class="wikilink1">'.$display_name.'</a>';
} else {
$html = $display_name;
}
return $html;
switch ($this->info['item']) {
case 'media': // media file revision
if ($this->info['current']) {
$href = media_managerURL(['image'=> $id, 'tab_details'=> 'view'], '&');
$html = '<a href="'.$href.'" class="wikilink1">'.$id.'</a>';
} elseif (file_exists(mediaFN($id, $rev))) {
$href = media_managerURL(['image'=> $id, 'tab_details'=> 'view', 'rev'=> $rev], '&');
$html = '<a href="'.$href.'" class="wikilink1">'.$id.'</a>';
} else {
$html = $id;
}
return $html;
case 'page': // page revision
$display_name = useHeading('navigation') ? hsc(p_get_first_heading($id)) : $id;
if (!$display_name) $display_name = $id;
if ($this->info['type'] == DOKU_CHANGE_TYPE_DELETE) {
// externally deleted or older file restored
$href = wl($id, "", false, '&');
$html = '<a href="'.$href.'" class="wikilink2">'.$display_name.'</a>';
} elseif ($this->info['current'] || page_exists($id, $rev)) {
$href = wl($id, "rev=$rev", false, '&');
$html = '<a href="'.$href.'" class="wikilink1">'.$display_name.'</a>';
} else {
$html = $display_name;
}
return $html;
}
return '';
}
// icon difflink
@ -410,31 +225,31 @@ class Revisions extends Ui
$id = $this->info['id'];
$rev = $this->info['date'];
if (isset($this->info['media'])) {
// media file revision
if (isset($this->info['current']) || !file_exists(mediaFN($id, $rev))) {
$html = '<img src="'.DOKU_BASE.'lib/images/blank.gif" width="15" height="11" alt="" />';
} else {
$href = media_managerURL(['image'=> $id, 'rev'=> $rev, 'mediado'=>'diff'], '&');
$html = '<a href="'.$href.'" class="diff_link">'
. '<img src="'.DOKU_BASE.'lib/images/diff.png" width="15" height="11"'
. ' title="'. $lang['diff'] .'" alt="'.$lang['diff'] .'" />'
. '</a> ';
}
return $html;
} else {
// page revision
if ($this->info['current'] || !page_exists($id, $rev)) {
$html = '<img src="'.DOKU_BASE.'lib/images/blank.gif" width="15" height="11" alt="" />';
} else {
$href = wl($id, "rev=$rev,do=diff", false, '&');
$html = '<a href="'.$href.'" class="diff_link">'
. '<img src="'.DOKU_BASE.'lib/images/diff.png" width="15" height="11"'
. ' title="'.$lang['diff'].'" alt="'.$lang['diff'].'" />'
. '</a>';
}
return $html;
switch ($this->info['item']) {
case 'media': // media file revision
if ($this->info['current'] || !file_exists(mediaFN($id, $rev))) {
$html = '<img src="'.DOKU_BASE.'lib/images/blank.gif" width="15" height="11" alt="" />';
} else {
$href = media_managerURL(['image'=> $id, 'rev'=> $rev, 'mediado'=>'diff'], '&');
$html = '<a href="'.$href.'" class="diff_link">'
. '<img src="'.DOKU_BASE.'lib/images/diff.png" width="15" height="11"'
. ' title="'. $lang['diff'] .'" alt="'.$lang['diff'] .'" />'
. '</a> ';
}
return $html;
case 'page': // page revision
if ($this->info['current'] || !page_exists($id, $rev)) {
$html = '<img src="'.DOKU_BASE.'lib/images/blank.gif" width="15" height="11" alt="" />';
} else {
$href = wl($id, "rev=$rev,do=diff", false, '&');
$html = '<a href="'.$href.'" class="diff_link">'
. '<img src="'.DOKU_BASE.'lib/images/diff.png" width="15" height="11"'
. ' title="'.$lang['diff'].'" alt="'.$lang['diff'].'" />'
. '</a>';
}
return $html;
}
return '';
}
// size change

View File

@ -56,7 +56,7 @@ function auth_setup() {
if ($auth->success == false) {
// degrade to unauthenticated user
unset($auth);
$auth = null;
auth_logoff();
msg($lang['authtempfail'], -1);
return false;
@ -281,19 +281,23 @@ function auth_login($user, $pass, $sticky = false, $silent = false) {
*
* @author Andreas Gohr <andi@splitbrain.org>
*
* @return string a MD5 sum of various browser headers
* @return string a SHA256 sum of various browser headers
*/
function auth_browseruid() {
/* @var Input $INPUT */
global $INPUT;
$ip = clientIP(true);
$uid = '';
$uid .= $INPUT->server->str('HTTP_USER_AGENT');
$uid .= $INPUT->server->str('HTTP_ACCEPT_CHARSET');
$uid .= substr($ip, 0, strpos($ip, '.'));
$uid = \dokuwiki\Utf8\PhpString::strtolower($uid);
return md5($uid);
$ip = clientIP(true);
// convert IP string to packed binary representation
$pip = inet_pton($ip);
$uid = implode("\n", [
$INPUT->server->str('HTTP_USER_AGENT'),
$INPUT->server->str('HTTP_ACCEPT_LANGUAGE'),
$INPUT->server->str('HTTP_ACCEPT_ENCODING'),
substr($pip, 0, strlen($pip) / 2), // use half of the IP address (works for both IPv4 and IPv6)
]);
return hash('sha256', $uid);
}
/**

View File

@ -6,6 +6,9 @@
* @author Andreas Gohr <andi@splitbrain.org>
*/
use dokuwiki\ChangeLog\ChangeLog;
use dokuwiki\File\PageFile;
/**
* parses a changelog line into it's components
*
@ -15,31 +18,15 @@
* @return array|bool parsed line or false
*/
function parseChangelogLine($line) {
$line = rtrim($line, "\n");
$tmp = explode("\t", $line);
if ($tmp!==false && count($tmp)>1) {
$info = array();
$info['date'] = (int)$tmp[0]; // unix timestamp
$info['ip'] = $tmp[1]; // IPv4 address (127.0.0.1)
$info['type'] = $tmp[2]; // log line type
$info['id'] = $tmp[3]; // page id
$info['user'] = $tmp[4]; // user name
$info['sum'] = $tmp[5]; // edit summary (or action reason)
$info['extra'] = $tmp[6]; // extra data (varies by line type)
if(isset($tmp[7]) && $tmp[7] !== '') { //last item has line-end||
$info['sizechange'] = (int) $tmp[7];
} else {
$info['sizechange'] = null;
}
return $info;
} else {
return false;
}
return ChangeLog::parseLogLine($line);
}
/**
* Adds an entry to the changelog and saves the metadata for the page
*
* Note: timestamp of the change might not be unique especially after very quick
* repeated edits (e.g. change checkbox via do plugin)
*
* @param int $date Timestamp of the change
* @param String $id Name of the affected page
* @param String $type Type of the change see DOKU_CHANGE_TYPE_*
@ -53,79 +40,50 @@ function parseChangelogLine($line) {
* @author Andreas Gohr <andi@splitbrain.org>
* @author Esther Brunner <wikidesign@gmail.com>
* @author Ben Coburn <btcoburn@silicodon.net>
* @deprecated 2021-11-28
*/
function addLogEntry($date, $id, $type=DOKU_CHANGE_TYPE_EDIT, $summary='', $extra='', $flags=null, $sizechange = null){
function addLogEntry(
$date,
$id,
$type = DOKU_CHANGE_TYPE_EDIT,
$summary = '',
$extra = '',
$flags = null,
$sizechange = null)
{
// no more used in DokuWiki core, but left for third-party plugins
dbg_deprecated('see '. \dokuwiki\File\PageFile::class .'::saveWikiText()');
global $conf, $INFO;
/** @var Input $INPUT */
global $INPUT;
// check for special flags as keys
if (!is_array($flags)) { $flags = array(); }
if (!is_array($flags)) $flags = array();
$flagExternalEdit = isset($flags['ExternalEdit']);
$id = cleanid($id);
$file = wikiFN($id);
$created = @filectime($file);
$minor = ($type===DOKU_CHANGE_TYPE_MINOR_EDIT);
$wasRemoved = ($type===DOKU_CHANGE_TYPE_DELETE);
if(!$date) $date = time(); //use current time if none supplied
$remote = (!$flagExternalEdit)?clientIP(true):'127.0.0.1';
$user = (!$flagExternalEdit)?$INPUT->server->str('REMOTE_USER'):'';
if($sizechange === null) {
$sizechange = '';
} else {
$sizechange = (int) $sizechange;
}
if (!$date) $date = time(); //use current time if none supplied
$remote = (!$flagExternalEdit) ? clientIP(true) : '127.0.0.1';
$user = (!$flagExternalEdit) ? $INPUT->server->str('REMOTE_USER') : '';
$sizechange = ($sizechange === null) ? '' : (int)$sizechange;
$strip = array("\t", "\n");
$logline = array(
// update changelog file and get the added entry that is also to be stored in metadata
$pageFile = new PageFile($id);
$logEntry = $pageFile->changelog->addLogEntry([
'date' => $date,
'ip' => $remote,
'type' => str_replace($strip, '', $type),
'type' => $type,
'id' => $id,
'user' => $user,
'sum' => \dokuwiki\Utf8\PhpString::substr(str_replace($strip, '', $summary), 0, 255),
'extra' => str_replace($strip, '', $extra),
'sizechange' => $sizechange
);
'sum' => $summary,
'extra' => $extra,
'sizechange' => $sizechange,
]);
$wasCreated = ($type===DOKU_CHANGE_TYPE_CREATE);
$wasReverted = ($type===DOKU_CHANGE_TYPE_REVERT);
// update metadata
if (!$wasRemoved) {
$oldmeta = p_read_metadata($id)['persistent'];
$meta = array();
if (
$wasCreated && (
empty($oldmeta['date']['created']) ||
$oldmeta['date']['created'] === $created
)
){
// newly created
$meta['date']['created'] = $created;
if ($user){
$meta['creator'] = isset($INFO) ? $INFO['userinfo']['name'] : null;
$meta['user'] = $user;
}
} elseif (($wasCreated || $wasReverted) && !empty($oldmeta['date']['created'])) {
// re-created / restored
$meta['date']['created'] = $oldmeta['date']['created'];
$meta['date']['modified'] = $created; // use the files ctime here
$meta['creator'] = isset($oldmeta['creator']) ? $oldmeta['creator'] : null;
if ($user) $meta['contributor'][$user] = isset($INFO) ? $INFO['userinfo']['name'] : null;
} elseif (!$minor) { // non-minor modification
$meta['date']['modified'] = $date;
if ($user) $meta['contributor'][$user] = isset($INFO) ? $INFO['userinfo']['name'] : null;
}
$meta['last_change'] = $logline;
p_set_metadata($id, $meta);
}
// add changelog lines
$logline = implode("\t", $logline)."\n";
io_saveFile(metaFN($id,'.changes'),$logline,true); //page changelog
io_saveFile($conf['changelog'],$logline,true); //global changelog cache
$pageFile->updateMetadata($logEntry);
}
/**
@ -149,48 +107,42 @@ function addLogEntry($date, $id, $type=DOKU_CHANGE_TYPE_EDIT, $summary='', $extr
function addMediaLogEntry(
$date,
$id,
$type=DOKU_CHANGE_TYPE_EDIT,
$summary='',
$extra='',
$flags=null,
$type = DOKU_CHANGE_TYPE_EDIT,
$summary = '',
$extra = '',
$flags = null,
$sizechange = null)
{
global $conf;
/** @var Input $INPUT */
global $INPUT;
// check for special flags as keys
if (!is_array($flags)) $flags = array();
$flagExternalEdit = isset($flags['ExternalEdit']);
$id = cleanid($id);
if(!$date) $date = time(); //use current time if none supplied
$remote = clientIP(true);
$user = $INPUT->server->str('REMOTE_USER');
if($sizechange === null) {
$sizechange = '';
} else {
$sizechange = (int) $sizechange;
}
if (!$date) $date = time(); //use current time if none supplied
$remote = (!$flagExternalEdit) ? clientIP(true) : '127.0.0.1';
$user = (!$flagExternalEdit) ? $INPUT->server->str('REMOTE_USER') : '';
$sizechange = ($sizechange === null) ? '' : (int)$sizechange;
$strip = array("\t", "\n");
$logline = array(
// update changelog file and get the added entry
$logEntry = (new MediaChangeLog($id, 1024))->addLogEntry([
'date' => $date,
'ip' => $remote,
'type' => str_replace($strip, '', $type),
'type' => $type,
'id' => $id,
'user' => $user,
'sum' => \dokuwiki\Utf8\PhpString::substr(str_replace($strip, '', $summary), 0, 255),
'extra' => str_replace($strip, '', $extra),
'sizechange' => $sizechange
);
// add changelog lines
$logline = implode("\t", $logline)."\n";
io_saveFile($conf['media_changelog'],$logline,true); //global media changelog cache
io_saveFile(mediaMetaFN($id,'.changes'),$logline,true); //media file's changelog
'sum' => $summary,
'extra' => $extra,
'sizechange' => $sizechange,
]);
}
/**
* returns an array of recently changed files using the
* changelog
* returns an array of recently changed files using the changelog
*
* The following constants can be used to control which changes are
* included. Add them together as needed.
@ -211,12 +163,12 @@ function addMediaLogEntry(
* @author Ben Coburn <btcoburn@silicodon.net>
* @author Kate Arzamastseva <pshns@ukr.net>
*/
function getRecents($first,$num,$ns='',$flags=0){
function getRecents($first, $num, $ns = '', $flags = 0) {
global $conf;
$recent = array();
$count = 0;
if(!$num)
if (!$num)
return $recent;
// read all recent changes. (kept short)
@ -228,7 +180,7 @@ function getRecents($first,$num,$ns='',$flags=0){
if (!is_array($lines)) {
$lines = array();
}
$lines_position = count($lines)-1;
$lines_position = count($lines) - 1;
$media_lines_position = 0;
$media_lines = array();
@ -237,13 +189,13 @@ function getRecents($first,$num,$ns='',$flags=0){
if (!is_array($media_lines)) {
$media_lines = array();
}
$media_lines_position = count($media_lines)-1;
$media_lines_position = count($media_lines) - 1;
}
$seen = array(); // caches seen lines, _handleRecent() skips them
// handle lines
while ($lines_position >= 0 || (($flags & RECENTS_MEDIA_PAGES_MIXED) && $media_lines_position >=0)) {
while ($lines_position >= 0 || (($flags & RECENTS_MEDIA_PAGES_MIXED) && $media_lines_position >= 0)) {
if (empty($rec) && $lines_position >= 0) {
$rec = _handleRecent(@$lines[$lines_position], $ns, $flags, $seen);
if (!$rec) {
@ -274,11 +226,11 @@ function getRecents($first,$num,$ns='',$flags=0){
if ($flags & RECENTS_MEDIA_CHANGES) $x['media'] = true;
$rec = false;
}
if(--$first >= 0) continue; // skip first entries
if (--$first >= 0) continue; // skip first entries
$recent[] = $x;
$count++;
// break when we have enough entries
if($count >= $num){ break; }
if ($count >= $num) { break; }
}
return $recent;
}
@ -305,11 +257,11 @@ function getRecents($first,$num,$ns='',$flags=0){
* @author Michael Hamann <michael@content-space.de>
* @author Ben Coburn <btcoburn@silicodon.net>
*/
function getRecentsSince($from,$to=null,$ns='',$flags=0){
function getRecentsSince($from, $to = null, $ns = '', $flags = 0) {
global $conf;
$recent = array();
if($to && $to < $from)
if ($to && $to < $from)
return $recent;
// read all recent changes. (kept short)
@ -318,7 +270,7 @@ function getRecentsSince($from,$to=null,$ns='',$flags=0){
} else {
$lines = @file($conf['changelog']);
}
if(!$lines) return $recent;
if (!$lines) return $recent;
// we start searching at the end of the list
$lines = array_reverse($lines);
@ -326,9 +278,9 @@ function getRecentsSince($from,$to=null,$ns='',$flags=0){
// handle lines
$seen = array(); // caches seen lines, _handleRecent() skips them
foreach($lines as $line){
foreach ($lines as $line) {
$rec = _handleRecent($line, $ns, $flags, $seen);
if($rec !== false) {
if ($rec !== false) {
if ($rec['date'] >= $from) {
if (!$to || $rec['date'] <= $to) {
$recent[] = $rec;
@ -357,30 +309,30 @@ function getRecentsSince($from,$to=null,$ns='',$flags=0){
* @param array $seen listing of seen pages
* @return array|bool false or array with info about a change
*/
function _handleRecent($line,$ns,$flags,&$seen){
if(empty($line)) return false; //skip empty lines
function _handleRecent($line, $ns, $flags, &$seen) {
if (empty($line)) return false; //skip empty lines
// split the line into parts
$recent = parseChangelogLine($line);
if ($recent===false) { return false; }
$recent = ChangeLog::parseLogLine($line);
if ($recent === false) return false;
// skip seen ones
if(isset($seen[$recent['id']])) return false;
if (isset($seen[$recent['id']])) return false;
// skip changes, of only new items are requested
if($recent['type']!==DOKU_CHANGE_TYPE_CREATE && ($flags & RECENTS_ONLY_CREATION)) return false;
if ($recent['type'] !== DOKU_CHANGE_TYPE_CREATE && ($flags & RECENTS_ONLY_CREATION)) return false;
// skip minors
if($recent['type']===DOKU_CHANGE_TYPE_MINOR_EDIT && ($flags & RECENTS_SKIP_MINORS)) return false;
if ($recent['type'] === DOKU_CHANGE_TYPE_MINOR_EDIT && ($flags & RECENTS_SKIP_MINORS)) return false;
// remember in seen to skip additional sights
$seen[$recent['id']] = 1;
// check if it's a hidden page
if(isHiddenPage($recent['id'])) return false;
if (isHiddenPage($recent['id'])) return false;
// filter namespace
if (($ns) && (strpos($recent['id'],$ns.':') !== 0)) return false;
if (($ns) && (strpos($recent['id'], $ns.':') !== 0)) return false;
// exclude subnamespaces
if (($flags & RECENTS_SKIP_SUBSPACES) && (getNS($recent['id']) != $ns)) return false;
@ -394,10 +346,11 @@ function _handleRecent($line,$ns,$flags,&$seen){
if ($recent['perms'] < AUTH_READ) return false;
// check existance
if($flags & RECENTS_SKIP_DELETED){
if ($flags & RECENTS_SKIP_DELETED) {
$fn = (($flags & RECENTS_MEDIA_CHANGES) ? mediaFN($recent['id']) : wikiFN($recent['id']));
if(!file_exists($fn)) return false;
if (!file_exists($fn)) return false;
}
return $recent;
}

View File

@ -9,6 +9,8 @@
use dokuwiki\Cache\CacheInstructions;
use dokuwiki\Cache\CacheRenderer;
use dokuwiki\ChangeLog\PageChangeLog;
use dokuwiki\File\PageFile;
use dokuwiki\Logger;
use dokuwiki\Subscriptions\PageSubscriptionSender;
use dokuwiki\Subscriptions\SubscriberManager;
use dokuwiki\Extension\AuthPlugin;
@ -166,7 +168,7 @@ function basicinfo($id, $htmlClient=true){
}
// if some outside auth were used only REMOTE_USER is set
if(!$info['userinfo']['name']) {
if(empty($info['userinfo']['name'])) {
$info['userinfo']['name'] = $INPUT->server->str('REMOTE_USER');
}
@ -215,11 +217,12 @@ function pageinfo() {
$info['filepath'] = wikiFN($ID);
$info['exists'] = file_exists($info['filepath']);
$info['currentrev'] = @filemtime($info['filepath']);
if($REV) {
if ($REV) {
//check if current revision was meant
if($info['exists'] && ($info['currentrev'] == $REV)) {
if ($info['exists'] && ($info['currentrev'] == $REV)) {
$REV = '';
} elseif($RANGE) {
} elseif ($RANGE) {
//section editing does not work with old revisions!
$REV = '';
$RANGE = '';
@ -231,9 +234,8 @@ function pageinfo() {
}
}
$info['rev'] = $REV;
if($info['exists']) {
$info['writable'] = (is_writable($info['filepath']) &&
($info['perm'] >= AUTH_EDIT));
if ($info['exists']) {
$info['writable'] = (is_writable($info['filepath']) && $info['perm'] >= AUTH_EDIT);
} else {
$info['writable'] = ($info['perm'] >= AUTH_CREATE);
}
@ -245,41 +247,37 @@ function pageinfo() {
//who's the editor
$pagelog = new PageChangeLog($ID, 1024);
if($REV) {
if ($REV) {
$revinfo = $pagelog->getRevisionInfo($REV);
} else {
if(!empty($info['meta']['last_change']) && is_array($info['meta']['last_change'])) {
if (!empty($info['meta']['last_change']) && is_array($info['meta']['last_change'])) {
$revinfo = $info['meta']['last_change'];
} else {
$revinfo = $pagelog->getRevisionInfo($info['lastmod']);
// cache most recent changelog line in metadata if missing and still valid
if($revinfo !== false) {
if ($revinfo !== false) {
$info['meta']['last_change'] = $revinfo;
p_set_metadata($ID, array('last_change' => $revinfo));
}
}
}
//and check for an external edit
if($revinfo !== false && $revinfo['date'] != $info['lastmod']) {
if ($revinfo !== false && $revinfo['date'] != $info['lastmod']) {
// cached changelog line no longer valid
$revinfo = false;
$info['meta']['last_change'] = $revinfo;
p_set_metadata($ID, array('last_change' => $revinfo));
}
if($revinfo !== false){
if ($revinfo !== false) {
$info['ip'] = $revinfo['ip'];
$info['user'] = $revinfo['user'];
$info['sum'] = $revinfo['sum'];
// See also $INFO['meta']['last_change'] which is the most recent log line for page $ID.
// Use $INFO['meta']['last_change']['type']===DOKU_CHANGE_TYPE_MINOR_EDIT in place of $info['minor'].
if($revinfo['user']) {
$info['editor'] = $revinfo['user'];
} else {
$info['editor'] = $revinfo['ip'];
}
}else{
$info['editor'] = $revinfo['user'] ?: $revinfo['ip'];
} else {
$info['ip'] = null;
$info['user'] = null;
$info['sum'] = null;
@ -317,7 +315,7 @@ function jsinfo() {
*
* @return array with info about current media item
*/
function mediainfo(){
function mediainfo() {
global $NS;
global $IMG;
@ -790,36 +788,12 @@ function clientIP($single = false) {
$ip = array_merge($ip, explode(',', str_replace(' ', '', $INPUT->server->str('HTTP_X_REAL_IP'))));
}
// some IPv4/v6 regexps borrowed from Feyd
// see: http://forums.devnetwork.net/viewtopic.php?f=38&t=53479
$dec_octet = '(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|[0-9])';
$hex_digit = '[A-Fa-f0-9]';
$h16 = "{$hex_digit}{1,4}";
$IPv4Address = "$dec_octet\\.$dec_octet\\.$dec_octet\\.$dec_octet";
$ls32 = "(?:$h16:$h16|$IPv4Address)";
$IPv6Address =
"(?:(?:{$IPv4Address})|(?:".
"(?:$h16:){6}$ls32".
"|::(?:$h16:){5}$ls32".
"|(?:$h16)?::(?:$h16:){4}$ls32".
"|(?:(?:$h16:){0,1}$h16)?::(?:$h16:){3}$ls32".
"|(?:(?:$h16:){0,2}$h16)?::(?:$h16:){2}$ls32".
"|(?:(?:$h16:){0,3}$h16)?::(?:$h16:){1}$ls32".
"|(?:(?:$h16:){0,4}$h16)?::$ls32".
"|(?:(?:$h16:){0,5}$h16)?::$h16".
"|(?:(?:$h16:){0,6}$h16)?::".
")(?:\\/(?:12[0-8]|1[0-1][0-9]|[1-9][0-9]|[0-9]))?)";
// remove any non-IP stuff
$cnt = count($ip);
$match = array();
for($i = 0; $i < $cnt; $i++) {
if(preg_match("/^$IPv4Address$/", $ip[$i], $match) || preg_match("/^$IPv6Address$/", $ip[$i], $match)) {
$ip[$i] = $match[0];
} else {
$ip[$i] = '';
if(filter_var($ip[$i], FILTER_VALIDATE_IP) === false) {
unset($ip[$i]);
}
if(empty($ip[$i])) unset($ip[$i]);
}
$ip = array_values(array_unique($ip));
if(empty($ip) || !$ip[0]) $ip[0] = '0.0.0.0'; // for some strange reason we don't have a IP
@ -944,7 +918,7 @@ function checklock($id) {
//my own lock
@list($ip, $session) = explode("\n", io_readFile($lock));
if($ip == $INPUT->server->str('REMOTE_USER') || $ip == clientIP() || (session_id() && $session == session_id())) {
if($ip == $INPUT->server->str('REMOTE_USER') || (session_id() && $session == session_id())) {
return false;
}
@ -990,7 +964,7 @@ function unlock($id) {
$lock = wikiLockFN($id);
if(file_exists($lock)) {
@list($ip, $session) = explode("\n", io_readFile($lock));
if($ip == $INPUT->server->str('REMOTE_USER') || $ip == clientIP() || $session == session_id()) {
if($ip == $INPUT->server->str('REMOTE_USER') || $session == session_id()) {
@unlink($lock);
return true;
}
@ -1268,45 +1242,11 @@ function con($pre, $text, $suf, $pretty = false) {
* wiki, triggered in @see saveWikiText()
*
* @param string $id the page ID
* @deprecated 2021-11-28
*/
function detectExternalEdit($id) {
global $lang;
$fileLastMod = wikiFN($id);
$lastMod = @filemtime($fileLastMod); // from page
$pagelog = new PageChangeLog($id, 1024);
$lastRev = $pagelog->getRevisions(-1, 1); // from changelog
$lastRev = (int) (empty($lastRev) ? 0 : $lastRev[0]);
if(!file_exists(wikiFN($id, $lastMod)) && file_exists($fileLastMod) && $lastMod >= $lastRev) {
// add old revision to the attic if missing
saveOldRevision($id);
// add a changelog entry if this edit came from outside dokuwiki
if($lastMod > $lastRev) {
$fileLastRev = wikiFN($id, $lastRev);
$revinfo = $pagelog->getRevisionInfo($lastRev);
if(empty($lastRev) || !file_exists($fileLastRev) || $revinfo['type'] == DOKU_CHANGE_TYPE_DELETE) {
$filesize_old = 0;
} else {
$filesize_old = io_getSizeFile($fileLastRev);
}
$filesize_new = filesize($fileLastMod);
$sizechange = $filesize_new - $filesize_old;
addLogEntry(
$lastMod,
$id,
DOKU_CHANGE_TYPE_EDIT,
$lang['external_edit'],
'',
array('ExternalEdit' => true),
$sizechange
);
// remove soon to be stale instructions
$cache = new CacheInstructions($id, $fileLastMod);
$cache->removeCache();
}
}
dbg_deprecated(\dokuwiki\File\PageFile::class .'::detectExternalEdit()');
(new PageFile($id))->detectExternalEdit();
}
/**
@ -1322,117 +1262,19 @@ function detectExternalEdit($id) {
* @param bool $minor mark this saved version as minor update
*/
function saveWikiText($id, $text, $summary, $minor = false) {
/* Note to developers:
This code is subtle and delicate. Test the behavior of
the attic and changelog with dokuwiki and external edits
after any changes. External edits change the wiki page
directly without using php or dokuwiki.
*/
global $conf;
global $lang;
global $REV;
/* @var Input $INPUT */
global $INPUT;
// prepare data for event
$svdta = array();
$svdta['id'] = $id;
$svdta['file'] = wikiFN($id);
$svdta['revertFrom'] = $REV;
$svdta['oldRevision'] = @filemtime($svdta['file']);
$svdta['newRevision'] = 0;
$svdta['newContent'] = $text;
$svdta['oldContent'] = rawWiki($id);
$svdta['summary'] = $summary;
$svdta['contentChanged'] = ($svdta['newContent'] != $svdta['oldContent']);
$svdta['changeInfo'] = '';
$svdta['changeType'] = DOKU_CHANGE_TYPE_EDIT;
$svdta['sizechange'] = null;
// select changelog line type
if($REV) {
$svdta['changeType'] = DOKU_CHANGE_TYPE_REVERT;
$svdta['changeInfo'] = $REV;
} else if(!file_exists($svdta['file'])) {
$svdta['changeType'] = DOKU_CHANGE_TYPE_CREATE;
} else if(trim($text) == '') {
// empty or whitespace only content deletes
$svdta['changeType'] = DOKU_CHANGE_TYPE_DELETE;
// autoset summary on deletion
if(blank($svdta['summary'])) {
$svdta['summary'] = $lang['deleted'];
}
} else if($minor && $conf['useacl'] && $INPUT->server->str('REMOTE_USER')) {
//minor edits only for logged in users
$svdta['changeType'] = DOKU_CHANGE_TYPE_MINOR_EDIT;
}
$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)
if(!$svdta['contentChanged']) return;
detectExternalEdit($id);
if(
$svdta['changeType'] == DOKU_CHANGE_TYPE_CREATE ||
($svdta['changeType'] == DOKU_CHANGE_TYPE_REVERT && !file_exists($svdta['file']))
) {
$filesize_old = 0;
} else {
$filesize_old = filesize($svdta['file']);
}
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);
Event::createAndTrigger('IO_WIKIPAGE_WRITE', $data);
// pre-save deleted revision
@touch($svdta['file']);
clearstatcache();
$svdta['newRevision'] = saveOldRevision($id);
// 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...
// purge non-persistant meta data
p_purge_metadata($id);
// remove empty namespaces
io_sweepNS($id, 'datadir');
io_sweepNS($id, 'mediadir');
} else {
// save file (namespace dir is created in io_writeWikiPage)
io_writeWikiPage($svdta['file'], $svdta['newContent'], $id);
// pre-save the revision, to keep the attic in sync
$svdta['newRevision'] = saveOldRevision($id);
$filesize_new = filesize($svdta['file']);
}
$svdta['sizechange'] = $filesize_new - $filesize_old;
$event->advise_after();
addLogEntry(
$svdta['newRevision'],
$svdta['id'],
$svdta['changeType'],
$svdta['summary'],
$svdta['changeInfo'],
null,
$svdta['sizechange']
);
// get COMMON_WIKIPAGE_SAVE event data
$data = (new PageFile($id))->saveWikiText($text, $summary, $minor);
// send notify mails
notify($svdta['id'], 'admin', $svdta['oldRevision'], $svdta['summary'], $minor, $svdta['newRevision']);
notify($svdta['id'], 'subscribers', $svdta['oldRevision'], $svdta['summary'], $minor, $svdta['newRevision']);
// update the purgefile (timestamp of the last time anything within the wiki was changed)
io_saveFile($conf['cachedir'].'/purgefile', time());
list('oldRevision' => $rev, 'newRevision' => $new_rev, 'summary' => $summary) = $data;
notify($id, 'admin', $rev, $summary, $minor, $new_rev);
notify($id, 'subscribers', $rev, $summary, $minor, $new_rev);
// if useheading is enabled, purge the cache of all linking pages
if(useHeading('content')) {
if (useHeading('content')) {
$pages = ft_backlinks($id, true);
foreach($pages as $page) {
foreach ($pages as $page) {
$cache = new CacheRenderer($page, wikiFN($page), 'xhtml');
$cache->removeCache();
}
@ -1440,21 +1282,17 @@ function saveWikiText($id, $text, $summary, $minor = false) {
}
/**
* moves the current version to the attic and returns its
* revision date
* moves the current version to the attic and returns its revision date
*
* @author Andreas Gohr <andi@splitbrain.org>
*
* @param string $id page id
* @return int|string revision timestamp
* @deprecated 2021-11-28
*/
function saveOldRevision($id) {
$oldf = wikiFN($id);
if(!file_exists($oldf)) return '';
$date = filemtime($oldf);
$newf = wikiFN($id, $date);
io_writeWikiPage($newf, rawWiki($id), $id, $date);
return $date;
dbg_deprecated(\dokuwiki\File\PageFile::class .'::saveOldRevision()');
return (new PageFile($id))->saveOldRevision();
}
/**
@ -1462,7 +1300,7 @@ function saveOldRevision($id) {
*
* @param string $id The changed page
* @param string $who Who to notify (admin|subscribers|register)
* @param int|string $rev Old page revision
* @param int|string $rev Old page revision
* @param string $summary What changed
* @param boolean $minor Is this a minor edit?
* @param string[] $replace Additional string substitutions, @KEY@ to be replaced by value
@ -1477,20 +1315,20 @@ function notify($id, $who, $rev = '', $summary = '', $minor = false, $replace =
global $INPUT;
// decide if there is something to do, eg. whom to mail
if($who == 'admin') {
if(empty($conf['notify'])) return false; //notify enabled?
if ($who == 'admin') {
if (empty($conf['notify'])) return false; //notify enabled?
$tpl = 'mailtext';
$to = $conf['notify'];
} elseif($who == 'subscribers') {
if(!actionOK('subscribe')) return false; //subscribers enabled?
if($conf['useacl'] && $INPUT->server->str('REMOTE_USER') && $minor) return false; //skip minors
} elseif ($who == 'subscribers') {
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);
Event::createAndTrigger(
'COMMON_NOTIFY_ADDRESSLIST', $data,
array(new SubscriberManager(), 'notifyAddresses')
);
$to = $data['addresslist'];
if(empty($to)) return false;
if (empty($to)) return false;
$tpl = 'subscr_single';
} else {
return false; //just to be safe

View File

@ -297,12 +297,17 @@ function html_locked() {
* @author Kate Arzamastseva <pshns@ukr.net>
*
* @param int $first skip the first n changelog lines
* @param bool|string $media_id id of media, or false for current page
* @param string $media_id id of media, or empty for current page
* @deprecated 2020-07-18
*/
function html_revisions($first=0, $media_id = false) {
dbg_deprecated(\dokuwiki\Ui\Revisions::class .'::show()');
(new dokuwiki\Ui\Revisions($first, $media_id))->show();
function html_revisions($first = 0, $media_id = '') {
dbg_deprecated(\dokuwiki\Ui\PageRevisions::class .'::show()');
if ($media_id) {
(new dokuwiki\Ui\MediaRevisions($media_id))->show($first);
} else {
global $INFO;
(new dokuwiki\Ui\PageRevisions($INFO['id']))->show($first);
}
}
/**
@ -494,7 +499,7 @@ function html_backlinks() {
* @deprecated 2020-07-18
*/
function html_diff_head($l_rev, $r_rev, $id = null, $media = false, $inline = false) {
dbg_deprecated('see '. \dokuwiki\Ui\Diff::class .'::diffHead()');
dbg_deprecated('see '. \dokuwiki\Ui\PageDiff::class .'::buildDiffHead()');
}
/**
@ -509,8 +514,12 @@ function html_diff_head($l_rev, $r_rev, $id = null, $media = false, $inline = fa
* @deprecated 2020-07-18
*/
function html_diff($text = '', $intro = true, $type = null) {
dbg_deprecated(\dokuwiki\Ui\Diff::class .'::show()');
(new dokuwiki\Ui\Diff($text, $intro, $type))->show();
dbg_deprecated(\dokuwiki\Ui\PageDiff::class .'::show()');
global $INFO;
(new dokuwiki\Ui\PageDiff($INFO['id']))->compareWith($text)->preference([
'showIntro' => $intro,
'difftype' => $type,
])->show();
}
/**
@ -524,7 +533,7 @@ function html_diff($text = '', $intro = true, $type = null) {
* @deprecated 2020-07-18
*/
function html_diff_navigation($pagelog, $type, $l_rev, $r_rev) {
dbg_deprecated('see '. \dokuwiki\Ui\Diff::class .'::diffNavigation()');
dbg_deprecated('see '. \dokuwiki\Ui\PageDiff::class .'::buildRevisionsNavigation()');
}
/**
@ -538,7 +547,7 @@ function html_diff_navigation($pagelog, $type, $l_rev, $r_rev) {
* @deprecated 2020-07-18
*/
function html_diff_navigationlink($difftype, $linktype, $lrev, $rrev = null) {
dbg_deprecated('see '. \dokuwiki\Ui\Diff::class .'::diffViewlink()');
dbg_deprecated('see '. \dokuwiki\Ui\PageDiff::class .'::diffViewlink()');
}
/**
@ -549,8 +558,8 @@ function html_diff_navigationlink($difftype, $linktype, $lrev, $rrev = null) {
* @deprecated 2020-07-18
*/
function html_insert_softbreaks($diffhtml) {
dbg_deprecated(\dokuwiki\Ui\Diff::class .'::insertSoftbreaks()');
return (new dokuwiki\Ui\Diff())->insertSoftbreaks($diffhtml);
dbg_deprecated(\dokuwiki\Ui\PageDiff::class .'::insertSoftbreaks()');
return (new dokuwiki\Ui\PageDiff)->insertSoftbreaks($diffhtml);
}
/**
@ -563,8 +572,8 @@ function html_insert_softbreaks($diffhtml) {
* @deprecated 2020-07-18
*/
function html_conflict($text, $summary) {
dbg_deprecated(\dokuwiki\Ui\Conflict::class .'::show()');
(new dokuwiki\Ui\Conflict($text, $summary))->show();
dbg_deprecated(\dokuwiki\Ui\PageConflict::class .'::show()');
(new dokuwiki\Ui\PageConflict($text, $summary))->show();
}
/**

View File

@ -213,7 +213,7 @@ $lang['created'] = 'اُنشئت';
$lang['restored'] = 'استعيدت نسخة قديمة (%s)';
$lang['external_edit'] = 'تحرير خارجي';
$lang['summary'] = 'ملخص التحرير';
$lang['noflash'] = 'تحتاج إلى<a href="http://www.adobe.com/products/flashplayer/">ملحق فلاش أدوبي</a> لعرض هذا المحتوى.';
$lang['noflash'] = 'تحتاج إلى<a href="http://get.adobe.com/flashplayer">ملحق فلاش أدوبي</a> لعرض هذا المحتوى.';
$lang['download'] = 'نزل Snippet';
$lang['tools'] = 'أدوات';
$lang['user_tools'] = 'أدوات المستخدم';
@ -294,7 +294,7 @@ $lang['i_enableacl'] = 'تفعيل ACL - مفضل';
$lang['i_superuser'] = 'مشرف';
$lang['i_problems'] = 'وجد برنامج التنصيب المشاكل التالية، لا يمكنك المتابعة قبل حلها.';
$lang['i_modified'] = 'لأسباب أمنية هذا البرنامج سيعمل فقط مع تنصيب دوكو ويكي جديد و غير معدّل.
يجب أن تعيد فك ضغط الملفات مرة أخرى من المكتبة المضغوطة، أو راجع <a href="http://dokuwiki.org/install"> تعليمات تنصيب دوكو ويكي </a> ';
يجب أن تعيد فك ضغط الملفات مرة أخرى من المكتبة المضغوطة، أو راجع <a href="https://www.dokuwiki.org/install"> تعليمات تنصيب دوكو ويكي </a> ';
$lang['i_funcna'] = 'دالة PHP التالية غير متوفرة.
<code>%s</code>
قد يكون مزود خدمة الاستفادة قد حجبها لسبب ما.';

View File

@ -151,7 +151,7 @@ $lang['created'] = 'yaranıb';
$lang['restored'] = 'köhnə versiya qaytarıldı (%s)';
$lang['external_edit'] = 'bayırdan dəyişik';
$lang['summary'] = 'Dəyişiklər xülasəsi';
$lang['noflash'] = 'Bu məzmuna baxmaq üçün <a href="http://www.adobe.com/products/flashplayer/">Adobe Flash Plugin</a> tələb olunur.';
$lang['noflash'] = 'Bu məzmuna baxmaq üçün <a href="http://get.adobe.com/flashplayer">Adobe Flash Plugin</a> tələb olunur.';
$lang['download'] = 'Kodu yüklə';
$lang['mail_newpage'] = 'səhifə əlavə olundu:';
$lang['mail_changed'] = 'səhifəyə düzəliş edildi:';
@ -203,7 +203,7 @@ $lang['i_enableacl'] = 'Haqlar kontrolu siyahısının istifadəsinə
$lang['i_superuser'] = 'Super-istifadəci';
$lang['i_problems'] = 'Quraşdırma proqramı aşağıdakı problemlər ilə üzləşdi. Davam etmək üçün onları həll etmək lazımdır. ';
$lang['i_modified'] = 'Təhlükəsizlik baxımından bu proqram ancaq yeni, dəyişməmiş halda olan DokuWiki üzərində işləyir.
Siz ya yüklənmiş quraşdırma paketini yenidən açmalısınız, ya da <a href="http://dokuwiki.org/install">DokuWiki-nin tam quraşdırma instruksiyasına</a> müraciyət etməlisiniz';
Siz ya yüklənmiş quraşdırma paketini yenidən açmalısınız, ya da <a href="https://www.dokuwiki.org/install">DokuWiki-nin tam quraşdırma instruksiyasına</a> müraciyət etməlisiniz';
$lang['i_funcna'] = 'PHP-nin <code>%s</code> funksiyası mövcud deyil. Bəlkə, o hansı sa səbəbdən sizin host-unuz tərəfindən blok edilib?';
$lang['i_phpver'] = 'Sizin PHP-nin versiyası (<code>%s</code>) tələb olunan versiyadan aşagıdır (<code>%s</code>). Quraşdırılmış PHP-nin versiyasını yeniləyin.';
$lang['i_permfail'] = '<code>%s</code> DokuWiki-yə yazı üçün bağlıdır. Bu qovluğun giriş haqlarını yoxlamaq lazımdır!';

View File

@ -209,7 +209,7 @@ $lang['created'] = 'створана';
$lang['restored'] = 'старая версія адноўлена (%s)';
$lang['external_edit'] = 'знешняе змена';
$lang['summary'] = 'Зводка змяненняў';
$lang['noflash'] = 'Для прагляду змесціва гэтага патрабуецца <a href="http://www.adobe.com/products/flashplayer/">Adobe Flash Plugin</a>.';
$lang['noflash'] = 'Для прагляду змесціва гэтага патрабуецца <a href="http://get.adobe.com/flashplayer">Adobe Flash Plugin</a>.';
$lang['download'] = 'Спампаваць фрагмент кода';
$lang['tools'] = 'Інструменты';
$lang['user_tools'] = 'Інструменты карыстальніка';

View File

@ -203,7 +203,7 @@ $lang['created'] = 'създадена';
$lang['restored'] = 'възстановена предишна версия (%s)';
$lang['external_edit'] = 'външна редакция';
$lang['summary'] = 'Обобщение';
$lang['noflash'] = 'Необходим е <a href="http://www.adobe.com/products/flashplayer/">Adobe Flash Plugin</a> за изобразяване на съдържанието.';
$lang['noflash'] = 'Необходим е <a href="http://get.adobe.com/flashplayer">Adobe Flash Plugin</a> за изобразяване на съдържанието.';
$lang['download'] = 'Изтегляне на фрагмент';
$lang['tools'] = 'Инструменти';
$lang['user_tools'] = 'Инструменти за потребители';
@ -284,7 +284,7 @@ $lang['i_enableacl'] = 'Ползване на списък за дос
$lang['i_superuser'] = 'Супер потребител';
$lang['i_problems'] = 'Открити са проблеми, които възпрепятстват инсталирането. Ще можете да продължите след като отстраните долуизброените проблеми.';
$lang['i_modified'] = 'Поради мерки за сигурност инсталаторът работи само с нови и непроменени инсталационни файлове.
Трябва да разархивирате отново файловете от сваления архив или да се посъветвате с <a href="http://dokuwiki.org/install">Инструкциите за инсталиране на Dokuwiki</a>.';
Трябва да разархивирате отново файловете от сваления архив или да се посъветвате с <a href="https://www.dokuwiki.org/install">Инструкциите за инсталиране на Dokuwiki</a>.';
$lang['i_funcna'] = 'PHP функцията <code>%s</code> не е достъпна. Може би е забранена от доставчика на хостинг.';
$lang['i_phpver'] = 'Инсталираната версия <code>%s</code> на PHP е по-стара от необходимата <code>%s</code>. Актуализирайте PHP инсталацията.';
$lang['i_mbfuncoverload'] = 'Необходимо е да изключите mbstring.func_overload в php.ini за да може DokuWiki да стартира.';

View File

@ -195,7 +195,7 @@ $lang['created'] = 'তৈরি করা';
$lang['restored'] = 'পুরানো সংস্করণের পুনঃস্থাপন (%s)';
$lang['external_edit'] = 'বাহ্যিক সম্পাদনা';
$lang['summary'] = 'সম্পাদনা সারাংশ';
$lang['noflash'] = 'এ href="http://www.adobe.com/products/flashplayer/"> অ্যাডোবি ফ্ল্যাশ প্লাগইন </a> এই সামগ্রী প্রদর্শন করার জন্য প্রয়োজন হয়.';
$lang['noflash'] = 'এ href="http://get.adobe.com/flashplayer"> অ্যাডোবি ফ্ল্যাশ প্লাগইন </a> এই সামগ্রী প্রদর্শন করার জন্য প্রয়োজন হয়.';
$lang['download'] = 'ডাউনলোড স্নিপেট ';
$lang['tools'] = 'সরঞ্জামসমূহ';
$lang['user_tools'] = 'ব্যবহারকারীর সরঞ্জামসমূহ';

View File

@ -138,7 +138,7 @@ $lang['created'] = 'creat';
$lang['restored'] = 'restaurada l\'última versió (%s)';
$lang['external_edit'] = 'edició externa';
$lang['summary'] = 'Editar sumari';
$lang['noflash'] = 'Necessita el <a href="http://www.adobe.com/products/flashplayer/">plúgin d\'Adobe Flash</a> per a vore este contingut.';
$lang['noflash'] = 'Necessita el <a href="http://get.adobe.com/flashplayer">plúgin d\'Adobe Flash</a> per a vore este contingut.';
$lang['download'] = 'Descarregar un tros';
$lang['mail_newpage'] = 'pàgina afegida:';
$lang['mail_changed'] = 'pàgina canviada:';
@ -192,7 +192,7 @@ $lang['i_superuser'] = 'Super-usuari';
$lang['i_problems'] = 'L\'instalador ha trobat els problemes mostrats més avall. No pot continuar fins que no els arregle.';
$lang['i_modified'] = 'Per raons de seguritat, este procés només funcionarà en una instalació nova i verge de DokuWiki.
Deuria tornar a extraure els archius del paquet que ha descarregat o consultar les
<a href="http://dokuwiki.org/install">instruccions d\'instalació de Dokuwiki</a> completes';
<a href="https://www.dokuwiki.org/install">instruccions d\'instalació de Dokuwiki</a> completes';
$lang['i_funcna'] = 'La funció de PHP <code>%s</code> no està disponible. ¿Pot ser que el seu proveïdor d\'hostage l\'haja desactivada per algun motiu?';
$lang['i_phpver'] = 'La versió de PHP <code>%s</code> és menor que
la <code>%s</code> que es necessita. Necessita actualitzar PHP.';

View File

@ -219,7 +219,7 @@ $lang['created'] = 'creat';
$lang['restored'] = 's\'ha restaurat una versió anterior %s';
$lang['external_edit'] = 'edició externa';
$lang['summary'] = 'Resum d\'edició';
$lang['noflash'] = 'Per a visualitzar aquest contingut necessiteu el <a href="http://www.adobe.com/products/flashplayer/">connector d\'Adobe Flash</a>.';
$lang['noflash'] = 'Per a visualitzar aquest contingut necessiteu el <a href="http://get.adobe.com/flashplayer">connector d\'Adobe Flash</a>.';
$lang['download'] = 'Baixa el fragment';
$lang['tools'] = 'Eines';
$lang['user_tools'] = 'Eines de l\'usuari';
@ -299,7 +299,7 @@ $lang['i_wikiname'] = 'Nom del wiki';
$lang['i_enableacl'] = 'Habilita ACL (recomanat)';
$lang['i_superuser'] = 'Superusuari';
$lang['i_problems'] = 'L\'instal·lador ha trobat alguns problemes, que s\'indiquen més avall. No podeu continuar fins que no els hàgiu solucionat.';
$lang['i_modified'] = 'Per raons de seguretat aquesta seqüència només funciona amb una instal·lació nova i no modificada de Dokuwiki. Hauríeu de tornar a baixar el paquet i/o descomprimir-lo o consultar les <a href="http://dokuwiki.org/install">instruccions d\'instal·lació de Dokuwiki</a> completes';
$lang['i_modified'] = 'Per raons de seguretat aquesta seqüència només funciona amb una instal·lació nova i no modificada de Dokuwiki. Hauríeu de tornar a baixar el paquet i/o descomprimir-lo o consultar les <a href="https://www.dokuwiki.org/install">instruccions d\'instal·lació de Dokuwiki</a> completes';
$lang['i_funcna'] = 'La funció PHP <code>%s</code> no està disponible. Potser el vostre proveïdor de serveis l\'ha inhabilitada per alguna raó';
$lang['i_disabled'] = 'El vostre proveïdor l\'ha desactivat.';
$lang['i_phpver'] = 'La vostra versió de PHP <code>%s</code> és inferior a la requerida <code>%s</code>. Necessiteu actualitzar la vostra instal·lació de PHP.';

View File

@ -233,7 +233,7 @@ $lang['created'] = 'vytvořeno';
$lang['restored'] = 'stará verze byla obnovena (%s)';
$lang['external_edit'] = 'upraveno mimo DokuWiki';
$lang['summary'] = 'Komentář k úpravám';
$lang['noflash'] = 'Pro přehrání obsahu potřebujete <a href="http://www.adobe.com/products/flashplayer/">Adobe Flash Plugin</a>.';
$lang['noflash'] = 'Pro přehrání obsahu potřebujete <a href="http://get.adobe.com/flashplayer">Adobe Flash Plugin</a>.';
$lang['download'] = 'Stáhnout snippet';
$lang['tools'] = 'Nástroje';
$lang['user_tools'] = 'Uživatelské nástroje';
@ -313,7 +313,7 @@ $lang['i_wikiname'] = 'Název wiki';
$lang['i_enableacl'] = 'Zapnout ACL (doporučeno)';
$lang['i_superuser'] = 'Správce';
$lang['i_problems'] = 'Instalátor narazil na níže popsané problémy. Nelze pokračovat v instalaci, dokud je neopravíte.';
$lang['i_modified'] = 'Instalátor bude z bezpečnostních důvodů pracovat pouze s čistou a ještě neupravenou instalací DokuWiki. Buď znovu rozbalte soubory z instalačního balíčku, nebo zkuste prostudovat <a href="http://dokuwiki.org/install">instrukce pro instalaci DokuWiki</a>.';
$lang['i_modified'] = 'Instalátor bude z bezpečnostních důvodů pracovat pouze s čistou a ještě neupravenou instalací DokuWiki. Buď znovu rozbalte soubory z instalačního balíčku, nebo zkuste prostudovat <a href="https://www.dokuwiki.org/install">instrukce pro instalaci DokuWiki</a>.';
$lang['i_funcna'] = 'PHP funkce <code>%s</code> není dostupná. Váš webhosting ji možná z nějakého důvodu vypnul.';
$lang['i_disabled'] = 'Bylo zakázáno vaším poskytovatelem.';
$lang['i_funcnmail'] = '<b>Poznámka:</b> Funkce mail() není v PHP dostupná. %s Pokud tento problém přetrvává, zkuste nainstalovat <a href="https://www.dokuwiki.org/plugin:smtp">smtp plugin</a>.';

View File

@ -209,7 +209,7 @@ $lang['created'] = 'crewyd';
$lang['restored'] = 'adferwyd hen adolygiad (%s)';
$lang['external_edit'] = 'golygiad allanol';
$lang['summary'] = 'Crynodeb golygiad';
$lang['noflash'] = 'Mae angen <a href="http://www.adobe.com/products/flashplayer/">Ategyn Adobe Flash</a> i ddangos y cynnwys hwn.';
$lang['noflash'] = 'Mae angen <a href="http://get.adobe.com/flashplayer">Ategyn Adobe Flash</a> i ddangos y cynnwys hwn.';
$lang['download'] = 'Lawrlwytho Darn';
$lang['tools'] = 'Teclynnau';
$lang['user_tools'] = 'Teclynnau Defnyddiwr';
@ -302,7 +302,7 @@ $lang['i_superuser'] = 'Uwchddefnyddiwr';
$lang['i_problems'] = 'Gwnaeth yr arsefydlwr ddod o hyd i broblemau, isod. \'Sdim modd parhau nes i chi eu datrys nhw.';
$lang['i_modified'] = 'Oherwydd rhesymau diogelwch, bydd y sgript hwn dim ond yn gweithio gydag arsefydliad DokuWiki newydd sydd heb ei newid.
Dylech chi naill ai ail-echdynnu\'r ffeiliau o\'r pecyn a lawrlwythwyd neu porwch dros y
<a href="http://dokuwiki.org/install">canllawiau arsefydylu Dokuwiki</a> cyfan';
<a href="https://www.dokuwiki.org/install">canllawiau arsefydylu Dokuwiki</a> cyfan';
$lang['i_funcna'] = 'Swyddogaeth PHP <code>%s</code> ddim ar gael. Posib bod eich gwesteiwr wedi\'i hanalluogi am ryw reswm?';
$lang['i_phpver'] = 'Mae\'ch fersiwn PHP <code>%s</code> yn is na\'r hyn sydd ei angen <code>%s</code>. Mae angen i chi ddiweddaru eich arsefydliad PHP.';
$lang['i_mbfuncoverload'] = 'Mae\'n rhaid analluogi mbstring.func_overload mewn php.ini er mwyn rhedeg DokuWiki.';

View File

@ -227,7 +227,7 @@ $lang['created'] = 'oprettet';
$lang['restored'] = 'gammel revision gendannet (%s)';
$lang['external_edit'] = 'ekstern redigering';
$lang['summary'] = 'Resumé af ændrigner';
$lang['noflash'] = 'Du skal installere <a href="http://www.adobe.com/products/flashplayer/">Adobe Flash Player</a> for at kunne se dette indhold.';
$lang['noflash'] = 'Du skal installere <a href="http://get.adobe.com/flashplayer">Adobe Flash Player</a> for at kunne se dette indhold.';
$lang['download'] = 'Hent kodestykke';
$lang['tools'] = 'Værktøjer';
$lang['user_tools'] = 'Brugerværktøjer';
@ -309,10 +309,10 @@ $lang['i_superuser'] = 'Superbruger';
$lang['i_problems'] = 'Installeren fandt nogle problemer, vist nedenunder. Du kan ikke fortsætte før du har rettet dem.';
$lang['i_modified'] = 'Af sikkerheds hensyn vil dette script kun virke en ny og umodificeret Dokuwiki installation.
Du burde enten gen-udpakke filerne fra den hentede pakke eller tjekke den fuldstændige
<a href="http://dokuwiki.org/install">DokuWiki installations instruktioner</a>';
<a href="https://www.dokuwiki.org/install">DokuWiki installations instruktioner</a>';
$lang['i_funcna'] = 'PHP funtionen <code>%s</code> er ikke tilgængelig. Måske har din udbyder slået det fra af en eller anden grund?';
$lang['i_disabled'] = 'Det er blevet slået fra af din udbyder.';
$lang['i_funcnmail'] = '<b>Bemærk:</b> PHP mail funktionen er ikke tilgængelig. %s Hvis den forbliver utilgængelig, kan du installere <a href="http://dokuwiki.org/plugins/smtp">SMTP udvidelsen</a>.';
$lang['i_funcnmail'] = '<b>Bemærk:</b> PHP mail funktionen er ikke tilgængelig. %s Hvis den forbliver utilgængelig, kan du installere <a href="https://www.dokuwiki.org/plugin:smtp">SMTP udvidelsen</a>.';
$lang['i_phpver'] = 'Din PHP version <code>%s</code> er mindre en den nødvendige <code>%s</code>. Du er nød til at opgradere din PHP installation.';
$lang['i_mbfuncoverload'] = 'mbstring.func_overload skal være deaktiveret i php.ini for at køre DokuWiki.';
$lang['i_urandom'] = 'DokuWiki kan ikke oprette kryptografisk sikre numre til cookies. Du bør måske kontrollere dine open_basedir indstillinger i php.ini for korrekt <code>/dev/urandom</code> adgang.';

View File

@ -234,7 +234,7 @@ $lang['created'] = 'angelegt';
$lang['restored'] = 'alte Version wiederhergestellt (%s)';
$lang['external_edit'] = 'Externe Bearbeitung';
$lang['summary'] = 'Zusammenfassung';
$lang['noflash'] = 'Das <a href="http://www.adobe.com/products/flashplayer/">Adobe Flash Plugin</a> wird benötigt, um diesen Inhalt anzuzeigen.';
$lang['noflash'] = 'Das <a href="http://get.adobe.com/flashplayer">Adobe Flash Plugin</a> wird benötigt, um diesen Inhalt anzuzeigen.';
$lang['download'] = 'Schnipsel herunterladen';
$lang['tools'] = 'Werkzeuge';
$lang['user_tools'] = 'Benutzer-Werkzeuge';
@ -314,7 +314,7 @@ $lang['i_wikiname'] = 'Wiki-Name';
$lang['i_enableacl'] = 'Zugriffskontrolle (ACL) aktivieren (empfohlen)';
$lang['i_superuser'] = 'Benutzername des Administrators';
$lang['i_problems'] = 'Das Installationsprogramm hat unten aufgeführte Probleme festgestellt, die zunächst behoben werden müssen, bevor du mit der Installation fortfahren kannst.';
$lang['i_modified'] = 'Aus Sicherheitsgründen arbeitet dieses Skript nur mit einer neuen bzw. nicht modifizierten DokuWiki-Installation. Du solltest entweder alle Dateien noch einmal frisch installieren oder die <a href="http://dokuwiki.org/install">Dokuwiki-Installationsanleitung</a> konsultieren.';
$lang['i_modified'] = 'Aus Sicherheitsgründen arbeitet dieses Skript nur mit einer neuen bzw. nicht modifizierten DokuWiki-Installation. Du solltest entweder alle Dateien noch einmal frisch installieren oder die <a href="https://www.dokuwiki.org/install">Dokuwiki-Installationsanleitung</a> konsultieren.';
$lang['i_funcna'] = 'Die PHP-Funktion <code>%s</code> ist nicht verfügbar. Unter Umständen wurde sie von deinem Hoster deaktiviert?';
$lang['i_disabled'] = 'Es wurde von deinem Provider deaktiviert.';
$lang['i_funcnmail'] = '<b>Hinweis:</b> Die PHP-Funktion "mail()" ist nicht verfügbar. %s Alternativ kansnt du das <a href="https://www.dokuwiki.org/plugin:smtp">SMTP-Plugin</a> installieren.';

View File

@ -252,7 +252,7 @@ $lang['created'] = 'angelegt';
$lang['restored'] = 'alte Version wiederhergestellt (%s)';
$lang['external_edit'] = 'Externe Bearbeitung';
$lang['summary'] = 'Zusammenfassung';
$lang['noflash'] = 'Das <a href="http://www.adobe.com/products/flashplayer/">Adobe Flash Plugin</a> wird benötigt, um diesen Inhalt anzuzeigen.';
$lang['noflash'] = 'Das <a href="http://get.adobe.com/flashplayer">Adobe Flash Plugin</a> wird benötigt, um diesen Inhalt anzuzeigen.';
$lang['download'] = 'Schnipsel herunterladen';
$lang['tools'] = 'Werkzeuge';
$lang['user_tools'] = 'Benutzer-Werkzeuge';
@ -332,7 +332,7 @@ $lang['i_wikiname'] = 'Wiki-Name';
$lang['i_enableacl'] = 'Zugangskontrolle (ACL) aktivieren (empfohlen)';
$lang['i_superuser'] = 'Benutzername des Administrators';
$lang['i_problems'] = 'Das Installationsprogramm hat unten aufgeführte Probleme festgestellt, die zunächst behoben werden müssen bevor Sie mit der Installation fortfahren können.';
$lang['i_modified'] = 'Aus Sicherheitsgründen arbeitet dieses Skript nur mit einer neuen bzw. nicht modifizierten DokuWiki Installation. Sie sollten entweder alle Dateien noch einmal frisch installieren oder die <a href="http://dokuwiki.org/install">Dokuwiki-Installationsanleitung</a> konsultieren.';
$lang['i_modified'] = 'Aus Sicherheitsgründen arbeitet dieses Skript nur mit einer neuen bzw. nicht modifizierten DokuWiki Installation. Sie sollten entweder alle Dateien noch einmal frisch installieren oder die <a href="https://www.dokuwiki.org/install">Dokuwiki-Installationsanleitung</a> konsultieren.';
$lang['i_funcna'] = 'Die PHP-Funktion <code>%s</code> ist nicht verfügbar. Unter Umständen wurde sie von Ihrem Hoster deaktiviert?';
$lang['i_disabled'] = 'Es wurde von Ihrem Provider deaktiviert.';
$lang['i_funcnmail'] = '<b>Hinweis:</b> Die PHP-Funktion "mail()" ist nicht verfügbar. %s Alternativ können Sie das <a href="https://www.dokuwiki.org/plugin:smtp">SMTP-Plugin</a> installieren.';

View File

@ -222,7 +222,7 @@ $lang['created'] = 'δημιουργήθηκε';
$lang['restored'] = 'παλαιότερη έκδοση επαναφέρθηκε (%s)';
$lang['external_edit'] = 'εξωτερική τροποποίηση';
$lang['summary'] = 'Επεξεργασία σύνοψης';
$lang['noflash'] = 'Το <a href="http://www.adobe.com/products/flashplayer/">Adobe Flash Plugin</a> απαιτείται για την προβολή αυτού του στοιχείου.';
$lang['noflash'] = 'Το <a href="http://get.adobe.com/flashplayer">Adobe Flash Plugin</a> απαιτείται για την προβολή αυτού του στοιχείου.';
$lang['download'] = 'Λήψη Κώδικα';
$lang['tools'] = 'Εργαλεία';
$lang['user_tools'] = 'Εργαλεία Χρήστη';

View File

@ -226,6 +226,7 @@ $lang['created'] = 'created';
$lang['restored'] = 'old revision restored (%s)';
$lang['external_edit'] = 'external edit';
$lang['summary'] = 'Edit summary';
$lang['unknowndate'] = 'Unknown date';
$lang['noflash'] = 'The <a href="http://get.adobe.com/flashplayer">Adobe Flash Plugin</a> is needed to display this content.';
$lang['download'] = 'Download Snippet';
$lang['tools'] = 'Tools';

View File

@ -214,7 +214,7 @@ $lang['created'] = 'kreita';
$lang['restored'] = 'malnova revizio restarigita (%s)';
$lang['external_edit'] = 'ekstera redakto';
$lang['summary'] = 'Bulteno de ŝanĝoj';
$lang['noflash'] = 'La <a href="http://www.adobe.com/products/flashplayer/">Adobe Flash Plugin</a> necesas por montri tiun ĉi enhavon.';
$lang['noflash'] = 'La <a href="http://get.adobe.com/flashplayer">Adobe Flash Plugin</a> necesas por montri tiun ĉi enhavon.';
$lang['download'] = 'Elŝuti eltiraĵon';
$lang['tools'] = 'Iloj';
$lang['user_tools'] = 'Uzantaj iloj';

View File

@ -256,7 +256,7 @@ $lang['created'] = 'creado';
$lang['restored'] = 'se ha restaurado la vieja versión (%s)';
$lang['external_edit'] = 'editor externo';
$lang['summary'] = 'Resumen de la edición';
$lang['noflash'] = 'Para mostrar este contenido es necesario el <a href="http://www.adobe.com/products/flashplayer/">Plugin Adobe Flash</a>.';
$lang['noflash'] = 'Para mostrar este contenido es necesario el <a href="http://get.adobe.com/flashplayer">Plugin Adobe Flash</a>.';
$lang['download'] = 'Descargar trozo de código fuente';
$lang['tools'] = 'Herramientas';
$lang['user_tools'] = 'Herramientas de usuario';
@ -336,10 +336,10 @@ $lang['i_wikiname'] = 'Nombre del wiki';
$lang['i_enableacl'] = 'Habilitar ACL (recomendado) (ACL: lista de control de acceso)';
$lang['i_superuser'] = 'Super-usuario';
$lang['i_problems'] = 'El instalador encontró algunos problemas, se muestran abajo. No se puede continuar la instalación hasta que usted no los corrija.';
$lang['i_modified'] = 'Por razones de seguridad este script sólo funcionará con una instalación nueva y no modificada de Dokuwiki. Usted debe extraer nuevamente los ficheros del paquete bajado, o bien consultar las <a href="http://dokuwiki.org/install">instrucciones de instalación de Dokuwiki</a> completas.';
$lang['i_modified'] = 'Por razones de seguridad este script sólo funcionará con una instalación nueva y no modificada de Dokuwiki. Usted debe extraer nuevamente los ficheros del paquete bajado, o bien consultar las <a href="https://www.dokuwiki.org/install">instrucciones de instalación de Dokuwiki</a> completas.';
$lang['i_funcna'] = 'La función de PHP <code>%s</code> no está disponible. ¿Tal vez su proveedor de hosting la ha deshabilitado por alguna razón?';
$lang['i_disabled'] = 'Ha sido deshabilitado por su proveedor.';
$lang['i_funcnmail'] = '<b>Nota:</b> La función de PHP mail() no está disponible. %s si no está disponible, puede instalar el <a href="http://dokuwiki.org/plugins/smtp">complemento smtp</a>.';
$lang['i_funcnmail'] = '<b>Nota:</b> La función de PHP mail() no está disponible. %s si no está disponible, puede instalar el <a href="https://www.dokuwiki.org/plugin:smtp">complemento smtp</a>.';
$lang['i_phpver'] = 'Su versión de PHP <code>%s</code> es menor que la necesaria <code>%s</code>. Es necesario que actualice su instalación de PHP.';
$lang['i_mbfuncoverload'] = 'mbstring.func_overload se debe deshabilitar en php.ini para que funcione DokuWiki.';
$lang['i_urandom'] = 'DokuWiki no puede crear números criptográficamente seguros para las cookies. Es posible que desee verificar la configuración de open_basedir en php.ini para obtener el acceso apropiado a <code>/dev/urandom</code>.';

View File

@ -195,7 +195,7 @@ $lang['created'] = 'tekitatud';
$lang['restored'] = 'vana versioon taastatud (%s)';
$lang['external_edit'] = 'väline muutmine';
$lang['summary'] = 'kokkuvõte muudatustest';
$lang['noflash'] = 'Sele sisu vaatamisesks on vajalik <a href="http://www.adobe.com/products/flashplayer/">Adobe Flash Laiendus</a>.';
$lang['noflash'] = 'Sele sisu vaatamisesks on vajalik <a href="http://get.adobe.com/flashplayer">Adobe Flash Laiendus</a>.';
$lang['tools'] = 'Tööriistad';
$lang['user_tools'] = 'Kasutaja tarvikud';
$lang['site_tools'] = 'Lehe tööriistad';
@ -276,7 +276,7 @@ $lang['i_enableacl'] = 'Kas lubada kasutajate haldus (soovitatav)';
$lang['i_superuser'] = 'Superkasutaja';
$lang['i_problems'] = 'Paigaldaja leidis mõned vead, mis on allpool välja toodud. Enne vigade eemaldamist ei saa jätkata.';
$lang['i_modified'] = 'Õnnetuste vältimiseks läheb see skript käima ainult värskelt paigaldatud ja muutmata Dokuwiki peal.
Sa peaksid ilmselt kogu koodi uuesti lahti pakkima. Vaata ka <a href="http://dokuwiki.org/install">Dokuwiki installeerimis juhendit</a>';
Sa peaksid ilmselt kogu koodi uuesti lahti pakkima. Vaata ka <a href="https://www.dokuwiki.org/install">Dokuwiki installeerimis juhendit</a>';
$lang['i_funcna'] = 'PHP funktsiooni <code>%s</code> ei ole olemas.võibolla sinu serveri hooldaja on selle mingil põhjusel keelanud?';
$lang['i_phpver'] = 'Sinu PHP versioon <code>%s</code> on vanem nõutavast <code>%s</code>. Pead oma paigaldatud PHP-d uuendama.';
$lang['i_permfail'] = 'Dokuwiki ei saa kirjutada faili <code>%s</code>. Kontrolli serveris failide õigused üle.';

View File

@ -199,7 +199,7 @@ $lang['created'] = 'sortua';
$lang['restored'] = 'bertsio zaharra berrezarria (%s)';
$lang['external_edit'] = 'kanpoko aldaketa';
$lang['summary'] = 'Aldatu laburpena';
$lang['noflash'] = '<a href="http://www.adobe.com/products/flashplayer/">Adobe Flash Plugin</a> beharrezkoa da eduki hau bistaratzeko.';
$lang['noflash'] = '<a href="http://get.adobe.com/flashplayer">Adobe Flash Plugin</a> beharrezkoa da eduki hau bistaratzeko.';
$lang['download'] = 'Deskarga Snippet-a';
$lang['tools'] = 'Tresnak';
$lang['user_tools'] = 'Erabiltzaile Tresnak';
@ -279,7 +279,7 @@ $lang['i_wikiname'] = 'Wiki Izena';
$lang['i_enableacl'] = 'Gaitu ACL (gomendatua) (ACL: Atzipen Kontrol Lista)';
$lang['i_superuser'] = 'Supererabiltzailea';
$lang['i_problems'] = 'Instalatzaileak arazo batzuk aurkitu ditu, behean azalduak. Ezin duzu horiek konpondu arte jarraitu.';
$lang['i_modified'] = 'Segurtasun arrazoiengatik, script hau DokuWikiren instalazio berri eta aldatu gabeko batekin bakarrik dabil. Deskargatutako paketetik fitxategiak berriz atera edo <a href="http://dokuwiki.org/install">DokuWikiren instalazio azalpenak</a> osorik irakurri beharko zenituzke.';
$lang['i_modified'] = 'Segurtasun arrazoiengatik, script hau DokuWikiren instalazio berri eta aldatu gabeko batekin bakarrik dabil. Deskargatutako paketetik fitxategiak berriz atera edo <a href="https://www.dokuwiki.org/install">DokuWikiren instalazio azalpenak</a> osorik irakurri beharko zenituzke.';
$lang['i_funcna'] = 'PHP <code>%s</code> funtzioa ez dago erabilgarri. Agian zure hosting hornitzaileak arrazoiren batengatik ezgaituko zuen?';
$lang['i_phpver'] = 'Zure PHP <code>%s</code> bertsioa behar den <code>%s</code> bertsioa baino zaharragoa da. PHP instalazioa eguneratu beharra daukazu.';
$lang['i_permfail'] = 'DokuWiki ez da <code>%s</code> idazteko gai. Direktorio honen baimenen konfigurazioa konpondu behar duzu!';

View File

@ -225,7 +225,7 @@ $lang['created'] = 'ایجاد شد';
$lang['restored'] = 'یک نگارش پیشین واگردانی شد. (%s)';
$lang['external_edit'] = 'ویرایش خارجی';
$lang['summary'] = 'پیش‌نمایش';
$lang['noflash'] = 'برای نمایش محتویات <a href="http://www.adobe.com/products/flashplayer/">افزونه‌ی فلش</a> مورد نیاز است.';
$lang['noflash'] = 'برای نمایش محتویات <a href="http://get.adobe.com/flashplayer">افزونه‌ی فلش</a> مورد نیاز است.';
$lang['download'] = 'دیافت فایل منقطع گردید';
$lang['tools'] = 'ابزار';
$lang['user_tools'] = 'ابزار کاربر';
@ -305,7 +305,7 @@ $lang['i_wikiname'] = 'نام ویکی';
$lang['i_enableacl'] = 'فعال بودن کنترل دسترسی‌ها (توصیه شده)';
$lang['i_superuser'] = 'کاربر اصلی';
$lang['i_problems'] = 'نصب کننده با مشکلات زیر مواجه شد. در صورت رفع این مشکلات، امکان ادامه نصب خواهد بود.';
$lang['i_modified'] = 'به دلایل امنیتی، این اسکریپت فقط با نصب تازه و بدون تغییر دوکوویکی کار خواهد کرد. شما باید دوباره فایل فشرده را باز کنید <a href="http://dokuwiki.org/install">راهنمای نصب DokuWiki</a> را بررسی کنید.';
$lang['i_modified'] = 'به دلایل امنیتی، این اسکریپت فقط با نصب تازه و بدون تغییر دوکوویکی کار خواهد کرد. شما باید دوباره فایل فشرده را باز کنید <a href="https://www.dokuwiki.org/install">راهنمای نصب DokuWiki</a> را بررسی کنید.';
$lang['i_funcna'] = 'تابع <code>%s</code> در پی‌اچ‌پی موجود نیست. ممکن است شرکت خدمات وب شما آن را مسدود کرده باشد.';
$lang['i_phpver'] = 'نگارش پی‌اچ‌پی <code>%s</code> پایین‌تر از نگارش مورد نیاز، یعنی <code>%s</code> است. خواهشمندیم به روز رسانی کنید.';
$lang['i_mbfuncoverload'] = 'برای اجرای دوکوویکی باید mbstring.func_overload را در php.ini غیرفعال کنید.';

View File

@ -201,7 +201,7 @@ $lang['created'] = 'luotu';
$lang['restored'] = 'vanha versio palautettu (%s)';
$lang['external_edit'] = 'ulkoinen muokkaus';
$lang['summary'] = 'Yhteenveto muokkauksesta';
$lang['noflash'] = 'Tarvitset <a href="http://www.adobe.com/products/flashplayer/">Adobe Flash-liitännäisen</a> nähdäksesi tämän sisällön.';
$lang['noflash'] = 'Tarvitset <a href="http://get.adobe.com/flashplayer">Adobe Flash-liitännäisen</a> nähdäksesi tämän sisällön.';
$lang['download'] = 'Lataa palanen';
$lang['tools'] = 'Työkalut';
$lang['user_tools'] = 'Käyttäjän työkalut';
@ -281,7 +281,7 @@ $lang['i_wikiname'] = 'Wikin nimi';
$lang['i_enableacl'] = 'Käytä käyttöoikeuksien hallintaa (ACL) (Suositeltu)';
$lang['i_superuser'] = 'Pääkäyttäjä';
$lang['i_problems'] = 'Asennusohjelma löysi alla listattuja ongelmia ongelmia. Et voi jatkaa ennen kuin ne on korjattu.';
$lang['i_modified'] = 'Turvallisuussyistä tämä ohjelma toimii vain uusien ja muokkaamattomien Dokuwiki-asennusten kanssa. Pura tiedostot uudestaan asennuspaketista, tai lue <a href="http://dokuwiki.org/install">Dokuwikin asennusohje (englanniksi)</a>';
$lang['i_modified'] = 'Turvallisuussyistä tämä ohjelma toimii vain uusien ja muokkaamattomien Dokuwiki-asennusten kanssa. Pura tiedostot uudestaan asennuspaketista, tai lue <a href="https://www.dokuwiki.org/install">Dokuwikin asennusohje (englanniksi)</a>';
$lang['i_funcna'] = 'PHP:n funktio <code>%s</code> ei ole käytettävissä. Palveluntarjoajasi on saattanut poistaa sen jostain syystä.';
$lang['i_phpver'] = 'Käyttämäsi PHP-ohjelmiston versio <code>%s</code> on pienempi, kuin tarvitaan <code>%s</code>. PHP-asennuksesi pitää päivittää.';
$lang['i_mbfuncoverload'] = 'mbstring.func_overload pitää ottaa pois käytöstä php.ini -tiedostosta käyttääksesi DokuWikiä';

View File

@ -251,7 +251,7 @@ $lang['created'] = 'créée';
$lang['restored'] = 'ancienne révision (%s) restaurée';
$lang['external_edit'] = 'modification externe';
$lang['summary'] = 'Résumé';
$lang['noflash'] = 'L\'<a href="http://www.adobe.com/products/flashplayer/">extension Adobe Flash</a> est nécessaire pour afficher ce contenu.';
$lang['noflash'] = 'L\'<a href="http://get.adobe.com/flashplayer">extension Adobe Flash</a> est nécessaire pour afficher ce contenu.';
$lang['download'] = 'Télécharger cet extrait';
$lang['tools'] = 'Outils';
$lang['user_tools'] = 'Outils pour utilisateurs';
@ -331,10 +331,10 @@ $lang['i_wikiname'] = 'Nom du wiki';
$lang['i_enableacl'] = 'Activer le contrôle d\'accès (recommandé)';
$lang['i_superuser'] = 'Super-utilisateur';
$lang['i_problems'] = 'L\'installateur a détecté les problèmes indiqués ci-dessous. Vous ne pouvez pas poursuivre l\'installation tant qu\'ils n\'auront pas été corrigés.';
$lang['i_modified'] = 'Pour des raisons de sécurité, ce script ne fonctionne qu\'avec une installation neuve et non modifiée de DokuWiki. Vous devriez ré-extraire les fichiers depuis le paquet téléchargé ou consulter les <a href="http://dokuwiki.org/install">instructions d\'installation de DokuWiki</a>';
$lang['i_modified'] = 'Pour des raisons de sécurité, ce script ne fonctionne qu\'avec une installation neuve et non modifiée de DokuWiki. Vous devriez ré-extraire les fichiers depuis le paquet téléchargé ou consulter les <a href="https://www.dokuwiki.org/install">instructions d\'installation de DokuWiki</a>';
$lang['i_funcna'] = 'La fonction PHP <code>%s</code> n\'est pas disponible. Peut-être que votre hébergeur web l\'a désactivée ?';
$lang['i_disabled'] = 'Elle a été désactivée par votre hébergeur';
$lang['i_funcnmail'] = '<b>Note:</b> La fonction PHP mail n\'est pas disponible. %s Si vous ne pouvez pas l\'activer, vous pourriez installer le <a href="http://dokuwiki.org/plugins/smtp">greffon smtp</a>.';
$lang['i_funcnmail'] = '<b>Note:</b> La fonction PHP mail n\'est pas disponible. %s Si vous ne pouvez pas l\'activer, vous pourriez installer le <a href="https://www.dokuwiki.org/plugin:smtp">greffon smtp</a>.';
$lang['i_phpver'] = 'Votre version de PHP (%s) est antérieure à la version requise (%s). Vous devez mettre à jour votre installation de PHP.';
$lang['i_mbfuncoverload'] = 'Il faut désactiver mbstring.func_overload dans php.ini pour DokuWiki';
$lang['i_urandom'] = 'DokuWiki ne peut créer de nombres cryptographiquement sûrs pour les cookies. Vous voudrez peut-être vérifier que le réglage open_basedir dans php.ini permet l\'accès à <code>/dev/urandom</code>.';

View File

@ -182,7 +182,7 @@ $lang['created'] = 'creado';
$lang['restored'] = 'revisión antiga restaurada (%s)';
$lang['external_edit'] = 'edición externa';
$lang['summary'] = 'Resumo da edición';
$lang['noflash'] = 'Precísase o <a href="http://www.adobe.com/products/flashplayer/">Extensión Adobe Flash</a> para amosar este contido.';
$lang['noflash'] = 'Precísase o <a href="http://get.adobe.com/flashplayer">Extensión Adobe Flash</a> para amosar este contido.';
$lang['download'] = 'Descargar Retallo (Snippet)';
$lang['tools'] = 'Ferramentas';
$lang['user_tools'] = 'Ferramentas de usuario';
@ -264,7 +264,7 @@ $lang['i_superuser'] = 'Super-usuario';
$lang['i_problems'] = 'O instalador atopou algúns problemas, que se amosan de seguido. Non poderás continuar até que os soluciones.';
$lang['i_modified'] = 'Por razóns de seguridade este script funcionará cunha instalación nova e sen modificar do Dokuwiki.
Podes ou ben extraer de novo os arquivos dende o paquete descargado ou consultar as
<a href="http://dokuwiki.org/install">instruccións completas de instalación do Dokuwiki</a>';
<a href="https://www.dokuwiki.org/install">instruccións completas de instalación do Dokuwiki</a>';
$lang['i_funcna'] = 'A función <code>%s</code> do PHP non está dispoñíbel. Pode que o teu provedor de hospedaxe a desactivase por algún motivo?';
$lang['i_phpver'] = 'A túa versión <code>%s</code> do PHP é inferior á <code>%s</code> precisa. Debes actualizar a túa instalación do PHP.';
$lang['i_permfail'] = '<code>%s</code> non é escribíbel polo DokuWiki. Debes corrixir a configuración de permisos deste directorio!';

View File

@ -208,7 +208,7 @@ $lang['created'] = 'נוצר';
$lang['restored'] = 'שוחזר (%s)';
$lang['external_edit'] = 'עריכה חיצונית';
$lang['summary'] = 'תקציר העריכה';
$lang['noflash'] = '<a href="http://www.adobe.com/products/flashplayer/">תוסף פלאש לדפדפן</a> נדרש כדי להציג תוכן זה.';
$lang['noflash'] = '<a href="http://get.adobe.com/flashplayer">תוסף פלאש לדפדפן</a> נדרש כדי להציג תוכן זה.';
$lang['download'] = 'הורדת מקטע';
$lang['tools'] = 'כלים';
$lang['user_tools'] = 'כלים של משתמש';
@ -290,7 +290,7 @@ $lang['i_superuser'] = 'משתמש־על';
$lang['i_problems'] = 'תכנית ההתקנה זיהתה מספר בעיות המפורטות להלן. אין באפשרותך להמשיך לפני תיקונן.';
$lang['i_modified'] = 'משיקולי אבטחה סקריפט זה יעבוד אך ורק עם התקנת DokuWiki חדשה שלא עברה כל שינוי.
עליך לחלץ שנית את הקבצים מהחבילה שהורדה או להיעזר בדף
<a href="http://dokuwiki.org/install">Dokuwiki installation instructions</a>';
<a href="https://www.dokuwiki.org/install">Dokuwiki installation instructions</a>';
$lang['i_funcna'] = 'פונקציית ה-PHP&#8207; <code>%s</code> אינה זמינה. יתכן כי מארח האתר חסם אותה מסיבה כלשהי?';
$lang['i_phpver'] = 'גרסת PHP שלך <code>%s</code> נמוכה מ <code>%s</code> הצורך. אתה צריך לשדרג PHP שלך להתקין.';
$lang['i_mbfuncoverload'] = 'יש לבטל את mbstring.func_overload בphp.ini בכדי להריץ את DokuWiki';

View File

@ -214,7 +214,7 @@ $lang['created'] = 'stvoreno';
$lang['restored'] = 'vraćeno na prijašnju izmjenu (%s)';
$lang['external_edit'] = 'vanjsko uređivanje';
$lang['summary'] = 'Sažetak izmjena';
$lang['noflash'] = 'Za prikazivanje ovog sadržaja potreban je <a href="http://www.adobe.com/products/flashplayer/">Adobe Flash Plugin</a>';
$lang['noflash'] = 'Za prikazivanje ovog sadržaja potreban je <a href="http://get.adobe.com/flashplayer">Adobe Flash Plugin</a>';
$lang['download'] = 'Preuzmi isječak';
$lang['tools'] = 'Alati';
$lang['user_tools'] = 'Korisnički alati';
@ -295,7 +295,7 @@ $lang['i_enableacl'] = 'Omogući ACL (preporučeno)';
$lang['i_superuser'] = 'Superkorisnik';
$lang['i_problems'] = 'Instalacija je pronašla probleme koji su naznačeni ispod. Nije moguće nastaviti dok se ti problemi ne riješe.';
$lang['i_modified'] = 'Zbog sigurnosnih razlog, ova skripta raditi će samo sa novim i neizmijenjenim DokuWiki instalacijama.
Molimo ponovno prekopirajte datoteke iz preuzetoga paketa ili pogledajte detaljno <a href="http://dokuwiki.org/install">Uputstvo za postavljanje DokuWiki-a</a>';
Molimo ponovno prekopirajte datoteke iz preuzetoga paketa ili pogledajte detaljno <a href="https://www.dokuwiki.org/install">Uputstvo za postavljanje DokuWiki-a</a>';
$lang['i_funcna'] = 'PHP funkcija <code>%s</code> nije dostupna. Možda ju je vaš pružatelj hostinga onemogućio iz nekog razloga?';
$lang['i_phpver'] = 'Vaša PHP inačica <code>%s</code> je niža od potrebne <code>%s</code>. Trebate nadograditi vašu PHP instalaciju.';
$lang['i_mbfuncoverload'] = 'mbstring.func_overload mora biti onemogućena u php.ini da bi ste pokrenuli DokuWiki.';

View File

@ -205,7 +205,7 @@ $lang['created'] = 'létrehozva';
$lang['restored'] = 'régebbi változat helyreállítva (%s)';
$lang['external_edit'] = 'külső szerkesztés';
$lang['summary'] = 'A változások összefoglalása';
$lang['noflash'] = 'Ennek a tartalomnak a megtekintéséhez <a href="http://www.adobe.com/products/flashplayer/">Adobe Flash Plugin</a> szükséges.';
$lang['noflash'] = 'Ennek a tartalomnak a megtekintéséhez <a href="http://get.adobe.com/flashplayer">Adobe Flash Plugin</a> szükséges.';
$lang['download'] = 'Kódrészlet letöltése';
$lang['tools'] = 'Eszközök';
$lang['user_tools'] = 'Felhasználói eszközök';
@ -286,7 +286,7 @@ $lang['i_enableacl'] = 'Hozzáférési listák engedélyezése (ajánl
$lang['i_superuser'] = 'Adminisztrátor';
$lang['i_problems'] = 'A Beállító Varázsló a következő problémák miatt megakadt. Nem tudjuk folytatni, amíg ezek nincsenek elhárítva!';
$lang['i_modified'] = 'Biztonsági okokból ez a Varázsló csak új és módosítatlan DokuWiki változaton működik.
Csomagold ki újra a fájlokat a letöltött csomagból, vagy nézd meg a teljes <a href="http://dokuwiki.org/install">Dokuwiki telepítési útmutatót</a>.';
Csomagold ki újra a fájlokat a letöltött csomagból, vagy nézd meg a teljes <a href="https://www.dokuwiki.org/install">Dokuwiki telepítési útmutatót</a>.';
$lang['i_funcna'] = 'A <code>%s</code> PHP funkció nem elérhető. Esetleg a tárhelyszolgáltató letiltotta biztonsági okok miatt?';
$lang['i_phpver'] = 'A PHP <code>%s</code> verziója alacsonyabb, mint ami szükséges lenne: <code>%s</code>. Frissítsd a PHP-det újabb verzióra!';
$lang['i_mbfuncoverload'] = 'A DokuWiki futtatásához az mbstring.func_overload opciót ki kell kapcsolni a php.ini-ben.';

View File

@ -164,7 +164,7 @@ $lang['created'] = 'create';
$lang['restored'] = 'ancian version restaurate (%s)';
$lang['external_edit'] = 'modification externe';
$lang['summary'] = 'Modificar summario';
$lang['noflash'] = 'Le <a href="http://www.adobe.com/products/flashplayer/">plug-in Flash de Adobe</a> es necessari pro monstrar iste contento.';
$lang['noflash'] = 'Le <a href="http://get.adobe.com/flashplayer">plug-in Flash de Adobe</a> es necessari pro monstrar iste contento.';
$lang['download'] = 'Discargar fragmento';
$lang['mail_newpage'] = 'pagina addite:';
$lang['mail_changed'] = 'pagina modificate:';
@ -232,7 +232,7 @@ $lang['i_enableacl'] = 'Activar ACL (recommendate)';
$lang['i_superuser'] = 'Superusator';
$lang['i_problems'] = 'Le installator ha trovate alcun problemas, indicate hic infra. Tu debe resolver iste problemas pro poter continuar.';
$lang['i_modified'] = 'Pro motivos de securitate, iste script functiona solmente con un installation de DokuWiki nove e non modificate.
Tu debe re-extraher le files del pacchetto discargate, o consultar le <a href="http://dokuwiki.org/install">instructiones de installation</a> complete pro altere optiones.';
Tu debe re-extraher le files del pacchetto discargate, o consultar le <a href="https://www.dokuwiki.org/install">instructiones de installation</a> complete pro altere optiones.';
$lang['i_funcna'] = 'Le function PHP <code>%s</code> non es disponibile. Pote esser que tu albergo web lo ha disactivate pro un ration o altere.';
$lang['i_phpver'] = 'Le version de PHP <code>%s</code> es plus ancian que le version requisite <code>%s</code>. Es necessari actualisar le installation de PHP.';
$lang['i_permfail'] = '<code>%s</code> non permitte le accesso de scriptura a DokuWiki. Tu debe reparar le permissiones de iste directorio!';

View File

@ -190,7 +190,7 @@ $lang['deleted'] = 'terhapus';
$lang['created'] = 'dibuat';
$lang['restored'] = 'revisi lama ditampilkan kembali (%s)';
$lang['external_edit'] = 'Perubahan eksternal';
$lang['noflash'] = '<a href="http://www.adobe.com/products/flashplayer/">Adobe Flash Plugin</a> diperlukan untuk menampilkan konten ini.';
$lang['noflash'] = '<a href="http://get.adobe.com/flashplayer">Adobe Flash Plugin</a> diperlukan untuk menampilkan konten ini.';
$lang['download'] = 'Unduh Cuplikan';
$lang['tools'] = 'Alat';
$lang['user_tools'] = 'Alat Pengguna';
@ -257,7 +257,7 @@ $lang['i_installer'] = 'Instalasi DokuWiki';
$lang['i_wikiname'] = 'Nama Wiki';
$lang['i_enableacl'] = 'Aktifkan ACL (disarankan)';
$lang['i_problems'] = 'Terdapat beberapa kesalahan seperti berikut. Anda tidak dapat melanjutkan sampai kesalahan tersebut diperbaiki.';
$lang['i_modified'] = 'Untuk alasan keamanan, skrip ini hanya dapat dijalankan pada instalasi DikuWiki baru dan belum di modifikasi. Silahkan meng-ekstrak kembali berkasi dari halaman dowload, atau lihat <a href="http://dokuwiki.org/install">Dokuwiki installation instructions</a> ';
$lang['i_modified'] = 'Untuk alasan keamanan, skrip ini hanya dapat dijalankan pada instalasi DikuWiki baru dan belum di modifikasi. Silahkan meng-ekstrak kembali berkasi dari halaman dowload, atau lihat <a href="https://www.dokuwiki.org/install">Dokuwiki installation instructions</a> ';
$lang['i_funcna'] = 'Fungsi PHP <code>%s</code> tidak tersedia. Mungkin dinonaktifkan oleh layanan hosting Anda?';
$lang['i_phpver'] = 'Versi PHP Anda <code>%s</code> lebih rendah dari yang dibutuhkan <code>%s</code>. Mohon melakukan upgrade.';
$lang['i_permfail'] = '<code>%s</code> tidak dapat ditulis oleh DokuWiki. Anda harus memperbaiki konfigurasi hak akses untuk direktori tersebut.';

View File

@ -139,7 +139,7 @@ $lang['created'] = 'myndað';
$lang['restored'] = 'Breytt aftur til fyrri útgáfu (%s)';
$lang['external_edit'] = 'utanaðkomandi breyta';
$lang['summary'] = 'Forskoða';
$lang['noflash'] = 'Það þarf <a href="http://www.adobe.com/products/flashplayer/">Adobe Flash viðbót</a> til að sýna sumt efnið á þessari síðu';
$lang['noflash'] = 'Það þarf <a href="http://get.adobe.com/flashplayer">Adobe Flash viðbót</a> til að sýna sumt efnið á þessari síðu';
$lang['download'] = 'Hlaða niður til kóðabút';
$lang['mail_newpage'] = 'síðu bætt við:';
$lang['mail_changed'] = 'síðu breytt:';

View File

@ -235,7 +235,7 @@ $lang['created'] = 'creata';
$lang['restored'] = 'versione precedente ripristinata (%s)';
$lang['external_edit'] = 'modifica esterna';
$lang['summary'] = 'Oggetto della modifica';
$lang['noflash'] = 'E\' necessario <a href="http://www.adobe.com/products/flashplayer/">il plugin Adobe Flash</a> per visualizzare questo contenuto.';
$lang['noflash'] = 'E\' necessario <a href="http://get.adobe.com/flashplayer">il plugin Adobe Flash</a> per visualizzare questo contenuto.';
$lang['download'] = 'Scarica lo "snippet"';
$lang['tools'] = 'Strumenti';
$lang['user_tools'] = 'Strumenti Utente';
@ -317,10 +317,10 @@ $lang['i_superuser'] = 'Amministratore';
$lang['i_problems'] = 'Si sono verificati problemi durante l\'installazione, indicati di seguito. Non è possibile continuare finché non saranno risolti.';
$lang['i_modified'] = 'Per motivi di sicurezza questa procedura funziona solamente con un\'installazione Dokuwiki nuova e non modificata.
Prova a estrarre di nuovo i file dal pacchetto scaricato oppure consulta le
<a href="http://dokuwiki.org/install">istruzioni per l\'installazione di Dokuwiki</a>';
<a href="https://www.dokuwiki.org/install">istruzioni per l\'installazione di Dokuwiki</a>';
$lang['i_funcna'] = 'La funzione PHP <code>%s</code> non è disponibile. Forse è stata disabilitata dal tuo provider per qualche motivo?';
$lang['i_disabled'] = 'E\' stato disabilitato dal tuo provider di servizi.';
$lang['i_funcnmail'] = '<b>Nota:</b> La funzione mail PHP non è disponibile. %s Se rimane non disponibile, puoi provare ad installare <a href="http://dokuwiki.org/plugins/smtp">smtp plugin</a>.';
$lang['i_funcnmail'] = '<b>Nota:</b> La funzione mail PHP non è disponibile. %s Se rimane non disponibile, puoi provare ad installare <a href="https://www.dokuwiki.org/plugin:smtp">smtp plugin</a>.';
$lang['i_phpver'] = 'La versione di PHP <code>%s</code> è inferiore a quella richiesta <code>%s</code>. Devi aggiornare l\'installazione di PHP.';
$lang['i_mbfuncoverload'] = 'mbstring.func_overload deve essere disabilitato in php.ini per eseguire DokuWiki.';
$lang['i_urandom'] = 'DokuWiki non può creare un numero crittograficamente sicuro di cookies. Puoi provare a controllare sulle impostazioni open_basedir su php.ini per un corretto <code>/dev/urandom</code> accesso.';

View File

@ -199,7 +199,7 @@ $lang['current'] = '現在';
$lang['yours'] = 'あなたのバージョン';
$lang['diff'] = '現在のリビジョンとの差分を表示';
$lang['diff2'] = '選択したリビジョン間の差分を表示';
$lang['difflink'] = 'この比較画面にリンクする';
$lang['difflink'] = 'この比較画面へのリンク';
$lang['diff_type'] = '差分の表示方法:';
$lang['diff_inline'] = 'インライン';
$lang['diff_side'] = '横に並べる';
@ -218,7 +218,7 @@ $lang['created'] = '作成';
$lang['restored'] = '以前のリビジョンを復元 (%s)';
$lang['external_edit'] = '外部編集';
$lang['summary'] = '編集の概要';
$lang['noflash'] = 'この内容を表示するには <a href="http://www.adobe.com/products/flashplayer/">Adobe Flash Plugin</a> が必要です。';
$lang['noflash'] = 'この内容を表示するには <a href="http://get.adobe.com/flashplayer">Adobe Flash Plugin</a> が必要です。';
$lang['download'] = 'この部分をダウンロード';
$lang['tools'] = 'ツール';
$lang['user_tools'] = 'ユーザ用ツール';
@ -300,10 +300,10 @@ $lang['i_superuser'] = 'スーパーユーザー';
$lang['i_problems'] = '問題が発見されました。以下に示す問題を解決するまで、インストールを続行できません。';
$lang['i_modified'] = 'セキュリティの理由から、新規もしくはカスタマイズしていない DokuWiki に対してのみ、このスクリプトは有効です。
ダウンロードしたパッケージを再解凍して使用するか、
<a href="http://dokuwiki.org/install">Dokuwiki インストールガイド</a>を参考にしてインストールしてください。';
<a href="https://www.dokuwiki.org/install">Dokuwiki インストールガイド</a>を参考にしてインストールしてください。';
$lang['i_funcna'] = 'PHPの関数 <code>%s</code> が使用できません。ホスティング会社が何らかの理由で無効にしている可能性があります。';
$lang['i_disabled'] = 'ご利用のプロバイダにより制限されています。';
$lang['i_funcnmail'] = '<b>注:</b>PHPの mail 関数が利用不能になっています。 %s この状況が続く場合は、<a href="http://dokuwiki.org/plugins/smtp">smtpプラグイン</a>をインストールして解決する事も出来ます。';
$lang['i_funcnmail'] = '<b>注:</b>PHPの mail 関数が利用不能になっています。 %s この状況が続く場合は、<a href="https://www.dokuwiki.org/plugin:smtp">smtpプラグイン</a>をインストールして解決する事も出来ます。';
$lang['i_phpver'] = 'PHPのバージョン <code>%s</code> が必要なバージョン <code>%s</code> より以前のものです。PHPのアップグレードが必要です。';
$lang['i_mbfuncoverload'] = 'DokuWiki を実行する php.ini ファイルの mbstring.func_overload は無効にして下さい。';
$lang['i_urandom'] = 'DokuWikiは、Cookieに対して暗号的に安全な番号を作成できません。<code>/dev/urandom</code>に対する適切なアクセスについて、php.iniの設定 open_basedir を確認する事をお勧めします。';

View File

@ -199,7 +199,7 @@ $lang['deleted'] = 'წაშლილია';
$lang['created'] = 'შექმნილია';
$lang['restored'] = 'ძველი ვერსია აღდგენილია (%s)';
$lang['external_edit'] = 'რედაქტირება';
$lang['noflash'] = '<a href="http://www.adobe.com/products/flashplayer/">საჭიროა Adobe Flash Plugin</a>';
$lang['noflash'] = '<a href="http://get.adobe.com/flashplayer">საჭიროა Adobe Flash Plugin</a>';
$lang['download'] = 'Snippet-ის გადმოწერა';
$lang['tools'] = 'ინსტრუმენტები';
$lang['user_tools'] = 'მომხმარებლის ინსტრუმენტები';

View File

@ -216,7 +216,7 @@ $lang['created'] = '만듦';
$lang['restored'] = '이전 판으로 되돌림 (%s)';
$lang['external_edit'] = '바깥 편집';
$lang['summary'] = '편집 요약';
$lang['noflash'] = '이 내용을 표시하기 위해서 <a href="http://www.adobe.com/products/flashplayer/">Adobe Flash 플러그인</a>이 필요합니다.';
$lang['noflash'] = '이 내용을 표시하기 위해서 <a href="http://get.adobe.com/flashplayer">Adobe Flash 플러그인</a>이 필요합니다.';
$lang['download'] = '조각 다운로드';
$lang['tools'] = '도구';
$lang['user_tools'] = '사용자 도구';

View File

@ -164,7 +164,7 @@ $lang['created'] = 'creatur';
$lang['restored'] = 'Recensio uetus restituta (%s)';
$lang['external_edit'] = 'Externe recensere';
$lang['summary'] = 'Indicem recensere';
$lang['noflash'] = '<a href="http://www.adobe.com/products/flashplayer/">Adobe Flash Plugin</a> necessarium est.';
$lang['noflash'] = '<a href="http://get.adobe.com/flashplayer">Adobe Flash Plugin</a> necessarium est.';
$lang['download'] = 'Snippet capere';
$lang['mail_newpage'] = 'Pagina addita:';
$lang['mail_changed'] = 'Pagina mutata:';
@ -233,7 +233,7 @@ $lang['i_wikiname'] = 'Nomen Vicis';
$lang['i_enableacl'] = 'ICA aptum facias (consulatum est)';
$lang['i_superuser'] = 'Magister\stra';
$lang['i_problems'] = 'Creator hos errores habes. Continuare potes postquam omnia soluentur.';
$lang['i_modified'] = 'Hoc scriptum solum cum noua forma Dokuuicis est. Hoc rursum capere in pagina, in qua haec machina capta est, potes aut i ad <a href="http://dokuwiki.org/install">Dokuuicis installation instructions</a>';
$lang['i_modified'] = 'Hoc scriptum solum cum noua forma Dokuuicis est. Hoc rursum capere in pagina, in qua haec machina capta est, potes aut i ad <a href="https://www.dokuwiki.org/install">Dokuuicis installation instructions</a>';
$lang['i_funcna'] = 'PHP functio <code>%s</code> inepta est.';
$lang['i_phpver'] = 'Forma tua PHP <code>%s</code> minor quam illa necessaria <code>%s</code>.';
$lang['i_permfail'] = '<code>%s</code> non a uice scribitur. Facultates inspicere.';

View File

@ -125,7 +125,7 @@ $lang['created'] = 'erstallt';
$lang['restored'] = 'al Versioun zeréckgeholl (%s)';
$lang['external_edit'] = 'extern Ännerung';
$lang['summary'] = 'Resumé vun den Ännerungen';
$lang['noflash'] = 'Den <a href="http://www.adobe.com/products/flashplayer/">Adobe Flash Plugin</a> get gebraucht fir dësen Inhalt unzeweisen.';
$lang['noflash'] = 'Den <a href="http://get.adobe.com/flashplayer">Adobe Flash Plugin</a> get gebraucht fir dësen Inhalt unzeweisen.';
$lang['mail_newpage'] = 'Säit bäigesat:';
$lang['mail_changed'] = 'Säit geännert:';
$lang['mail_subscribe_list'] = 'g\'ännert Säiten am Namespace:';
@ -176,7 +176,7 @@ $lang['i_installer'] = 'DokuWiki Installer';
$lang['i_wikiname'] = 'Numm vum Wiki';
$lang['i_enableacl'] = 'ACL uschalten (rekommandéiert)';
$lang['i_problems'] = 'Den Installer huet Problemer fond. Se stinn hei ënnendrënner. Du kanns net weiderfueren bis de se behuewen hues.';
$lang['i_modified'] = 'Aus Sécherheetsgrënn funktionnéiert dëse Script nëmme mat enger neier an onverännerter Dokuwiki Installatioun. Entweder muss de d\'Dateie frësch extrahéieren oder kuck d\'komplett <a href="http://dokuwiki.org/install">Dokuwiki Installatiounsinstruktiounen</a>';
$lang['i_modified'] = 'Aus Sécherheetsgrënn funktionnéiert dëse Script nëmme mat enger neier an onverännerter Dokuwiki Installatioun. Entweder muss de d\'Dateie frësch extrahéieren oder kuck d\'komplett <a href="https://www.dokuwiki.org/install">Dokuwiki Installatiounsinstruktiounen</a>';
$lang['i_funcna'] = 'PHP-Funktioun <code>%s</code> ass net verfügbar. Vläicht huet däi Provider se aus iergend engem Grond ausgeschalt.';
$lang['i_phpver'] = 'Deng PHP-Versioun <code>%s</code> ass méi kleng wéi déi gebrauchte Versioun <code>%s</code>. Du muss deng PHP-Installatioun aktualiséieren. ';
$lang['i_pol0'] = 'Oppene Wiki (liese, schreiwen an eroplueden fir jidfereen)';

View File

@ -141,7 +141,7 @@ $lang['created'] = 'sukurtas';
$lang['restored'] = 'atstatyta sena versija (%s)';
$lang['external_edit'] = 'redaguoti papildomomis priemonėmis';
$lang['summary'] = 'Redaguoti santrauką';
$lang['noflash'] = '<a href="http://www.adobe.com/products/flashplayer/">Adobe Flash Plugin</a> reikalingas šios medžiagos peržiūrai.';
$lang['noflash'] = '<a href="http://get.adobe.com/flashplayer">Adobe Flash Plugin</a> reikalingas šios medžiagos peržiūrai.';
$lang['mail_newpage'] = '[DokuWiki] puslapis pridėtas:';
$lang['mail_changed'] = '[DokuWiki] puslapis pakeistas:';
$lang['mail_new_user'] = 'naujas vartotojas:';

View File

@ -197,7 +197,7 @@ $lang['created'] = 'izveidots';
$lang['restored'] = 'vecā versija atjaunota (%s)';
$lang['external_edit'] = 'ārpussistēmas labojums';
$lang['summary'] = 'Anotācija';
$lang['noflash'] = 'Lai attēlotu lapas saturu, vajag <a href="http://www.adobe.com/products/flashplayer/">Adobe Flash Plugin</a>.';
$lang['noflash'] = 'Lai attēlotu lapas saturu, vajag <a href="http://get.adobe.com/flashplayer">Adobe Flash Plugin</a>.';
$lang['download'] = 'Lejuplādēt «kodiņu»((snippet))';
$lang['tools'] = 'Rīki';
$lang['user_tools'] = 'Lietotāja rīki';
@ -278,7 +278,7 @@ $lang['i_enableacl'] = 'Lietot ACL (ieteikts)';
$lang['i_superuser'] = 'Superuser';
$lang['i_problems'] = 'Instalētājs atrada zemāk minētās problēmas. Kamēr tās nenovērš, nav iespējam turpināt.';
$lang['i_modified'] = 'Drošības nolūkos šis skripts darbosies tika ar jaunu nemodificētu Dokuwiki instalāciju.
Vai nu no jauna jāatarhivē faili no lejupielādētās pakas vai jāraugās pēc padoma pilnā Dokuwiki instalācijas instrukcijā <a href="http://dokuwiki.org/install"></a>';
Vai nu no jauna jāatarhivē faili no lejupielādētās pakas vai jāraugās pēc padoma pilnā Dokuwiki instalācijas instrukcijā <a href="https://www.dokuwiki.org/install"></a>';
$lang['i_funcna'] = 'PHP funkcija <code>%s</code> nav pieejama. Varbūt jūsu servera īpašnieks to kāda iemesla dēļ atslēdzis?';
$lang['i_phpver'] = 'Jūsu PHP versija <code>%s</code> ir par vecu. Vajag versiju <code>%s</code>. Atjaunojiet savu PHP instalāciju.';
$lang['i_mbfuncoverload'] = 'Lai darbinātu DokuWiki, php.ini failā ir jāatspējo mbstring.func_overload.';

View File

@ -139,7 +139,7 @@ $lang['created'] = 'креирана';
$lang['restored'] = 'обновена е стара ревизија (%s)';
$lang['external_edit'] = 'надворешно уредување';
$lang['summary'] = 'Уреди го изводот';
$lang['noflash'] = '<a href="http://www.adobe.com/products/flashplayer/">Adobe Flash приклучокот</a> е потребен за да се прикаже оваа содржина.';
$lang['noflash'] = '<a href="http://get.adobe.com/flashplayer">Adobe Flash приклучокот</a> е потребен за да се прикаже оваа содржина.';
$lang['download'] = 'Симни Snippe';
$lang['mail_newpage'] = 'додадена е страницата:';
$lang['mail_changed'] = 'променета е страницата:';
@ -202,7 +202,7 @@ $lang['i_wikiname'] = 'вики име';
$lang['i_enableacl'] = 'Овозможи ACL (препорачано)';
$lang['i_superuser'] = 'Супер корисник';
$lang['i_problems'] = 'Инсталерот пронајде неколку проблеми кои се прикажани подолу. Не можете да продолжите понатаму се додека не ги поправите.';
$lang['i_modified'] = 'За безбедносни причини оваа скрипта ќе работи само со нова и неизменета инсталација од DokuWiki. Или извадете ги повторно датотеките од симнатиот пакет или консултирајте се со комплетните <a href="http://dokuwiki.org/install">Dokuwiki инструкции за инсталација</a>';
$lang['i_modified'] = 'За безбедносни причини оваа скрипта ќе работи само со нова и неизменета инсталација од DokuWiki. Или извадете ги повторно датотеките од симнатиот пакет или консултирајте се со комплетните <a href="https://www.dokuwiki.org/install">Dokuwiki инструкции за инсталација</a>';
$lang['i_funcna'] = 'PHP функцијата <code>%s</code> не е достапна. Можеби вашиот хостинг провајдер ја оневозможил со причина?';
$lang['i_phpver'] = 'Вашата верзија на PHP <code>%s</code> е пониска од потребната <code>%s</code>. Треба да ја надградите вашата PHP инсталација.';
$lang['i_permfail'] = '<code>%s</code> не е запишлива од DokuWiki. Треба да ги поправите подесувањата за пермисии на овој директориум!';

View File

@ -180,7 +180,7 @@ $lang['deleted'] = 'काढून टाकले';
$lang['created'] = 'निर्माण केले';
$lang['external_edit'] = 'बाहेरून संपादित';
$lang['summary'] = 'सारांश बदला';
$lang['noflash'] = 'ही माहिती दाखवण्यासाठी <a href="http://www.adobe.com/products/flashplayer/">अडोब फ्लॅश प्लेअर</a> ची गरज आहे.';
$lang['noflash'] = 'ही माहिती दाखवण्यासाठी <a href="http://get.adobe.com/flashplayer">अडोब फ्लॅश प्लेअर</a> ची गरज आहे.';
$lang['download'] = 'तुकडा डाउनलोड करा';
$lang['tools'] = 'साधने';
$lang['user_tools'] = 'युजरची साधने';
@ -245,7 +245,7 @@ $lang['i_wikiname'] = 'विकी नाम';
$lang['i_enableacl'] = 'ACL चालू करा ( अधिक चांगले )';
$lang['i_superuser'] = 'सुपर-सदस्य';
$lang['i_problems'] = 'इनस्टॉलरला काही अडचणि आल्या आहेत. त्या ठीक केल्याशिवाय तुम्ही पुढे जाऊ शकत नाही.';
$lang['i_modified'] = 'सुरक्षिततेच्या कारणासठि ही स्क्रिप्ट फ़क्त नवीन आणि बदललेल्या डॉक्युविकि इन्स्टॉलेशन मधेच चालेल. तुम्ही एकतर डाउनलोड केलेले पॅकेज मधील फाइल परत प्रसारित करा किंवा <a href="http://dokuwiki.org/install">डॉक्युविकि इन्स्टॉलेशन विषयी सूचना</a> वाचा.';
$lang['i_modified'] = 'सुरक्षिततेच्या कारणासठि ही स्क्रिप्ट फ़क्त नवीन आणि बदललेल्या डॉक्युविकि इन्स्टॉलेशन मधेच चालेल. तुम्ही एकतर डाउनलोड केलेले पॅकेज मधील फाइल परत प्रसारित करा किंवा <a href="https://www.dokuwiki.org/install">डॉक्युविकि इन्स्टॉलेशन विषयी सूचना</a> वाचा.';
$lang['i_funcna'] = 'PHP मधलं <code>%s</code> हे फंक्शन उपलब्ध नाही. बहुधा तुमच्या होस्टिंग पुरवणाराने ते काही कारणाने अनुपलब्ध केलं असावं.';
$lang['i_phpver'] = 'तुमची PHP आवृत्ति <code>%s</code> ही आवश्यक असलेल्या <code>%s</code> ह्या आवृत्तिपेक्षा कमी आहे. कृपया तुमचे PHP इन्स्टॉलेशन अद्ययावत करा.';
$lang['i_permfail'] = '<code>%s</code> या डिरेक्टरी मध्ये डॉक्युविकि बदल करू शकत नाही. कृपया या डिरेक्टरीच्या परवानग्या ठीक करा.';

View File

@ -184,7 +184,7 @@ $lang['i_wikiname'] = 'विकी नाम';
$lang['i_enableacl'] = 'ACL लागु गर्नुहोस्( सिफारिस गरिएको)';
$lang['i_superuser'] = 'मूख्य प्रयोगकर्ता';
$lang['i_problems'] = 'स्थापकले तल देखाइएको त्रुटि फेला पार्‌यो ।तपाईले यो त्रुटि नसच्याए सम्म अगि बढ्न सक्नुहुने छैन।';
$lang['i_modified'] = 'सुरक्षाको कारणले यो स्क्रिप्ट नया तथा नसच्याइएको Dokuwiki स्थापनामा मात्र काम गर्छ। तपाईले कि डाउनलोड गर्नुभएको प्याकेज पुन: खोल्नुहोस् कि <a href="http://dokuwiki.org/install">Dokuwiki स्थापना विधि</a>';
$lang['i_modified'] = 'सुरक्षाको कारणले यो स्क्रिप्ट नया तथा नसच्याइएको Dokuwiki स्थापनामा मात्र काम गर्छ। तपाईले कि डाउनलोड गर्नुभएको प्याकेज पुन: खोल्नुहोस् कि <a href="https://www.dokuwiki.org/install">Dokuwiki स्थापना विधि</a>';
$lang['i_funcna'] = 'PHP function <code>%s</code> उपलव्ध छैन । हुनसक्छ तपाईको होस्टिङ्ग प्रदायकले कुनै कारण वश यसलाई वन्द गरिदिएका हुनसक्छन् । ';
$lang['i_phpver'] = 'तपाईको PHP संस्करण <code>%s</code> चाहिएको <code>%s</code> भन्दा कम छ। तपाईले आफ्नो PHP स्थापना अध्यावधिक गर्नुपर्छ ।';
$lang['i_permfail'] = '<code>%s</code> DokuWiki द्वारा लेख्य छैन । तपाईले डाइरेक्टरीको अनुमति परिवर्तन गर्नुपर्छ !';

View File

@ -239,7 +239,7 @@ $lang['created'] = 'aangemaakt';
$lang['restored'] = 'oude revisie hersteld (%s)';
$lang['external_edit'] = 'Externe bewerking';
$lang['summary'] = 'Samenvatting wijziging';
$lang['noflash'] = 'De <a href="http://www.adobe.com/products/flashplayer/">Adobe Flash Plugin</a> is vereist om de pagina te kunnen weergeven.';
$lang['noflash'] = 'De <a href="http://get.adobe.com/flashplayer">Adobe Flash Plugin</a> is vereist om de pagina te kunnen weergeven.';
$lang['download'] = 'Download fragment';
$lang['tools'] = 'Hulpmiddelen';
$lang['user_tools'] = 'Gebruikershulpmiddelen';
@ -319,7 +319,7 @@ $lang['i_wikiname'] = 'Wikinaam';
$lang['i_enableacl'] = 'ACLs inschakelen (aanbevolen)';
$lang['i_superuser'] = 'Superuser';
$lang['i_problems'] = 'De installer vond problemen, hieronder aangegeven. Verhelp deze voor je doorgaat.';
$lang['i_modified'] = 'Uit veiligheidsoverwegingen werkt dit script alleen met nieuwe en onveranderde DokuWiki-installaties. Pak de bestanden opnieuw uit of raadpleeg de <a href="http://dokuwiki.org/install">Dokuwiki installatie-instructies</a>';
$lang['i_modified'] = 'Uit veiligheidsoverwegingen werkt dit script alleen met nieuwe en onveranderde DokuWiki-installaties. Pak de bestanden opnieuw uit of raadpleeg de <a href="https://www.dokuwiki.org/install">Dokuwiki installatie-instructies</a>';
$lang['i_funcna'] = 'PHP functie <code>%s</code> is niet beschikbaar. Wellicht heeft je hosting provider deze uitgeschakeld?';
$lang['i_phpver'] = 'PHP-versie <code>%s</code> is lager dan de vereiste <code>%s</code>. Upgrade PHP.';
$lang['i_mbfuncoverload'] = 'Om DokuWiki te draaien moet mbstring.func_overload uitgeschakeld zijn in php.ini.';

View File

@ -228,7 +228,7 @@ $lang['created'] = 'opprettet';
$lang['restored'] = 'gjenopprettet til en tidligere versjon (%s)';
$lang['external_edit'] = 'ekstern redigering';
$lang['summary'] = 'Redigeringskommentar';
$lang['noflash'] = 'For at dette innholdet skal vises må du ha <a href="http://www.adobe.com/products/flashplayer/">Adobe Flash Plugin</a>.';
$lang['noflash'] = 'For at dette innholdet skal vises må du ha <a href="http://get.adobe.com/flashplayer">Adobe Flash Plugin</a>.';
$lang['download'] = 'Last ned utdraget';
$lang['tools'] = 'Verktøy';
$lang['user_tools'] = 'Brukerverktøy';
@ -310,7 +310,7 @@ $lang['i_superuser'] = 'Superbruker';
$lang['i_problems'] = 'Installasjonen oppdaget noen problemer, disse listes nedenfor. Du kan ikke fortsett før du har løst disse.';
$lang['i_modified'] = 'For sikkerhets skyld vil dette skriptet bare virke med en ny og uendret Dokuwiki-installsjon.
Du bør enten pakke ut filene nytt fra den nedlastede pakken, eller konsultere den komplette
<a href="http://dokuwiki.org/install">Dokuwiki-installasjonsinstruksen</a>';
<a href="https://www.dokuwiki.org/install">Dokuwiki-installasjonsinstruksen</a>';
$lang['i_funcna'] = 'PHP-funksjonen <code>%s</code> er ikke tilgjengelig. Kanskje din nettleverandør har deaktivert denne?';
$lang['i_phpver'] = 'Din PHP versjon <code>%s</code> er lavere enn kravet <code>%s</code>. Du må oppgradere PHP installasjonen. ';
$lang['i_mbfuncoverload'] = 'mbstring.func_overload må deaktiveres i php.ini for å kjøre DokuWiki.';

View File

@ -233,7 +233,7 @@ $lang['created'] = 'utworzono';
$lang['restored'] = 'przywrócono poprzednią wersję (%s)';
$lang['external_edit'] = 'edycja zewnętrzna';
$lang['summary'] = 'Opis zmian';
$lang['noflash'] = 'Plugin <a href="http://www.adobe.com/products/flashplayer/">Adobe Flash Plugin</a> jest niezbędny do obejrzenia tej zawartości.';
$lang['noflash'] = 'Plugin <a href="http://get.adobe.com/flashplayer">Adobe Flash Plugin</a> jest niezbędny do obejrzenia tej zawartości.';
$lang['download'] = 'Pobierz zrzut';
$lang['tools'] = 'Narzędzia';
$lang['user_tools'] = 'Narzędzia użytkownika';
@ -314,7 +314,7 @@ $lang['i_enableacl'] = 'Włącz mechanizm uprawnień ACL (zalecane)';
$lang['i_superuser'] = 'Administrator';
$lang['i_problems'] = 'Instalator napotkał poniższe problemy. Nie można kontynuować póki nie zostaną usunięte.';
$lang['i_modified'] = 'Ze względów bezpieczeństwa, ten skrypt działa tylko z nową i niezmodyfikowaną instalacją DokuWiki.
Aby uruchomić instalator ponownie, rozpakuj archiwum DokuWiki lub zapoznaj się z <a href="http://dokuwiki.org/install">instrukcją instalacji Dokuwiki</a>';
Aby uruchomić instalator ponownie, rozpakuj archiwum DokuWiki lub zapoznaj się z <a href="https://www.dokuwiki.org/install">instrukcją instalacji Dokuwiki</a>';
$lang['i_funcna'] = 'Funkcja PHP <code>%s</code> jest niedostępna.';
$lang['i_disabled'] = 'To zostało wyłączone przez twojego dostawcę.';
$lang['i_phpver'] = 'Wersja PHP <code>%s</code> jest niższa od wymaganej <code>%s</code>. Zaktualizuj instalację PHP.';

View File

@ -237,7 +237,7 @@ $lang['created'] = 'criada';
$lang['restored'] = 'a revisão anterior foi restaurada (%s)';
$lang['external_edit'] = 'edição externa';
$lang['summary'] = 'Resumo da edição';
$lang['noflash'] = 'O <a href="http://www.adobe.com/products/flashplayer/">plug-in Adobe Flash</a> é necessário para exibir este conteúdo.';
$lang['noflash'] = 'O <a href="http://get.adobe.com/flashplayer">plug-in Adobe Flash</a> é necessário para exibir este conteúdo.';
$lang['download'] = 'Baixar o snippet';
$lang['tools'] = 'Ferramentas';
$lang['user_tools'] = 'Ferramentas do usuário';
@ -318,7 +318,7 @@ $lang['i_enableacl'] = 'Habilitar Lista de Controle de Acessos (recome
$lang['i_superuser'] = 'Superusuário';
$lang['i_problems'] = 'O instalador encontrou alguns problemas, indicados abaixo. Você não pode continuar até corrigi-los.';
$lang['i_modified'] = 'Por questões de segurança, esse script funcionará apenas em uma instalação nova e não modificada do DokuWiki.
Você pode extrair novamente os arquivos do pacote original ou consultar as <a href="http://dokuwiki.org/install">instruções de instalação do DokuWiki</a>.';
Você pode extrair novamente os arquivos do pacote original ou consultar as <a href="https://www.dokuwiki.org/install">instruções de instalação do DokuWiki</a>.';
$lang['i_funcna'] = 'A função PHP <code>%s</code> não está disponível. O seu host a mantém desabilitada por algum motivo?';
$lang['i_disabled'] = 'Foi desativado pelo seu provedor.';
$lang['i_funcnmail'] = '<b>Nota:</b> A função de correio PHP não está disponível. %s Se permanecer indisponível, você pode instalar o <a href="https://www.dokuwiki.org/plugin:smtp">plugin SMTP</a>.';

View File

@ -228,7 +228,7 @@ $lang['created'] = 'criado';
$lang['restored'] = 'versão anterior restaurada (%s)';
$lang['external_edit'] = 'edição externa';
$lang['summary'] = 'Sumário da edição';
$lang['noflash'] = 'O <a href="http://www.adobe.com/products/flashplayer/">Plugin Adobe Flash</a> é necessário para exibir este conteúdo.';
$lang['noflash'] = 'O <a href="http://get.adobe.com/flashplayer">Plugin Adobe Flash</a> é necessário para exibir este conteúdo.';
$lang['download'] = 'Baixar Snippet';
$lang['tools'] = 'Ferramentas';
$lang['user_tools'] = 'Ferramentas de Usuário';
@ -308,10 +308,10 @@ $lang['i_wikiname'] = 'Nome Wiki';
$lang['i_enableacl'] = 'Ativar ACL (recomendado)';
$lang['i_superuser'] = 'Superusuário';
$lang['i_problems'] = 'O instalador encontrou alguns problemas, indicados abaixo. Não pode continuar até que sejam corrigidos.';
$lang['i_modified'] = 'Por razões de segurança, este script só funciona em novas e não-modificadas instalações do Dokuwiki. Você deve re-extrair os arquivos do pacote que baixou ou então consultar as <a href="http://dokuwiki.org/install">instruções de instalação do Dokuwiki</a>';
$lang['i_modified'] = 'Por razões de segurança, este script só funciona em novas e não-modificadas instalações do Dokuwiki. Você deve re-extrair os arquivos do pacote que baixou ou então consultar as <a href="https://www.dokuwiki.org/install">instruções de instalação do Dokuwiki</a>';
$lang['i_funcna'] = 'A função PHP <code>%s</code> não está disponível. Talvez o host a tenha desativado-a por alguma razão?';
$lang['i_disabled'] = 'Isso foi desativado pelo seu provedor.';
$lang['i_funcnmail'] = '<b>Nota:</b> A função mail do PHP não está disponível. %s Se ela permanecer indisponível, instale o <a href="http://dokuwiki.org/plugins/smtp">plugin smtp</a>.';
$lang['i_funcnmail'] = '<b>Nota:</b> A função mail do PHP não está disponível. %s Se ela permanecer indisponível, instale o <a href="https://www.dokuwiki.org/plugin:smtp">plugin smtp</a>.';
$lang['i_phpver'] = 'A versão de PHP actual <code>%s</code> é inferior à versão mínima <code>%s</code>. É preciso atualizar a instalação PHP.';
$lang['i_mbfuncoverload'] = 'mbstring.func_overload deve ser desativada no php.ini para executar o DokuWiki.';
$lang['i_urandom'] = 'DokuWiki não pode criar números criptograficamente seguros para cookies. Verifique a configuração open_basedir no php.ini para um acesso <code>/dev/urandom</code> adequado.';

View File

@ -220,7 +220,7 @@ $lang['created'] = 'creat';
$lang['restored'] = 'versiune veche restaurată (%s)';
$lang['external_edit'] = 'editare externă';
$lang['summary'] = 'Editează sumarul';
$lang['noflash'] = 'Plugin-ul <a href="http://www.adobe.com/products/flashplayer/">Adobe Flash Plugin</a> este necesar pentru afișarea corectă a conținutului.';
$lang['noflash'] = 'Plugin-ul <a href="http://get.adobe.com/flashplayer">Adobe Flash Plugin</a> este necesar pentru afișarea corectă a conținutului.';
$lang['download'] = 'Bloc descărcări';
$lang['tools'] = 'Unelte';
$lang['user_tools'] = 'Unelte utilizator';
@ -301,7 +301,7 @@ $lang['i_enableacl'] = 'Activează ACL (liste de control a accesului)
$lang['i_superuser'] = 'Utilizator privilegiat';
$lang['i_problems'] = 'Programul de instalare a găsit câteva probleme, indicate mai jos. Nu poți continua până nu le rezolvi.';
$lang['i_modified'] = 'Din motive de securitate, acest script va funcționa doar cu o instalare nouă și nemodificată a DokuWiki.
Poți fie extragi din nou fișierele din arhiva descărcată fie consulți instrucțiunile de instalare DokuWiki la <a href="http://dokuwiki.org/install">';
Poți fie extragi din nou fișierele din arhiva descărcată fie consulți instrucțiunile de instalare DokuWiki la <a href="https://www.dokuwiki.org/install">';
$lang['i_funcna'] = 'Funcția PHP <code>%s</code> nu este disponibilă. Probabil provider-ul tău a dezactivat-o pentru un motiv anume.';
$lang['i_disabled'] = 'a fost dezactivat de furnizorul tău';
$lang['i_funcnmail'] = '<b>Notă:</b> Funcția PHP de email nu este disponibilă %s Daca tot rămâne nedisponibilă, trebuie sa instalezi <a href="https://www.dokuwiki.org/plugin:smtp">modulul stmp</a>. ';

View File

@ -248,7 +248,7 @@ $lang['created'] = 'создано';
$lang['restored'] = 'старая версия восстановлена (%s)';
$lang['external_edit'] = 'внешнее изменение';
$lang['summary'] = 'Сводка изменений';
$lang['noflash'] = 'Для просмотра этого содержимого требуется <a href="http://www.adobe.com/products/flashplayer/">Adobe Flash Plugin</a>.';
$lang['noflash'] = 'Для просмотра этого содержимого требуется <a href="http://get.adobe.com/flashplayer">Adobe Flash Plugin</a>.';
$lang['download'] = 'Скачать фрагмент кода';
$lang['tools'] = 'Инструменты';
$lang['user_tools'] = 'Инструменты пользователя';

View File

@ -221,7 +221,7 @@ $lang['created'] = 'vytvorené';
$lang['restored'] = 'stará verzia bola obnovená (%s)';
$lang['external_edit'] = 'externá úprava';
$lang['summary'] = 'Komentár k úpravám';
$lang['noflash'] = 'Pre zobrazenie tohto obsahu potrebujete <a href="http://www.adobe.com/products/flashplayer/">Adobe Flash Plugin</a>.';
$lang['noflash'] = 'Pre zobrazenie tohto obsahu potrebujete <a href="http://get.adobe.com/flashplayer">Adobe Flash Plugin</a>.';
$lang['download'] = 'Stiahnuť';
$lang['tools'] = 'Nástroje';
$lang['user_tools'] = 'Nástroje používateľa';
@ -301,7 +301,7 @@ $lang['i_wikiname'] = 'Názov Wiki';
$lang['i_enableacl'] = 'Aktivovať ACL (doporučené)';
$lang['i_superuser'] = 'Správca';
$lang['i_problems'] = 'Inštalátor narazil na nižšie uvedené problémy. Nemôžete pokračovať, pokiaľ ich neodstránite.';
$lang['i_modified'] = 'Z bezpečnostných dôvodov bude tento skript fungovať iba s novou, neupravenou inštaláciou Dokuwiki. Môžete buď znovu rozbaliť stiahnutý inštalačný balík alebo preštudovať <a href="http://dokuwiki.org/install"> inštalačné inštrukcie Dokuwiki</a>';
$lang['i_modified'] = 'Z bezpečnostných dôvodov bude tento skript fungovať iba s novou, neupravenou inštaláciou Dokuwiki. Môžete buď znovu rozbaliť stiahnutý inštalačný balík alebo preštudovať <a href="https://www.dokuwiki.org/install"> inštalačné inštrukcie Dokuwiki</a>';
$lang['i_funcna'] = 'PHP funkcia <code>%s</code> nie je dostupná. Je možné, že ju z určitých dôvodov zablokoval váš poskytovateľ webhostingu?';
$lang['i_funcnmail'] = '<b>Note:</b> PHP mail funkcia nie je dostupná. %s Ak zostáva stále nedostupná, možno by ste mohli nainštalovať <a href="https://www.dokuwiki.org/plugin:smtp">smtp plugin</a>.';
$lang['i_phpver'] = 'Vaša verzia PHP <code>%s</code> je nižšia ako požadovaná <code>%s</code>. Potrebujete aktualizovať Vašu inštaláciu PHP.';

View File

@ -196,7 +196,7 @@ $lang['created'] = 'ustvarjena';
$lang['restored'] = 'povrnjena stara različica (%s)';
$lang['external_edit'] = 'urejanje v zunanjem urejevalniku';
$lang['summary'] = 'Povzetek urejanja';
$lang['noflash'] = 'Za prikaz vsebine je treba namestiti <a href="http://www.adobe.com/products/flashplayer/">Adobe Flash Plugin</a>';
$lang['noflash'] = 'Za prikaz vsebine je treba namestiti <a href="http://get.adobe.com/flashplayer">Adobe Flash Plugin</a>';
$lang['download'] = 'Naloži izrezek';
$lang['tools'] = 'Orodja';
$lang['user_tools'] = 'Uporabniška orodja';
@ -276,7 +276,7 @@ $lang['i_wikiname'] = 'Ime Wiki spletišča';
$lang['i_enableacl'] = 'Omogoči ACL (priporočeno)';
$lang['i_superuser'] = 'Skrbnik';
$lang['i_problems'] = 'Namestilnik je naletel na težave, ki so izpisane spodaj. Namestitve ni mogoče nadaljevati, dokler težave ne bodo odpravljene.';
$lang['i_modified'] = 'Iz varnostnih razlogov skript deluje le v novi in neprilagojeni namestitvi sistema DokuWiki. Postopek namestitve je treba začeti znova ali pa sistem namestiti ročno s pomočjo <a href="http://dokuwiki.org/install">navodil nameščanja Dokuwiki</a>.';
$lang['i_modified'] = 'Iz varnostnih razlogov skript deluje le v novi in neprilagojeni namestitvi sistema DokuWiki. Postopek namestitve je treba začeti znova ali pa sistem namestiti ročno s pomočjo <a href="https://www.dokuwiki.org/install">navodil nameščanja Dokuwiki</a>.';
$lang['i_funcna'] = 'Funkcija PHP <code>%s</code> ni na voljo. Morda je možnost na strežniku zaradi varnostnih razlogov onemogočena.';
$lang['i_phpver'] = 'Različica PHP <code>%s</code> je nižja od zahtevane različice <code>%s</code>. Pred nadaljevanjem je treba posodobiti namestitev PHP.';
$lang['i_permfail'] = 'Predmet <code>%s</code> ni zapisljiv. Zahtevana je sprememba dovoljenj za to mapo.';

View File

@ -159,7 +159,7 @@ $lang['created'] = 'u krijua';
$lang['restored'] = 'Kthehu tek një version i vjetër (%s)';
$lang['external_edit'] = 'redaktim i jashtëm';
$lang['summary'] = 'Përmbledhja redaktimit';
$lang['noflash'] = 'Nevojitet <a href="http://www.adobe.com/products/flashplayer/">Adobe Flash Plugin</a> për të paraqitur këtë përmbajtje.';
$lang['noflash'] = 'Nevojitet <a href="http://get.adobe.com/flashplayer">Adobe Flash Plugin</a> për të paraqitur këtë përmbajtje.';
$lang['download'] = 'Shkarko Copën';
$lang['mail_newpage'] = 'faqje u shtua:';
$lang['mail_changed'] = 'faqja u ndryshua:';
@ -226,7 +226,7 @@ $lang['i_enableacl'] = 'Aktivizo ACL (rekomanduar)';
$lang['i_superuser'] = 'Superpërdorues';
$lang['i_problems'] = 'Installer-i gjeti disa probleme, të shfaqura më poshtë. Nuk mund të vazhdoni derisa t\'i keni rregulluar.';
$lang['i_modified'] = 'Për arsye sigurie ky skript do punojë vetëm me një instalim ri dhe pamodifikuar DokuWiki.
Ose duhet ekstraktoni skedarët nga e para nga pakoja e shkarkimit ose konsultohuni me <a href="http://dokuwiki.org/install">Dokuwiki installation instructions</a>';
Ose duhet ekstraktoni skedarët nga e para nga pakoja e shkarkimit ose konsultohuni me <a href="https://www.dokuwiki.org/install">Dokuwiki installation instructions</a>';
$lang['i_funcna'] = 'Funksioni PHP <code>%s</code> nuk është i disponueshëm. Mbase siguruesi juaj i host-it e ka çaktivizuar për ndonjë arsye?';
$lang['i_phpver'] = 'Versioni juaj i PHP <code>%s</code> është më i vogël se ai i duhuri <code>%s</code>. Duhet të përditësoni instalimin tuaj të PHP-së.';
$lang['i_permfail'] = '<code>%s</code> nuk është e shkruajtshme nga DokuWiki. Duhet të rregulloni lejet e përdorimit për këtë direktori.';

View File

@ -216,7 +216,7 @@ $lang['created'] = 'направљено';
$lang['restored'] = 'стара верзија повраћена (%s)';
$lang['external_edit'] = 'спољна измена';
$lang['summary'] = 'Сажетак измене';
$lang['noflash'] = 'За приказивање ове врсте материјала потребан вам је <a href="http://www.adobe.com/products/flashplayer/">Adobe Flash Plugin</a>.';
$lang['noflash'] = 'За приказивање ове врсте материјала потребан вам је <a href="http://get.adobe.com/flashplayer">Adobe Flash Plugin</a>.';
$lang['download'] = 'Преузми снипет';
$lang['tools'] = 'Алатке';
$lang['user_tools'] = 'Корисничке алатке';
@ -296,7 +296,7 @@ $lang['i_wikiname'] = 'Назив викија';
$lang['i_enableacl'] = 'Укључи ';
$lang['i_superuser'] = 'Суперкорисник';
$lang['i_problems'] = 'Инсталација је наишла на проблеме који су навадени у тексту испод. Не можете наставити даље док их не исправите.';
$lang['i_modified'] = 'Из сигурносних разлога ова скрипта ради само са новом Dokuwiki инсталацијом. Требало би или да опет распакујете архиву преузету са сајта или да погледате <a href="http://dokuwiki.org/install">Dokuwiki инструкције за инсталацију</a>';
$lang['i_modified'] = 'Из сигурносних разлога ова скрипта ради само са новом Dokuwiki инсталацијом. Требало би или да опет распакујете архиву преузету са сајта или да погледате <a href="https://www.dokuwiki.org/install">Dokuwiki инструкције за инсталацију</a>';
$lang['i_funcna'] = 'ПХП функција <code>%s</code> није доступна. Можда је Ваш хостинг провајдер забранио из неког разлога?';
$lang['i_phpver'] = '<code>%s</code> Верзија Вашег ПХПа је нижа од неопходне <code>%s</code>. Требало би да надоградите ПХП инсталацију.';
$lang['i_mbfuncoverload'] = 'mbstring.func_overload мора бити искључен у датотеци php.ini да бисте користили Докувики.';

View File

@ -227,7 +227,7 @@ $lang['created'] = 'skapad';
$lang['restored'] = 'tidigare version återställd (%s)';
$lang['external_edit'] = 'extern redigering';
$lang['summary'] = 'Redigeringskommentar';
$lang['noflash'] = '<a href="http://www.adobe.com/products/flashplayer/">Adobe Flash Plugin</a> behövs för att visa detta innehåll.';
$lang['noflash'] = '<a href="http://get.adobe.com/flashplayer">Adobe Flash Plugin</a> behövs för att visa detta innehåll.';
$lang['download'] = 'Ladda ner kodfragmentet';
$lang['tools'] = 'Verktyg';
$lang['user_tools'] = 'Användarverktyg';
@ -309,7 +309,7 @@ $lang['i_superuser'] = 'Användarnamn för administratören';
$lang['i_problems'] = 'Installationsprogrammet hittade några problem som visas nedan. Du kan inte fortsätta innan du har fixat dem.';
$lang['i_modified'] = 'Av säkerhetsskäl fungerar det här skriptet bara med en ny och omodifierad installation av Dokuwiki.
Du får antingen packa upp det nedladdade paketet nytt, eller konsultera de kompletta
<a href="http://dokuwiki.org/install">instruktionerna för installation av Dokuwiki</a>';
<a href="https://www.dokuwiki.org/install">instruktionerna för installation av Dokuwiki</a>';
$lang['i_funcna'] = 'PHP-funktionen <code>%s</code> är inte tillgänglig. Kanske ditt webbhotell har avaktiverat den av någon anledning?';
$lang['i_disabled'] = 'Det är avstängt av din leverantör.';
$lang['i_funcnmail'] = '<b>Note:</b> PHP mail funktionen är inte tillgänglig. %s Om det är fortsatt otillgängligt kan du installera <a href="https://www.dokuwiki.org/plugin:smtp">smtp pluginet</a>';

View File

@ -215,7 +215,7 @@ $lang['created'] = 'ถูกสร้าง';
$lang['restored'] = 'ย้อนไปรุ่นก่อนหน้า (%s)';
$lang['external_edit'] = 'แก้ไขภายนอก';
$lang['summary'] = 'สรุป(หมายเหตุ)การแก้ไขนี้';
$lang['noflash'] = 'ต้องการตัวเล่นแฟลช <a href="http://www.adobe.com/products/flashplayer/">Adobe Flash Plugin</a> เพื่อแสดงผลเนื้อหานี้';
$lang['noflash'] = 'ต้องการตัวเล่นแฟลช <a href="http://get.adobe.com/flashplayer">Adobe Flash Plugin</a> เพื่อแสดงผลเนื้อหานี้';
$lang['download'] = 'ดาวน์โหลดสนิปเป็ด(Snippet)';
$lang['tools'] = 'เครื่องมือ';
$lang['user_tools'] = 'เครื่องมือสำหรับผู้ใช้';
@ -284,7 +284,7 @@ $lang['i_superuser'] = 'ซุปเปอร์ยูสเซอร
$lang['i_problems'] = 'ตัวติดตั้งพบปัญหาบางประการ ตามที่ระบุด้านล่าง คุณไม่สามารถทำต่อได้จนกว่าจะได้แก้ไขสิ่งเหล่านั้น';
$lang['i_modified'] = 'ด้วยเหตุผลด้านความปลอดภัย สคริปต์นี้จะทำงานกับเฉพาะโดกุวิกิที่ติดตั้งใหม่หรือยังไม่ได้ดัดแปลงแก้ไข
คุณควรเลือกระหว่างคลี่ไฟล์จากแพคเกจที่ได้ดาวน์โหลดมาอีกครั้ง หรือศึกษาจากคู่มือ
<a href="http://dokuwiki.org/install">Dokuwiki installation instructions</a>';
<a href="https://www.dokuwiki.org/install">Dokuwiki installation instructions</a>';
$lang['i_funcna'] = 'PHP function <code>%s</code> ไม่สามารถใช้งานได้ อาจเป็นเพราะผู้ให้บริการโฮสไม่เปิดให้ใช้งาน';
$lang['i_phpver'] = 'PHP รุ่นที่คุณกำลังใช้งานอยู่คือ <code>%s</code> คุณจำเป็นต้องอัพเกรด PHP ให้เป็นรุ่น <code>%s</code> หรือสูงกว่า';
$lang['i_permfail'] = '<code>%s</code> DokuWiki ไม่สามารถเขียนข้อมูลได้ ต้องตั้งค่าสิทธิ์การอนุญาตของไดเรคทอรีนี้เสียก่อน!';

View File

@ -222,7 +222,7 @@ $lang['created'] = 'oluşturuldu';
$lang['restored'] = 'eski sürüme dönüldü (%s)';
$lang['external_edit'] = 'Dışarıdan düzenle';
$lang['summary'] = 'Özeti düzenle';
$lang['noflash'] = 'Bu içeriği göstermek için <a href="http://www.adobe.com/products/flashplayer/">Adobe Flash Eklentisi</a> gerekmektedir.';
$lang['noflash'] = 'Bu içeriği göstermek için <a href="http://get.adobe.com/flashplayer">Adobe Flash Eklentisi</a> gerekmektedir.';
$lang['download'] = 'Parçacığı indir';
$lang['tools'] = 'Alet';
$lang['user_tools'] = 'Kullanıcı Aletleri';
@ -302,7 +302,7 @@ $lang['i_wikiname'] = 'Wiki Adı';
$lang['i_enableacl'] = 'ACL\'yi etkinleştir (tavsiye edilir)';
$lang['i_superuser'] = 'Ana Kullanıcı';
$lang['i_problems'] = 'Kurulum sihirbazı aşağıda gösterilen sorunları buldu. Bunları düzeltmeden devam etmeniz mümkün değil.';
$lang['i_modified'] = 'Güzenlik sebebiyle bu script sadece yeni ve değiştirilmemiş bir Dokuwiki kurulumunda çalışır. Ya indirdiğiniz paketi yeniden açmalı ya da <a href="http://dokuwiki.org/install"> adresindeki Dokuwiki kurulum kılavuzu</a>na bakmalısınız.';
$lang['i_modified'] = 'Güzenlik sebebiyle bu script sadece yeni ve değiştirilmemiş bir Dokuwiki kurulumunda çalışır. Ya indirdiğiniz paketi yeniden açmalı ya da <a href="https://www.dokuwiki.org/install"> adresindeki Dokuwiki kurulum kılavuzu</a>na bakmalısınız.';
$lang['i_funcna'] = '<code>%s</code> PHP fonksiyonu bulunmamaktadır. Barındırma(Hosting) hizmetinde bu özellik kapatılmış olabilir.';
$lang['i_disabled'] = 'Sağlayıcınız tarafından devre dışı bırakılmış.';
$lang['i_phpver'] = '<code>%s</code> PHP sürümü, gereken <code>%s</code> sürümünden daha düşük. PHP kurulumunu yükseltmeniz gerekmektedir.';

View File

@ -224,7 +224,7 @@ $lang['created'] = 'створено';
$lang['restored'] = 'відновлено стару ревізію (%s)';
$lang['external_edit'] = 'зовнішнє редагування';
$lang['summary'] = 'Підсумок змін';
$lang['noflash'] = 'Для перегляду цієї сторінки необхідно встановити <a href="http://www.adobe.com/products/flashplayer/">Adobe Flash Plugin</a>.';
$lang['noflash'] = 'Для перегляду цієї сторінки необхідно встановити <a href="http://get.adobe.com/flashplayer">Adobe Flash Plugin</a>.';
$lang['download'] = 'Завантажити фрагмент';
$lang['tools'] = 'Налаштування';
$lang['user_tools'] = 'Користувальницькькі налаштування';
@ -305,7 +305,7 @@ $lang['i_enableacl'] = 'Дозволити використання AC
$lang['i_superuser'] = 'Суперкористувач';
$lang['i_problems'] = 'Програма установки знайшла декілька проблем, що вказані нижче. Ви не можете продовжити, поки не виправите їх';
$lang['i_modified'] = 'З причин безпеки цей скрипт буде працювати тільки з новою та немодифікованою установкою ДокуВікі.
Вам слід або ще раз розпакувати файли із завантаженого пакету, або звернутися до повної <a href="http://dokuwiki.org/install">інструкції з установки ДокуВікі</a>';
Вам слід або ще раз розпакувати файли із завантаженого пакету, або звернутися до повної <a href="https://www.dokuwiki.org/install">інструкції з установки ДокуВікі</a>';
$lang['i_funcna'] = 'Функція PHP <code>%s</code> не доступна. Можливо, хостинг-провайдер відключив її з якихось причин?';
$lang['i_phpver'] = 'Версія PHP <code>%s</code> менша, ніж необхідно - <code>%s</code>. Необхідно оновити PHP.';
$lang['i_mbfuncoverload'] = 'mbstring.func_overload має бути вимкнена у php.ini щоб запустити DokuWiki.';

View File

@ -212,7 +212,7 @@ $lang['created'] = 'đã tạo';
$lang['restored'] = 'đã khôi phục phiên bản cũ (%s)';
$lang['external_edit'] = 'sửa đổi bên ngoài';
$lang['summary'] = 'Tóm lược sửa đổi';
$lang['noflash'] = 'Cần có <a href="http://www.adobe.com/products/flashplayer/">Adobe Flash Plugin</a> mới có thể xem được nội dung này.';
$lang['noflash'] = 'Cần có <a href="http://get.adobe.com/flashplayer">Adobe Flash Plugin</a> mới có thể xem được nội dung này.';
$lang['download'] = 'Tải xuống đoạn trích';
$lang['tools'] = 'Công cụ';
$lang['user_tools'] = 'Công cụ thành viên';
@ -294,10 +294,10 @@ $lang['i_superuser'] = 'Siêu thành viên';
$lang['i_problems'] = 'Trình cài đặt tìm thấy một số vấn đề, được chỉ ra bên dưới. Bạn không thể tiếp tục cho đến khi bạn đã sửa chúng.';
$lang['i_modified'] = ' do bảo mật, tập lệnh này sẽ chỉ hoạt động với bản cài đặt Dokuwiki mới chưa được sửa đổi.
Bạn nên trích xuất lại các tập tin từ gói đã tải xuống hoặc tham khảo
<a href="http://dokuwiki.org/install">Hướng dẫn cài đặt Dokuwiki</a> đầy đủ';
<a href="https://www.dokuwiki.org/install">Hướng dẫn cài đặt Dokuwiki</a> đầy đủ';
$lang['i_funcna'] = 'Hàm PHP <code>%s</code> không có sẵn. Có lẽ nhà cung cấp dịch vụ lưu trữ của bạn đã vô hiệu hóa nó vì một số lý do?';
$lang['i_disabled'] = 'Nó đã bị vô hiệu hóa bởi nhà cung cấp của bạn.';
$lang['i_funcnmail'] = '<b>Lưu ý:</b> Không có sẵn hàm PHP mail. %s Nếu nó vẫn không có sẵn, bạn có thể cài đặt <a href="http://dokuwiki.org/plugins/smtp">smtp plugin</a>.';
$lang['i_funcnmail'] = '<b>Lưu ý:</b> Không có sẵn hàm PHP mail. %s Nếu nó vẫn không có sẵn, bạn có thể cài đặt <a href="https://www.dokuwiki.org/plugin:smtp">smtp plugin</a>.';
$lang['i_phpver'] = 'Phiên bản PHP <code>%s</code> hiện taị thấp hơn mức <code>%s</code> cần thiết. Bạn cần nâng cấp cài đặt PHP của bạn.';
$lang['i_mbfuncoverload'] = 'mbopes.func_overload phải bị vô hiệu trong php.ini để chạy DokuWiki.';
$lang['i_urandom'] = 'DokuWiki không thể tạo số mật mã an toàn cho cookie. Bạn có thể muốn kiểm tra cài đặt open_basingir trong php.ini để truy cập <code>/dev/urandom</code> thích hợp.';

View File

@ -210,7 +210,7 @@ $lang['created'] = '建立';
$lang['restored'] = '還原成舊版 (%s)';
$lang['external_edit'] = '外部編輯';
$lang['summary'] = '編輯摘要';
$lang['noflash'] = '顯示此內容需要 <a href="http://www.adobe.com/products/flashplayer/">Adobe Flash 附加元件</a>。';
$lang['noflash'] = '顯示此內容需要 <a href="http://get.adobe.com/flashplayer">Adobe Flash 附加元件</a>。';
$lang['download'] = '下載程式碼片段';
$lang['tools'] = '工具';
$lang['user_tools'] = '使用者工具';
@ -291,7 +291,7 @@ $lang['i_enableacl'] = '啟用 ACL (建議)';
$lang['i_superuser'] = '超級使用者';
$lang['i_problems'] = '安裝程式發現如下的問題。您必須修正它們才能繼續。';
$lang['i_modified'] = '出於安全考量,本腳本只能用於安裝全新且未修改的 Dokuwiki。
您可以重新解壓下載的封包或查閱完整的<a href=\"http://dokuwiki.org/install\">Dokuwiki 安裝指南</a>';
您可以重新解壓下載的封包或查閱完整的<a href=\"https://www.dokuwiki.org/install\">Dokuwiki 安裝指南</a>';
$lang['i_funcna'] = 'PHP 函數 <code>%s</code> 無法使用。也許您的主機供應者基於某些理由停用了它?';
$lang['i_phpver'] = '您的 PHP 版本 <code>%s</code> 比需要的版本 <code>%s</code> 還低。您必須更新您的PHP。';
$lang['i_permfail'] = '<code>%s</code> 無法經由 DokuWiki 寫入。您必須修正該目錄的權限!';

View File

@ -567,11 +567,11 @@ function media_upload_finish($fn_tmp, $fn, $id, $imime, $overwrite, $move = 'mov
* @param string $id
* @return int - revision date
*/
function media_saveOldRevision($id){
function media_saveOldRevision($id) {
global $conf, $lang;
$oldf = mediaFN($id);
if(!file_exists($oldf)) return '';
if (!file_exists($oldf)) return '';
$date = filemtime($oldf);
if (!$conf['mediarevisions']) return $date;
@ -592,9 +592,9 @@ function media_saveOldRevision($id){
}
}
$newf = mediaFN($id,$date);
$newf = mediaFN($id, $date);
io_makeFileDir($newf);
if(copy($oldf, $newf)) {
if (copy($oldf, $newf)) {
// Set the correct permission here.
// Always chmod media because they may be saved with different permissions than expected from the php umask.
// (Should normally chmod to $conf['fperm'] only if $conf['fperm'] is set.)
@ -997,10 +997,10 @@ function media_tab_history($image, $ns, $auth=null) {
if ($auth >= AUTH_READ && $image) {
if ($do == 'diff'){
media_diff($image, $ns, $auth);
(new dokuwiki\Ui\MediaDiff($image))->show(); //media_diff($image, $ns, $auth);
} else {
$first = $INPUT->int('first');
html_revisions($first, $image);
(new dokuwiki\Ui\MediaRevisions($image))->show($first);
}
} else {
echo '<div class="nothing">'.$lang['media_perm_read'].'</div>'.NL;
@ -1017,7 +1017,7 @@ function media_tab_history($image, $ns, $auth=null) {
*
* @author Kate Arzamastseva <pshns@ukr.net>
*/
function media_preview($image, $auth, $rev='', $meta=false) {
function media_preview($image, $auth, $rev = '', $meta = false) {
$size = media_image_preview_size($image, $rev, $meta);
@ -1041,7 +1041,7 @@ function media_preview($image, $auth, $rev='', $meta=false) {
echo '<img src="'.$src.'" alt="" style="max-width: '.$size[0].'px;" />';
echo '</a>';
echo '</div>'.NL;
echo '</div>';
}
}
@ -1052,12 +1052,12 @@ function media_preview($image, $auth, $rev='', $meta=false) {
*
* @param string $image media id
* @param int $auth permission level
* @param string|int $rev revision timestamp, or empty string
* @param int|string $rev revision timestamp, or empty string
*/
function media_preview_buttons($image, $auth, $rev = '') {
global $lang, $conf;
echo '<ul class="actions">'.DOKU_LF;
echo '<ul class="actions">';
if ($auth >= AUTH_DELETE && !$rev && file_exists(mediaFN($image))) {
@ -1071,7 +1071,7 @@ function media_preview_buttons($image, $auth, $rev = '') {
$form->addTagClose('div');
echo '<li>';
echo $form->toHTML();
echo '</li>'.DOKU_LF;
echo '</li>';
}
$auth_ow = (($conf['mediarevisions']) ? AUTH_UPLOAD : AUTH_DELETE);
@ -1087,7 +1087,7 @@ function media_preview_buttons($image, $auth, $rev = '') {
$form->addTagClose('div');
echo '<li>';
echo $form->toHTML();
echo '</li>'.DOKU_LF;
echo '</li>';
}
if ($auth >= AUTH_UPLOAD && $rev && $conf['mediarevisions'] && file_exists(mediaFN($image, $rev))) {
@ -1104,10 +1104,10 @@ function media_preview_buttons($image, $auth, $rev = '') {
$form->addTagClose('div');
echo '<li>';
echo $form->toHTML();
echo '</li>'.DOKU_LF;
echo '</li>';
}
echo '</ul>'.DOKU_LF;
echo '</ul>';
}
/**
@ -1118,16 +1118,18 @@ function media_preview_buttons($image, $auth, $rev = '') {
* @param int|string $rev
* @param JpegMeta|bool $meta
* @param int $size
* @return array|false
* @return array
*/
function media_image_preview_size($image, $rev, $meta, $size = 500) {
if (!preg_match("/\.(jpe?g|gif|png)$/", $image) || !file_exists(mediaFN($image, $rev))) return false;
function media_image_preview_size($image, $rev, $meta = false, $size = 500) {
if (!preg_match("/\.(jpe?g|gif|png)$/", $image)
|| !file_exists($filename = mediaFN($image, $rev))
) return array();
$info = getimagesize(mediaFN($image, $rev));
$info = getimagesize($filename);
$w = (int) $info[0];
$h = (int) $info[1];
if($meta && ($w > $size || $h > $size)){
if ($meta && ($w > $size || $h > $size)) {
$ratio = $meta->getResizeRatio($size, $size);
$w = floor($w * $ratio);
$h = floor($h * $ratio);
@ -1145,10 +1147,10 @@ function media_image_preview_size($image, $rev, $meta, $size = 500) {
* @param string $alt alternative value
* @return string
*/
function media_getTag($tags,$meta,$alt=''){
if($meta === false) return $alt;
function media_getTag($tags, $meta = false, $alt = '') {
if (!$meta) return $alt;
$info = $meta->getField($tags);
if($info == false) return $alt;
if (!$info) return $alt;
return $info;
}
@ -1163,19 +1165,19 @@ function media_getTag($tags,$meta,$alt=''){
function media_file_tags($meta) {
// load the field descriptions
static $fields = null;
if(is_null($fields)){
if (is_null($fields)) {
$config_files = getConfigFiles('mediameta');
foreach ($config_files as $config_file) {
if(file_exists($config_file)) include($config_file);
if (file_exists($config_file)) include($config_file);
}
}
$tags = array();
foreach($fields as $key => $tag){
foreach ($fields as $key => $tag) {
$t = array();
if (!empty($tag[0])) $t = array($tag[0]);
if(isset($tag[3]) && is_array($tag[3])) $t = array_merge($t,$tag[3]);
if (isset($tag[3]) && is_array($tag[3])) $t = array_merge($t,$tag[3]);
$value = media_getTag($t, $meta);
$tags[] = array('tag' => $tag, 'value' => $value);
}
@ -1234,65 +1236,10 @@ function media_details($image, $auth, $rev='', $meta=false) {
* @param int $auth permission level
* @param bool $fromajax
* @return false|null|string
* @deprecated 2020-12-31
*/
function media_diff($image, $ns, $auth, $fromajax = false) {
global $conf;
global $INPUT;
if ($auth < AUTH_READ || !$image || !$conf['mediarevisions']) return '';
$rev1 = $INPUT->int('rev');
$rev2 = $INPUT->ref('rev2');
if(is_array($rev2)){
$rev1 = (int) $rev2[0];
$rev2 = (int) $rev2[1];
if(!$rev1){
$rev1 = $rev2;
unset($rev2);
}
}else{
$rev2 = $INPUT->int('rev2');
}
if ($rev1 && !file_exists(mediaFN($image, $rev1))) $rev1 = false;
if ($rev2 && !file_exists(mediaFN($image, $rev2))) $rev2 = false;
if($rev1 && $rev2){ // two specific revisions wanted
// make sure order is correct (older on the left)
if($rev1 < $rev2){
$l_rev = $rev1;
$r_rev = $rev2;
}else{
$l_rev = $rev2;
$r_rev = $rev1;
}
}elseif($rev1){ // single revision given, compare to current
$r_rev = '';
$l_rev = $rev1;
}else{ // no revision was given, compare previous to current
$r_rev = '';
$medialog = new MediaChangeLog($image);
$revs = $medialog->getRevisions(0, 1);
if (file_exists(mediaFN($image, $revs[0]))) {
$l_rev = $revs[0];
} else {
$l_rev = '';
}
}
// prepare event data
$data = array();
$data[0] = $image;
$data[1] = $l_rev;
$data[2] = $r_rev;
$data[3] = $ns;
$data[4] = $auth;
$data[5] = $fromajax;
// trigger event
return Event::createAndTrigger('MEDIA_DIFF', $data, '_media_file_diff', true);
dbg_deprecated('see '. \dokuwiki\Ui\MediaDiff::class .'::show()');
}
/**
@ -1300,13 +1247,10 @@ function media_diff($image, $ns, $auth, $fromajax = false) {
*
* @param array $data event data
* @return false|null
* @deprecated 2020-12-31
*/
function _media_file_diff($data) {
if(is_array($data) && count($data)===6) {
media_file_diff($data[0], $data[1], $data[2], $data[3], $data[4], $data[5]);
} else {
return false;
}
dbg_deprecated('see '. \dokuwiki\Ui\MediaDiff::class .'::show()');
}
/**
@ -1320,120 +1264,10 @@ function _media_file_diff($data) {
* @param string $ns
* @param int $auth permission level
* @param bool $fromajax
* @deprecated 2020-12-31
*/
function media_file_diff($image, $l_rev, $r_rev, $ns, $auth, $fromajax) {
global $lang;
global $INPUT;
$l_meta = new JpegMeta(mediaFN($image, $l_rev));
$r_meta = new JpegMeta(mediaFN($image, $r_rev));
$is_img = preg_match('/\.(jpe?g|gif|png)$/', $image);
if ($is_img) {
$l_size = media_image_preview_size($image, $l_rev, $l_meta);
$r_size = media_image_preview_size($image, $r_rev, $r_meta);
$is_img = ($l_size && $r_size && ($l_size[0] >= 30 || $r_size[0] >= 30));
$difftype = $INPUT->str('difftype');
if (!$fromajax) {
$form = new Form([
'id' => 'mediamanager__form_diffview',
'action' => media_managerURL([], '&'),
'method' => 'get',
'class' => 'diffView',
]);
$form->addTagOpen('div')->addClass('no');
$form->setHiddenField('sectok', null);
$form->setHiddenField('mediado', 'diff');
$form->setHiddenField('rev2[0]', $l_rev);
$form->setHiddenField('rev2[1]', $r_rev);
echo $form->toHTML();
echo NL.'<div id="mediamanager__diff" >'.NL;
}
if ($difftype == 'opacity' || $difftype == 'portions') {
media_image_diff($image, $l_rev, $r_rev, $l_size, $r_size, $difftype);
if (!$fromajax) echo '</div>';
return;
}
}
list($l_head, $r_head) = (new dokuwiki\Ui\Diff)->diffHead($l_rev, $r_rev, $image, true);
?>
<div class="table">
<table>
<tr>
<th><?php echo $l_head; ?></th>
<th><?php echo $r_head; ?></th>
</tr>
<?php
echo '<tr class="image">';
echo '<td>';
media_preview($image, $auth, $l_rev, $l_meta);
echo '</td>';
echo '<td>';
media_preview($image, $auth, $r_rev, $r_meta);
echo '</td>';
echo '</tr>'.NL;
echo '<tr class="actions">';
echo '<td>';
media_preview_buttons($image, $auth, $l_rev);
echo '</td>';
echo '<td>';
media_preview_buttons($image, $auth, $r_rev);
echo '</td>';
echo '</tr>'.NL;
$l_tags = media_file_tags($l_meta);
$r_tags = media_file_tags($r_meta);
// FIXME r_tags-only stuff
foreach ($l_tags as $key => $l_tag) {
if ($l_tag['value'] != $r_tags[$key]['value']) {
$r_tags[$key]['highlighted'] = true;
$l_tags[$key]['highlighted'] = true;
} else if (!$l_tag['value'] || !$r_tags[$key]['value']) {
unset($r_tags[$key]);
unset($l_tags[$key]);
}
}
echo '<tr>';
foreach(array($l_tags,$r_tags) as $tags){
echo '<td>'.NL;
echo '<dl class="img_tags">';
foreach($tags as $tag){
$value = cleanText($tag['value']);
if (!$value) $value = '-';
echo '<dt>'.$lang[$tag['tag'][1]].'</dt>';
echo '<dd>';
if ($tag['highlighted']) {
echo '<strong>';
}
if ($tag['tag'][2] == 'date') echo dformat($value);
else echo hsc($value);
if ($tag['highlighted']) {
echo '</strong>';
}
echo '</dd>';
}
echo '</dl>'.NL;
echo '</td>';
}
echo '</tr>'.NL;
echo '</table>'.NL;
echo '</div>'.NL;
if ($is_img && !$fromajax) echo '</div>';
dbg_deprecated('see '. \dokuwiki\Ui\MediaDiff::class .'::showFileDiff()');
}
/**
@ -1448,32 +1282,10 @@ function media_file_diff($image, $l_rev, $r_rev, $ns, $auth, $fromajax) {
* @param array $l_size array with width and height
* @param array $r_size array with width and height
* @param string $type
* @deprecated 2020-12-31
*/
function media_image_diff($image, $l_rev, $r_rev, $l_size, $r_size, $type) {
if ($l_size != $r_size) {
if ($r_size[0] > $l_size[0]) {
$l_size = $r_size;
}
}
$l_more = array('rev' => $l_rev, 'h' => $l_size[1], 'w' => $l_size[0]);
$r_more = array('rev' => $r_rev, 'h' => $l_size[1], 'w' => $l_size[0]);
$l_src = ml($image, $l_more);
$r_src = ml($image, $r_more);
// slider
echo '<div class="slider" style="max-width: '.($l_size[0]-20).'px;" ></div>'.NL;
// two images in divs
echo '<div class="imageDiff ' . $type . '">'.NL;
echo '<div class="image1" style="max-width: '.$l_size[0].'px;">';
echo '<img src="'.$l_src.'" alt="" />';
echo '</div>'.NL;
echo '<div class="image2" style="max-width: '.$l_size[0].'px;">';
echo '<img src="'.$r_src.'" alt="" />';
echo '</div>'.NL;
echo '</div>'.NL;
dbg_deprecated('see '. \dokuwiki\Ui\MediaDiff::class .'::showImageDiff()');
}
/**

Some files were not shown because too many files have changed in this diff Show More