Merge branch 'master' into retrytests

* master: (407 commits)
  do not export the appveyor config
  Added appveyor config for automated windows testing
  Update check supports HTTPS
  fixed some style errors found by scrutinizer
  removed unused, empty files
  some cleanup fpr set_metadata test
  added one more test for internal links
  parsertests: replaced var keywords and added type hints
  Fix p_set_metadata damaging contributors with numeric ID
  Add tests for array_replace part of set_metadata
  Fix rendering null $language going to GeSHi (fixes #2088)
  Fix RSS syntax XSS bug (#2081)
  Fix sanitation of $language for code highlighting (fixes #2080)
  translation update
  fix(config): empty string is valid for numericopt
  removed old tpl_content_core method
  updated composer dependencies
  Removed progressbar from searchform
  Release preparation
  translation update
  ...
This commit is contained in:
Andreas Gohr 2017-08-27 11:57:48 +02:00
commit e8a516272f
1230 changed files with 93233 additions and 60926 deletions

1
.gitattributes vendored
View File

@ -9,6 +9,7 @@
.gitignore export-ignore
.editorconfig export-ignore
.travis.yml export-ignore
appveyor.yml export-ignore
composer.json export-ignore
composer.lock export-ignore
_test export-ignore

17
.gitignore vendored
View File

@ -18,6 +18,11 @@
*.DS_Store
*.iml
.idea/
# Eclipse IDE
.buildpath
.project
.settings/
# DokuWiki
/data/attic/*
/data/cache/*
/data/index/*
@ -40,6 +45,7 @@
!/lib/plugins/authldap
!/lib/plugins/authmysql
!/lib/plugins/authpgsql
!/lib/plugins/authpdo
!/lib/plugins/authplain
!/lib/plugins/config
!/lib/plugins/extension
@ -61,7 +67,7 @@ lib/images/*/local/*
# composer default ignores
composer.phar
vendor/bin/*
vendor/*/*/phpunit.xml
vendor/*/*/phpunit.xml*
vendor/*/*/.travis.yml
vendor/*/*/bin/*
vendor/*/*/tests/*
@ -71,3 +77,12 @@ vendor/*/*/docs/*
vendor/*/*/contrib/*
vendor/splitbrain/php-archive/apigen.neon
vendor/splitbrain/php-archive/generate-api.sh
vendor/paragonie/random_compat/build-phar.sh
vendor/paragonie/random_compat/dist/*
vendor/paragonie/random_compat/other/*
vendor/simplepie/simplepie/db.sql
vendor/marcusschwarz/lesserphp/package.sh
vendor/marcusschwarz/lesserphp/lessify*
vendor/marcusschwarz/lesserphp/Makefile
vendor/marcusschwarz/lesserphp/plessc

View File

@ -1,23 +1,49 @@
language: php
sudo: false
php:
- "nightly"
- "7.1"
- "7.0"
- "5.6"
- "5.5"
- "5.4"
- "5.3"
- "hhvm"
env:
- DISABLE_FUNCTIONS=
- DISABLE_FUNCTIONS="gzopen"
matrix:
fast_finish: true
include:
- php: hhvm
sudo: true
dist: trusty
group: edge # until the next update
addons:
apt:
packages:
- mysql-server-5.6
- mysql-client-core-5.6
- mysql-client-5.6
services:
- mysql
- postgresql
env: DISABLE_FUNCTIONS=
allow_failures:
- php: "hhvm"
- php: "nightly"
exclude:
- php: "hhvm"
env: DISABLE_FUNCTIONS="gzopen"
notifications:
irc:
channels:
- "chat.freenode.net#dokuwiki"
on_success: change
on_failure: change
before_script: echo "disable_functions=$DISABLE_FUNCTIONS" >> ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/travis.ini
install:
- wget -O ~/.phpenv/versions/hhvm/bin/phpunit https://phar.phpunit.de/phpunit-5.7.phar
- chmod 755 ~/.phpenv/versions/hhvm/bin/phpunit
before_script:
# Disable the HHVM JIT for faster Unit Testing
- if [[ $TRAVIS_PHP_VERSION = hhv* ]]; then echo 'hhvm.jit = 0' >> /etc/hhvm/php.ini; fi
- if [[ $TRAVIS_PHP_VERSION != hhv* ]]; then test -z "$DISABLE_FUNCTIONS" || echo "disable_functions=$DISABLE_FUNCTIONS" >> ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/travis.ini; fi
- cp _test/mysql.conf.php.dist _test/mysql.conf.php
- cp _test/pgsql.conf.php.dist _test/pgsql.conf.php
script: cd _test && phpunit --verbose --stderr

2
README
View File

@ -4,7 +4,7 @@ at http://www.dokuwiki.org/
For Installation Instructions see
http://www.dokuwiki.org/install
DokuWiki - 2004-2015 (c) Andreas Gohr <andi@splitbrain.org>
DokuWiki - 2004-2017 (c) Andreas Gohr <andi@splitbrain.org>
and the DokuWiki Community
See COPYING and file headers for license info

View File

@ -5,7 +5,7 @@ This is the test suite to automatically test various parts of DokuWiki.
===== Requirements =====
* PHPUnit 3.6.10+ http://www.phpunit.de/
* PHP 5.3+ http://www.php.net
* PHP 5.3+ http://php.net
===== PHPUnit Installation ======

View File

@ -1,4 +1,26 @@
<?php
if(!class_exists('PHPUnit_Framework_TestCase')) {
/**
* phpunit 5/6 compatibility
*/
class PHPUnit_Framework_TestCase extends PHPUnit\Framework\TestCase {
/**
* @param string $class
* @param null|string $message
*/
public function setExpectedException($class, $message=null) {
$this->expectException($class);
if(!is_null($message)) {
$this->expectExceptionMessage($message);
}
}
}
}
/**
* Helper class to provide basic functionality for tests
*/
@ -167,4 +189,54 @@ abstract class DokuWikiTest extends PHPUnit_Framework_TestCase {
}
}
/*
* Compatibility for older PHPUnit versions
*
* @param string $originalClassName
* @return PHPUnit_Framework_MockObject_MockObject
*/
protected function createMock($originalClassName) {
if(is_callable(array('parent', 'createMock'))) {
return parent::createMock($originalClassName);
} else {
return $this->getMock($originalClassName);
}
}
/**
* Compatibility for older PHPUnit versions
*
* @param string $originalClassName
* @param array $methods
* @return PHPUnit_Framework_MockObject_MockObject
*/
protected function createPartialMock($originalClassName, array $methods) {
if(is_callable(array('parent', 'createPartialMock'))) {
return parent::createPartialMock($originalClassName, $methods);
} else {
return $this->getMock($originalClassName, $methods);
}
}
/**
* Waits until a new second has passed
*
* The very first call will return immeadiately, proceeding calls will return
* only after at least 1 second after the last call has passed.
*
* When passing $init=true it will not return immeadiately but use the current
* second as initialization. It might still return faster than a second.
*
* @param bool $init wait from now on, not from last time
* @return int new timestamp
*/
protected function waitForTick($init = false) {
static $last = 0;
if($init) $last = time();
while($last === $now = time()) {
usleep(100000); //recheck in a 10th of a second
}
$last = $now;
return $now;
}
}

View File

