mirror of
https://github.com/php/web-wiki.git
synced 2026-03-23 23:12:22 +01:00
Update to 2024-02-06a "Kaos"
This commit is contained in:
@@ -4,7 +4,7 @@ at https://www.dokuwiki.org/
|
||||
For Installation Instructions see
|
||||
https://www.dokuwiki.org/install
|
||||
|
||||
DokuWiki - 2004-2020 (c) Andreas Gohr <andi@splitbrain.org>
|
||||
DokuWiki - 2004-2024 (c) Andreas Gohr <andi@splitbrain.org>
|
||||
and the DokuWiki Community
|
||||
See COPYING and file headers for license info
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ We try to fix vulnerabilites as fast as possible, but please keep in mind that t
|
||||
|
||||
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)
|
||||
* Use [huntr.dev](https://www.huntr.dev/repos/dokuwiki/dokuwiki)
|
||||
* Send an e-mail to [Andi](mailto:andi@splitbrain.org)
|
||||
* Open a [Github Issue](https://github.com/splitbrain/dokuwiki/issues)
|
||||
* Open a [Github Issue](https://github.com/dokuwiki/dokuwiki/issues)
|
||||
* Send a mail to the [Mailing List](https://www.dokuwiki.org/mailinglist)
|
||||
|
||||
@@ -1 +1 @@
|
||||
2022-07-31b "Igor"
|
||||
2024-02-06a "Kaos"
|
||||
|
||||
@@ -3,16 +3,17 @@
|
||||
|
||||
use splitbrain\phpcli\CLI;
|
||||
use splitbrain\phpcli\Options;
|
||||
use dokuwiki\Utf8\PhpString;
|
||||
|
||||
if(!defined('DOKU_INC')) define('DOKU_INC', realpath(dirname(__FILE__) . '/../') . '/');
|
||||
if (!defined('DOKU_INC')) define('DOKU_INC', realpath(__DIR__ . '/../') . '/');
|
||||
define('NOSESSION', 1);
|
||||
require_once(DOKU_INC . 'inc/init.php');
|
||||
|
||||
/**
|
||||
* Checkout and commit pages from the command line while maintaining the history
|
||||
*/
|
||||
class PageCLI extends CLI {
|
||||
|
||||
class PageCLI extends CLI
|
||||
{
|
||||
protected $force = false;
|
||||
protected $username = '';
|
||||
|
||||
@@ -22,7 +23,8 @@ class PageCLI extends CLI {
|
||||
* @param Options $options
|
||||
* @return void
|
||||
*/
|
||||
protected function setup(Options $options) {
|
||||
protected function setup(Options $options)
|
||||
{
|
||||
/* global */
|
||||
$options->registerOption(
|
||||
'force',
|
||||
@@ -133,7 +135,7 @@ class PageCLI extends CLI {
|
||||
$options->registerArgument(
|
||||
'key',
|
||||
'The name of the metadata item to be retrieved.' . "\n" .
|
||||
'If empty, an array of all the metadata items is returned.' ."\n" .
|
||||
'If empty, an array of all the metadata items is returned.' . "\n" .
|
||||
'For retrieving items that are stored in sub-arrays, separate the ' .
|
||||
'keys of the different levels by spaces, in quotes, eg "date modified".',
|
||||
false,
|
||||
@@ -149,13 +151,14 @@ class PageCLI extends CLI {
|
||||
* @param Options $options
|
||||
* @return void
|
||||
*/
|
||||
protected function main(Options $options) {
|
||||
protected function main(Options $options)
|
||||
{
|
||||
$this->force = $options->getOpt('force', false);
|
||||
$this->username = $options->getOpt('user', $this->getUser());
|
||||
|
||||
$command = $options->getCmd();
|
||||
$args = $options->getArgs();
|
||||
switch($command) {
|
||||
switch ($command) {
|
||||
case 'checkout':
|
||||
$wiki_id = array_shift($args);
|
||||
$localfile = array_shift($args);
|
||||
@@ -199,31 +202,32 @@ class PageCLI extends CLI {
|
||||
* @param string $wiki_id
|
||||
* @param string $localfile
|
||||
*/
|
||||
protected function commandCheckout($wiki_id, $localfile) {
|
||||
protected function commandCheckout($wiki_id, $localfile)
|
||||
{
|
||||
global $conf;
|
||||
|
||||
$wiki_id = cleanID($wiki_id);
|
||||
$wiki_fn = wikiFN($wiki_id);
|
||||
|
||||
if(!file_exists($wiki_fn)) {
|
||||
if (!file_exists($wiki_fn)) {
|
||||
$this->fatal("$wiki_id does not yet exist");
|
||||
}
|
||||
|
||||
if(empty($localfile)) {
|
||||
$localfile = getcwd() . '/' . \dokuwiki\Utf8\PhpString::basename($wiki_fn);
|
||||
if (empty($localfile)) {
|
||||
$localfile = getcwd() . '/' . PhpString::basename($wiki_fn);
|
||||
}
|
||||
|
||||
if(!file_exists(dirname($localfile))) {
|
||||
if (!file_exists(dirname($localfile))) {
|
||||
$this->fatal("Directory " . dirname($localfile) . " does not exist");
|
||||
}
|
||||
|
||||
if(stristr(realpath(dirname($localfile)), realpath($conf['datadir'])) !== false) {
|
||||
if (stristr(realpath(dirname($localfile)), (string) realpath($conf['datadir'])) !== false) {
|
||||
$this->fatal("Attempt to check out file into data directory - not allowed");
|
||||
}
|
||||
|
||||
$this->obtainLock($wiki_id);
|
||||
|
||||
if(!copy($wiki_fn, $localfile)) {
|
||||
if (!copy($wiki_fn, $localfile)) {
|
||||
$this->clearLock($wiki_id);
|
||||
$this->fatal("Unable to copy $wiki_fn to $localfile");
|
||||
}
|
||||
@@ -239,19 +243,20 @@ class PageCLI extends CLI {
|
||||
* @param string $message
|
||||
* @param bool $minor
|
||||
*/
|
||||
protected function commandCommit($localfile, $wiki_id, $message, $minor) {
|
||||
protected function commandCommit($localfile, $wiki_id, $message, $minor)
|
||||
{
|
||||
$wiki_id = cleanID($wiki_id);
|
||||
$message = trim($message);
|
||||
|
||||
if(!file_exists($localfile)) {
|
||||
if (!file_exists($localfile)) {
|
||||
$this->fatal("$localfile does not exist");
|
||||
}
|
||||
|
||||
if(!is_readable($localfile)) {
|
||||
if (!is_readable($localfile)) {
|
||||
$this->fatal("Cannot read from $localfile");
|
||||
}
|
||||
|
||||
if(!$message) {
|
||||
if (!$message) {
|
||||
$this->fatal("Summary message required");
|
||||
}
|
||||
|
||||
@@ -269,19 +274,20 @@ class PageCLI extends CLI {
|
||||
*
|
||||
* @param string $wiki_id
|
||||
*/
|
||||
protected function obtainLock($wiki_id) {
|
||||
if($this->force) $this->deleteLock($wiki_id);
|
||||
protected function obtainLock($wiki_id)
|
||||
{
|
||||
if ($this->force) $this->deleteLock($wiki_id);
|
||||
|
||||
$_SERVER['REMOTE_USER'] = $this->username;
|
||||
|
||||
if(checklock($wiki_id)) {
|
||||
if (checklock($wiki_id)) {
|
||||
$this->error("Page $wiki_id is already locked by another user");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
lock($wiki_id);
|
||||
|
||||
if(checklock($wiki_id)) {
|
||||
if (checklock($wiki_id)) {
|
||||
$this->error("Unable to obtain lock for $wiki_id ");
|
||||
var_dump(checklock($wiki_id));
|
||||
exit(1);
|
||||
@@ -293,18 +299,19 @@ class PageCLI extends CLI {
|
||||
*
|
||||
* @param string $wiki_id
|
||||
*/
|
||||
protected function clearLock($wiki_id) {
|
||||
if($this->force) $this->deleteLock($wiki_id);
|
||||
protected function clearLock($wiki_id)
|
||||
{
|
||||
if ($this->force) $this->deleteLock($wiki_id);
|
||||
|
||||
$_SERVER['REMOTE_USER'] = $this->username;
|
||||
if(checklock($wiki_id)) {
|
||||
if (checklock($wiki_id)) {
|
||||
$this->error("Page $wiki_id is locked by another user");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
unlock($wiki_id);
|
||||
|
||||
if(file_exists(wikiLockFN($wiki_id))) {
|
||||
if (file_exists(wikiLockFN($wiki_id))) {
|
||||
$this->error("Unable to clear lock for $wiki_id");
|
||||
exit(1);
|
||||
}
|
||||
@@ -315,11 +322,12 @@ class PageCLI extends CLI {
|
||||
*
|
||||
* @param string $wiki_id
|
||||
*/
|
||||
protected function deleteLock($wiki_id) {
|
||||
protected function deleteLock($wiki_id)
|
||||
{
|
||||
$wikiLockFN = wikiLockFN($wiki_id);
|
||||
|
||||
if(file_exists($wikiLockFN)) {
|
||||
if(!unlink($wikiLockFN)) {
|
||||
if (file_exists($wikiLockFN)) {
|
||||
if (!unlink($wikiLockFN)) {
|
||||
$this->error("Unable to delete $wikiLockFN");
|
||||
exit(1);
|
||||
}
|
||||
@@ -331,14 +339,15 @@ class PageCLI extends CLI {
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getUser() {
|
||||
protected function getUser()
|
||||
{
|
||||
$user = getenv('USER');
|
||||
if(empty ($user)) {
|
||||
if (empty($user)) {
|
||||
$user = getenv('USERNAME');
|
||||
} else {
|
||||
return $user;
|
||||
}
|
||||
if(empty ($user)) {
|
||||
if (empty($user)) {
|
||||
$user = 'admin';
|
||||
}
|
||||
return $user;
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
use splitbrain\phpcli\CLI;
|
||||
use splitbrain\phpcli\Options;
|
||||
|
||||
if(!defined('DOKU_INC')) define('DOKU_INC', realpath(dirname(__FILE__) . '/../') . '/');
|
||||
if (!defined('DOKU_INC')) define('DOKU_INC', realpath(__DIR__ . '/../') . '/');
|
||||
define('NOSESSION', 1);
|
||||
require_once(DOKU_INC . 'inc/init.php');
|
||||
|
||||
@@ -13,15 +13,16 @@ require_once(DOKU_INC . 'inc/init.php');
|
||||
*
|
||||
* @author Andreas Gohr <andi@splitbrain.org>
|
||||
*/
|
||||
class GitToolCLI extends CLI {
|
||||
|
||||
class GitToolCLI extends CLI
|
||||
{
|
||||
/**
|
||||
* Register options and arguments on the given $options object
|
||||
*
|
||||
* @param Options $options
|
||||
* @return void
|
||||
*/
|
||||
protected function setup(Options $options) {
|
||||
protected function setup(Options $options)
|
||||
{
|
||||
$options->setHelp(
|
||||
"Manage git repositories for DokuWiki and its plugins and templates.\n\n" .
|
||||
"$> ./bin/gittool.php clone gallery template:ach\n" .
|
||||
@@ -79,12 +80,13 @@ class GitToolCLI extends CLI {
|
||||
* @param Options $options
|
||||
* @return void
|
||||
*/
|
||||
protected function main(Options $options) {
|
||||
protected function main(Options $options)
|
||||
{
|
||||
$command = $options->getCmd();
|
||||
$args = $options->getArgs();
|
||||
if(!$command) $command = array_shift($args);
|
||||
if (!$command) $command = array_shift($args);
|
||||
|
||||
switch($command) {
|
||||
switch ($command) {
|
||||
case '':
|
||||
echo $options->help();
|
||||
break;
|
||||
@@ -108,28 +110,27 @@ class GitToolCLI extends CLI {
|
||||
*
|
||||
* @param array $extensions
|
||||
*/
|
||||
public function cmdClone($extensions) {
|
||||
$errors = array();
|
||||
$succeeded = array();
|
||||
public function cmdClone($extensions)
|
||||
{
|
||||
$errors = [];
|
||||
$succeeded = [];
|
||||
|
||||
foreach($extensions as $ext) {
|
||||
foreach ($extensions as $ext) {
|
||||
$repo = $this->getSourceRepo($ext);
|
||||
|
||||
if(!$repo) {
|
||||
if (!$repo) {
|
||||
$this->error("could not find a repository for $ext");
|
||||
$errors[] = $ext;
|
||||
} elseif ($this->cloneExtension($ext, $repo)) {
|
||||
$succeeded[] = $ext;
|
||||
} else {
|
||||
if($this->cloneExtension($ext, $repo)) {
|
||||
$succeeded[] = $ext;
|
||||
} else {
|
||||
$errors[] = $ext;
|
||||
}
|
||||
$errors[] = $ext;
|
||||
}
|
||||
}
|
||||
|
||||
echo "\n";
|
||||
if($succeeded) $this->success('successfully cloned the following extensions: ' . join(', ', $succeeded));
|
||||
if($errors) $this->error('failed to clone the following extensions: ' . join(', ', $errors));
|
||||
if ($succeeded) $this->success('successfully cloned the following extensions: ' . implode(', ', $succeeded));
|
||||
if ($errors) $this->error('failed to clone the following extensions: ' . implode(', ', $errors));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -137,32 +138,31 @@ class GitToolCLI extends CLI {
|
||||
*
|
||||
* @param array $extensions
|
||||
*/
|
||||
public function cmdInstall($extensions) {
|
||||
$errors = array();
|
||||
$succeeded = array();
|
||||
public function cmdInstall($extensions)
|
||||
{
|
||||
$errors = [];
|
||||
$succeeded = [];
|
||||
|
||||
foreach($extensions as $ext) {
|
||||
foreach ($extensions as $ext) {
|
||||
$repo = $this->getSourceRepo($ext);
|
||||
|
||||
if(!$repo) {
|
||||
if (!$repo) {
|
||||
$this->info("could not find a repository for $ext");
|
||||
if($this->downloadExtension($ext)) {
|
||||
if ($this->downloadExtension($ext)) {
|
||||
$succeeded[] = $ext;
|
||||
} else {
|
||||
$errors[] = $ext;
|
||||
}
|
||||
} elseif ($this->cloneExtension($ext, $repo)) {
|
||||
$succeeded[] = $ext;
|
||||
} else {
|
||||
if($this->cloneExtension($ext, $repo)) {
|
||||
$succeeded[] = $ext;
|
||||
} else {
|
||||
$errors[] = $ext;
|
||||
}
|
||||
$errors[] = $ext;
|
||||
}
|
||||
}
|
||||
|
||||
echo "\n";
|
||||
if($succeeded) $this->success('successfully installed the following extensions: ' . join(', ', $succeeded));
|
||||
if($errors) $this->error('failed to install the following extensions: ' . join(', ', $errors));
|
||||
if ($succeeded) $this->success('successfully installed the following extensions: ' . implode(', ', $succeeded));
|
||||
if ($errors) $this->error('failed to install the following extensions: ' . implode(', ', $errors));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -171,15 +171,16 @@ class GitToolCLI extends CLI {
|
||||
* @param $cmd
|
||||
* @param $arg
|
||||
*/
|
||||
public function cmdGit($cmd, $arg) {
|
||||
public function cmdGit($cmd, $arg)
|
||||
{
|
||||
$repos = $this->findRepos();
|
||||
|
||||
$shell = array_merge(array('git', $cmd), $arg);
|
||||
$shell = array_merge(['git', $cmd], $arg);
|
||||
$shell = array_map('escapeshellarg', $shell);
|
||||
$shell = join(' ', $shell);
|
||||
$shell = implode(' ', $shell);
|
||||
|
||||
foreach($repos as $repo) {
|
||||
if(!@chdir($repo)) {
|
||||
foreach ($repos as $repo) {
|
||||
if (!@chdir($repo)) {
|
||||
$this->error("Could not change into $repo");
|
||||
continue;
|
||||
}
|
||||
@@ -188,7 +189,7 @@ class GitToolCLI extends CLI {
|
||||
$ret = 0;
|
||||
system($shell, $ret);
|
||||
|
||||
if($ret == 0) {
|
||||
if ($ret == 0) {
|
||||
$this->success("git succeeded in $repo");
|
||||
} else {
|
||||
$this->error("git failed in $repo");
|
||||
@@ -199,9 +200,10 @@ class GitToolCLI extends CLI {
|
||||
/**
|
||||
* Simply lists the repositories
|
||||
*/
|
||||
public function cmdRepos() {
|
||||
public function cmdRepos()
|
||||
{
|
||||
$repos = $this->findRepos();
|
||||
foreach($repos as $repo) {
|
||||
foreach ($repos as $repo) {
|
||||
echo "$repo\n";
|
||||
}
|
||||
}
|
||||
@@ -212,15 +214,16 @@ class GitToolCLI extends CLI {
|
||||
* @param string $ext
|
||||
* @return bool|null
|
||||
*/
|
||||
private function downloadExtension($ext) {
|
||||
private function downloadExtension($ext)
|
||||
{
|
||||
/** @var helper_plugin_extension_extension $plugin */
|
||||
$plugin = plugin_load('helper', 'extension_extension');
|
||||
if(!$ext) die("extension plugin not available, can't continue");
|
||||
if (!$ext) die("extension plugin not available, can't continue");
|
||||
|
||||
$plugin->setExtension($ext);
|
||||
|
||||
$url = $plugin->getDownloadURL();
|
||||
if(!$url) {
|
||||
if (!$url) {
|
||||
$this->error("no download URL for $ext");
|
||||
return false;
|
||||
}
|
||||
@@ -229,11 +232,11 @@ class GitToolCLI extends CLI {
|
||||
try {
|
||||
$this->info("installing $ext via download from $url");
|
||||
$ok = $plugin->installFromURL($url);
|
||||
} catch(Exception $e) {
|
||||
} catch (Exception $e) {
|
||||
$this->error($e->getMessage());
|
||||
}
|
||||
|
||||
if($ok) {
|
||||
if ($ok) {
|
||||
$this->success("installed $ext via download");
|
||||
return true;
|
||||
} else {
|
||||
@@ -249,8 +252,9 @@ class GitToolCLI extends CLI {
|
||||
* @param string $repo
|
||||
* @return bool
|
||||
*/
|
||||
private function cloneExtension($ext, $repo) {
|
||||
if(substr($ext, 0, 9) == 'template:') {
|
||||
private function cloneExtension($ext, $repo)
|
||||
{
|
||||
if (str_starts_with($ext, 'template:')) {
|
||||
$target = fullpath(tpl_incdir() . '../' . substr($ext, 9));
|
||||
} else {
|
||||
$target = DOKU_PLUGIN . $ext;
|
||||
@@ -259,7 +263,7 @@ class GitToolCLI extends CLI {
|
||||
$this->info("cloning $ext from $repo to $target");
|
||||
$ret = 0;
|
||||
system("git clone $repo $target", $ret);
|
||||
if($ret === 0) {
|
||||
if ($ret === 0) {
|
||||
$this->success("cloning of $ext succeeded");
|
||||
return true;
|
||||
} else {
|
||||
@@ -275,7 +279,8 @@ class GitToolCLI extends CLI {
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function findRepos() {
|
||||
private function findRepos()
|
||||
{
|
||||
$this->info('Looking for .git directories');
|
||||
$data = array_merge(
|
||||
glob(DOKU_INC . '.git', GLOB_ONLYDIR),
|
||||
@@ -283,7 +288,7 @@ class GitToolCLI extends CLI {
|
||||
glob(fullpath(tpl_incdir() . '../') . '/*/.git', GLOB_ONLYDIR)
|
||||
);
|
||||
|
||||
if(!$data) {
|
||||
if (!$data) {
|
||||
$this->error('Found no .git directories');
|
||||
} else {
|
||||
$this->success('Found ' . count($data) . ' .git directories');
|
||||
@@ -298,34 +303,35 @@ class GitToolCLI extends CLI {
|
||||
* @param $extension
|
||||
* @return false|string
|
||||
*/
|
||||
private function getSourceRepo($extension) {
|
||||
private function getSourceRepo($extension)
|
||||
{
|
||||
/** @var helper_plugin_extension_extension $ext */
|
||||
$ext = plugin_load('helper', 'extension_extension');
|
||||
if(!$ext) die("extension plugin not available, can't continue");
|
||||
if (!$ext) die("extension plugin not available, can't continue");
|
||||
|
||||
$ext->setExtension($extension);
|
||||
|
||||
$repourl = $ext->getSourcerepoURL();
|
||||
if(!$repourl) return false;
|
||||
if (!$repourl) return false;
|
||||
|
||||
// match github repos
|
||||
if(preg_match('/github\.com\/([^\/]+)\/([^\/]+)/i', $repourl, $m)) {
|
||||
if (preg_match('/github\.com\/([^\/]+)\/([^\/]+)/i', $repourl, $m)) {
|
||||
$user = $m[1];
|
||||
$repo = $m[2];
|
||||
return 'https://github.com/' . $user . '/' . $repo . '.git';
|
||||
}
|
||||
|
||||
// match gitorious repos
|
||||
if(preg_match('/gitorious.org\/([^\/]+)\/([^\/]+)?/i', $repourl, $m)) {
|
||||
if (preg_match('/gitorious.org\/([^\/]+)\/([^\/]+)?/i', $repourl, $m)) {
|
||||
$user = $m[1];
|
||||
$repo = $m[2];
|
||||
if(!$repo) $repo = $user;
|
||||
if (!$repo) $repo = $user;
|
||||
|
||||
return 'https://git.gitorious.org/' . $user . '/' . $repo . '.git';
|
||||
}
|
||||
|
||||
// match bitbucket repos - most people seem to use mercurial there though
|
||||
if(preg_match('/bitbucket\.org\/([^\/]+)\/([^\/]+)/i', $repourl, $m)) {
|
||||
if (preg_match('/bitbucket\.org\/([^\/]+)\/([^\/]+)/i', $repourl, $m)) {
|
||||
$user = $m[1];
|
||||
$repo = $m[2];
|
||||
return 'https://bitbucket.org/' . $user . '/' . $repo . '.git';
|
||||
|
||||
@@ -4,15 +4,15 @@
|
||||
use splitbrain\phpcli\CLI;
|
||||
use splitbrain\phpcli\Options;
|
||||
|
||||
if(!defined('DOKU_INC')) define('DOKU_INC', realpath(dirname(__FILE__) . '/../') . '/');
|
||||
if (!defined('DOKU_INC')) define('DOKU_INC', realpath(__DIR__ . '/../') . '/');
|
||||
define('NOSESSION', 1);
|
||||
require_once(DOKU_INC . 'inc/init.php');
|
||||
|
||||
/**
|
||||
* Update the Search Index from command line
|
||||
*/
|
||||
class IndexerCLI extends CLI {
|
||||
|
||||
class IndexerCLI extends CLI
|
||||
{
|
||||
private $quiet = false;
|
||||
private $clear = false;
|
||||
|
||||
@@ -22,7 +22,8 @@ class IndexerCLI extends CLI {
|
||||
* @param Options $options
|
||||
* @return void
|
||||
*/
|
||||
protected function setup(Options $options) {
|
||||
protected function setup(Options $options)
|
||||
{
|
||||
$options->setHelp(
|
||||
'Updates the searchindex by indexing all new or changed pages. When the -c option is ' .
|
||||
'given the index is cleared first.'
|
||||
@@ -48,11 +49,12 @@ class IndexerCLI extends CLI {
|
||||
* @param Options $options
|
||||
* @return void
|
||||
*/
|
||||
protected function main(Options $options) {
|
||||
protected function main(Options $options)
|
||||
{
|
||||
$this->clear = $options->getOpt('clear');
|
||||
$this->quiet = $options->getOpt('quiet');
|
||||
|
||||
if($this->clear) $this->clearindex();
|
||||
if ($this->clear) $this->clearindex();
|
||||
|
||||
$this->update();
|
||||
}
|
||||
@@ -60,14 +62,15 @@ class IndexerCLI extends CLI {
|
||||
/**
|
||||
* Update the index
|
||||
*/
|
||||
protected function update() {
|
||||
protected function update()
|
||||
{
|
||||
global $conf;
|
||||
$data = array();
|
||||
$data = [];
|
||||
$this->quietecho("Searching pages... ");
|
||||
search($data, $conf['datadir'], 'search_allpages', array('skipacl' => true));
|
||||
search($data, $conf['datadir'], 'search_allpages', ['skipacl' => true]);
|
||||
$this->quietecho(count($data) . " pages found.\n");
|
||||
|
||||
foreach($data as $val) {
|
||||
foreach ($data as $val) {
|
||||
$this->index($val['id']);
|
||||
}
|
||||
}
|
||||
@@ -77,7 +80,8 @@ class IndexerCLI extends CLI {
|
||||
*
|
||||
* @param string $id
|
||||
*/
|
||||
protected function index($id) {
|
||||
protected function index($id)
|
||||
{
|
||||
$this->quietecho("$id... ");
|
||||
idx_addPage($id, !$this->quiet, $this->clear);
|
||||
$this->quietecho("done.\n");
|
||||
@@ -86,7 +90,8 @@ class IndexerCLI extends CLI {
|
||||
/**
|
||||
* Clear all index files
|
||||
*/
|
||||
protected function clearindex() {
|
||||
protected function clearindex()
|
||||
{
|
||||
$this->quietecho("Clearing index... ");
|
||||
idx_get_indexer()->clear();
|
||||
$this->quietecho("done.\n");
|
||||
@@ -97,8 +102,9 @@ class IndexerCLI extends CLI {
|
||||
*
|
||||
* @param string $msg
|
||||
*/
|
||||
protected function quietecho($msg) {
|
||||
if(!$this->quiet) echo $msg;
|
||||
protected function quietecho($msg)
|
||||
{
|
||||
if (!$this->quiet) echo $msg;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,20 +5,23 @@ use dokuwiki\Extension\PluginController;
|
||||
use splitbrain\phpcli\CLI;
|
||||
use splitbrain\phpcli\Colors;
|
||||
use splitbrain\phpcli\Options;
|
||||
use dokuwiki\Extension\CLIPlugin;
|
||||
use splitbrain\phpcli\TableFormatter;
|
||||
|
||||
if(!defined('DOKU_INC')) define('DOKU_INC', realpath(dirname(__FILE__) . '/../') . '/');
|
||||
if (!defined('DOKU_INC')) define('DOKU_INC', realpath(__DIR__ . '/../') . '/');
|
||||
define('NOSESSION', 1);
|
||||
require_once(DOKU_INC . 'inc/init.php');
|
||||
|
||||
class PluginCLI extends CLI {
|
||||
|
||||
class PluginCLI extends CLI
|
||||
{
|
||||
/**
|
||||
* Register options and arguments on the given $options object
|
||||
*
|
||||
* @param Options $options
|
||||
* @return void
|
||||
*/
|
||||
protected function setup(Options $options) {
|
||||
protected function setup(Options $options)
|
||||
{
|
||||
$options->setHelp('Excecutes Plugin command line tools');
|
||||
$options->registerArgument('plugin', 'The plugin CLI you want to run. Leave off to see list', false);
|
||||
}
|
||||
@@ -31,13 +34,14 @@ class PluginCLI extends CLI {
|
||||
* @param Options $options
|
||||
* @return void
|
||||
*/
|
||||
protected function main(Options $options) {
|
||||
protected function main(Options $options)
|
||||
{
|
||||
global $argv;
|
||||
$argv = $options->getArgs();
|
||||
|
||||
if($argv) {
|
||||
if ($argv) {
|
||||
$plugin = $this->loadPlugin($argv[0]);
|
||||
if($plugin !== null) {
|
||||
if ($plugin instanceof CLIPlugin) {
|
||||
$plugin->run();
|
||||
} else {
|
||||
$this->fatal('Command {cmd} not found.', ['cmd' => $argv[0]]);
|
||||
@@ -51,7 +55,8 @@ class PluginCLI extends CLI {
|
||||
/**
|
||||
* List available plugins
|
||||
*/
|
||||
protected function listPlugins() {
|
||||
protected function listPlugins()
|
||||
{
|
||||
/** @var PluginController $plugin_controller */
|
||||
global $plugin_controller;
|
||||
|
||||
@@ -62,21 +67,20 @@ class PluginCLI extends CLI {
|
||||
|
||||
$list = $plugin_controller->getList('cli');
|
||||
sort($list);
|
||||
if(!count($list)) {
|
||||
if ($list === []) {
|
||||
echo $this->colors->wrap(" No plugins providing CLI components available\n", Colors::C_RED);
|
||||
} else {
|
||||
$tf = new \splitbrain\phpcli\TableFormatter($this->colors);
|
||||
$tf = new TableFormatter($this->colors);
|
||||
|
||||
foreach($list as $name) {
|
||||
foreach ($list as $name) {
|
||||
$plugin = $this->loadPlugin($name);
|
||||
if($plugin === null) continue;
|
||||
if (!$plugin instanceof CLIPlugin) continue;
|
||||
$info = $plugin->getInfo();
|
||||
|
||||
echo $tf->format(
|
||||
[2, '30%', '*'],
|
||||
['', $name, $info['desc']],
|
||||
['', Colors::C_CYAN, '']
|
||||
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -86,12 +90,15 @@ class PluginCLI extends CLI {
|
||||
* Instantiate a CLI plugin
|
||||
*
|
||||
* @param string $name
|
||||
* @return \dokuwiki\Extension\CLIPlugin|null
|
||||
* @return CLIPlugin|null
|
||||
*/
|
||||
protected function loadPlugin($name) {
|
||||
protected function loadPlugin($name)
|
||||
{
|
||||
if (plugin_isdisabled($name)) return null;
|
||||
|
||||
// execute the plugin CLI
|
||||
$class = "cli_plugin_$name";
|
||||
if(class_exists($class)) {
|
||||
if (class_exists($class)) {
|
||||
return new $class();
|
||||
}
|
||||
return null;
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
use splitbrain\phpcli\CLI;
|
||||
use splitbrain\phpcli\Options;
|
||||
|
||||
if(!defined('DOKU_INC')) define('DOKU_INC', realpath(dirname(__FILE__) . '/../') . '/');
|
||||
if (!defined('DOKU_INC')) define('DOKU_INC', realpath(__DIR__ . '/../') . '/');
|
||||
define('NOSESSION', 1);
|
||||
require_once(DOKU_INC . 'inc/init.php');
|
||||
|
||||
@@ -19,15 +19,16 @@ require_once(DOKU_INC . 'inc/init.php');
|
||||
* @license GPL2
|
||||
* @author Andreas Gohr <andi@splitbrain.org>
|
||||
*/
|
||||
class RenderCLI extends CLI {
|
||||
|
||||
class RenderCLI extends CLI
|
||||
{
|
||||
/**
|
||||
* Register options and arguments on the given $options object
|
||||
*
|
||||
* @param Options $options
|
||||
* @return void
|
||||
*/
|
||||
protected function setup(Options $options) {
|
||||
protected function setup(Options $options)
|
||||
{
|
||||
$options->setHelp(
|
||||
'A simple commandline tool to render some DokuWiki syntax with a given renderer.' .
|
||||
"\n\n" .
|
||||
@@ -47,14 +48,15 @@ class RenderCLI extends CLI {
|
||||
* @throws DokuCLI_Exception
|
||||
* @return void
|
||||
*/
|
||||
protected function main(Options $options) {
|
||||
protected function main(Options $options)
|
||||
{
|
||||
$renderer = $options->getOpt('renderer', 'xhtml');
|
||||
|
||||
// do the action
|
||||
$source = stream_get_contents(STDIN);
|
||||
$info = array();
|
||||
$info = [];
|
||||
$result = p_render($renderer, p_get_instructions($source), $info);
|
||||
if(is_null($result)) throw new DokuCLI_Exception("No such renderer $renderer");
|
||||
if (is_null($result)) throw new DokuCLI_Exception("No such renderer $renderer");
|
||||
echo $result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,22 +4,23 @@
|
||||
use splitbrain\phpcli\CLI;
|
||||
use splitbrain\phpcli\Options;
|
||||
|
||||
if(!defined('DOKU_INC')) define('DOKU_INC', realpath(dirname(__FILE__) . '/../') . '/');
|
||||
if (!defined('DOKU_INC')) define('DOKU_INC', realpath(__DIR__ . '/../') . '/');
|
||||
define('NOSESSION', 1);
|
||||
require_once(DOKU_INC . 'inc/init.php');
|
||||
|
||||
/**
|
||||
* Remove unwanted languages from a DokuWiki install
|
||||
*/
|
||||
class StripLangsCLI extends CLI {
|
||||
|
||||
class StripLangsCLI extends CLI
|
||||
{
|
||||
/**
|
||||
* Register options and arguments on the given $options object
|
||||
*
|
||||
* @param Options $options
|
||||
* @return void
|
||||
*/
|
||||
protected function setup(Options $options) {
|
||||
protected function setup(Options $options)
|
||||
{
|
||||
|
||||
$options->setHelp(
|
||||
'Remove all languages from the installation, besides the ones specified. English language ' .
|
||||
@@ -47,21 +48,22 @@ class StripLangsCLI extends CLI {
|
||||
* @param Options $options
|
||||
* @return void
|
||||
*/
|
||||
protected function main(Options $options) {
|
||||
if($options->getOpt('keep')) {
|
||||
protected function main(Options $options)
|
||||
{
|
||||
if ($options->getOpt('keep')) {
|
||||
$keep = explode(',', $options->getOpt('keep'));
|
||||
if(!in_array('en', $keep)) $keep[] = 'en';
|
||||
} elseif($options->getOpt('english-only')) {
|
||||
$keep = array('en');
|
||||
if (!in_array('en', $keep)) $keep[] = 'en';
|
||||
} elseif ($options->getOpt('english-only')) {
|
||||
$keep = ['en'];
|
||||
} else {
|
||||
echo $options->help();
|
||||
exit(0);
|
||||
}
|
||||
|
||||
// Kill all language directories in /inc/lang and /lib/plugins besides those in $langs array
|
||||
$this->stripDirLangs(realpath(dirname(__FILE__) . '/../inc/lang'), $keep);
|
||||
$this->processExtensions(realpath(dirname(__FILE__) . '/../lib/plugins'), $keep);
|
||||
$this->processExtensions(realpath(dirname(__FILE__) . '/../lib/tpl'), $keep);
|
||||
$this->stripDirLangs(realpath(__DIR__ . '/../inc/lang'), $keep);
|
||||
$this->processExtensions(realpath(__DIR__ . '/../lib/plugins'), $keep);
|
||||
$this->processExtensions(realpath(__DIR__ . '/../lib/tpl'), $keep);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -70,17 +72,17 @@ class StripLangsCLI extends CLI {
|
||||
* @param string $path path to plugin or template dir
|
||||
* @param array $keep_langs languages to keep
|
||||
*/
|
||||
protected function processExtensions($path, $keep_langs) {
|
||||
if(is_dir($path)) {
|
||||
protected function processExtensions($path, $keep_langs)
|
||||
{
|
||||
if (is_dir($path)) {
|
||||
$entries = scandir($path);
|
||||
|
||||
foreach($entries as $entry) {
|
||||
if($entry != "." && $entry != "..") {
|
||||
if(is_dir($path . '/' . $entry)) {
|
||||
|
||||
foreach ($entries as $entry) {
|
||||
if ($entry != "." && $entry != "..") {
|
||||
if (is_dir($path . '/' . $entry)) {
|
||||
$plugin_langs = $path . '/' . $entry . '/lang';
|
||||
|
||||
if(is_dir($plugin_langs)) {
|
||||
if (is_dir($plugin_langs)) {
|
||||
$this->stripDirLangs($plugin_langs, $keep_langs);
|
||||
}
|
||||
}
|
||||
@@ -95,13 +97,13 @@ class StripLangsCLI extends CLI {
|
||||
* @param string $path path to lang dir
|
||||
* @param array $keep_langs languages to keep
|
||||
*/
|
||||
protected function stripDirLangs($path, $keep_langs) {
|
||||
protected function stripDirLangs($path, $keep_langs)
|
||||
{
|
||||
$dir = dir($path);
|
||||
|
||||
while(($cur_dir = $dir->read()) !== false) {
|
||||
if($cur_dir != '.' and $cur_dir != '..' and is_dir($path . '/' . $cur_dir)) {
|
||||
|
||||
if(!in_array($cur_dir, $keep_langs, true)) {
|
||||
while (($cur_dir = $dir->read()) !== false) {
|
||||
if ($cur_dir != '.' && $cur_dir != '..' && is_dir($path . '/' . $cur_dir)) {
|
||||
if (!in_array($cur_dir, $keep_langs, true)) {
|
||||
io_rmdir($path . '/' . $cur_dir, true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,23 +6,23 @@ use dokuwiki\File\PageResolver;
|
||||
use splitbrain\phpcli\CLI;
|
||||
use splitbrain\phpcli\Options;
|
||||
|
||||
if(!defined('DOKU_INC')) define('DOKU_INC', realpath(dirname(__FILE__) . '/../') . '/');
|
||||
if (!defined('DOKU_INC')) define('DOKU_INC', realpath(__DIR__ . '/../') . '/');
|
||||
define('NOSESSION', 1);
|
||||
require_once(DOKU_INC . 'inc/init.php');
|
||||
|
||||
/**
|
||||
* Find wanted pages
|
||||
*/
|
||||
class WantedPagesCLI extends CLI {
|
||||
|
||||
const DIR_CONTINUE = 1;
|
||||
const DIR_NS = 2;
|
||||
const DIR_PAGE = 3;
|
||||
class WantedPagesCLI extends CLI
|
||||
{
|
||||
protected const DIR_CONTINUE = 1;
|
||||
protected const DIR_NS = 2;
|
||||
protected const DIR_PAGE = 3;
|
||||
|
||||
private $skip = false;
|
||||
private $sort = 'wanted';
|
||||
|
||||
private $result = array();
|
||||
private $result = [];
|
||||
|
||||
/**
|
||||
* Register options and arguments on the given $options object
|
||||
@@ -30,7 +30,8 @@ class WantedPagesCLI extends CLI {
|
||||
* @param Options $options
|
||||
* @return void
|
||||
*/
|
||||
protected function setup(Options $options) {
|
||||
protected function setup(Options $options)
|
||||
{
|
||||
$options->setHelp(
|
||||
'Outputs a list of wanted pages (pages that do not exist yet) and their origin pages ' .
|
||||
' (the pages that are linkin to these missing pages).'
|
||||
@@ -63,9 +64,10 @@ class WantedPagesCLI extends CLI {
|
||||
* @param Options $options
|
||||
* @return void
|
||||
*/
|
||||
protected function main(Options $options) {
|
||||
protected function main(Options $options)
|
||||
{
|
||||
$args = $options->getArgs();
|
||||
if($args) {
|
||||
if ($args) {
|
||||
$startdir = dirname(wikiFN($args[0] . ':xxx'));
|
||||
} else {
|
||||
$startdir = dirname(wikiFN('xxx'));
|
||||
@@ -76,17 +78,17 @@ class WantedPagesCLI extends CLI {
|
||||
|
||||
$this->info("searching $startdir");
|
||||
|
||||
foreach($this->getPages($startdir) as $page) {
|
||||
foreach ($this->getPages($startdir) as $page) {
|
||||
$this->internalLinks($page);
|
||||
}
|
||||
Sort::ksort($this->result);
|
||||
foreach($this->result as $main => $subs) {
|
||||
if($this->skip) {
|
||||
print "$main\n";
|
||||
foreach ($this->result as $main => $subs) {
|
||||
if ($this->skip) {
|
||||
echo "$main\n";
|
||||
} else {
|
||||
$subs = array_unique($subs);
|
||||
Sort::sort($subs);
|
||||
foreach($subs as $sub) {
|
||||
foreach ($subs as $sub) {
|
||||
printf("%-40s %s\n", $main, $sub);
|
||||
}
|
||||
}
|
||||
@@ -100,17 +102,18 @@ class WantedPagesCLI extends CLI {
|
||||
* @param string $basepath
|
||||
* @return int
|
||||
*/
|
||||
protected function dirFilter($entry, $basepath) {
|
||||
if($entry == '.' || $entry == '..') {
|
||||
protected function dirFilter($entry, $basepath)
|
||||
{
|
||||
if ($entry == '.' || $entry == '..') {
|
||||
return WantedPagesCLI::DIR_CONTINUE;
|
||||
}
|
||||
if(is_dir($basepath . '/' . $entry)) {
|
||||
if(strpos($entry, '_') === 0) {
|
||||
if (is_dir($basepath . '/' . $entry)) {
|
||||
if (strpos($entry, '_') === 0) {
|
||||
return WantedPagesCLI::DIR_CONTINUE;
|
||||
}
|
||||
return WantedPagesCLI::DIR_NS;
|
||||
}
|
||||
if(preg_match('/\.txt$/', $entry)) {
|
||||
if (preg_match('/\.txt$/', $entry)) {
|
||||
return WantedPagesCLI::DIR_PAGE;
|
||||
}
|
||||
return WantedPagesCLI::DIR_CONTINUE;
|
||||
@@ -123,30 +126,28 @@ class WantedPagesCLI extends CLI {
|
||||
* @return array
|
||||
* @throws DokuCLI_Exception
|
||||
*/
|
||||
protected function getPages($dir) {
|
||||
protected function getPages($dir)
|
||||
{
|
||||
static $trunclen = null;
|
||||
if(!$trunclen) {
|
||||
if (!$trunclen) {
|
||||
global $conf;
|
||||
$trunclen = strlen($conf['datadir'] . ':');
|
||||
}
|
||||
|
||||
if(!is_dir($dir)) {
|
||||
if (!is_dir($dir)) {
|
||||
throw new DokuCLI_Exception("Unable to read directory $dir");
|
||||
}
|
||||
|
||||
$pages = array();
|
||||
$pages = [];
|
||||
$dh = opendir($dir);
|
||||
while(false !== ($entry = readdir($dh))) {
|
||||
while (false !== ($entry = readdir($dh))) {
|
||||
$status = $this->dirFilter($entry, $dir);
|
||||
if($status == WantedPagesCLI::DIR_CONTINUE) {
|
||||
if ($status == WantedPagesCLI::DIR_CONTINUE) {
|
||||
continue;
|
||||
} else if($status == WantedPagesCLI::DIR_NS) {
|
||||
} elseif ($status == WantedPagesCLI::DIR_NS) {
|
||||
$pages = array_merge($pages, $this->getPages($dir . '/' . $entry));
|
||||
} else {
|
||||
$page = array(
|
||||
'id' => pathID(substr($dir . '/' . $entry, $trunclen)),
|
||||
'file' => $dir . '/' . $entry,
|
||||
);
|
||||
$page = ['id' => pathID(substr($dir . '/' . $entry, $trunclen)), 'file' => $dir . '/' . $entry];
|
||||
$pages[] = $page;
|
||||
}
|
||||
}
|
||||
@@ -159,18 +160,19 @@ class WantedPagesCLI extends CLI {
|
||||
*
|
||||
* @param array $page array with page id and file path
|
||||
*/
|
||||
protected function internalLinks($page) {
|
||||
protected function internalLinks($page)
|
||||
{
|
||||
global $conf;
|
||||
$instructions = p_get_instructions(file_get_contents($page['file']));
|
||||
$resolver = new PageResolver($page['id']);
|
||||
$pid = $page['id'];
|
||||
foreach($instructions as $ins) {
|
||||
if($ins[0] == 'internallink' || ($conf['camelcase'] && $ins[0] == 'camelcaselink')) {
|
||||
foreach ($instructions as $ins) {
|
||||
if ($ins[0] == 'internallink' || ($conf['camelcase'] && $ins[0] == 'camelcaselink')) {
|
||||
$mid = $resolver->resolveId($ins[1][0]);
|
||||
if(!page_exists($mid)) {
|
||||
list($mid) = explode('#', $mid); //record pages without hashes
|
||||
if (!page_exists($mid)) {
|
||||
[$mid] = explode('#', $mid); //record pages without hashes
|
||||
|
||||
if($this->sort == 'origin') {
|
||||
if ($this->sort == 'origin') {
|
||||
$this->result[$pid][] = $mid;
|
||||
} else {
|
||||
$this->result[$mid][] = $pid;
|
||||
|
||||
@@ -64,6 +64,7 @@ $conf['rememberme'] = 1; //Enable/disable remember me on login
|
||||
$conf['disableactions'] = ''; //comma separated list of actions to disable
|
||||
$conf['auth_security_timeout'] = 900; //time (seconds) auth data is considered valid, set to 0 to recheck on every page view
|
||||
$conf['securecookie'] = 1; //never send HTTPS cookies via HTTP
|
||||
$conf['samesitecookie'] = 'Lax'; //SameSite attribute for cookies (Lax|Strict|None|Empty)
|
||||
$conf['remote'] = 0; //Enable/disable remote interfaces
|
||||
$conf['remoteuser'] = '!!not set!!'; //user/groups that have access to remote interface (comma separated). leave empty to allow all users
|
||||
$conf['remotecors'] = ''; //enable Cross-Origin Resource Sharing (CORS) for the remote interfaces. Asterisk (*) to allow all origins. leave empty to deny.
|
||||
@@ -81,8 +82,6 @@ $conf['iexssprotect']= 1; // check for JavaScript and HTML in upl
|
||||
|
||||
/* Editing Settings */
|
||||
$conf['usedraft'] = 1; //automatically save a draft while editing (0|1)
|
||||
$conf['htmlok'] = 0; //may raw HTML be embedded? This may break layout and XHTML validity 0|1
|
||||
$conf['phpok'] = 0; //may PHP code be embedded? Never do this on the internet! 0|1
|
||||
$conf['locktime'] = 15*60; //maximum age for lockfiles (defaults to 15 minutes)
|
||||
$conf['cachetime'] = 60*60*24; //maximum age for cachefile in seconds (defaults to a day)
|
||||
|
||||
@@ -112,10 +111,11 @@ $conf['mailfrom'] = ''; //use this email when sending mails
|
||||
$conf['mailreturnpath'] = ''; //use this email as returnpath for bounce mails
|
||||
$conf['mailprefix'] = ''; //use this as prefix of outgoing mails
|
||||
$conf['htmlmail'] = 1; //send HTML multipart mails
|
||||
$conf['dontlog'] = 'debug'; //logging facilites that should be disabled
|
||||
$conf['dontlog'] = 'debug'; //logging facilities that should be disabled
|
||||
$conf['logretain'] = 3; //how many days of logs to keep
|
||||
|
||||
/* Syndication Settings */
|
||||
$conf['sitemap'] = 0; //Create a google sitemap? How often? In days.
|
||||
$conf['sitemap'] = 0; //Create a Google sitemap? How often? In days.
|
||||
$conf['rss_type'] = 'rss1'; //type of RSS feed to provide, by default:
|
||||
// 'rss' - RSS 0.91
|
||||
// 'rss1' - RSS 1.0
|
||||
@@ -148,13 +148,13 @@ $conf['sepchar'] = '_'; //word separator character in page name
|
||||
// letter, a digit, '_', '-', or '.'.
|
||||
$conf['canonical'] = 0; //Should all URLs use full canonical http://... style?
|
||||
$conf['fnencode'] = 'url'; //encode filenames (url|safe|utf-8)
|
||||
$conf['autoplural'] = 0; //try (non)plural form of nonexisting files?
|
||||
$conf['autoplural'] = 0; //try (non)plural form of nonexistent files?
|
||||
$conf['compression'] = 'gz'; //compress old revisions: (0: off) ('gz': gnuzip) ('bz2': bzip)
|
||||
// bz2 generates smaller files, but needs more cpu-power
|
||||
$conf['gzip_output'] = 0; //use gzip content encodeing for the output xhtml (if allowed by browser)
|
||||
$conf['gzip_output'] = 0; //use gzip content encoding for the output xhtml (if allowed by browser)
|
||||
$conf['compress'] = 1; //Strip whitespaces and comments from Styles and JavaScript? 1|0
|
||||
$conf['cssdatauri'] = 512; //Maximum byte size of small images to embed into CSS, won't work on IE<8
|
||||
$conf['send404'] = 0; //Send a HTTP 404 status for non existing pages?
|
||||
$conf['send404'] = 0; //Send an HTTP 404 status for nonexistent pages?
|
||||
$conf['broken_iua'] = 0; //Platform with broken ignore_user_abort (IIS+CGI) 0|1
|
||||
$conf['xsendfile'] = 0; //Use X-Sendfile (1 = lighttpd, 2 = standard)
|
||||
$conf['renderer_xhtml'] = 'xhtml'; //renderer to use for main page generation
|
||||
@@ -167,6 +167,7 @@ $conf['trustedproxy'] = '^(::1|[fF][eE]80:|127\.|10\.|192\.168\.|172\.((1[6-9])|
|
||||
|
||||
/* Feature Flags */
|
||||
$conf['defer_js'] = 1; // Defer javascript to be executed after the page's HTML has been parsed. Setting will be removed in the next release.
|
||||
$conf['hidewarnings'] = 0; // Hide warnings
|
||||
|
||||
/* Network Settings */
|
||||
$conf['dnslookups'] = 1; //disable to disallow IP to hostname lookups
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
<?php
|
||||
/**
|
||||
* This configures which meta data will be editable through
|
||||
* This configures which metadata will be editable through
|
||||
* the media manager. Each field of the array is an array with the
|
||||
* following contents:
|
||||
* fieldname - Where data will be saved (EXIF or IPTC field)
|
||||
* label - key to lookup in the $lang var, if not found printed as is
|
||||
* htmltype - 'text', 'textarea' or 'date'
|
||||
* lookups - array additional fields to lookup the data (EXIF or IPTC fields)
|
||||
* lookups - array additional fields to look up the data (EXIF or IPTC fields)
|
||||
*
|
||||
* The fields are not ordered continously to make inserting additional items
|
||||
* The fields are not ordered continuously to make inserting additional items
|
||||
* in between simpler.
|
||||
*
|
||||
* This is a PHP snippet, so PHP syntax applies.
|
||||
@@ -16,7 +16,7 @@
|
||||
* Note: $fields is not a global variable and will not be available to any
|
||||
* other functions or templates later
|
||||
*
|
||||
* You may extend or overwrite this variable in a optional
|
||||
* You may extend or overwrite this variable in an optional
|
||||
* conf/mediameta.local.php file
|
||||
*
|
||||
* For a list of available EXIF/IPTC fields refer to
|
||||
|
||||
@@ -7,6 +7,7 @@ jpg image/jpeg
|
||||
jpeg image/jpeg
|
||||
gif image/gif
|
||||
png image/png
|
||||
webp image/webp
|
||||
ico image/vnd.microsoft.icon
|
||||
|
||||
mp3 audio/mpeg
|
||||
|
||||
@@ -34,15 +34,15 @@ $conf['plugin']['authmysql']['database'] = '';
|
||||
$conf['plugin']['authmysql']['debug'] = 0;
|
||||
|
||||
/* Normally password encryption is done by DokuWiki (recommended) but for
|
||||
* some reasons it might be usefull to let the database do the encryption.
|
||||
* some reasons it might be useful to let the database do the encryption.
|
||||
* Set 'forwardClearPass' to '1' and the cleartext password is forwarded to
|
||||
* the database, otherwise the encrypted one.
|
||||
*/
|
||||
$conf['plugin']['authmysql']['forwardClearPass'] = 0;
|
||||
|
||||
/* Multiple table operations will be protected by locks. This array tolds
|
||||
/* Multiple table operations will be protected by locks. This array tells
|
||||
* the plugin which tables to lock. If you use any aliases for table names
|
||||
* these array must also contain these aliases. Any unamed alias will cause
|
||||
* these array must also contain these aliases. Any unnamed alias will cause
|
||||
* a warning during operation. See the example below.
|
||||
*/
|
||||
$conf['plugin']['authmysql']['TablesToLock']= array("users", "users AS u","groups", "groups AS g", "usergroup", "usergroup AS ug");
|
||||
@@ -76,8 +76,8 @@ $conf['plugin']['authmysql']['checkPass'] = "SELECT pass
|
||||
* 'name' the user's full name
|
||||
* 'mail' the user's email address
|
||||
*
|
||||
* Keep in mind that Dokuwiki will access thise information through the
|
||||
* names listed above so aliasses might be neseccary.
|
||||
* Keep in mind that Dokuwiki will access this information through the
|
||||
* names listed above so aliases might be necessary.
|
||||
*
|
||||
* Following patters will be replaced:
|
||||
* %{user} user name
|
||||
@@ -89,7 +89,7 @@ $conf['plugin']['authmysql']['getUserInfo'] = "SELECT pass, CONCAT(firstname,' '
|
||||
/* This statement is used to get all groups a user is member of. The
|
||||
* result should be a table containing all groups the given user is
|
||||
* member of. The plugin accesses the group name as 'group' so an alias
|
||||
* might be nessecary.
|
||||
* might be necessary.
|
||||
*
|
||||
* Following patters will be replaced:
|
||||
* %{user} user name
|
||||
@@ -106,11 +106,11 @@ $conf['plugin']['authmysql']['getGroups'] = "SELECT name as `group`
|
||||
|
||||
/* This statement should return a table containing all user login names
|
||||
* that meet certain filter criteria. The filter expressions will be added
|
||||
* case dependend by the plugin. At the end a sort expression will be added.
|
||||
* case dependent by the plugin. At the end a sort expression will be added.
|
||||
* Important is that this list contains no double entries for a user. Each
|
||||
* user name is only allowed once in the table.
|
||||
*
|
||||
* The login name will be accessed as 'user' to an alias might be neseccary.
|
||||
* The login name will be accessed as 'user' to an alias might be necessary.
|
||||
* No patterns will be replaced in this statement but following patters
|
||||
* will be replaced in the filter expressions:
|
||||
* %{user} in FilterLogin user's login name
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<?php
|
||||
/**
|
||||
* This file configures the enabled/disabled status of plugins, which are also protected
|
||||
* from changes by the extention manager. These settings will override any local settings.
|
||||
* from changes by the extension manager. These settings will override any local settings.
|
||||
* It is not recommended to change this file, as it is overwritten on DokuWiki upgrades.
|
||||
*/
|
||||
$plugins['acl'] = 1;
|
||||
|
||||
@@ -68,6 +68,30 @@ vendor/paragonie/random_compat/lib/random_bytes_libsodium.php
|
||||
vendor/paragonie/random_compat/lib/random_bytes_libsodium_legacy.php
|
||||
vendor/paragonie/random_compat/lib/random_bytes_mcrypt.php
|
||||
vendor/paragonie/random_compat/lib/random_int.php
|
||||
lib/images/smileys/icon_cool.gif
|
||||
lib/images/smileys/icon_eek.gif
|
||||
lib/images/smileys/icon_eek.gif
|
||||
lib/images/smileys/icon_sad.gif
|
||||
lib/images/smileys/icon_smile.gif
|
||||
lib/images/smileys/icon_smile2.gif
|
||||
lib/images/smileys/icon_doubt.gif
|
||||
lib/images/smileys/icon_doubt2.gif
|
||||
lib/images/smileys/icon_confused.gif
|
||||
lib/images/smileys/icon_biggrin.gif
|
||||
lib/images/smileys/icon_razz.gif
|
||||
lib/images/smileys/icon_surprised.gif
|
||||
lib/images/smileys/icon_surprised.gif
|
||||
lib/images/smileys/icon_silenced.gif
|
||||
lib/images/smileys/icon_silenced.gif
|
||||
lib/images/smileys/icon_neutral.gif
|
||||
lib/images/smileys/icon_wink.gif
|
||||
lib/images/smileys/facepalm.gif
|
||||
lib/images/smileys/icon_fun.gif
|
||||
lib/images/smileys/icon_question.gif
|
||||
lib/images/smileys/icon_exclaim.gif
|
||||
lib/images/smileys/icon_lol.gif
|
||||
lib/images/smileys/fixme.gif
|
||||
lib/images/smileys/delete.gif
|
||||
|
||||
# removed in 2020-06-01
|
||||
inc/PluginInterface.php
|
||||
@@ -911,3 +935,54 @@ lib/images/toolbar/list.png
|
||||
lib/images/toolbar/list_ul.png
|
||||
lib/images/toolbar/rule.png
|
||||
lib/tpl/default/images/interwiki.png
|
||||
.github/version.php
|
||||
.github/workflows/release.yml
|
||||
_test/tests/inc/form/checkableelement.test.php
|
||||
_test/tests/inc/pageutils_resolve_id.test.php
|
||||
inc/Parsing/ParserMode/Html.php
|
||||
inc/Parsing/ParserMode/Php.php
|
||||
_test/tests/lib/exe/js_js_compress.test.php
|
||||
_test/tests/lib/exe/js_js_compress/test-CommentInDoubleQuotes1-in.js
|
||||
_test/tests/lib/exe/js_js_compress/test-CommentInDoubleQuotes1-out.js
|
||||
_test/tests/lib/exe/js_js_compress/test-CommentInDoubleQuotes2-in.js
|
||||
_test/tests/lib/exe/js_js_compress/test-CommentInDoubleQuotes2-out.js
|
||||
_test/tests/lib/exe/js_js_compress/test-CommentInSingleQuotes1-in.js
|
||||
_test/tests/lib/exe/js_js_compress/test-CommentInSingleQuotes1-out.js
|
||||
_test/tests/lib/exe/js_js_compress/test-CommentInSingleQuotes2-in.js
|
||||
_test/tests/lib/exe/js_js_compress/test-CommentInSingleQuotes2-out.js
|
||||
_test/tests/lib/exe/js_js_compress/test-CommentMultiline-in.js
|
||||
_test/tests/lib/exe/js_js_compress/test-CommentMultiline-out.js
|
||||
_test/tests/lib/exe/js_js_compress/test-CommentSingleLine-in.js
|
||||
_test/tests/lib/exe/js_js_compress/test-CommentSingleLine-out.js
|
||||
_test/tests/lib/exe/js_js_compress/test-IfThenElseBraces-in.js
|
||||
_test/tests/lib/exe/js_js_compress/test-IfThenElseBraces-out.js
|
||||
_test/tests/lib/exe/js_js_compress/test-IfThenElseNoBraces-in.js
|
||||
_test/tests/lib/exe/js_js_compress/test-IfThenElseNoBraces-out.js
|
||||
_test/tests/lib/exe/js_js_compress/test-RegexpBackslash-in.js
|
||||
_test/tests/lib/exe/js_js_compress/test-RegexpBackslash-out.js
|
||||
_test/tests/lib/exe/js_js_compress/test-RegexpSimple-in.js
|
||||
_test/tests/lib/exe/js_js_compress/test-RegexpSimple-out.js
|
||||
_test/tests/lib/exe/js_js_compress/test-RegexpSimpleWhitespace-in.js
|
||||
_test/tests/lib/exe/js_js_compress/test-RegexpSimpleWhitespace-out.js
|
||||
_test/tests/lib/exe/js_js_compress/test-RegexpString-in.js
|
||||
_test/tests/lib/exe/js_js_compress/test-RegexpString-out.js
|
||||
_test/tests/lib/exe/js_js_compress/test-StatementDoWhile-in.js
|
||||
_test/tests/lib/exe/js_js_compress/test-StatementDoWhile-out.js
|
||||
_test/tests/lib/exe/js_js_compress/test-StatementForIn-in.js
|
||||
_test/tests/lib/exe/js_js_compress/test-StatementForIn-out.js
|
||||
_test/tests/lib/exe/js_js_compress/test-StatementNew-in.js
|
||||
_test/tests/lib/exe/js_js_compress/test-StatementNew-out.js
|
||||
_test/tests/lib/exe/js_js_compress/test-StatementSwitchCase-in.js
|
||||
_test/tests/lib/exe/js_js_compress/test-StatementSwitchCase-out.js
|
||||
_test/tests/lib/exe/js_js_compress/test-StringDoubleQuotes-in.js
|
||||
_test/tests/lib/exe/js_js_compress/test-StringDoubleQuotes-out.js
|
||||
_test/tests/lib/exe/js_js_compress/test-StringSingleQuotes-in.js
|
||||
_test/tests/lib/exe/js_js_compress/test-StringSingleQuotes-out.js
|
||||
vendor/kissifrot/php-ixr/.editorconfig
|
||||
vendor/kissifrot/php-ixr/.gitignore
|
||||
_test/tests/inc/pageutils_resolve_mediaid.test.php
|
||||
_test/tests/inc/pageutils_resolve_pageid.test.php
|
||||
vendor/phpseclib/phpseclib/phpseclib/Net/SCP.php
|
||||
vendor/phpseclib/phpseclib/phpseclib/Net/SSH1.php
|
||||
vendor/marcusschwarz/lesserphp/README.md
|
||||
vendor/marcusschwarz/lesserphp/lessc.inc.php
|
||||
|
||||
@@ -136,12 +136,12 @@ Resize to given width: {{wiki:dokuwiki-128.png?50}}
|
||||
|
||||
Resize to given width and height((when the aspect ratio of the given width and height doesn't match that of the image, it will be cropped to the new ratio before resizing)): {{wiki:dokuwiki-128.png?200x50}}
|
||||
|
||||
Resized external image: {{https://secure.php.net/images/php.gif?200x50}}
|
||||
Resized external image: {{https://www.php.net/images/php.gif?200x50}}
|
||||
|
||||
Real size: {{wiki:dokuwiki-128.png}}
|
||||
Resize to given width: {{wiki:dokuwiki-128.png?50}}
|
||||
Resize to given width and height: {{wiki:dokuwiki-128.png?200x50}}
|
||||
Resized external image: {{https://secure.php.net/images/php.gif?200x50}}
|
||||
Resized external image: {{https://www.php.net/images/php.gif?200x50}}
|
||||
|
||||
|
||||
By using left or right whitespaces you can choose the alignment.
|
||||
@@ -437,57 +437,6 @@ When you use the ''%%<code>%%'' or ''%%<file>%%'' syntax as above, you might wan
|
||||
|
||||
If you don't want any highlighting but want a downloadable file, specify a dash (''-'') as the language code: ''%%<code - myfile.foo>%%''.
|
||||
|
||||
|
||||
===== Embedding HTML and PHP =====
|
||||
|
||||
You can embed raw HTML or PHP code into your documents by using the ''%%<html>%%'' or ''%%<php>%%'' tags. (Use uppercase tags if you need to enclose block level elements.)
|
||||
|
||||
HTML example:
|
||||
|
||||
<code>
|
||||
<html>
|
||||
This is some <span style="color:red;font-size:150%;">inline HTML</span>
|
||||
</html>
|
||||
<HTML>
|
||||
<p style="border:2px dashed red;">And this is some block HTML</p>
|
||||
</HTML>
|
||||
</code>
|
||||
|
||||
<html>
|
||||
This is some <span style="color:red;font-size:150%;">inline HTML</span>
|
||||
</html>
|
||||
<HTML>
|
||||
<p style="border:2px dashed red;">And this is some block HTML</p>
|
||||
</HTML>
|
||||
|
||||
PHP example:
|
||||
|
||||
<code>
|
||||
<php>
|
||||
echo 'The PHP version: ';
|
||||
echo phpversion();
|
||||
echo ' (generated inline HTML)';
|
||||
</php>
|
||||
<PHP>
|
||||
echo '<table class="inline"><tr><td>The same, but inside a block level element:</td>';
|
||||
echo '<td>'.phpversion().'</td>';
|
||||
echo '</tr></table>';
|
||||
</PHP>
|
||||
</code>
|
||||
|
||||
<php>
|
||||
echo 'The PHP version: ';
|
||||
echo phpversion();
|
||||
echo ' (inline HTML)';
|
||||
</php>
|
||||
<PHP>
|
||||
echo '<table class="inline"><tr><td>The same, but inside a block level element:</td>';
|
||||
echo '<td>'.phpversion().'</td>';
|
||||
echo '</tr></table>';
|
||||
</PHP>
|
||||
|
||||
**Please Note**: HTML and PHP embedding is disabled by default in the configuration. If disabled, the code is displayed instead of executed.
|
||||
|
||||
===== RSS/ATOM Feed Aggregation =====
|
||||
[[DokuWiki]] can integrate data from external XML feeds. For parsing the XML feeds, [[http://simplepie.org/|SimplePie]] is used. All formats understood by SimplePie can be used in DokuWiki as well. You can influence the rendering by multiple additional space separated parameters:
|
||||
|
||||
@@ -496,7 +445,7 @@ echo '</tr></table>';
|
||||
| reverse | display the last items in the feed first |
|
||||
| author | show item authors names |
|
||||
| date | show item dates |
|
||||
| description| show the item description. If [[doku>config:htmlok|HTML]] is disabled all tags will be stripped |
|
||||
| description| show the item description. All HTML tags will be stripped |
|
||||
| nosort | do not sort the items in the feed |
|
||||
| //n//[dhm] | refresh period, where d=days, h=hours, m=minutes. (e.g. 12h = 12 hours). |
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* DokuWiki mainscript
|
||||
*
|
||||
@@ -8,47 +9,48 @@
|
||||
* @global Input $INPUT
|
||||
*/
|
||||
|
||||
// update message version - always use a string to avoid localized floats!
|
||||
use dokuwiki\ChangeLog\PageChangeLog;
|
||||
use dokuwiki\Extension\Event;
|
||||
|
||||
$updateVersion = "53.1";
|
||||
// update message version - always use a string to avoid localized floats!
|
||||
$updateVersion = "55.1";
|
||||
|
||||
// xdebug_start_profiling();
|
||||
|
||||
if(!defined('DOKU_INC')) define('DOKU_INC', dirname(__FILE__).'/');
|
||||
if (!defined('DOKU_INC')) define('DOKU_INC', __DIR__ . '/');
|
||||
|
||||
// define all DokuWiki globals here (needed within test requests but also helps to keep track)
|
||||
global $ACT, $INPUT, $QUERY, $ID, $REV, $DATE_AT, $IDX,
|
||||
$DATE, $RANGE, $HIGH, $TEXT, $PRE, $SUF, $SUM, $INFO, $JSINFO;
|
||||
global $ACT, $INPUT, $QUERY, $ID, $REV, $DATE_AT, $IDX,
|
||||
$DATE, $RANGE, $HIGH, $TEXT, $PRE, $SUF, $SUM, $INFO, $JSINFO;
|
||||
|
||||
|
||||
if(isset($_SERVER['HTTP_X_DOKUWIKI_DO'])) {
|
||||
if (isset($_SERVER['HTTP_X_DOKUWIKI_DO'])) {
|
||||
$ACT = trim(strtolower($_SERVER['HTTP_X_DOKUWIKI_DO']));
|
||||
} elseif(!empty($_REQUEST['idx'])) {
|
||||
} elseif (!empty($_REQUEST['idx'])) {
|
||||
$ACT = 'index';
|
||||
} elseif(isset($_REQUEST['do'])) {
|
||||
} elseif (isset($_REQUEST['do'])) {
|
||||
$ACT = $_REQUEST['do'];
|
||||
} else {
|
||||
$ACT = 'show';
|
||||
}
|
||||
|
||||
// load and initialize the core system
|
||||
require_once(DOKU_INC.'inc/init.php');
|
||||
require_once(DOKU_INC . 'inc/init.php');
|
||||
|
||||
//import variables
|
||||
$INPUT->set('id', str_replace("\xC2\xAD", '', $INPUT->str('id'))); //soft-hyphen
|
||||
$QUERY = trim($INPUT->str('q'));
|
||||
$ID = getID();
|
||||
$QUERY = trim($INPUT->str('q'));
|
||||
$ID = getID();
|
||||
|
||||
$REV = $INPUT->int('rev');
|
||||
$REV = $INPUT->int('rev');
|
||||
$DATE_AT = $INPUT->str('at');
|
||||
$IDX = $INPUT->str('idx');
|
||||
$DATE = $INPUT->int('date');
|
||||
$IDX = $INPUT->str('idx');
|
||||
$DATE = $INPUT->int('date');
|
||||
$RANGE = $INPUT->str('range');
|
||||
$HIGH = $INPUT->param('s');
|
||||
if(empty($HIGH)) $HIGH = getGoogleQuery();
|
||||
$HIGH = $INPUT->param('s');
|
||||
if (empty($HIGH)) $HIGH = getGoogleQuery();
|
||||
|
||||
if($INPUT->post->has('wikitext')) {
|
||||
if ($INPUT->post->has('wikitext')) {
|
||||
$TEXT = cleanText($INPUT->post->str('wikitext'));
|
||||
}
|
||||
$PRE = cleanText(substr($INPUT->post->str('prefix'), 0, -1));
|
||||
@@ -57,13 +59,13 @@ $SUM = $INPUT->post->str('summary');
|
||||
|
||||
|
||||
//parse DATE_AT
|
||||
if($DATE_AT) {
|
||||
if ($DATE_AT) {
|
||||
$date_parse = strtotime($DATE_AT);
|
||||
if($date_parse) {
|
||||
if ($date_parse) {
|
||||
$DATE_AT = $date_parse;
|
||||
} else { // check for UNIX Timestamp
|
||||
$date_parse = @date('Ymd',$DATE_AT);
|
||||
if(!$date_parse || $date_parse === '19700101') {
|
||||
$date_parse = @date('Ymd', $DATE_AT);
|
||||
if (!$date_parse || $date_parse === '19700101') {
|
||||
msg(sprintf($lang['unable_to_parse_date'], hsc($DATE_AT)));
|
||||
$DATE_AT = null;
|
||||
}
|
||||
@@ -71,19 +73,21 @@ if($DATE_AT) {
|
||||
}
|
||||
|
||||
//check for existing $REV related to $DATE_AT
|
||||
if($DATE_AT) {
|
||||
$pagelog = new \dokuwiki\ChangeLog\PageChangeLog($ID);
|
||||
if ($DATE_AT) {
|
||||
$pagelog = new PageChangeLog($ID);
|
||||
$rev_t = $pagelog->getLastRevisionAt($DATE_AT);
|
||||
if($rev_t === '') { //current revision
|
||||
if ($rev_t === '') {
|
||||
//current revision
|
||||
$REV = null;
|
||||
$DATE_AT = null;
|
||||
} else if ($rev_t === false) { //page did not exist
|
||||
$rev_n = $pagelog->getRelativeRevision($DATE_AT,+1);
|
||||
} elseif ($rev_t === false) {
|
||||
//page did not exist
|
||||
$rev_n = $pagelog->getRelativeRevision($DATE_AT, +1);
|
||||
msg(
|
||||
sprintf(
|
||||
$lang['page_nonexist_rev'],
|
||||
dformat($DATE_AT),
|
||||
wl($ID, array('rev' => $rev_n)),
|
||||
wl($ID, ['rev' => $rev_n]),
|
||||
dformat($rev_n)
|
||||
)
|
||||
);
|
||||
@@ -97,26 +101,27 @@ if($DATE_AT) {
|
||||
$INFO = pageinfo();
|
||||
|
||||
// handle debugging
|
||||
if($conf['allowdebug'] && $ACT == 'debug') {
|
||||
if ($conf['allowdebug'] && $ACT == 'debug') {
|
||||
html_debug();
|
||||
exit;
|
||||
}
|
||||
|
||||
//send 404 for missing pages if configured or ID has special meaning to bots
|
||||
if(!$INFO['exists'] &&
|
||||
if (
|
||||
!$INFO['exists'] &&
|
||||
($conf['send404'] || preg_match('/^(robots\.txt|sitemap\.xml(\.gz)?|favicon\.ico|crossdomain\.xml)$/', $ID)) &&
|
||||
($ACT == 'show' || (!is_array($ACT) && substr($ACT, 0, 7) == 'export_'))
|
||||
($ACT == 'show' || (!is_array($ACT) && str_starts_with($ACT, 'export_')))
|
||||
) {
|
||||
header('HTTP/1.0 404 Not Found');
|
||||
}
|
||||
|
||||
//prepare breadcrumbs (initialize a static var)
|
||||
if($conf['breadcrumbs']) breadcrumbs();
|
||||
if ($conf['breadcrumbs']) breadcrumbs();
|
||||
|
||||
// check upstream
|
||||
checkUpdateMessages();
|
||||
|
||||
$tmp = array(); // No event data
|
||||
$tmp = []; // No event data
|
||||
Event::createAndTrigger('DOKUWIKI_STARTED', $tmp);
|
||||
|
||||
//close session
|
||||
@@ -125,7 +130,7 @@ session_write_close();
|
||||
//do the work (picks up what to do from global env)
|
||||
act_dispatch();
|
||||
|
||||
$tmp = array(); // No event data
|
||||
$tmp = []; // No event data
|
||||
Event::createAndTrigger('DOKUWIKI_DONE', $tmp);
|
||||
|
||||
// xdebug_dump_function_profile(1);
|
||||
|
||||
@@ -10,13 +10,15 @@
|
||||
* @global Input $INPUT
|
||||
*/
|
||||
|
||||
use dokuwiki\Feed\FeedCreator;
|
||||
use dokuwiki\Feed\FeedCreatorOptions;
|
||||
use dokuwiki\Cache\Cache;
|
||||
use dokuwiki\ChangeLog\MediaChangeLog;
|
||||
use dokuwiki\ChangeLog\PageChangeLog;
|
||||
use dokuwiki\Extension\AuthPlugin;
|
||||
use dokuwiki\Extension\Event;
|
||||
|
||||
if (!defined('DOKU_INC')) define('DOKU_INC', dirname(__FILE__) . '/');
|
||||
if (!defined('DOKU_INC')) define('DOKU_INC', __DIR__ . '/');
|
||||
require_once(DOKU_INC . 'inc/init.php');
|
||||
|
||||
//close session
|
||||
@@ -29,518 +31,45 @@ if (!actionOK('rss')) {
|
||||
exit;
|
||||
}
|
||||
|
||||
// get params
|
||||
$opt = rss_parseOptions();
|
||||
$options = new FeedCreatorOptions();
|
||||
|
||||
// the feed is dynamic - we need a cache for each combo
|
||||
// (but most people just use the default feed so it's still effective)
|
||||
$key = join('', array_values($opt)) . '$' . $_SERVER['REMOTE_USER']
|
||||
. '$' . $_SERVER['HTTP_HOST'] . $_SERVER['SERVER_PORT'];
|
||||
$key = implode('$', [
|
||||
$options->getCacheKey(),
|
||||
$INPUT->server->str('REMOTE_USER'),
|
||||
$INPUT->server->str('HTTP_HOST'),
|
||||
$INPUT->server->str('SERVER_PORT')
|
||||
]);
|
||||
$cache = new Cache($key, '.feed');
|
||||
|
||||
// prepare cache depends
|
||||
$depends['files'] = getConfigFiles('main');
|
||||
$depends['age'] = $conf['rss_update'];
|
||||
$depends['age'] = $conf['rss_update'];
|
||||
$depends['purge'] = $INPUT->bool('purge');
|
||||
|
||||
// check cacheage and deliver if nothing has changed since last
|
||||
// time or the update interval has not passed, also handles conditional requests
|
||||
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
|
||||
header('Pragma: public');
|
||||
header('Content-Type: application/xml; charset=utf-8');
|
||||
header('Content-Type: ' . $options->getMimeType());
|
||||
header('X-Robots-Tag: noindex');
|
||||
if ($cache->useCache($depends)) {
|
||||
http_conditionalRequest($cache->getTime());
|
||||
if ($conf['allowdebug']) header("X-CacheUsed: $cache->cache");
|
||||
print $cache->retrieveCache();
|
||||
echo $cache->retrieveCache();
|
||||
exit;
|
||||
} else {
|
||||
http_conditionalRequest(time());
|
||||
}
|
||||
|
||||
// create new feed
|
||||
$rss = new UniversalFeedCreator();
|
||||
$rss->title = $conf['title'] . (($opt['namespace']) ? ' ' . $opt['namespace'] : '');
|
||||
$rss->link = DOKU_URL;
|
||||
$rss->syndicationURL = DOKU_URL . 'feed.php';
|
||||
$rss->cssStyleSheet = DOKU_URL . 'lib/exe/css.php?s=feed';
|
||||
|
||||
$image = new FeedImage();
|
||||
$image->title = $conf['title'];
|
||||
$image->url = tpl_getMediaFile([':wiki:favicon.ico', ':favicon.ico', 'images/favicon.ico'], true);
|
||||
$image->link = DOKU_URL;
|
||||
$rss->image = $image;
|
||||
|
||||
$data = null;
|
||||
$modes = [
|
||||
'list' => 'rssListNamespace',
|
||||
'search' => 'rssSearch',
|
||||
'recent' => 'rssRecentChanges'
|
||||
];
|
||||
|
||||
if (isset($modes[$opt['feed_mode']])) {
|
||||
$data = $modes[$opt['feed_mode']]($opt);
|
||||
} else {
|
||||
$eventData = [
|
||||
'opt' => &$opt,
|
||||
'data' => &$data,
|
||||
];
|
||||
$event = new Event('FEED_MODE_UNKNOWN', $eventData);
|
||||
if ($event->advise_before(true)) {
|
||||
echo sprintf('<error>Unknown feed mode %s</error>', hsc($opt['feed_mode']));
|
||||
exit;
|
||||
}
|
||||
$event->advise_after();
|
||||
try {
|
||||
$feed = (new FeedCreator($options))->build();
|
||||
$cache->storeCache($feed);
|
||||
echo $feed;
|
||||
} catch (Exception $e) {
|
||||
http_status(500);
|
||||
echo '<error>' . hsc($e->getMessage()) . '</error>';
|
||||
exit;
|
||||
}
|
||||
|
||||
rss_buildItems($rss, $data, $opt);
|
||||
$feed = $rss->createFeed($opt['feed_type']);
|
||||
|
||||
// save cachefile
|
||||
$cache->storeCache($feed);
|
||||
|
||||
// finally deliver
|
||||
print $feed;
|
||||
|
||||
// ---------------------------------------------------------------- //
|
||||
|
||||
/**
|
||||
* Get URL parameters and config options and return an initialized option array
|
||||
*
|
||||
* @author Andreas Gohr <andi@splitbrain.org>
|
||||
*/
|
||||
function rss_parseOptions()
|
||||
{
|
||||
global $conf;
|
||||
global $INPUT;
|
||||
|
||||
$opt = [];
|
||||
|
||||
foreach (
|
||||
[
|
||||
// Basic feed properties
|
||||
// Plugins may probably want to add new values to these
|
||||
// properties for implementing own feeds
|
||||
|
||||
// One of: list, search, recent
|
||||
'feed_mode' => ['str', 'mode', 'recent'],
|
||||
// One of: diff, page, rev, current
|
||||
'link_to' => ['str', 'linkto', $conf['rss_linkto']],
|
||||
// One of: abstract, diff, htmldiff, html
|
||||
'item_content' => ['str', 'content', $conf['rss_content']],
|
||||
|
||||
// Special feed properties
|
||||
// These are only used by certain feed_modes
|
||||
|
||||
// String, used for feed title, in list and rc mode
|
||||
'namespace' => ['str', 'ns', null],
|
||||
// Positive integer, only used in rc mode
|
||||
'items' => ['int', 'num', $conf['recent']],
|
||||
// Boolean, only used in rc mode
|
||||
'show_minor' => ['bool', 'minor', false],
|
||||
// Boolean, only used in rc mode
|
||||
'only_new' => ['bool', 'onlynewpages', false],
|
||||
// String, only used in list mode
|
||||
'sort' => ['str', 'sort', 'natural'],
|
||||
// String, only used in search mode
|
||||
'search_query' => ['str', 'q', null],
|
||||
// One of: pages, media, both
|
||||
'content_type' => ['str', 'view', $conf['rss_media']]
|
||||
|
||||
] as $name => $val
|
||||
) {
|
||||
$opt[$name] = $INPUT->{$val[0]}($val[1], $val[2], true);
|
||||
}
|
||||
|
||||
$opt['items'] = max(0, (int) $opt['items']);
|
||||
$opt['show_minor'] = (bool) $opt['show_minor'];
|
||||
$opt['only_new'] = (bool) $opt['only_new'];
|
||||
$opt['sort'] = valid_input_set('sort', ['default' => 'natural', 'date'], $opt);
|
||||
|
||||
$opt['guardmail'] = ($conf['mailguard'] != '' && $conf['mailguard'] != 'none');
|
||||
|
||||
$type = $INPUT->valid(
|
||||
'type',
|
||||
['rss', 'rss2', 'atom', 'atom1', 'rss1'],
|
||||
$conf['rss_type']
|
||||
);
|
||||
switch ($type) {
|
||||
case 'rss':
|
||||
$opt['feed_type'] = 'RSS0.91';
|
||||
$opt['mime_type'] = 'text/xml';
|
||||
break;
|
||||
case 'rss2':
|
||||
$opt['feed_type'] = 'RSS2.0';
|
||||
$opt['mime_type'] = 'text/xml';
|
||||
break;
|
||||
case 'atom':
|
||||
$opt['feed_type'] = 'ATOM0.3';
|
||||
$opt['mime_type'] = 'application/xml';
|
||||
break;
|
||||
case 'atom1':
|
||||
$opt['feed_type'] = 'ATOM1.0';
|
||||
$opt['mime_type'] = 'application/atom+xml';
|
||||
break;
|
||||
default:
|
||||
$opt['feed_type'] = 'RSS1.0';
|
||||
$opt['mime_type'] = 'application/xml';
|
||||
}
|
||||
|
||||
$eventData = [
|
||||
'opt' => &$opt,
|
||||
];
|
||||
Event::createAndTrigger('FEED_OPTS_POSTPROCESS', $eventData);
|
||||
return $opt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add recent changed pages to a feed object
|
||||
*
|
||||
* @param FeedCreator $rss the FeedCreator Object
|
||||
* @param array $data the items to add
|
||||
* @param array $opt the feed options
|
||||
* @author Andreas Gohr <andi@splitbrain.org>
|
||||
*/
|
||||
function rss_buildItems(&$rss, &$data, $opt)
|
||||
{
|
||||
global $conf;
|
||||
global $lang;
|
||||
/* @var AuthPlugin $auth */
|
||||
global $auth;
|
||||
|
||||
$eventData = [
|
||||
'rss' => &$rss,
|
||||
'data' => &$data,
|
||||
'opt' => &$opt,
|
||||
];
|
||||
$event = new Event('FEED_DATA_PROCESS', $eventData);
|
||||
if ($event->advise_before(false)) {
|
||||
foreach ($data as $ditem) {
|
||||
if (!is_array($ditem)) {
|
||||
// not an array? then only a list of IDs was given
|
||||
$ditem = ['id' => $ditem];
|
||||
}
|
||||
|
||||
$item = new FeedItem();
|
||||
$id = $ditem['id'];
|
||||
if (!$ditem['media']) {
|
||||
$meta = p_get_metadata($id);
|
||||
} else {
|
||||
$meta = [];
|
||||
}
|
||||
|
||||
// add date
|
||||
if ($ditem['date']) {
|
||||
$date = $ditem['date'];
|
||||
} elseif ($ditem['media']) {
|
||||
$date = @filemtime(mediaFN($id));
|
||||
} elseif (file_exists(wikiFN($id))) {
|
||||
$date = @filemtime(wikiFN($id));
|
||||
} elseif ($meta['date']['modified']) {
|
||||
$date = $meta['date']['modified'];
|
||||
} else {
|
||||
$date = 0;
|
||||
}
|
||||
if ($date) $item->date = date('r', $date);
|
||||
|
||||
// add title
|
||||
if ($conf['useheading'] && $meta['title']) {
|
||||
$item->title = $meta['title'];
|
||||
} else {
|
||||
$item->title = $ditem['id'];
|
||||
}
|
||||
if ($conf['rss_show_summary'] && !empty($ditem['sum'])) {
|
||||
$item->title .= ' - ' . strip_tags($ditem['sum']);
|
||||
}
|
||||
|
||||
// add item link
|
||||
switch ($opt['link_to']) {
|
||||
case 'page':
|
||||
if ($ditem['media']) {
|
||||
$item->link = media_managerURL(
|
||||
[
|
||||
'image' => $id,
|
||||
'ns' => getNS($id),
|
||||
'rev' => $date
|
||||
],
|
||||
'&',
|
||||
true
|
||||
);
|
||||
} else {
|
||||
$item->link = wl($id, 'rev=' . $date, true, '&');
|
||||
}
|
||||
break;
|
||||
case 'rev':
|
||||
if ($ditem['media']) {
|
||||
$item->link = media_managerURL(
|
||||
[
|
||||
'image' => $id,
|
||||
'ns' => getNS($id),
|
||||
'rev' => $date,
|
||||
'tab_details' => 'history'
|
||||
],
|
||||
'&',
|
||||
true
|
||||
);
|
||||
} else {
|
||||
$item->link = wl($id, 'do=revisions&rev=' . $date, true, '&');
|
||||
}
|
||||
break;
|
||||
case 'current':
|
||||
if ($ditem['media']) {
|
||||
$item->link = media_managerURL(
|
||||
[
|
||||
'image' => $id,
|
||||
'ns' => getNS($id)
|
||||
],
|
||||
'&',
|
||||
true
|
||||
);
|
||||
} else {
|
||||
$item->link = wl($id, '', true, '&');
|
||||
}
|
||||
break;
|
||||
case 'diff':
|
||||
default:
|
||||
if ($ditem['media']) {
|
||||
$item->link = media_managerURL(
|
||||
[
|
||||
'image' => $id,
|
||||
'ns' => getNS($id),
|
||||
'rev' => $date,
|
||||
'tab_details' => 'history',
|
||||
'mediado' => 'diff'
|
||||
],
|
||||
'&',
|
||||
true
|
||||
);
|
||||
} else {
|
||||
$item->link = wl($id, 'rev=' . $date . '&do=diff', true, '&');
|
||||
}
|
||||
}
|
||||
|
||||
// add item content
|
||||
switch ($opt['item_content']) {
|
||||
case 'diff':
|
||||
case 'htmldiff':
|
||||
if ($ditem['media']) {
|
||||
$medialog = new MediaChangeLog($id);
|
||||
$revs = $medialog->getRevisions(0, 1);
|
||||
$rev = $revs[0];
|
||||
$src_r = '';
|
||||
$src_l = '';
|
||||
|
||||
if ($size = media_image_preview_size($id, '', new JpegMeta(mediaFN($id)), 300)) {
|
||||
$more = 'w=' . $size[0] . '&h=' . $size[1] . '&t=' . @filemtime(mediaFN($id));
|
||||
$src_r = ml($id, $more, true, '&', true);
|
||||
}
|
||||
if ($rev && $size = media_image_preview_size($id, $rev, new JpegMeta(mediaFN($id, $rev)),
|
||||
300)) {
|
||||
$more = 'rev=' . $rev . '&w=' . $size[0] . '&h=' . $size[1];
|
||||
$src_l = ml($id, $more, true, '&', true);
|
||||
}
|
||||
$content = '';
|
||||
if ($src_r) {
|
||||
$content = '<table>';
|
||||
$content .= '<tr><th width="50%">' . $rev . '</th>';
|
||||
$content .= '<th width="50%">' . $lang['current'] . '</th></tr>';
|
||||
$content .= '<tr align="center"><td><img src="' . $src_l . '" alt="" /></td><td>';
|
||||
$content .= '<img src="' . $src_r . '" alt="' . $id . '" /></td></tr>';
|
||||
$content .= '</table>';
|
||||
}
|
||||
} else {
|
||||
require_once(DOKU_INC . 'inc/DifferenceEngine.php');
|
||||
$pagelog = new PageChangeLog($id);
|
||||
$revs = $pagelog->getRevisions(0, 1);
|
||||
$rev = $revs[0];
|
||||
|
||||
if ($rev) {
|
||||
$df = new Diff(
|
||||
explode("\n", rawWiki($id, $rev)),
|
||||
explode("\n", rawWiki($id, ''))
|
||||
);
|
||||
} else {
|
||||
$df = new Diff(
|
||||
[''],
|
||||
explode("\n", rawWiki($id, ''))
|
||||
);
|
||||
}
|
||||
|
||||
if ($opt['item_content'] == 'htmldiff') {
|
||||
// note: no need to escape diff output, TableDiffFormatter provides 'safe' html
|
||||
$tdf = new TableDiffFormatter();
|
||||
$content = '<table>';
|
||||
$content .= '<tr><th colspan="2" width="50%">' . $rev . '</th>';
|
||||
$content .= '<th colspan="2" width="50%">' . $lang['current'] . '</th></tr>';
|
||||
$content .= $tdf->format($df);
|
||||
$content .= '</table>';
|
||||
} else {
|
||||
// note: diff output must be escaped, UnifiedDiffFormatter provides plain text
|
||||
$udf = new UnifiedDiffFormatter();
|
||||
$content = "<pre>\n" . hsc($udf->format($df)) . "\n</pre>";
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'html':
|
||||
if ($ditem['media']) {
|
||||
if ($size = media_image_preview_size($id, '', new JpegMeta(mediaFN($id)))) {
|
||||
$more = 'w=' . $size[0] . '&h=' . $size[1] . '&t=' . @filemtime(mediaFN($id));
|
||||
$src = ml($id, $more, true, '&', true);
|
||||
$content = '<img src="' . $src . '" alt="' . $id . '" />';
|
||||
} else {
|
||||
$content = '';
|
||||
}
|
||||
} else {
|
||||
if (@filemtime(wikiFN($id)) === $date) {
|
||||
$content = p_wiki_xhtml($id, '', false);
|
||||
} else {
|
||||
$content = p_wiki_xhtml($id, $date, false);
|
||||
}
|
||||
// no TOC in feeds
|
||||
$content = preg_replace('/(<!-- TOC START -->).*(<!-- TOC END -->)/s', '', $content);
|
||||
|
||||
// add alignment for images
|
||||
$content = preg_replace('/(<img .*?class="medialeft")/s', '\\1 align="left"', $content);
|
||||
$content = preg_replace('/(<img .*?class="mediaright")/s', '\\1 align="right"', $content);
|
||||
|
||||
// make URLs work when canonical is not set, regexp instead of rerendering!
|
||||
if (!$conf['canonical']) {
|
||||
$base = preg_quote(DOKU_REL, '/');
|
||||
$content = preg_replace(
|
||||
'/(<a href|<img src)="(' . $base . ')/s', '$1="' . DOKU_URL,
|
||||
$content
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
case 'abstract':
|
||||
default:
|
||||
if ($ditem['media']) {
|
||||
if ($size = media_image_preview_size($id, '', new JpegMeta(mediaFN($id)))) {
|
||||
$more = 'w=' . $size[0] . '&h=' . $size[1] . '&t=' . @filemtime(mediaFN($id));
|
||||
$src = ml($id, $more, true, '&', true);
|
||||
$content = '<img src="' . $src . '" alt="' . $id . '" />';
|
||||
} else {
|
||||
$content = '';
|
||||
}
|
||||
} else {
|
||||
$content = $meta['description']['abstract'];
|
||||
}
|
||||
}
|
||||
$item->description = $content; //FIXME a plugin hook here could be senseful
|
||||
|
||||
// add user
|
||||
# FIXME should the user be pulled from metadata as well?
|
||||
$user = @$ditem['user']; // the @ spares time repeating lookup
|
||||
if (blank($user)) {
|
||||
$item->author = 'Anonymous';
|
||||
$item->authorEmail = 'anonymous@undisclosed.example.com';
|
||||
} else {
|
||||
$item->author = $user;
|
||||
$item->authorEmail = $user . '@undisclosed.example.com';
|
||||
|
||||
// get real user name if configured
|
||||
if ($conf['useacl'] && $auth) {
|
||||
$userInfo = $auth->getUserData($user);
|
||||
if ($userInfo) {
|
||||
switch ($conf['showuseras']) {
|
||||
case 'username':
|
||||
case 'username_link':
|
||||
$item->author = $userInfo['name'];
|
||||
break;
|
||||
default:
|
||||
$item->author = $user;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
$item->author = $user;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// add category
|
||||
if (isset($meta['subject'])) {
|
||||
$item->category = $meta['subject'];
|
||||
} else {
|
||||
$cat = getNS($id);
|
||||
if ($cat) $item->category = $cat;
|
||||
}
|
||||
|
||||
// finally add the item to the feed object, after handing it to registered plugins
|
||||
$evdata = [
|
||||
'item' => &$item,
|
||||
'opt' => &$opt,
|
||||
'ditem' => &$ditem,
|
||||
'rss' => &$rss
|
||||
];
|
||||
$evt = new Event('FEED_ITEM_ADD', $evdata);
|
||||
if ($evt->advise_before()) {
|
||||
$rss->addItem($item);
|
||||
}
|
||||
$evt->advise_after(); // for completeness
|
||||
}
|
||||
}
|
||||
$event->advise_after();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add recent changed pages to the feed object
|
||||
*
|
||||
* @author Andreas Gohr <andi@splitbrain.org>
|
||||
*/
|
||||
function rssRecentChanges($opt)
|
||||
{
|
||||
global $conf;
|
||||
$flags = 0;
|
||||
if (!$conf['rss_show_deleted']) $flags += RECENTS_SKIP_DELETED;
|
||||
if (!$opt['show_minor']) $flags += RECENTS_SKIP_MINORS;
|
||||
if ($opt['only_new']) $flags += RECENTS_ONLY_CREATION;
|
||||
if ($opt['content_type'] == 'media' && $conf['mediarevisions']) $flags += RECENTS_MEDIA_CHANGES;
|
||||
if ($opt['content_type'] == 'both' && $conf['mediarevisions']) $flags += RECENTS_MEDIA_PAGES_MIXED;
|
||||
|
||||
$recents = getRecents(0, $opt['items'], $opt['namespace'], $flags);
|
||||
return $recents;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add all pages of a namespace to the feed object
|
||||
*
|
||||
* @author Andreas Gohr <andi@splitbrain.org>
|
||||
*/
|
||||
function rssListNamespace($opt)
|
||||
{
|
||||
require_once(DOKU_INC . 'inc/search.php');
|
||||
global $conf;
|
||||
|
||||
$ns = ':' . cleanID($opt['namespace']);
|
||||
$ns = utf8_encodeFN(str_replace(':', '/', $ns));
|
||||
|
||||
$data = [];
|
||||
$search_opts = [
|
||||
'depth' => 1,
|
||||
'pagesonly' => true,
|
||||
'listfiles' => true
|
||||
];
|
||||
search($data, $conf['datadir'], 'search_universal', $search_opts, $ns, $lvl = 1, $opt['sort']);
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the result of a full text search to the feed object
|
||||
*
|
||||
* @author Andreas Gohr <andi@splitbrain.org>
|
||||
*/
|
||||
function rssSearch($opt)
|
||||
{
|
||||
if (!$opt['search_query'] || !actionOK('search')) return [];
|
||||
|
||||
require_once(DOKU_INC . 'inc/fulltext.php');
|
||||
$data = ft_pageSearch($opt['search_query'], $poswords);
|
||||
$data = array_keys($data);
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
//Setup VIM: ex: et ts=4 :
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
namespace dokuwiki\Action;
|
||||
|
||||
use dokuwiki\Action\Exception\ActionAclRequiredException;
|
||||
use dokuwiki\Extension\AuthPlugin;
|
||||
|
||||
/**
|
||||
* Class AbstractAclAction
|
||||
@@ -11,15 +12,15 @@ use dokuwiki\Action\Exception\ActionAclRequiredException;
|
||||
*
|
||||
* @package dokuwiki\Action
|
||||
*/
|
||||
abstract class AbstractAclAction extends AbstractAction {
|
||||
|
||||
abstract class AbstractAclAction extends AbstractAction
|
||||
{
|
||||
/** @inheritdoc */
|
||||
public function checkPreconditions() {
|
||||
public function checkPreconditions()
|
||||
{
|
||||
parent::checkPreconditions();
|
||||
global $conf;
|
||||
global $auth;
|
||||
if(!$conf['useacl']) throw new ActionAclRequiredException();
|
||||
if(!$auth) throw new ActionAclRequiredException();
|
||||
if (!$conf['useacl']) throw new ActionAclRequiredException();
|
||||
if (!$auth instanceof AuthPlugin) throw new ActionAclRequiredException();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -12,8 +12,8 @@ use dokuwiki\Action\Exception\FatalException;
|
||||
*
|
||||
* @package dokuwiki\Action
|
||||
*/
|
||||
abstract class AbstractAction {
|
||||
|
||||
abstract class AbstractAction
|
||||
{
|
||||
/** @var string holds the name of the action (lowercase class name, no namespace) */
|
||||
protected $actionname;
|
||||
|
||||
@@ -22,8 +22,9 @@ abstract class AbstractAction {
|
||||
*
|
||||
* @param string $actionname the name of this action (see getActionName() for caveats)
|
||||
*/
|
||||
public function __construct($actionname = '') {
|
||||
if($actionname !== '') {
|
||||
public function __construct($actionname = '')
|
||||
{
|
||||
if ($actionname !== '') {
|
||||
$this->actionname = $actionname;
|
||||
} else {
|
||||
// http://stackoverflow.com/a/27457689/172068
|
||||
@@ -48,7 +49,8 @@ abstract class AbstractAction {
|
||||
* @throws ActionException
|
||||
* @return void
|
||||
*/
|
||||
public function checkPreconditions() {
|
||||
public function checkPreconditions()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -61,7 +63,8 @@ abstract class AbstractAction {
|
||||
* @throws ActionException
|
||||
* @return void
|
||||
*/
|
||||
public function preProcess() {
|
||||
public function preProcess()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -70,7 +73,8 @@ abstract class AbstractAction {
|
||||
* @fixme we may want to return a Ui class here
|
||||
* @throws FatalException
|
||||
*/
|
||||
public function tplContent() {
|
||||
public function tplContent()
|
||||
{
|
||||
throw new FatalException('No content for Action ' . $this->actionname);
|
||||
}
|
||||
|
||||
@@ -82,7 +86,8 @@ abstract class AbstractAction {
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getActionName() {
|
||||
public function getActionName()
|
||||
{
|
||||
return $this->actionname;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,18 +14,19 @@ use dokuwiki\Action\Exception\FatalException;
|
||||
*
|
||||
* @package dokuwiki\Action
|
||||
*/
|
||||
abstract class AbstractAliasAction extends AbstractAction {
|
||||
|
||||
abstract class AbstractAliasAction extends AbstractAction
|
||||
{
|
||||
/** @inheritdoc */
|
||||
public function minimumPermission() {
|
||||
public function minimumPermission()
|
||||
{
|
||||
return AUTH_NONE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws FatalException
|
||||
*/
|
||||
public function preProcess() {
|
||||
public function preProcess()
|
||||
{
|
||||
throw new FatalException('Alias Actions need to implement preProcess to load the aliased action');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -11,15 +11,15 @@ use dokuwiki\Action\Exception\ActionUserRequiredException;
|
||||
*
|
||||
* @package dokuwiki\Action
|
||||
*/
|
||||
abstract class AbstractUserAction extends AbstractAclAction {
|
||||
|
||||
abstract class AbstractUserAction extends AbstractAclAction
|
||||
{
|
||||
/** @inheritdoc */
|
||||
public function checkPreconditions() {
|
||||
public function checkPreconditions()
|
||||
{
|
||||
parent::checkPreconditions();
|
||||
global $INPUT;
|
||||
if($INPUT->server->str('REMOTE_USER') === '') {
|
||||
if ($INPUT->server->str('REMOTE_USER') === '') {
|
||||
throw new ActionUserRequiredException();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -12,22 +12,24 @@ use dokuwiki\Extension\AdminPlugin;
|
||||
*
|
||||
* @package dokuwiki\Action
|
||||
*/
|
||||
class Admin extends AbstractUserAction {
|
||||
|
||||
class Admin extends AbstractUserAction
|
||||
{
|
||||
/** @inheritdoc */
|
||||
public function minimumPermission() {
|
||||
public function minimumPermission()
|
||||
{
|
||||
return AUTH_READ; // let in check later
|
||||
}
|
||||
|
||||
/** @inheritDoc */
|
||||
public function preProcess() {
|
||||
public function preProcess()
|
||||
{
|
||||
global $INPUT;
|
||||
|
||||
// retrieve admin plugin name from $_REQUEST['page']
|
||||
if($INPUT->str('page', '', true) != '') {
|
||||
if ($INPUT->str('page', '', true) != '') {
|
||||
/** @var AdminPlugin $plugin */
|
||||
if($plugin = plugin_getRequestAdminPlugin()) { // FIXME this method does also permission checking
|
||||
if(!$plugin->isAccessibleByCurrentUser()) {
|
||||
if ($plugin = plugin_getRequestAdminPlugin()) { // FIXME this method does also permission checking
|
||||
if (!$plugin->isAccessibleByCurrentUser()) {
|
||||
throw new ActionException('denied');
|
||||
}
|
||||
$plugin->handle();
|
||||
@@ -36,7 +38,8 @@ class Admin extends AbstractUserAction {
|
||||
}
|
||||
|
||||
/** @inheritDoc */
|
||||
public function tplContent() {
|
||||
public function tplContent()
|
||||
{
|
||||
tpl_admin();
|
||||
}
|
||||
}
|
||||
|
||||
34
dokuwiki/inc/Action/Authtoken.php
Normal file
34
dokuwiki/inc/Action/Authtoken.php
Normal file
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace dokuwiki\Action;
|
||||
|
||||
use dokuwiki\Action\Exception\ActionAbort;
|
||||
use dokuwiki\Action\Exception\ActionException;
|
||||
use dokuwiki\JWT;
|
||||
|
||||
class Authtoken extends AbstractUserAction
|
||||
{
|
||||
/** @inheritdoc */
|
||||
public function minimumPermission()
|
||||
{
|
||||
return AUTH_NONE;
|
||||
}
|
||||
|
||||
/** @inheritdoc */
|
||||
public function checkPreconditions()
|
||||
{
|
||||
parent::checkPreconditions();
|
||||
|
||||
if (!checkSecurityToken()) throw new ActionException('profile');
|
||||
}
|
||||
|
||||
/** @inheritdoc */
|
||||
public function preProcess()
|
||||
{
|
||||
global $INPUT;
|
||||
parent::preProcess();
|
||||
$token = JWT::fromUser($INPUT->server->str('REMOTE_USER'));
|
||||
$token->save();
|
||||
throw new ActionAbort('profile');
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace dokuwiki\Action;
|
||||
|
||||
use dokuwiki\Ui\Backlinks;
|
||||
use dokuwiki\Ui;
|
||||
|
||||
/**
|
||||
@@ -22,7 +23,6 @@ class Backlink extends AbstractAction
|
||||
/** @inheritdoc */
|
||||
public function tplContent()
|
||||
{
|
||||
(new Ui\Backlinks)->show();
|
||||
(new Backlinks())->show();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -11,18 +11,18 @@ use dokuwiki\Action\Exception\ActionAbort;
|
||||
*
|
||||
* @package dokuwiki\Action
|
||||
*/
|
||||
class Cancel extends AbstractAliasAction {
|
||||
|
||||
class Cancel extends AbstractAliasAction
|
||||
{
|
||||
/**
|
||||
* @inheritdoc
|
||||
* @throws ActionAbort
|
||||
*/
|
||||
public function preProcess() {
|
||||
public function preProcess()
|
||||
{
|
||||
global $ID;
|
||||
unlock($ID);
|
||||
|
||||
// continue with draftdel -> redirect -> show
|
||||
throw new ActionAbort('draftdel');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -11,16 +11,17 @@ use dokuwiki\Action\Exception\ActionAbort;
|
||||
*
|
||||
* @package dokuwiki\Action
|
||||
*/
|
||||
class Check extends AbstractAction {
|
||||
|
||||
class Check extends AbstractAction
|
||||
{
|
||||
/** @inheritdoc */
|
||||
public function minimumPermission() {
|
||||
public function minimumPermission()
|
||||
{
|
||||
return AUTH_READ;
|
||||
}
|
||||
|
||||
public function preProcess() {
|
||||
public function preProcess()
|
||||
{
|
||||
check();
|
||||
throw new ActionAbort();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace dokuwiki\Action;
|
||||
|
||||
use dokuwiki\Ui\PageConflict;
|
||||
use dokuwiki\Ui;
|
||||
|
||||
/**
|
||||
@@ -33,7 +34,6 @@ class Conflict extends AbstractAction
|
||||
global $SUM;
|
||||
|
||||
$text = con($PRE, $TEXT, $SUF);
|
||||
(new Ui\PageConflict($text, $SUM))->show();
|
||||
(new PageConflict($text, $SUM))->show();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace dokuwiki\Action;
|
||||
|
||||
use dokuwiki\Ui\Login;
|
||||
use dokuwiki\Extension\Event;
|
||||
use dokuwiki\Ui;
|
||||
|
||||
@@ -30,7 +31,7 @@ class Denied extends AbstractAction
|
||||
if ($event->advise_before()) {
|
||||
global $INPUT;
|
||||
if (empty($INPUT->server->str('REMOTE_USER')) && actionOK('login')) {
|
||||
(new Ui\Login)->show();
|
||||
(new Login())->show();
|
||||
}
|
||||
}
|
||||
$event->advise_after();
|
||||
@@ -46,7 +47,6 @@ class Denied extends AbstractAction
|
||||
public function showBanner()
|
||||
{
|
||||
// print intro
|
||||
print p_locale_xhtml('denied');
|
||||
echo p_locale_xhtml('denied');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace dokuwiki\Action;
|
||||
|
||||
use dokuwiki\Ui\PageDiff;
|
||||
use dokuwiki\Ui;
|
||||
|
||||
/**
|
||||
@@ -35,7 +36,6 @@ class Diff extends AbstractAction
|
||||
public function tplContent()
|
||||
{
|
||||
global $INFO;
|
||||
(new Ui\PageDiff($INFO['id']))->preference('showIntro', true)->show();
|
||||
(new PageDiff($INFO['id']))->preference('showIntro', true)->show();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace dokuwiki\Action;
|
||||
|
||||
use dokuwiki\Ui\PageDraft;
|
||||
use dokuwiki\Action\Exception\ActionException;
|
||||
use dokuwiki\Ui;
|
||||
|
||||
@@ -31,13 +32,12 @@ class Draft extends AbstractAction
|
||||
{
|
||||
parent::checkPreconditions();
|
||||
global $INFO;
|
||||
if (!file_exists($INFO['draft'])) throw new ActionException('edit');
|
||||
if (!isset($INFO['draft']) || !file_exists($INFO['draft'])) throw new ActionException('edit');
|
||||
}
|
||||
|
||||
/** @inheritdoc */
|
||||
public function tplContent()
|
||||
{
|
||||
(new Ui\PageDraft)->show();
|
||||
(new PageDraft())->show();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace dokuwiki\Action;
|
||||
|
||||
use dokuwiki\Draft;
|
||||
use dokuwiki\Action\Exception\ActionAbort;
|
||||
|
||||
/**
|
||||
@@ -11,10 +12,11 @@ use dokuwiki\Action\Exception\ActionAbort;
|
||||
*
|
||||
* @package dokuwiki\Action
|
||||
*/
|
||||
class Draftdel extends AbstractAction {
|
||||
|
||||
class Draftdel extends AbstractAction
|
||||
{
|
||||
/** @inheritdoc */
|
||||
public function minimumPermission() {
|
||||
public function minimumPermission()
|
||||
{
|
||||
return AUTH_EDIT;
|
||||
}
|
||||
|
||||
@@ -25,14 +27,14 @@ class Draftdel extends AbstractAction {
|
||||
*
|
||||
* @throws ActionAbort
|
||||
*/
|
||||
public function preProcess() {
|
||||
public function preProcess()
|
||||
{
|
||||
global $INFO, $ID;
|
||||
$draft = new \dokuwiki\Draft($ID, $INFO['client']);
|
||||
$draft = new Draft($ID, $INFO['client']);
|
||||
if ($draft->isDraftAvailable() && checkSecurityToken()) {
|
||||
$draft->deleteDraft();
|
||||
}
|
||||
|
||||
throw new ActionAbort('redirect');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace dokuwiki\Action;
|
||||
|
||||
use dokuwiki\Ui\Editor;
|
||||
use dokuwiki\Action\Exception\ActionAbort;
|
||||
use dokuwiki\Ui;
|
||||
|
||||
@@ -57,7 +58,7 @@ class Edit extends AbstractAction
|
||||
if (!isset($TEXT)) {
|
||||
if ($INFO['exists']) {
|
||||
if ($RANGE) {
|
||||
list($PRE, $TEXT, $SUF) = rawWikiSlices($RANGE, $ID, $REV);
|
||||
[$PRE, $TEXT, $SUF] = rawWikiSlices($RANGE, $ID, $REV);
|
||||
} else {
|
||||
$TEXT = rawWiki($ID, $REV);
|
||||
}
|
||||
@@ -90,7 +91,6 @@ class Edit extends AbstractAction
|
||||
/** @inheritdoc */
|
||||
public function tplContent()
|
||||
{
|
||||
(new Ui\Editor)->show();
|
||||
(new Editor())->show();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -15,6 +15,6 @@ namespace dokuwiki\Action\Exception;
|
||||
*
|
||||
* @package dokuwiki\Action\Exception
|
||||
*/
|
||||
class ActionAbort extends ActionException {
|
||||
|
||||
class ActionAbort extends ActionException
|
||||
{
|
||||
}
|
||||
|
||||
@@ -12,6 +12,6 @@ namespace dokuwiki\Action\Exception;
|
||||
*
|
||||
* @package dokuwiki\Action\Exception
|
||||
*/
|
||||
class ActionAclRequiredException extends ActionException {
|
||||
|
||||
class ActionAclRequiredException extends ActionException
|
||||
{
|
||||
}
|
||||
|
||||
@@ -12,6 +12,6 @@ namespace dokuwiki\Action\Exception;
|
||||
*
|
||||
* @package dokuwiki\Action\Exception
|
||||
*/
|
||||
class ActionDisabledException extends ActionException {
|
||||
|
||||
class ActionDisabledException extends ActionException
|
||||
{
|
||||
}
|
||||
|
||||
@@ -13,8 +13,8 @@ namespace dokuwiki\Action\Exception;
|
||||
*
|
||||
* @package dokuwiki\Action\Exception
|
||||
*/
|
||||
class ActionException extends \Exception {
|
||||
|
||||
class ActionException extends \Exception
|
||||
{
|
||||
/** @var string the new action */
|
||||
protected $newaction;
|
||||
|
||||
@@ -30,11 +30,12 @@ class ActionException extends \Exception {
|
||||
* @param string|null $newaction the action that should be used next
|
||||
* @param string $message optional message, will not be shown except for some dub classes
|
||||
*/
|
||||
public function __construct($newaction = null, $message = '') {
|
||||
public function __construct($newaction = null, $message = '')
|
||||
{
|
||||
global $INPUT;
|
||||
parent::__construct($message);
|
||||
if(is_null($newaction)) {
|
||||
if(strtolower($INPUT->server->str('REQUEST_METHOD')) == 'post') {
|
||||
if (is_null($newaction)) {
|
||||
if (strtolower($INPUT->server->str('REQUEST_METHOD')) == 'post') {
|
||||
$newaction = 'redirect';
|
||||
} else {
|
||||
$newaction = 'show';
|
||||
@@ -49,7 +50,8 @@ class ActionException extends \Exception {
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getNewAction() {
|
||||
public function getNewAction()
|
||||
{
|
||||
return $this->newaction;
|
||||
}
|
||||
|
||||
@@ -59,8 +61,9 @@ class ActionException extends \Exception {
|
||||
* @param null|bool $set when null is given, the current setting is not changed
|
||||
* @return bool
|
||||
*/
|
||||
public function displayToUser($set = null) {
|
||||
if(!is_null($set)) $this->displayToUser = $set;
|
||||
public function displayToUser($set = null)
|
||||
{
|
||||
if (!is_null($set)) $this->displayToUser = $set;
|
||||
return $set;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,6 @@ namespace dokuwiki\Action\Exception;
|
||||
*
|
||||
* @package dokuwiki\Action\Exception
|
||||
*/
|
||||
class ActionUserRequiredException extends ActionException {
|
||||
|
||||
class ActionUserRequiredException extends ActionException
|
||||
{
|
||||
}
|
||||
|
||||
@@ -12,7 +12,8 @@ namespace dokuwiki\Action\Exception;
|
||||
*
|
||||
* @package dokuwiki\Action\Exception
|
||||
*/
|
||||
class FatalException extends \Exception {
|
||||
class FatalException extends \Exception
|
||||
{
|
||||
/**
|
||||
* FatalException constructor.
|
||||
*
|
||||
@@ -20,7 +21,8 @@ class FatalException extends \Exception {
|
||||
* @param int $status the HTTP status to send
|
||||
* @param null|\Exception $previous previous exception
|
||||
*/
|
||||
public function __construct($message = 'A fatal error occured', $status = 500, $previous = null) {
|
||||
public function __construct($message = 'A fatal error occured', $status = 500, $previous = null)
|
||||
{
|
||||
parent::__construct($message, $status, $previous);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,6 @@ namespace dokuwiki\Action\Exception;
|
||||
*
|
||||
* @package dokuwiki\Action\Exception
|
||||
*/
|
||||
class NoActionException extends \Exception {
|
||||
|
||||
class NoActionException extends \Exception
|
||||
{
|
||||
}
|
||||
|
||||
@@ -12,10 +12,11 @@ use dokuwiki\Extension\Event;
|
||||
*
|
||||
* @package dokuwiki\Action
|
||||
*/
|
||||
class Export extends AbstractAction {
|
||||
|
||||
class Export extends AbstractAction
|
||||
{
|
||||
/** @inheritdoc */
|
||||
public function minimumPermission() {
|
||||
public function minimumPermission()
|
||||
{
|
||||
return AUTH_READ;
|
||||
}
|
||||
|
||||
@@ -34,7 +35,8 @@ class Export extends AbstractAction {
|
||||
* @author Michael Klier <chi@chimeric.de>
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function preProcess() {
|
||||
public function preProcess()
|
||||
{
|
||||
global $ID;
|
||||
global $REV;
|
||||
global $conf;
|
||||
@@ -42,13 +44,13 @@ class Export extends AbstractAction {
|
||||
|
||||
$pre = '';
|
||||
$post = '';
|
||||
$headers = array();
|
||||
$headers = [];
|
||||
|
||||
// search engines: never cache exported docs! (Google only currently)
|
||||
$headers['X-Robots-Tag'] = 'noindex';
|
||||
|
||||
$mode = substr($this->actionname, 7);
|
||||
switch($mode) {
|
||||
switch ($mode) {
|
||||
case 'raw':
|
||||
$headers['Content-Type'] = 'text/plain; charset=utf-8';
|
||||
$headers['Content-Disposition'] = 'attachment; filename=' . noNS($ID) . '.txt';
|
||||
@@ -91,7 +93,7 @@ class Export extends AbstractAction {
|
||||
}
|
||||
|
||||
// prepare event data
|
||||
$data = array();
|
||||
$data = [];
|
||||
$data['id'] = $ID;
|
||||
$data['mode'] = $mode;
|
||||
$data['headers'] = $headers;
|
||||
@@ -99,15 +101,14 @@ class Export extends AbstractAction {
|
||||
|
||||
Event::createAndTrigger('ACTION_EXPORT_POSTPROCESS', $data);
|
||||
|
||||
if(!empty($data['output'])) {
|
||||
if(is_array($data['headers'])) foreach($data['headers'] as $key => $val) {
|
||||
if (!empty($data['output'])) {
|
||||
if (is_array($data['headers'])) foreach ($data['headers'] as $key => $val) {
|
||||
header("$key: $val");
|
||||
}
|
||||
print $pre . $data['output'] . $post;
|
||||
echo $pre . $data['output'] . $post;
|
||||
exit;
|
||||
}
|
||||
|
||||
throw new ActionAbort();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -25,5 +25,4 @@ class Index extends AbstractAction
|
||||
global $IDX;
|
||||
(new Ui\Index($IDX))->show();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace dokuwiki\Action;
|
||||
|
||||
use dokuwiki\Ui;
|
||||
use dokuwiki\Ui\Editor;
|
||||
|
||||
/**
|
||||
* Class Locked
|
||||
@@ -23,15 +23,15 @@ class Locked extends AbstractAction
|
||||
public function tplContent()
|
||||
{
|
||||
$this->showBanner();
|
||||
(new Ui\Editor)->show();
|
||||
(new Editor())->show();
|
||||
}
|
||||
|
||||
/**
|
||||
* Display error on locked pages
|
||||
*
|
||||
* @return void
|
||||
* @author Andreas Gohr <andi@splitbrain.org>
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function showBanner()
|
||||
{
|
||||
@@ -42,15 +42,16 @@ class Locked extends AbstractAction
|
||||
|
||||
$locktime = filemtime(wikiLockFN($ID));
|
||||
$expire = dformat($locktime + $conf['locktime']);
|
||||
$min = round(($conf['locktime'] - (time() - $locktime) )/60);
|
||||
$min = round(($conf['locktime'] - (time() - $locktime)) / 60);
|
||||
|
||||
// print intro
|
||||
print p_locale_xhtml('locked');
|
||||
echo p_locale_xhtml('locked');
|
||||
|
||||
print '<ul>';
|
||||
print '<li><div class="li"><strong>'.$lang['lockedby'].'</strong> '.editorinfo($INFO['locked']).'</div></li>';
|
||||
print '<li><div class="li"><strong>'.$lang['lockexpire'].'</strong> '.$expire.' ('.$min.' min)</div></li>';
|
||||
print '</ul>'.DOKU_LF;
|
||||
echo '<ul>';
|
||||
echo '<li><div class="li"><strong>' . $lang['lockedby'] . '</strong> ' .
|
||||
editorinfo($INFO['locked']) . '</div></li>';
|
||||
echo '<li><div class="li"><strong>' . $lang['lockexpire'] . '</strong> ' .
|
||||
$expire . ' (' . $min . ' min)</div></li>';
|
||||
echo '</ul>' . DOKU_LF;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -34,7 +34,6 @@ class Login extends AbstractAclAction
|
||||
/** @inheritdoc */
|
||||
public function tplContent()
|
||||
{
|
||||
(new Ui\Login)->show();
|
||||
(new Ui\Login())->show();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -13,24 +13,27 @@ use dokuwiki\Extension\AuthPlugin;
|
||||
*
|
||||
* @package dokuwiki\Action
|
||||
*/
|
||||
class Logout extends AbstractUserAction {
|
||||
|
||||
class Logout extends AbstractUserAction
|
||||
{
|
||||
/** @inheritdoc */
|
||||
public function minimumPermission() {
|
||||
public function minimumPermission()
|
||||
{
|
||||
return AUTH_NONE;
|
||||
}
|
||||
|
||||
/** @inheritdoc */
|
||||
public function checkPreconditions() {
|
||||
public function checkPreconditions()
|
||||
{
|
||||
parent::checkPreconditions();
|
||||
|
||||
/** @var AuthPlugin $auth */
|
||||
global $auth;
|
||||
if(!$auth->canDo('logout')) throw new ActionDisabledException();
|
||||
if (!$auth->canDo('logout')) throw new ActionDisabledException();
|
||||
}
|
||||
|
||||
/** @inheritdoc */
|
||||
public function preProcess() {
|
||||
public function preProcess()
|
||||
{
|
||||
global $ID;
|
||||
global $INPUT;
|
||||
|
||||
@@ -38,16 +41,15 @@ class Logout extends AbstractUserAction {
|
||||
|
||||
// when logging out during an edit session, unlock the page
|
||||
$lockedby = checklock($ID);
|
||||
if($lockedby == $INPUT->server->str('REMOTE_USER')) {
|
||||
if ($lockedby == $INPUT->server->str('REMOTE_USER')) {
|
||||
unlock($ID);
|
||||
}
|
||||
|
||||
// do the logout stuff and redirect to login
|
||||
auth_logoff();
|
||||
send_redirect(wl($ID, array('do' => 'login'), true, '&'));
|
||||
send_redirect(wl($ID, ['do' => 'login'], true, '&'));
|
||||
|
||||
// should never be reached
|
||||
throw new ActionException('login');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -9,16 +9,17 @@ namespace dokuwiki\Action;
|
||||
*
|
||||
* @package dokuwiki\Action
|
||||
*/
|
||||
class Media extends AbstractAction {
|
||||
|
||||
class Media extends AbstractAction
|
||||
{
|
||||
/** @inheritdoc */
|
||||
public function minimumPermission() {
|
||||
public function minimumPermission()
|
||||
{
|
||||
return AUTH_READ;
|
||||
}
|
||||
|
||||
/** @inheritdoc */
|
||||
public function tplContent() {
|
||||
public function tplContent()
|
||||
{
|
||||
tpl_media();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -11,10 +11,11 @@ use dokuwiki\Extension\Event;
|
||||
*
|
||||
* @package dokuwiki\Action
|
||||
*/
|
||||
class Plugin extends AbstractAction {
|
||||
|
||||
class Plugin extends AbstractAction
|
||||
{
|
||||
/** @inheritdoc */
|
||||
public function minimumPermission() {
|
||||
public function minimumPermission()
|
||||
{
|
||||
return AUTH_NONE;
|
||||
}
|
||||
|
||||
@@ -24,9 +25,10 @@ class Plugin extends AbstractAction {
|
||||
* @inheritdoc
|
||||
* @triggers TPL_ACT_UNKNOWN
|
||||
*/
|
||||
public function tplContent() {
|
||||
public function tplContent()
|
||||
{
|
||||
$evt = new Event('TPL_ACT_UNKNOWN', $this->actionname);
|
||||
if($evt->advise_before()) {
|
||||
if ($evt->advise_before()) {
|
||||
msg('Failed to handle action: ' . hsc($this->actionname), -1);
|
||||
}
|
||||
$evt->advise_after();
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
|
||||
namespace dokuwiki\Action;
|
||||
|
||||
use dokuwiki\Ui\Editor;
|
||||
use dokuwiki\Ui\PageView;
|
||||
use dokuwiki\Draft;
|
||||
use dokuwiki\Ui;
|
||||
|
||||
/**
|
||||
@@ -25,8 +28,8 @@ class Preview extends Edit
|
||||
public function tplContent()
|
||||
{
|
||||
global $TEXT;
|
||||
(new Ui\Editor)->show();
|
||||
(new Ui\PageView($TEXT))->show();
|
||||
(new Editor())->show();
|
||||
(new PageView($TEXT))->show();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -35,7 +38,7 @@ class Preview extends Edit
|
||||
protected function savedraft()
|
||||
{
|
||||
global $ID, $INFO;
|
||||
$draft = new \dokuwiki\Draft($ID, $INFO['client']);
|
||||
$draft = new Draft($ID, $INFO['client']);
|
||||
if (!$draft->saveDraft()) {
|
||||
$errors = $draft->getErrors();
|
||||
foreach ($errors as $error) {
|
||||
@@ -43,5 +46,4 @@ class Preview extends Edit
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace dokuwiki\Action;
|
||||
|
||||
use dokuwiki\Ui\UserProfile;
|
||||
use dokuwiki\Action\Exception\ActionAbort;
|
||||
use dokuwiki\Action\Exception\ActionDisabledException;
|
||||
use dokuwiki\Extension\AuthPlugin;
|
||||
@@ -29,7 +30,7 @@ class Profile extends AbstractUserAction
|
||||
|
||||
/** @var AuthPlugin $auth */
|
||||
global $auth;
|
||||
if(!$auth->canDo('Profile')) throw new ActionDisabledException();
|
||||
if (!$auth->canDo('Profile')) throw new ActionDisabledException();
|
||||
}
|
||||
|
||||
/** @inheritdoc */
|
||||
@@ -45,7 +46,6 @@ class Profile extends AbstractUserAction
|
||||
/** @inheritdoc */
|
||||
public function tplContent()
|
||||
{
|
||||
(new Ui\UserProfile)->show();
|
||||
(new UserProfile())->show();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -13,31 +13,33 @@ use dokuwiki\Extension\AuthPlugin;
|
||||
*
|
||||
* @package dokuwiki\Action
|
||||
*/
|
||||
class ProfileDelete extends AbstractUserAction {
|
||||
|
||||
class ProfileDelete extends AbstractUserAction
|
||||
{
|
||||
/** @inheritdoc */
|
||||
public function minimumPermission() {
|
||||
public function minimumPermission()
|
||||
{
|
||||
return AUTH_NONE;
|
||||
}
|
||||
|
||||
/** @inheritdoc */
|
||||
public function checkPreconditions() {
|
||||
public function checkPreconditions()
|
||||
{
|
||||
parent::checkPreconditions();
|
||||
|
||||
/** @var AuthPlugin $auth */
|
||||
global $auth;
|
||||
if(!$auth->canDo('delUser')) throw new ActionDisabledException();
|
||||
if (!$auth->canDo('delUser')) throw new ActionDisabledException();
|
||||
}
|
||||
|
||||
/** @inheritdoc */
|
||||
public function preProcess() {
|
||||
public function preProcess()
|
||||
{
|
||||
global $lang;
|
||||
if(auth_deleteprofile()) {
|
||||
if (auth_deleteprofile()) {
|
||||
msg($lang['profdeleted'], 1);
|
||||
throw new ActionAbort('show');
|
||||
} else {
|
||||
throw new ActionAbort('profile');
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -41,5 +41,4 @@ class Recent extends AbstractAction
|
||||
global $INPUT;
|
||||
(new Ui\Recent($INPUT->extract('first')->int('first'), $this->showType))->show();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -11,14 +11,14 @@ use dokuwiki\Action\Exception\ActionAbort;
|
||||
*
|
||||
* @package dokuwiki\Action
|
||||
*/
|
||||
class Recover extends AbstractAliasAction {
|
||||
|
||||
class Recover extends AbstractAliasAction
|
||||
{
|
||||
/**
|
||||
* @inheritdoc
|
||||
* @throws ActionAbort
|
||||
*/
|
||||
public function preProcess() {
|
||||
public function preProcess()
|
||||
{
|
||||
throw new ActionAbort('edit');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -12,37 +12,35 @@ use dokuwiki\Extension\Event;
|
||||
*
|
||||
* @package dokuwiki\Action
|
||||
*/
|
||||
class Redirect extends AbstractAliasAction {
|
||||
|
||||
class Redirect extends AbstractAliasAction
|
||||
{
|
||||
/**
|
||||
* Redirect to the show action, trying to jump to the previously edited section
|
||||
*
|
||||
* @triggers ACTION_SHOW_REDIRECT
|
||||
* @throws ActionAbort
|
||||
*/
|
||||
public function preProcess() {
|
||||
public function preProcess()
|
||||
{
|
||||
global $PRE;
|
||||
global $TEXT;
|
||||
global $INPUT;
|
||||
global $ID;
|
||||
global $ACT;
|
||||
|
||||
$opts = array(
|
||||
'id' => $ID,
|
||||
'preact' => $ACT
|
||||
);
|
||||
$opts = ['id' => $ID, 'preact' => $ACT];
|
||||
//get section name when coming from section edit
|
||||
if($INPUT->has('hid')) {
|
||||
if ($INPUT->has('hid')) {
|
||||
// Use explicitly transmitted header id
|
||||
$opts['fragment'] = $INPUT->str('hid');
|
||||
} else if($PRE && preg_match('/^\s*==+([^=\n]+)/', $TEXT, $match)) {
|
||||
} elseif ($PRE && preg_match('/^\s*==+([^=\n]+)/', $TEXT, $match)) {
|
||||
// Fallback to old mechanism
|
||||
$check = false; //Byref
|
||||
$opts['fragment'] = sectionID($match[0], $check);
|
||||
}
|
||||
|
||||
// execute the redirect
|
||||
Event::createAndTrigger('ACTION_SHOW_REDIRECT', $opts, array($this, 'redirect'));
|
||||
Event::createAndTrigger('ACTION_SHOW_REDIRECT', $opts, [$this, 'redirect']);
|
||||
|
||||
// should never be reached
|
||||
throw new ActionAbort('show');
|
||||
@@ -55,9 +53,10 @@ class Redirect extends AbstractAliasAction {
|
||||
*
|
||||
* @param array $opts id and fragment for the redirect and the preact
|
||||
*/
|
||||
public function redirect($opts) {
|
||||
public function redirect($opts)
|
||||
{
|
||||
$go = wl($opts['id'], '', true, '&');
|
||||
if(isset($opts['fragment'])) $go .= '#' . $opts['fragment'];
|
||||
if (isset($opts['fragment'])) $go .= '#' . $opts['fragment'];
|
||||
|
||||
//show it
|
||||
send_redirect($go);
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace dokuwiki\Action;
|
||||
|
||||
use dokuwiki\Ui\UserRegister;
|
||||
use dokuwiki\Action\Exception\ActionAbort;
|
||||
use dokuwiki\Action\Exception\ActionDisabledException;
|
||||
use dokuwiki\Extension\AuthPlugin;
|
||||
@@ -45,7 +46,6 @@ class Register extends AbstractAclAction
|
||||
/** @inheritdoc */
|
||||
public function tplContent()
|
||||
{
|
||||
(new Ui\UserRegister)->show();
|
||||
(new UserRegister())->show();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace dokuwiki\Action;
|
||||
|
||||
use dokuwiki\Ui\UserResendPwd;
|
||||
use dokuwiki\Action\Exception\ActionAbort;
|
||||
use dokuwiki\Action\Exception\ActionDisabledException;
|
||||
use dokuwiki\Extension\AuthPlugin;
|
||||
@@ -46,7 +47,7 @@ class Resendpwd extends AbstractAclAction
|
||||
/** @inheritdoc */
|
||||
public function tplContent()
|
||||
{
|
||||
(new Ui\UserResendPwd)->show();
|
||||
(new UserResendPwd())->show();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -81,7 +82,7 @@ class Resendpwd extends AbstractAclAction
|
||||
if ($token) {
|
||||
// we're in token phase - get user info from token
|
||||
|
||||
$tfile = $conf['cachedir'] .'/'. $token[0] .'/'. $token . '.pwauth';
|
||||
$tfile = $conf['cachedir'] . '/' . $token[0] . '/' . $token . '.pwauth';
|
||||
if (!file_exists($tfile)) {
|
||||
msg($lang['resendpwdbadauth'], -1);
|
||||
$INPUT->remove('pwauth');
|
||||
@@ -97,7 +98,7 @@ class Resendpwd extends AbstractAclAction
|
||||
|
||||
$user = io_readfile($tfile);
|
||||
$userinfo = $auth->getUserData($user, $requireGroups = false);
|
||||
if (!$userinfo['mail']) {
|
||||
if (empty($userinfo['mail'])) {
|
||||
msg($lang['resendpwdnouser'], -1);
|
||||
return false;
|
||||
}
|
||||
@@ -113,15 +114,13 @@ class Resendpwd extends AbstractAclAction
|
||||
}
|
||||
|
||||
// change it
|
||||
if (!$auth->triggerUserMod('modify', array($user, array('pass' => $pass)))) {
|
||||
if (!$auth->triggerUserMod('modify', [$user, ['pass' => $pass]])) {
|
||||
msg($lang['proffail'], -1);
|
||||
return false;
|
||||
}
|
||||
|
||||
} else { // autogenerate the password and send by mail
|
||||
|
||||
$pass = auth_pwgen($user);
|
||||
if (!$auth->triggerUserMod('modify', array($user, array('pass' => $pass)))) {
|
||||
if (!$auth->triggerUserMod('modify', [$user, ['pass' => $pass]])) {
|
||||
msg($lang['proffail'], -1);
|
||||
return false;
|
||||
}
|
||||
@@ -135,7 +134,6 @@ class Resendpwd extends AbstractAclAction
|
||||
|
||||
@unlink($tfile);
|
||||
return true;
|
||||
|
||||
} else {
|
||||
// we're in request phase
|
||||
|
||||
@@ -149,27 +147,27 @@ class Resendpwd extends AbstractAclAction
|
||||
}
|
||||
|
||||
$userinfo = $auth->getUserData($user, $requireGroups = false);
|
||||
if (!$userinfo['mail']) {
|
||||
if (empty($userinfo['mail'])) {
|
||||
msg($lang['resendpwdnouser'], -1);
|
||||
return false;
|
||||
}
|
||||
|
||||
// generate auth token
|
||||
$token = md5(auth_randombytes(16)); // random secret
|
||||
$tfile = $conf['cachedir'] .'/'. $token[0] .'/'. $token .'.pwauth';
|
||||
$url = wl('', array('do' => 'resendpwd', 'pwauth' => $token), true, '&');
|
||||
$tfile = $conf['cachedir'] . '/' . $token[0] . '/' . $token . '.pwauth';
|
||||
$url = wl('', ['do' => 'resendpwd', 'pwauth' => $token], true, '&');
|
||||
|
||||
io_saveFile($tfile, $user);
|
||||
|
||||
$text = rawLocale('pwconfirm');
|
||||
$trep = array(
|
||||
$trep = [
|
||||
'FULLNAME' => $userinfo['name'],
|
||||
'LOGIN' => $user,
|
||||
'CONFIRM' => $url
|
||||
);
|
||||
];
|
||||
|
||||
$mail = new \Mailer();
|
||||
$mail->to($userinfo['name'] .' <'. $userinfo['mail'] .'>');
|
||||
$mail->to($userinfo['name'] . ' <' . $userinfo['mail'] . '>');
|
||||
$mail->subject($lang['regpwmail']);
|
||||
$mail->setBody($text, $trep);
|
||||
if ($mail->send()) {
|
||||
@@ -181,5 +179,4 @@ class Resendpwd extends AbstractAclAction
|
||||
}
|
||||
// never reached
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -14,7 +14,6 @@ use dokuwiki\Action\Exception\ActionException;
|
||||
*/
|
||||
class Revert extends AbstractUserAction
|
||||
{
|
||||
|
||||
/** @inheritdoc */
|
||||
public function minimumPermission()
|
||||
{
|
||||
@@ -59,5 +58,4 @@ class Revert extends AbstractUserAction
|
||||
// continue with draftdel -> redirect -> show
|
||||
throw new ActionAbort('draftdel');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace dokuwiki\Action;
|
||||
|
||||
use dokuwiki\Ui\PageRevisions;
|
||||
use dokuwiki\Ui;
|
||||
|
||||
/**
|
||||
@@ -23,6 +24,6 @@ class Revisions extends AbstractAction
|
||||
public function tplContent()
|
||||
{
|
||||
global $INFO, $INPUT;
|
||||
(new Ui\PageRevisions($INFO['id']))->show($INPUT->int('first'));
|
||||
(new PageRevisions($INFO['id']))->show($INPUT->int('first', -1));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,12 +12,13 @@ use dokuwiki\Action\Exception\ActionException;
|
||||
*
|
||||
* @package dokuwiki\Action
|
||||
*/
|
||||
class Save extends AbstractAction {
|
||||
|
||||
class Save extends AbstractAction
|
||||
{
|
||||
/** @inheritdoc */
|
||||
public function minimumPermission() {
|
||||
public function minimumPermission()
|
||||
{
|
||||
global $INFO;
|
||||
if($INFO['exists']) {
|
||||
if ($INFO['exists']) {
|
||||
return AUTH_EDIT;
|
||||
} else {
|
||||
return AUTH_CREATE;
|
||||
@@ -25,8 +26,9 @@ class Save extends AbstractAction {
|
||||
}
|
||||
|
||||
/** @inheritdoc */
|
||||
public function preProcess() {
|
||||
if(!checkSecurityToken()) throw new ActionException('preview');
|
||||
public function preProcess()
|
||||
{
|
||||
if (!checkSecurityToken()) throw new ActionException('preview');
|
||||
|
||||
global $ID;
|
||||
global $DATE;
|
||||
@@ -39,12 +41,13 @@ class Save extends AbstractAction {
|
||||
global $INPUT;
|
||||
|
||||
//spam check
|
||||
if(checkwordblock()) {
|
||||
if (checkwordblock()) {
|
||||
msg($lang['wordblock'], -1);
|
||||
throw new ActionException('edit');
|
||||
}
|
||||
//conflict check
|
||||
if($DATE != 0
|
||||
if (
|
||||
$DATE != 0
|
||||
&& isset($INFO['meta']['date']['modified'])
|
||||
&& $INFO['meta']['date']['modified'] > $DATE
|
||||
) {
|
||||
@@ -59,5 +62,4 @@ class Save extends AbstractAction {
|
||||
// continue with draftdel -> redirect -> show
|
||||
throw new ActionAbort('draftdel');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -11,14 +11,15 @@ use dokuwiki\Action\Exception\ActionAbort;
|
||||
*
|
||||
* @package dokuwiki\Action
|
||||
*/
|
||||
class Search extends AbstractAction {
|
||||
|
||||
protected $pageLookupResults = array();
|
||||
protected $fullTextResults = array();
|
||||
protected $highlight = array();
|
||||
class Search extends AbstractAction
|
||||
{
|
||||
protected $pageLookupResults = [];
|
||||
protected $fullTextResults = [];
|
||||
protected $highlight = [];
|
||||
|
||||
/** @inheritdoc */
|
||||
public function minimumPermission() {
|
||||
public function minimumPermission()
|
||||
{
|
||||
return AUTH_NONE;
|
||||
}
|
||||
|
||||
@@ -27,7 +28,8 @@ class Search extends AbstractAction {
|
||||
*
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function checkPreconditions() {
|
||||
public function checkPreconditions()
|
||||
{
|
||||
parent::checkPreconditions();
|
||||
}
|
||||
|
||||
@@ -125,7 +127,6 @@ class Search extends AbstractAction {
|
||||
}
|
||||
|
||||
return '*' . $part . '*';
|
||||
|
||||
}, $queryParts);
|
||||
$QUERY = implode(' ', $queryParts);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Created by IntelliJ IDEA.
|
||||
* User: andi
|
||||
@@ -8,6 +9,7 @@
|
||||
|
||||
namespace dokuwiki\Action;
|
||||
|
||||
use dokuwiki\Ui\PageView;
|
||||
use dokuwiki\Ui;
|
||||
|
||||
/**
|
||||
@@ -20,7 +22,8 @@ use dokuwiki\Ui;
|
||||
class Show extends AbstractAction
|
||||
{
|
||||
/** @inheritdoc */
|
||||
public function minimumPermission() {
|
||||
public function minimumPermission()
|
||||
{
|
||||
return AUTH_READ;
|
||||
}
|
||||
|
||||
@@ -34,7 +37,6 @@ class Show extends AbstractAction
|
||||
/** @inheritdoc */
|
||||
public function tplContent()
|
||||
{
|
||||
(new Ui\PageView())->show();
|
||||
(new PageView())->show();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -13,10 +13,11 @@ use dokuwiki\Utf8\PhpString;
|
||||
*
|
||||
* @package dokuwiki\Action
|
||||
*/
|
||||
class Sitemap extends AbstractAction {
|
||||
|
||||
class Sitemap extends AbstractAction
|
||||
{
|
||||
/** @inheritdoc */
|
||||
public function minimumPermission() {
|
||||
public function minimumPermission()
|
||||
{
|
||||
return AUTH_NONE;
|
||||
}
|
||||
|
||||
@@ -27,26 +28,27 @@ class Sitemap extends AbstractAction {
|
||||
* @throws FatalException
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function preProcess() {
|
||||
public function preProcess()
|
||||
{
|
||||
global $conf;
|
||||
|
||||
if($conf['sitemap'] < 1 || !is_numeric($conf['sitemap'])) {
|
||||
if ($conf['sitemap'] < 1 || !is_numeric($conf['sitemap'])) {
|
||||
throw new FatalException('Sitemap generation is disabled', 404);
|
||||
}
|
||||
|
||||
$sitemap = Mapper::getFilePath();
|
||||
if(Mapper::sitemapIsCompressed()) {
|
||||
if (Mapper::sitemapIsCompressed()) {
|
||||
$mime = 'application/x-gzip';
|
||||
} else {
|
||||
$mime = 'application/xml; charset=utf-8';
|
||||
}
|
||||
|
||||
// Check if sitemap file exists, otherwise create it
|
||||
if(!is_readable($sitemap)) {
|
||||
if (!is_readable($sitemap)) {
|
||||
Mapper::generate();
|
||||
}
|
||||
|
||||
if(is_readable($sitemap)) {
|
||||
if (is_readable($sitemap)) {
|
||||
// Send headers
|
||||
header('Content-Type: ' . $mime);
|
||||
header('Content-Disposition: attachment; filename=' . PhpString::basename($sitemap));
|
||||
@@ -63,5 +65,4 @@ class Sitemap extends AbstractAction {
|
||||
|
||||
throw new FatalException('Could not read the sitemap file - bad permissions?');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace dokuwiki\Action;
|
||||
|
||||
use dokuwiki\Ui\Editor;
|
||||
use dokuwiki\Ui;
|
||||
|
||||
/**
|
||||
@@ -35,7 +36,6 @@ class Source extends AbstractAction
|
||||
/** @inheritdoc */
|
||||
public function tplContent()
|
||||
{
|
||||
(new Ui\Editor)->show();
|
||||
(new Editor())->show();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ class Subscribe extends AbstractUserAction
|
||||
parent::checkPreconditions();
|
||||
|
||||
global $conf;
|
||||
if(isset($conf['subscribers']) && !$conf['subscribers']) throw new ActionDisabledException();
|
||||
if (isset($conf['subscribers']) && !$conf['subscribers']) throw new ActionDisabledException();
|
||||
}
|
||||
|
||||
/** @inheritdoc */
|
||||
@@ -48,7 +48,7 @@ class Subscribe extends AbstractUserAction
|
||||
/** @inheritdoc */
|
||||
public function tplContent()
|
||||
{
|
||||
(new Ui\Subscribe)->show();
|
||||
(new Ui\Subscribe())->show();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -65,8 +65,8 @@ class Subscribe extends AbstractUserAction
|
||||
global $INPUT;
|
||||
|
||||
// get and preprocess data.
|
||||
$params = array();
|
||||
foreach (array('target', 'style', 'action') as $param) {
|
||||
$params = [];
|
||||
foreach (['target', 'style', 'action'] as $param) {
|
||||
if ($INPUT->has("sub_$param")) {
|
||||
$params[$param] = $INPUT->str("sub_$param");
|
||||
}
|
||||
@@ -76,7 +76,7 @@ class Subscribe extends AbstractUserAction
|
||||
if (empty($params['action']) || !checkSecurityToken()) return;
|
||||
|
||||
// Handle POST data, may throw exception.
|
||||
Event::createAndTrigger('ACTION_HANDLE_SUBSCRIBE', $params, array($this, 'handlePostData'));
|
||||
Event::createAndTrigger('ACTION_HANDLE_SUBSCRIBE', $params, [$this, 'handlePostData']);
|
||||
|
||||
$target = $params['target'];
|
||||
$style = $params['style'];
|
||||
@@ -93,9 +93,11 @@ class Subscribe extends AbstractUserAction
|
||||
if ($ok) {
|
||||
msg(
|
||||
sprintf(
|
||||
$lang["subscr_{$action}_success"], hsc($INFO['userinfo']['name']),
|
||||
$lang["subscr_{$action}_success"],
|
||||
hsc($INFO['userinfo']['name']),
|
||||
prettyprint_id($target)
|
||||
), 1
|
||||
),
|
||||
1
|
||||
);
|
||||
throw new ActionAbort('redirect');
|
||||
}
|
||||
@@ -131,18 +133,22 @@ class Subscribe extends AbstractUserAction
|
||||
throw new Exception('no subscription target given');
|
||||
}
|
||||
$target = $params['target'];
|
||||
$valid_styles = array('every', 'digest');
|
||||
if (substr($target, -1, 1) === ':') {
|
||||
$valid_styles = ['every', 'digest'];
|
||||
if (str_ends_with($target, ':')) {
|
||||
// Allow “list” subscribe style since the target is a namespace.
|
||||
$valid_styles[] = 'list';
|
||||
}
|
||||
$style = valid_input_set(
|
||||
'style', $valid_styles, $params,
|
||||
'style',
|
||||
$valid_styles,
|
||||
$params,
|
||||
'invalid subscription style given'
|
||||
);
|
||||
$action = valid_input_set(
|
||||
'action', array('subscribe', 'unsubscribe'),
|
||||
$params, 'invalid subscription action given'
|
||||
'action',
|
||||
['subscribe', 'unsubscribe'],
|
||||
$params,
|
||||
'invalid subscription action given'
|
||||
);
|
||||
|
||||
// Check other conditions.
|
||||
@@ -170,7 +176,6 @@ class Subscribe extends AbstractUserAction
|
||||
$style = null;
|
||||
}
|
||||
|
||||
$params = compact('target', 'style', 'action');
|
||||
$params = ['target' => $target, 'style' => $style, 'action' => $action];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace dokuwiki;
|
||||
|
||||
use dokuwiki\Extension\Event;
|
||||
use dokuwiki\Action\AbstractAction;
|
||||
use dokuwiki\Action\Exception\ActionDisabledException;
|
||||
use dokuwiki\Action\Exception\ActionException;
|
||||
@@ -13,19 +14,19 @@ use dokuwiki\Action\Plugin;
|
||||
* Class ActionRouter
|
||||
* @package dokuwiki
|
||||
*/
|
||||
class ActionRouter {
|
||||
|
||||
class ActionRouter
|
||||
{
|
||||
/** @var AbstractAction */
|
||||
protected $action;
|
||||
|
||||
/** @var ActionRouter */
|
||||
protected static $instance = null;
|
||||
protected static $instance;
|
||||
|
||||
/** @var int transition counter */
|
||||
protected $transitions = 0;
|
||||
|
||||
/** maximum loop */
|
||||
const MAX_TRANSITIONS = 5;
|
||||
protected const MAX_TRANSITIONS = 5;
|
||||
|
||||
/** @var string[] the actions disabled in the configuration */
|
||||
protected $disabled;
|
||||
@@ -36,13 +37,13 @@ class ActionRouter {
|
||||
* Sets up the correct action based on the $ACT global. Writes back
|
||||
* the selected action to $ACT
|
||||
*/
|
||||
protected function __construct() {
|
||||
protected function __construct()
|
||||
{
|
||||
global $ACT;
|
||||
global $conf;
|
||||
|
||||
$this->disabled = explode(',', $conf['disableactions']);
|
||||
$this->disabled = array_map('trim', $this->disabled);
|
||||
$this->transitions = 0;
|
||||
|
||||
$ACT = act_clean($ACT);
|
||||
$this->setupAction($ACT);
|
||||
@@ -55,8 +56,9 @@ class ActionRouter {
|
||||
* @param bool $reinit
|
||||
* @return ActionRouter
|
||||
*/
|
||||
public static function getInstance($reinit = false) {
|
||||
if((self::$instance === null) || $reinit) {
|
||||
public static function getInstance($reinit = false)
|
||||
{
|
||||
if ((!self::$instance instanceof \dokuwiki\ActionRouter) || $reinit) {
|
||||
self::$instance = new ActionRouter();
|
||||
}
|
||||
return self::$instance;
|
||||
@@ -71,12 +73,13 @@ class ActionRouter {
|
||||
* @param string $actionname this is passed as a reference to $ACT, for plugin backward compatibility
|
||||
* @triggers ACTION_ACT_PREPROCESS
|
||||
*/
|
||||
protected function setupAction(&$actionname) {
|
||||
protected function setupAction(&$actionname)
|
||||
{
|
||||
$presetup = $actionname;
|
||||
|
||||
try {
|
||||
// give plugins an opportunity to process the actionname
|
||||
$evt = new Extension\Event('ACTION_ACT_PREPROCESS', $actionname);
|
||||
$evt = new Event('ACTION_ACT_PREPROCESS', $actionname);
|
||||
if ($evt->advise_before()) {
|
||||
$this->action = $this->loadAction($actionname);
|
||||
$this->checkAction($this->action);
|
||||
@@ -86,29 +89,27 @@ class ActionRouter {
|
||||
$this->action = new Plugin($actionname);
|
||||
}
|
||||
$evt->advise_after();
|
||||
|
||||
} catch(ActionException $e) {
|
||||
} catch (ActionException $e) {
|
||||
// we should have gotten a new action
|
||||
$actionname = $e->getNewAction();
|
||||
|
||||
// this one should trigger a user message
|
||||
if(is_a($e, ActionDisabledException::class)) {
|
||||
if ($e instanceof ActionDisabledException) {
|
||||
msg('Action disabled: ' . hsc($presetup), -1);
|
||||
}
|
||||
|
||||
// some actions may request the display of a message
|
||||
if($e->displayToUser()) {
|
||||
if ($e->displayToUser()) {
|
||||
msg(hsc($e->getMessage()), -1);
|
||||
}
|
||||
|
||||
// do setup for new action
|
||||
$this->transitionAction($presetup, $actionname);
|
||||
|
||||
} catch(NoActionException $e) {
|
||||
} catch (NoActionException $e) {
|
||||
msg('Action unknown: ' . hsc($actionname), -1);
|
||||
$actionname = 'show';
|
||||
$this->transitionAction($presetup, $actionname);
|
||||
} catch(\Exception $e) {
|
||||
} catch (\Exception $e) {
|
||||
$this->handleFatalException($e);
|
||||
}
|
||||
}
|
||||
@@ -122,16 +123,17 @@ class ActionRouter {
|
||||
* @param string $to new action name
|
||||
* @param null|ActionException $e any previous exception that caused the transition
|
||||
*/
|
||||
protected function transitionAction($from, $to, $e = null) {
|
||||
protected function transitionAction($from, $to, $e = null)
|
||||
{
|
||||
$this->transitions++;
|
||||
|
||||
// no infinite recursion
|
||||
if($from == $to) {
|
||||
if ($from == $to) {
|
||||
$this->handleFatalException(new FatalException('Infinite loop in actions', 500, $e));
|
||||
}
|
||||
|
||||
// larger loops will be caught here
|
||||
if($this->transitions >= self::MAX_TRANSITIONS) {
|
||||
if ($this->transitions >= self::MAX_TRANSITIONS) {
|
||||
$this->handleFatalException(new FatalException('Maximum action transitions reached', 500, $e));
|
||||
}
|
||||
|
||||
@@ -147,13 +149,14 @@ class ActionRouter {
|
||||
* @param \Exception|FatalException $e
|
||||
* @throws FatalException during unit testing
|
||||
*/
|
||||
protected function handleFatalException(\Exception $e) {
|
||||
if(is_a($e, FatalException::class)) {
|
||||
protected function handleFatalException(\Throwable $e)
|
||||
{
|
||||
if ($e instanceof FatalException) {
|
||||
http_status($e->getCode());
|
||||
} else {
|
||||
http_status(500);
|
||||
}
|
||||
if(defined('DOKU_UNITTEST')) {
|
||||
if (defined('DOKU_UNITTEST')) {
|
||||
throw $e;
|
||||
}
|
||||
ErrorHandler::logException($e);
|
||||
@@ -175,13 +178,14 @@ class ActionRouter {
|
||||
* @return AbstractAction
|
||||
* @throws NoActionException
|
||||
*/
|
||||
public function loadAction($actionname) {
|
||||
public function loadAction($actionname)
|
||||
{
|
||||
$actionname = strtolower($actionname); // FIXME is this needed here? should we run a cleanup somewhere else?
|
||||
$parts = explode('_', $actionname);
|
||||
while(!empty($parts)) {
|
||||
$load = join('_', $parts);
|
||||
while ($parts !== []) {
|
||||
$load = implode('_', $parts);
|
||||
$class = 'dokuwiki\\Action\\' . str_replace('_', '', ucwords($load, '_'));
|
||||
if(class_exists($class)) {
|
||||
if (class_exists($class)) {
|
||||
return new $class($actionname);
|
||||
}
|
||||
array_pop($parts);
|
||||
@@ -197,23 +201,24 @@ class ActionRouter {
|
||||
* @throws ActionDisabledException
|
||||
* @throws ActionException
|
||||
*/
|
||||
public function checkAction(AbstractAction $action) {
|
||||
public function checkAction(AbstractAction $action)
|
||||
{
|
||||
global $INFO;
|
||||
global $ID;
|
||||
|
||||
if(in_array($action->getActionName(), $this->disabled)) {
|
||||
if (in_array($action->getActionName(), $this->disabled)) {
|
||||
throw new ActionDisabledException();
|
||||
}
|
||||
|
||||
$action->checkPreconditions();
|
||||
|
||||
if(isset($INFO)) {
|
||||
if (isset($INFO)) {
|
||||
$perm = $INFO['perm'];
|
||||
} else {
|
||||
$perm = auth_quickaclcheck($ID);
|
||||
}
|
||||
|
||||
if($perm < $action->minimumPermission()) {
|
||||
if ($perm < $action->minimumPermission()) {
|
||||
throw new ActionException('denied');
|
||||
}
|
||||
}
|
||||
@@ -223,7 +228,8 @@ class ActionRouter {
|
||||
*
|
||||
* @return AbstractAction
|
||||
*/
|
||||
public function getAction() {
|
||||
public function getAction()
|
||||
{
|
||||
return $this->action;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
|
||||
namespace dokuwiki;
|
||||
|
||||
use dokuwiki\Extension\Event;
|
||||
use dokuwiki\Ui\MediaDiff;
|
||||
use dokuwiki\Ui\Index;
|
||||
use dokuwiki\Ui;
|
||||
use dokuwiki\Utf8\Sort;
|
||||
|
||||
@@ -11,21 +14,22 @@ use dokuwiki\Utf8\Sort;
|
||||
* @todo The calls should be refactored out to their own proper classes
|
||||
* @package dokuwiki
|
||||
*/
|
||||
class Ajax {
|
||||
|
||||
class Ajax
|
||||
{
|
||||
/**
|
||||
* Execute the given call
|
||||
*
|
||||
* @param string $call name of the ajax call
|
||||
*/
|
||||
public function __construct($call) {
|
||||
public function __construct($call)
|
||||
{
|
||||
$callfn = 'call' . ucfirst($call);
|
||||
if(method_exists($this, $callfn)) {
|
||||
if (method_exists($this, $callfn)) {
|
||||
$this->$callfn();
|
||||
} else {
|
||||
$evt = new Extension\Event('AJAX_CALL_UNKNOWN', $call);
|
||||
if($evt->advise_before()) {
|
||||
print "AJAX call '" . hsc($call) . "' unknown!\n";
|
||||
$evt = new Event('AJAX_CALL_UNKNOWN', $call);
|
||||
if ($evt->advise_before()) {
|
||||
echo "AJAX call '" . hsc($call) . "' unknown!\n";
|
||||
} else {
|
||||
$evt->advise_after();
|
||||
unset($evt);
|
||||
@@ -38,31 +42,32 @@ class Ajax {
|
||||
*
|
||||
* @author Andreas Gohr <andi@splitbrain.org>
|
||||
*/
|
||||
protected function callQsearch() {
|
||||
protected function callQsearch()
|
||||
{
|
||||
global $lang;
|
||||
global $INPUT;
|
||||
|
||||
$maxnumbersuggestions = 50;
|
||||
|
||||
$query = $INPUT->post->str('q');
|
||||
if(empty($query)) $query = $INPUT->get->str('q');
|
||||
if(empty($query)) return;
|
||||
if (empty($query)) $query = $INPUT->get->str('q');
|
||||
if (empty($query)) return;
|
||||
|
||||
$query = urldecode($query);
|
||||
|
||||
$data = ft_pageLookup($query, true, useHeading('navigation'));
|
||||
|
||||
if(!count($data)) return;
|
||||
if ($data === []) return;
|
||||
|
||||
print '<strong>' . $lang['quickhits'] . '</strong>';
|
||||
print '<ul>';
|
||||
echo '<strong>' . $lang['quickhits'] . '</strong>';
|
||||
echo '<ul>';
|
||||
$counter = 0;
|
||||
foreach($data as $id => $title) {
|
||||
if(useHeading('navigation')) {
|
||||
foreach ($data as $id => $title) {
|
||||
if (useHeading('navigation')) {
|
||||
$name = $title;
|
||||
} else {
|
||||
$ns = getNS($id);
|
||||
if($ns) {
|
||||
if ($ns) {
|
||||
$name = noNS($id) . ' (' . $ns . ')';
|
||||
} else {
|
||||
$name = $id;
|
||||
@@ -71,12 +76,12 @@ class Ajax {
|
||||
echo '<li>' . html_wikilink(':' . $id, $name) . '</li>';
|
||||
|
||||
$counter++;
|
||||
if($counter > $maxnumbersuggestions) {
|
||||
if ($counter > $maxnumbersuggestions) {
|
||||
echo '<li>...</li>';
|
||||
break;
|
||||
}
|
||||
}
|
||||
print '</ul>';
|
||||
echo '</ul>';
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -85,15 +90,16 @@ class Ajax {
|
||||
* @link http://www.opensearch.org/Specifications/OpenSearch/Extensions/Suggestions/1.0
|
||||
* @author Mike Frysinger <vapier@gentoo.org>
|
||||
*/
|
||||
protected function callSuggestions() {
|
||||
protected function callSuggestions()
|
||||
{
|
||||
global $INPUT;
|
||||
|
||||
$query = cleanID($INPUT->post->str('q'));
|
||||
if(empty($query)) $query = cleanID($INPUT->get->str('q'));
|
||||
if(empty($query)) return;
|
||||
if (empty($query)) $query = cleanID($INPUT->get->str('q'));
|
||||
if (empty($query)) return;
|
||||
|
||||
$data = ft_pageLookup($query);
|
||||
if(!count($data)) return;
|
||||
if ($data === []) return;
|
||||
$data = array_keys($data);
|
||||
|
||||
// limit results to 15 hits
|
||||
@@ -104,15 +110,15 @@ class Ajax {
|
||||
Sort::sort($data);
|
||||
|
||||
/* now construct a json */
|
||||
$suggestions = array(
|
||||
$query, // the original query
|
||||
$data, // some suggestions
|
||||
array(), // no description
|
||||
array() // no urls
|
||||
);
|
||||
$suggestions = [
|
||||
$query, // the original query
|
||||
$data, // some suggestions
|
||||
[], // no description
|
||||
[], // no urls
|
||||
];
|
||||
|
||||
header('Content-Type: application/x-suggestions+json');
|
||||
print json_encode($suggestions);
|
||||
echo json_encode($suggestions, JSON_THROW_ON_ERROR);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -120,13 +126,14 @@ class Ajax {
|
||||
*
|
||||
* Andreas Gohr <andi@splitbrain.org>
|
||||
*/
|
||||
protected function callLock() {
|
||||
protected function callLock()
|
||||
{
|
||||
global $ID;
|
||||
global $INFO;
|
||||
global $INPUT;
|
||||
|
||||
$ID = cleanID($INPUT->post->str('id'));
|
||||
if(empty($ID)) return;
|
||||
if (empty($ID)) return;
|
||||
|
||||
$INFO = pageinfo();
|
||||
|
||||
@@ -135,13 +142,13 @@ class Ajax {
|
||||
'lock' => '0',
|
||||
'draft' => '',
|
||||
];
|
||||
if(!$INFO['writable']) {
|
||||
if (!$INFO['writable']) {
|
||||
$response['errors'][] = 'Permission to write this page has been denied.';
|
||||
echo json_encode($response);
|
||||
return;
|
||||
}
|
||||
|
||||
if(!checklock($ID)) {
|
||||
if (!checklock($ID)) {
|
||||
lock($ID);
|
||||
$response['lock'] = '1';
|
||||
}
|
||||
@@ -152,7 +159,7 @@ class Ajax {
|
||||
} else {
|
||||
$response['errors'] = array_merge($response['errors'], $draft->getErrors());
|
||||
}
|
||||
echo json_encode($response);
|
||||
echo json_encode($response, JSON_THROW_ON_ERROR);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -160,13 +167,14 @@ class Ajax {
|
||||
*
|
||||
* @author Andreas Gohr <andi@splitbrain.org>
|
||||
*/
|
||||
protected function callDraftdel() {
|
||||
protected function callDraftdel()
|
||||
{
|
||||
global $INPUT;
|
||||
$id = cleanID($INPUT->str('id'));
|
||||
if(empty($id)) return;
|
||||
if (empty($id)) return;
|
||||
|
||||
$client = $_SERVER['REMOTE_USER'];
|
||||
if(!$client) $client = clientIP(true);
|
||||
$client = $INPUT->server->str('REMOTE_USER');
|
||||
if (!$client) $client = clientIP(true);
|
||||
|
||||
$draft = new Draft($id, $client);
|
||||
if ($draft->isDraftAvailable() && checkSecurityToken()) {
|
||||
@@ -179,7 +187,8 @@ class Ajax {
|
||||
*
|
||||
* @author Andreas Gohr <andi@splitbrain.org>
|
||||
*/
|
||||
protected function callMedians() {
|
||||
protected function callMedians()
|
||||
{
|
||||
global $conf;
|
||||
global $INPUT;
|
||||
|
||||
@@ -189,9 +198,9 @@ class Ajax {
|
||||
|
||||
$lvl = count(explode(':', $ns));
|
||||
|
||||
$data = array();
|
||||
search($data, $conf['mediadir'], 'search_index', array('nofiles' => true), $dir);
|
||||
foreach(array_keys($data) as $item) {
|
||||
$data = [];
|
||||
search($data, $conf['mediadir'], 'search_index', ['nofiles' => true], $dir);
|
||||
foreach (array_keys($data) as $item) {
|
||||
$data[$item]['level'] = $lvl + 1;
|
||||
}
|
||||
echo html_buildlist($data, 'idx', 'media_nstree_item', 'media_nstree_li');
|
||||
@@ -202,13 +211,14 @@ class Ajax {
|
||||
*
|
||||
* @author Andreas Gohr <andi@splitbrain.org>
|
||||
*/
|
||||
protected function callMedialist() {
|
||||
protected function callMedialist()
|
||||
{
|
||||
global $NS;
|
||||
global $INPUT;
|
||||
|
||||
$NS = cleanID($INPUT->post->str('ns'));
|
||||
$sort = $INPUT->post->bool('recent') ? 'date' : 'natural';
|
||||
if($INPUT->post->str('do') == 'media') {
|
||||
if ($INPUT->post->str('do') == 'media') {
|
||||
tpl_mediaFileList();
|
||||
} else {
|
||||
tpl_mediaContent(true, $sort);
|
||||
@@ -221,17 +231,18 @@ class Ajax {
|
||||
*
|
||||
* @author Kate Arzamastseva <pshns@ukr.net>
|
||||
*/
|
||||
protected function callMediadetails() {
|
||||
protected function callMediadetails()
|
||||
{
|
||||
global $IMG, $JUMPTO, $REV, $fullscreen, $INPUT;
|
||||
$fullscreen = true;
|
||||
require_once(DOKU_INC . 'lib/exe/mediamanager.php');
|
||||
|
||||
$image = '';
|
||||
if($INPUT->has('image')) $image = cleanID($INPUT->str('image'));
|
||||
if(isset($IMG)) $image = $IMG;
|
||||
if(isset($JUMPTO)) $image = $JUMPTO;
|
||||
if ($INPUT->has('image')) $image = cleanID($INPUT->str('image'));
|
||||
if (isset($IMG)) $image = $IMG;
|
||||
if (isset($JUMPTO)) $image = $JUMPTO;
|
||||
$rev = false;
|
||||
if(isset($REV) && !$JUMPTO) $rev = $REV;
|
||||
if (isset($REV) && !$JUMPTO) $rev = $REV;
|
||||
|
||||
html_msgarea();
|
||||
tpl_mediaFileDetails($image, $rev);
|
||||
@@ -242,12 +253,13 @@ class Ajax {
|
||||
*
|
||||
* @author Kate Arzamastseva <pshns@ukr.net>
|
||||
*/
|
||||
protected function callMediadiff() {
|
||||
protected function callMediadiff()
|
||||
{
|
||||
global $INPUT;
|
||||
|
||||
$image = '';
|
||||
if($INPUT->has('image')) $image = cleanID($INPUT->str('image'));
|
||||
(new Ui\MediaDiff($image))->preference('fromAjax', true)->show();
|
||||
if ($INPUT->has('image')) $image = cleanID($INPUT->str('image'));
|
||||
(new MediaDiff($image))->preference('fromAjax', true)->show();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -255,13 +267,14 @@ class Ajax {
|
||||
*
|
||||
* @author Kate Arzamastseva <pshns@ukr.net>
|
||||
*/
|
||||
protected function callMediaupload() {
|
||||
protected function callMediaupload()
|
||||
{
|
||||
global $NS, $MSG, $INPUT;
|
||||
|
||||
$id = '';
|
||||
if(isset($_FILES['qqfile']['tmp_name'])) {
|
||||
if (isset($_FILES['qqfile']['tmp_name'])) {
|
||||
$id = $INPUT->post->str('mediaid', $_FILES['qqfile']['name']);
|
||||
} elseif($INPUT->get->has('qqfile')) {
|
||||
} elseif ($INPUT->get->has('qqfile')) {
|
||||
$id = $INPUT->get->str('qqfile');
|
||||
}
|
||||
|
||||
@@ -271,38 +284,35 @@ class Ajax {
|
||||
$ns = $NS . ':' . getNS($id);
|
||||
|
||||
$AUTH = auth_quickaclcheck("$ns:*");
|
||||
if($AUTH >= AUTH_UPLOAD) {
|
||||
if ($AUTH >= AUTH_UPLOAD) {
|
||||
io_createNamespace("$ns:xxx", 'media');
|
||||
}
|
||||
|
||||
if(isset($_FILES['qqfile']['error']) && $_FILES['qqfile']['error']) unset($_FILES['qqfile']);
|
||||
if (isset($_FILES['qqfile']['error']) && $_FILES['qqfile']['error']) unset($_FILES['qqfile']);
|
||||
|
||||
$res = false;
|
||||
if(isset($_FILES['qqfile']['tmp_name'])) $res = media_upload($NS, $AUTH, $_FILES['qqfile']);
|
||||
if($INPUT->get->has('qqfile')) $res = media_upload_xhr($NS, $AUTH);
|
||||
if (isset($_FILES['qqfile']['tmp_name'])) $res = media_upload($NS, $AUTH, $_FILES['qqfile']);
|
||||
if ($INPUT->get->has('qqfile')) $res = media_upload_xhr($NS, $AUTH);
|
||||
|
||||
if($res) {
|
||||
$result = array(
|
||||
if ($res) {
|
||||
$result = [
|
||||
'success' => true,
|
||||
'link' => media_managerURL(array('ns' => $ns, 'image' => $NS . ':' . $id), '&'),
|
||||
'link' => media_managerURL(['ns' => $ns, 'image' => $NS . ':' . $id], '&'),
|
||||
'id' => $NS . ':' . $id,
|
||||
'ns' => $NS
|
||||
);
|
||||
];
|
||||
} else {
|
||||
$error = '';
|
||||
if(isset($MSG)) {
|
||||
foreach($MSG as $msg) {
|
||||
if (isset($MSG)) {
|
||||
foreach ($MSG as $msg) {
|
||||
$error .= $msg['msg'];
|
||||
}
|
||||
}
|
||||
$result = array(
|
||||
'error' => $error,
|
||||
'ns' => $NS
|
||||
);
|
||||
$result = ['error' => $error, 'ns' => $NS];
|
||||
}
|
||||
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode($result);
|
||||
echo json_encode($result, JSON_THROW_ON_ERROR);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -310,7 +320,8 @@ class Ajax {
|
||||
*
|
||||
* @author Andreas Gohr <andi@splitbrain.org>
|
||||
*/
|
||||
protected function callIndex() {
|
||||
protected function callIndex()
|
||||
{
|
||||
global $conf;
|
||||
global $INPUT;
|
||||
|
||||
@@ -320,12 +331,12 @@ class Ajax {
|
||||
|
||||
$lvl = count(explode(':', $ns));
|
||||
|
||||
$data = array();
|
||||
search($data, $conf['datadir'], 'search_index', array('ns' => $ns), $dir);
|
||||
$data = [];
|
||||
search($data, $conf['datadir'], 'search_index', ['ns' => $ns], $dir);
|
||||
foreach (array_keys($data) as $item) {
|
||||
$data[$item]['level'] = $lvl + 1;
|
||||
}
|
||||
$idx = new Ui\Index;
|
||||
$idx = new Index();
|
||||
echo html_buildlist($data, 'idx', [$idx,'formatListItem'], [$idx,'tagListItem']);
|
||||
}
|
||||
|
||||
@@ -334,7 +345,8 @@ class Ajax {
|
||||
*
|
||||
* @author Andreas Gohr <gohr@cosmocode.de>
|
||||
*/
|
||||
protected function callLinkwiz() {
|
||||
protected function callLinkwiz()
|
||||
{
|
||||
global $conf;
|
||||
global $lang;
|
||||
global $INPUT;
|
||||
@@ -344,92 +356,81 @@ class Ajax {
|
||||
$ns = getNS($q);
|
||||
|
||||
$ns = cleanID($ns);
|
||||
|
||||
$id = cleanID($id);
|
||||
|
||||
$nsd = utf8_encodeFN(str_replace(':', '/', $ns));
|
||||
|
||||
$data = array();
|
||||
if($q !== '' && $ns === '') {
|
||||
|
||||
$data = [];
|
||||
if ($q !== '' && $ns === '') {
|
||||
// use index to lookup matching pages
|
||||
$pages = ft_pageLookup($id, true);
|
||||
|
||||
// If 'useheading' option is 'always' or 'content',
|
||||
// search page titles with original query as well.
|
||||
if ($conf['useheading'] == '1' || $conf['useheading'] == 'content') {
|
||||
if ($conf['useheading'] == '1' || $conf['useheading'] == 'content') {
|
||||
$pages = array_merge($pages, ft_pageLookup($q, true, true));
|
||||
asort($pages, SORT_STRING);
|
||||
}
|
||||
|
||||
|
||||
// result contains matches in pages and namespaces
|
||||
// we now extract the matching namespaces to show
|
||||
// them seperately
|
||||
$dirs = array();
|
||||
$dirs = [];
|
||||
|
||||
foreach($pages as $pid => $title) {
|
||||
if(strpos(getNS($pid), $id) !== false) {
|
||||
foreach ($pages as $pid => $title) {
|
||||
if (strpos(getNS($pid), $id) !== false) {
|
||||
// match was in the namespace
|
||||
$dirs[getNS($pid)] = 1; // assoc array avoids dupes
|
||||
} else {
|
||||
// it is a matching page, add it to the result
|
||||
$data[] = array(
|
||||
'id' => $pid,
|
||||
'title' => $title,
|
||||
'type' => 'f',
|
||||
);
|
||||
$data[] = ['id' => $pid, 'title' => $title, 'type' => 'f'];
|
||||
}
|
||||
unset($pages[$pid]);
|
||||
}
|
||||
foreach($dirs as $dir => $junk) {
|
||||
$data[] = array(
|
||||
'id' => $dir,
|
||||
'type' => 'd',
|
||||
);
|
||||
foreach (array_keys($dirs) as $dir) {
|
||||
$data[] = ['id' => $dir, 'type' => 'd'];
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
$opts = array(
|
||||
$opts = [
|
||||
'depth' => 1,
|
||||
'listfiles' => true,
|
||||
'listdirs' => true,
|
||||
'pagesonly' => true,
|
||||
'firsthead' => true,
|
||||
'sneakyacl' => $conf['sneaky_index'],
|
||||
);
|
||||
if($id) $opts['filematch'] = '^.*\/' . $id;
|
||||
if($id) $opts['dirmatch'] = '^.*\/' . $id;
|
||||
'sneakyacl' => $conf['sneaky_index']
|
||||
];
|
||||
if ($id) $opts['filematch'] = '^.*\/' . $id;
|
||||
if ($id) $opts['dirmatch'] = '^.*\/' . $id;
|
||||
search($data, $conf['datadir'], 'search_universal', $opts, $nsd);
|
||||
|
||||
// add back to upper
|
||||
if($ns) {
|
||||
if ($ns) {
|
||||
array_unshift(
|
||||
$data, array(
|
||||
'id' => getNS($ns),
|
||||
'type' => 'u',
|
||||
)
|
||||
$data,
|
||||
['id' => getNS($ns), 'type' => 'u']
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// fixme sort results in a useful way ?
|
||||
|
||||
if(!count($data)) {
|
||||
if (!count($data)) {
|
||||
echo $lang['nothingfound'];
|
||||
exit;
|
||||
}
|
||||
|
||||
// output the found data
|
||||
$even = 1;
|
||||
foreach($data as $item) {
|
||||
foreach ($data as $item) {
|
||||
$even *= -1; //zebra
|
||||
|
||||
if(($item['type'] == 'd' || $item['type'] == 'u') && $item['id'] !== '') $item['id'] .= ':';
|
||||
if (($item['type'] == 'd' || $item['type'] == 'u') && $item['id'] !== '') $item['id'] .= ':';
|
||||
$link = wl($item['id']);
|
||||
|
||||
echo '<div class="' . (($even > 0) ? 'even' : 'odd') . ' type_' . $item['type'] . '">';
|
||||
|
||||
if($item['type'] == 'u') {
|
||||
if ($item['type'] == 'u') {
|
||||
$name = $lang['upperns'];
|
||||
} else {
|
||||
$name = hsc($item['id']);
|
||||
@@ -437,12 +438,10 @@ class Ajax {
|
||||
|
||||
echo '<a href="' . $link . '" title="' . hsc($item['id']) . '" class="wikilink1">' . $name . '</a>';
|
||||
|
||||
if(!blank($item['title'])) {
|
||||
if (!blank($item['title'])) {
|
||||
echo '<span>' . hsc($item['title']) . '</span>';
|
||||
}
|
||||
echo '</div>';
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ class Cache
|
||||
public $key = ''; // primary identifier for this item
|
||||
public $ext = ''; // file ext for cache data, secondary identifier for this item
|
||||
public $cache = ''; // cache file name
|
||||
public $depends = array(); // array containing cache dependency information,
|
||||
public $depends = []; // array containing cache dependency information,
|
||||
// used by makeDefaultCacheDecision to determine cache validity
|
||||
|
||||
// phpcs:disable
|
||||
@@ -73,7 +73,7 @@ class Cache
|
||||
*
|
||||
* @return bool true if cache can be used, false otherwise
|
||||
*/
|
||||
public function useCache($depends = array())
|
||||
public function useCache($depends = [])
|
||||
{
|
||||
$this->depends = $depends;
|
||||
$this->addDependencies();
|
||||
@@ -83,7 +83,7 @@ class Cache
|
||||
Event::createAndTrigger(
|
||||
$this->getEvent(),
|
||||
$this,
|
||||
array($this, 'makeDefaultCacheDecision')
|
||||
[$this, 'makeDefaultCacheDecision']
|
||||
)
|
||||
);
|
||||
}
|
||||
@@ -212,7 +212,7 @@ class Cache
|
||||
}
|
||||
|
||||
if (isset($stats[$this->ext])) {
|
||||
list($ext, $count, $hits) = explode(',', $stats[$this->ext]);
|
||||
[$ext, $count, $hits] = explode(',', $stats[$this->ext]);
|
||||
} else {
|
||||
$ext = $this->ext;
|
||||
$count = 0;
|
||||
@@ -225,7 +225,7 @@ class Cache
|
||||
}
|
||||
$stats[$this->ext] = "$ext,$count,$hits";
|
||||
|
||||
io_saveFile($file, join("\n", $stats));
|
||||
io_saveFile($file, implode("\n", $stats));
|
||||
|
||||
return $success;
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@ namespace dokuwiki\Cache;
|
||||
*/
|
||||
class CacheImageMod extends Cache
|
||||
{
|
||||
|
||||
/** @var string source file */
|
||||
protected $file;
|
||||
|
||||
@@ -52,5 +51,4 @@ class CacheImageMod extends Cache
|
||||
getConfigFiles('main')
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -5,9 +5,8 @@ namespace dokuwiki\Cache;
|
||||
/**
|
||||
* Caching of parser instructions
|
||||
*/
|
||||
class CacheInstructions extends \dokuwiki\Cache\CacheParser
|
||||
class CacheInstructions extends CacheParser
|
||||
{
|
||||
|
||||
/**
|
||||
* @param string $id page id
|
||||
* @param string $file source file for cache
|
||||
@@ -26,7 +25,7 @@ class CacheInstructions extends \dokuwiki\Cache\CacheParser
|
||||
public function retrieveCache($clean = true)
|
||||
{
|
||||
$contents = io_readFile($this->cache, false);
|
||||
return !empty($contents) ? unserialize($contents) : array();
|
||||
return empty($contents) ? [] : unserialize($contents);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -7,7 +7,6 @@ namespace dokuwiki\Cache;
|
||||
*/
|
||||
class CacheParser extends Cache
|
||||
{
|
||||
|
||||
public $file = ''; // source file for cache
|
||||
public $mode = ''; // input mode (represents the processing the input file will undergo)
|
||||
public $page = '';
|
||||
@@ -20,6 +19,8 @@ class CacheParser extends Cache
|
||||
*/
|
||||
public function __construct($id, $file, $mode)
|
||||
{
|
||||
global $INPUT;
|
||||
|
||||
if ($id) {
|
||||
$this->page = $id;
|
||||
}
|
||||
@@ -27,38 +28,36 @@ class CacheParser extends Cache
|
||||
$this->mode = $mode;
|
||||
|
||||
$this->setEvent('PARSER_CACHE_USE');
|
||||
parent::__construct($file . $_SERVER['HTTP_HOST'] . $_SERVER['SERVER_PORT'], '.' . $mode);
|
||||
parent::__construct($file . $INPUT->server->str('HTTP_HOST') . $INPUT->server->str('SERVER_PORT'), '.' . $mode);
|
||||
}
|
||||
|
||||
/**
|
||||
* method contains cache use decision logic
|
||||
*
|
||||
* @return bool see useCache()
|
||||
* @return bool see useCache()
|
||||
*/
|
||||
public function makeDefaultCacheDecision()
|
||||
{
|
||||
|
||||
if (!file_exists($this->file)) {
|
||||
// source doesn't exist
|
||||
return false;
|
||||
} // source exists?
|
||||
}
|
||||
return parent::makeDefaultCacheDecision();
|
||||
}
|
||||
|
||||
protected function addDependencies()
|
||||
{
|
||||
|
||||
// parser cache file dependencies ...
|
||||
$files = array(
|
||||
$this->file, // ... source
|
||||
DOKU_INC . 'inc/parser/Parser.php', // ... parser
|
||||
DOKU_INC . 'inc/parser/handler.php', // ... handler
|
||||
);
|
||||
$files = array_merge($files, getConfigFiles('main')); // ... wiki settings
|
||||
$files = [
|
||||
$this->file, // source
|
||||
DOKU_INC . 'inc/Parsing/Parser.php', // parser
|
||||
DOKU_INC . 'inc/parser/handler.php', // handler
|
||||
];
|
||||
$files = array_merge($files, getConfigFiles('main')); // wiki settings
|
||||
|
||||
$this->depends['files'] = !empty($this->depends['files']) ?
|
||||
array_merge($files, $this->depends['files']) :
|
||||
$files;
|
||||
$this->depends['files'] = empty($this->depends['files']) ?
|
||||
$files :
|
||||
array_merge($files, $this->depends['files']);
|
||||
parent::addDependencies();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@ namespace dokuwiki\Cache;
|
||||
*/
|
||||
class CacheRenderer extends CacheParser
|
||||
{
|
||||
|
||||
/**
|
||||
* method contains cache use decision logic
|
||||
*
|
||||
@@ -40,8 +39,10 @@ class CacheRenderer extends CacheParser
|
||||
// for wiki pages, check metadata dependencies
|
||||
$metadata = p_get_metadata($this->page);
|
||||
|
||||
if (!isset($metadata['relation']['references']) ||
|
||||
empty($metadata['relation']['references'])) {
|
||||
if (
|
||||
!isset($metadata['relation']['references']) ||
|
||||
empty($metadata['relation']['references'])
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -70,13 +71,10 @@ class CacheRenderer extends CacheParser
|
||||
}
|
||||
|
||||
// renderer cache file dependencies ...
|
||||
$files = array(
|
||||
DOKU_INC . 'inc/parser/' . $this->mode . '.php', // ... the renderer
|
||||
);
|
||||
$files = [DOKU_INC . 'inc/parser/' . $this->mode . '.php'];
|
||||
|
||||
// page implies metadata and possibly some other dependencies
|
||||
if (isset($this->page)) {
|
||||
|
||||
// for xhtml this will render the metadata if needed
|
||||
$valid = p_get_metadata($this->page, 'date valid');
|
||||
if (!empty($valid['age'])) {
|
||||
@@ -85,9 +83,9 @@ class CacheRenderer extends CacheParser
|
||||
}
|
||||
}
|
||||
|
||||
$this->depends['files'] = !empty($this->depends['files']) ?
|
||||
array_merge($files, $this->depends['files']) :
|
||||
$files;
|
||||
$this->depends['files'] = empty($this->depends['files']) ?
|
||||
$files :
|
||||
array_merge($files, $this->depends['files']);
|
||||
|
||||
parent::addDependencies();
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ abstract class ChangeLog
|
||||
/** @var false|int */
|
||||
protected $currentRevision;
|
||||
/** @var array */
|
||||
protected $cache;
|
||||
protected $cache = [];
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
@@ -30,7 +30,7 @@ abstract class ChangeLog
|
||||
|
||||
$this->cache =& $cache_revinfo;
|
||||
if (!isset($this->cache[$id])) {
|
||||
$this->cache[$id] = array();
|
||||
$this->cache[$id] = [];
|
||||
}
|
||||
|
||||
$this->id = $id;
|
||||
@@ -40,9 +40,17 @@ abstract class ChangeLog
|
||||
/**
|
||||
* Returns path to current page/media
|
||||
*
|
||||
* @param string|int $rev empty string or revision timestamp
|
||||
* @return string path to file
|
||||
*/
|
||||
abstract protected function getFilename();
|
||||
abstract protected function getFilename($rev = '');
|
||||
|
||||
/**
|
||||
* Returns mode
|
||||
*
|
||||
* @return string RevisionInfo::MODE_MEDIA or RevisionInfo::MODE_PAGE
|
||||
*/
|
||||
abstract protected function getMode();
|
||||
|
||||
/**
|
||||
* Check whether given revision is the current page
|
||||
@@ -98,17 +106,20 @@ abstract class ChangeLog
|
||||
}
|
||||
|
||||
/**
|
||||
* Save revision info to the cache pool
|
||||
* Parses a changelog line into its components and save revision info to the cache pool
|
||||
*
|
||||
* @param array $info Revision info structure
|
||||
* @return bool
|
||||
* @param string $value changelog line
|
||||
* @return array|bool parsed line or false
|
||||
*/
|
||||
protected function cacheRevisionInfo($info)
|
||||
protected function parseAndCacheLogLine($value)
|
||||
{
|
||||
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;
|
||||
$info = static::parseLogLine($value);
|
||||
if (is_array($info)) {
|
||||
$info['mode'] = $this->getMode();
|
||||
$this->cache[$this->id][$info['date']] ??= $info;
|
||||
return $info;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -130,6 +141,8 @@ abstract class ChangeLog
|
||||
* - sum: edit summary (or action reason)
|
||||
* - extra: extra data (varies by line type)
|
||||
* - sizechange: change of filesize
|
||||
* additional:
|
||||
* - mode: page or media
|
||||
*
|
||||
* @author Ben Coburn <btcoburn@silicodon.net>
|
||||
* @author Kate Arzamastseva <pshns@ukr.net>
|
||||
@@ -145,26 +158,23 @@ abstract class ChangeLog
|
||||
}
|
||||
|
||||
// check if it's already in the memory cache
|
||||
if (isset($this->cache[$this->id]) && isset($this->cache[$this->id][$rev])) {
|
||||
if (isset($this->cache[$this->id][$rev])) {
|
||||
return $this->cache[$this->id][$rev];
|
||||
}
|
||||
|
||||
//read lines from changelog
|
||||
list($fp, $lines) = $this->readloglines($rev);
|
||||
[$fp, $lines] = $this->readloglines($rev);
|
||||
if ($fp) {
|
||||
fclose($fp);
|
||||
}
|
||||
if (empty($lines)) return false;
|
||||
|
||||
// parse and cache changelog lines
|
||||
foreach ($lines as $value) {
|
||||
$info = $this->parseLogLine($value);
|
||||
$this->cacheRevisionInfo($info);
|
||||
foreach ($lines as $line) {
|
||||
$this->parseAndCacheLogLine($line);
|
||||
}
|
||||
if (!isset($this->cache[$this->id][$rev])) {
|
||||
return false;
|
||||
}
|
||||
return $this->cache[$this->id][$rev];
|
||||
|
||||
return $this->cache[$this->id][$rev] ?? false;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -192,8 +202,8 @@ abstract class ChangeLog
|
||||
*/
|
||||
public function getRevisions($first, $num)
|
||||
{
|
||||
$revs = array();
|
||||
$lines = array();
|
||||
$revs = [];
|
||||
$lines = [];
|
||||
$count = 0;
|
||||
|
||||
$logfile = $this->getChangelogFilename();
|
||||
@@ -259,7 +269,7 @@ abstract class ChangeLog
|
||||
|
||||
// combine with previous chunk
|
||||
$count += count($tmp);
|
||||
$lines = array_merge($tmp, $lines);
|
||||
$lines = [...$tmp, ...$lines];
|
||||
|
||||
// next chunk
|
||||
if ($finger == 0) {
|
||||
@@ -284,8 +294,8 @@ abstract class ChangeLog
|
||||
|
||||
// handle lines in reverse order
|
||||
for ($i = count($lines) - 1; $i >= 0; $i--) {
|
||||
$info = $this->parseLogLine($lines[$i]);
|
||||
if ($this->cacheRevisionInfo($info)) {
|
||||
$info = $this->parseAndCacheLogLine($lines[$i]);
|
||||
if (is_array($info)) {
|
||||
$revs[] = $info['date'];
|
||||
}
|
||||
}
|
||||
@@ -321,7 +331,7 @@ abstract class ChangeLog
|
||||
}
|
||||
|
||||
//get lines from changelog
|
||||
list($fp, $lines, $head, $tail, $eof) = $this->readloglines($rev);
|
||||
[$fp, $lines, $head, $tail, $eof] = $this->readloglines($rev);
|
||||
if (empty($lines)) return false;
|
||||
|
||||
// look for revisions later/earlier than $rev, when founded count till the wanted revision is reached
|
||||
@@ -330,7 +340,7 @@ abstract class ChangeLog
|
||||
$relativeRev = false;
|
||||
$checkOtherChunk = true; //always runs once
|
||||
while (!$relativeRev && $checkOtherChunk) {
|
||||
$info = array();
|
||||
$info = [];
|
||||
//parse in normal or reverse order
|
||||
$count = count($lines);
|
||||
if ($direction > 0) {
|
||||
@@ -340,9 +350,9 @@ abstract class ChangeLog
|
||||
$start = $count - 1;
|
||||
$step = -1;
|
||||
}
|
||||
for ($i = $start; $i >= 0 && $i < $count; $i = $i + $step) {
|
||||
$info = $this->parseLogLine($lines[$i]);
|
||||
if ($this->cacheRevisionInfo($info)) {
|
||||
for ($i = $start; $i >= 0 && $i < $count; $i += $step) {
|
||||
$info = $this->parseAndCacheLogLine($lines[$i]);
|
||||
if (is_array($info)) {
|
||||
//look for revs older/earlier then reference $rev and select $direction-th one
|
||||
if (($direction > 0 && $info['date'] > $rev) || ($direction < 0 && $info['date'] < $rev)) {
|
||||
$revCounter++;
|
||||
@@ -356,10 +366,10 @@ abstract class ChangeLog
|
||||
//true when $rev is found, but not the wanted follow-up.
|
||||
$checkOtherChunk = $fp
|
||||
&& ($info['date'] == $rev || ($revCounter > 0 && !$relativeRev))
|
||||
&& !(($tail == $eof && $direction > 0) || ($head == 0 && $direction < 0));
|
||||
&& (!($tail == $eof && $direction > 0) && !($head == 0 && $direction < 0));
|
||||
|
||||
if ($checkOtherChunk) {
|
||||
list($lines, $head, $tail) = $this->readAdjacentChunk($fp, $head, $tail, $direction);
|
||||
[$lines, $head, $tail] = $this->readAdjacentChunk($fp, $head, $tail, $direction);
|
||||
|
||||
if (empty($lines)) break;
|
||||
}
|
||||
@@ -382,7 +392,7 @@ abstract class ChangeLog
|
||||
*/
|
||||
public function getRevisionsAround($rev1, $rev2, $max = 50)
|
||||
{
|
||||
$max = intval(abs($max) / 2) * 2 + 1;
|
||||
$max = (int) (abs($max) / 2) * 2 + 1;
|
||||
$rev1 = max($rev1, 0);
|
||||
$rev2 = max($rev2, 0);
|
||||
|
||||
@@ -397,41 +407,43 @@ abstract class ChangeLog
|
||||
$rev2 = $this->currentRevision();
|
||||
}
|
||||
//collect revisions around rev2
|
||||
list($revs2, $allRevs, $fp, $lines, $head, $tail) = $this->retrieveRevisionsAround($rev2, $max);
|
||||
[$revs2, $allRevs, $fp, $lines, $head, $tail] = $this->retrieveRevisionsAround($rev2, $max);
|
||||
|
||||
if (empty($revs2)) return array(array(), array());
|
||||
if (empty($revs2)) return [[], []];
|
||||
|
||||
//collect revisions around rev1
|
||||
$index = array_search($rev1, $allRevs);
|
||||
if ($index === false) {
|
||||
//no overlapping revisions
|
||||
list($revs1, , , , ,) = $this->retrieveRevisionsAround($rev1, $max);
|
||||
if (empty($revs1)) $revs1 = array();
|
||||
[$revs1, , , , , ] = $this->retrieveRevisionsAround($rev1, $max);
|
||||
if (empty($revs1)) $revs1 = [];
|
||||
} 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--) {
|
||||
$info = $this->parseLogLine($lines[$i]);
|
||||
if ($this->cacheRevisionInfo($info)) {
|
||||
$info = $this->parseAndCacheLogLine($lines[$i]);
|
||||
if (is_array($info)) {
|
||||
$revs1[] = $info['date'];
|
||||
$index++;
|
||||
|
||||
if ($index > intval($max / 2)) break 2;
|
||||
if ($index > (int) ($max / 2)) {
|
||||
break 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
list($lines, $head, $tail) = $this->readAdjacentChunk($fp, $head, $tail, -1);
|
||||
[$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 - intval($max / 2), 0), $max);
|
||||
$revs1 = array_slice($revs1, max($index - (int) ($max / 2), 0), $max);
|
||||
}
|
||||
|
||||
return array(array_reverse($revs1), array_reverse($revs2));
|
||||
return [array_reverse($revs1), array_reverse($revs2)];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -447,12 +459,11 @@ abstract class ChangeLog
|
||||
//requested date_at(timestamp) younger or equal then modified_time($this->id) => load current
|
||||
if (file_exists($fileLastMod) && $date_at >= @filemtime($fileLastMod)) {
|
||||
return '';
|
||||
} elseif ($rev = $this->getRelativeRevision($date_at + 1, -1)) {
|
||||
//+1 to get also the requested date revision
|
||||
return $rev;
|
||||
} else {
|
||||
if ($rev = $this->getRelativeRevision($date_at + 1, -1)) { //+1 to get also the requested date revision
|
||||
return $rev;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -477,11 +488,12 @@ abstract class ChangeLog
|
||||
*/
|
||||
protected function retrieveRevisionsAround($rev, $max)
|
||||
{
|
||||
$revs = array();
|
||||
$afterCount = $beforeCount = 0;
|
||||
$revs = [];
|
||||
$afterCount = 0;
|
||||
$beforeCount = 0;
|
||||
|
||||
//get lines from changelog
|
||||
list($fp, $lines, $startHead, $startTail, $eof) = $this->readloglines($rev);
|
||||
[$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
|
||||
@@ -489,26 +501,31 @@ abstract class ChangeLog
|
||||
$tail = $startTail;
|
||||
while (count($lines) > 0) {
|
||||
foreach ($lines as $line) {
|
||||
$info = $this->parseLogLine($line);
|
||||
if ($this->cacheRevisionInfo($info)) {
|
||||
$info = $this->parseAndCacheLogLine($line);
|
||||
if (is_array($info)) {
|
||||
$revs[] = $info['date'];
|
||||
if ($info['date'] >= $rev) {
|
||||
//count revs after reference $rev
|
||||
$afterCount++;
|
||||
if ($afterCount == 1) $beforeCount = count($revs);
|
||||
if ($afterCount == 1) {
|
||||
$beforeCount = count($revs);
|
||||
}
|
||||
}
|
||||
//enough revs after reference $rev?
|
||||
if ($afterCount > intval($max / 2)) break 2;
|
||||
if ($afterCount > (int) ($max / 2)) {
|
||||
break 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
//retrieve next chunk
|
||||
list($lines, $head, $tail) = $this->readAdjacentChunk($fp, $head, $tail, 1);
|
||||
[$lines, $head, $tail] = $this->readAdjacentChunk($fp, $head, $tail, 1);
|
||||
}
|
||||
$lastTail = $tail;
|
||||
|
||||
// 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])
|
||||
if (
|
||||
$lastTail == $eof && $afterCount <= (int) ($max / 2) &&
|
||||
count($revs) && !$this->isCurrentRevision($revs[count($revs) - 1])
|
||||
) {
|
||||
$revs[] = $this->currentRevision;
|
||||
$afterCount++;
|
||||
@@ -520,21 +537,21 @@ abstract class ChangeLog
|
||||
}
|
||||
|
||||
//read more chunks backward until $max/2 is reached and total number of revs is equal to $max
|
||||
$lines = array();
|
||||
$lines = [];
|
||||
$i = 0;
|
||||
if ($afterCount > 0) {
|
||||
$head = $startHead;
|
||||
$tail = $startTail;
|
||||
while ($head > 0) {
|
||||
list($lines, $head, $tail) = $this->readAdjacentChunk($fp, $head, $tail, -1);
|
||||
$head = $startHead;
|
||||
$tail = $startTail;
|
||||
while ($head > 0) {
|
||||
[$lines, $head, $tail] = $this->readAdjacentChunk($fp, $head, $tail, -1);
|
||||
|
||||
for ($i = count($lines) - 1; $i >= 0; $i--) {
|
||||
$info = $this->parseLogLine($lines[$i]);
|
||||
if ($this->cacheRevisionInfo($info)) {
|
||||
$revs[] = $info['date'];
|
||||
$beforeCount++;
|
||||
//enough revs before reference $rev?
|
||||
if ($beforeCount > max(intval($max / 2), $max - $afterCount)) break 2;
|
||||
for ($i = count($lines) - 1; $i >= 0; $i--) {
|
||||
$info = $this->parseAndCacheLogLine($lines[$i]);
|
||||
if (is_array($info)) {
|
||||
$revs[] = $info['date'];
|
||||
$beforeCount++;
|
||||
//enough revs before reference $rev?
|
||||
if ($beforeCount > max((int) ($max / 2), $max - $afterCount)) {
|
||||
break 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -547,7 +564,7 @@ abstract class ChangeLog
|
||||
//trunk desired selection
|
||||
$requestedRevs = array_slice($revs, -$max, $max);
|
||||
|
||||
return array($requestedRevs, $revs, $fp, $lines, $head, $lastTail);
|
||||
return [$requestedRevs, $revs, $fp, $lines, $head, $lastTail];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -575,6 +592,8 @@ abstract class ChangeLog
|
||||
* - extra: extra data (varies by line type)
|
||||
* - sizechange: change of filesize
|
||||
* - timestamp: unix timestamp or false (key set only for external edit occurred)
|
||||
* additional:
|
||||
* - mode: page or media
|
||||
*
|
||||
* @author Satoshi Sahara <sahara.satoshi@gmail.com>
|
||||
*/
|
||||
@@ -582,7 +601,9 @@ abstract class ChangeLog
|
||||
{
|
||||
global $lang;
|
||||
|
||||
if (isset($this->currentRevision)) return $this->getRevisionInfo($this->currentRevision);
|
||||
if (isset($this->currentRevision)) {
|
||||
return $this->getRevisionInfo($this->currentRevision);
|
||||
}
|
||||
|
||||
// get revision id from the item file timestamp and changelog
|
||||
$fileLastMod = $this->getFilename();
|
||||
@@ -607,17 +628,17 @@ abstract class ChangeLog
|
||||
|
||||
// externally deleted, set revision date as late as possible
|
||||
$revInfo = [
|
||||
'date' => max($lastRev +1, time() -1), // 1 sec before now or new page save
|
||||
'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'].')',
|
||||
'sum' => $lang['deleted'] . ' - ' . $lang['external_edit'] . ' (' . $lang['unknowndate'] . ')',
|
||||
'extra' => '',
|
||||
'sizechange' => -io_getSizeFile($this->getFilename($lastRev)),
|
||||
'timestamp' => false,
|
||||
'mode' => $this->getMode()
|
||||
];
|
||||
|
||||
} else { // item file exists, with timestamp $fileRev
|
||||
// here, file timestamp $fileRev is different with last revision timestamp $lastRev in changelog
|
||||
$isJustCreated = $lastRev === false || (
|
||||
@@ -630,23 +651,23 @@ abstract class ChangeLog
|
||||
|
||||
if ($isJustCreated) {
|
||||
$timestamp = $fileRev;
|
||||
$sum = $lang['created'].' - '.$lang['external_edit'];
|
||||
$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 occurrence.
|
||||
$msg = "Warning: current file modification time is older than last revision date";
|
||||
$details = 'File revision: '.$fileRev.' '.dformat($fileRev, "%Y-%m-%d %H:%M:%S")."\n"
|
||||
.'Last revision: '.$lastRev.' '.dformat($lastRev, "%Y-%m-%d %H:%M:%S");
|
||||
$details = 'File revision: ' . $fileRev . ' ' . dformat($fileRev, "%Y-%m-%d %H:%M:%S") . "\n"
|
||||
. 'Last revision: ' . $lastRev . ' ' . dformat($lastRev, "%Y-%m-%d %H:%M:%S");
|
||||
Logger::error($msg, $details, $this->getFilename());
|
||||
$timestamp = false;
|
||||
$sum = $lang['external_edit'].' ('.$lang['unknowndate'].')';
|
||||
$sum = $lang['external_edit'] . ' (' . $lang['unknowndate'] . ')';
|
||||
}
|
||||
|
||||
// externally created or edited
|
||||
$revInfo = [
|
||||
'date' => $timestamp ?: $lastRev +1,
|
||||
'date' => $timestamp ?: $lastRev + 1,
|
||||
'ip' => '127.0.0.1',
|
||||
'type' => $isJustCreated ? DOKU_CHANGE_TYPE_CREATE : DOKU_CHANGE_TYPE_EDIT,
|
||||
'id' => $this->id,
|
||||
@@ -655,6 +676,7 @@ abstract class ChangeLog
|
||||
'extra' => '',
|
||||
'sizechange' => $sizechange,
|
||||
'timestamp' => $timestamp,
|
||||
'mode' => $this->getMode()
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@@ -17,26 +17,26 @@ trait ChangeLogTrait
|
||||
abstract public function addLogEntry(array $info, $timestamp = null);
|
||||
|
||||
/**
|
||||
* Parses a changelog line into it's components
|
||||
*
|
||||
* @author Ben Coburn <btcoburn@silicodon.net>
|
||||
* Parses a changelog line into its components
|
||||
*
|
||||
* @param string $line changelog line
|
||||
* @return array|bool parsed line or false
|
||||
* @author Ben Coburn <btcoburn@silicodon.net>
|
||||
*
|
||||
*/
|
||||
public static function parseLogLine($line)
|
||||
{
|
||||
$info = explode("\t", rtrim($line, "\n"));
|
||||
if ($info !== false && count($info) > 1) {
|
||||
$info = sexplode("\t", rtrim($line, "\n"), 8);
|
||||
if ($info[3]) { // we need at least the page id to consider it a valid line
|
||||
return [
|
||||
'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)
|
||||
'date' => (int)$info[0], // unix timestamp
|
||||
'ip' => $info[1], // IP 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, //
|
||||
'sizechange' => ($info[7] != '') ? (int)$info[7] : null, // size difference in bytes
|
||||
];
|
||||
} else {
|
||||
return false;
|
||||
@@ -44,7 +44,7 @@ trait ChangeLogTrait
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a changelog line from it's components
|
||||
* Build a changelog line from its components
|
||||
*
|
||||
* @param array $info Revision info structure
|
||||
* @param int $timestamp log line date (optional)
|
||||
@@ -53,18 +53,18 @@ trait ChangeLogTrait
|
||||
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' => PhpString::substr(str_replace($strip, '', $info['sum']), 0, 255),
|
||||
$entry = [
|
||||
'date' => $timestamp ?? $info['date'],
|
||||
'ip' => $info['ip'],
|
||||
'type' => str_replace($strip, '', $info['type']),
|
||||
'id' => $info['id'],
|
||||
'user' => $info['user'],
|
||||
'sum' => PhpString::substr(str_replace($strip, '', $info['sum'] ?? ''), 0, 255),
|
||||
'extra' => str_replace($strip, '', $info['extra']),
|
||||
'sizechange' => $info['sizechange'],
|
||||
);
|
||||
'sizechange' => $info['sizechange']
|
||||
];
|
||||
$info = $entry;
|
||||
return implode("\t", $entry) ."\n";
|
||||
return implode("\t", $entry) . "\n";
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -98,7 +98,7 @@ trait ChangeLogTrait
|
||||
{
|
||||
if (!is_numeric($chunk_size)) $chunk_size = 0;
|
||||
|
||||
$this->chunk_size = (int)max($chunk_size, 0);
|
||||
$this->chunk_size = max($chunk_size, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -145,7 +145,7 @@ trait ChangeLogTrait
|
||||
|
||||
// find chunk
|
||||
while ($tail - $head > $this->chunk_size) {
|
||||
$finger = $head + intval(($tail - $head) / 2);
|
||||
$finger = $head + (int)(($tail - $head) / 2);
|
||||
$finger = $this->getNewlinepointer($fp, $finger);
|
||||
$tmp = fgets($fp);
|
||||
if ($finger == $head || $finger == $tail) {
|
||||
@@ -169,13 +169,7 @@ trait ChangeLogTrait
|
||||
|
||||
$lines = $this->readChunk($fp, $head, $tail);
|
||||
}
|
||||
return array(
|
||||
$fp,
|
||||
$lines,
|
||||
$head,
|
||||
$tail,
|
||||
$eof,
|
||||
);
|
||||
return [$fp, $lines, $head, $tail, $eof];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -238,12 +232,12 @@ trait ChangeLogTrait
|
||||
*/
|
||||
protected function readAdjacentChunk($fp, $head, $tail, $direction)
|
||||
{
|
||||
if (!$fp) return array(array(), $head, $tail);
|
||||
if (!$fp) return [[], $head, $tail];
|
||||
|
||||
if ($direction > 0) {
|
||||
//read forward
|
||||
$head = $tail;
|
||||
$tail = $head + intval($this->chunk_size * (2 / 3));
|
||||
$tail = $head + (int)($this->chunk_size * (2 / 3));
|
||||
$tail = $this->getNewlinepointer($fp, $tail);
|
||||
} else {
|
||||
//read backward
|
||||
@@ -263,7 +257,6 @@ trait ChangeLogTrait
|
||||
|
||||
//load next chunk
|
||||
$lines = $this->readChunk($fp, $head, $tail);
|
||||
return array($lines, $head, $tail);
|
||||
return [$lines, $head, $tail];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@ namespace dokuwiki\ChangeLog;
|
||||
*/
|
||||
class MediaChangeLog extends ChangeLog
|
||||
{
|
||||
|
||||
/**
|
||||
* Returns path to changelog
|
||||
*
|
||||
@@ -29,6 +28,15 @@ class MediaChangeLog extends ChangeLog
|
||||
return mediaFN($this->id, $rev);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns mode
|
||||
*
|
||||
* @return string RevisionInfo::MODE_PAGE
|
||||
*/
|
||||
protected function getMode()
|
||||
{
|
||||
return RevisionInfo::MODE_MEDIA;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
@@ -47,14 +55,14 @@ class MediaChangeLog extends ChangeLog
|
||||
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);
|
||||
$logline = static::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'];
|
||||
$info['mode'] = $this->getMode();
|
||||
$this->cache[$this->id][$this->currentRevision] = $info;
|
||||
return $info;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@ namespace dokuwiki\ChangeLog;
|
||||
*/
|
||||
class PageChangeLog extends ChangeLog
|
||||
{
|
||||
|
||||
/**
|
||||
* Returns path to changelog
|
||||
*
|
||||
@@ -29,6 +28,15 @@ class PageChangeLog extends ChangeLog
|
||||
return wikiFN($this->id, $rev);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns mode
|
||||
*
|
||||
* @return string RevisionInfo::MODE_PAGE
|
||||
*/
|
||||
protected function getMode()
|
||||
{
|
||||
return RevisionInfo::MODE_PAGE;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
@@ -47,14 +55,14 @@ class PageChangeLog extends ChangeLog
|
||||
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, true);
|
||||
$logline = static::buildLogLine($info, $timestamp);
|
||||
io_saveFile(metaFN($this->id, '.changes'), $logline, true);
|
||||
io_saveFile($conf['changelog'], $logline, true); //global changelog cache
|
||||
|
||||
// update cache
|
||||
$this->currentRevision = $info['date'];
|
||||
$info['mode'] = $this->getMode();
|
||||
$this->cache[$this->id][$this->currentRevision] = $info;
|
||||
return $info;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -9,9 +9,14 @@ namespace dokuwiki\ChangeLog;
|
||||
* - Ui\Recent
|
||||
* - Ui\PageRevisions
|
||||
* - Ui\MediaRevisions
|
||||
* - Ui\PageDiff
|
||||
* - Ui\MediaDiff
|
||||
*/
|
||||
class RevisionInfo
|
||||
{
|
||||
public const MODE_PAGE = 'page';
|
||||
public const MODE_MEDIA = 'media';
|
||||
|
||||
/* @var array */
|
||||
protected $info;
|
||||
|
||||
@@ -34,12 +39,9 @@ class RevisionInfo
|
||||
*/
|
||||
public function __construct($info = null)
|
||||
{
|
||||
if (is_array($info) && isset($info['id'])) {
|
||||
// define strategy context
|
||||
$info['mode'] = strrpos($info['id'], '.') ? 'media' : 'page';
|
||||
} else {
|
||||
if (!is_array($info) || !isset($info['id'])) {
|
||||
$info = [
|
||||
'mode' => 'page',
|
||||
'mode' => self::MODE_PAGE,
|
||||
'date' => false,
|
||||
];
|
||||
}
|
||||
@@ -106,11 +108,12 @@ class RevisionInfo
|
||||
public function showFileIcon()
|
||||
{
|
||||
$id = $this->val('id');
|
||||
switch ($this->val('mode')) {
|
||||
case 'media': // media file revision
|
||||
return media_printicon($id);
|
||||
case 'page': // page revision
|
||||
return '<img class="icon" src="'.DOKU_BASE.'lib/images/fileicons/file.png" alt="'.$id.'" />';
|
||||
if ($this->val('mode') == self::MODE_MEDIA) {
|
||||
// media file revision
|
||||
return media_printicon($id);
|
||||
} elseif ($this->val('mode') == self::MODE_PAGE) {
|
||||
// page revision
|
||||
return '<img class="icon" src="' . DOKU_BASE . 'lib/images/fileicons/file.png" alt="' . $id . '" />';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -127,9 +130,9 @@ class RevisionInfo
|
||||
if ($checkTimestamp && $this->val('timestamp') === false) {
|
||||
// exact date is unknown for externally deleted file
|
||||
// when unknown, alter formatted string "YYYY-mm-DD HH:MM" to "____-__-__ __:__"
|
||||
$formatted = preg_replace('/[0-9a-zA-Z]/','_', $formatted);
|
||||
$formatted = preg_replace('/[0-9a-zA-Z]/', '_', $formatted);
|
||||
}
|
||||
return '<span class="date">'. $formatted .'</span>';
|
||||
return '<span class="date">' . $formatted . '</span>';
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -140,7 +143,7 @@ class RevisionInfo
|
||||
*/
|
||||
public function showEditSummary()
|
||||
{
|
||||
return '<span class="sum">'.' – '. hsc($this->val('sum')).'</span>';
|
||||
return '<span class="sum">' . ' – ' . hsc($this->val('sum')) . '</span>';
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -152,12 +155,14 @@ class RevisionInfo
|
||||
public function showEditor()
|
||||
{
|
||||
if ($this->val('user')) {
|
||||
$html = '<bdi>'. editorinfo($this->val('user')) .'</bdi>';
|
||||
if (auth_ismanager()) $html .= ' <bdo dir="ltr">('. $this->val('ip') .')</bdo>';
|
||||
$html = '<bdi>' . editorinfo($this->val('user')) . '</bdi>';
|
||||
if (auth_ismanager()) {
|
||||
$html .= ' <bdo dir="ltr">(' . $this->val('ip') . ')</bdo>';
|
||||
}
|
||||
} else {
|
||||
$html = '<bdo dir="ltr">'. $this->val('ip') .'</bdo>';
|
||||
$html = '<bdo dir="ltr">' . $this->val('ip') . '</bdo>';
|
||||
}
|
||||
return '<span class="user">'. $html. '</span>';
|
||||
return '<span class="user">' . $html . '</span>';
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -171,37 +176,35 @@ class RevisionInfo
|
||||
$id = $this->val('id');
|
||||
$rev = $this->isCurrent() ? '' : $this->val('date');
|
||||
|
||||
switch ($this->val('mode')) {
|
||||
case 'media': // media file revision
|
||||
$params = ['tab_details'=> 'view', 'ns'=> getNS($id), 'image'=> $id];
|
||||
if ($rev) $params += ['rev'=> $rev];
|
||||
$href = media_managerURL($params, '&');
|
||||
$display_name = $id;
|
||||
$exists = file_exists(mediaFN($id, $rev));
|
||||
break;
|
||||
case 'page': // page revision
|
||||
$params = $rev ? ['rev'=> $rev] : [];
|
||||
$href = wl($id, $params, false, '&');
|
||||
$display_name = useHeading('navigation') ? hsc(p_get_first_heading($id)) : $id;
|
||||
if (!$display_name) $display_name = $id;
|
||||
$exists = page_exists($id, $rev);
|
||||
if ($this->val('mode') == self::MODE_MEDIA) {
|
||||
// media file revision
|
||||
$params = ['tab_details' => 'view', 'ns' => getNS($id), 'image' => $id];
|
||||
if ($rev) $params += ['rev' => $rev];
|
||||
$href = media_managerURL($params, '&');
|
||||
$display_name = $id;
|
||||
$exists = file_exists(mediaFN($id, $rev));
|
||||
} elseif ($this->val('mode') == self::MODE_PAGE) {
|
||||
// page revision
|
||||
$params = $rev ? ['rev' => $rev] : [];
|
||||
$href = wl($id, $params, false, '&');
|
||||
$display_name = useHeading('navigation') ? hsc(p_get_first_heading($id)) : $id;
|
||||
if (!$display_name) $display_name = $id;
|
||||
$exists = page_exists($id, $rev);
|
||||
}
|
||||
|
||||
if($exists) {
|
||||
if ($exists) {
|
||||
$class = 'wikilink1';
|
||||
} elseif ($this->isCurrent()) {
|
||||
//show only not-existing link for current page, which allows for directly create a new page/upload
|
||||
$class = 'wikilink2';
|
||||
} else {
|
||||
if($this->isCurrent()) {
|
||||
//show only not-existing link for current page, which allows for directly create a new page/upload
|
||||
$class = 'wikilink2';
|
||||
} else {
|
||||
//revision is not in attic
|
||||
return $display_name;
|
||||
}
|
||||
//revision is not in attic
|
||||
return $display_name;
|
||||
}
|
||||
if ($this->val('type') == DOKU_CHANGE_TYPE_DELETE) {
|
||||
$class = 'wikilink2';
|
||||
}
|
||||
return '<a href="'.$href.'" class="'.$class.'">'.$display_name.'</a>';
|
||||
return '<a href="' . $href . '" class="' . $class . '">' . $display_name . '</a>';
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -217,7 +220,7 @@ class RevisionInfo
|
||||
|
||||
$id = $this->val('id');
|
||||
$rev = $this->isCurrent() ? '' : $this->val('date');
|
||||
$params = ($rev) ? ['rev'=> $rev] : [];
|
||||
$params = ($rev) ? ['rev' => $rev] : [];
|
||||
|
||||
// revision info may have timestamp key when external edits occurred
|
||||
$date = ($this->val('timestamp') === false)
|
||||
@@ -225,30 +228,28 @@ class RevisionInfo
|
||||
: dformat($this->val('date'));
|
||||
|
||||
|
||||
switch ($this->val('mode')) {
|
||||
case 'media': // media file revision
|
||||
$href = ml($id, $params, false, '&');
|
||||
$exists = file_exists(mediaFN($id, $rev));
|
||||
break;
|
||||
case 'page': // page revision
|
||||
$href = wl($id, $params, false, '&');
|
||||
$exists = page_exists($id, $rev);
|
||||
if ($this->val('mode') == self::MODE_MEDIA) {
|
||||
// media file revision
|
||||
$href = ml($id, $params, false, '&');
|
||||
$exists = file_exists(mediaFN($id, $rev));
|
||||
} elseif ($this->val('mode') == self::MODE_PAGE) {
|
||||
// page revision
|
||||
$href = wl($id, $params, false, '&');
|
||||
$exists = page_exists($id, $rev);
|
||||
}
|
||||
if($exists) {
|
||||
if ($exists) {
|
||||
$class = 'wikilink1';
|
||||
} elseif ($this->isCurrent()) {
|
||||
//show only not-existing link for current page, which allows for directly create a new page/upload
|
||||
$class = 'wikilink2';
|
||||
} else {
|
||||
if($this->isCurrent()) {
|
||||
//show only not-existing link for current page, which allows for directly create a new page/upload
|
||||
$class = 'wikilink2';
|
||||
} else {
|
||||
//revision is not in attic
|
||||
return $id.' ['.$date.']';
|
||||
}
|
||||
//revision is not in attic
|
||||
return $id . ' [' . $date . ']';
|
||||
}
|
||||
if ($this->val('type') == DOKU_CHANGE_TYPE_DELETE) {
|
||||
$class = 'wikilink2';
|
||||
}
|
||||
return '<bdi><a class="'.$class.'" href="'.$href.'">'.$id.' ['.$date.']'.'</a></bdi>';
|
||||
return '<bdi><a class="' . $class . '" href="' . $href . '">' . $id . ' [' . $date . ']' . '</a></bdi>';
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -263,33 +264,33 @@ class RevisionInfo
|
||||
$id = $this->val('id');
|
||||
|
||||
$href = '';
|
||||
switch ($this->val('mode')) {
|
||||
case 'media': // media file revision
|
||||
// unlike page, media file does not copied to media_attic when uploaded.
|
||||
// diff icon will not be shown when external edit occurred
|
||||
// because no attic file to be compared with current.
|
||||
$revs = (new MediaChangeLog($id))->getRevisions(0, 1);
|
||||
$showLink = (count($revs) && file_exists(mediaFN($id,$revs[0])) && file_exists(mediaFN($id)));
|
||||
if ($showLink) {
|
||||
$param = ['tab_details'=>'history', 'mediado'=>'diff', 'ns'=> getNS($id), 'image'=> $id];
|
||||
$href = media_managerURL($param, '&');
|
||||
}
|
||||
break;
|
||||
case 'page': // page revision
|
||||
// when a page just created anyway, it is natural to expect no older revisions
|
||||
// even if it had once existed but deleted before. Simply ignore to check changelog.
|
||||
if ($this->val('type') !== DOKU_CHANGE_TYPE_CREATE) {
|
||||
$href = wl($id, ['do'=>'diff'], false, '&');
|
||||
}
|
||||
if ($this->val('mode') == self::MODE_MEDIA) {
|
||||
// media file revision
|
||||
// unlike page, media file does not copied to media_attic when uploaded.
|
||||
// diff icon will not be shown when external edit occurred
|
||||
// because no attic file to be compared with current.
|
||||
$revs = (new MediaChangeLog($id))->getRevisions(0, 1);
|
||||
$showLink = (count($revs) && file_exists(mediaFN($id, $revs[0])) && file_exists(mediaFN($id)));
|
||||
if ($showLink) {
|
||||
$param = ['tab_details' => 'history', 'mediado' => 'diff', 'ns' => getNS($id), 'image' => $id];
|
||||
$href = media_managerURL($param, '&');
|
||||
}
|
||||
} elseif ($this->val('mode') == self::MODE_PAGE) {
|
||||
// page revision
|
||||
// when a page just created anyway, it is natural to expect no older revisions
|
||||
// even if it had once existed but deleted before. Simply ignore to check changelog.
|
||||
if ($this->val('type') !== DOKU_CHANGE_TYPE_CREATE) {
|
||||
$href = wl($id, ['do' => 'diff'], false, '&');
|
||||
}
|
||||
}
|
||||
|
||||
if ($href) {
|
||||
return '<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 '<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>';
|
||||
} else {
|
||||
return '<img src="'.DOKU_BASE.'lib/images/blank.gif" width="15" height="11" alt="" />';
|
||||
return '<img src="' . DOKU_BASE . 'lib/images/blank.gif" width="15" height="11" alt="" />';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -306,26 +307,26 @@ class RevisionInfo
|
||||
$rev = $this->isCurrent() ? '' : $this->val('date');
|
||||
|
||||
$href = '';
|
||||
switch ($this->val('mode')) {
|
||||
case 'media': // media file revision
|
||||
if (!$this->isCurrent() && file_exists(mediaFN($id, $rev))) {
|
||||
$param = ['mediado'=>'diff', 'image'=> $id, 'rev'=> $rev];
|
||||
$href = media_managerURL($param, '&');
|
||||
}
|
||||
break;
|
||||
case 'page': // page revision
|
||||
if (!$this->isCurrent()) {
|
||||
$href = wl($id, ['rev'=> $rev, 'do'=>'diff'], false, '&');
|
||||
}
|
||||
if ($this->val('mode') == self::MODE_MEDIA) {
|
||||
// media file revision
|
||||
if (!$this->isCurrent() && file_exists(mediaFN($id, $rev))) {
|
||||
$param = ['mediado' => 'diff', 'image' => $id, 'rev' => $rev];
|
||||
$href = media_managerURL($param, '&');
|
||||
}
|
||||
} elseif ($this->val('mode') == self::MODE_PAGE) {
|
||||
// page revision
|
||||
if (!$this->isCurrent()) {
|
||||
$href = wl($id, ['rev' => $rev, 'do' => 'diff'], false, '&');
|
||||
}
|
||||
}
|
||||
|
||||
if ($href) {
|
||||
return '<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 '<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>';
|
||||
} else {
|
||||
return '<img src="'.DOKU_BASE.'lib/images/blank.gif" width="15" height="11" alt="" />';
|
||||
return '<img src="' . DOKU_BASE . 'lib/images/blank.gif" width="15" height="11" alt="" />';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -344,17 +345,17 @@ class RevisionInfo
|
||||
}
|
||||
|
||||
$id = $this->val('id');
|
||||
switch ($this->val('mode')) {
|
||||
case 'media': // media file revision
|
||||
$param = ['tab_details'=>'history', 'ns'=> getNS($id), 'image'=> $id];
|
||||
$href = media_managerURL($param, '&');
|
||||
break;
|
||||
case 'page': // page revision
|
||||
$href = wl($id, ['do'=>'revisions'], false, '&');
|
||||
if ($this->val('mode') == self::MODE_MEDIA) {
|
||||
// media file revision
|
||||
$param = ['tab_details' => 'history', 'ns' => getNS($id), 'image' => $id];
|
||||
$href = media_managerURL($param, '&');
|
||||
} elseif ($this->val('mode') == self::MODE_PAGE) {
|
||||
// page revision
|
||||
$href = wl($id, ['do' => 'revisions'], false, '&');
|
||||
}
|
||||
return '<a href="'.$href.'" class="revisions_link">'
|
||||
. '<img src="'.DOKU_BASE.'lib/images/history.png" width="12" height="14"'
|
||||
. ' title="'.$lang['btn_revs'].'" alt="'.$lang['btn_revs'].'" />'
|
||||
return '<a href="' . $href . '" class="revisions_link">'
|
||||
. '<img src="' . DOKU_BASE . 'lib/images/history.png" width="12" height="14"'
|
||||
. ' title="' . $lang['btn_revs'] . '" alt="' . $lang['btn_revs'] . '" />'
|
||||
. '</a>';
|
||||
}
|
||||
|
||||
@@ -377,7 +378,7 @@ class RevisionInfo
|
||||
} else {
|
||||
$value = '±' . $value;
|
||||
}
|
||||
return '<span class="'.$class.'">'.$value.'</span>';
|
||||
return '<span class="' . $class . '">' . $value . '</span>';
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -389,8 +390,6 @@ class RevisionInfo
|
||||
public function showCurrentIndicator()
|
||||
{
|
||||
global $lang;
|
||||
return $this->isCurrent() ? '('.$lang['current'].')' : '';
|
||||
return $this->isCurrent() ? '(' . $lang['current'] . ')' : '';
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1,15 +1,35 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace dokuwiki\Debug;
|
||||
|
||||
use Doku_Event;
|
||||
use dokuwiki\Extension\Event;
|
||||
use dokuwiki\Extension\EventHandler;
|
||||
use dokuwiki\Logger;
|
||||
|
||||
class DebugHelper
|
||||
{
|
||||
const INFO_DEPRECATION_LOG_EVENT = 'INFO_DEPRECATION_LOG';
|
||||
protected const INFO_DEPRECATION_LOG_EVENT = 'INFO_DEPRECATION_LOG';
|
||||
|
||||
/**
|
||||
* Check if deprecation messages shall be handled
|
||||
*
|
||||
* This is either because its logging is not disabled or a deprecation handler was registered
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function isEnabled()
|
||||
{
|
||||
/** @var EventHandler $EVENT_HANDLER */
|
||||
global $EVENT_HANDLER;
|
||||
if (
|
||||
!Logger::getInstance(Logger::LOG_DEPRECATED)->isLogging() &&
|
||||
(!$EVENT_HANDLER instanceof EventHandler || !$EVENT_HANDLER->hasHandlerForEvent('INFO_DEPRECATION_LOG'))
|
||||
) {
|
||||
// avoid any work if no one cares
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Log accesses to deprecated fucntions to the debug log
|
||||
@@ -21,61 +41,54 @@ class DebugHelper
|
||||
*/
|
||||
public static function dbgDeprecatedFunction($alternative = '', $callerOffset = 1, $thing = '')
|
||||
{
|
||||
global $conf;
|
||||
/** @var EventHandler $EVENT_HANDLER */
|
||||
global $EVENT_HANDLER;
|
||||
if (
|
||||
!$conf['allowdebug'] &&
|
||||
($EVENT_HANDLER === null || !$EVENT_HANDLER->hasHandlerForEvent('INFO_DEPRECATION_LOG'))
|
||||
){
|
||||
// avoid any work if no one cares
|
||||
return;
|
||||
}
|
||||
if (!self::isEnabled()) return;
|
||||
|
||||
$backtrace = debug_backtrace();
|
||||
for ($i = 0; $i < $callerOffset; $i += 1) {
|
||||
array_shift($backtrace);
|
||||
for ($i = 0; $i < $callerOffset; ++$i) {
|
||||
if (count($backtrace) > 1) array_shift($backtrace);
|
||||
}
|
||||
|
||||
list($self, $call) = $backtrace;
|
||||
|
||||
if (!$thing) {
|
||||
$thing = trim(
|
||||
(!empty($self['class']) ? ($self['class'] . '::') : '') .
|
||||
$self['function'] . '()', ':');
|
||||
}
|
||||
[$self, $call] = $backtrace;
|
||||
|
||||
self::triggerDeprecationEvent(
|
||||
$backtrace,
|
||||
$alternative,
|
||||
$thing,
|
||||
trim(
|
||||
(!empty($call['class']) ? ($call['class'] . '::') : '') .
|
||||
$call['function'] . '()', ':'),
|
||||
$self['file'],
|
||||
$self['line']
|
||||
self::formatCall($self),
|
||||
self::formatCall($call),
|
||||
$self['file'] ?? $call['file'] ?? '',
|
||||
$self['line'] ?? $call['line'] ?? 0
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Format the given backtrace info into a proper function/method call string
|
||||
* @param array $call
|
||||
* @return string
|
||||
*/
|
||||
protected static function formatCall($call)
|
||||
{
|
||||
$thing = '';
|
||||
if (!empty($call['class'])) {
|
||||
$thing .= $call['class'] . '::';
|
||||
}
|
||||
$thing .= $call['function'] . '()';
|
||||
return trim($thing, ':');
|
||||
}
|
||||
|
||||
/**
|
||||
* This marks logs a deprecation warning for a property that should no longer be used
|
||||
*
|
||||
* This is usually called withing a magic getter or setter.
|
||||
* For logging deprecated functions or methods see dbgDeprecatedFunction()
|
||||
*
|
||||
* @param string $class The class with the deprecated property
|
||||
* @param string $class The class with the deprecated property
|
||||
* @param string $propertyName The name of the deprecated property
|
||||
*
|
||||
* @triggers \dokuwiki\Debug::INFO_DEPRECATION_LOG_EVENT
|
||||
*/
|
||||
public static function dbgDeprecatedProperty($class, $propertyName)
|
||||
{
|
||||
global $conf;
|
||||
global $EVENT_HANDLER;
|
||||
if (!$conf['allowdebug'] && !$EVENT_HANDLER->hasHandlerForEvent(self::INFO_DEPRECATION_LOG_EVENT)) {
|
||||
// avoid any work if no one cares
|
||||
return;
|
||||
}
|
||||
if (!self::isEnabled()) return;
|
||||
|
||||
$backtrace = debug_backtrace();
|
||||
array_shift($backtrace);
|
||||
@@ -102,8 +115,8 @@ class DebugHelper
|
||||
* @param string $deprecatedThing
|
||||
* @param string $caller
|
||||
* @param string $file
|
||||
* @param int $line
|
||||
* @param int $callerOffset How many lines should be removed from the beginning of the backtrace
|
||||
* @param int $line
|
||||
* @param int $callerOffset How many lines should be removed from the beginning of the backtrace
|
||||
*/
|
||||
public static function dbgCustomDeprecationEvent(
|
||||
$alternative,
|
||||
@@ -113,13 +126,7 @@ class DebugHelper
|
||||
$line,
|
||||
$callerOffset = 1
|
||||
) {
|
||||
global $conf;
|
||||
/** @var EventHandler $EVENT_HANDLER */
|
||||
global $EVENT_HANDLER;
|
||||
if (!$conf['allowdebug'] && !$EVENT_HANDLER->hasHandlerForEvent(self::INFO_DEPRECATION_LOG_EVENT)) {
|
||||
// avoid any work if no one cares
|
||||
return;
|
||||
}
|
||||
if (!self::isEnabled()) return;
|
||||
|
||||
$backtrace = array_slice(debug_backtrace(), $callerOffset);
|
||||
|
||||
@@ -131,16 +138,15 @@ class DebugHelper
|
||||
$file,
|
||||
$line
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $backtrace
|
||||
* @param array $backtrace
|
||||
* @param string $alternative
|
||||
* @param string $deprecatedThing
|
||||
* @param string $caller
|
||||
* @param string $file
|
||||
* @param int $line
|
||||
* @param int $line
|
||||
*/
|
||||
private static function triggerDeprecationEvent(
|
||||
array $backtrace,
|
||||
@@ -158,7 +164,7 @@ class DebugHelper
|
||||
'file' => $file,
|
||||
'line' => $line,
|
||||
];
|
||||
$event = new Doku_Event(self::INFO_DEPRECATION_LOG_EVENT, $data);
|
||||
$event = new Event(self::INFO_DEPRECATION_LOG_EVENT, $data);
|
||||
if ($event->advise_before()) {
|
||||
$msg = $event->data['called'] . ' is deprecated. It was called from ';
|
||||
$msg .= $event->data['caller'] . ' in ' . $event->data['file'] . ':' . $event->data['line'];
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Trait for issuing warnings on deprecated access.
|
||||
*
|
||||
@@ -6,7 +7,6 @@
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
namespace dokuwiki\Debug;
|
||||
|
||||
/**
|
||||
@@ -32,7 +32,6 @@ namespace dokuwiki\Debug;
|
||||
*/
|
||||
trait PropertyDeprecationHelper
|
||||
{
|
||||
|
||||
/**
|
||||
* List of deprecated properties, in <property name> => <class> format
|
||||
* where <class> is the the name of the class defining the property
|
||||
@@ -54,7 +53,7 @@ trait PropertyDeprecationHelper
|
||||
$property,
|
||||
$class = null
|
||||
) {
|
||||
$this->deprecatedPublicProperties[$property] = $class ?: get_class();
|
||||
$this->deprecatedPublicProperties[$property] = $class ?: get_class($this);
|
||||
}
|
||||
|
||||
public function __get($name)
|
||||
@@ -108,7 +107,7 @@ trait PropertyDeprecationHelper
|
||||
// The class name is not necessarily correct here but getting the correct class
|
||||
// name would be expensive, this will work most of the time and getting it
|
||||
// wrong is not a big deal.
|
||||
return __CLASS__;
|
||||
return self::class;
|
||||
}
|
||||
// property_exists() returns false when the property does exist but is private (and not
|
||||
// defined by the current class, for some value of "current" that differs slightly
|
||||
@@ -124,7 +123,7 @@ trait PropertyDeprecationHelper
|
||||
$classname = substr($obfuscatedProp, 1, -strlen($obfuscatedPropTail));
|
||||
if ($classname === '*') {
|
||||
// sanity; this shouldn't be possible as protected properties were handled earlier
|
||||
$classname = __CLASS__;
|
||||
$classname = self::class;
|
||||
}
|
||||
return $classname;
|
||||
}
|
||||
|
||||
@@ -929,6 +929,18 @@ define('NBSP', "\xC2\xA0"); // utf-8 non-breaking space.
|
||||
|
||||
class _HWLDF_WordAccumulator {
|
||||
|
||||
/** @var array */
|
||||
protected $_lines;
|
||||
|
||||
/** @var string */
|
||||
protected $_line;
|
||||
|
||||
/** @var string */
|
||||
protected $_group;
|
||||
|
||||
/** @var string */
|
||||
protected $_tag;
|
||||
|
||||
function __construct() {
|
||||
$this->_lines = array();
|
||||
$this->_line = '';
|
||||
@@ -1439,6 +1451,18 @@ class Diff3 extends Diff {
|
||||
*/
|
||||
class _Diff3_Op {
|
||||
|
||||
/** @var array|mixed */
|
||||
protected $orig;
|
||||
|
||||
/** @var array|mixed */
|
||||
protected $final1;
|
||||
|
||||
/** @var array|mixed */
|
||||
protected $final2;
|
||||
|
||||
/** @var array|mixed|false */
|
||||
protected $_merged;
|
||||
|
||||
function __construct($orig = false, $final1 = false, $final2 = false) {
|
||||
$this->orig = $orig ? $orig : array();
|
||||
$this->final1 = $final1 ? $final1 : array();
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
namespace dokuwiki;
|
||||
|
||||
use dokuwiki\Extension\Event;
|
||||
|
||||
/**
|
||||
* Class Draft
|
||||
*
|
||||
@@ -9,7 +11,6 @@ namespace dokuwiki;
|
||||
*/
|
||||
class Draft
|
||||
{
|
||||
|
||||
protected $errors = [];
|
||||
protected $cname;
|
||||
protected $id;
|
||||
@@ -26,7 +27,7 @@ class Draft
|
||||
$this->id = $ID;
|
||||
$this->client = $client;
|
||||
$this->cname = getCacheName("$client\n$ID", '.draft');
|
||||
if(file_exists($this->cname) && file_exists(wikiFN($ID))) {
|
||||
if (file_exists($this->cname) && file_exists(wikiFN($ID))) {
|
||||
if (filemtime($this->cname) < filemtime(wikiFN($ID))) {
|
||||
// remove stale draft
|
||||
$this->deleteDraft();
|
||||
@@ -72,8 +73,10 @@ class Draft
|
||||
if (!$conf['usedraft']) {
|
||||
return false;
|
||||
}
|
||||
if (!$INPUT->post->has('wikitext') &&
|
||||
!$EVENT_HANDLER->hasHandlerForEvent('DRAFT_SAVE')) {
|
||||
if (
|
||||
!$INPUT->post->has('wikitext') &&
|
||||
!$EVENT_HANDLER->hasHandlerForEvent('DRAFT_SAVE')
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
$draft = [
|
||||
@@ -86,7 +89,7 @@ class Draft
|
||||
'cname' => $this->cname,
|
||||
'errors' => [],
|
||||
];
|
||||
$event = new Extension\Event('DRAFT_SAVE', $draft);
|
||||
$event = new Event('DRAFT_SAVE', $draft);
|
||||
if ($event->advise_before()) {
|
||||
$draft['hasBeenSaved'] = io_saveFile($draft['cname'], serialize($draft));
|
||||
if ($draft['hasBeenSaved']) {
|
||||
@@ -116,8 +119,8 @@ class Draft
|
||||
"Draft for page $this->id and user $this->client doesn't exist at $this->cname."
|
||||
);
|
||||
}
|
||||
$draft = unserialize(io_readFile($this->cname,false));
|
||||
return cleanText(con($draft['prefix'],$draft['text'],$draft['suffix'],true));
|
||||
$draft = unserialize(io_readFile($this->cname, false));
|
||||
return cleanText(con($draft['prefix'], $draft['text'], $draft['suffix'], true));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -11,6 +11,28 @@ use dokuwiki\Exception\FatalException;
|
||||
*/
|
||||
class ErrorHandler
|
||||
{
|
||||
/**
|
||||
* Standard error codes used in PHP errors
|
||||
* @see https://www.php.net/manual/en/errorfunc.constants.php
|
||||
*/
|
||||
protected const ERRORCODES = [
|
||||
1 => 'E_ERROR',
|
||||
2 => 'E_WARNING',
|
||||
4 => 'E_PARSE',
|
||||
8 => 'E_NOTICE',
|
||||
16 => 'E_CORE_ERROR',
|
||||
32 => 'E_CORE_WARNING',
|
||||
64 => 'E_COMPILE_ERROR',
|
||||
128 => 'E_COMPILE_WARNING',
|
||||
256 => 'E_USER_ERROR',
|
||||
512 => 'E_USER_WARNING',
|
||||
1024 => 'E_USER_NOTICE',
|
||||
2048 => 'E_STRICT',
|
||||
4096 => 'E_RECOVERABLE_ERROR',
|
||||
8192 => 'E_DEPRECATED',
|
||||
16384 => 'E_USER_DEPRECATED',
|
||||
];
|
||||
|
||||
/**
|
||||
* Register the default error handling
|
||||
*/
|
||||
@@ -19,6 +41,10 @@ class ErrorHandler
|
||||
if (!defined('DOKU_UNITTEST')) {
|
||||
set_exception_handler([ErrorHandler::class, 'fatalException']);
|
||||
register_shutdown_function([ErrorHandler::class, 'fatalShutdown']);
|
||||
set_error_handler(
|
||||
[ErrorHandler::class, 'errorHandler'],
|
||||
E_WARNING | E_USER_ERROR | E_USER_WARNING | E_RECOVERABLE_ERROR
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,14 +126,52 @@ EOT;
|
||||
*/
|
||||
public static function logException($e)
|
||||
{
|
||||
if ($e instanceof \ErrorException) {
|
||||
$prefix = self::ERRORCODES[$e->getSeverity()];
|
||||
} else {
|
||||
$prefix = get_class($e);
|
||||
}
|
||||
|
||||
return Logger::getInstance()->log(
|
||||
get_class($e) . ': ' . $e->getMessage(),
|
||||
$prefix . ': ' . $e->getMessage(),
|
||||
$e->getTraceAsString(),
|
||||
$e->getFile(),
|
||||
$e->getLine()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Error handler to log non-exception errors
|
||||
*
|
||||
* @param int $errno
|
||||
* @param string $errstr
|
||||
* @param string $errfile
|
||||
* @param int $errline
|
||||
* @return bool
|
||||
*/
|
||||
public static function errorHandler($errno, $errstr, $errfile, $errline)
|
||||
{
|
||||
global $conf;
|
||||
|
||||
// ignore supressed warnings
|
||||
if (!(error_reporting() & $errno)) return false;
|
||||
|
||||
$ex = new \ErrorException(
|
||||
$errstr,
|
||||
0,
|
||||
$errno,
|
||||
$errfile,
|
||||
$errline
|
||||
);
|
||||
self::logException($ex);
|
||||
|
||||
if ($ex->getSeverity() === E_WARNING && $conf['hidewarnings']) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the the stacktrace for plugin files
|
||||
*
|
||||
|
||||
@@ -7,5 +7,4 @@ namespace dokuwiki\Exception;
|
||||
*/
|
||||
class FatalException extends \ErrorException
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@@ -12,11 +12,10 @@ namespace dokuwiki\Extension;
|
||||
*/
|
||||
abstract class ActionPlugin extends Plugin
|
||||
{
|
||||
|
||||
/**
|
||||
* Registers a callback function for a given event
|
||||
*
|
||||
* @param \Doku_Event_Handler $controller
|
||||
* @param EventHandler $controller
|
||||
*/
|
||||
abstract public function register(\Doku_Event_Handler $controller);
|
||||
abstract public function register(EventHandler $controller);
|
||||
}
|
||||
|
||||
@@ -12,7 +12,6 @@ namespace dokuwiki\Extension;
|
||||
*/
|
||||
abstract class AdminPlugin extends Plugin
|
||||
{
|
||||
|
||||
/**
|
||||
* Return the text that is displayed at the main admin menu
|
||||
* (Default localized language string 'menu' is returned, override this function for setting another name)
|
||||
@@ -78,13 +77,14 @@ abstract class AdminPlugin extends Plugin
|
||||
*
|
||||
* @return bool true if the current user may access this admin plugin
|
||||
*/
|
||||
public function isAccessibleByCurrentUser() {
|
||||
public function isAccessibleByCurrentUser()
|
||||
{
|
||||
$data = [];
|
||||
$data['instance'] = $this;
|
||||
$data['hasAccess'] = false;
|
||||
|
||||
$event = new Event('ADMINPLUGIN_ACCESS_CHECK', $data);
|
||||
if($event->advise_before()) {
|
||||
if ($event->advise_before()) {
|
||||
if ($this->forAdminOnly()) {
|
||||
$data['hasAccess'] = auth_isadmin();
|
||||
} else {
|
||||
@@ -116,8 +116,6 @@ abstract class AdminPlugin extends Plugin
|
||||
*/
|
||||
public function getTOC()
|
||||
{
|
||||
return array();
|
||||
return [];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ abstract class AuthPlugin extends Plugin
|
||||
* do. The things a backend can do need to be set to true
|
||||
* in the constructor.
|
||||
*/
|
||||
protected $cando = array(
|
||||
protected $cando = [
|
||||
'addUser' => false, // can Users be created?
|
||||
'delUser' => false, // can Users be deleted?
|
||||
'modLogin' => false, // can login names be changed?
|
||||
@@ -33,7 +33,7 @@ abstract class AuthPlugin extends Plugin
|
||||
'getGroups' => false, // can a list of available groups be retrieved?
|
||||
'external' => false, // does the module do external auth checking?
|
||||
'logout' => true, // can the user logout again? (eg. not possible with HTTP auth)
|
||||
);
|
||||
];
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
@@ -90,7 +90,6 @@ abstract class AuthPlugin extends Plugin
|
||||
return ($this->cando['modPass'] ||
|
||||
$this->cando['modName'] ||
|
||||
$this->cando['modMail']);
|
||||
break;
|
||||
case 'UserMod':
|
||||
// can at least anything be changed?
|
||||
return ($this->cando['modPass'] ||
|
||||
@@ -99,7 +98,6 @@ abstract class AuthPlugin extends Plugin
|
||||
$this->cando['modLogin'] ||
|
||||
$this->cando['modGroups'] ||
|
||||
$this->cando['modMail']);
|
||||
break;
|
||||
default:
|
||||
// print a helping message for developers
|
||||
if (!isset($this->cando[$cap])) {
|
||||
@@ -124,20 +122,20 @@ abstract class AuthPlugin extends Plugin
|
||||
*/
|
||||
public function triggerUserMod($type, $params)
|
||||
{
|
||||
$validTypes = array(
|
||||
$validTypes = [
|
||||
'create' => 'createUser',
|
||||
'modify' => 'modifyUser',
|
||||
'delete' => 'deleteUsers',
|
||||
);
|
||||
'delete' => 'deleteUsers'
|
||||
];
|
||||
if (empty($validTypes[$type])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$result = false;
|
||||
$eventdata = array('type' => $type, 'params' => $params, 'modification_result' => null);
|
||||
$eventdata = ['type' => $type, 'params' => $params, 'modification_result' => null];
|
||||
$evt = new Event('AUTH_USER_CHANGE', $eventdata);
|
||||
if ($evt->advise_before(true)) {
|
||||
$result = call_user_func_array(array($this, $validTypes[$type]), $evt->data['params']);
|
||||
$result = call_user_func_array([$this, $validTypes[$type]], $evt->data['params']);
|
||||
$evt->data['modification_result'] = $result;
|
||||
}
|
||||
$evt->advise_after();
|
||||
@@ -323,7 +321,7 @@ abstract class AuthPlugin extends Plugin
|
||||
* @param array $filter array of field/pattern pairs, empty array for no filter
|
||||
* @return int
|
||||
*/
|
||||
public function getUserCount($filter = array())
|
||||
public function getUserCount($filter = [])
|
||||
{
|
||||
msg("authorisation method does not provide user counts", -1);
|
||||
return 0;
|
||||
@@ -343,7 +341,7 @@ abstract class AuthPlugin extends Plugin
|
||||
public function retrieveUsers($start = 0, $limit = 0, $filter = null)
|
||||
{
|
||||
msg("authorisation method does not support mass retrieval of user data", -1);
|
||||
return array();
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -374,7 +372,7 @@ abstract class AuthPlugin extends Plugin
|
||||
public function retrieveGroups($start = 0, $limit = 0)
|
||||
{
|
||||
msg("authorisation method does not support group list retrieval", -1);
|
||||
return array();
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -2,12 +2,14 @@
|
||||
|
||||
namespace dokuwiki\Extension;
|
||||
|
||||
use splitbrain\phpcli\CLI;
|
||||
|
||||
/**
|
||||
* CLI plugin prototype
|
||||
*
|
||||
* Provides DokuWiki plugin functionality on top of php-cli
|
||||
*/
|
||||
abstract class CLIPlugin extends \splitbrain\phpcli\CLI implements PluginInterface
|
||||
abstract class CLIPlugin extends CLI implements PluginInterface
|
||||
{
|
||||
use PluginTrait;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
// phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
|
||||
|
||||
namespace dokuwiki\Extension;
|
||||
@@ -13,13 +14,13 @@ class Event
|
||||
/** @var string READONLY event name, objects must register against this name to see the event */
|
||||
public $name = '';
|
||||
/** @var mixed|null READWRITE data relevant to the event, no standardised format, refer to event docs */
|
||||
public $data = null;
|
||||
public $data;
|
||||
/**
|
||||
* @var mixed|null READWRITE the results of the event action, only relevant in "_AFTER" advise
|
||||
* event handlers may modify this if they are preventing the default action
|
||||
* to provide the after event handlers with event results
|
||||
*/
|
||||
public $result = null;
|
||||
public $result;
|
||||
/** @var bool READONLY if true, event handlers can prevent the events default action */
|
||||
public $canPreventDefault = true;
|
||||
|
||||
@@ -193,7 +194,7 @@ class Event
|
||||
* by default this is the return value of the default action however
|
||||
* it can be set or modified by event handler hooks
|
||||
*/
|
||||
static public function createAndTrigger($name, &$data, $action = null, $canPreventDefault = true)
|
||||
public static function createAndTrigger($name, &$data, $action = null, $canPreventDefault = true)
|
||||
{
|
||||
$evt = new Event($name, $data);
|
||||
return $evt->trigger($action, $canPreventDefault);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
// phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
|
||||
|
||||
namespace dokuwiki\Extension;
|
||||
@@ -8,11 +9,10 @@ namespace dokuwiki\Extension;
|
||||
*/
|
||||
class EventHandler
|
||||
{
|
||||
|
||||
// public properties: none
|
||||
|
||||
// private properties
|
||||
protected $hooks = array(); // array of events and their registered handlers
|
||||
protected $hooks = []; // array of events and their registered handlers
|
||||
|
||||
/**
|
||||
* event_handler
|
||||
@@ -31,7 +31,7 @@ class EventHandler
|
||||
foreach ($pluginlist as $plugin_name) {
|
||||
$plugin = plugin_load('action', $plugin_name);
|
||||
|
||||
if ($plugin !== null) $plugin->register($this);
|
||||
if ($plugin instanceof PluginInterface) $plugin->register($this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,19 +40,18 @@ class EventHandler
|
||||
*
|
||||
* register a hook for an event
|
||||
*
|
||||
* @param string $event string name used by the event, (incl '_before' or '_after' for triggers)
|
||||
* @param string $advise
|
||||
* @param object $obj object in whose scope method is to be executed,
|
||||
* if NULL, method is assumed to be a globally available function
|
||||
* @param string $method event handler function
|
||||
* @param mixed $param data passed to the event handler
|
||||
* @param int $seq sequence number for ordering hook execution (ascending)
|
||||
* @param string $event name used by the event
|
||||
* @param string $advise BEFORE|AFTER
|
||||
* @param object $obj scope for the method be executed on, NULL for global function or callable
|
||||
* @param string|callable $method event handler function
|
||||
* @param mixed $param data passed to the event handler
|
||||
* @param int $seq sequence number for ordering hook execution (ascending)
|
||||
*/
|
||||
public function register_hook($event, $advise, $obj, $method, $param = null, $seq = 0)
|
||||
{
|
||||
$seq = (int)$seq;
|
||||
$doSort = !isset($this->hooks[$event . '_' . $advise][$seq]);
|
||||
$this->hooks[$event . '_' . $advise][$seq][] = array($obj, $method, $param);
|
||||
$this->hooks[$event . '_' . $advise][$seq][] = [$obj, $method, $param];
|
||||
|
||||
if ($doSort) {
|
||||
ksort($this->hooks[$event . '_' . $advise]);
|
||||
@@ -73,7 +72,7 @@ class EventHandler
|
||||
if (!empty($this->hooks[$evt_name])) {
|
||||
foreach ($this->hooks[$evt_name] as $sequenced_hooks) {
|
||||
foreach ($sequenced_hooks as $hook) {
|
||||
list($obj, $method, $param) = $hook;
|
||||
[$obj, $method, $param] = $hook;
|
||||
|
||||
if ($obj === null) {
|
||||
$method($event, $param);
|
||||
@@ -105,4 +104,16 @@ class EventHandler
|
||||
|
||||
return isset($this->hooks[$name . '_BEFORE']) || isset($this->hooks[$name . '_AFTER']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all hooks and their currently registered handlers
|
||||
*
|
||||
* The handlers are sorted by sequence, then by register time
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getEventHandlers()
|
||||
{
|
||||
return $this->hooks;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ use dokuwiki\ErrorHandler;
|
||||
class PluginController
|
||||
{
|
||||
/** @var array the types of plugins DokuWiki supports */
|
||||
const PLUGIN_TYPES = ['auth', 'admin', 'syntax', 'action', 'renderer', 'helper', 'remote', 'cli'];
|
||||
public const PLUGIN_TYPES = ['auth', 'admin', 'syntax', 'action', 'renderer', 'helper', 'remote', 'cli'];
|
||||
|
||||
protected $listByType = [];
|
||||
/** @var array all installed plugins and their enabled state [plugin=>enabled] */
|
||||
@@ -28,6 +28,7 @@ class PluginController
|
||||
{
|
||||
$this->loadConfig();
|
||||
$this->populateMasterList();
|
||||
$this->initAutoloaders();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -83,7 +84,7 @@ class PluginController
|
||||
//we keep all loaded plugins available in global scope for reuse
|
||||
global $DOKU_PLUGINS;
|
||||
|
||||
list($plugin, /* $component */) = $this->splitName($name);
|
||||
[$plugin, /* component */ ] = $this->splitName($name);
|
||||
|
||||
// check if disabled
|
||||
if (!$disabled && !$this->isEnabled($plugin)) {
|
||||
@@ -96,8 +97,7 @@ class PluginController
|
||||
//plugin already loaded?
|
||||
if (!empty($DOKU_PLUGINS[$type][$name])) {
|
||||
if ($new || !$DOKU_PLUGINS[$type][$name]->isSingleton()) {
|
||||
|
||||
return class_exists($class, true) ? new $class : null;
|
||||
return class_exists($class, true) ? new $class() : null;
|
||||
}
|
||||
|
||||
return $DOKU_PLUGINS[$type][$name];
|
||||
@@ -115,21 +115,19 @@ class PluginController
|
||||
hsc(
|
||||
$inf['base']
|
||||
)
|
||||
), -1
|
||||
),
|
||||
-1
|
||||
);
|
||||
} elseif (preg_match('/^' . DOKU_PLUGIN_NAME_REGEX . '$/', $plugin) !== 1) {
|
||||
msg(
|
||||
sprintf(
|
||||
"Plugin name '%s' is not a valid plugin name, only the characters a-z ".
|
||||
"and 0-9 are allowed. " .
|
||||
'Maybe the plugin has been installed in the wrong directory?', hsc($plugin)
|
||||
), -1
|
||||
);
|
||||
msg(sprintf(
|
||||
'Plugin name \'%s\' is not a valid plugin name, only the characters a-z and 0-9 are allowed. ' .
|
||||
'Maybe the plugin has been installed in the wrong directory?',
|
||||
hsc($plugin)
|
||||
), -1);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
$DOKU_PLUGINS[$type][$name] = new $class;
|
||||
|
||||
$DOKU_PLUGINS[$type][$name] = new $class();
|
||||
} catch (\Throwable $e) {
|
||||
ErrorHandler::showExceptionMsg($e, sprintf('Failed to load plugin %s', $plugin));
|
||||
return null;
|
||||
@@ -204,14 +202,13 @@ class PluginController
|
||||
protected function populateMasterList()
|
||||
{
|
||||
if ($dh = @opendir(DOKU_PLUGIN)) {
|
||||
$all_plugins = array();
|
||||
$all_plugins = [];
|
||||
while (false !== ($plugin = readdir($dh))) {
|
||||
if ($plugin[0] === '.') continue; // skip hidden entries
|
||||
if (is_file(DOKU_PLUGIN . $plugin)) continue; // skip files, we're only interested in directories
|
||||
|
||||
if (array_key_exists($plugin, $this->masterList) && $this->masterList[$plugin] == 0) {
|
||||
$all_plugins[$plugin] = 0;
|
||||
|
||||
} elseif (array_key_exists($plugin, $this->masterList) && $this->masterList[$plugin] == 1) {
|
||||
$all_plugins[$plugin] = 1;
|
||||
} else {
|
||||
@@ -234,7 +231,7 @@ class PluginController
|
||||
*/
|
||||
protected function checkRequire($files)
|
||||
{
|
||||
$plugins = array();
|
||||
$plugins = [];
|
||||
foreach ($files as $file) {
|
||||
if (file_exists($file)) {
|
||||
include_once($file);
|
||||
@@ -297,7 +294,7 @@ class PluginController
|
||||
//gives us the ones we need to check and save
|
||||
$diffed_ones = array_diff_key($local_default, $this->pluginCascade['default']);
|
||||
//The ones which we are sure of (list of 0s not in default)
|
||||
$sure_plugins = array_filter($diffed_ones, array($this, 'negate'));
|
||||
$sure_plugins = array_filter($diffed_ones, [$this, 'negate']);
|
||||
//the ones in need of diff
|
||||
$conflicts = array_diff_key($local_default, $diffed_ones);
|
||||
//The final list
|
||||
@@ -311,20 +308,18 @@ class PluginController
|
||||
protected function loadConfig()
|
||||
{
|
||||
global $config_cascade;
|
||||
foreach (array('default', 'protected') as $type) {
|
||||
foreach (['default', 'protected'] as $type) {
|
||||
if (array_key_exists($type, $config_cascade['plugins'])) {
|
||||
$this->pluginCascade[$type] = $this->checkRequire($config_cascade['plugins'][$type]);
|
||||
}
|
||||
}
|
||||
$local = $config_cascade['plugins']['local'];
|
||||
$this->lastLocalConfigFile = array_pop($local);
|
||||
$this->pluginCascade['local'] = $this->checkRequire(array($this->lastLocalConfigFile));
|
||||
if (is_array($local)) {
|
||||
$this->pluginCascade['default'] = array_merge(
|
||||
$this->pluginCascade['default'],
|
||||
$this->checkRequire($local)
|
||||
);
|
||||
}
|
||||
$this->pluginCascade['local'] = $this->checkRequire([$this->lastLocalConfigFile]);
|
||||
$this->pluginCascade['default'] = array_merge(
|
||||
$this->pluginCascade['default'],
|
||||
$this->checkRequire($local)
|
||||
);
|
||||
$this->masterList = array_merge(
|
||||
$this->pluginCascade['default'],
|
||||
$this->pluginCascade['local'],
|
||||
@@ -344,11 +339,10 @@ class PluginController
|
||||
{
|
||||
$master_list = $enabled
|
||||
? array_keys(array_filter($this->masterList))
|
||||
: array_keys(array_filter($this->masterList, array($this, 'negate')));
|
||||
$plugins = array();
|
||||
: array_keys(array_filter($this->masterList, [$this, 'negate']));
|
||||
$plugins = [];
|
||||
|
||||
foreach ($master_list as $plugin) {
|
||||
|
||||
if (file_exists(DOKU_PLUGIN . "$plugin/$type.php")) {
|
||||
$plugins[] = $plugin;
|
||||
continue;
|
||||
@@ -358,7 +352,10 @@ class PluginController
|
||||
if (is_dir($typedir)) {
|
||||
if ($dp = opendir($typedir)) {
|
||||
while (false !== ($component = readdir($dp))) {
|
||||
if (strpos($component, '.') === 0 || strtolower(substr($component, -4)) !== '.php') continue;
|
||||
if (
|
||||
str_starts_with($component, '.') ||
|
||||
!str_ends_with(strtolower($component), '.php')
|
||||
) continue;
|
||||
if (is_file($typedir . $component)) {
|
||||
$plugins[] = $plugin . '_' . substr($component, 0, -4);
|
||||
}
|
||||
@@ -366,7 +363,6 @@ class PluginController
|
||||
closedir($dp);
|
||||
}
|
||||
}
|
||||
|
||||
}//foreach
|
||||
|
||||
return $plugins;
|
||||
@@ -383,10 +379,10 @@ class PluginController
|
||||
protected function splitName($name)
|
||||
{
|
||||
if (!isset($this->masterList[$name])) {
|
||||
return explode('_', $name, 2);
|
||||
return sexplode('_', $name, 2, '');
|
||||
}
|
||||
|
||||
return array($name, '');
|
||||
return [$name, ''];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -399,4 +395,21 @@ class PluginController
|
||||
{
|
||||
return !(bool)$input;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize vendor autoloaders for all plugins that have them
|
||||
*/
|
||||
protected function initAutoloaders()
|
||||
{
|
||||
$plugins = $this->getList();
|
||||
foreach ($plugins as $plugin) {
|
||||
if (file_exists(DOKU_PLUGIN . $plugin . '/vendor/autoload.php')) {
|
||||
try {
|
||||
require_once(DOKU_PLUGIN . $plugin . '/vendor/autoload.php');
|
||||
} catch (\Throwable $e) {
|
||||
ErrorHandler::showExceptionMsg($e, sprintf('Failed to init plugin %s autoloader', $plugin));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -157,6 +157,3 @@ interface PluginInterface
|
||||
*/
|
||||
public function isSingleton();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -2,35 +2,59 @@
|
||||
|
||||
namespace dokuwiki\Extension;
|
||||
|
||||
use dokuwiki\Logger;
|
||||
|
||||
/**
|
||||
* Provides standard DokuWiki plugin behaviour
|
||||
*/
|
||||
trait PluginTrait
|
||||
{
|
||||
|
||||
protected $localised = false; // set to true by setupLocale() after loading language dependent strings
|
||||
protected $lang = array(); // array to hold language dependent strings, best accessed via ->getLang()
|
||||
protected $lang = []; // array to hold language dependent strings, best accessed via ->getLang()
|
||||
protected $configloaded = false; // set to true by loadConfig() after loading plugin configuration variables
|
||||
protected $conf = array(); // array to hold plugin settings, best accessed via ->getConf()
|
||||
protected $conf = []; // array to hold plugin settings, best accessed via ->getConf()
|
||||
|
||||
/**
|
||||
* @see PluginInterface::getInfo()
|
||||
*/
|
||||
public function getInfo()
|
||||
{
|
||||
$parts = explode('_', get_class($this));
|
||||
$info = DOKU_PLUGIN . '/' . $parts[2] . '/plugin.info.txt';
|
||||
if (file_exists($info)) return confToHash($info);
|
||||
$class = get_class($this);
|
||||
$parts = sexplode('_', $class, 3);
|
||||
$ext = $parts[2];
|
||||
|
||||
msg(
|
||||
'getInfo() not implemented in ' . get_class($this) . ' and ' . $info . ' not found.<br />' .
|
||||
'Verify you\'re running the latest version of the plugin. If the problem persists, send a ' .
|
||||
'bug report to the author of the ' . $parts[2] . ' plugin.', -1
|
||||
);
|
||||
return array(
|
||||
if (empty($ext)) {
|
||||
throw new \RuntimeException('Class does not follow the plugin naming convention');
|
||||
}
|
||||
|
||||
// class like action_plugin_myplugin_ajax belongs to plugin 'myplugin'
|
||||
$ext = strtok($ext, '_');
|
||||
|
||||
$base = [
|
||||
'base' => $ext,
|
||||
'author' => 'Unknown',
|
||||
'email' => 'unknown@example.com',
|
||||
'date' => '0000-00-00',
|
||||
'name' => $parts[2] . ' plugin',
|
||||
);
|
||||
'name' => $ext . ' plugin',
|
||||
'desc' => 'Unknown purpose - bad plugin.info.txt',
|
||||
'url' => 'https://www.dokuwiki.org/plugins/' . $ext,
|
||||
];
|
||||
|
||||
$file = DOKU_PLUGIN . '/' . $ext . '/plugin.info.txt';
|
||||
if (file_exists($file)) {
|
||||
$raw = confToHash($file);
|
||||
|
||||
// check if all required fields are present
|
||||
$msg = 'Extension %s does not provide a valid %s in %s';
|
||||
foreach (array_keys($base) as $line) {
|
||||
if (empty($raw[$line])) Logger::error(sprintf($msg, $ext, $line, $file));
|
||||
}
|
||||
|
||||
return array_merge($base, $raw);
|
||||
}
|
||||
|
||||
Logger::error(sprintf('Extension %s does not provide a plugin.info.txt in %s', $ext, $file));
|
||||
return $base;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -58,7 +82,7 @@ trait PluginTrait
|
||||
*/
|
||||
public function getPluginType()
|
||||
{
|
||||
list($t) = explode('_', get_class($this), 2);
|
||||
[$t] = explode('_', get_class($this), 2);
|
||||
return $t;
|
||||
}
|
||||
|
||||
@@ -67,7 +91,7 @@ trait PluginTrait
|
||||
*/
|
||||
public function getPluginName()
|
||||
{
|
||||
list(/* $t */, /* $p */, $n) = explode('_', get_class($this), 4);
|
||||
[/* t */, /* p */, $n] = sexplode('_', get_class($this), 4, '');
|
||||
return $n;
|
||||
}
|
||||
|
||||
@@ -76,8 +100,8 @@ trait PluginTrait
|
||||
*/
|
||||
public function getPluginComponent()
|
||||
{
|
||||
list(/* $t */, /* $p */, /* $n */, $c) = explode('_', get_class($this), 4);
|
||||
return (isset($c) ? $c : '');
|
||||
[/* t */, /* p */, /* n */, $c] = sexplode('_', get_class($this), 4, '');
|
||||
return $c;
|
||||
}
|
||||
|
||||
// endregion
|
||||
@@ -90,7 +114,7 @@ trait PluginTrait
|
||||
{
|
||||
if (!$this->localised) $this->setupLocale();
|
||||
|
||||
return (isset($this->lang[$id]) ? $this->lang[$id] : '');
|
||||
return ($this->lang[$id] ?? '');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -129,7 +153,7 @@ trait PluginTrait
|
||||
global $conf, $config_cascade; // definitely don't invoke "global $lang"
|
||||
$path = DOKU_PLUGIN . $this->getPluginName() . '/lang/';
|
||||
|
||||
$lang = array();
|
||||
$lang = [];
|
||||
|
||||
// don't include once, in case several plugin components require the same language file
|
||||
@include($path . 'en/lang.php');
|
||||
@@ -201,7 +225,7 @@ trait PluginTrait
|
||||
{
|
||||
|
||||
$path = DOKU_PLUGIN . $this->getPluginName() . '/conf/';
|
||||
$conf = array();
|
||||
$conf = [];
|
||||
|
||||
if (file_exists($path . 'default.php')) {
|
||||
include($path . 'default.php');
|
||||
@@ -221,7 +245,7 @@ trait PluginTrait
|
||||
if (!$email) return $name;
|
||||
$email = obfuscate($email);
|
||||
if (!$name) $name = $email;
|
||||
$class = "class='" . ($class ? $class : 'mail') . "'";
|
||||
$class = "class='" . ($class ?: 'mail') . "'";
|
||||
return "<a href='mailto:$email' $class title='$email' $more>$name</a>";
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
namespace dokuwiki\Extension;
|
||||
|
||||
use dokuwiki\Remote\Api;
|
||||
use dokuwiki\Remote\ApiCall;
|
||||
use ReflectionException;
|
||||
use ReflectionMethod;
|
||||
|
||||
@@ -13,8 +14,7 @@ use ReflectionMethod;
|
||||
*/
|
||||
abstract class RemotePlugin extends Plugin
|
||||
{
|
||||
|
||||
private $api;
|
||||
private Api $api;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
@@ -30,12 +30,12 @@ abstract class RemotePlugin extends Plugin
|
||||
* By default it exports all public methods of a remote plugin. Methods beginning
|
||||
* with an underscore are skipped.
|
||||
*
|
||||
* @return array Information about all provided methods. {@see dokuwiki\Remote\RemoteAPI}.
|
||||
* @return ApiCall[] Information about all provided methods. ('methodname' => ApiCall)
|
||||
* @throws ReflectionException
|
||||
*/
|
||||
public function _getMethods()
|
||||
public function getMethods()
|
||||
{
|
||||
$result = array();
|
||||
$result = [];
|
||||
|
||||
$reflection = new \ReflectionClass($this);
|
||||
foreach ($reflection->getMethods(ReflectionMethod::IS_PUBLIC) as $method) {
|
||||
@@ -45,72 +45,30 @@ abstract class RemotePlugin extends Plugin
|
||||
continue;
|
||||
}
|
||||
$method_name = $method->name;
|
||||
if (strpos($method_name, '_') === 0) {
|
||||
if ($method_name[0] === '_') {
|
||||
continue;
|
||||
}
|
||||
|
||||
// strip asterisks
|
||||
$doc = $method->getDocComment();
|
||||
$doc = preg_replace(
|
||||
array('/^[ \t]*\/\*+[ \t]*/m', '/[ \t]*\*+[ \t]*/m', '/\*+\/\s*$/m', '/\s*\/\s*$/m'),
|
||||
array('', '', '', ''),
|
||||
$doc
|
||||
);
|
||||
|
||||
// prepare data
|
||||
$data = array();
|
||||
$data['name'] = $method_name;
|
||||
$data['public'] = 0;
|
||||
$data['doc'] = $doc;
|
||||
$data['args'] = array();
|
||||
|
||||
// get parameter type from doc block type hint
|
||||
foreach ($method->getParameters() as $parameter) {
|
||||
$name = $parameter->name;
|
||||
$type = 'string'; // we default to string
|
||||
if (preg_match('/^@param[ \t]+([\w|\[\]]+)[ \t]\$' . $name . '/m', $doc, $m)) {
|
||||
$type = $this->cleanTypeHint($m[1]);
|
||||
}
|
||||
$data['args'][] = $type;
|
||||
}
|
||||
|
||||
// get return type from doc block type hint
|
||||
if (preg_match('/^@return[ \t]+([\w|\[\]]+)/m', $doc, $m)) {
|
||||
$data['return'] = $this->cleanTypeHint($m[1]);
|
||||
} else {
|
||||
$data['return'] = 'string';
|
||||
if ($method_name === 'getMethods') {
|
||||
continue; // skip self, if overridden
|
||||
}
|
||||
|
||||
// add to result
|
||||
$result[$method_name] = $data;
|
||||
$result[$method_name] = new ApiCall([$this, $method_name], 'plugins');
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Matches the given type hint against the valid options for the remote API
|
||||
*
|
||||
* @param string $hint
|
||||
* @return string
|
||||
* @deprecated 2023-11-30
|
||||
*/
|
||||
protected function cleanTypeHint($hint)
|
||||
public function _getMethods()
|
||||
{
|
||||
$types = explode('|', $hint);
|
||||
foreach ($types as $t) {
|
||||
if (substr($t, -2) === '[]') {
|
||||
return 'array';
|
||||
}
|
||||
if ($t === 'boolean') {
|
||||
return 'bool';
|
||||
}
|
||||
if (in_array($t, array('array', 'string', 'int', 'double', 'bool', 'null', 'date', 'file'))) {
|
||||
return $t;
|
||||
}
|
||||
}
|
||||
return 'string';
|
||||
dbg_deprecated('getMethods()');
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @return Api
|
||||
*/
|
||||
@@ -118,5 +76,4 @@ abstract class RemotePlugin extends Plugin
|
||||
{
|
||||
return $this->api;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace dokuwiki\Extension;
|
||||
|
||||
use dokuwiki\Parsing\ParserMode\Plugin;
|
||||
use Doku_Handler;
|
||||
use Doku_Renderer;
|
||||
|
||||
@@ -14,10 +15,8 @@ use Doku_Renderer;
|
||||
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
|
||||
* @author Andreas Gohr <andi@splitbrain.org>
|
||||
*/
|
||||
abstract class SyntaxPlugin extends \dokuwiki\Parsing\ParserMode\Plugin
|
||||
abstract class SyntaxPlugin extends Plugin
|
||||
{
|
||||
use PluginTrait;
|
||||
|
||||
protected $allowedModesSetup = false;
|
||||
|
||||
/**
|
||||
@@ -40,7 +39,7 @@ abstract class SyntaxPlugin extends \dokuwiki\Parsing\ParserMode\Plugin
|
||||
*/
|
||||
public function getAllowedTypes()
|
||||
{
|
||||
return array();
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -120,7 +119,7 @@ abstract class SyntaxPlugin extends \dokuwiki\Parsing\ParserMode\Plugin
|
||||
$this->allowedModes = array_merge($this->allowedModes, $PARSER_MODES[$mt]);
|
||||
}
|
||||
|
||||
$idx = array_search(substr(get_class($this), 7), (array)$this->allowedModes);
|
||||
$idx = array_search(substr(get_class($this), 7), (array)$this->allowedModes, true);
|
||||
if ($idx !== false) {
|
||||
unset($this->allowedModes[$idx]);
|
||||
}
|
||||
|
||||
232
dokuwiki/inc/Feed/FeedCreator.php
Normal file
232
dokuwiki/inc/Feed/FeedCreator.php
Normal file
@@ -0,0 +1,232 @@
|
||||
<?php
|
||||
|
||||
namespace dokuwiki\Feed;
|
||||
|
||||
use dokuwiki\Extension\Event;
|
||||
|
||||
class FeedCreator
|
||||
{
|
||||
/** @var \UniversalFeedCreator */
|
||||
protected $feed;
|
||||
|
||||
/** @var FeedCreatorOptions */
|
||||
protected $options;
|
||||
|
||||
/**
|
||||
* @param FeedCreatorOptions $options
|
||||
*/
|
||||
public function __construct(FeedCreatorOptions $options)
|
||||
{
|
||||
$this->options = $options;
|
||||
|
||||
$this->feed = new \UniversalFeedCreator();
|
||||
$this->feed->title = $this->options->get('title');
|
||||
$this->feed->description = $this->options->get('subtitle');
|
||||
$this->feed->link = DOKU_URL;
|
||||
$this->feed->syndicationURL = DOKU_URL . 'feed.php';
|
||||
$this->feed->cssStyleSheet = DOKU_URL . 'lib/exe/css.php?s=feed';
|
||||
|
||||
$this->initLogo();
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the feed
|
||||
*
|
||||
* @return string The raw XML for the feed
|
||||
*/
|
||||
public function build()
|
||||
{
|
||||
switch ($this->options->get('feed_mode')) {
|
||||
case 'list':
|
||||
$items = $this->fetchItemsFromNamespace();
|
||||
break;
|
||||
case 'search':
|
||||
$items = $this->fetchItemsFromSearch();
|
||||
break;
|
||||
case 'recent':
|
||||
$items = $this->fetchItemsFromRecentChanges();
|
||||
break;
|
||||
default:
|
||||
$items = $this->fetchItemsFromPlugin();
|
||||
}
|
||||
|
||||
$eventData = [
|
||||
'rss' => $this->feed,
|
||||
'data' => &$items,
|
||||
'opt' => &$this->options->options,
|
||||
];
|
||||
$event = new Event('FEED_DATA_PROCESS', $eventData);
|
||||
if ($event->advise_before(false)) {
|
||||
foreach ($items as $item) {
|
||||
$this->createAndAddItem($item);
|
||||
}
|
||||
}
|
||||
$event->advise_after();
|
||||
|
||||
return $this->feed->createFeed($this->options->getType());
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the raw data, create feed item and add it to the feed
|
||||
*
|
||||
* @param array|string $data raw item data
|
||||
* @return \FeedItem
|
||||
* @triggers FEED_ITEM_ADD
|
||||
*/
|
||||
protected function createAndAddItem($data)
|
||||
{
|
||||
if (is_string($data)) {
|
||||
$data = ['id' => $data];
|
||||
}
|
||||
|
||||
if (($data['mode'] ?? '') == 'media' || isset($data['media'])) {
|
||||
$data['id'] = $data['media'] ?? $data['id'];
|
||||
$proc = new FeedMediaProcessor($data);
|
||||
} else {
|
||||
$proc = new FeedPageProcessor($data);
|
||||
}
|
||||
|
||||
$item = new \FeedItem();
|
||||
$item->title = $proc->getTitle();
|
||||
if ($this->options->get('show_summary') && $proc->getSummary()) {
|
||||
$item->title .= ' - ' . $proc->getSummary();
|
||||
}
|
||||
$item->date = $proc->getRev();
|
||||
[$item->authorEmail, $item->author] = $proc->getAuthor();
|
||||
$item->link = $proc->getURL($this->options->get('link_to'));
|
||||
$item->description = $proc->getBody($this->options->get('item_content'));
|
||||
|
||||
$evdata = [
|
||||
'item' => $item,
|
||||
'opt' => &$this->options->options,
|
||||
'ditem' => &$data,
|
||||
'rss' => $this->feed,
|
||||
];
|
||||
|
||||
$evt = new Event('FEED_ITEM_ADD', $evdata);
|
||||
if ($evt->advise_before()) {
|
||||
$this->feed->addItem($item);
|
||||
}
|
||||
$evt->advise_after();
|
||||
|
||||
return $item;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read all pages from a namespace
|
||||
*
|
||||
* @todo this currently does not honor the rss_media setting and only ever lists pages
|
||||
* @return array
|
||||
*/
|
||||
protected function fetchItemsFromNamespace()
|
||||
{
|
||||
global $conf;
|
||||
|
||||
$ns = ':' . cleanID($this->options->get('namespace'));
|
||||
$ns = utf8_encodeFN(str_replace(':', '/', $ns));
|
||||
|
||||
$data = [];
|
||||
$search_opts = [
|
||||
'depth' => 1,
|
||||
'pagesonly' => true,
|
||||
'listfiles' => true
|
||||
];
|
||||
search(
|
||||
$data,
|
||||
$conf['datadir'],
|
||||
'search_universal',
|
||||
$search_opts,
|
||||
$ns,
|
||||
$lvl = 1,
|
||||
$this->options->get('sort')
|
||||
);
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the result of a full text search to the feed object
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function fetchItemsFromSearch()
|
||||
{
|
||||
if (!actionOK('search')) throw new \RuntimeException('search is disabled');
|
||||
if (!$this->options->get('search_query')) return [];
|
||||
|
||||
$data = ft_pageSearch($this->options->get('search_query'), $poswords);
|
||||
return array_keys($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add recent changed pages to the feed object
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function fetchItemsFromRecentChanges()
|
||||
{
|
||||
global $conf;
|
||||
$flags = 0;
|
||||
if (!$this->options->get('show_deleted')) $flags += RECENTS_SKIP_DELETED;
|
||||
if (!$this->options->get('show_minor')) $flags += RECENTS_SKIP_MINORS;
|
||||
if ($this->options->get('only_new')) $flags += RECENTS_ONLY_CREATION;
|
||||
if ($this->options->get('content_type') == 'media' && $conf['mediarevisions']) {
|
||||
$flags += RECENTS_MEDIA_CHANGES;
|
||||
}
|
||||
if ($this->options->get('content_type') == 'both' && $conf['mediarevisions']) {
|
||||
$flags += RECENTS_MEDIA_PAGES_MIXED;
|
||||
}
|
||||
|
||||
return getRecents(0, $this->options->get('items'), $this->options->get('namespace'), $flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add items from a plugin to the feed object
|
||||
*
|
||||
* @triggers FEED_MODE_UNKNOWN
|
||||
* @return array
|
||||
*/
|
||||
protected function fetchItemsFromPlugin()
|
||||
{
|
||||
$eventData = [
|
||||
'opt' => $this->options->options,
|
||||
'data' => [],
|
||||
];
|
||||
$event = new Event('FEED_MODE_UNKNOWN', $eventData);
|
||||
if ($event->advise_before(true)) {
|
||||
throw new \RuntimeException('unknown feed mode');
|
||||
}
|
||||
$event->advise_after();
|
||||
|
||||
return $eventData['data'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a logo to the feed
|
||||
*
|
||||
* Looks at different possible candidates for a logo and adds the first one
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function initLogo()
|
||||
{
|
||||
global $conf;
|
||||
|
||||
$this->feed->image = new \FeedImage();
|
||||
$this->feed->image->title = $conf['title'];
|
||||
$this->feed->image->link = DOKU_URL;
|
||||
$this->feed->image->url = tpl_getMediaFile([
|
||||
':wiki:logo.svg',
|
||||
':logo.svg',
|
||||
':wiki:logo.png',
|
||||
':logo.png',
|
||||
':wiki:logo.jpg',
|
||||
':logo.jpg',
|
||||
':wiki:favicon.ico',
|
||||
':favicon.ico',
|
||||
':wiki:dokuwiki.svg',
|
||||
':wiki:dokuwiki-128.png',
|
||||
'images/favicon.ico'
|
||||
], true);
|
||||
}
|
||||
}
|
||||
161
dokuwiki/inc/Feed/FeedCreatorOptions.php
Normal file
161
dokuwiki/inc/Feed/FeedCreatorOptions.php
Normal file
@@ -0,0 +1,161 @@
|
||||
<?php
|
||||
|
||||
namespace dokuwiki\Feed;
|
||||
|
||||
use dokuwiki\Extension\Event;
|
||||
|
||||
/**
|
||||
* Hold the options for feed generation
|
||||
*/
|
||||
class FeedCreatorOptions
|
||||
{
|
||||
/** @var array[] supported feed types */
|
||||
protected $types = [
|
||||
'rss' => [
|
||||
'name' => 'RSS0.91',
|
||||
'mime' => 'text/xml; charset=utf-8',
|
||||
],
|
||||
'rss1' => [
|
||||
'name' => 'RSS1.0',
|
||||
'mime' => 'text/xml; charset=utf-8',
|
||||
],
|
||||
'rss2' => [
|
||||
'name' => 'RSS2.0',
|
||||
'mime' => 'text/xml; charset=utf-8',
|
||||
],
|
||||
'atom' => [
|
||||
'name' => 'ATOM0.3',
|
||||
'mime' => 'application/xml; charset=utf-8',
|
||||
],
|
||||
'atom1' => [
|
||||
'name' => 'ATOM1.0',
|
||||
'mime' => 'application/atom+xml; charset=utf-8',
|
||||
],
|
||||
];
|
||||
|
||||
/** @var array[] the set options */
|
||||
public $options = [
|
||||
'type' => 'rss',
|
||||
'feed_mode' => 'recent',
|
||||
'link_to' => 'page',
|
||||
'item_content' => 'diff',
|
||||
'namespace' => '',
|
||||
'items' => 15,
|
||||
'show_minor' => false,
|
||||
'show_deleted' => false,
|
||||
'show_summary' => false,
|
||||
'only_new' => false,
|
||||
'sort' => 'natural',
|
||||
'search_query' => '',
|
||||
'content_type' => 'pages',
|
||||
'guardmail' => 'none',
|
||||
'title' => '',
|
||||
];
|
||||
|
||||
/**
|
||||
* Initialize the options from the request, falling back to config defaults
|
||||
*
|
||||
* @triggers FEED_OPTS_POSTPROCESS
|
||||
* @param array $options additional options to set (for testing)
|
||||
*/
|
||||
public function __construct($options = [])
|
||||
{
|
||||
global $conf;
|
||||
global $INPUT;
|
||||
|
||||
$this->options['type'] = $INPUT->valid(
|
||||
'type',
|
||||
array_keys($this->types),
|
||||
$conf['rss_type']
|
||||
);
|
||||
// we only support 'list', 'search', 'recent' but accept anything so plugins can take over
|
||||
$this->options['feed_mode'] = $INPUT->str('mode', 'recent');
|
||||
$this->options['link_to'] = $INPUT->valid(
|
||||
'linkto',
|
||||
['diff', 'page', 'rev', 'current'],
|
||||
$conf['rss_linkto']
|
||||
);
|
||||
$this->options['item_content'] = $INPUT->valid(
|
||||
'content',
|
||||
['abstract', 'diff', 'htmldiff', 'html'],
|
||||
$conf['rss_content']
|
||||
);
|
||||
$this->options['namespace'] = $INPUT->filter('cleanID')->str('ns');
|
||||
$this->options['items'] = max(0, $INPUT->int('num', $conf['recent']));
|
||||
$this->options['show_minor'] = $INPUT->bool('minor');
|
||||
$this->options['show_deleted'] = $conf['rss_show_deleted'];
|
||||
$this->options['show_summary'] = $conf['rss_show_summary'];
|
||||
$this->options['only_new'] = $INPUT->bool('onlynewpages');
|
||||
$this->options['sort'] = $INPUT->valid(
|
||||
'sort',
|
||||
['natural', 'date'],
|
||||
'natural'
|
||||
);
|
||||
$this->options['search_query'] = $INPUT->str('q');
|
||||
$this->options['content_type'] = $INPUT->valid(
|
||||
'view',
|
||||
['pages', 'media', 'both'],
|
||||
$conf['rss_media']
|
||||
);
|
||||
$this->options['guardmail'] = $conf['mailguard'];
|
||||
$this->options['title'] = $conf['title'];
|
||||
if ($this->options['namespace']) {
|
||||
$this->options['title'] .= ' - ' . $this->options['namespace'];
|
||||
}
|
||||
$this->options['subtitle'] = $conf['tagline'];
|
||||
|
||||
$this->options = array_merge($this->options, $options);
|
||||
|
||||
// initialization finished, let plugins know
|
||||
$eventData = [
|
||||
'opt' => &$this->options,
|
||||
];
|
||||
Event::createAndTrigger('FEED_OPTS_POSTPROCESS', $eventData);
|
||||
}
|
||||
|
||||
/**
|
||||
* The cache key to use for a feed with these options
|
||||
*
|
||||
* Does not contain user or host specific information yet
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getCacheKey()
|
||||
{
|
||||
return implode('', array_values($this->options));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a feed option by name
|
||||
*
|
||||
* @param string $option The name of the option
|
||||
* @param mixed $default default value if option is not set (should usually not happen)
|
||||
* @return mixed
|
||||
*/
|
||||
public function get($option, $default = null)
|
||||
{
|
||||
return $this->options[$option] ?? $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the feed type for UniversalFeedCreator
|
||||
*
|
||||
* This returns the apropriate type for UniversalFeedCreator
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getType()
|
||||
{
|
||||
return $this->types[$this->options['type']]['name'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the feed mime type
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getMimeType()
|
||||
{
|
||||
return $this->types[$this->options['type']]['mime'];
|
||||
}
|
||||
}
|
||||
172
dokuwiki/inc/Feed/FeedItemProcessor.php
Normal file
172
dokuwiki/inc/Feed/FeedItemProcessor.php
Normal file
@@ -0,0 +1,172 @@
|
||||
<?php
|
||||
|
||||
namespace dokuwiki\Feed;
|
||||
|
||||
use dokuwiki\Extension\AuthPlugin;
|
||||
use RuntimeException;
|
||||
|
||||
/**
|
||||
* Accept more or less arbitrary data to represent data to later construct a feed item from.
|
||||
* Provide lazy loading accessors to all the data we need for feed generation.
|
||||
*/
|
||||
abstract class FeedItemProcessor
|
||||
{
|
||||
/** @var string This page's ID */
|
||||
protected $id;
|
||||
|
||||
/** @var array bag of holding */
|
||||
protected $data;
|
||||
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param array $data Needs to have at least an 'id' key
|
||||
*/
|
||||
public function __construct($data)
|
||||
{
|
||||
if (!isset($data['id'])) throw new RuntimeException('Missing ID');
|
||||
$this->id = cleanID($data['id']);
|
||||
$this->data = $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the page ID
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getId()
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the revision timestamp of this page
|
||||
*
|
||||
* If the input gave us a revision, date or lastmodified already, we trust that it is correct.
|
||||
*
|
||||
* Note: we only handle most current revisions in feeds, so the revision is usually just the
|
||||
* lastmodifed timestamp of the page file. However, if the item does not exist, we need to
|
||||
* determine the revision from the changelog.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getRev()
|
||||
{
|
||||
if ($this->data['rev'] ?? 0) return $this->data['rev'];
|
||||
|
||||
if (isset($this->data['date'])) {
|
||||
$this->data['rev'] = (int)$this->data['date'];
|
||||
}
|
||||
|
||||
if (isset($this->data['lastmodified'])) {
|
||||
$this->data['rev'] = (int)$this->data['lastmodified'];
|
||||
}
|
||||
|
||||
return $this->data['rev'] ?? 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct the URL for the feed item based on the link_to option
|
||||
*
|
||||
* @param string $linkto The link_to option
|
||||
* @return string URL
|
||||
*/
|
||||
abstract public function getURL($linkto);
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getTitle()
|
||||
{
|
||||
return $this->data['title'] ?? noNS($this->getId());
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct the body of the feed item based on the item_content option
|
||||
*
|
||||
* @param string $content The item_content option
|
||||
* @return string
|
||||
*/
|
||||
abstract public function getBody($content);
|
||||
|
||||
/**
|
||||
* Get the change summary for this item if any
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getSummary()
|
||||
{
|
||||
return (string)($this->data['sum'] ?? '');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the author info for this item
|
||||
*
|
||||
* @return string[] [email, author]
|
||||
*/
|
||||
public function getAuthor()
|
||||
{
|
||||
global $conf;
|
||||
global $auth;
|
||||
|
||||
$user = $this->data['user'] ?? '';
|
||||
$author = 'Anonymous';
|
||||
$email = 'anonymous@undisclosed.example.com';
|
||||
|
||||
if (!$user) return [$email, $author];
|
||||
$author = $user;
|
||||
$email = $user . '@undisclosed.example.com';
|
||||
|
||||
if ($conf['useacl'] && $auth instanceof AuthPlugin) {
|
||||
$userInfo = $auth->getUserData($user);
|
||||
if ($userInfo) {
|
||||
switch ($conf['showuseras']) {
|
||||
case 'username':
|
||||
case 'username_link':
|
||||
$author = $userInfo['name'];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return [$email, $author];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the categories for this item
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
abstract public function getCategory();
|
||||
|
||||
|
||||
/**
|
||||
* Clean HTML for the use in feeds
|
||||
*
|
||||
* @param string $html
|
||||
* @return string
|
||||
*/
|
||||
protected function cleanHTML($html)
|
||||
{
|
||||
global $conf;
|
||||
|
||||
// no TOC in feeds
|
||||
$html = preg_replace('/(<!-- TOC START -->).*(<!-- TOC END -->)/s', '', $html);
|
||||
|
||||
// add alignment for images
|
||||
$html = preg_replace('/(<img .*?class="medialeft")/s', '\\1 align="left"', $html);
|
||||
$html = preg_replace('/(<img .*?class="mediaright")/s', '\\1 align="right"', $html);
|
||||
|
||||
// make URLs work when canonical is not set, regexp instead of rerendering!
|
||||
if (!$conf['canonical']) {
|
||||
$base = preg_quote(DOKU_REL, '/');
|
||||
$html = preg_replace(
|
||||
'/(<a href|<img src)="(' . $base . ')/s',
|
||||
'$1="' . DOKU_URL,
|
||||
$html
|
||||
);
|
||||
}
|
||||
|
||||
return $html;
|
||||
}
|
||||
}
|
||||
189
dokuwiki/inc/Feed/FeedMediaProcessor.php
Normal file
189
dokuwiki/inc/Feed/FeedMediaProcessor.php
Normal file
@@ -0,0 +1,189 @@
|
||||
<?php
|
||||
|
||||
namespace dokuwiki\Feed;
|
||||
|
||||
use dokuwiki\ChangeLog\MediaChangeLog;
|
||||
use dokuwiki\File\MediaFile;
|
||||
use dokuwiki\Ui\Media\Display;
|
||||
|
||||
class FeedMediaProcessor extends FeedItemProcessor
|
||||
{
|
||||
/** @inheritdoc */
|
||||
public function getURL($linkto)
|
||||
{
|
||||
switch ($linkto) {
|
||||
case 'page':
|
||||
$opt = [
|
||||
'image' => $this->getId(),
|
||||
'ns' => getNS($this->getId()),
|
||||
'rev' => $this->getRev()
|
||||
];
|
||||
break;
|
||||
case 'rev':
|
||||
$opt = [
|
||||
'image' => $this->getId(),
|
||||
'ns' => getNS($this->getId()),
|
||||
'rev' => $this->getRev(),
|
||||
'tab_details' => 'history'
|
||||
];
|
||||
break;
|
||||
case 'current':
|
||||
$opt = [
|
||||
'image' => $this->getId(),
|
||||
'ns' => getNS($this->getId())
|
||||
];
|
||||
break;
|
||||
case 'diff':
|
||||
default:
|
||||
$opt = [
|
||||
'image' => $this->getId(),
|
||||
'ns' => getNS($this->getId()),
|
||||
'rev' => $this->getRev(),
|
||||
'tab_details' => 'history',
|
||||
'media_do' => 'diff'
|
||||
];
|
||||
}
|
||||
|
||||
return media_managerURL($opt, '&', true);
|
||||
}
|
||||
|
||||
public function getBody($content)
|
||||
{
|
||||
switch ($content) {
|
||||
case 'diff':
|
||||
case 'htmldiff':
|
||||
$prev = $this->getPrev();
|
||||
|
||||
if ($prev) {
|
||||
if ($this->isExisting()) {
|
||||
$src1 = new MediaFile($this->getId(), $prev);
|
||||
$src2 = new MediaFile($this->getId());
|
||||
} else {
|
||||
$src1 = new MediaFile($this->getId(), $prev);
|
||||
$src2 = null;
|
||||
}
|
||||
} else {
|
||||
$src1 = null;
|
||||
$src2 = new MediaFile($this->getId());
|
||||
}
|
||||
return $this->createDiffTable($src1, $src2);
|
||||
|
||||
case 'abstract':
|
||||
case 'html':
|
||||
default:
|
||||
$src = new Display(new MediaFile($this->getId()));
|
||||
return $this->cleanHTML($src->getPreviewHtml(500, 500));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
* @todo read exif keywords
|
||||
*/
|
||||
public function getCategory()
|
||||
{
|
||||
return (array)getNS($this->getId());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the revision timestamp of this page
|
||||
*
|
||||
* Note: we only handle most current revisions in feeds, so the revision is usually just the
|
||||
* lastmodifed timestamp of the page file. However, if the page does not exist, we need to
|
||||
* determine the revision from the changelog.
|
||||
* @return int
|
||||
*/
|
||||
public function getRev()
|
||||
{
|
||||
$rev = parent::getRev();
|
||||
if ($rev) return $rev;
|
||||
|
||||
if (media_exists($this->id)) {
|
||||
$this->data['rev'] = filemtime(mediaFN($this->id));
|
||||
$this->data['exists'] = true;
|
||||
} else {
|
||||
$this->loadRevisions();
|
||||
}
|
||||
return $this->data['rev'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the previous revision timestamp of this page
|
||||
*
|
||||
* @return int|null The previous revision or null if there is none
|
||||
*/
|
||||
public function getPrev()
|
||||
{
|
||||
if ($this->data['prev'] ?? 0) return $this->data['prev'];
|
||||
$this->loadRevisions();
|
||||
return $this->data['prev'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Does this page exist?
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isExisting()
|
||||
{
|
||||
if (!isset($this->data['exists'])) {
|
||||
$this->data['exists'] = media_exists($this->id);
|
||||
}
|
||||
return $this->data['exists'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the current and previous revision from the changelog
|
||||
* @return void
|
||||
*/
|
||||
protected function loadRevisions()
|
||||
{
|
||||
$changelog = new MediaChangeLog($this->id);
|
||||
$revs = $changelog->getRevisions(0, 2); // FIXME check that this returns the current one correctly
|
||||
if (!isset($this->data['rev'])) {
|
||||
// prefer an already set date, only set if missing
|
||||
// it should usally not happen that neither is available
|
||||
$this->data['rev'] = $revs[0] ?? 0;
|
||||
}
|
||||
// a previous revision might not exist
|
||||
$this->data['prev'] = $revs[1] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a table showing the two media files
|
||||
*
|
||||
* @param MediaFile|null $src1
|
||||
* @param MediaFile|null $src2
|
||||
* @return string
|
||||
*/
|
||||
protected function createDiffTable($src1, $src2)
|
||||
{
|
||||
global $lang;
|
||||
|
||||
$content = '<table>';
|
||||
$content .= '<tr>';
|
||||
$content .= '<th width="50%">' . ($src1 ? $src1->getRev() : '') . '</th>';
|
||||
$content .= '<th width="50%">' . $lang['current'] . '</th>';
|
||||
$content .= '</tr>';
|
||||
$content .= '<tr>';
|
||||
|
||||
$content .= '<td align="center">';
|
||||
if ($src1) {
|
||||
$display = new Display($src1);
|
||||
$display->getPreviewHtml(300, 300);
|
||||
}
|
||||
$content .= '</td>';
|
||||
|
||||
$content .= '<td align="center">';
|
||||
if ($src2) {
|
||||
$display = new Display($src2);
|
||||
$display->getPreviewHtml(300, 300);
|
||||
}
|
||||
$content .= '</td>';
|
||||
|
||||
$content .= '</tr>';
|
||||
$content .= '</table>';
|
||||
|
||||
return $this->cleanHTML($content);
|
||||
}
|
||||
}
|
||||
215
dokuwiki/inc/Feed/FeedPageProcessor.php
Normal file
215
dokuwiki/inc/Feed/FeedPageProcessor.php
Normal file
@@ -0,0 +1,215 @@
|
||||
<?php
|
||||
|
||||
namespace dokuwiki\Feed;
|
||||
|
||||
use Diff;
|
||||
use dokuwiki\ChangeLog\PageChangeLog;
|
||||
use TableDiffFormatter;
|
||||
use UnifiedDiffFormatter;
|
||||
|
||||
/**
|
||||
* Accept more or less arbitrary data to represent a page and provide lazy loading accessors
|
||||
* to all the data we need for feed generation.
|
||||
*/
|
||||
class FeedPageProcessor extends FeedItemProcessor
|
||||
{
|
||||
/** @var array[] metadata */
|
||||
protected $meta;
|
||||
|
||||
// region data processors
|
||||
|
||||
/** @inheritdoc */
|
||||
public function getURL($linkto)
|
||||
{
|
||||
switch ($linkto) {
|
||||
case 'page':
|
||||
$opt = ['rev' => $this->getRev()];
|
||||
break;
|
||||
case 'rev':
|
||||
$opt = ['rev' => $this->getRev(), 'do' => 'revisions'];
|
||||
break;
|
||||
case 'current':
|
||||
$opt = [];
|
||||
break;
|
||||
case 'diff':
|
||||
default:
|
||||
$opt = ['rev' => $this->getRev(), 'do' => 'diff'];
|
||||
}
|
||||
|
||||
return wl($this->getId(), $opt, true, '&');
|
||||
}
|
||||
|
||||
/** @inheritdoc */
|
||||
public function getBody($content)
|
||||
{
|
||||
global $lang;
|
||||
|
||||
switch ($content) {
|
||||
case 'diff':
|
||||
$diff = $this->getDiff();
|
||||
// note: diff output must be escaped, UnifiedDiffFormatter provides plain text
|
||||
$udf = new UnifiedDiffFormatter();
|
||||
return "<pre>\n" . hsc($udf->format($diff)) . "\n</pre>";
|
||||
|
||||
case 'htmldiff':
|
||||
$diff = $this->getDiff();
|
||||
// note: no need to escape diff output, TableDiffFormatter provides 'safe' html
|
||||
$tdf = new TableDiffFormatter();
|
||||
$content = '<table>';
|
||||
$content .= '<tr><th colspan="2" width="50%">' . dformat($this->getPrev()) . '</th>';
|
||||
$content .= '<th colspan="2" width="50%">' . $lang['current'] . '</th></tr>';
|
||||
$content .= $tdf->format($diff);
|
||||
$content .= '</table>';
|
||||
return $content;
|
||||
|
||||
case 'html':
|
||||
if ($this->isExisting()) {
|
||||
$html = p_wiki_xhtml($this->getId(), '', false);
|
||||
} else {
|
||||
$html = p_wiki_xhtml($this->getId(), $this->getRev(), false);
|
||||
}
|
||||
return $this->cleanHTML($html);
|
||||
|
||||
case 'abstract':
|
||||
default:
|
||||
return $this->getAbstract();
|
||||
}
|
||||
}
|
||||
|
||||
/** @inheritdoc */
|
||||
public function getCategory()
|
||||
{
|
||||
$meta = $this->getMetaData();
|
||||
return (array)($meta['subject'] ?? (string)getNS($this->getId()));
|
||||
}
|
||||
|
||||
// endregion
|
||||
|
||||
// region data accessors
|
||||
|
||||
/**
|
||||
* Get the page abstract
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getAbstract()
|
||||
{
|
||||
if (!isset($this->data['abstract'])) {
|
||||
$meta = $this->getMetaData();
|
||||
if (isset($meta['description']['abstract'])) {
|
||||
$this->data['abstract'] = (string)$meta['description']['abstract'];
|
||||
} else {
|
||||
$this->data['abstract'] = '';
|
||||
}
|
||||
}
|
||||
return $this->data['abstract'];
|
||||
}
|
||||
|
||||
/** @inheritdoc */
|
||||
public function getRev()
|
||||
{
|
||||
$rev = parent::getRev();
|
||||
if ($rev) return $rev;
|
||||
|
||||
if (page_exists($this->id)) {
|
||||
$this->data['rev'] = filemtime(wikiFN($this->id));
|
||||
$this->data['exists'] = true;
|
||||
} else {
|
||||
$this->loadRevisions();
|
||||
}
|
||||
return $this->data['rev'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the previous revision timestamp of this page
|
||||
*
|
||||
* @return int|null The previous revision or null if there is none
|
||||
*/
|
||||
public function getPrev()
|
||||
{
|
||||
if ($this->data['prev'] ?? 0) return $this->data['prev'];
|
||||
$this->loadRevisions();
|
||||
return $this->data['prev'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Does this page exist?
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isExisting()
|
||||
{
|
||||
if (!isset($this->data['exists'])) {
|
||||
$this->data['exists'] = page_exists($this->id);
|
||||
}
|
||||
return $this->data['exists'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the title of this page
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getTitle()
|
||||
{
|
||||
global $conf;
|
||||
if (!isset($this->data['title'])) {
|
||||
if ($conf['useheading']) {
|
||||
$this->data['title'] = p_get_first_heading($this->id);
|
||||
} else {
|
||||
$this->data['title'] = noNS($this->id);
|
||||
}
|
||||
}
|
||||
return $this->data['title'];
|
||||
}
|
||||
|
||||
// endregion
|
||||
|
||||
/**
|
||||
* Get the metadata of this page
|
||||
*
|
||||
* @return array[]
|
||||
*/
|
||||
protected function getMetaData()
|
||||
{
|
||||
if (!isset($this->meta)) {
|
||||
$this->meta = (array)p_get_metadata($this->id);
|
||||
}
|
||||
return $this->meta;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the current and previous revision from the changelog
|
||||
* @return void
|
||||
*/
|
||||
protected function loadRevisions()
|
||||
{
|
||||
$changelog = new PageChangeLog($this->id);
|
||||
$revs = $changelog->getRevisions(0, 2); // FIXME check that this returns the current one correctly
|
||||
if (!isset($this->data['rev'])) {
|
||||
// prefer an already set date, only set if missing
|
||||
// it should usally not happen that neither is available
|
||||
$this->data['rev'] = $revs[0] ?? 0;
|
||||
}
|
||||
// a previous revision might not exist
|
||||
$this->data['prev'] = $revs[1] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a diff between this and the previous revision
|
||||
*
|
||||
* @return Diff
|
||||
*/
|
||||
protected function getDiff()
|
||||
{
|
||||
$prev = $this->getPrev();
|
||||
|
||||
if ($prev) {
|
||||
return new Diff(
|
||||
explode("\n", rawWiki($this->getId(), $prev)),
|
||||
explode("\n", rawWiki($this->getId(), ''))
|
||||
);
|
||||
}
|
||||
return new Diff([''], explode("\n", rawWiki($this->getId(), '')));
|
||||
}
|
||||
}
|
||||
@@ -1,16 +1,22 @@
|
||||
<?php
|
||||
|
||||
use SimplePie\SimplePie;
|
||||
use dokuwiki\FeedParserFile;
|
||||
use SimplePie\File;
|
||||
|
||||
/**
|
||||
* We override some methods of the original SimplePie class here
|
||||
*/
|
||||
class FeedParser extends SimplePie {
|
||||
|
||||
class FeedParser extends SimplePie
|
||||
{
|
||||
/**
|
||||
* Constructor. Set some defaults
|
||||
*/
|
||||
public function __construct(){
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
$this->enable_cache(false);
|
||||
$this->set_file_class(\dokuwiki\FeedParserFile::class);
|
||||
$this->registry->register(File::class, FeedParserFile::class);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -19,9 +25,8 @@ class FeedParser extends SimplePie {
|
||||
* phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
|
||||
* @param string $url
|
||||
*/
|
||||
public function feed_url($url){
|
||||
public function feed_url($url)
|
||||
{
|
||||
$this->set_feed_url($url);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
namespace dokuwiki;
|
||||
|
||||
use SimplePie\File;
|
||||
use SimplePie\SimplePie;
|
||||
use dokuwiki\HTTP\DokuHTTPClient;
|
||||
|
||||
/**
|
||||
@@ -9,7 +11,7 @@ use dokuwiki\HTTP\DokuHTTPClient;
|
||||
*
|
||||
* Replaces SimplePie's own class
|
||||
*/
|
||||
class FeedParserFile extends \SimplePie_File
|
||||
class FeedParserFile extends File
|
||||
{
|
||||
protected $http;
|
||||
/** @noinspection PhpMissingParentConstructorInspection */
|
||||
@@ -22,13 +24,7 @@ class FeedParserFile extends \SimplePie_File
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function __construct(
|
||||
$url,
|
||||
$timeout = 10,
|
||||
$redirects = 5,
|
||||
$headers = null,
|
||||
$useragent = null,
|
||||
$force_fsockopen = false,
|
||||
$curl_options = array()
|
||||
$url
|
||||
) {
|
||||
$this->http = new DokuHTTPClient();
|
||||
$this->success = $this->http->sendRequest($url);
|
||||
@@ -37,7 +33,7 @@ class FeedParserFile extends \SimplePie_File
|
||||
$this->body = $this->http->resp_body;
|
||||
$this->error = $this->http->error;
|
||||
|
||||
$this->method = SIMPLEPIE_FILE_SOURCE_REMOTE | SIMPLEPIE_FILE_SOURCE_FSOCKOPEN;
|
||||
$this->method = SimplePie::FILE_SOURCE_REMOTE | SimplePie::FILE_SOURCE_FSOCKOPEN;
|
||||
|
||||
return $this->success;
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user