@ -5,6 +5,15 @@
*/
class TestUtils {
/**
* converts path to unix-like on windows OS
* @param string $path UNIX-like path to be converted
* @return string
*/
public static function w2u($path) {
return isWindows() ? str_replace('\\', '/', $path) : $path;
}
/**
* helper for recursive copy()
*

View File

@ -388,7 +388,7 @@ class DOMDocumentWrapper {
phpQuery::debug("Full markup load (XML), appending charset '$charset'");
$markup = $this->charsetAppendToXML($markup, $charset);
}
// see http://pl2.php.net/manual/en/book.dom.php#78929
// see http://php.net/manual/en/book.dom.php#78929
// LIBXML_DTDLOAD (>= PHP 5.1)
// does XML ctalogues works with LIBXML_NONET
// $this->document->resolveExternals = true;
@ -401,7 +401,7 @@ class DOMDocumentWrapper {
? $this->document->loadXML($markup)
: @$this->document->loadXML($markup);
} else {
/** @link http://pl2.php.net/manual/en/libxml.constants.php */
/** @link http://php.net/manual/en/libxml.constants.php */
$libxmlStatic = phpQuery::$debug === 2
? LIBXML_DTDLOAD|LIBXML_DTDATTR|LIBXML_NONET
: LIBXML_DTDLOAD|LIBXML_DTDATTR|LIBXML_NONET|LIBXML_NOWARNING|LIBXML_NOERROR;

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generated by IcoMoon.io -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="64" height="64" viewBox="0 0 64 64">
<!--
this is a
multiline
comment
-->
<path d="M64 20l-32-16-32 16 32 16 32-16zM32 9.311l21.379 10.689-21.379 10.689-21.379-10.689 21.379-10.689zM57.59 28.795l6.41 3.205-32 16-32-16 6.41-3.205 25.59 12.795zM57.59 40.795l6.41 3.205-32 16-32-16 6.41-3.205 25.59 12.795z" fill="#000000"></path>
</svg>

After

Width:  |  Height:  |  Size: 625 B

View File

@ -91,9 +91,9 @@ Notes:
You can also use an image to link to another internal or external page by combining the syntax for links and [[#images_and_other_files|images]] (see below) like this:
[[http://www.php.net|{{wiki:dokuwiki-128.png}}]]
[[http://php.net|{{wiki:dokuwiki-128.png}}]]
[[http://www.php.net|{{wiki:dokuwiki-128.png}}]]
[[http://php.net|{{wiki:dokuwiki-128.png}}]]
Please note: The image formatting is the only formatting syntax accepted in link names.
@ -131,12 +131,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: {{http://de3.php.net/images/php.gif?200x50}}
Resized external image: {{http://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: {{http://de3.php.net/images/php.gif?200x50}}
Resized external image: {{http://php.net/images/php.gif?200x50}}
By using left or right whitespaces you can choose the alignment.

View File

@ -0,0 +1,9 @@
<?php
/**
* This configures the access to a mysql database. The user needs to have permissions
* to create and drop databases.
*/
$conf['host'] = 'localhost';
$conf['port'] = 3306;
$conf['user'] = 'root';
$conf['pass'] = '';

View File

@ -0,0 +1,9 @@
<?php
/**
* This configures the access to a postgres database. The user needs to have permissions
* to create and drop databases.
*/
$conf['host'] = 'localhost';
$conf['port'] = 5432;
$conf['user'] = 'postgres';
$conf['pass'] = '';

View File

@ -4,6 +4,7 @@
convertNoticesToExceptions="false"
colors="true"
stderr="true"
backupGlobals="true"
>
<testsuites>

View File

@ -0,0 +1,182 @@
<?php
use dokuwiki\Action\AbstractAclAction;
use dokuwiki\Action\AbstractUserAction;
use dokuwiki\Action\Exception\ActionAclRequiredException;
use dokuwiki\Action\Exception\ActionDisabledException;
use dokuwiki\Action\Exception\ActionUserRequiredException;
class action_general extends DokuWikiTest {
public function dataProvider() {
return array(
array('Login', AUTH_NONE, array('exists' => true, 'ismanager' => false)),
array('Logout', AUTH_NONE, array('exists' => true, 'ismanager' => false)),
array('Search', AUTH_NONE, array('exists' => true, 'ismanager' => false)),
array('Recent', AUTH_NONE, array('exists' => true, 'ismanager' => false)),
array('Profile', AUTH_NONE, array('exists' => true, 'ismanager' => false)),
array('ProfileDelete', AUTH_NONE, array('exists' => true, 'ismanager' => false)),
array('Index', AUTH_NONE, array('exists' => true, 'ismanager' => false)),
array('Sitemap', AUTH_NONE, array('exists' => true, 'ismanager' => false)),
array('Denied', AUTH_NONE, array('exists' => true, 'ismanager' => false)),
array('Register', AUTH_NONE, array('exists' => true, 'ismanager' => false)),
array('Resendpwd', AUTH_NONE, array('exists' => true, 'ismanager' => false)),
array('Backlink', AUTH_NONE, array('exists' => true, 'ismanager' => false)),
array('Revert', AUTH_ADMIN, array('exists' => true, 'ismanager' => false)),
array('Revert', AUTH_EDIT, array('exists' => true, 'ismanager' => true)),
array('Admin', AUTH_ADMIN, array('exists' => true, 'ismanager' => false)),
array('Admin', AUTH_READ, array('exists' => true, 'ismanager' => true)), // let in, check later again
array('Check', AUTH_READ, array('exists' => true, 'ismanager' => false)), // sensible?
array('Diff', AUTH_READ, array('exists' => true, 'ismanager' => false)),
array('Show', AUTH_READ, array('exists' => true, 'ismanager' => false)),
array('Subscribe', AUTH_READ, array('exists' => true, 'ismanager' => false)),
array('Locked', AUTH_READ, array('exists' => true, 'ismanager' => false)),
array('Source', AUTH_READ, array('exists' => true, 'ismanager' => false)),
array('Export', AUTH_READ, array('exists' => true, 'ismanager' => false)),
array('Media', AUTH_READ, array('exists' => true, 'ismanager' => false)),
array('Revisions', AUTH_READ, array('exists' => true, 'ismanager' => false)),
array('Draftdel', AUTH_EDIT, array('exists' => true, 'ismanager' => false)),
// aliases
array('Cancel', AUTH_NONE, array('exists' => true, 'ismanager' => false)),
array('Recover', AUTH_NONE, array('exists' => true, 'ismanager' => false)),
// EDITING existing page
array('Save', AUTH_EDIT, array('exists' => true, 'ismanager' => false)),
array('Conflict', AUTH_EDIT, array('exists' => true, 'ismanager' => false)),
array('Draft', AUTH_EDIT, array('exists' => true, 'ismanager' => false)),
//the edit function will check again and do a source show
//when no AUTH_EDIT available:
array('Edit', AUTH_READ, array('exists' => true, 'ismanager' => false)),
array('Preview', AUTH_READ, array('exists' => true, 'ismanager' => false)),
// EDITING new page
array('Save', AUTH_CREATE, array('exists' => false, 'ismanager' => false)),
array('Conflict', AUTH_CREATE, array('exists' => false, 'ismanager' => false)),
array('Draft', AUTH_CREATE, array('exists' => false, 'ismanager' => false)),
array('Edit', AUTH_CREATE, array('exists' => false, 'ismanager' => false)),
array('Preview', AUTH_CREATE, array('exists' => false, 'ismanager' => false)),
);
}
/**
* @dataProvider dataProvider
* @param $name
* @param $expected
* @param $info
*/
public function testMinimumPermissions($name, $expected, $info) {
global $INFO;
$INFO = $info;
$classname = 'dokuwiki\\Action\\' . $name;
/** @var \dokuwiki\Action\AbstractAction $class */
$class = new $classname();
$this->assertSame($expected, $class->minimumPermission());
}
/**
* All actions should handle the disableactions setting
*
* @dataProvider dataProvider
* @param $name
*/
public function testBaseClassActionOkPermission($name) {
$this->assertTrue(true); // mark as not risky
if($name == 'Show') return; // disabling show does not work
$classname = 'dokuwiki\\Action\\' . $name;
/** @var \dokuwiki\Action\AbstractAction $class */
$class = new $classname();
global $conf;
$conf['useacl'] = 1;
$conf['subscribers'] = 1;
$conf['disableactions'] = '';
$_SERVER['REMOTE_USER'] = 'someone';
try {
\dokuwiki\ActionRouter::getInstance(true)->checkAction($class);
} catch(\Exception $e) {
$this->assertNotSame(ActionDisabledException::class, get_class($e));
}
$conf['disableactions'] = $class->getActionName();
try {
\dokuwiki\ActionRouter::getInstance(true)->checkAction($class);
} catch(\Exception $e) {
$this->assertSame(ActionDisabledException::class, get_class($e), $e);
}
}
/**
* Actions inheriting from AbstractAclAction should have an ACL enabled check
*
* @dataProvider dataProvider
* @param $name
*/
public function testBaseClassAclPermission($name) {
$classname = 'dokuwiki\\Action\\' . $name;
/** @var \dokuwiki\Action\AbstractAction $class */
$class = new $classname();
$this->assertTrue(true); // mark as not risky
if(!is_a($class, AbstractAclAction::class)) return;
global $conf;
$conf['useacl'] = 1;
$conf['subscribers'] = 1;
try {
$class->checkPermissions();
} catch(\Exception $e) {
$this->assertNotSame(ActionAclRequiredException::class, get_class($e));
}
$conf['useacl'] = 0;
try {
$class->checkPermissions();
} catch(\Exception $e) {
$this->assertSame(ActionAclRequiredException::class, get_class($e));
}
}
/**
* Actions inheriting from AbstractUserAction should have user check
*
* @dataProvider dataProvider
* @param $name
*/
public function testBaseClassUserPermission($name) {
$classname = 'dokuwiki\\Action\\' . $name;
/** @var \dokuwiki\Action\AbstractAction $class */
$class = new $classname();
$this->assertTrue(true); // mark as not risky
if(!is_a($class, AbstractUserAction::class)) return;
global $conf;
$conf['useacl'] = 1;
$conf['subscribers'] = 1;
$_SERVER['REMOTE_USER'] = 'test';
try {
$class->checkPermissions();
} catch(\Exception $e) {
$this->assertNotSame(ActionUserRequiredException::class, get_class($e));
}
unset($_SERVER['REMOTE_USER']);
try {
$class->checkPermissions();
} catch(\Exception $e) {
$this->assertSame(ActionUserRequiredException::class, get_class($e));
}
}
}

View File

@ -2,7 +2,7 @@
class auth_acl_test extends DokuWikiTest {
var $oldAuthAcl;
protected $oldAuthAcl;
function setUp() {
parent::setUp();

View File

@ -2,102 +2,112 @@
class auth_password_test extends DokuWikiTest {
// hashes for the password foo$method, using abcdefgh12345678912345678912345678 as salt
var $passes = array(
'smd5' => '$1$abcdefgh$SYbjm2AEvSoHG7Xapi8so.',
'apr1' => '$apr1$abcdefgh$C/GzYTF4kOVByYLEoD5X4.',
'md5' => '8fa22d62408e5351553acdd91c6b7003',
'sha1' => 'b456d3b0efd105d613744ffd549514ecafcfc7e1',
'ssha' => '{SSHA}QMHG+uC7bHNYKkmoLbNsNI38/dJhYmNk',
'lsmd5' => '{SMD5}HGbkPrkWgy9KgcRGWlrsUWFiY2RlZmdo',
'crypt' => 'ablvoGr1hvZ5k',
'mysql' => '4a1fa3780bd6fd55',
'my411' => '*e5929347e25f82e19e4ebe92f1dc6b6e7c2dbd29',
'kmd5' => 'a579299436d7969791189acadd86fcb716',
'djangomd5' => 'md5$abcde$d0fdddeda8cd92725d2b54148ac09158',
'djangosha1' => 'sha1$abcde$c8e65a7f0acc9158843048a53dcc5a6bc4d17678',
/**
* precomputed hashes
*
* for the password foo$method, using abcdefgh12345678912345678912345678 as salt
*
* @return array
*/
public function hashes() {
);
$passes = array(
array('smd5', '$1$abcdefgh$SYbjm2AEvSoHG7Xapi8so.'),
array('apr1', '$apr1$abcdefgh$C/GzYTF4kOVByYLEoD5X4.'),
array('md5', '8fa22d62408e5351553acdd91c6b7003'),
array('sha1', 'b456d3b0efd105d613744ffd549514ecafcfc7e1'),
array('ssha', '{SSHA}QMHG+uC7bHNYKkmoLbNsNI38/dJhYmNk'),
array('lsmd5', '{SMD5}HGbkPrkWgy9KgcRGWlrsUWFiY2RlZmdo'),
array('crypt', 'ablvoGr1hvZ5k'),
array('mysql', '4a1fa3780bd6fd55'),
array('my411', '*E5929347E25F82E19E4EBE92F1DC6B6E7C2DBD29'),
array('kmd5', 'a579299436d7969791189acadd86fcb716'),
array('djangomd5', 'md5$abcde$d0fdddeda8cd92725d2b54148ac09158'),
array('djangosha1', 'sha1$abcde$c8e65a7f0acc9158843048a53dcc5a6bc4d17678'),
);
function __construct() {
if(defined('CRYPT_SHA512') && CRYPT_SHA512 == 1) {
// Check SHA512 only if available in this PHP
$this->passes['sha512'] = '$6$abcdefgh12345678$J9.zOcgx0lotwZdcz0uulA3IVQMinZvFZVjA5vapRLVAAqtay23XD4xeeUxQ3B4JvDWYFBIxVWW1tOYlHX13k1';
$passes[] = array('sha512', '$6$abcdefgh12345678$J9.zOcgx0lotwZdcz0uulA3IVQMinZvFZVjA5vapRLVAAqtay23XD4xeeUxQ3B4JvDWYFBIxVWW1tOYlHX13k1');
}
if(function_exists('hash_pbkdf2')) {
if(in_array('sha256', hash_algos())) {
$this->passes['djangopbkdf2_sha256'] = 'pbkdf2_sha256$24000$abcdefgh1234$R23OyZJ0nGHLG6MvPNfEkV5AOz3jUY5zthByPXs2gn0=';
$passes[] = array('djangopbkdf2_sha256', 'pbkdf2_sha256$24000$abcdefgh1234$R23OyZJ0nGHLG6MvPNfEkV5AOz3jUY5zthByPXs2gn0=');
}
if(in_array('sha1', hash_algos())) {
$this->passes['djangopbkdf2_sha1'] = 'pbkdf2_sha1$24000$abcdefgh1234$pOliX4vV1hgOv7lFNURIHHx41HI=';
$passes[] = array('djangopbkdf2_sha1', 'pbkdf2_sha1$24000$abcdefgh1234$pOliX4vV1hgOv7lFNURIHHx41HI=');
}
}
return $passes;
}
function test_cryptPassword(){
foreach($this->passes as $method => $hash){
$info = "testing method $method";
$this->assertEquals(
$hash,
auth_cryptPassword('foo'.$method, $method,'abcdefgh12345678912345678912345678'),
$info);
}
/**
* @dataProvider hashes
* @param $method
* @param $hash
*/
function test_cryptPassword($method, $hash) {
$this->assertEquals(
$hash,
auth_cryptPassword('foo' . $method, $method, 'abcdefgh12345678912345678912345678')
);
}
function test_verifyPassword(){
foreach($this->passes as $method => $hash){
$info = "testing method $method";
$this->assertTrue(auth_verifyPassword('foo'.$method, $hash), $info);
$this->assertFalse(auth_verifyPassword('bar'.$method, $hash), $info);
}
/**
* @dataProvider hashes
* @param $method
* @param $hash
*/
function test_verifyPassword($method, $hash) {
$this->assertTrue(auth_verifyPassword('foo' . $method, $hash));
$this->assertFalse(auth_verifyPassword('bar' . $method, $hash));
}
function test_verifySelf(){
foreach($this->passes as $method => $hash){
$info = "testing method $method";
$hash = auth_cryptPassword('foo'.$method,$method);
$this->assertTrue(auth_verifyPassword('foo'.$method, $hash), $info);
}
/**
* @dataProvider hashes
* @param $method
* @param $hash
*/
function test_verifySelf($method, $hash) {
$hash = auth_cryptPassword('foo' . $method, $method);
$this->assertTrue(auth_verifyPassword('foo' . $method, $hash));
}
function test_bcrypt_self(){
$hash = auth_cryptPassword('foobcrypt','bcrypt');
$this->assertTrue(auth_verifyPassword('foobcrypt',$hash));
function test_bcrypt_self() {
$hash = auth_cryptPassword('foobcrypt', 'bcrypt');
$this->assertTrue(auth_verifyPassword('foobcrypt', $hash));
}
function test_verifyPassword_fixedbcrypt(){
$this->assertTrue(auth_verifyPassword('foobcrypt','$2a$12$uTWercxbq4sjp2xAzv3we.ZOxk51m5V/Bv5bp2H27oVFJl5neFQoC'));
function test_verifyPassword_fixedbcrypt() {
$this->assertTrue(auth_verifyPassword('foobcrypt', '$2a$12$uTWercxbq4sjp2xAzv3we.ZOxk51m5V/Bv5bp2H27oVFJl5neFQoC'));
}
function test_verifyPassword_nohash(){
$this->assertTrue(auth_verifyPassword('foo','$1$$n1rTiFE0nRifwV/43bVon/'));
function test_verifyPassword_nohash() {
$this->assertTrue(auth_verifyPassword('foo', '$1$$n1rTiFE0nRifwV/43bVon/'));
}
function test_verifyPassword_fixedpmd5(){
$this->assertTrue(auth_verifyPassword('test12345','$P$9IQRaTwmfeRo7ud9Fh4E2PdI0S3r.L0'));
$this->assertTrue(auth_verifyPassword('test12345','$H$9IQRaTwmfeRo7ud9Fh4E2PdI0S3r.L0'));
function test_verifyPassword_fixedpmd5() {
$this->assertTrue(auth_verifyPassword('test12345', '$P$9IQRaTwmfeRo7ud9Fh4E2PdI0S3r.L0'));
$this->assertTrue(auth_verifyPassword('test12345', '$H$9IQRaTwmfeRo7ud9Fh4E2PdI0S3r.L0'));
}
function test_veryPassword_mediawiki(){
function test_veryPassword_mediawiki() {
$this->assertTrue(auth_verifyPassword('password', ':B:838c83e1:e4ab7024509eef084cdabd03d8b2972c'));
}
/**
* pmd5 checking should throw an exception when a hash with a too high
* iteration count is passed
*/
function test_verifyPassword_pmd5Exception(){
function test_verifyPassword_pmd5Exception() {
$except = false;
try{
try {
auth_verifyPassword('foopmd5', '$H$abcdefgh1ZbJodHxmeXVAhEzTG7IAp.');
}catch (Exception $e){
} catch(Exception $e) {
$except = true;
}
$this->assertTrue($except);
}
}
//Setup VIM: ex: et ts=4 :

View File

@ -1,33 +0,0 @@
<?php
/**
* Test for blowfish encryption.
*/
class blowfish_test extends DokuWikiTest {
public function testEncryptDecryptNumbers() {
$secret = '$%ÄüfuDFRR';
$string = '12345678';
$this->assertEquals(
$string,
PMA_blowfish_decrypt(PMA_blowfish_encrypt($string, $secret), $secret)
);
}
public function testEncryptDecryptChars() {
$secret = '$%ÄüfuDFRR';
$string = 'abcDEF012!"§$%&/()=?`´"\',.;:-_#+*~öäüÖÄÜ^°²³';
$this->assertEquals(
$string,
PMA_blowfish_decrypt(PMA_blowfish_encrypt($string, $secret), $secret)
);
}
// FS#1690 FS#1713
public function testEncryptDecryptBinary() {
$secret = '$%ÄüfuDFRR';
$string = "this is\0binary because of\0zero bytes";
$this->assertEquals(
$string,
PMA_blowfish_decrypt(PMA_blowfish_encrypt($string, $secret), $secret)
);
}
}

View File

@ -124,4 +124,46 @@ class changelog_getlastrevisionat_test extends DokuWikiTest {
$current = $pagelog->getLastRevisionAt($rev);
$this->assertEquals($currentexpected, $current);
}
}
/**
* test get correct revision on deleted media
*
*/
function test_deletedimage() {
global $conf;
global $AUTH_ACL;
//we need to have a user with AUTH_DELETE rights
//save settings
$oldSuperUser = $conf['superuser'];
$oldUseacl = $conf['useacl'];
$oldRemoteUser = $_SERVER['REMOTE_USER'];
$conf['superuser'] = 'admin';
$conf['useacl'] = 1;
$_SERVER['REMOTE_USER'] = 'admin';
$image = 'wiki:imageat.png';
$ret = copy(mediaFn('wiki:kind_zu_katze.png'),mediaFn($image));
$revexpected = @filemtime(mediaFn($image));
$rev = $revexpected + 10;
$this->waitForTick(true);
$ret = media_delete($image, 0);
$medialog = new MediaChangelog($image);
$current = $medialog->getLastRevisionAt($rev);
// as we wait for a tick, we should get something greater than the timestamp
$this->assertGreaterThan($revexpected, $current);
// however, it should be less than the current time or equal to it
$this->assertLessThanOrEqual(time(), $current);
//restore settings
$_SERVER['REMOTE_USER'] = $oldRemoteUser;
$conf['superuser'] = $oldSuperUser;
$conf['useacl'] = $oldUseacl;
}
}

View File

@ -0,0 +1,28 @@
<?php
class common_embedSVG_test extends DokuWikiTest {
/**
* embed should succeed with a cleaned up result
*/
function test_success() {
$file = mediaFN('wiki:test.svg');
$clean =
'<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" '.
'width="64" height="64" viewBox="0 0 64 64"><path d="M64 20l-32-16-32 16 32 16 32-16zM32 '.
'9.311l21.379 10.689-21.379 10.689-21.379-10.689 21.379-10.689zM57.59 28.795l6.41 3.205-32 16-32-16 '.
'6.41-3.205 25.59 12.795zM57.59 40.795l6.41 3.205-32 16-32-16 6.41-3.205 25.59 12.795z" '.
'fill="#000000"></path></svg>';
$this->assertEquals($clean, inlineSVG($file));
}
/**
* embed should fail because of the file size limit
*/
function test_fail() {
$file = mediaFN('wiki:test.svg');
$this->assertFalse(inlineSVG($file, 100));
}
}

View File

@ -1,6 +1,12 @@
<?php
class common_saveWikiText_test extends DokuWikiTest {
/** Delay writes of old revisions by a second. */
public function handle_write(Doku_Event $event, $param) {
if ($event->data[3] !== false) {
$this->waitForTick();
}
}
/**
* Execute a whole bunch of saves on the same page and check the results
@ -24,8 +30,9 @@ class common_saveWikiText_test extends DokuWikiTest {
$this->assertEquals('first save', $revinfo['sum']);
$this->assertEquals(DOKU_CHANGE_TYPE_CREATE, $revinfo['type']);
$this->assertEquals(10, $revinfo['sizechange']);
$this->assertFileExists(wikiFN($page, $revinfo['date']));
sleep(1); // wait for new revision ID
$this->waitForTick(true); // wait for new revision ID
// save with same content should be ignored
saveWikiText($page, 'teststring', 'second save', false);
@ -51,7 +58,7 @@ class common_saveWikiText_test extends DokuWikiTest {
$this->assertEquals(DOKU_CHANGE_TYPE_EDIT, $revinfo['type']);
$this->assertEquals(5, $revinfo['sizechange']);
sleep(1); // wait for new revision ID
$this->waitForTick(); // wait for new revision ID
// add a minor edit (unauthenticated)
saveWikiText($page, 'teststring3long', 'fourth save', true);
@ -68,7 +75,7 @@ class common_saveWikiText_test extends DokuWikiTest {
$this->assertEquals(DOKU_CHANGE_TYPE_EDIT, $revinfo['type']);
$this->assertEquals(0, $revinfo['sizechange']);
sleep(1); // wait for new revision ID
$this->waitForTick(); // wait for new revision ID
// add a minor edit (authenticated)
$_SERVER['REMOTE_USER'] = 'user';
@ -86,7 +93,7 @@ class common_saveWikiText_test extends DokuWikiTest {
$this->assertEquals(DOKU_CHANGE_TYPE_MINOR_EDIT, $revinfo['type']);
$this->assertEquals(-4, $revinfo['sizechange']);
sleep(1); // wait for new revision ID
$this->waitForTick(); // wait for new revision ID
// delete
saveWikiText($page, '', 'sixth save', false);
@ -100,8 +107,9 @@ class common_saveWikiText_test extends DokuWikiTest {
$this->assertEquals('sixth save', $revinfo['sum']);
$this->assertEquals(DOKU_CHANGE_TYPE_DELETE, $revinfo['type']);
$this->assertEquals(-11, $revinfo['sizechange']);
$this->assertFileExists(wikiFN($page, $revinfo['date']));
sleep(1); // wait for new revision ID
$this->waitForTick(); // wait for new revision ID
// restore
$REV = $lastmod;
@ -120,14 +128,15 @@ class common_saveWikiText_test extends DokuWikiTest {
$this->assertEquals(DOKU_CHANGE_TYPE_REVERT, $revinfo['type']);
$this->assertEquals($REV, $revinfo['extra']);
$this->assertEquals(11, $revinfo['sizechange']);
$this->assertFileExists(wikiFN($page, $revinfo['date']));
$REV = '';
sleep(1); // wait for new revision ID
$this->waitForTick(); // wait for new revision ID
// create external edit
file_put_contents($file, 'teststring5');
sleep(1); // wait for new revision ID
$this->waitForTick(); // wait for new revision ID
// save on top of external edit
saveWikiText($page, 'teststring6', 'eigth save', false);
@ -155,6 +164,12 @@ class common_saveWikiText_test extends DokuWikiTest {
* Execute a whole bunch of saves on the same page and check the results
*/
function test_savesequencedeleteexternalrevision() {
// add an additional delay when saving files to make sure
// nobody relies on the saving happening in the same second
/** @var $EVENT_HANDLER Doku_Event_Handler */
global $EVENT_HANDLER;
$EVENT_HANDLER->register_hook('IO_WIKIPAGE_WRITE', 'BEFORE', $this, 'handle_write');
$page = 'page2';
$file = wikiFN($page);
@ -171,8 +186,9 @@ class common_saveWikiText_test extends DokuWikiTest {
$this->assertEquals('first save', $revinfo['sum']);
$this->assertEquals(DOKU_CHANGE_TYPE_CREATE, $revinfo['type']);
$this->assertEquals(10, $revinfo['sizechange']);
$this->assertFileExists(wikiFN($page, $revinfo['date']));
sleep(1); // wait for new revision ID
$this->waitForTick(true); // wait for new revision ID
// delete
saveWikiText($page, '', 'second save', false);
@ -186,13 +202,14 @@ class common_saveWikiText_test extends DokuWikiTest {
$this->assertEquals('second save', $revinfo['sum']);
$this->assertEquals(DOKU_CHANGE_TYPE_DELETE, $revinfo['type']);
$this->assertEquals(-10, $revinfo['sizechange']);
$this->assertFileExists(wikiFN($page, $revinfo['date']));
sleep(1); // wait for new revision ID
$this->waitForTick(); // wait for new revision ID
// create external edit
file_put_contents($file, 'teststring5');
sleep(1); // wait for new revision ID
$this->waitForTick(); // wait for new revision ID
// save on top of external edit
saveWikiText($page, 'teststring6', 'third save', false);
@ -205,11 +222,13 @@ class common_saveWikiText_test extends DokuWikiTest {
$this->assertEquals('third save', $revinfo['sum']);
$this->assertEquals(DOKU_CHANGE_TYPE_EDIT, $revinfo['type']);
$this->assertEquals(0, $revinfo['sizechange']);
$this->assertFileExists(wikiFN($page, $revinfo['date']));
$revinfo = $pagelog->getRevisionInfo($revisions[1]);
$this->assertEquals('external edit', $revinfo['sum']);
$this->assertEquals(DOKU_CHANGE_TYPE_EDIT, $revinfo['type']);
$this->assertEquals(11, $revinfo['sizechange']);
$this->assertFileExists(wikiFN($page, $revinfo['date']));
}
@ -226,7 +245,7 @@ class common_saveWikiText_test extends DokuWikiTest {
// create external edit
file_put_contents($file, 'teststring');
sleep(1); // wait for new revision ID
$this->waitForTick(true); // wait for new revision ID
// save on top of external edit
saveWikiText($page, 'teststring6', 'first save', false);
@ -268,14 +287,14 @@ class common_saveWikiText_test extends DokuWikiTest {
$this->assertEquals(DOKU_CHANGE_TYPE_CREATE, $revinfo['type']);
$this->assertEquals(10, $revinfo['sizechange']);
sleep(1); // wait for new revision ID
$this->waitForTick(true); // wait for new revision ID
// create external delete
unlink($file);
clearstatcache(false, $file);
sleep(1); // wait for new revision ID
$this->waitForTick(); // wait for new revision ID
// save on top of external delete. save is seen as creation
saveWikiText($page, 'teststring6', 'second save', false);
@ -317,7 +336,7 @@ class common_saveWikiText_test extends DokuWikiTest {
$this->assertEquals(DOKU_CHANGE_TYPE_CREATE, $revinfo['type']);
$this->assertEquals(10, $revinfo['sizechange']);
sleep(1); // wait for new revision ID
$this->waitForTick(true); // wait for new revision ID
// save with same content should be ignored
saveWikiText($page, 'teststring', 'second save', false);
@ -344,7 +363,7 @@ class common_saveWikiText_test extends DokuWikiTest {
$this->assertEquals(DOKU_CHANGE_TYPE_EDIT, $revinfo['type']);
$this->assertEquals(5, $revinfo['sizechange']);
sleep(1); // wait for new revision ID
$this->waitForTick(); // wait for new revision ID
// add a minor edit (unauthenticated)
saveWikiText($page, 'teststring3long', 'fourth save', true);
@ -361,7 +380,7 @@ class common_saveWikiText_test extends DokuWikiTest {
$this->assertEquals(DOKU_CHANGE_TYPE_EDIT, $revinfo['type']);
$this->assertEquals(0, $revinfo['sizechange']);
sleep(1); // wait for new revision ID
$this->waitForTick(); // wait for new revision ID
// add a minor edit (authenticated)
$_SERVER['REMOTE_USER'] = 'user';
@ -379,7 +398,7 @@ class common_saveWikiText_test extends DokuWikiTest {
$this->assertEquals(DOKU_CHANGE_TYPE_MINOR_EDIT, $revinfo['type']);
$this->assertEquals(-4, $revinfo['sizechange']);
sleep(1); // wait for new revision ID
$this->waitForTick(); // wait for new revision ID
// restore
$REV = $revertrev;

View File

@ -58,7 +58,10 @@ class form_dropdownelement_test extends DokuWikiTest {
'data-foo' => 'bar'
)
),
'second'
'second',
'3' => array(
'label' => 'the label of the complex third option',
)
);
$form->addDropdown('foo', $options, 'label text');
@ -70,7 +73,7 @@ class form_dropdownelement_test extends DokuWikiTest {
$this->assertTrue($select->length == 1);
$options = $pq->find('option');
$this->assertTrue($options->length == 2);
$this->assertEquals(3, $options->length);
$option = $pq->find('option#theID');
$this->assertEquals(1, $option->length);
@ -81,6 +84,81 @@ class form_dropdownelement_test extends DokuWikiTest {
$this->assertTrue($option->hasClass('classes'));
}
public function test_optgroups() {
$form = new Form\Form();
$options1 = array(
'first' => 'the label',
'second'
);
$options2 = array(
'third' => array (
'label' => 'label of third option',
'attribute' => 'attribute-value'
),
'fourth'
);
$dropdown = $form->addDropdown('foo', null, 'label text');
$dropdown->addOptGroup('opt1', $options1);
$dropdown->addOptGroup('opt2', $options2);
$dropdown->val('third');
$this->assertEquals('third', $dropdown->val());
/** @var Form\OptGroup[] $optGroups */
$optGroups = $dropdown->optGroups();
$this->assertEquals(array(
'first' => array('label' => 'the label'),
'second' => array('label' => 'second')
), $optGroups['opt1']->options());
// HTML
$html = $form->toHTML();
$pq = phpQuery::newDocumentXHTML($html);
$optGroupsHTML = $pq->find('optgroup');
$this->assertEquals(2, $optGroupsHTML->length);
$options = $pq->find('option');
$this->assertEquals(4, $options->length);
$selected = $pq->find('option[selected=selected]');
$this->assertEquals('third', $selected->val());
$this->assertEquals('label of third option', $selected->text());
}
/**
* Ensure that there is always only a single one selected option
*/
public function test_optgroups_doubleselect() {
$form = new Form\Form();
$options1 = array(
'double' => 'the label'
);
$options2 = array(
'double' => array (
'label' => 'label of third option',
'attribute' => 'attribute-value'
)
);
$dropdown = $form->addDropdown('foo', null, 'label text');
$dropdown->addOptGroup('opt1', $options1);
$dropdown->addOptGroup('opt2', $options2);
$dropdown->val('double');
// HTML
$html = $form->toHTML();
$pq = phpQuery::newDocumentXHTML($html);
$selected = $pq->find('option[selected=selected]');
$this->assertEquals(1, $selected->length);
$this->assertEquals('the label', $selected->text());
}
/**
* check that posted values overwrite preset default
*/

View File

@ -9,6 +9,7 @@ class io_getSizeFile_test extends DokuWikiTest {
if (!DOKU_HAS_GZIP) {
$this->markTestSkipped('skipping all zlib tests. Need zlib extension');
}
$this->assertTrue(true); // avoid being marked as risky for having no assertion
}
/*
@ -18,6 +19,7 @@ class io_getSizeFile_test extends DokuWikiTest {
if (!DOKU_HAS_BZIP) {
$this->markTestSkipped('skipping all bzip2 tests. Need bz2 extension');
}
$this->assertTrue(true); // avoid being marked as risky for having no assertion
}
function test_plain(){

View File

@ -8,7 +8,9 @@ class io_readfile_test extends DokuWikiTest {
public function test_ext_zlib() {
if (!DOKU_HAS_GZIP) {
$this->markTestSkipped('skipping all zlib tests. Need zlib extension');
return;
}
$this->assertTrue(true);
}
/*
@ -17,7 +19,9 @@ class io_readfile_test extends DokuWikiTest {
public function test_ext_bz2() {
if (!DOKU_HAS_BZIP) {
$this->markTestSkipped('skipping all bzip2 tests. Need bz2 extension');
return;
}
$this->assertTrue(true);
}
function test_plain(){

View File

@ -10,7 +10,9 @@ class io_replaceinfile_test extends DokuWikiTest {
public function test_ext_zlib() {
if (!DOKU_HAS_GZIP) {
$this->markTestSkipped('skipping all zlib tests. Need zlib extension');
return;
}
$this->assertTrue(true);
}
/*
@ -19,7 +21,9 @@ class io_replaceinfile_test extends DokuWikiTest {
public function test_ext_bz2() {
if (!DOKU_HAS_BZIP) {
$this->markTestSkipped('skipping all bzip2 tests. Need bz2 extension');
return;
}
$this->assertTrue(true);
}
function _write($file){
@ -97,11 +101,16 @@ class io_replaceinfile_test extends DokuWikiTest {
/**
* Test passing an invalid parameter.
*
* @expectedException PHPUnit_Framework_Error_Warning
*/
function test_badparam()
{
if (class_exists('PHPUnit\Framework\Error\Warning')) {
$expect = 'PHPUnit\Framework\Error\Warning'; // PHPUnit 6
} else {
$expect = 'PHPUnit_Framework_Error_Warning'; // PHPUnit 5
}
$this->setExpectedException($expect);
/* The empty $oldline parameter should be caught before the file doesn't exist test. */
$this->assertFalse(io_replaceInFile(TMP_DIR.'/not_existing_file.txt', '', '', false, 0));
}

View File

@ -8,7 +8,9 @@ class io_savefile_test extends DokuWikiTest {
public function test_ext_zlib() {
if (!DOKU_HAS_GZIP) {
$this->markTestSkipped('skipping all zlib tests. Need zlib extension');
return;
}
$this->assertTrue(true);
}
/*
@ -17,7 +19,9 @@ class io_savefile_test extends DokuWikiTest {
public function test_ext_bz2() {
if (!DOKU_HAS_BZIP) {
$this->markTestSkipped('skipping all bzip2 tests. Need bz2 extension');
return;
}
$this->assertTrue(true);
}
function _write($file){

View File

@ -1,80 +1,76 @@
<?php
class mail_isvalid extends DokuWikiTest {
class mail_isvalid_test extends DokuWikiTest {
public function provider() {
return array(
// our own tests
array('bugs@php.net', true),
array('~someone@somewhere.com', true),
array('no+body.here@somewhere.com.au', true),
array('username+tag@domain.com', true), // FS#1447
array("rfc2822+allthesechars_#*!'`/-={}are.legal@somewhere.com.au", true),
array('_foo@test.com', true), // FS#1049
array('bugs@php.net1', true), // new ICAN rulez seem to allow this
array('.bugs@php.net1', false),
array('bu..gs@php.net', false),
array('bugs@php..net', false),
array('bugs@.php.net', false),
array('bugs@php.net.', false),
array('bu(g)s@php.net1', false),
array('bu[g]s@php.net1', false),
array('somebody@somewhere.museum', true),
array('somebody@somewhere.travel', true),
array('root@[2010:fb:fdac::311:2101]', true),
array('test@example', true), // we allow local addresses
function test1(){
$tests = array();
// tests from http://code.google.com/p/php-email-address-validation/ below
// our own tests
$tests[] = array('bugs@php.net',true);
$tests[] = array('~someone@somewhere.com',true);
$tests[] = array('no+body.here@somewhere.com.au',true);
$tests[] = array('username+tag@domain.com',true); // FS#1447
$tests[] = array("rfc2822+allthesechars_#*!'`/-={}are.legal@somewhere.com.au",true);
$tests[] = array('_foo@test.com',true); // FS#1049
$tests[] = array('bugs@php.net1',true); // new ICAN rulez seem to allow this
$tests[] = array('.bugs@php.net1',false);
$tests[] = array('bu..gs@php.net',false);
$tests[] = array('bugs@php..net',false);
$tests[] = array('bugs@.php.net',false);
$tests[] = array('bugs@php.net.',false);
$tests[] = array('bu(g)s@php.net1',false);
$tests[] = array('bu[g]s@php.net1',false);
$tests[] = array('somebody@somewhere.museum',true);
$tests[] = array('somebody@somewhere.travel',true);
$tests[] = array('root@[2010:fb:fdac::311:2101]',true);
$tests[] = array('test@example', true); // we allow local addresses
array('test@example.com', true),
array('TEST@example.com', true),
array('1234567890@example.com', true),
array('test+test@example.com', true),
array('test-test@example.com', true),
array('t*est@example.com', true),
array('+1~1+@example.com', true),
array('{_test_}@example.com', true),
array('"[[ test ]]"@example.com', true),
array('test.test@example.com', true),
array('test."test"@example.com', true),
array('"test@test"@example.com', true),
array('test@123.123.123.123', true),
array('test@[123.123.123.123]', true),
array('test@example.example.com', true),
array('test@example.example.example.com', true),
// tests from http://code.google.com/p/php-email-address-validation/ below
$tests[] = array('test@example.com', true);
$tests[] = array('TEST@example.com', true);
$tests[] = array('1234567890@example.com', true);
$tests[] = array('test+test@example.com', true);
$tests[] = array('test-test@example.com', true);
$tests[] = array('t*est@example.com', true);
$tests[] = array('+1~1+@example.com', true);
$tests[] = array('{_test_}@example.com', true);
$tests[] = array('"[[ test ]]"@example.com', true);
$tests[] = array('test.test@example.com', true);
$tests[] = array('test."test"@example.com', true);
$tests[] = array('"test@test"@example.com', true);
$tests[] = array('test@123.123.123.123', true);
$tests[] = array('test@[123.123.123.123]', true);
$tests[] = array('test@example.example.com', true);
$tests[] = array('test@example.example.example.com', true);
$tests[] = array('test.example.com', false);
$tests[] = array('test.@example.com', false);
$tests[] = array('test..test@example.com', false);
$tests[] = array('.test@example.com', false);
$tests[] = array('test@test@example.com', false);
$tests[] = array('test@@example.com', false);
$tests[] = array('-- test --@example.com', false); // No spaces allowed in local part
$tests[] = array('[test]@example.com', false); // Square brackets only allowed within quotes
$tests[] = array('"test\test"@example.com', false); // Quotes cannot contain backslash
$tests[] = array('"test"test"@example.com', false); // Quotes cannot be nested
$tests[] = array('()[]\;:,<>@example.com', false); // Disallowed Characters
$tests[] = array('test@.', false);
$tests[] = array('test@example.', false);
$tests[] = array('test@.org', false);
$tests[] = array('12345678901234567890123456789012345678901234567890123456789012345@example.com', false); // 64 characters is maximum length for local part. This is 65.
$tests[] = array('test@123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012.com', false); // 255 characters is maximum length for domain. This is 256.
$tests[] = array('test@[123.123.123.123', false);
$tests[] = array('test@123.123.123.123]', false);
foreach($tests as $test){
$info = 'Testing '.$test[0];
if($test[1]){
$this->assertTrue((bool) mail_isvalid($test[0]), $info);
}else{
$this->assertFalse((bool) mail_isvalid($test[0]), $info);
}
}
array('test.example.com', false),
array('test.@example.com', false),
array('test..test@example.com', false),
array('.test@example.com', false),
array('test@test@example.com', false),
array('test@@example.com', false),
array('-- test --@example.com', false), // No spaces allowed in local part
array('[test]@example.com', false), // Square brackets only allowed within quotes
array('"test\test"@example.com', false), // Quotes cannot contain backslash
array('"test"test"@example.com', false), // Quotes cannot be nested
array('()[]\;:,<>@example.com', false), // Disallowed Characters
array('test@.', false),
array('test@example.', false),
array('test@.org', false),
array('12345678901234567890123456789012345678901234567890123456789012345@example.com', false), // 64 characters is maximum length for local part. This is 65.
array('test@123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012.com', false), // 255 characters is maximum length for domain. This is 256.
array('test@[123.123.123.123', false),
array('test@123.123.123.123]', false),
);
}
/**
* @dataProvider provider
* @param string $input
* @param bool $success
*/
function test1($input, $success) {
$result = mail_isvalid($input);
$this->assertSame($success, $result);
}
}
//Setup VIM: ex: et ts=4 :

View File

@ -73,6 +73,10 @@ class mailer_test extends DokuWikiTest {
}
function test_addresses(){
if (isWindows()) {
$this->markTestSkipped();
}
$mail = new TestMailer();
$mail->to('andi@splitbrain.org');
@ -241,6 +245,7 @@ class mailer_test extends DokuWikiTest {
}
}
$this->assertTrue(true); // avoid being marked as risky for having no assertion
}
function test_simplemailsignature() {

View File

@ -17,7 +17,7 @@ class media_get_from_url_test extends DokuWikiTest {
// remember time stamp
$time = filemtime($local);
clearstatcache(false, $local);
sleep(1);
$this->waitForTick(true);
// fetch again and make sure we got a cache file
$local = media_get_from_URL('http://www.google.com/images/srpr/logo3w.png','png',-1);
@ -77,4 +77,4 @@ class media_get_from_url_test extends DokuWikiTest {
unlink($local);
}
}
}

View File

@ -2,7 +2,7 @@
class pageutils_findnearest_test extends DokuWikiTest {
var $oldAuthAcl;
protected $oldAuthAcl;
function setUp() {
parent::setUp();

View File

@ -4,13 +4,13 @@ class wikifn_test extends DokuWikiTest {
function test_cache_cleaning_cleanToUnclean(){
$this->assertEquals(wikiFN('wiki:',null,false),DOKU_TMP_DATA.'pages/wiki/.txt');
$this->assertEquals(wikiFN('wiki:',null,true),DOKU_TMP_DATA.'pages/wiki.txt');
$this->assertEquals(wikiFN('wiki:',null,false), TestUtils::w2u(DOKU_TMP_DATA.'pages/wiki/.txt'));
$this->assertEquals(wikiFN('wiki:',null,true), TestUtils::w2u(DOKU_TMP_DATA.'pages/wiki.txt'));
}
function test_cache_cleaning_uncleanToClean(){
$this->assertEquals(wikiFN('wiki:',null,true),DOKU_TMP_DATA.'pages/wiki.txt');
$this->assertEquals(wikiFN('wiki:',null,false),DOKU_TMP_DATA.'pages/wiki/.txt');
$this->assertEquals(wikiFN('wiki:',null,true), TestUtils::w2u(DOKU_TMP_DATA.'pages/wiki.txt'));
$this->assertEquals(wikiFN('wiki:',null,false), TestUtils::w2u(DOKU_TMP_DATA.'pages/wiki/.txt'));
}
}

View File

@ -158,20 +158,20 @@ class TestParser {
class TestOfLexer extends DokuWikiTest {
function testNoPatterns() {
$handler = $this->getMock('TestParser');
$handler = $this->createMock('TestParser');
$handler->expects($this->never())->method('accept');
$lexer = new Doku_Lexer($handler);
$this->assertFalse($lexer->parse("abcdef"));
}
function testEmptyPage() {
$handler = $this->getMock('TestParser');
$handler = $this->createMock('TestParser');
$handler->expects($this->never())->method('accept');
$lexer = new Doku_Lexer($handler);
$lexer->addPattern("a+");
$this->assertTrue($lexer->parse(""));
}
function testSinglePattern() {
$handler = $this->getMock('TestParser');
$handler = $this->createMock('TestParser');
$handler->expects($this->at(0))->method('accept')
->with("aaa", DOKU_LEXER_MATCHED, 0)->will($this->returnValue(true));
$handler->expects($this->at(1))->method('accept')
@ -194,7 +194,7 @@ class TestOfLexer extends DokuWikiTest {
$this->assertTrue($lexer->parse("aaaxayyyaxaaaz"));
}
function testMultiplePattern() {
$handler = $this->getMock('TestParser', array('accept'));
$handler = $this->createPartialMock('TestParser', array('accept'));
$target = array("a", "b", "a", "bb", "x", "b", "a", "xxxxxx", "a", "x");
$positions = array(0, 1, 2, 3, 5, 6, 7, 8, 14, 15);
for ($i = 0; $i < count($target); $i++) {
@ -210,7 +210,7 @@ class TestOfLexer extends DokuWikiTest {
class TestOfLexerModes extends DokuWikiTest {
function testIsolatedPattern() {
$handler = $this->getMock('TestParser');
$handler = $this->createMock('TestParser');
$handler->expects($this->at(0))->method('a')
->with("a", DOKU_LEXER_MATCHED,0)->will($this->returnValue(true));
$handler->expects($this->at(1))->method('a')
@ -233,7 +233,7 @@ class TestOfLexerModes extends DokuWikiTest {
$this->assertTrue($lexer->parse("abaabxbaaaxaaaax"));
}
function testModeChange() {
$handler = $this->getMock('TestParser');
$handler = $this->createMock('TestParser');
$handler->expects($this->at(0))->method('a')
->with("a", DOKU_LEXER_MATCHED,0)->will($this->returnValue(true));
$handler->expects($this->at(1))->method('a')
@ -268,7 +268,7 @@ class TestOfLexerModes extends DokuWikiTest {
$this->assertTrue($lexer->parse("abaabaaa:ababbabbba"));
}
function testNesting() {
$handler = $this->getMock('TestParser');
$handler = $this->createMock('TestParser');
$handler->expects($this->at(0))->method('a')
->with("aa", DOKU_LEXER_MATCHED,0)->will($this->returnValue(true));
$handler->expects($this->at(1))->method('a')
@ -301,7 +301,7 @@ class TestOfLexerModes extends DokuWikiTest {
$this->assertTrue($lexer->parse("aabaab(bbabb)aab"));
}
function testSingular() {
$handler = $this->getMock('TestParser');
$handler = $this->createMock('TestParser');
$handler->expects($this->at(0))->method('a')
->with("aa", DOKU_LEXER_MATCHED,0)->will($this->returnValue(true));
$handler->expects($this->at(1))->method('b')
@ -320,7 +320,7 @@ class TestOfLexerModes extends DokuWikiTest {
$this->assertTrue($lexer->parse("aabaaxxbbbxx"));
}
function testUnwindTooFar() {
$handler = $this->getMock('TestParser');
$handler = $this->createMock('TestParser');
$handler->expects($this->at(0))->method('a')
->with("aa", DOKU_LEXER_MATCHED,0)->will($this->returnValue(true));
$handler->expects($this->at(1))->method('a')
@ -335,7 +335,7 @@ class TestOfLexerModes extends DokuWikiTest {
class TestOfLexerHandlers extends DokuWikiTest {
function testModeMapping() {
$handler = $this->getMock('TestParser');
$handler = $this->createMock('TestParser');
$handler->expects($this->at(0))->method('a')
->with("aa", DOKU_LEXER_MATCHED,0)->will($this->returnValue(true));
$handler->expects($this->at(1))->method('a')
@ -376,7 +376,7 @@ class TestOfLexerByteIndices extends DokuWikiTest {
function testIndex() {
$doc = "aaa<file>bcd</file>eee";
$handler = $this->getMock('TestParserByteIndex');
$handler = $this->createMock('TestParserByteIndex');
$handler->expects($this->any())->method('ignore')->will($this->returnValue(true));
$handler->expects($this->at(1))->method('caught')
->with("<file>", DOKU_LEXER_ENTER, strpos($doc,'<file>'))->will($this->returnValue(true));
@ -402,7 +402,7 @@ class TestOfLexerByteIndices extends DokuWikiTest {
function testIndexLookaheadEqual() {
$doc = "aaa<file>bcd</file>eee";
$handler = $this->getMock('TestParserByteIndex');
$handler = $this->createMock('TestParserByteIndex');
$handler->expects($this->any())->method('ignore')->will($this->returnValue(true));
$handler->expects($this->at(1))->method('caught')
->with("<file>", DOKU_LEXER_ENTER, strpos($doc,'<file>'))->will($this->returnValue(true));
@ -428,7 +428,7 @@ class TestOfLexerByteIndices extends DokuWikiTest {
function testIndexLookaheadNotEqual() {
$doc = "aaa<file>bcd</file>eee";
$handler = $this->getMock('TestParserByteIndex');
$handler = $this->createMock('TestParserByteIndex');
$handler->expects($this->any())->method('ignore')->will($this->returnValue(true));
$handler->expects($this->at(1))->method('caught')
->with("<file>", DOKU_LEXER_ENTER, strpos($doc,'<file>'))->will($this->returnValue(true));
@ -454,7 +454,7 @@ class TestOfLexerByteIndices extends DokuWikiTest {
function testIndexLookbehindEqual() {
$doc = "aaa<file>bcd</file>eee";
$handler = $this->getMock('TestParserByteIndex');
$handler = $this->createMock('TestParserByteIndex');
$handler->expects($this->any())->method('ignore')->will($this->returnValue(true));
$handler->expects($this->at(1))->method('caught')
->with("<file>", DOKU_LEXER_ENTER, strpos($doc,'<file>'))->will($this->returnValue(true));
@ -480,7 +480,7 @@ class TestOfLexerByteIndices extends DokuWikiTest {
function testIndexLookbehindNotEqual() {
$doc = "aaa<file>bcd</file>eee";
$handler = $this->getMock('TestParserByteIndex');
$handler = $this->createMock('TestParserByteIndex');
$handler->expects($this->any())->method('ignore')->will($this->returnValue(true));
$handler->expects($this->at(1))->method('caught')
->with("<file>", DOKU_LEXER_ENTER, strpos($doc,'<file>'))->will($this->returnValue(true));
@ -511,7 +511,7 @@ class TestOfLexerByteIndices extends DokuWikiTest {
$doc = "ALL FOOLS ARE FOO";
$pattern = '\bFOO\b';
$handler = $this->getMock('TestParserByteIndex');
$handler = $this->createMock('TestParserByteIndex');
$handler->expects($this->any())->method('ignore')->will($this->returnValue(true));
$matches = array();
@ -527,5 +527,3 @@ class TestOfLexerByteIndices extends DokuWikiTest {
}
}
?>

View File

@ -5,14 +5,16 @@ require_once DOKU_INC . 'inc/parser/handler.php';
abstract class TestOfDoku_Parser extends DokuWikiTest {
var $P;
var $H;
/** @var Doku_Parser */
protected $P;
/** @var Doku_Handler */
protected $H;
function setUp() {
parent::setUp();
$this->P = new Doku_Parser();
$this->H = new Doku_Handler();
$this->P->Handler = & $this->H;
$this->P->Handler = $this->H;
}
function tearDown() {

View File

@ -1,6 +1,11 @@
<?php
require_once 'parser.inc.php';
/**
* Tests for the implementation of link syntax
*
* @group parser_links
*/
class TestOfDoku_Parser_Links extends TestOfDoku_Parser {
function testExternalLinkSimple() {
@ -274,6 +279,36 @@ class TestOfDoku_Parser_Links extends TestOfDoku_Parser {
$this->assertEquals(array_map('stripByteIndex',$this->H->calls),$calls);
}
function testInternalLinkCodeFollows() {
$this->P->addMode('internallink',new Doku_Parser_Mode_InternalLink());
$this->P->parse("Foo [[wiki:internal:link|Test]] Bar <code>command [arg1 [arg2 [arg3]]]</code>");
$calls = array (
array('document_start',array()),
array('p_open',array()),
array('cdata',array("\n".'Foo ')),
array('internallink',array('wiki:internal:link','Test')),
array('cdata',array(' Bar <code>command [arg1 [arg2 [arg3]]]</code>')),
array('p_close',array()),
array('document_end',array()),
);
$this->assertEquals(array_map('stripByteIndex',$this->H->calls),$calls);
}
function testInternalLinkCodeFollows2() {
$this->P->addMode('internallink',new Doku_Parser_Mode_InternalLink());
$this->P->parse("Foo [[wiki:internal:link|[Square brackets in title] Test]] Bar <code>command [arg1 [arg2 [arg3]]]</code>");
$calls = array (
array('document_start',array()),
array('p_open',array()),
array('cdata',array("\n".'Foo ')),
array('internallink',array('wiki:internal:link','[Square brackets in title] Test')),
array('cdata',array(' Bar <code>command [arg1 [arg2 [arg3]]]</code>')),
array('p_close',array()),
array('document_end',array()),
);
$this->assertEquals(array_map('stripByteIndex',$this->H->calls),$calls);
}
function testExternalInInternalLink() {
$this->P->addMode('internallink',new Doku_Parser_Mode_InternalLink());
$this->P->parse("Foo [[http://www.google.com|Google]] Bar");
@ -289,6 +324,54 @@ class TestOfDoku_Parser_Links extends TestOfDoku_Parser {
$this->assertEquals(array_map('stripByteIndex',$this->H->calls),$calls);
}
function testExternalInInternalLink2() {
$this->P->addMode('internallink',new Doku_Parser_Mode_InternalLink());
$this->P->parse("Foo [[http://www.google.com?test[]=squarebracketsinurl|Google]] Bar");
$calls = array (
array('document_start',array()),
array('p_open',array()),
array('cdata',array("\n".'Foo ')),
array('externallink',array('http://www.google.com?test[]=squarebracketsinurl','Google')),
array('cdata',array(' Bar')),
array('p_close',array()),
array('document_end',array()),
);
$this->assertEquals(array_map('stripByteIndex',$this->H->calls),$calls);
}
function testExternalInInternalLink2CodeFollows() {
$this->P->addMode('internallink',new Doku_Parser_Mode_InternalLink());
$this->P->parse("Foo [[http://www.google.com?test[]=squarebracketsinurl|Google]] Bar <code>command [arg1 [arg2 [arg3]]]</code>");
$calls = array (
array('document_start',array()),
array('p_open',array()),
array('cdata',array("\n".'Foo ')),
array('externallink',array('http://www.google.com?test[]=squarebracketsinurl','Google')),
array('cdata',array(' Bar <code>command [arg1 [arg2 [arg3]]]</code>')),
array('p_close',array()),
array('document_end',array()),
);
$this->assertEquals(array_map('stripByteIndex',$this->H->calls),$calls);
}
function testTwoInternalLinks() {
$this->P->addMode('internallink',new Doku_Parser_Mode_InternalLink());
$this->P->parse("Foo [[foo:bar|one]] and [[bar:foo|two]] Bar");
$calls = array (
array('document_start',array()),
array('p_open',array()),
array('cdata',array("\n".'Foo ')),
array('internallink',array('foo:bar','one')),
array('cdata',array(' and ')),
array('internallink',array('bar:foo','two')),
array('cdata',array(' Bar')),
array('p_close',array()),
array('document_end',array()),
);
$this->assertEquals(array_map('stripByteIndex',$this->H->calls),$calls);
}
function testInterwikiLink() {
$this->P->addMode('internallink',new Doku_Parser_Mode_InternalLink());
$this->P->parse("Foo [[iw>somepage|Some Page]] Bar");
@ -393,7 +476,7 @@ class TestOfDoku_Parser_Links extends TestOfDoku_Parser {
);
$this->assertEquals(array_map('stripByteIndex',$this->H->calls),$calls);
}
function testWindowsShareLinkHyphen() {
$this->P->addMode('windowssharelink',new Doku_Parser_Mode_WindowsShareLink());
$this->P->parse('Foo \\\server\share-hyphen Bar');

View File

@ -4,6 +4,7 @@ require_once 'parser.inc.php';
/**
* Tests for the implementation of audio and video files
*
* @group parser_media
* @author Michael Große <grosse@cosmocode.de>
*/
class TestOfDoku_Parser_Media extends TestOfDoku_Parser {
@ -118,12 +119,12 @@ class TestOfDoku_Parser_Media extends TestOfDoku_Parser {
$this->assertNotSame(false, $substr_start, 'Substring not found.');
// find $a_webm in $url
$a_webm = '<a href="' . DOKU_BASE . 'lib/exe/fetch.php?id=&amp;cache=&amp;media=wiki:kind_zu_katze.webm" class="media mediafile mf_webm" title="wiki:kind_zu_katze.webm (99.1&#xa0;KB)">kind_zu_katze.webm</a>';
$a_webm = '<a href="' . DOKU_BASE . 'lib/exe/fetch.php?id=&amp;cache=&amp;media=wiki:kind_zu_katze.webm" class="media mediafile mf_webm" title="wiki:kind_zu_katze.webm (99.1'."\xC2\xA0".'KB)">kind_zu_katze.webm</a>';
$substr_start = strpos($url, $a_webm, $substr_start + strlen($source_ogv));
$this->assertNotSame(false, $substr_start, 'Substring not found.');
// find $a_webm in $url
$a_ogv = '<a href="' . DOKU_BASE . 'lib/exe/fetch.php?id=&amp;cache=&amp;media=wiki:kind_zu_katze.ogv" class="media mediafile mf_ogv" title="wiki:kind_zu_katze.ogv (44.8&#xa0;KB)">kind_zu_katze.ogv</a>';
$a_ogv = '<a href="' . DOKU_BASE . 'lib/exe/fetch.php?id=&amp;cache=&amp;media=wiki:kind_zu_katze.ogv" class="media mediafile mf_ogv" title="wiki:kind_zu_katze.ogv (44.8'."\xC2\xA0".'KB)">kind_zu_katze.ogv</a>';
$substr_start = strpos($url, $a_ogv, $substr_start + strlen($a_webm));
$this->assertNotSame(false, $substr_start, 'Substring not found.');
@ -131,4 +132,64 @@ class TestOfDoku_Parser_Media extends TestOfDoku_Parser {
$substr_start = strlen($url) - strlen($rest);
$this->assertEquals($rest, substr($url, $substr_start));
}
function testSimpleLinkText() {
$file = 'wiki:dokuwiki-128.png';
$parser_response = p_get_instructions('{{' . $file . '|This is a simple text.}}');
$calls = array (
array('document_start',array()),
array('p_open',array()),
array('internalmedia',array($file,'This is a simple text.',null,null,null,'cache','details')),
array('cdata',array(null)),
array('p_close',array()),
array('document_end',array()),
);
$this->assertEquals(array_map('stripbyteindex',$parser_response),$calls);
}
function testLinkTextWithWavedBrackets_1() {
$file = 'wiki:dokuwiki-128.png';
$parser_response = p_get_instructions('{{' . $file . '|We got a { here.}}');
$calls = array (
array('document_start',array()),
array('p_open',array()),
array('internalmedia',array($file,'We got a { here.',null,null,null,'cache','details')),
array('cdata',array(null)),
array('p_close',array()),
array('document_end',array()),
);
$this->assertEquals(array_map('stripbyteindex',$parser_response),$calls);
}
function testLinkTextWithWavedBrackets_2() {
$file = 'wiki:dokuwiki-128.png';
$parser_response = p_get_instructions('{{' . $file . '|We got a } here.}}');
$calls = array (
array('document_start',array()),
array('p_open',array()),
array('internalmedia',array($file,'We got a } here.',null,null,null,'cache','details')),
array('cdata',array(null)),
array('p_close',array()),
array('document_end',array()),
);
$this->assertEquals(array_map('stripbyteindex',$parser_response),$calls);
}
function testLinkTextWithWavedBrackets_3() {
$file = 'wiki:dokuwiki-128.png';
$parser_response = p_get_instructions('{{' . $file . '|We got a { and a } here.}}');
$calls = array (
array('document_start',array()),
array('p_open',array()),
array('internalmedia',array($file,'We got a { and a } here.',null,null,null,'cache','details')),
array('cdata',array(null)),
array('p_close',array()),
array('document_end',array()),
);
$this->assertEquals(array_map('stripbyteindex',$parser_response),$calls);
}
}

View File

@ -0,0 +1,273 @@
<?php
/**
* Class renderer_xhtml_test
*/
class renderer_xhtml_test extends DokuWikiTest {
/** @var Doku_Renderer_xhtml */
protected $R;
/**
* Called for each test
*
* @throws Exception
*/
function setUp() {
parent::setUp();
$this->R = new Doku_Renderer_xhtml();
}
function tearDown() {
unset($this->R);
}
function test_tableopen_0arg() {
$this->R->table_open();
$expected = '<div class="table"><table class="inline">'."\n";
$this->assertEquals($expected, $this->R->doc);
}
function test_tableopen_1arg() {
$this->R->table_open(4);
$expected = '<div class="table"><table class="inline">'."\n";
$this->assertEquals($expected, $this->R->doc);
}
function test_tableopen_2arg() {
$this->R->table_open(4, 4);
$expected = '<div class="table"><table class="inline">'."\n";
$this->assertEquals($expected, $this->R->doc);
}
function test_tableopen_3arg() {
$this->R->table_open(4, 4, 100);
$expected = '<div class="table sectionedit1"><table class="inline">'."\n";
$this->assertEquals($expected, $this->R->doc);
}
function test_tableopen_4arg_str() {
$this->R->table_open(4, 4, 100, 'feature');
$expected = '<div class="table feature sectionedit1"><table class="inline">'."\n";
$this->assertEquals($expected, $this->R->doc);
}
function test_tableopen_4arg_arr() {
$this->R->table_open(4, 4, 100, array('feature', 'test'));
$expected = '<div class="table feature test sectionedit1"><table class="inline">'."\n";
$this->assertEquals($expected, $this->R->doc);
}
function test_table() {
$this->R->table_open(null, null, null, 'feature');
$this->R->tablethead_open();
$this->R->tablerow_open('item');
$this->R->tableheader_open();
$this->R->cdata('header1');
$this->R->tableheader_close();
$this->R->tableheader_open(1, null, 1, 'second');
$this->R->cdata('header2');
$this->R->tableheader_close();
$this->R->tablerow_close();
$this->R->tablethead_close();
$this->R->tabletbody_open();
$this->R->tablerow_open('values');
$this->R->tablecell_open(1, null, 1, 'first value');
$this->R->cdata('cell1,1');
$this->R->tablecell_close();
$this->R->tablecell_open(1, null, 1, 'second');
$this->R->cdata('cell1,2');
$this->R->tablecell_close();
$this->R->tablerow_close();
$this->R->tablerow_open();
$this->R->tablecell_open();
$this->R->cdata('cell2.1');
$this->R->tablecell_close();
$this->R->tablecell_open();
$this->R->cdata('cell2,2');
$this->R->tablecell_close();
$this->R->tablerow_close();
$this->R->tabletbody_close();
$this->R->table_close();
$expected = '<div class="table feature"><table class="inline">
<thead>
<tr class="row0 item">
<th class="col0">header1</th><th class="col1 second">header2</th>
</tr>
</thead>
<tbody>
<tr class="row1 values">
<td class="col0 first value">cell1,1</td><td class="col1 second">cell1,2</td>
</tr>
<tr class="row2">
<td class="col0">cell2.1</td><td class="col1">cell2,2</td>
</tr>
</tbody>
</table></div>
';
$this->assertEquals($expected, $this->R->doc);
}
function test_olist() {
$this->R->document_start();
$this->R->listo_open();
$this->R->listitem_open(1, Doku_Handler_List::NODE);
$this->R->listcontent_open();
$this->R->cdata('item1');
$this->R->listcontent_close();
$this->R->listo_open();
$this->R->listitem_open(2);
$this->R->listcontent_open();
$this->R->cdata('item1b');
$this->R->listcontent_close();
$this->R->listitem_close();
$this->R->listo_close();
$this->R->listitem_close();
$this->R->listitem_open(1);
$this->R->listcontent_open();
$this->R->cdata('item2');
$this->R->listcontent_close();
$this->R->listitem_close();
$this->R->listitem_open(1, Doku_Handler_List::NODE);
$this->R->listcontent_open();
$this->R->cdata('item3');
$this->R->listcontent_close();
$this->R->listo_open('special');
$this->R->listitem_open(2);
$this->R->listcontent_open();
$this->R->cdata('item3b');
$this->R->listcontent_close();
$this->R->listitem_close();
$this->R->listo_close();
$this->R->listitem_close();
$this->R->listo_close();
$this->R->document_end();
$expected = '<ol>
<li class="level1 node"><div class="li">item1</div>
<ol>
<li class="level2"><div class="li">item1b</div>
</li>
</ol>
</li>
<li class="level1"><div class="li">item2</div>
</li>
<li class="level1 node"><div class="li">item3</div>
<ol class="special">
<li class="level2"><div class="li">item3b</div>
</li>
</ol>
</li>
</ol>
';
$this->assertEquals($expected, $this->R->doc);
}
function test_ulist() {
$this->R->document_start();
$this->R->listu_open();
$this->R->listitem_open(1, Doku_Handler_List::NODE);
$this->R->listcontent_open();
$this->R->cdata('item1');
$this->R->listcontent_close();
$this->R->listu_open();
$this->R->listitem_open(2);
$this->R->listcontent_open();
$this->R->cdata('item1b');
$this->R->listcontent_close();
$this->R->listitem_close();
$this->R->listu_close();
$this->R->listitem_close();
$this->R->listitem_open(1);
$this->R->listcontent_open();
$this->R->cdata('item2');
$this->R->listcontent_close();
$this->R->listitem_close();
$this->R->listitem_open(1, Doku_Handler_List::NODE);
$this->R->listcontent_open();
$this->R->cdata('item3');
$this->R->listcontent_close();
$this->R->listu_open('special');
$this->R->listitem_open(2);
$this->R->listcontent_open();
$this->R->cdata('item3b');
$this->R->listcontent_close();
$this->R->listitem_close();
$this->R->listu_close();
$this->R->listitem_close();
$this->R->listu_close();
$this->R->document_end();
$expected = '<ul>
<li class="level1 node"><div class="li">item1</div>
<ul>
<li class="level2"><div class="li">item1b</div>
</li>
</ul>
</li>
<li class="level1"><div class="li">item2</div>
</li>
<li class="level1 node"><div class="li">item3</div>
<ul class="special">
<li class="level2"><div class="li">item3b</div>
</li>
</ul>
</li>
</ul>
';
$this->assertEquals($expected, $this->R->doc);
}
public function test_blankHeader() {
$this->R->header('0', 1, 1);
$expected = '<h1 class="sectionedit1" id="section0">0</h1>';
$this->assertEquals($expected, trim($this->R->doc));
}
public function test_blankTitleLink() {
global $conf;
$id = 'blanktest';
$conf['useheading'] = 1;
saveWikiText($id,'====== 0 ======', 'test');
$this->assertTrue(page_exists($id));
$header = p_get_first_heading($id, METADATA_RENDER_UNLIMITED);
$this->assertSame('0', $header);
$this->R->internallink($id);
$expected = '<a href="/./doku.php?id='.$id.'" class="wikilink1" title="'.$id.'">0</a>';
$this->assertEquals($expected, trim($this->R->doc));
}
}

View File

@ -0,0 +1,83 @@
<?php
/**
* Class parserutils_set_metadata_test
*/
class parserutils_set_metadata_test extends DokuWikiTest {
// the id used for this test case
private $id;
/**
* Set up fake user environment with for the gieven user
*
* @param string $user
*/
function helper_prepare_user($user = '1') {
global $INFO, $USERINFO;
// prepare fake users
static $users = [
'1' => [
'pass' => '179ad45c6ce2cb97cf1029e212046e81',
'name' => 'Tester1',
'mail' => 'tester1@example.com',
'grps' => array('admin', 'user'),
]
,
'tester2' => [
'pass' => '179ad45c6ce2cb97cf1029e212046e81',
'name' => 'Tester2',
'mail' => 'tester2@example.com',
'grps' => array('user'),
]
];
if(!isset($users[$user])) throw new RuntimeException('requested non-existing user');
// set up globals
$_SERVER['REMOTE_ADDR'] = '1.2.3.4';
$USERINFO = $users[$user];
$INFO['userinfo'] = $USERINFO;
$_SERVER['REMOTE_USER'] = $user;
}
/**
* test array merge, including contributors with numeric keys and array data overwritting
*/
function test_array_replace(){
// prepare user
$this->helper_prepare_user('1');
// prepare page
$this->id = 'test:set_metadata_array_replace';
saveWikiText($this->id, 'Test', 'Test data setup');
$meta = p_get_metadata($this->id);
$this->assertEquals('1', $meta['user'], 'Initial page has wrong user ID');
// $this->assertEquals(empty($meta['contributor']), true, 'Initial page should have no contributors');
// first revision with numeric user
$this->waitForTick();
saveWikiText($this->id, 'Test1', 'Test first edit');
$meta = p_get_metadata($this->id);
$last_edit_date = $meta['date']['modified'];
$this->assertEquals(array('1'=>'Tester1'), $meta['contributor'], 'First edit contributors error');
// second revision with alphabetic user
$this->waitForTick();
$this->helper_prepare_user('tester2');
saveWikiText($this->id, 'Test2', 'Test second edit');
$meta = p_get_metadata($this->id);
$this->assertNotEquals($last_edit_date, $meta['date']['modified'], 'First edit date merge error');
$this->assertEquals(array('tester2'=>'Tester2', '1'=>'Tester1'), $meta['contributor'], 'Second edit contributors error');
// third revision with the first user
$this->waitForTick();
$this->helper_prepare_user('1');
saveWikiText($this->id, 'Test3', 'Test third edit');
$meta = p_get_metadata($this->id);
$this->assertEquals(array('tester2'=>'Tester2', '1'=>'Tester1'), $meta['contributor'], 'Third edit contributors error');
}
}

View File

@ -129,10 +129,10 @@ class remote_plugin_testplugin2 extends DokuWiki_Remote_Plugin {
class remote_test extends DokuWikiTest {
var $userinfo;
protected $userinfo;
/** @var RemoteAPI */
var $remote;
protected $remote;
function setUp() {
parent::setUp();
@ -144,7 +144,7 @@ class remote_test extends DokuWikiTest {
parent::setUp();
// mock plugin controller to return our test plugins
$pluginManager = $this->getMock('Doku_Plugin_Controller');
$pluginManager = $this->createMock('Doku_Plugin_Controller');
$pluginManager->method('getList')->willReturn(array('testplugin', 'testplugin2'));
$pluginManager->method('load')->willReturnCallback(
function($type, $plugin) {
@ -256,6 +256,7 @@ class remote_test extends DokuWikiTest {
$conf['remote'] = 1;
$conf['remoteuser'] = '';
$this->remote->forceAccess(); // no exception should occur
$this->assertTrue(true); // avoid being marked as risky for having no assertion
}
/**

View File

@ -11,6 +11,9 @@ class remoteapicore_test extends DokuWikiTest {
protected $remote;
public function setUp() {
// we need a clean setup before each single test:
DokuWikiTest::setUpBeforeClass();
parent::setUp();
global $conf;
global $USERINFO;
@ -28,21 +31,27 @@ class remoteapicore_test extends DokuWikiTest {
}
public function tearDown() {
parent::tearDown();
global $USERINFO;
global $AUTH_ACL;
$USERINFO = $this->userinfo;
$AUTH_ACL = $this->oldAuthAcl;
}
public function test_core() {
/** Delay writes of old revisions by a second. */
public function handle_write(Doku_Event $event, $param) {
if ($event->data[3] !== false) {
$this->waitForTick();
}
}
public function test_getVersion() {
$this->assertEquals(getVersion(), $this->remote->call('dokuwiki.getVersion'));
// $params = array('user', 'passwrd');
// $this->assertEquals(, $remoteApi->call('dokuwiki.login')); //TODO
// $this->assertEquals(, $remoteApi->call('dokuwiki.logoff')); //TODO
}
public function test_getPageList() {
$file1 = wikiFN('wiki:dokuwiki');
$file2 = wikiFN('wiki:syntax');
$expected = array(
@ -70,15 +79,20 @@ class remoteapicore_test extends DokuWikiTest {
)
);
$this->assertEquals($expected, $this->remote->call('dokuwiki.getPagelist', $params));
}
idx_addPage('wiki:syntax'); //full text search depends on index
public function test_search() {
$id = 'wiki:syntax';
$file = wikiFN($id);
idx_addPage($id); //full text search depends on index
$expected = array(
array(
'id' => 'wiki:syntax',
'id' => $id,
'score' => 1,
'rev' => filemtime($file2),
'mtime' => filemtime($file2),
'size' => filesize($file2),
'rev' => filemtime($file),
'mtime' => filemtime($file),
'size' => filesize($file),
'snippet' => ' a footnote)) by using double parentheses.
===== <strong class="search_hit">Sectioning</strong> =====
@ -89,11 +103,15 @@ You can use up to five different levels of',
);
$params = array('Sectioning');
$this->assertEquals($expected, $this->remote->call('dokuwiki.search', $params));
}
public function test_getTime() {
$timeexpect = time();
$timeactual = $this->remote->call('dokuwiki.getTime');
$this->assertTrue(($timeexpect <= $timeactual) && ($timeactual <= $timeexpect + 1));
}
public function test_setLocks() {
$expected = array(
'locked' => array('wiki:dokuwiki', 'wiki:syntax', 'nonexisting'),
'lockfail' => array(),
@ -121,171 +139,316 @@ You can use up to five different levels of',
)
);
$this->assertEquals($expected, $this->remote->call('dokuwiki.setLocks', $params));
}
public function test_getTitle() {
global $conf;
$this->assertEquals($conf['title'], $this->remote->call('dokuwiki.getTitle'));
}
public function test_putPage() {
$id = 'putpage';
$file3 = wikiFN('nice_page');
$content = "====Title====\nText";
$params = array(
'nice_page',
$id,
$content,
array(
'minor' => false,
'sum' => 'Summary of nice text'
)
);
$this->assertEquals(true, $this->remote->call('wiki.putPage', $params)); //TODO check exceptions
$this->assertEquals($content, rawWiki('nice_page'));
$this->assertTrue($this->remote->call('wiki.putPage', $params));
$this->assertEquals($content, rawWiki($id));
$rev[1] = filemtime(wikiFN('nice_page')); //stored for later
sleep(1); // wait for new revision ID
//remove page
$params = array(
$id,
'',
array(
'minor' => false,
)
);
$this->assertTrue($this->remote->call('wiki.putPage', $params));
$this->assertFileNotExists(wikiFN($id));
}
$params = array('nice_page');
public function test_getPage() {
$id = 'getpage';
$content = 'a test';
saveWikiText($id, $content, 'test for getpage');
$params = array($id);
$this->assertEquals($content, $this->remote->call('wiki.getPage', $params));
}
$morecontent = "\nOther text.";
$secondcontent = $content . $morecontent;
$params_append = array(
'nice_page',
public function test_appendPage() {
$id = 'appendpage';
$content = 'a test';
$morecontent = "\nOther text";
saveWikiText($id, $content, 'local');
$params = array(
$id,
$morecontent,
array()
);
$this->assertEquals(true, $this->remote->call('dokuwiki.appendPage', $params_append));
$this->assertEquals($secondcontent, rawWiki('nice_page'));
$this->assertEquals(true, $this->remote->call('dokuwiki.appendPage', $params));
$this->assertEquals($content . $morecontent, rawWiki($id));
}
$params = array('nice_page', '');
$this->assertEquals($secondcontent, $this->remote->call('wiki.getPageVersion', $params));
$params = array('nice_page', $rev[1]);
$this->assertEquals($content, $this->remote->call('wiki.getPageVersion', $params));
$params = array('nice_page', 1234);
$this->assertEquals('', $this->remote->call('wiki.getPageVersion', $params), 'Not existing revision');
$params = array('notexisting', 1234);
$this->assertEquals('', $this->remote->call('wiki.getPageVersion', $params), 'Not existing page');
public function test_getPageVersion() {
$id = 'pageversion';
$file = wikiFN($id);
$html1 = "\n<h3 class=\"sectionedit1\" id=\"title\">Title</h3>\n<div class=\"level3\">\n\n<p>\nText\n";
$html2 = "Other text.\n";
$html3 = "</p>\n\n</div>\n";
$params = array('nice_page');
$this->assertEquals($html1 . $html2 . $html3, $this->remote->call('wiki.getPageHTML', $params));
saveWikiText($id, 'first version', 'first');
$rev1 = filemtime($file);
clearstatcache(false, $file);
$this->waitForTick(true);
saveWikiText($id, 'second version', 'second');
$rev2 = filemtime($file);
$params = array('nice_page', '');
$this->assertEquals($html1 . $html2 . $html3, $this->remote->call('wiki.getPageHTMLVersion', $params));
$params = array('nice_page', $rev[1]);
$this->assertEquals($html1 . $html3, $this->remote->call('wiki.getPageHTMLVersion', $params));
$params = array('nice_page', 1234);
$this->assertEquals('', $this->remote->call('wiki.getPageHTMLVersion', $params));
$params = array($id, '');
$this->assertEquals('second version', $this->remote->call('wiki.getPageVersion', $params), 'no revision given');
$params = array($id, $rev1);
$this->assertEquals('first version', $this->remote->call('wiki.getPageVersion', $params), '1st revision given');
$params = array($id, $rev2);
$this->assertEquals('second version', $this->remote->call('wiki.getPageVersion', $params), '2nd revision given');
$params = array($id, 1234);
$this->assertEquals('', $this->remote->call('wiki.getPageVersion', $params), 'Non existing revision given');
$params = array('foobar', 1234);
$this->assertEquals('', $this->remote->call('wiki.getPageVersion', $params), 'Non existing page given');
}
public function test_getPageHTML() {
$id = 'htmltest';
$content = "====Title====\nText";
$html = "\n<h3 class=\"sectionedit1\" id=\"title\">Title</h3>\n<div class=\"level3\">\n\n<p>\nText\n</p>\n\n</div>\n";
saveWikiText($id, $content, 'htmltest');
$params = array($id);
$this->assertEquals($html, $this->remote->call('wiki.getPageHTML', $params));
}
public function test_getPageHTMLVersion() {
$id = 'htmltest';
$file = wikiFN($id);
$content1 = "====Title====\nText";
$html1 = "\n<h3 class=\"sectionedit1\" id=\"title\">Title</h3>\n<div class=\"level3\">\n\n<p>\nText\n</p>\n\n</div>\n";
$content2 = "====Foobar====\nText Bamm";
$html2 = "\n<h3 class=\"sectionedit1\" id=\"foobar\">Foobar</h3>\n<div class=\"level3\">\n\n<p>\nText Bamm\n</p>\n\n</div>\n";
saveWikiText($id, $content1, 'first');
$rev1 = filemtime($file);
clearstatcache(false, $file);
$this->waitForTick(true);
saveWikiText($id, $content2, 'second');
$rev2 = filemtime($file);
$params = array($id, '');
$this->assertEquals($html2, $this->remote->call('wiki.getPageHTMLVersion', $params), 'no revision given');
$params = array($id, $rev1);
$this->assertEquals($html1, $this->remote->call('wiki.getPageHTMLVersion', $params), '1st revision given');
$params = array($id, $rev2);
$this->assertEquals($html2, $this->remote->call('wiki.getPageHTMLVersion', $params), '2nd revision given');
$params = array($id, 1234);
$this->assertEquals('', $this->remote->call('wiki.getPageHTMLVersion', $params), 'Non existing revision given');
$params = array('foobar', 1234);
$this->assertEquals('', $this->remote->call('wiki.getPageHTMLVersion', $params), 'Non existing page given');
}
public function test_getAllPages() {
// all pages depends on index
idx_addPage('wiki:syntax');
idx_addPage('wiki:dokuwiki');
$file1 = wikiFN('wiki:syntax');
$file2 = wikiFN('wiki:dokuwiki');
$expected = array(
array(
'id' => 'wiki:syntax',
'perms' => 8,
'size' => filesize($file2),
'lastModified' => filemtime($file2)
'size' => filesize($file1),
'lastModified' => filemtime($file1)
),
array(
'id' => 'nice_page',
'id' => 'wiki:dokuwiki',
'perms' => 8,
'size' => filesize($file3),
'lastModified' => filemtime($file3)
'size' => filesize($file2),
'lastModified' => filemtime($file2)
)
);
$this->assertEquals($expected, $this->remote->call('wiki.getAllPages')); //only indexed pages
$this->assertEquals($expected, $this->remote->call('wiki.getAllPages'));
}
public function test_getBacklinks() {
saveWikiText('linky', '[[wiki:syntax]]', 'test');
// backlinks need index
idx_addPage('wiki:syntax');
idx_addPage('linky');
$params = array('wiki:syntax');
$this->assertEquals(ft_backlinks('wiki:syntax'), $this->remote->call('wiki.getBackLinks', $params));
$result = $this->remote->call('wiki.getBackLinks', $params);
$this->assertTrue(count($result) > 0);
$this->assertEquals(ft_backlinks('wiki:syntax'), $result);
}
public function test_getPageInfo() {
$id = 'pageinfo';
$file = wikiFN($id);
saveWikiText($id, 'test', 'test');
$expected = array(
'name' => 'nice_page',
'lastModified' => filemtime($file3),
'name' => $id,
'lastModified' => filemtime($file),
'author' => clientIP(),
'version' => filemtime($file3)
'version' => filemtime($file)
);
$params = array('nice_page');
$params = array($id);
$this->assertEquals($expected, $this->remote->call('wiki.getPageInfo', $params));
}
public function test_getPageInfoVersion() {
$id = 'pageinfo';
$file = wikiFN($id);
saveWikiText($id, 'first version', 'first');
$rev1 = filemtime($file);
clearstatcache(false, $file);
$this->waitForTick(true);
saveWikiText($id, 'second version', 'second');
$rev2 = filemtime($file);
$expected = array(
'name' => 'nice_page',
'lastModified' => $rev[1],
'name' => $id,
'lastModified' => $rev2,
'author' => clientIP(),
'version' => $rev[1]
'version' => $rev2
);
$params = array('nice_page', $rev[1]);
$this->assertEquals($expected, $this->remote->call('wiki.getPageInfoVersion', $params));
$params = array($id, '');
$this->assertEquals($expected, $this->remote->call('wiki.getPageInfoVersion', $params), 'no revision given');
$rev[2] = filemtime(wikiFN('nice_page'));
sleep(1); // wait for new revision ID
$this->remote->call('dokuwiki.appendPage', $params_append);
$rev[3] = filemtime(wikiFN('nice_page'));
sleep(1);
$this->remote->call('dokuwiki.appendPage', $params_append);
$rev[4] = filemtime(wikiFN('nice_page'));
sleep(1);
$this->remote->call('dokuwiki.appendPage', $params_append);
$rev[5] = filemtime(wikiFN('nice_page'));
sleep(1);
$this->remote->call('dokuwiki.appendPage', $params_append);
$rev[6] = filemtime(wikiFN('nice_page'));
sleep(1);
$expected = array(
'name' => $id,
'lastModified' => $rev1,
'author' => clientIP(),
'version' => $rev1
);
$params = array($id, $rev1);
$this->assertEquals($expected, $this->remote->call('wiki.getPageInfoVersion', $params), '1st revision given');
$expected = array(
'name' => $id,
'lastModified' => $rev2,
'author' => clientIP(),
'version' => $rev2
);
$params = array($id, $rev2);
$this->assertEquals($expected, $this->remote->call('wiki.getPageInfoVersion', $params), '2nd revision given');
}
public function test_getRecentChanges() {
saveWikiText('pageone', 'test', 'test');
$rev1 = filemtime(wikiFN('pageone'));
saveWikiText('pagetwo', 'test', 'test');
$rev2 = filemtime(wikiFN('pagetwo'));
$expected = array(
array(
'name' => 'nice_page',
'lastModified' => $rev[6],
'name' => 'pageone',
'lastModified' => $rev1,
'author' => '',
'version' => $rev[6],
'version' => $rev1,
'perms' => 8,
'size' => 78
'size' => 4
),
array(
'name' => 'pagetwo',
'lastModified' => $rev2,
'author' => '',
'version' => $rev2,
'perms' => 8,
'size' => 4
)
);
$params = array(strtotime("-1 year"));
$this->assertEquals($expected, $this->remote->call('wiki.getRecentChanges', $params));
}
$params = array('nice_page', 0);
$versions = $this->remote->call('wiki.getPageVersions', $params);
$this->assertEquals($rev[6], $versions[0]['version']);
$this->assertEquals($rev[5], $versions[1]['version']);
$this->assertEquals($rev[1], $versions[5]['version']);
$this->assertEquals(6, count($this->remote->call('wiki.getPageVersions', $params)));
public function test_getPageVersions() {
/** @var $EVENT_HANDLER Doku_Event_Handler */
global $EVENT_HANDLER;
$EVENT_HANDLER->register_hook('IO_WIKIPAGE_WRITE', 'BEFORE', $this, 'handle_write');
global $conf;
$params = array('nice_page', 1);
$id = 'revpage';
$file = wikiFN($id);
$rev = array();
for($i = 0; $i < 6; $i++) {
$this->waitForTick();
saveWikiText($id, "rev$i", "rev$i");
clearstatcache(false, $file);
$rev[$i] = filemtime($file);
}
$params = array($id, 0);
$versions = $this->remote->call('wiki.getPageVersions', $params);
$this->assertEquals(6, count($versions));
$this->assertEquals($rev[5], $versions[0]['version']);
$this->assertEquals($rev[4], $versions[1]['version']);
$this->assertEquals(5, count($this->remote->call('wiki.getPageVersions', $params)));
$this->assertEquals($rev[3], $versions[2]['version']);
$this->assertEquals($rev[2], $versions[3]['version']);
$this->assertEquals($rev[1], $versions[4]['version']);
$this->assertEquals($rev[0], $versions[5]['version']);
$conf['recent'] = 3; //set number of page returned
$params = array('nice_page', 1);
$this->assertEquals(3, count($this->remote->call('wiki.getPageVersions', $params)));
$params = array('nice_page', $conf['recent']);
$params = array($id, 1); // offset 1
$versions = $this->remote->call('wiki.getPageVersions', $params);
$this->assertEquals($rev[3], $versions[0]['version']); //skips current,1st old,2nd old
$this->assertEquals(3, count($this->remote->call('wiki.getPageVersions', $params)));
$this->assertEquals(5, count($versions));
$this->assertEquals($rev[4], $versions[0]['version']);
$this->assertEquals($rev[3], $versions[1]['version']);
$this->assertEquals($rev[2], $versions[2]['version']);
$this->assertEquals($rev[1], $versions[3]['version']);
$this->assertEquals($rev[0], $versions[4]['version']);
$params = array('nice_page', 2 * $conf['recent']);
$this->assertEquals(0, count($this->remote->call('wiki.getPageVersions', $params)));
$conf['recent'] = 3; //set number of results per page
//remove page
$file3 = wikiFN('nice_page');
$content = "";
$params = array(
'nice_page',
$content,
array(
'minor' => false,
)
);
$this->assertEquals(true, $this->remote->call('wiki.putPage', $params));
$this->assertFalse(file_exists($file3));
$params = array($id, 0); // first page
$versions = $this->remote->call('wiki.getPageVersions', $params);
$this->assertEquals(3, count($versions));
$this->assertEquals($rev[5], $versions[0]['version']);
$this->assertEquals($rev[4], $versions[1]['version']);
$this->assertEquals($rev[3], $versions[2]['version']);
$params = array('nice_page', 0);
$this->assertEquals(2, count($this->remote->call('wiki.getPageVersions', $params)));
$params = array($id, $conf['recent']); // second page
$versions = $this->remote->call('wiki.getPageVersions', $params);
$this->assertEquals(3, count($versions));
$this->assertEquals($rev[2], $versions[0]['version']);
$this->assertEquals($rev[1], $versions[1]['version']);
$this->assertEquals($rev[0], $versions[2]['version']);
$params = array('nice_page', 1);
$this->assertEquals(3, count($this->remote->call('wiki.getPageVersions', $params)));
$params = array($id, $conf['recent'] * 2); // third page
$versions = $this->remote->call('wiki.getPageVersions', $params);
$this->assertEquals(0, count($versions));
}
$params = array('nice_page');
public function test_aclCheck() {
$id = 'aclpage';
$params = array($id);
$this->assertEquals(AUTH_UPLOAD, $this->remote->call('wiki.aclCheck', $params));
global $conf;
@ -298,39 +461,43 @@ You can use up to five different levels of',
'* @user 2', //edit
);
$params = array('nice_page');
$params = array($id);
$this->assertEquals(AUTH_EDIT, $this->remote->call('wiki.aclCheck', $params));
}
public function test_getXMLRPCAPIVersion() {
$this->assertEquals(DOKU_API_VERSION, $this->remote->call('dokuwiki.getXMLRPCAPIVersion'));
}
public function test_getRPCVersionSupported() {
$this->assertEquals(2, $this->remote->call('wiki.getRPCVersionSupported'));
}
public function test_core2() {
public function test_listLinks() {
$localdoku = array(
'type' => 'local',
'page' => 'DokuWiki',
'href' => DOKU_BASE . DOKU_SCRIPT . '?id=DokuWiki'
);
$expected = array( //no local links
$localdoku,
array(
'type' => 'extern',
'page' => 'http://www.freelists.org',
'href' => 'http://www.freelists.org'
),
array(
'type' => 'extern',
'page' => 'https://tools.ietf.org/html/rfc1855',
'href' => 'https://tools.ietf.org/html/rfc1855'
),
array(
'type' => 'extern',
'page' => 'http://www.catb.org/~esr/faqs/smart-questions.html',
'href' => 'http://www.catb.org/~esr/faqs/smart-questions.html'
),
$localdoku,
$localdoku
$localdoku,
array(
'type' => 'extern',
'page' => 'http://www.freelists.org',
'href' => 'http://www.freelists.org'
),
array(
'type' => 'extern',
'page' => 'https://tools.ietf.org/html/rfc1855',
'href' => 'https://tools.ietf.org/html/rfc1855'
),
array(
'type' => 'extern',
'page' => 'http://www.catb.org/~esr/faqs/smart-questions.html',
'href' => 'http://www.catb.org/~esr/faqs/smart-questions.html'
),
$localdoku,
$localdoku
);
$params = array('mailinglist');
$this->assertEquals($expected, $this->remote->call('wiki.listLinks', $params));
@ -368,7 +535,7 @@ You can use up to five different levels of',
);
$this->assertEquals($expected, $this->remote->call('wiki.getRecentMediaChanges', $params));
sleep(1);
$this->waitForTick(true);
$conf['useacl'] = 1;
$_SERVER['REMOTE_USER'] = 'john';
$USERINFO['grps'] = array('user');

View File

@ -5,8 +5,8 @@ if(!defined('UTF8_NOMBSTRING')) define('UTF8_NOMBSTRING',1);
class utf8_utf16be_test extends DokuWikiTest {
// some chars from various code regions
var $utf8 = '鈩ℵŁöx';
var $utf16 = "\x92\x29\x21\x35\x1\x41\x0\xf6\x0\x78";
protected $utf8 = '鈩ℵŁöx';
protected $utf16 = "\x92\x29\x21\x35\x1\x41\x0\xf6\x0\x78";
/**
* Convert from UTF-8 to UTF-16BE

View File

@ -38,10 +38,22 @@ class css_at_import_less_test extends DokuWikiTest {
$this->assertEquals($expected_less, $less);
}
/**
* makes proper relative path to be used in CSS @import
* @param string $path
* @return string
*/
private function importPath($path) {
if (isWindows()) {
return preg_replace('#(^.*[\\\\])#','', $path);
}
return preg_replace('#(^.*[/])#','', $path);
}
public function test_basic() {
$this->setUpFiles();
$import = preg_replace('#(^.*[/])#','',$this->import);
$import = $this->importPath($this->import);
$in_css = '@import "'.$import.'";';
$in_less = '@foo: "bar";
content: @foo;';
@ -56,12 +68,12 @@ content: @foo;';
public function test_subdirectory() {
$this->setUpFiles('/foo/bar');
$import = preg_replace('#(^.*[/])#','',$this->import);
$import = $this->importPath($this->import);
$in_css = '@import "'.$import.'";';
$in_less = '@foo: "bar";
content: @foo;';
$expected_css = '@import "/foo/bar/'.$import.'";';
$expected_css = isWindows() ? '@import "\\foo\\bar/'.$import.'";' : '@import "/foo/bar/'.$import.'";';
$expected_less = 'content: "bar";';
io_saveFile($this->import, $in_less);

View File

@ -77,11 +77,17 @@ class css_css_loadfile_test extends DokuWikiTest {
$this->file = tempnam($dir, 'css');
$this->csstest('@import "test.less"', '@import "/foo/bar/test.less"');
$this->csstest('@import \'test.less\'', '@import \'/foo/bar/test.less\'');
$this->csstest('@import url(test.less)', '@import url(/foo/bar/test.less)');
$this->csstest('@import "abc/test.less"', '@import "/foo/bar/abc/test.less"');
if (isWindows()) {
$this->csstest('@import "test.less"', '@import "\foo\bar/test.less"');
$this->csstest('@import \'test.less\'', '@import \'\foo\bar/test.less\'');
$this->csstest('@import url(test.less)', '@import url(\foo\bar/test.less)');
$this->csstest('@import "abc/test.less"', '@import "\foo\bar/abc/test.less"');
} else {
$this->csstest('@import "test.less"', '@import "/foo/bar/test.less"');
$this->csstest('@import \'test.less\'', '@import \'/foo/bar/test.less\'');
$this->csstest('@import url(test.less)', '@import url(/foo/bar/test.less)');
$this->csstest('@import "abc/test.less"', '@import "/foo/bar/abc/test.less"');
}
}
public function tearDown() {

47
appveyor.yml Normal file
View File

@ -0,0 +1,47 @@
build: false
clone_folder: c:\dokuwiki
max_jobs: 3
platform: x86
pull_requests:
do_not_increment_build_number: true
version: '{build}.{branch}'
environment:
matrix:
- PHP_VERSION: '7.0.21'
VC: 'VC14'
PHPUNIT: '6.3'
- PHP_VERSION: '5.6.30'
VC: 'VC11'
PHPUNIT: '5.7'
cache:
- c:\php -> appveyor.yml
init:
- SET PATH=c:\php\%PHP_VERSION%;%PATH%
install:
- echo %PHP_VERSION%
- IF NOT EXIST c:\php mkdir c:\php
- IF NOT EXIST c:\php\%PHP_VERSION% mkdir c:\php\%PHP_VERSION%
- cd c:\php\%PHP_VERSION%
- IF NOT EXIST php-installed.txt appveyor DownloadFile http://windows.php.net/downloads/releases/archives/php-%PHP_VERSION%-Win32-%VC%-x86.zip
- IF NOT EXIST php-installed.txt 7z x php-%PHP_VERSION%-Win32-%VC%-x86.zip -y >nul
- IF NOT EXIST php-installed.txt del /Q *.zip
- IF NOT EXIST php-installed.txt copy /Y php.ini-development php.ini
- IF NOT EXIST php-installed.txt echo max_execution_time=1200 >> php.ini
- IF NOT EXIST php-installed.txt echo date.timezone="UTC" >> php.ini
- IF NOT EXIST php-installed.txt echo extension_dir=ext >> php.ini
- IF NOT EXIST php-installed.txt echo extension=php_openssl.dll >> php.ini
- IF NOT EXIST php-installed.txt echo extension=php_mbstring.dll >> php.ini
- IF NOT EXIST php-installed.txt echo extension=php_gd2.dll >> php.ini
- IF NOT EXIST php-installed.txt echo extension=php_bz2.dll >> php.ini
- IF NOT EXIST php-installed.txt echo extension=php_pdo_sqlite.dll >> php.ini
- IF NOT EXIST php-installed.txt appveyor DownloadFile https://phar.phpunit.de/phpunit-%PHPUNIT%.phar -FileName phpunit.phar
- IF NOT EXIST php-installed.txt type nul >> php-installed.txt
test_script:
- php -v
- cd c:\dokuwiki\_test
- php c:\php\%PHP_VERSION%\phpunit.phar

View File

@ -1,8 +1,8 @@
#!/usr/bin/php
<?php
if(!defined('DOKU_INC')) define('DOKU_INC', realpath(dirname(__FILE__).'/../').'/');
if(!defined('DOKU_INC')) define('DOKU_INC', realpath(dirname(__FILE__) . '/../') . '/');
define('NOSESSION', 1);
require_once(DOKU_INC.'inc/init.php');
require_once(DOKU_INC . 'inc/init.php');
/**
* Find wanted pages
@ -10,8 +10,13 @@ require_once(DOKU_INC.'inc/init.php');
class WantedPagesCLI extends DokuCLI {
const DIR_CONTINUE = 1;
const DIR_NS = 2;
const DIR_PAGE = 3;
const DIR_NS = 2;
const DIR_PAGE = 3;
private $skip = false;
private $sort = 'wanted';
private $result = array();
/**
* Register options and arguments on the given $options object
@ -21,13 +26,27 @@ class WantedPagesCLI extends DokuCLI {
*/
protected function setup(DokuCLI_Options $options) {
$options->setHelp(
'Outputs a list of wanted pages (pages which have internal links but do not yet exist).'
'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).'
);
$options->registerArgument(
'namespace',
'The namespace to lookup. Defaults to root namespace',
false
);
$options->registerOption(
'sort',
'Sort by wanted or origin page',
's',
'(wanted|origin)'
);
$options->registerOption(
'skip',
'Do not show the second dimension',
'k'
);
}
/**
@ -41,23 +60,30 @@ class WantedPagesCLI extends DokuCLI {
protected function main(DokuCLI_Options $options) {
if($options->args) {
$startdir = dirname(wikiFN($options->args[0].':xxx'));
$startdir = dirname(wikiFN($options->args[0] . ':xxx'));
} else {
$startdir = dirname(wikiFN('xxx'));
}
$this->skip = $options->getOpt('skip');
$this->sort = $options->getOpt('sort');
$this->info("searching $startdir");
$wanted_pages = array();
foreach($this->get_pages($startdir) as $page) {
$wanted_pages = array_merge($wanted_pages, $this->internal_links($page));
$this->internal_links($page);
}
$wanted_pages = array_unique($wanted_pages);
sort($wanted_pages);
foreach($wanted_pages as $page) {
print $page."\n";
ksort($this->result);
foreach($this->result as $main => $subs) {
if($this->skip) {
print "$main\n";
} else {
$subs = array_unique($subs);
sort($subs);
foreach($subs as $sub) {
printf("%-40s %s\n", $main, $sub);
}
}
}
}
@ -72,7 +98,7 @@ class WantedPagesCLI extends DokuCLI {
if($entry == '.' || $entry == '..') {
return WantedPagesCLI::DIR_CONTINUE;
}
if(is_dir($basepath.'/'.$entry)) {
if(is_dir($basepath . '/' . $entry)) {
if(strpos($entry, '_') === 0) {
return WantedPagesCLI::DIR_CONTINUE;
}
@ -95,7 +121,7 @@ class WantedPagesCLI extends DokuCLI {
static $trunclen = null;
if(!$trunclen) {
global $conf;
$trunclen = strlen($conf['datadir'].':');
$trunclen = strlen($conf['datadir'] . ':');
}
if(!is_dir($dir)) {
@ -103,17 +129,17 @@ class WantedPagesCLI extends DokuCLI {
}
$pages = array();
$dh = opendir($dir);
$dh = opendir($dir);
while(false !== ($entry = readdir($dh))) {
$status = $this->dir_filter($entry, $dir);
if($status == WantedPagesCLI::DIR_CONTINUE) {
continue;
} else if($status == WantedPagesCLI::DIR_NS) {
$pages = array_merge($pages, $this->get_pages($dir.'/'.$entry));
$pages = array_merge($pages, $this->get_pages($dir . '/' . $entry));
} else {
$page = array(
'id' => pathID(substr($dir.'/'.$entry, $trunclen)),
'file' => $dir.'/'.$entry,
$page = array(
'id' => pathID(substr($dir . '/' . $entry, $trunclen)),
'file' => $dir . '/' . $entry,
);
$pages[] = $page;
}
@ -123,31 +149,34 @@ class WantedPagesCLI extends DokuCLI {
}
/**
* Parse instructions and returns the non-existing links
* Parse instructions and add the non-existing links to the result array
*
* @param array $page array with page id and file path
* @return array
*/
function internal_links($page) {
global $conf;
$instructions = p_get_instructions(file_get_contents($page['file']));
$links = array();
$cns = getNS($page['id']);
$exists = false;
$cns = getNS($page['id']);
$exists = false;
$pid = $page['id'];
foreach($instructions as $ins) {
if($ins[0] == 'internallink' || ($conf['camelcase'] && $ins[0] == 'camelcaselink')) {
$mid = $ins[1][0];
resolve_pageid($cns, $mid, $exists);
if(!$exists) {
list($mid) = explode('#', $mid); //record pages without hashs
$links[] = $mid;
list($mid) = explode('#', $mid); //record pages without hashes
if($this->sort == 'origin') {
$this->result[$pid][] = $mid;
} else {
$this->result[$mid][] = $pid;
}
}
}
}
return $links;
}
}
// Main
$cli = new WantedPagesCLI();
$cli->run();
$cli->run();

View File

@ -1,6 +1,23 @@
{
"name": "splitbrain/dokuwiki",
"description": "DokuWiki is a simple to use and highly versatile Open Source wiki software that doesn't require a database",
"homepage": "https://www.dokuwiki.org",
"type": "project",
"license": "GPL v2",
"require": {
"php": ">=5.6",
"splitbrain/php-archive": "~1.0",
"easybook/geshi": "~1.0"
}
"phpseclib/phpseclib": "~2.0",
"paragonie/random_compat": "^2.0",
"simplepie/simplepie": "^1.4",
"geshi/geshi": "^1.0",
"openpsa/universalfeedcreator": "^1.8",
"aziraphale/email-address-validator": "^2",
"marcusschwarz/lesserphp": "^0.5.1"
},
"suggest": {
"squizlabs/php_codesniffer": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.",
"phpunit/phpunit": "Allows automated tests to be run without system-wide install."
},
"prefer-stable": true
}

407
composer.lock generated
View File

@ -4,66 +4,401 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically"
],
"hash": "23ee0dd06136e2301c930e75055300d5",
"content-hash": "149ef96a4cadb6765aac9e7c6a2b5b17",
"packages": [
{
"name": "easybook/geshi",
"version": "v1.0.8.17",
"name": "aziraphale/email-address-validator",
"version": "2.0.1",
"source": {
"type": "git",
"url": "https://github.com/easybook/geshi.git",
"reference": "0fced4f530c0a1726588651f04c2bf2a3073c9c0"
"url": "https://github.com/aziraphale/email-address-validator.git",
"reference": "fa25bc22c1c0b6491657c91473fae3e40719a650"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/easybook/geshi/zipball/0fced4f530c0a1726588651f04c2bf2a3073c9c0",
"reference": "0fced4f530c0a1726588651f04c2bf2a3073c9c0",
"url": "https://api.github.com/repos/aziraphale/email-address-validator/zipball/fa25bc22c1c0b6491657c91473fae3e40719a650",
"reference": "fa25bc22c1c0b6491657c91473fae3e40719a650",
"shasum": ""
},
"require": {
"php": ">4.3.0"
"require-dev": {
"phpunit/phpunit": "^5.7"
},
"type": "library",
"autoload": {
"psr-0": {
"EmailAddressValidator": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Dave Child",
"email": "dave@addedbytes.com"
},
{
"name": "Andrew Gillard",
"email": "andrew@lorddeath.net"
}
],
"description": "Fork of AddedBytes' PHP EmailAddressValidator script, now with Composer support!",
"homepage": "https://github.com/aziraphale/email-address-validator",
"time": "2017-05-22T14:05:57+00:00"
},
{
"name": "geshi/geshi",
"version": "v1.0.9.0",
"source": {
"type": "git",
"url": "https://github.com/GeSHi/geshi-1.0.git",
"reference": "5a7b461338d322d941986a656d4d1651452e73dd"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/GeSHi/geshi-1.0/zipball/5a7b461338d322d941986a656d4d1651452e73dd",
"reference": "5a7b461338d322d941986a656d4d1651452e73dd",
"shasum": ""
},
"require-dev": {
"phpunit/phpunit": "^5.7"
},
"type": "library",
"autoload": {
"classmap": [
"./"
"src/geshi/",
"src/geshi.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"GPL-2.0"
"GPL-2.0+"
],
"authors": [
{
"name": "Nigel McNie",
"email": "nigel@geshi.org"
},
{
"name": "Benny Baumann",
"email": "BenBE@geshi.org"
"email": "BenBE@geshi.org",
"homepage": "http://blog.benny-baumann.de/",
"role": "Developer"
}
],
"description": "GeSHi - Generic Syntax Highlighter. This is an unmodified port of GeSHi project code found on SourceForge.",
"homepage": "http://qbnz.com/highlighter",
"keywords": [
"highlight",
"highlighter",
"syntax"
],
"time": "2016-03-29 13:15:17"
"description": "Generic Syntax Highlighter",
"homepage": "http://qbnz.com/highlighter/",
"time": "2017-05-05T05:51:25+00:00"
},
{
"name": "splitbrain/php-archive",
"version": "1.0.7",
"name": "marcusschwarz/lesserphp",
"version": "v0.5.1",
"source": {
"type": "git",
"url": "https://github.com/splitbrain/php-archive.git",
"reference": "c075304b44c4aadff0718af445e86bf730f331ff"
"url": "https://github.com/MarcusSchwarz/lesserphp.git",
"reference": "e9e3d53980c0e486b07c75e12f2bae5e10bdee44"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/splitbrain/php-archive/zipball/c075304b44c4aadff0718af445e86bf730f331ff",
"reference": "c075304b44c4aadff0718af445e86bf730f331ff",
"url": "https://api.github.com/repos/MarcusSchwarz/lesserphp/zipball/e9e3d53980c0e486b07c75e12f2bae5e10bdee44",
"reference": "e9e3d53980c0e486b07c75e12f2bae5e10bdee44",
"shasum": ""
},
"require-dev": {
"phpunit/phpunit": "~4.3"
},
"bin": [
"plessc"
],
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "0.5.1-dev"
}
},
"autoload": {
"classmap": [
"lessc.inc.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT",
"GPL-3.0"
],
"authors": [
{
"name": "Leaf Corcoran",
"email": "leafot@gmail.com",
"homepage": "http://leafo.net"
},
{
"name": "Marcus Schwarz",
"email": "github@maswaba.de",
"homepage": "https://www.maswaba.de"
}
],
"description": "lesserphp is a compiler for LESS written in PHP based on leafo's lessphp.",
"homepage": "http://leafo.net/lessphp/",
"time": "2016-09-30T11:13:18+00:00"
},
{
"name": "openpsa/universalfeedcreator",
"version": "v1.8.3",
"source": {
"type": "git",
"url": "https://github.com/flack/UniversalFeedCreator.git",
"reference": "6261e130446d8f787bbfd229a602fb11e6816a4e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/flack/UniversalFeedCreator/zipball/6261e130446d8f787bbfd229a602fb11e6816a4e",
"reference": "6261e130446d8f787bbfd229a602fb11e6816a4e",
"shasum": ""
},
"require": {
"php": ">=5.0"
},
"require-dev": {
"phpunit/phpunit": "*"
},
"type": "library",
"autoload": {
"classmap": [
"lib"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"LGPL"
],
"authors": [
{
"name": "Andreas Flack",
"email": "flack@contentcontrol-berlin.de",
"homepage": "http://www.contentcontrol-berlin.de/"
}
],
"description": "RSS and Atom feed generator by Kai Blankenhorn",
"keywords": [
"atom",
"georss",
"gpx",
"opml",
"pie",
"rss"
],
"time": "2017-05-18T08:28:48+00:00"
},
{
"name": "paragonie/random_compat",
"version": "v2.0.10",
"source": {
"type": "git",
"url": "https://github.com/paragonie/random_compat.git",
"reference": "634bae8e911eefa89c1abfbf1b66da679ac8f54d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/paragonie/random_compat/zipball/634bae8e911eefa89c1abfbf1b66da679ac8f54d",
"reference": "634bae8e911eefa89c1abfbf1b66da679ac8f54d",
"shasum": ""
},
"require": {
"php": ">=5.2.0"
},
"require-dev": {
"phpunit/phpunit": "4.*|5.*"
},
"suggest": {
"ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes."
},
"type": "library",
"autoload": {
"files": [
"lib/random.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Paragon Initiative Enterprises",
"email": "security@paragonie.com",
"homepage": "https://paragonie.com"
}
],
"description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7",
"keywords": [
"csprng",
"pseudorandom",
"random"
],
"time": "2017-03-13T16:27:32+00:00"
},
{
"name": "phpseclib/phpseclib",
"version": "2.0.6",
"source": {
"type": "git",
"url": "https://github.com/phpseclib/phpseclib.git",
"reference": "34a7699e6f31b1ef4035ee36444407cecf9f56aa"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/34a7699e6f31b1ef4035ee36444407cecf9f56aa",
"reference": "34a7699e6f31b1ef4035ee36444407cecf9f56aa",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
"require-dev": {
"phing/phing": "~2.7",
"phpunit/phpunit": "~4.0",
"sami/sami": "~2.0",
"squizlabs/php_codesniffer": "~2.0"
},
"suggest": {
"ext-gmp": "Install the GMP (GNU Multiple Precision) extension in order to speed up arbitrary precision integer arithmetic operations.",
"ext-libsodium": "SSH2/SFTP can make use of some algorithms provided by the libsodium-php extension.",
"ext-mcrypt": "Install the Mcrypt extension in order to speed up a few other cryptographic operations.",
"ext-openssl": "Install the OpenSSL extension in order to speed up a wide variety of cryptographic operations."
},
"type": "library",
"autoload": {
"files": [
"phpseclib/bootstrap.php"
],
"psr-4": {
"phpseclib\\": "phpseclib/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Jim Wigginton",
"email": "terrafrost@php.net",
"role": "Lead Developer"
},
{
"name": "Patrick Monnerat",
"email": "pm@datasphere.ch",
"role": "Developer"
},
{
"name": "Andreas Fischer",
"email": "bantu@phpbb.com",
"role": "Developer"
},
{
"name": "Hans-Jürgen Petrich",
"email": "petrich@tronic-media.com",
"role": "Developer"
},
{
"name": "Graham Campbell",
"email": "graham@alt-three.com",
"role": "Developer"
}
],
"description": "PHP Secure Communications Library - Pure-PHP implementations of RSA, AES, SSH2, SFTP, X.509 etc.",
"homepage": "http://phpseclib.sourceforge.net",
"keywords": [
"BigInteger",
"aes",
"asn.1",
"asn1",
"blowfish",
"crypto",
"cryptography",
"encryption",
"rsa",
"security",
"sftp",
"signature",
"signing",
"ssh",
"twofish",
"x.509",
"x509"
],
"time": "2017-06-05T06:31:10+00:00"
},
{
"name": "simplepie/simplepie",
"version": "1.5",
"source": {
"type": "git",
"url": "https://github.com/simplepie/simplepie.git",
"reference": "5de5551953f95feef12cf355a7a26a70f94aa3ab"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/simplepie/simplepie/zipball/5de5551953f95feef12cf355a7a26a70f94aa3ab",
"reference": "5de5551953f95feef12cf355a7a26a70f94aa3ab",
"shasum": ""
},
"require": {
"php": ">=5.3.0"
},
"require-dev": {
"phpunit/phpunit": "~4 || ~5"
},
"suggest": {
"mf2/mf2": "Microformat module that allows for parsing HTML for microformats"
},
"type": "library",
"autoload": {
"psr-0": {
"SimplePie": "library"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Ryan Parman",
"homepage": "http://ryanparman.com/",
"role": "Creator, alumnus developer"
},
{
"name": "Geoffrey Sneddon",
"homepage": "http://gsnedders.com/",
"role": "Alumnus developer"
},
{
"name": "Ryan McCue",
"email": "me@ryanmccue.info",
"homepage": "http://ryanmccue.info/",
"role": "Developer"
}
],
"description": "A simple Atom/RSS parsing library for PHP",
"homepage": "http://simplepie.org/",
"keywords": [
"atom",
"feeds",
"rss"
],
"time": "2017-04-17T07:29:31+00:00"
},
{
"name": "splitbrain/php-archive",
"version": "1.0.9",
"source": {
"type": "git",
"url": "https://github.com/splitbrain/php-archive.git",
"reference": "2a63b8cf0bfc7fdc0d987c9b7348e639e55cce76"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/splitbrain/php-archive/zipball/2a63b8cf0bfc7fdc0d987c9b7348e639e55cce76",
"reference": "2a63b8cf0bfc7fdc0d987c9b7348e639e55cce76",
"shasum": ""
},
"require": {
@ -72,6 +407,10 @@
"require-dev": {
"phpunit/phpunit": "4.5.*"
},
"suggest": {
"ext-iconv": "Used for proper filename encode handling",
"ext-mbstring": "Can be used alternatively for handling filename encoding"
},
"type": "library",
"autoload": {
"psr-4": {
@ -97,15 +436,17 @@
"unzip",
"zip"
],
"time": "2015-08-12 13:24:34"
"time": "2017-06-11T06:11:38+00:00"
}
],
"packages-dev": [],
"aliases": [],
"minimum-stability": "stable",
"stability-flags": [],
"prefer-stable": false,
"prefer-stable": true,
"prefer-lowest": false,
"platform": [],
"platform": {
"php": ">=5.6"
},
"platform-dev": []
}

View File

@ -158,6 +158,7 @@ $conf['readdircache'] = 0; //time cache in second for the readdir
/* Network Settings */
$conf['dnslookups'] = 1; //disable to disallow IP to hostname lookups
$conf['jquerycdn'] = 0; //use a CDN for delivering jQuery?
// Proxy setup - if your Server needs a proxy to access the web set these
$conf['proxy']['host'] = '';
$conf['proxy']['port'] = '';

View File

@ -6,5 +6,5 @@
#
# Format:
#
# login:passwordhash:Real Name:email:groups,comma,seperated
# login:passwordhash:Real Name:email:groups,comma,separated

View File

@ -2,6 +2,28 @@
# but were removed later. An up to date DokuWiki should not have any of
# the files installed
# remove in 2017-02-19
inc/SimplePie.php
inc/Tar.class.php
inc/ZipLib.class.php
inc/phpseclib/Crypt_AES.php
inc/phpseclib/Crypt_Rijndael.php
inc/phpseclib/update.sh
inc/phpseclib/LICENSE
inc/phpseclib/Crypt_Base.php
inc/phpseclib/Crypt_Hash.php
inc/phpseclib/Math_BigInteger.php
lib/scripts/jquery/jquery-migrate.js
lib/scripts/jquery/jquery-ui-theme/images/ui-bg_flat_0_aaaaaa_40x100.png
lib/scripts/jquery/jquery-ui-theme/images/ui-bg_flat_75_ffffff_40x100.png
lib/scripts/jquery/jquery-ui.js
lib/scripts/jquery/jquery.js
lib/tpl/dokuwiki/css/_admin.css
# removed in 2016-06-26
inc/cliopts.php
lib/tpl/dokuwiki/css/mixins.less
# removed in 2015-08-10
inc/TarLib.class.php
inc/geshi.php

View File

@ -96,9 +96,9 @@ $lang['js']['nosmblinks'] = '';
You can also use an image to link to another internal or external page by combining the syntax for links and [[#images_and_other_files|images]] (see below) like this:
[[http://www.php.net|{{wiki:dokuwiki-128.png}}]]
[[http://php.net|{{wiki:dokuwiki-128.png}}]]
[[http://www.php.net|{{wiki:dokuwiki-128.png}}]]
[[http://php.net|{{wiki:dokuwiki-128.png}}]]
Please note: The image formatting is the only formatting syntax accepted in link names.
@ -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: {{http://de3.php.net/images/php.gif?200x50}}
Resized external image: {{http://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: {{http://de3.php.net/images/php.gif?200x50}}
Resized external image: {{http://php.net/images/php.gif?200x50}}
By using left or right whitespaces you can choose the alignment.
@ -416,7 +416,7 @@ class HelloWorldApp {
}
</code>
The following language strings are currently recognized: //4cs, 6502acme, 6502kickass, 6502tasm, 68000devpac, abap, actionscript-french, actionscript, actionscript3, ada, algol68, apache, applescript, asm, asp, autoconf, autohotkey, autoit, avisynth, awk, bascomavr, bash, basic4gl, bf, bibtex, blitzbasic, bnf, boo, c, c_loadrunner, c_mac, caddcl, cadlisp, cfdg, cfm, chaiscript, cil, clojure, cmake, cobol, coffeescript, cpp, cpp-qt, csharp, css, cuesheet, d, dcs, delphi, diff, div, dos, dot, e, epc, ecmascript, eiffel, email, erlang, euphoria, f1, falcon, fo, fortran, freebasic, fsharp, gambas, genero, genie, gdb, glsl, gml, gnuplot, go, groovy, gettext, gwbasic, haskell, hicest, hq9plus, html, html5, icon, idl, ini, inno, intercal, io, j, java5, java, javascript, jquery, kixtart, klonec, klonecpp, latex, lb, lisp, llvm, locobasic, logtalk, lolcode, lotusformulas, lotusscript, lscript, lsl2, lua, m68k, magiksf, make, mapbasic, matlab, mirc, modula2, modula3, mmix, mpasm, mxml, mysql, newlisp, nsis, oberon2, objc, objeck, ocaml-brief, ocaml, oobas, oracle8, oracle11, oxygene, oz, pascal, pcre, perl, perl6, per, pf, php-brief, php, pike, pic16, pixelbender, pli, plsql, postgresql, povray, powerbuilder, powershell, proftpd, progress, prolog, properties, providex, purebasic, pycon, python, q, qbasic, rails, rebol, reg, robots, rpmspec, rsplus, ruby, sas, scala, scheme, scilab, sdlbasic, smalltalk, smarty, sql, systemverilog, tcl, teraterm, text, thinbasic, tsql, typoscript, unicon, uscript, vala, vbnet, vb, verilog, vhdl, vim, visualfoxpro, visualprolog, whitespace, winbatch, whois, xbasic, xml, xorg_conf, xpp, yaml, z80, zxbasic//
The following language strings are currently recognized: //4cs 6502acme 6502kickass 6502tasm 68000devpac abap actionscript3 actionscript ada aimms algol68 apache applescript apt_sources arm asm asp asymptote autoconf autohotkey autoit avisynth awk bascomavr bash basic4gl batch bf biblatex bibtex blitzbasic bnf boo caddcl cadlisp ceylon cfdg cfm chaiscript chapel cil c_loadrunner clojure c_mac cmake cobol coffeescript c cpp cpp-qt cpp-winapi csharp css cuesheet c_winapi dart dcl dcpu16 dcs delphi diff div dos dot d ecmascript eiffel email epc e erlang euphoria ezt f1 falcon fo fortran freebasic freeswitch fsharp gambas gdb genero genie gettext glsl gml gnuplot go groovy gwbasic haskell haxe hicest hq9plus html html4strict html5 icon idl ini inno intercal io ispfpanel java5 java javascript jcl j jquery julia kixtart klonec klonecpp kotlin latex lb ldif lisp llvm locobasic logtalk lolcode lotusformulas lotusscript lscript lsl2 lua m68k magiksf make mapbasic mathematica matlab mercury metapost mirc mk-61 mmix modula2 modula3 mpasm mxml mysql nagios netrexx newlisp nginx nimrod nsis oberon2 objc objeck ocaml-brief ocaml octave oobas oorexx oracle11 oracle8 oxygene oz parasail parigp pascal pcre perl6 perl per pf phix php-brief php pic16 pike pixelbender pli plsql postgresql postscript povray powerbuilder powershell proftpd progress prolog properties providex purebasic pycon pys60 python qbasic qml q racket rails rbs rebol reg rexx robots rpmspec rsplus ruby rust sas sass scala scheme scilab scl sdlbasic smalltalk smarty spark sparql sql standardml stonescript swift systemverilog tclegg tcl teraterm texgraph text thinbasic tsql twig typoscript unicon upc urbi uscript vala vbnet vb vbscript vedit verilog vhdl vim visualfoxpro visualprolog whitespace whois winbatch xbasic xml xojo xorg_conf xpp yaml z80 zxbasic//
==== Downloadable Code Blocks ====

View File

@ -9,7 +9,7 @@
*/
// update message version - always use a string to avoid localized floats!
$updateVersion = "48";
$updateVersion = "50";
// xdebug_start_profiling();
@ -62,7 +62,7 @@ if($DATE_AT) {
} else { // check for UNIX Timestamp
$date_parse = @date('Ymd',$DATE_AT);
if(!$date_parse || $date_parse === '19700101') {
msg(sprintf($lang['unable_to_parse_date'], $DATE_AT));
msg(sprintf($lang['unable_to_parse_date'], hsc($DATE_AT)));
$DATE_AT = null;
}
}

View File

@ -51,7 +51,7 @@ if($cache->useCache($depends)) {
}
// create new feed
$rss = new DokuWikiFeedCreator();
$rss = new UniversalFeedCreator();
$rss->title = $conf['title'].(($opt['namespace']) ? ' '.$opt['namespace'] : '');
$rss->link = DOKU_URL;
$rss->syndicationURL = DOKU_URL.'feed.php';
@ -85,7 +85,7 @@ if(isset($modes[$opt['feed_mode']])) {
}
rss_buildItems($rss, $data, $opt);
$feed = $rss->createFeed($opt['feed_type'], 'utf-8');
$feed = $rss->createFeed($opt['feed_type']);
// save cachefile
$cache->storeCache($feed);
@ -402,34 +402,30 @@ function rss_buildItems(&$rss, &$data, $opt) {
// add user
# FIXME should the user be pulled from metadata as well?
$user = @$ditem['user']; // the @ spares time repeating lookup
$item->author = '';
if($user && $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;
}
if($userInfo && !$opt['guardmail']) {
$item->authorEmail = $userInfo['mail'];
} else {
//cannot obfuscate because some RSS readers may check validity
$item->authorEmail = $user.'@'.$ditem['ip'];
}
} elseif($user) {
// this happens when no ACL but some Apache auth is used
$item->author = $user;
$item->authorEmail = $user.'@'.$ditem['ip'];
if(blank($user)) {
$item->author = 'Anonymous';
$item->authorEmail = 'anonymous@undisclosed.example.com';
} else {
$item->authorEmail = 'anonymous@'.$ditem['ip'];
$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

View File

@ -0,0 +1,25 @@
<?php
namespace dokuwiki\Action;
use dokuwiki\Action\Exception\ActionAclRequiredException;
/**
* Class AbstractAclAction
*
* An action that requires the ACL subsystem to be enabled (eg. useacl=1)
*
* @package dokuwiki\Action
*/
abstract class AbstractAclAction extends AbstractAction {
/** @inheritdoc */
public function checkPermissions() {
parent::checkPermissions();
global $conf;
global $auth;
if(!$conf['useacl']) throw new ActionAclRequiredException();
if(!$auth) throw new ActionAclRequiredException();
}
}

View File

@ -0,0 +1,88 @@
<?php
namespace dokuwiki\Action;
use dokuwiki\Action\Exception\ActionDisabledException;
use dokuwiki\Action\Exception\ActionException;
use dokuwiki\Action\Exception\FatalException;
/**
* Class AbstractAction
*
* Base class for all actions
*
* @package dokuwiki\Action
*/
abstract class AbstractAction {
/** @var string holds the name of the action (lowercase class name, no namespace) */
protected $actionname;
/**
* AbstractAction constructor.
*
* @param string $actionname the name of this action (see getActionName() for caveats)
*/
public function __construct($actionname = '') {
if($actionname !== '') {
$this->actionname = $actionname;
} else {
// http://stackoverflow.com/a/27457689/172068
$this->actionname = strtolower(substr(strrchr(get_class($this), '\\'), 1));
}
}
/**
* Return the minimum permission needed
*
* This needs to return one of the AUTH_* constants. It will be checked against
* the current user and page after checkPermissions() ran through. If it fails,
* the user will be shown the Denied action.
*
* @return int
*/
abstract public function minimumPermission();
/**
* Check permissions are correct to run this action
*
* @throws ActionException
* @return void
*/
public function checkPermissions() {
}
/**
* Process data
*
* This runs before any output is sent to the browser.
*
* Throw an Exception if a different action should be run after this step.
*
* @throws ActionException
* @return void
*/
public function preProcess() {
}
/**
* Output whatever content is wanted within tpl_content();
*
* @fixme we may want to return a Ui class here
*/
public function tplContent() {
throw new FatalException('No content for Action ' . $this->actionname);
}
/**
* Returns the name of this action
*
* This is usually the lowercased class name, but may differ for some actions.
* eg. the export_ modes or for the Plugin action.
*
* @return string
*/
public function getActionName() {
return $this->actionname;
}
}

View File

@ -0,0 +1,28 @@
<?php
namespace dokuwiki\Action;
use dokuwiki\Action\Exception\FatalException;
/**
* Class AbstractAliasAction
*
* An action that is an alias for another action. Skips the minimumPermission check
*
* Be sure to implement preProcess() and throw an ActionAbort exception
* with the proper action.
*
* @package dokuwiki\Action
*/
abstract class AbstractAliasAction extends AbstractAction {
/** @inheritdoc */
public function minimumPermission() {
return AUTH_NONE;
}
public function preProcess() {
throw new FatalException('Alias Actions need to implement preProcess to load the aliased action');
}
}

View File

@ -0,0 +1,25 @@
<?php
namespace dokuwiki\Action;
use dokuwiki\Action\Exception\ActionUserRequiredException;
/**
* Class AbstractUserAction
*
* An action that requires a logged in user
*
* @package dokuwiki\Action
*/
abstract class AbstractUserAction extends AbstractAclAction {
/** @inheritdoc */
public function checkPermissions() {
parent::checkPermissions();
global $INPUT;
if(!$INPUT->server->str('REMOTE_USER')) {
throw new ActionUserRequiredException();
}
}
}

56
inc/Action/Admin.php Normal file
View File

@ -0,0 +1,56 @@
<?php
namespace dokuwiki\Action;
use dokuwiki\Action\Exception\ActionException;
/**
* Class Admin
*
* Action to show the admin interface or admin plugins
*
* @package dokuwiki\Action
*/
class Admin extends AbstractUserAction {
/** @inheritdoc */
public function minimumPermission() {
global $INFO;
if($INFO['ismanager']) {
return AUTH_READ; // let in check later
} else {
return AUTH_ADMIN;
}
}
public function checkPermissions() {
parent::checkPermissions();
global $INFO;
if(!$INFO['ismanager']) {
throw new ActionException('denied');
}
}
public function preProcess() {
global $INPUT;
global $INFO;
// retrieve admin plugin name from $_REQUEST['page']
if(($page = $INPUT->str('page', '', true)) != '') {
/** @var $plugin \DokuWiki_Admin_Plugin */
if($plugin = plugin_getRequestAdminPlugin()) { // FIXME this method does also permission checking
if($plugin->forAdminOnly() && !$INFO['isadmin']) {
throw new ActionException('denied');
}
$plugin->handle();
}
}
}
public function tplContent() {
tpl_admin();
}
}

24
inc/Action/Backlink.php Normal file
View File

@ -0,0 +1,24 @@
<?php
namespace dokuwiki\Action;
/**
* Class Backlink
*
* Shows which pages link to the current page
*
* @package dokuwiki\Action
*/
class Backlink extends AbstractAction {
/** @inheritdoc */
public function minimumPermission() {
return AUTH_NONE;
}
/** @inheritdoc */
public function tplContent() {
html_backlinks();
}
}

21
inc/Action/Cancel.php Normal file
View File

@ -0,0 +1,21 @@
<?php
namespace dokuwiki\Action;
use dokuwiki\Action\Exception\ActionAbort;
/**
* Class Cancel
*
* Alias for show. Aborts editing
*
* @package dokuwiki\Action
*/
class Cancel extends AbstractAliasAction {
public function preProcess() {
// continue with draftdel -> redirect -> show
throw new ActionAbort('draftdel');
}
}

26
inc/Action/Check.php Normal file
View File

@ -0,0 +1,26 @@
<?php
namespace dokuwiki\Action;
use dokuwiki\Action\Exception\ActionAbort;
/**
* Class Check
*
* Adds some debugging info before aborting to show
*
* @package dokuwiki\Action
*/
class Check extends AbstractAction {
/** @inheritdoc */
public function minimumPermission() {
return AUTH_READ;
}
public function preProcess() {
check();
throw new ActionAbort();
}
}

34
inc/Action/Conflict.php Normal file
View File

@ -0,0 +1,34 @@
<?php
namespace dokuwiki\Action;
/**
* Class Conflict
*
* Show the conflict resolution screen
*
* @package dokuwiki\Action
*/
class Conflict extends AbstractAction {
/** @inheritdoc */
public function minimumPermission() {
global $INFO;
if($INFO['exists']) {
return AUTH_EDIT;
} else {
return AUTH_CREATE;
}
}
public function tplContent() {
global $PRE;
global $TEXT;
global $SUF;
global $SUM;
html_conflict(con($PRE, $TEXT, $SUF), $SUM);
html_diff(con($PRE, $TEXT, $SUF), false);
}
}

23
inc/Action/Denied.php Normal file
View File

@ -0,0 +1,23 @@
<?php
namespace dokuwiki\Action;
/**
* Class Denied
*
* Show the access denied screen
*
* @package dokuwiki\Action
*/
class Denied extends AbstractAclAction {
/** @inheritdoc */
public function minimumPermission() {
return AUTH_NONE;
}
public function tplContent() {
html_denied();
}
}

35
inc/Action/Diff.php Normal file
View File

@ -0,0 +1,35 @@
<?php
namespace dokuwiki\Action;
/**
* Class Diff
*
* Show the differences between two revisions
*
* @package dokuwiki\Action
*/
class Diff extends AbstractAction {
/** @inheritdoc */
public function minimumPermission() {
return AUTH_READ;
}
/** @inheritdoc */
public function preProcess() {
global $INPUT;
// store the selected diff type in cookie
$difftype = $INPUT->str('difftype');
if(!empty($difftype)) {
set_doku_pref('difftype', $difftype);
}
}
/** @inheritdoc */
public function tplContent() {
html_diff();
}
}

39
inc/Action/Draft.php Normal file
View File

@ -0,0 +1,39 @@
<?php
namespace dokuwiki\Action;
use dokuwiki\Action\Exception\ActionException;
/**
* Class Draft
*
* Screen to see and recover a draft
*
* @package dokuwiki\Action
* @fixme combine with Recover?
*/
class Draft extends AbstractAction {
/** @inheritdoc */
public function minimumPermission() {
global $INFO;
if($INFO['exists']) {
return AUTH_EDIT;
} else {
return AUTH_CREATE;
}
}
/** @inheritdoc */
public function checkPermissions() {
parent::checkPermissions();
global $INFO;
if(!file_exists($INFO['draft'])) throw new ActionException('edit');
}
/** @inheritdoc */
public function tplContent() {
html_draft();
}
}

36
inc/Action/Draftdel.php Normal file
View File

@ -0,0 +1,36 @@
<?php
namespace dokuwiki\Action;
use dokuwiki\Action\Exception\ActionAbort;
/**
* Class Draftdel
*
* Delete a draft
*
* @package dokuwiki\Action
*/
class Draftdel extends AbstractAction {
/** @inheritdoc */
public function minimumPermission() {
return AUTH_EDIT;
}
/**
* Delete an existing draft if any
*
* Reads draft information from $INFO. Redirects to show, afterwards.
*
* @throws ActionAbort
*/
public function preProcess() {
global $INFO;
@unlink($INFO['draft']);
$INFO['draft'] = null;
throw new ActionAbort('redirect');
}
}

91
inc/Action/Edit.php Normal file
View File

@ -0,0 +1,91 @@
<?php
namespace dokuwiki\Action;
use dokuwiki\Action\Exception\ActionAbort;
/**
* Class Edit
*
* Handle editing
*
* @package dokuwiki\Action
*/
class Edit extends AbstractAction {
/** @inheritdoc */
public function minimumPermission() {
global $INFO;
if($INFO['exists']) {
return AUTH_READ; // we check again below
} else {
return AUTH_CREATE;
}
}
/**
* @inheritdoc falls back to 'source' if page not writable
*/
public function checkPermissions() {
parent::checkPermissions();
global $INFO;
// no edit permission? view source
if($INFO['exists'] && !$INFO['writable']) {
throw new ActionAbort('source');
}
}
/** @inheritdoc */
public function preProcess() {
global $ID;
global $INFO;
global $TEXT;
global $RANGE;
global $PRE;
global $SUF;
global $REV;
global $SUM;
global $lang;
global $DATE;
if(!isset($TEXT)) {
if($INFO['exists']) {
if($RANGE) {
list($PRE, $TEXT, $SUF) = rawWikiSlices($RANGE, $ID, $REV);
} else {
$TEXT = rawWiki($ID, $REV);
}
} else {
$TEXT = pageTemplate($ID);
}
}
//set summary default
if(!$SUM) {
if($REV) {
$SUM = sprintf($lang['restored'], dformat($REV));
} elseif(!$INFO['exists']) {
$SUM = $lang['created'];
}
}
// Use the date of the newest revision, not of the revision we edit
// This is used for conflict detection
if(!$DATE) $DATE = @filemtime(wikiFN($ID));
//check if locked by anyone - if not lock for my self
$lockedby = checklock($ID);
if($lockedby) {
throw new ActionAbort('locked');
};
lock($ID);
}
/** @inheritdoc */
public function tplContent() {
html_edit();
}
}

View File

@ -0,0 +1,20 @@
<?php
namespace dokuwiki\Action\Exception;
/**
* Class ActionAbort
*
* Strictly speaking not an Exception but an expected execution path. Used to
* signal when one action is done and another should take over.
*
* If you want to signal the same but under some error condition use ActionException
* or one of it's decendants.
*
* The message will NOT be shown to the enduser
*
* @package dokuwiki\Action\Exception
*/
class ActionAbort extends ActionException {
}

View File

@ -0,0 +1,17 @@
<?php
namespace dokuwiki\Action\Exception;
/**
* Class ActionAclRequiredException
*
* Thrown by AbstractACLAction when an action requires that the ACL subsystem is
* enabled but it isn't. You should not use it
*
* The message will NOT be shown to the enduser
*
* @package dokuwiki\Action\Exception
*/
class ActionAclRequiredException extends ActionException {
}

View File

@ -0,0 +1,17 @@
<?php
namespace dokuwiki\Action\Exception;
/**
* Class ActionDisabledException
*
* Thrown when the requested action has been disabled. Eg. through the 'disableactions'
* config setting. You should probably not use it.
*
* The message will NOT be shown to the enduser, but a generic information will be shown.
*
* @package dokuwiki\Action\Exception
*/
class ActionDisabledException extends ActionException {
}

View File

@ -0,0 +1,66 @@
<?php
namespace dokuwiki\Action\Exception;
/**
* Class ActionException
*
* This exception and its subclasses signal that the current action should be
* aborted and a different action should be used instead. The new action can
* be given as parameter in the constructor. Defaults to 'show'
*
* The message will NOT be shown to the enduser
*
* @package dokuwiki\Action\Exception
*/
class ActionException extends \Exception {
/** @var string the new action */
protected $newaction;
/** @var bool should the exception's message be shown to the user? */
protected $displayToUser = false;
/**
* ActionException constructor.
*
* When no new action is given 'show' is assumed. For requests that originated in a POST,
* a 'redirect' is used which will cause a redirect to the 'show' action.
*
* @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 = '') {
global $INPUT;
parent::__construct($message);
if(is_null($newaction)) {
if(strtolower($INPUT->server->str('REQUEST_METHOD')) == 'post') {
$newaction = 'redirect';
} else {
$newaction = 'show';
}
}
$this->newaction = $newaction;
}
/**
* Returns the action to use next
*
* @return string
*/
public function getNewAction() {
return $this->newaction;
}
/**
* Should this Exception's message be shown to the user?
*
* @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;
return $set;
}
}

View File

@ -0,0 +1,17 @@
<?php
namespace dokuwiki\Action\Exception;
/**
* Class ActionUserRequiredException
*
* Thrown by AbstractUserAction when an action requires that a user is logged
* in but it isn't. You should not use it.
*
* The message will NOT be shown to the enduser
*
* @package dokuwiki\Action\Exception
*/
class ActionUserRequiredException extends ActionException {
}

View File

@ -0,0 +1,29 @@
<?php
namespace dokuwiki\Action\Exception;
/**
* Class FatalException
*
* A fatal exception during handling the action
*
* Will abort all handling and display some info to the user. The HTTP status code
* can be defined.
*
* @package dokuwiki\Action\Exception
*/
class FatalException extends \Exception {
protected $status;
/**
* FatalException constructor.
*
* @param string $message the message to send
* @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) {
parent::__construct($message, $status, $previous);
}
}

View File

@ -0,0 +1,15 @@
<?php
namespace dokuwiki\Action\Exception;
/**
* Class NoActionException
*
* Thrown in the ActionRouter when a wanted action can not be found. Triggers
* the unknown action event
*
* @package dokuwiki\Action\Exception
*/
class NoActionException extends \Exception {
}

112
inc/Action/Export.php Normal file
View File

@ -0,0 +1,112 @@
<?php
namespace dokuwiki\Action;
use dokuwiki\Action\Exception\ActionAbort;
/**
* Class Export
*
* Handle exporting by calling the appropriate renderer
*
* @package dokuwiki\Action
*/
class Export extends AbstractAction {
/** @inheritdoc */
public function minimumPermission() {
return AUTH_READ;
}
/**
* Export a wiki page for various formats
*
* Triggers ACTION_EXPORT_POSTPROCESS
*
* Event data:
* data['id'] -- page id
* data['mode'] -- requested export mode
* data['headers'] -- export headers
* data['output'] -- export output
*
* @author Andreas Gohr <andi@splitbrain.org>
* @author Michael Klier <chi@chimeric.de>
* @inheritdoc
*/
public function preProcess() {
global $ID;
global $REV;
global $conf;
global $lang;
$pre = '';
$post = '';
$headers = array();
// search engines: never cache exported docs! (Google only currently)
$headers['X-Robots-Tag'] = 'noindex';
$mode = substr($this->actionname, 7);
switch($mode) {
case 'raw':
$headers['Content-Type'] = 'text/plain; charset=utf-8';
$headers['Content-Disposition'] = 'attachment; filename=' . noNS($ID) . '.txt';
$output = rawWiki($ID, $REV);
break;
case 'xhtml':
$pre .= '<!DOCTYPE html>' . DOKU_LF;
$pre .= '<html lang="' . $conf['lang'] . '" dir="' . $lang['direction'] . '">' . DOKU_LF;
$pre .= '<head>' . DOKU_LF;
$pre .= ' <meta charset="utf-8" />' . DOKU_LF; // FIXME improve wrapper
$pre .= ' <title>' . $ID . '</title>' . DOKU_LF;
// get metaheaders
ob_start();
tpl_metaheaders();
$pre .= ob_get_clean();
$pre .= '</head>' . DOKU_LF;
$pre .= '<body>' . DOKU_LF;
$pre .= '<div class="dokuwiki export">' . DOKU_LF;
// get toc
$pre .= tpl_toc(true);
$headers['Content-Type'] = 'text/html; charset=utf-8';
$output = p_wiki_xhtml($ID, $REV, false);
$post .= '</div>' . DOKU_LF;
$post .= '</body>' . DOKU_LF;
$post .= '</html>' . DOKU_LF;
break;
case 'xhtmlbody':
$headers['Content-Type'] = 'text/html; charset=utf-8';
$output = p_wiki_xhtml($ID, $REV, false);
break;
default:
$output = p_cached_output(wikiFN($ID, $REV), $mode, $ID);
$headers = p_get_metadata($ID, "format $mode");
break;
}
// prepare event data
$data = array();
$data['id'] = $ID;
$data['mode'] = $mode;
$data['headers'] = $headers;
$data['output'] =& $output;
trigger_event('ACTION_EXPORT_POSTPROCESS', $data);
if(!empty($data['output'])) {
if(is_array($data['headers'])) foreach($data['headers'] as $key => $val) {
header("$key: $val");
}
print $pre . $data['output'] . $post;
exit;
}
throw new ActionAbort();
}
}

25
inc/Action/Index.php Normal file
View File

@ -0,0 +1,25 @@
<?php
namespace dokuwiki\Action;
/**
* Class Index
*
* Show the human readable sitemap. Do not confuse with Sitemap
*
* @package dokuwiki\Action
*/
class Index extends AbstractAction {
/** @inheritdoc */
public function minimumPermission() {
return AUTH_NONE;
}
/** @inheritdoc */
public function tplContent() {
global $IDX;
html_index($IDX);
}
}

24
inc/Action/Locked.php Normal file
View File

@ -0,0 +1,24 @@
<?php
namespace dokuwiki\Action;
/**
* Class Locked
*
* Show a locked screen when a page is locked
*
* @package dokuwiki\Action
*/
class Locked extends AbstractAction {
/** @inheritdoc */
public function minimumPermission() {
return AUTH_READ;
}
/** @inheritdoc */
public function tplContent() {
html_locked();
}
}

36
inc/Action/Login.php Normal file
View File

@ -0,0 +1,36 @@
<?php
namespace dokuwiki\Action;
use dokuwiki\Action\Exception\ActionException;
/**
* Class Login
*
* The login form. Actual logins are handled in inc/auth.php
*
* @package dokuwiki\Action
*/
class Login extends AbstractAclAction {
/** @inheritdoc */
public function minimumPermission() {
return AUTH_NONE;
}
/** @inheritdoc */
public function checkPermissions() {
global $INPUT;
parent::checkPermissions();
if($INPUT->server->has('REMOTE_USER')) {
// nothing to do
throw new ActionException();
}
}
/** @inheritdoc */
public function tplContent() {
html_login();
}
}

50
inc/Action/Logout.php Normal file
View File

@ -0,0 +1,50 @@
<?php
namespace dokuwiki\Action;
use dokuwiki\Action\Exception\ActionDisabledException;
use dokuwiki\Action\Exception\ActionException;
/**
* Class Logout
*
* Log out a user
*
* @package dokuwiki\Action
*/
class Logout extends AbstractUserAction {
/** @inheritdoc */
public function minimumPermission() {
return AUTH_NONE;
}
/** @inheritdoc */
public function checkPermissions() {
parent::checkPermissions();
/** @var \DokuWiki_Auth_Plugin $auth */
global $auth;
if(!$auth->canDo('logout')) throw new ActionDisabledException();
}
/** @inheritdoc */
public function preProcess() {
global $ID;
global $INPUT;
// when logging out during an edit session, unlock the page
$lockedby = checklock($ID);
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')));
// should never be reached
throw new ActionException('login');
}
}

24
inc/Action/Media.php Normal file
View File

@ -0,0 +1,24 @@
<?php
namespace dokuwiki\Action;
/**
* Class Media
*
* The full screen media manager
*
* @package dokuwiki\Action
*/
class Media extends AbstractAction {
/** @inheritdoc */
public function minimumPermission() {
return AUTH_READ;
}
/** @inheritdoc */
public function tplContent() {
tpl_media();
}
}

32
inc/Action/Plugin.php Normal file
View File

@ -0,0 +1,32 @@
<?php
namespace dokuwiki\Action;
/**
* Class Plugin
*
* Used to run action plugins
*
* @package dokuwiki\Action
*/
class Plugin extends AbstractAction {
/** @inheritdoc */
public function minimumPermission() {
return AUTH_NONE;
}
/**
* Outputs nothing but a warning unless an action plugin overwrites it
*
* @inheritdoc
* @triggers TPL_ACT_UNKNOWN
*/
public function tplContent() {
$evt = new \Doku_Event('TPL_ACT_UNKNOWN', $this->actionname);
if($evt->advise_before()) {
msg('Failed to handle action: ' . hsc($this->actionname), -1);
}
$evt->advise_after();
}
}

58
inc/Action/Preview.php Normal file
View File

@ -0,0 +1,58 @@
<?php
namespace dokuwiki\Action;
/**
* Class Preview
*
* preview during editing
*
* @package dokuwiki\Action
*/
class Preview extends Edit {
/** @inheritdoc */
public function preProcess() {
header('X-XSS-Protection: 0');
$this->savedraft();
parent::preProcess();
}
/** @inheritdoc */
public function tplContent() {
global $TEXT;
html_edit();
html_show($TEXT);
}
/**
* Saves a draft on preview
*/
protected function savedraft() {
global $INFO;
global $ID;
global $INPUT;
global $conf;
if(!$conf['usedraft']) return;
if(!$INPUT->post->has('wikitext')) return;
// ensure environment (safeguard when used via AJAX)
assert(isset($INFO['client']), 'INFO.client should have been set');
assert(isset($ID), 'ID should have been set');
$draft = array(
'id' => $ID,
'prefix' => substr($INPUT->post->str('prefix'), 0, -1),
'text' => $INPUT->post->str('wikitext'),
'suffix' => $INPUT->post->str('suffix'),
'date' => $INPUT->post->int('date'),
'client' => $INFO['client'],
);
$cname = getCacheName($draft['client'] . $ID, '.draft');
if(io_saveFile($cname, serialize($draft))) {
$INFO['draft'] = $cname;
}
}
}

45
inc/Action/Profile.php Normal file
View File

@ -0,0 +1,45 @@
<?php
namespace dokuwiki\Action;
use dokuwiki\Action\Exception\ActionAbort;
use dokuwiki\Action\Exception\ActionDisabledException;
/**
* Class Profile
*
* Handle the profile form
*
* @package dokuwiki\Action
*/
class Profile extends AbstractUserAction {
/** @inheritdoc */
public function minimumPermission() {
return AUTH_NONE;
}
/** @inheritdoc */
public function checkPermissions() {
parent::checkPermissions();
/** @var \DokuWiki_Auth_Plugin $auth */
global $auth;
if(!$auth->canDo('Profile')) throw new ActionDisabledException();
}
/** @inheritdoc */
public function preProcess() {
global $lang;
if(updateprofile()) {
msg($lang['profchanged'], 1);
throw new ActionAbort('show');
}
}
/** @inheritdoc */
public function tplContent() {
html_updateprofile();
}
}

View File

@ -0,0 +1,42 @@
<?php
namespace dokuwiki\Action;
use dokuwiki\Action\Exception\ActionAbort;
use dokuwiki\Action\Exception\ActionDisabledException;
/**
* Class ProfileDelete
*
* Delete a user account
*
* @package dokuwiki\Action
*/
class ProfileDelete extends AbstractUserAction {
/** @inheritdoc */
public function minimumPermission() {
return AUTH_NONE;
}
/** @inheritdoc */
public function checkPermissions() {
parent::checkPermissions();
/** @var \DokuWiki_Auth_Plugin $auth */
global $auth;
if(!$auth->canDo('delUser')) throw new ActionDisabledException();
}
/** @inheritdoc */
public function preProcess() {
global $lang;
if(auth_deleteprofile()) {
msg($lang['profdeleted'], 1);
throw new ActionAbort('show');
} else {
throw new ActionAbort('profile');
}
}
}

34
inc/Action/Recent.php Normal file
View File

@ -0,0 +1,34 @@
<?php
namespace dokuwiki\Action;
/**
* Class Recent
*
* The recent changes view
*
* @package dokuwiki\Action
*/
class Recent extends AbstractAction {
/** @inheritdoc */
public function minimumPermission() {
return AUTH_NONE;
}
/** @inheritdoc */
public function preProcess() {
global $INPUT;
$show_changes = $INPUT->str('show_changes');
if(!empty($show_changes)) {
set_doku_pref('show_changes', $show_changes);
}
}
/** @inheritdoc */
public function tplContent() {
global $INPUT;
html_recent((int) $INPUT->extract('first')->int('first'));
}
}

21
inc/Action/Recover.php Normal file
View File

@ -0,0 +1,21 @@
<?php
namespace dokuwiki\Action;
use dokuwiki\Action\Exception\ActionAbort;
/**
* Class Recover
*
* Recover a draft
*
* @package dokuwiki\Action
*/
class Recover extends AbstractAliasAction {
/** @inheritdoc */
public function preProcess() {
throw new ActionAbort('edit');
}
}

64
inc/Action/Redirect.php Normal file
View File

@ -0,0 +1,64 @@
<?php
namespace dokuwiki\Action;
use dokuwiki\Action\Exception\ActionAbort;
/**
* Class Redirect
*
* Used to redirect to the current page with the last edited section as a target if found
*
* @package dokuwiki\Action
*/
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() {
global $PRE;
global $TEXT;
global $INPUT;
global $ID;
global $ACT;
$opts = array(
'id' => $ID,
'preact' => $ACT
);
//get section name when coming from section edit
if($INPUT->has('hid')) {
// Use explicitly transmitted header id
$opts['fragment'] = $INPUT->str('hid');
} else if($PRE && preg_match('/^\s*==+([^=\n]+)/', $TEXT, $match)) {
// Fallback to old mechanism
$check = false; //Byref
$opts['fragment'] = sectionID($match[0], $check);
}
// execute the redirect
trigger_event('ACTION_SHOW_REDIRECT', $opts, array($this, 'redirect'));
// should never be reached
throw new ActionAbort();
}
/**
* Execute the redirect
*
* Default action for ACTION_SHOW_REDIRECT
*
* @param array $opts id and fragment for the redirect and the preact
*/
public function redirect($opts) {
$go = wl($opts['id'], '', true);
if(isset($opts['fragment'])) $go .= '#' . $opts['fragment'];
//show it
send_redirect($go);
}
}

45
inc/Action/Register.php Normal file
View File

@ -0,0 +1,45 @@
<?php
namespace dokuwiki\Action;
use dokuwiki\Action\Exception\ActionAbort;
use dokuwiki\Action\Exception\ActionDisabledException;
/**
* Class Register
*
* Self registering a new user
*
* @package dokuwiki\Action
*/
class Register extends AbstractAclAction {
/** @inheritdoc */
public function minimumPermission() {
return AUTH_NONE;
}
/** @inheritdoc */
public function checkPermissions() {
parent::checkPermissions();
/** @var \DokuWiki_Auth_Plugin $auth */
global $auth;
global $conf;
if(isset($conf['openregister']) && !$conf['openregister']) throw new ActionDisabledException();
if(!$auth->canDo('addUser')) throw new ActionDisabledException();
}
/** @inheritdoc */
public function preProcess() {
if(register()) { // FIXME could be moved from auth to here
throw new ActionAbort('login');
}
}
/** @inheritdoc */
public function tplContent() {
html_register();
}
}

172
inc/Action/Resendpwd.php Normal file
View File

@ -0,0 +1,172 @@
<?php
namespace dokuwiki\Action;
use dokuwiki\Action\Exception\ActionAbort;
use dokuwiki\Action\Exception\ActionDisabledException;
/**
* Class Resendpwd
*
* Handle password recovery
*
* @package dokuwiki\Action
*/
class Resendpwd extends AbstractAclAction {
/** @inheritdoc */
public function minimumPermission() {
return AUTH_NONE;
}
/** @inheritdoc */
public function checkPermissions() {
parent::checkPermissions();
/** @var \DokuWiki_Auth_Plugin $auth */
global $auth;
global $conf;
if(isset($conf['resendpasswd']) && !$conf['resendpasswd']) throw new ActionDisabledException(); //legacy option
if(!$auth->canDo('modPass')) throw new ActionDisabledException();
}
/** @inheritdoc */
public function preProcess() {
if($this->resendpwd()) {
throw new ActionAbort('login');
}
}
/**
* Send a new password
*
* This function handles both phases of the password reset:
*
* - handling the first request of password reset
* - validating the password reset auth token
*
* @author Benoit Chesneau <benoit@bchesneau.info>
* @author Chris Smith <chris@jalakai.co.uk>
* @author Andreas Gohr <andi@splitbrain.org>
* @fixme this should be split up into multiple methods
* @return bool true on success, false on any error
*/
protected function resendpwd() {
global $lang;
global $conf;
/* @var \DokuWiki_Auth_Plugin $auth */
global $auth;
global $INPUT;
if(!actionOK('resendpwd')) {
msg($lang['resendna'], -1);
return false;
}
$token = preg_replace('/[^a-f0-9]+/', '', $INPUT->str('pwauth'));
if($token) {
// we're in token phase - get user info from token
$tfile = $conf['cachedir'] . '/' . $token{0} . '/' . $token . '.pwauth';
if(!file_exists($tfile)) {
msg($lang['resendpwdbadauth'], -1);
$INPUT->remove('pwauth');
return false;
}
// token is only valid for 3 days
if((time() - filemtime($tfile)) > (3 * 60 * 60 * 24)) {
msg($lang['resendpwdbadauth'], -1);
$INPUT->remove('pwauth');
@unlink($tfile);
return false;
}
$user = io_readfile($tfile);
$userinfo = $auth->getUserData($user, $requireGroups = false);
if(!$userinfo['mail']) {
msg($lang['resendpwdnouser'], -1);
return false;
}
if(!$conf['autopasswd']) { // we let the user choose a password
$pass = $INPUT->str('pass');
// password given correctly?
if(!$pass) return false;
if($pass != $INPUT->str('passchk')) {
msg($lang['regbadpass'], -1);
return false;
}
// change it
if(!$auth->triggerUserMod('modify', array($user, array('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)))) {
msg($lang['proffail'], -1);
return false;
}
if(auth_sendPassword($user, $pass)) {
msg($lang['resendpwdsuccess'], 1);
} else {
msg($lang['regmailfail'], -1);
}
}
@unlink($tfile);
return true;
} else {
// we're in request phase
if(!$INPUT->post->bool('save')) return false;
if(!$INPUT->post->str('login')) {
msg($lang['resendpwdmissing'], -1);
return false;
} else {
$user = trim($auth->cleanUser($INPUT->post->str('login')));
}
$userinfo = $auth->getUserData($user, $requireGroups = false);
if(!$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, '&');
io_saveFile($tfile, $user);
$text = rawLocale('pwconfirm');
$trep = array(
'FULLNAME' => $userinfo['name'],
'LOGIN' => $user,
'CONFIRM' => $url
);
$mail = new \Mailer();
$mail->to($userinfo['name'] . ' <' . $userinfo['mail'] . '>');
$mail->subject($lang['regpwmail']);
$mail->setBody($text, $trep);
if($mail->send()) {
msg($lang['resendpwdconfirm'], 1);
} else {
msg($lang['regmailfail'], -1);
}
return true;
}
// never reached
}
}

65
inc/Action/Revert.php Normal file
View File

@ -0,0 +1,65 @@
<?php
namespace dokuwiki\Action;
use dokuwiki\Action\Exception\ActionAbort;
use dokuwiki\Action\Exception\ActionException;
/**
* Class Revert
*
* Quick revert to an old revision
*
* @package dokuwiki\Action
*/
class Revert extends AbstractAction {
/** @inheritdoc */
public function minimumPermission() {
global $INFO;
if($INFO['ismanager']) {
return AUTH_EDIT;
} else {
return AUTH_ADMIN;
}
}
/**
*
* @inheritdoc
* @throws ActionAbort
* @throws ActionException
* @todo check for writability of the current page ($INFO might do it wrong and check the attic version)
*/
public function preProcess() {
if(!checkSecurityToken()) throw new ActionException();
global $ID;
global $REV;
global $lang;
// when no revision is given, delete current one
// FIXME this feature is not exposed in the GUI currently
$text = '';
$sum = $lang['deleted'];
if($REV) {
$text = rawWiki($ID, $REV);
if(!$text) throw new ActionException(); //something went wrong
$sum = sprintf($lang['restored'], dformat($REV));
}
// spam check
if(checkwordblock($text)) {
msg($lang['wordblock'], -1);
throw new ActionException('edit');
}
saveWikiText($ID, $text, $sum, false);
msg($sum, 1);
$REV = '';
// continue with draftdel -> redirect -> show
throw new ActionAbort('draftdel');
}
}

24
inc/Action/Revisions.php Normal file
View File

@ -0,0 +1,24 @@
<?php
namespace dokuwiki\Action;
/**
* Class Revisions
*
* Show the list of old revisions of the current page
*
* @package dokuwiki\Action
*/
class Revisions extends AbstractAction {
/** @inheritdoc */
public function minimumPermission() {
return AUTH_READ;
}
/** @inheritdoc */
public function tplContent() {
global $INPUT;
html_revisions($INPUT->int('first'));
}
}

60
inc/Action/Save.php Normal file
View File

@ -0,0 +1,60 @@
<?php
namespace dokuwiki\Action;
use dokuwiki\Action\Exception\ActionAbort;
use dokuwiki\Action\Exception\ActionException;
/**
* Class Save
*
* Save at the end of an edit session
*
* @package dokuwiki\Action
*/
class Save extends AbstractAction {
/** @inheritdoc */
public function minimumPermission() {
global $INFO;
if($INFO['exists']) {
return AUTH_EDIT;
} else {
return AUTH_CREATE;
}
}
/** @inheritdoc */
public function preProcess() {
if(!checkSecurityToken()) throw new ActionException('preview');
global $ID;
global $DATE;
global $PRE;
global $TEXT;
global $SUF;
global $SUM;
global $lang;
global $INFO;
global $INPUT;
//spam check
if(checkwordblock()) {
msg($lang['wordblock'], -1);
throw new ActionException('edit');
}
//conflict check
if($DATE != 0 && $INFO['meta']['date']['modified'] > $DATE) {
throw new ActionException('conflict');
}
//save it
saveWikiText($ID, con($PRE, $TEXT, $SUF, true), $SUM, $INPUT->bool('minor')); //use pretty mode for con
//unlock it
unlock($ID);
// continue with draftdel -> redirect -> show
throw new ActionAbort('draftdel');
}
}

37
inc/Action/Search.php Normal file
View File

@ -0,0 +1,37 @@
<?php
namespace dokuwiki\Action;
use dokuwiki\Action\Exception\ActionAbort;
/**
* Class Search
*
* Search for pages and content
*
* @package dokuwiki\Action
*/
class Search extends AbstractAction {
/** @inheritdoc */
public function minimumPermission() {
return AUTH_NONE;
}
/**
* we only search if a search word was given
*
* @inheritdoc
*/
public function checkPermissions() {
parent::checkPermissions();
global $QUERY;
$s = cleanID($QUERY);
if($s === '') throw new ActionAbort();
}
/** @inheritdoc */
public function tplContent() {
html_search();
}
}

30
inc/Action/Show.php Normal file
View File

@ -0,0 +1,30 @@
<?php
/**
* Created by IntelliJ IDEA.
* User: andi
* Date: 2/10/17
* Time: 4:32 PM
*/
namespace dokuwiki\Action;
/**
* Class Show
*
* The default action of showing a page
*
* @package dokuwiki\Action
*/
class Show extends AbstractAction {
/** @inheritdoc */
public function minimumPermission() {
return AUTH_READ;
}
/** @inheritdoc */
public function tplContent() {
html_show();
}
}

65
inc/Action/Sitemap.php Normal file
View File

@ -0,0 +1,65 @@
<?php
namespace dokuwiki\Action;
use dokuwiki\Action\Exception\FatalException;
/**
* Class Sitemap
*
* Generate an XML sitemap for search engines. Do not confuse with Index
*
* @package dokuwiki\Action
*/
class Sitemap extends AbstractAction {
/** @inheritdoc */
public function minimumPermission() {
return AUTH_NONE;
}
/**
* Handle sitemap delivery
*
* @author Michael Hamann <michael@content-space.de>
* @throws FatalException
* @inheritdoc
*/
public function preProcess() {
global $conf;
if($conf['sitemap'] < 1 || !is_numeric($conf['sitemap'])) {
throw new FatalException(404, 'Sitemap generation is disabled');
}
$sitemap = \Sitemapper::getFilePath();
if(\Sitemapper::sitemapIsCompressed()) {
$mime = 'application/x-gzip';
} else {
$mime = 'application/xml; charset=utf-8';
}
// Check if sitemap file exists, otherwise create it
if(!is_readable($sitemap)) {
\Sitemapper::generate();
}
if(is_readable($sitemap)) {
// Send headers
header('Content-Type: ' . $mime);
header('Content-Disposition: attachment; filename=' . utf8_basename($sitemap));
http_conditionalRequest(filemtime($sitemap));
// Send file
//use x-sendfile header to pass the delivery to compatible webservers
http_sendfile($sitemap);
readfile($sitemap);
exit;
}
throw new FatalException(500, 'Could not read the sitemap file - bad permissions?');
}
}

24
inc/Action/Source.php Normal file
View File

@ -0,0 +1,24 @@
<?php
namespace dokuwiki\Action;
/**
* Class Source
*
* Show the source of a page
*
* @package dokuwiki\Action
*/
class Source extends AbstractAction {
/** @inheritdoc */
public function minimumPermission() {
return AUTH_READ;
}
/** @inheritdoc */
public function tplContent() {
html_edit(); // FIXME is this correct? Should we split it off completely?
}
}

166
inc/Action/Subscribe.php Normal file
View File

@ -0,0 +1,166 @@
<?php
namespace dokuwiki\Action;
use dokuwiki\Action\Exception\ActionAbort;
use dokuwiki\Action\Exception\ActionDisabledException;
/**
* Class Subscribe
*
* E-Mail subscription handling
*
* @package dokuwiki\Action
*/
class Subscribe extends AbstractUserAction {
/** @inheritdoc */
public function minimumPermission() {
return AUTH_READ;
}
/** @inheritdoc */
public function checkPermissions() {
parent::checkPermissions();
global $conf;
if(isset($conf['subscribers']) && !$conf['subscribers']) throw new ActionDisabledException();
}
/** @inheritdoc */
public function preProcess() {
try {
$this->handleSubscribeData();
} catch(ActionAbort $e) {
throw $e;
} catch(\Exception $e) {
msg($e->getMessage(), -1);
}
}
/** @inheritdoc */
public function tplContent() {
tpl_subscribe();
}
/**
* Handle page 'subscribe'
*
* @author Adrian Lang <lang@cosmocode.de>
* @throws \Exception if (un)subscribing fails
* @throws ActionAbort when (un)subscribing worked
*/
protected function handleSubscribeData() {
global $lang;
global $INFO;
global $INPUT;
// get and preprocess data.
$params = array();
foreach(array('target', 'style', 'action') as $param) {
if($INPUT->has("sub_$param")) {
$params[$param] = $INPUT->str("sub_$param");
}
}
// any action given? if not just return and show the subscription page
if(empty($params['action']) || !checkSecurityToken()) return;
// Handle POST data, may throw exception.
trigger_event('ACTION_HANDLE_SUBSCRIBE', $params, array($this, 'handlePostData'));
$target = $params['target'];
$style = $params['style'];
$action = $params['action'];
// Perform action.
$sub = new \Subscription();
if($action == 'unsubscribe') {
$ok = $sub->remove($target, $INPUT->server->str('REMOTE_USER'), $style);
} else {
$ok = $sub->add($target, $INPUT->server->str('REMOTE_USER'), $style);
}
if($ok) {
msg(
sprintf(
$lang["subscr_{$action}_success"], hsc($INFO['userinfo']['name']),
prettyprint_id($target)
), 1
);
throw new ActionAbort('redirect');
} else {
throw new \Exception(
sprintf(
$lang["subscr_{$action}_error"],
hsc($INFO['userinfo']['name']),
prettyprint_id($target)
)
);
}
}
/**
* Validate POST data
*
* Validates POST data for a subscribe or unsubscribe request. This is the
* default action for the event ACTION_HANDLE_SUBSCRIBE.
*
* @author Adrian Lang <lang@cosmocode.de>
*
* @param array &$params the parameters: target, style and action
* @throws \Exception
*/
public function handlePostData(&$params) {
global $INFO;
global $lang;
global $INPUT;
// Get and validate parameters.
if(!isset($params['target'])) {
throw new \Exception('no subscription target given');
}
$target = $params['target'];
$valid_styles = array('every', 'digest');
if(substr($target, -1, 1) === ':') {
// Allow “list” subscribe style since the target is a namespace.
$valid_styles[] = 'list';
}
$style = valid_input_set(
'style', $valid_styles, $params,
'invalid subscription style given'
);
$action = valid_input_set(
'action', array('subscribe', 'unsubscribe'),
$params, 'invalid subscription action given'
);
// Check other conditions.
if($action === 'subscribe') {
if($INFO['userinfo']['mail'] === '') {
throw new \Exception($lang['subscr_subscribe_noaddress']);
}
} elseif($action === 'unsubscribe') {
$is = false;
foreach($INFO['subscribed'] as $subscr) {
if($subscr['target'] === $target) {
$is = true;
}
}
if($is === false) {
throw new \Exception(
sprintf(
$lang['subscr_not_subscribed'],
$INPUT->server->str('REMOTE_USER'),
prettyprint_id($target)
)
);
}
// subscription_set deletes a subscription if style = null.
$style = null;
}
$params = compact('target', 'style', 'action');
}
}

228
inc/ActionRouter.php Normal file
View File

@ -0,0 +1,228 @@
<?php
namespace dokuwiki;
use dokuwiki\Action\AbstractAction;
use dokuwiki\Action\Exception\ActionDisabledException;
use dokuwiki\Action\Exception\ActionException;
use dokuwiki\Action\Exception\FatalException;
use dokuwiki\Action\Exception\NoActionException;
use dokuwiki\Action\Plugin;
/**
* Class ActionRouter
* @package dokuwiki
*/
class ActionRouter {
/** @var AbstractAction */
protected $action;
/** @var ActionRouter */
protected static $instance;
/** @var int transition counter */
protected $transitions = 0;
/** maximum loop */
const MAX_TRANSITIONS = 5;
/** @var string[] the actions disabled in the configuration */
protected $disabled;
/**
* ActionRouter constructor. Singleton, thus protected!
*
* Sets up the correct action based on the $ACT global. Writes back
* the selected action to $ACT
*/
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);
$ACT = $this->action->getActionName();
}
/**
* Get the singleton instance
*
* @param bool $reinit
* @return ActionRouter
*/
public static function getInstance($reinit = false) {
if((self::$instance === null) || $reinit) {
self::$instance = new ActionRouter();
}
return self::$instance;
}
/**
* Setup the given action
*
* Instantiates the right class, runs permission checks and pre-processing and
* sets $action
*
* @param string $actionname
* @triggers ACTION_ACT_PREPROCESS
*/
protected function setupAction($actionname) {
$presetup = $actionname;
try {
$this->action = $this->loadAction($actionname);
$this->checkAction($this->action);
$this->action->preProcess();
} 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)) {
msg('Action disabled: ' . hsc($presetup), -1);
}
// some actions may request the display of a message
if($e->displayToUser()) {
msg(hsc($e->getMessage()), -1);
}
// do setup for new action
$this->transitionAction($presetup, $actionname);
} catch(NoActionException $e) {
// give plugins an opportunity to process the actionname
$evt = new \Doku_Event('ACTION_ACT_PREPROCESS', $actionname);
if($evt->advise_before()) {
if($actionname == $presetup) {
// no plugin changed the action, complain and switch to show
msg('Action unknown: ' . hsc($actionname), -1);
$actionname = 'show';
}
$this->transitionAction($presetup, $actionname);
} else {
// event said the action should be kept, assume action plugin will handle it later
$this->action = new Plugin($actionname);
}
$evt->advise_after();
} catch(\Exception $e) {
$this->handleFatalException($e);
}
}
/**
* Transitions from one action to another
*
* Basically just calls setupAction() again but does some checks before.
*
* @param string $from current action name
* @param string $to new action name
* @param null|ActionException $e any previous exception that caused the transition
*/
protected function transitionAction($from, $to, $e = null) {
$this->transitions++;
// no infinite recursion
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) {
$this->handleFatalException(new FatalException('Maximum action transitions reached', 500, $e));
}
// do the recursion
$this->setupAction($to);
}
/**
* Aborts all processing with a message
*
* When a FataException instanc is passed, the code is treated as Status code
*
* @param \Exception|FatalException $e
*/
protected function handleFatalException(\Exception $e) {
if(is_a($e, FatalException::class)) {
http_status($e->getCode());
} else {
http_status(500);
}
$msg = 'Something unforseen has happened: ' . $e->getMessage();
nice_die(hsc($msg));
}
/**
* Load the given action
*
* This translates the given name to a class name by uppercasing the first letter.
* Underscores translate to camelcase names. For actions with underscores, the different
* parts are removed beginning from the end until a matching class is found. The instatiated
* Action will always have the full original action set as Name
*
* Example: 'export_raw' -> ExportRaw then 'export' -> 'Export'
*
* @param $actionname
* @return AbstractAction
* @throws NoActionException
*/
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);
$class = 'dokuwiki\\Action\\' . str_replace('_', '', ucwords($load, '_'));
if(class_exists($class)) {
return new $class($actionname);
}
array_pop($parts);
}
throw new NoActionException();
}
/**
* Execute all the checks to see if this action can be executed
*
* @param AbstractAction $action
* @throws ActionDisabledException
* @throws ActionException
*/
public function checkAction(AbstractAction $action) {
global $INFO;
global $ID;
if(in_array($action->getActionName(), $this->disabled)) {
throw new ActionDisabledException();
}
$action->checkPermissions();
if(isset($INFO)) {
$perm = $INFO['perm'];
} else {
$perm = auth_quickaclcheck($ID);
}
if($perm < $action->minimumPermission()) {
throw new ActionException('denied');
}
}
/**
* Returns the action handling the current request
*
* @return AbstractAction
*/
public function getAction() {
return $this->action;
}
}

View File

@ -226,6 +226,14 @@ class _DiffEngine {
* of the two files do not match, and likewise that the last lines do not
* match. The caller must trim matching lines from the beginning and end
* of the portions it is going to specify.
*
* @param integer $xoff
* @param integer $xlim
* @param integer $yoff
* @param integer $ylim
* @param integer $nchunks
*
* @return array
*/
function _diag($xoff, $xlim, $yoff, $ylim, $nchunks) {
$flip = false;
@ -336,6 +344,11 @@ class _DiffEngine {
*
* Note that XLIM, YLIM are exclusive bounds.
* All line numbers are origin-0 and discarded lines are not counted.
*
* @param integer $xoff
* @param integer $xlim
* @param integer $yoff
* @param integer $ylim
*/
function _compareseq($xoff, $xlim, $yoff, $ylim) {
// Slide down the bottom initial diagonal.
@ -392,6 +405,10 @@ class _DiffEngine {
* to be the "change".
*
* This is extracted verbatim from analyze.c (GNU diffutils-2.7).
*
* @param array $lines
* @param array $changed
* @param array $other_changed
*/
function _shift_boundaries($lines, &$changed, $other_changed) {
$i = 0;
@ -612,6 +629,9 @@ class Diff {
* Check a Diff for validity.
*
* This is here only for debugging purposes.
*
* @param mixed $from_lines
* @param mixed $to_lines
*/
function _check($from_lines, $to_lines) {
if (serialize($from_lines) != serialize($this->orig()))
@ -889,6 +909,10 @@ class HTMLDiff {
/**
* Return a class or style parameter
*
* @param string $classname
*
* @return string
*/
static function css($classname){
global $DIFF_INLINESTYLES;
@ -1339,6 +1363,11 @@ class Diff3 extends Diff {
/**
* @access private
*
* @param array $edits1
* @param array $edits2
*
* @return array
*/
function _diff3($edits1, $edits2) {
$edits = array();

View File

@ -23,6 +23,8 @@ class FeedParser extends SimplePie {
/**
* Backward compatibility for older plugins
*
* @param string $url
*/
function feed_url($url){
$this->set_feed_url($url);
@ -41,14 +43,17 @@ class FeedParser_File extends SimplePie_File {
var $headers = array();
var $body;
var $error;
/** @noinspection PhpMissingParentConstructorInspection */
/**
* Inititializes the HTTPClient
*
* We ignore all given parameters - they are set in DokuHTTPClient
*
* @inheritdoc
*/
function __construct($url, $timeout=10, $redirects=5,
$headers=null, $useragent=null, $force_fsockopen=false) {
$headers=null, $useragent=null, $force_fsockopen=false, $curl_options = array()) {
$this->http = new DokuHTTPClient();
$this->success = $this->http->sendRequest($url);
@ -61,14 +66,17 @@ class FeedParser_File extends SimplePie_File {
return $this->success;
}
/** @inheritdoc */
function headers(){
return $this->headers;
}
/** @inheritdoc */
function body(){
return $this->body;
}
/** @inheritdoc */
function close(){
return true;
}

View File

@ -10,18 +10,59 @@ namespace dokuwiki\Form;
*/
class DropdownElement extends InputElement {
protected $options = array();
protected $value = '';
/** @var array OptGroup[] */
protected $optGroups = array();
/**
* @param string $name The name of this form element
* @param string $options The available options
* @param array $options The available options
* @param string $label The label text for this element (will be autoescaped)
*/
public function __construct($name, $options, $label = '') {
parent::__construct('dropdown', $name, $label);
$this->options($options);
$this->rmattr('type');
$this->optGroups[''] = new OptGroup(null, $options);
$this->val('');
}
/**
* Add an `<optgroup>` and respective options
*
* @param string $label
* @param array $options
* @return OptGroup a reference to the added optgroup
* @throws \Exception
*/
public function addOptGroup($label, $options) {
if (empty($label)) {
throw new \InvalidArgumentException(hsc('<optgroup> must have a label!'));
}
$this->optGroups[$label] = new OptGroup($label, $options);
return end($this->optGroups);
}
/**
* Set or get the optgroups of an Dropdown-Element.
*
* optgroups have to be given as associative array
* * the key being the label of the group
* * the value being an array of options as defined in @see OptGroup::options()
*
* @param null|array $optGroups
* @return OptGroup[]|DropdownElement
*/
public function optGroups($optGroups = null) {
if($optGroups === null) {
return $this->optGroups;
}
if (!is_array($optGroups)) {
throw new \InvalidArgumentException(hsc('Argument must be an associative array of label => [options]!'));
}
$this->optGroups = array();
foreach ($optGroups as $label => $options) {
$this->addOptGroup($label, $options);
}
return $this;
}
/**
@ -41,21 +82,10 @@ class DropdownElement extends InputElement {
* @return $this|array
*/
public function options($options = null) {
if($options === null) return $this->options;
if(!is_array($options)) throw new \InvalidArgumentException('Options have to be an array');
$this->options = array();
foreach($options as $key => $val) {
if(is_int($key)) {
$this->options[$val] = array('label' => (string) $val);
} elseif (!is_array($val)) {
$this->options[$key] = array('label' => (string) $val);
} else {
if (!key_exists('label', $val)) throw new \InvalidArgumentException('If option is given as array, it has to have a "label"-key!');
$this->options[$key] = $val;
}
if ($options === null) {
return $this->optGroups['']->options();
}
$this->val(''); // set default value (empty or first)
$this->optGroups[''] = new OptGroup(null, $options);
return $this;
}
@ -91,17 +121,57 @@ class DropdownElement extends InputElement {
public function val($value = null) {
if($value === null) return $this->value;
if(isset($this->options[$value])) {
$value_exists = $this->setValueInOptGroups($value);
if($value_exists) {
$this->value = $value;
} else {
// unknown value set, select first option instead
$keys = array_keys($this->options);
$this->value = (string) array_shift($keys);
$this->value = $this->getFirstOption();
$this->setValueInOptGroups($this->value);
}
return $this;
}
/**
* Returns the first options as it will be rendered in HTML
*
* @return string
*/
protected function getFirstOption() {
$options = $this->options();
if (!empty($options)) {
$keys = array_keys($options);
return (string) array_shift($keys);
}
foreach ($this->optGroups as $optGroup) {
$options = $optGroup->options();
if (!empty($options)) {
$keys = array_keys($options);
return (string) array_shift($keys);
}
}
}
/**
* Set the value in the OptGroups, including the optgroup for the options without optgroup.
*
* @param string $value
* @return bool
*/
protected function setValueInOptGroups($value) {
$value_exists = false;
/** @var OptGroup $optGroup */
foreach ($this->optGroups as $optGroup) {
$value_exists = $optGroup->storeValue($value) || $value_exists;
if ($value_exists) {
$value = null;
}
}
return $value_exists;
}
/**
* Create the HTML for the select it self
*
@ -111,15 +181,7 @@ class DropdownElement extends InputElement {
if($this->useInput) $this->prefillInput();
$html = '<select ' . buildAttributes($this->attrs()) . '>';
foreach($this->options as $key => $val) {
$selected = ($key == $this->value) ? ' selected="selected"' : '';
$attrs = '';
if (is_array($val['attrs'])) {
array_walk($val['attrs'],function (&$aval, $akey){$aval = hsc($akey).'="'.hsc($aval).'"';});
$attrs = join(' ', $val['attrs']);
}
$html .= '<option' . $selected . ' value="' . hsc($key) . '" '.$attrs.'>' . hsc($val['label']) . '</option>';
}
$html = array_reduce($this->optGroups, function($html, OptGroup $optGroup) {return $html . $optGroup->toHTML();}, $html);
$html .= '</select>';
return $html;

97
inc/Form/OptGroup.php Normal file
View File

@ -0,0 +1,97 @@
<?php
namespace dokuwiki\Form;
class OptGroup extends Element {
protected $options = array();
protected $value;
/**
* @param string $label The label text for this element (will be autoescaped)
* @param array $options The available options
*/
public function __construct($label, $options) {
parent::__construct('optGroup', array('label' => $label));
$this->options($options);
}
/**
* Store the given value so it can be used during rendering
*
* This is intended to be only called from within @see DropdownElement::val()
*
* @param string $value
* @return bool true if an option with the given value exists, false otherwise
*/
public function storeValue($value) {
$this->value = $value;
return isset($this->options[$value]);
}
/**
* Get or set the options of the optgroup
*
* Options can be given as associative array (value => label) or as an
* indexd array (label = value) or as an array of arrays. In the latter
* case an element has to look as follows:
* option-value => array (
* 'label' => option-label,
* 'attrs' => array (
* attr-key => attr-value, ...
* )
* )
*
* @param null|array $options
* @return $this|array
*/
public function options($options = null) {
if($options === null) return $this->options;
if(!is_array($options)) throw new \InvalidArgumentException('Options have to be an array');
$this->options = array();
foreach($options as $key => $val) {
if (is_array($val)) {
if (!key_exists('label', $val)) throw new \InvalidArgumentException('If option is given as array, it has to have a "label"-key!');
$this->options[$key] = $val;
} elseif(is_int($key)) {
$this->options[$val] = array('label' => (string) $val);
} else {
$this->options[$key] = array('label' => (string) $val);
}
}
return $this;
}
/**
* The HTML representation of this element
*
* @return string
*/
public function toHTML() {
if ($this->attributes['label'] === null) {
return $this->renderOptions();
}
$html = '<optgroup '. buildAttributes($this->attrs()) . '>';
$html .= $this->renderOptions();
$html .= '</optgroup>';
return $html;
}
/**
* @return string
*/
protected function renderOptions() {
$html = '';
foreach($this->options as $key => $val) {
$selected = ($key == $this->value) ? ' selected="selected"' : '';
$attrs = '';
if (!empty($val['attrs']) && is_array($val['attrs'])) {
$attrs = buildAttributes($val['attrs']);
}
$html .= '<option' . $selected . ' value="' . hsc($key) . '" '.$attrs.'>' . hsc($val['label']) . '</option>';
}
return $html;
}
}

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