1
0
Fork 0
mirror of https://github.com/YunoHost-Apps/dokuwiki_ynh.git synced 2024-09-03 18:26:20 +02:00

Refactoring and upgrade to 2017-02-19b "Frusterick Manners" version

This commit is contained in:
__cyp 2017-04-15 13:16:21 +02:00 committed by JimboJoe
parent 2b5659f8c7
commit 95b5d8a1ba
4851 changed files with 854 additions and 297214 deletions

View file

@ -1,4 +1,43 @@
Dokuwiki for YunoHost
---------------------
# Dokuwiki for YunoHost
https://www.dokuwiki.org
## Dokuwiki c'est quoi ?
DokuWiki est un logiciel wiki Open Source simple à utiliser et très polyvalent qui ne nécessite pas de base de données. Il est apprécié par les utilisateurs pour sa syntaxe propre et lisible. La facilité de maintenance, de sauvegarde et d'intégration en fait un favori d'administrateur. Des contrôles d'accès et des connecteurs d'authentification intégrés rendent DokuWiki particulièrement utile dans le contexte de l'entreprise et le grand nombre de plugins apportés par sa communauté dynamique permettent un large éventail de cas d'utilisation au-delà d'un wiki traditionnel.
Source: [dokuwiki.org](https://www.dokuwiki.org/)
### Installation
`$ sudo yunohost app install https://github.com/YunoHost-Apps/dokuwiki_ynh.git`
### Mise à jour
`$ sudo yunohost app upgrade --verbose dokuwiki -u https://github.com/YunoHost-Apps/dokuwiki_ynh.git`
Lors de la mise à jour de dokuwiki, les plugins officiels sont également mis à jour. Nous vous recommandons toutefois de vérifier le bon fonctionnement des plugins dans le panel d'administration après cette upgrade. Nous ne pouvons pas savoir si des plugins spéciaux posent problèmes.
## What is Dokuwiki?
DokuWiki is a simple to use and highly versatile Open Source wiki software that doesn't require a database. It is loved by users for its clean and readable syntax. The ease of maintenance, backup and integration makes it an administrator's favorite. Built in access controls and authentication connectors make DokuWiki especially useful in the enterprise context and the large number of plugins contributed by its vibrant community allow for a broad range of use cases beyond a traditional wiki.
Source: [dokuwiki.org](https://www.dokuwiki.org/)
### Install
`$ sudo yunohost app install https://github.com/YunoHost-Apps/dokuwiki_ynh.git`
### Update
`$ sudo yunohost app upgrade --verbose dokuwiki -u https://github.com/YunoHost-Apps/dokuwiki_ynh.git`
When updating dokuwiki, the official plugins are also updated. However, we recommend that you check the plugins in the administration panel after this upgrade. We can't know if special plugins are causing problems.
## Versionning
### Version 1.1.0 (07/03/17)
- Update app
### Version 1.0.0 (11/02/14)
- Create script app

View file

@ -1,8 +1,6 @@
location YNH_WWW_LOCATION {
location __PATHTOCHANGE__ {
alias __FINALPATH__/;
alias YNH_WWW_ALIAS ;
# Force https
if ($scheme = http) {
rewrite ^ https://$server_name$request_uri? permanent;
}
@ -12,16 +10,17 @@ location YNH_WWW_LOCATION {
location ~ [^/]\.php(/|$) {
fastcgi_split_path_info ^(.+?\.php)(/.*)$;
fastcgi_pass unix:/var/run/php5-fpm.sock;
fastcgi_pass unix:/var/run/php5-fpm-__NAMETOCHANGE__.sock;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param HTTPS on if_not_empty;
fastcgi_param REMOTE_USER $remote_user;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_param SCRIPT_FILENAME $request_filename;
}
# Secure DokuWiki
location ~ ^YNH_WWW_PATH/(data|conf|bin|inc)/ {
location ~ ^__PATHTOCHANGE__/(data|conf|bin|inc)/ {
deny all;
}
@ -35,7 +34,7 @@ location YNH_WWW_LOCATION {
expires 30d;
}
# Include SSOWAT user panel.
include conf.d/yunohost_panel.conf.inc;
#--PRIVATE--# Include SSOWAT user panel.
#--PRIVATE--include conf.d/yunohost_panel.conf.inc;
}

392
conf/php-fpm.conf Normal file
View file

@ -0,0 +1,392 @@
; Start a new pool named 'www'.
; the variable $pool can we used in any directive and will be replaced by the
; pool name ('www' here)
[__NAMETOCHANGE__]
; Per pool prefix
; It only applies on the following directives:
; - 'slowlog'
; - 'listen' (unixsocket)
; - 'chroot'
; - 'chdir'
; - 'php_values'
; - 'php_admin_values'
; When not set, the global prefix (or /usr) applies instead.
; Note: This directive can also be relative to the global prefix.
; Default Value: none
;prefix = /path/to/pools/$pool
; Unix user/group of processes
; Note: The user is mandatory. If the group is not set, the default user's group
; will be used.
user = www-data
group = www-data
; The address on which to accept FastCGI requests.
; Valid syntaxes are:
; 'ip.add.re.ss:port' - to listen on a TCP socket to a specific address on
; a specific port;
; 'port' - to listen on a TCP socket to all addresses on a
; specific port;
; '/path/to/unix/socket' - to listen on a unix socket.
; Note: This value is mandatory.
listen = /var/run/php5-fpm-__NAMETOCHANGE__.sock
; Set listen(2) backlog.
; Default Value: 128 (-1 on FreeBSD and OpenBSD)
;listen.backlog = 128
; Set permissions for unix socket, if one is used. In Linux, read/write
; permissions must be set in order to allow connections from a web server. Many
; BSD-derived systems allow connections regardless of permissions.
; Default Values: user and group are set as the running user
; mode is set to 0660
listen.owner = www-data
listen.group = www-data
;listen.mode = 0660
; List of ipv4 addresses of FastCGI clients which are allowed to connect.
; Equivalent to the FCGI_WEB_SERVER_ADDRS environment variable in the original
; PHP FCGI (5.2.2+). Makes sense only with a tcp listening socket. Each address
; must be separated by a comma. If this value is left blank, connections will be
; accepted from any ip address.
; Default Value: any
;listen.allowed_clients = 127.0.0.1
; Specify the nice(2) priority to apply to the pool processes (only if set)
; The value can vary from -19 (highest priority) to 20 (lower priority)
; Note: - It will only work if the FPM master process is launched as root
; - The pool processes will inherit the master process priority
; unless it specified otherwise
; Default Value: no set
; priority = -19
; Choose how the process manager will control the number of child processes.
; Possible Values:
; static - a fixed number (pm.max_children) of child processes;
; dynamic - the number of child processes are set dynamically based on the
; following directives. With this process management, there will be
; always at least 1 children.
; pm.max_children - the maximum number of children that can
; be alive at the same time.
; pm.start_servers - the number of children created on startup.
; pm.min_spare_servers - the minimum number of children in 'idle'
; state (waiting to process). If the number
; of 'idle' processes is less than this
; number then some children will be created.
; pm.max_spare_servers - the maximum number of children in 'idle'
; state (waiting to process). If the number
; of 'idle' processes is greater than this
; number then some children will be killed.
; ondemand - no children are created at startup. Children will be forked when
; new requests will connect. The following parameter are used:
; pm.max_children - the maximum number of children that
; can be alive at the same time.
; pm.process_idle_timeout - The number of seconds after which
; an idle process will be killed.
; Note: This value is mandatory.
pm = dynamic
; The number of child processes to be created when pm is set to 'static' and the
; maximum number of child processes when pm is set to 'dynamic' or 'ondemand'.
; This value sets the limit on the number of simultaneous requests that will be
; served. Equivalent to the ApacheMaxClients directive with mpm_prefork.
; Equivalent to the PHP_FCGI_CHILDREN environment variable in the original PHP
; CGI. The below defaults are based on a server without much resources. Don't
; forget to tweak pm.* to fit your needs.
; Note: Used when pm is set to 'static', 'dynamic' or 'ondemand'
; Note: This value is mandatory.
pm.max_children = 10
; The number of child processes created on startup.
; Note: Used only when pm is set to 'dynamic'
; Default Value: min_spare_servers + (max_spare_servers - min_spare_servers) / 2
pm.start_servers = 2
; The desired minimum number of idle server processes.
; Note: Used only when pm is set to 'dynamic'
; Note: Mandatory when pm is set to 'dynamic'
pm.min_spare_servers = 1
; The desired maximum number of idle server processes.
; Note: Used only when pm is set to 'dynamic'
; Note: Mandatory when pm is set to 'dynamic'
pm.max_spare_servers = 3
; The number of seconds after which an idle process will be killed.
; Note: Used only when pm is set to 'ondemand'
; Default Value: 10s
;pm.process_idle_timeout = 10s;
; The number of requests each child process should execute before respawning.
; This can be useful to work around memory leaks in 3rd party libraries. For
; endless request processing specify '0'. Equivalent to PHP_FCGI_MAX_REQUESTS.
; Default Value: 0
pm.max_requests = 500
; The URI to view the FPM status page. If this value is not set, no URI will be
; recognized as a status page. It shows the following informations:
; pool - the name of the pool;
; process manager - static, dynamic or ondemand;
; start time - the date and time FPM has started;
; start since - number of seconds since FPM has started;
; accepted conn - the number of request accepted by the pool;
; listen queue - the number of request in the queue of pending
; connections (see backlog in listen(2));
; max listen queue - the maximum number of requests in the queue
; of pending connections since FPM has started;
; listen queue len - the size of the socket queue of pending connections;
; idle processes - the number of idle processes;
; active processes - the number of active processes;
; total processes - the number of idle + active processes;
; max active processes - the maximum number of active processes since FPM
; has started;
; max children reached - number of times, the process limit has been reached,
; when pm tries to start more children (works only for
; pm 'dynamic' and 'ondemand');
; Value are updated in real time.
; Example output:
; pool: www
; process manager: static
; start time: 01/Jul/2011:17:53:49 +0200
; start since: 62636
; accepted conn: 190460
; listen queue: 0
; max listen queue: 1
; listen queue len: 42
; idle processes: 4
; active processes: 11
; total processes: 15
; max active processes: 12
; max children reached: 0
;
; By default the status page output is formatted as text/plain. Passing either
; 'html', 'xml' or 'json' in the query string will return the corresponding
; output syntax. Example:
; http://www.foo.bar/status
; http://www.foo.bar/status?json
; http://www.foo.bar/status?html
; http://www.foo.bar/status?xml
;
; By default the status page only outputs short status. Passing 'full' in the
; query string will also return status for each pool process.
; Example:
; http://www.foo.bar/status?full
; http://www.foo.bar/status?json&full
; http://www.foo.bar/status?html&full
; http://www.foo.bar/status?xml&full
; The Full status returns for each process:
; pid - the PID of the process;
; state - the state of the process (Idle, Running, ...);
; start time - the date and time the process has started;
; start since - the number of seconds since the process has started;
; requests - the number of requests the process has served;
; request duration - the duration in µs of the requests;
; request method - the request method (GET, POST, ...);
; request URI - the request URI with the query string;
; content length - the content length of the request (only with POST);
; user - the user (PHP_AUTH_USER) (or '-' if not set);
; script - the main script called (or '-' if not set);
; last request cpu - the %cpu the last request consumed
; it's always 0 if the process is not in Idle state
; because CPU calculation is done when the request
; processing has terminated;
; last request memory - the max amount of memory the last request consumed
; it's always 0 if the process is not in Idle state
; because memory calculation is done when the request
; processing has terminated;
; If the process is in Idle state, then informations are related to the
; last request the process has served. Otherwise informations are related to
; the current request being served.
; Example output:
; ************************
; pid: 31330
; state: Running
; start time: 01/Jul/2011:17:53:49 +0200
; start since: 63087
; requests: 12808
; request duration: 1250261
; request method: GET
; request URI: /test_mem.php?N=10000
; content length: 0
; user: -
; script: /home/fat/web/docs/php/test_mem.php
; last request cpu: 0.00
; last request memory: 0
;
; Note: There is a real-time FPM status monitoring sample web page available
; It's available in: ${prefix}/share/fpm/status.html
;
; Note: The value must start with a leading slash (/). The value can be
; anything, but it may not be a good idea to use the .php extension or it
; may conflict with a real PHP file.
; Default Value: not set
;pm.status_path = /status
; The ping URI to call the monitoring page of FPM. If this value is not set, no
; URI will be recognized as a ping page. This could be used to test from outside
; that FPM is alive and responding, or to
; - create a graph of FPM availability (rrd or such);
; - remove a server from a group if it is not responding (load balancing);
; - trigger alerts for the operating team (24/7).
; Note: The value must start with a leading slash (/). The value can be
; anything, but it may not be a good idea to use the .php extension or it
; may conflict with a real PHP file.
; Default Value: not set
;ping.path = /ping
; This directive may be used to customize the response of a ping request. The
; response is formatted as text/plain with a 200 response code.
; Default Value: pong
;ping.response = pong
; The access log file
; Default: not set
;access.log = log/$pool.access.log
; The access log format.
; The following syntax is allowed
; %%: the '%' character
; %C: %CPU used by the request
; it can accept the following format:
; - %{user}C for user CPU only
; - %{system}C for system CPU only
; - %{total}C for user + system CPU (default)
; %d: time taken to serve the request
; it can accept the following format:
; - %{seconds}d (default)
; - %{miliseconds}d
; - %{mili}d
; - %{microseconds}d
; - %{micro}d
; %e: an environment variable (same as $_ENV or $_SERVER)
; it must be associated with embraces to specify the name of the env
; variable. Some exemples:
; - server specifics like: %{REQUEST_METHOD}e or %{SERVER_PROTOCOL}e
; - HTTP headers like: %{HTTP_HOST}e or %{HTTP_USER_AGENT}e
; %f: script filename
; %l: content-length of the request (for POST request only)
; %m: request method
; %M: peak of memory allocated by PHP
; it can accept the following format:
; - %{bytes}M (default)
; - %{kilobytes}M
; - %{kilo}M
; - %{megabytes}M
; - %{mega}M
; %n: pool name
; %o: ouput header
; it must be associated with embraces to specify the name of the header:
; - %{Content-Type}o
; - %{X-Powered-By}o
; - %{Transfert-Encoding}o
; - ....
; %p: PID of the child that serviced the request
; %P: PID of the parent of the child that serviced the request
; %q: the query string
; %Q: the '?' character if query string exists
; %r: the request URI (without the query string, see %q and %Q)
; %R: remote IP address
; %s: status (response code)
; %t: server time the request was received
; it can accept a strftime(3) format:
; %d/%b/%Y:%H:%M:%S %z (default)
; %T: time the log has been written (the request has finished)
; it can accept a strftime(3) format:
; %d/%b/%Y:%H:%M:%S %z (default)
; %u: remote user
;
; Default: "%R - %u %t \"%m %r\" %s"
;access.format = "%R - %u %t \"%m %r%Q%q\" %s %f %{mili}d %{kilo}M %C%%"
; The log file for slow requests
; Default Value: not set
; Note: slowlog is mandatory if request_slowlog_timeout is set
slowlog = /var/log/nginx/__NAMETOCHANGE__.slow.log
; The timeout for serving a single request after which a PHP backtrace will be
; dumped to the 'slowlog' file. A value of '0s' means 'off'.
; Available units: s(econds)(default), m(inutes), h(ours), or d(ays)
; Default Value: 0
request_slowlog_timeout = 5s
; The timeout for serving a single request after which the worker process will
; be killed. This option should be used when the 'max_execution_time' ini option
; does not stop script execution for some reason. A value of '0' means 'off'.
; Available units: s(econds)(default), m(inutes), h(ours), or d(ays)
; Default Value: 0
request_terminate_timeout = 1d
; Set open file descriptor rlimit.
; Default Value: system defined value
;rlimit_files = 1024
; Set max core size rlimit.
; Possible Values: 'unlimited' or an integer greater or equal to 0
; Default Value: system defined value
;rlimit_core = 0
; Chroot to this directory at the start. This value must be defined as an
; absolute path. When this value is not set, chroot is not used.
; Note: you can prefix with '$prefix' to chroot to the pool prefix or one
; of its subdirectories. If the pool prefix is not set, the global prefix
; will be used instead.
; Note: chrooting is a great security feature and should be used whenever
; possible. However, all PHP paths will be relative to the chroot
; (error_log, sessions.save_path, ...).
; Default Value: not set
;chroot =
; Chdir to this directory at the start.
; Note: relative path can be used.
; Default Value: current directory or / when chroot
chdir = __FINALPATH__
; Redirect worker stdout and stderr into main error log. If not set, stdout and
; stderr will be redirected to /dev/null according to FastCGI specs.
; Note: on highloaded environement, this can cause some delay in the page
; process time (several ms).
; Default Value: no
catch_workers_output = yes
; Limits the extensions of the main script FPM will allow to parse. This can
; prevent configuration mistakes on the web server side. You should only limit
; FPM to .php extensions to prevent malicious users to use other extensions to
; exectute php code.
; Note: set an empty value to allow all extensions.
; Default Value: .php
;security.limit_extensions = .php .php3 .php4 .php5
; Pass environment variables like LD_LIBRARY_PATH. All $VARIABLEs are taken from
; the current environment.
; Default Value: clean env
;env[HOSTNAME] = $HOSTNAME
;env[PATH] = /usr/local/bin:/usr/bin:/bin
;env[TMP] = /tmp
;env[TMPDIR] = /tmp
;env[TEMP] = /tmp
; Additional php.ini defines, specific to this pool of workers. These settings
; overwrite the values previously defined in the php.ini. The directives are the
; same as the PHP SAPI:
; php_value/php_flag - you can set classic ini defines which can
; be overwritten from PHP call 'ini_set'.
; php_admin_value/php_admin_flag - these directives won't be overwritten by
; PHP call 'ini_set'
; For php_*flag, valid values are on, off, 1, 0, true, false, yes or no.
; Defining 'extension' will load the corresponding shared extension from
; extension_dir. Defining 'disable_functions' or 'disable_classes' will not
; overwrite previously defined php.ini values, but will append the new value
; instead.
; Note: path INI options can be relative and will be expanded with the prefix
; (pool, global or /usr)
; Default Value: nothing is defined by default except the values in php.ini and
; specified at startup with the -d argument
;php_admin_value[sendmail_path] = /usr/sbin/sendmail -t -i -f www@my.domain.com
;php_flag[display_errors] = off
;php_admin_value[error_log] = /var/log/fpm-php.www.log
;php_admin_flag[log_errors] = on
;php_admin_value[memory_limit] = 32M

3
conf/php-fpm.ini Normal file
View file

@ -0,0 +1,3 @@
upload_max_filesize=30M
post_max_size=30M
; max_execution_time=60

View file

@ -12,12 +12,13 @@
"es": "DokuWiki es un sistema de Wiki de uso sencillicimo y compatible con los estándares.",
"it": "DokuWiki è un Wiki aderente agli standard, semplice da usare, finalizzato principalmente alla creazione di documentazione di qualsiasi tipo."
},
"version": "1.1.0",
"url": "https://www.dokuwiki.org",
"maintainer": {
"name": "opi",
"email": "opi@zeropi.net"
},
"multi_instance": "true",
"multi_instance": true,
"services": [
"nginx",
"php5-fpm"

180
scripts/.fonctions Normal file
View file

@ -0,0 +1,180 @@
#!/bin/bash
ynh_version="2.4"
YNH_VERSION () { # Display number version of the YunoHost moulinette
ynh_version=$(sudo yunohost -v | grep "moulinette:" | cut -d' ' -f2 | cut -d'.' -f1,2)
}
CHECK_VAR () { # Check variable is not empty
# $1 = Checking variable
# $2 = Text to display on error
test -n "$1" || (echo "$2" >&2 && false)
}
EXIT_PROPERLY () { # Causes the script to stop in the event of an error. And clean the residue.
trap '' ERR
echo -e "\e[91m \e[1m" # Shell in light red bold
echo -e "!!\n $app install's script has encountered an error. Installation was cancelled.\n!!" >&2
if type -t CLEAN_SETUP > /dev/null; then # Checks the existence of the function before executing it.
CLEAN_SETUP # Call the specific cleanup function of the install script.
fi
sudo sed -i "\@\"$domain$path/\":@d" /etc/ssowat/conf.json
if [ "$ynh_version" = "2.2" ]; then
/bin/bash $script_dir/remove # Call the remove script. In 2.2, this behavior is not automatic.
fi
ynh_die
}
TRAP_ON () { # Activate signal capture
trap EXIT_PROPERLY ERR # Capturing exit signals on error
}
TRAP_OFF () { # Ignoring signal capture until TRAP_ON
trap '' ERR # Ignoring exit signals
}
CHECK_USER () { # Check the validity of the user admin
# $1 = User admin variable
ynh_user_exists "$1" || (echo "Wrong admin" >&2 && false)
}
CHECK_PATH () { # Checks / at the beginning of the path. And his absence at the end.
if [ "${path:0:1}" != "/" ]; then # If the first character is not /
path="/$path" # Add / at the beginning of path
fi
if [ "${path:${#path}-1}" == "/" ] && [ ${#path} -gt 1 ]; then # If the last character is a / and it is not the only character.
path="${path:0:${#path}-1}" # Delete last character
fi
}
CHECK_DOMAINPATH () { # Checks the availability of the path and domain.
sudo yunohost app checkurl $domain$path -a $app
}
CHECK_FINALPATH () { # Checks that the destination folder is not already in use.
final_path=/var/www/$app
if [ -e "$final_path" ]
then
echo "This path already contains a folder" >&2
false
fi
}
SETUP_SOURCE () { # Download source, decompress and copu into $final_path
src=$(cat ../sources/source_md5 | awk -F' ' {'print $2'})
sudo wget -nv -i ../sources/source_url -O $src
# Checks the checksum of the downloaded source.
# md5sum -c ../sources/source_md5 --status || ynh_die "Corrupt source"
# Decompress source
if [ "$(echo ${src##*.})" == "tgz" ]; then
tar -x -f $src
elif [ "$(echo ${src##*.})" == "zip" ]; then
unzip -q $src
else
false # Unsupported archive format.
fi
# Copy file source
sudo cp -a $(cat ../sources/source_dir)/. "$final_path"
# Copy additional file and modified
if test -e "../sources/ajouts"; then
sudo cp -a ../sources/ajouts/. "$final_path"
fi
}
POOL_FPM () { # Create the php-fpm pool configuration file and configure it.
sed -i "s@__NAMETOCHANGE__@$app@g" ../conf/php-fpm.conf
sed -i "s@__FINALPATH__@$final_path@g" ../conf/php-fpm.conf
finalphpconf=/etc/php5/fpm/pool.d/$app.conf
sudo cp ../conf/php-fpm.conf $finalphpconf
sudo chown root: $finalphpconf
finalphpini=/etc/php5/fpm/conf.d/20-$app.ini
sudo cp ../conf/php-fpm.ini $finalphpini
sudo chown root: $finalphpini
sudo systemctl reload php5-fpm
}
STORE_MD5_CONFIG () { # Saves the checksum of the config file
# $1 = Name of the conf file for storage in settings.yml
# $2 = Full name and path of the conf file.
ynh_app_setting_set $app $1_file_md5 $(sudo md5sum "$2" | cut -d' ' -f1)
}
CHECK_MD5_CONFIG () { # Created a backup of the config file if it was changed.
# $1 = Name of the conf file for storage in settings.yml
# $2 = Full name and path of the conf file.onf.
if [ "$(ynh_app_setting_get $app $1_file_md5)" != $(sudo md5sum "$2" | cut -d' ' -f1) ]; then
sudo cp -a "$2" "$2.backup.$(date '+%d.%m.%y_%Hh%M,%Ss')" # Si le fichier de config a été modifié, créer un backup.
fi
}
FIND_PORT () { # Search free port
# $1 = Port number to start the search.
port=$1
while ! sudo yunohost app checkport $port ; do
port=$((port+1))
done
CHECK_VAR "$port" "port empty"
}
### REMOVE SCRIPT
REMOVE_NGINX_CONF () { # Delete nginx configuration
if [ -e "/etc/nginx/conf.d/$domain.d/$app.conf" ]; then
echo "Delete nginx config"
sudo rm "/etc/nginx/conf.d/$domain.d/$app.conf"
sudo systemctl reload nginx
fi
}
REMOVE_FPM_CONF () { # Delete pool php-fpm configuration
if [ -e "/etc/php5/fpm/pool.d/$app.conf" ]; then # Delete fpm config
echo "Delete fpm config"
sudo rm "/etc/php5/fpm/pool.d/$app.conf"
fi
if [ -e "/etc/php5/fpm/conf.d/20-$app.ini" ]; then # Delete php config
echo "Delete php config"
sudo rm "/etc/php5/fpm/conf.d/20-$app.ini"
fi
sudo systemctl reload php5-fpm
}
REMOVE_LOGROTATE_CONF () { # Delete logrotate configuration
if [ -e "/etc/logrotate.d/$app" ]; then
echo "Delete logrotate config"
sudo rm "/etc/logrotate.d/$app"
fi
}
SECURE_REMOVE () { # Deleting a folder with variable verification
chaine="$1" # The argument must be given between simple quotes '', to avoid interpreting the variables.
no_var=0
while (echo "$chaine" | grep -q '\$') # Loop as long as there are $ in the string
do
no_var=1
global_var=$(echo "$chaine" | cut -d '$' -f 2) # Isole the first variable found.
only_var=\$$(expr "$global_var" : '\([A-Za-z0-9_]*\)') # Isole completely the variable by adding the $ at the beginning and keeping only the name of the variable. Mostly gets rid of / and a possible path behind.
real_var=$(eval "echo ${only_var}") # `eval "echo ${var}` Allows to interpret a variable contained in a variable.
if test -z "$real_var" || [ "$real_var" = "/" ]; then
echo "Variable $only_var is empty, suppression of $chaine cancelled." >&2
return 1
fi
chaine=$(echo "$chaine" | sed "s@$only_var@$real_var@") # Replaces variable with its value in the string.
done
if [ "$no_var" -eq 1 ]
then
if [ -e "$chaine" ]; then
echo "Delete directory $chaine"
sudo rm -r "$chaine"
fi
return 0
else
echo "No detected variable." >&2
return 1
fi
}

View file

@ -1,32 +1,23 @@
#!/bin/bash
# causes the shell to exit if any subcommand or pipeline returns a non-zero status
set -e
# Exit on command errors and treat unset variables as an error
set -eu
# Source YNH helpers
. /usr/share/yunohost/helpers
# This is a multi-instance app, meaning it can be installed several times independently
# The id of the app as stated in the manifest is available as $YNH_APP_ID
# The instance number is available as $YNH_APP_INSTANCE_NUMBER (equals "1", "2", ...)
# The app instance name is available as $YNH_APP_INSTANCE_NAME
# - the first time the app is installed, YNH_APP_INSTANCE_NAME = ynhexample
# - the second time the app is installed, YNH_APP_INSTANCE_NAME = ynhexample__2
# - ynhexample__{N} for the subsequent installations, with N=3,4, ...
# The app instance name is probably what you are interested the most, since this is
# guaranteed to be unique. This is a good unique identifier to define installation path,
# db names, ...
# Get multi-instances specific variables
app=$YNH_APP_INSTANCE_NAME
# Retrieve arguments
domain=$(sudo yunohost app setting $app domain)
# Source app helpers
source /usr/share/yunohost/helpers
# Backup directory location for the app from where the script is executed and
# which will be compressed afterward
backup_dir=$YNH_APP_BACKUP_DIR
# Retrieve app settings
domain=$(ynh_app_setting_get "$app" domain)
# Backup sources & data
ynh_backup "/var/www/$app" "./sources"
# Copy the app files
final_path="/var/www/${app}"
ynh_backup "$final_path" "sources" 1
# Copy Nginx conf
ynh_backup "/etc/nginx/conf.d/$domain.d/$app.conf" "./conf/nginx.conf"
# Copy the nginx conf files
ynh_backup "/etc/nginx/conf.d/${domain}.d/${app}.conf" "nginx.conf"
# Copy the php-fpm conf files
ynh_backup "/etc/php5/fpm/pool.d/${app}.conf" "php-fpm.conf"
ynh_backup "/etc/php5/fpm/conf.d/20-${app}.ini" "php-fpm.ini"

View file

@ -1,7 +1,7 @@
#!/bin/bash
# causes the shell to exit if any subcommand or pipeline returns a non-zero status
set -e
# Exit on command errors and treat unset variables as an error
set -eu
# This is a multi-instance app, meaning it can be installed several times independently
# The id of the app as stated in the manifest is available as $YNH_APP_ID
@ -13,60 +13,89 @@ set -e
# The app instance name is probably what you are interested the most, since this is
# guaranteed to be unique. This is a good unique identifier to define installation path,
# db names, ...
app=$YNH_APP_INSTANCE_NAME
# Retrieve arguments
source .fonctions # Loads the generic functions usually used in the script
# Source app helpers
source /usr/share/yunohost/helpers
TRAP_ON # Active trap for strop script if detect error.
domain=$YNH_APP_ARG_DOMAIN
path=$YNH_APP_ARG_PATH
admin=$YNH_APP_ARG_ADMIN
is_public=$YNH_APP_ARG_IS_PUBLIC
# Remove trailing slash to path
path=${path%/}
#force location to be / or /foo
location=${path:-/}
app=$YNH_APP_INSTANCE_NAME
CHECK_VAR "$app" "app name not set"
# Check domain/path availability
sudo yunohost app checkurl $domain$path -a $app
if [[ ! $? -eq 0 ]]; then
exit 1
fi
CHECK_USER "$admin"
CHECK_PATH
CHECK_DOMAINPATH
CHECK_FINALPATH
# Save app settings
sudo yunohost app setting $app admin -v "$admin"
sudo yunohost app setting $app is_public -v "$is_public"
ynh_app_setting_set $app domain $domain
ynh_app_setting_set $app path $path
ynh_app_setting_set $app admin $admin
ynh_app_setting_set $app is_public $is_public
# Modify dokuwiki conf
sed -i "s@YNH_ADMIN_USER@$admin@g" ../conf/dokuwiki.php
# Copy files to the right place
final_path=/var/www/$app
sudo mkdir -p $final_path
sudo cp -a ../sources/* $final_path
sudo mkdir "$final_path"
ynh_app_setting_set $app final_path $final_path
# Get source
SETUP_SOURCE
sudo cp ../conf/dokuwiki.php $final_path/conf
sudo cp ../conf/acl.auth.php $final_path/conf
# Files owned by root, www-data can just read
sudo find $final_path -type f -print0 | sudo xargs -0 chmod 0644
sudo find $final_path -type d -print0 | sudo xargs -0 chmod 0755
sudo chown -R root: $final_path
# Files owned by www-data can just read
# sudo find $final_path -type f -print0 | xargs -0 sudo chmod 0644
# sudo find $final_path -type d -print0 | xargs -0 sudo chmod 0755
sudo chown -R www-data: $final_path
# except for conf, data, some data subfolders, and lib/plugin, where www-data must have write permissions
sudo chown -R www-data:root $final_path/{conf,data,data/attic,data/cache,data/index,data/locks,data/media*,data/meta,data/pages,data/tmp,lib/plugins,lib/tpl}
sudo chmod -R 700 $final_path/{conf,data,data/attic,data/cache,data/index,data/locks,data/media*,data/meta,data/pages,data/tmp,lib/plugins,lib/tpl}
sudo chmod -R 700 $final_path/conf
sudo chmod -R 700 $final_path/data
sudo chmod -R 700 $final_path/lib/plugins
sudo chmod -R 700 $final_path/lib/tpl
# Modify Nginx configuration file and copy it to Nginx conf directory
sed -i "s@YNH_WWW_LOCATION@$location@g" ../conf/nginx.conf
sed -i "s@YNH_WWW_PATH@$path@g" ../conf/nginx.conf
sed -i "s@YNH_WWW_ALIAS@$final_path/@g" ../conf/nginx.conf
sudo cp ../conf/nginx.conf /etc/nginx/conf.d/$domain.d/$app.conf
sudo sed -i "s@__PATHTOCHANGE__@$path@g" /etc/nginx/conf.d/$domain.d/$app.conf
sudo sed -i "s@__FINALPATH__@$final_path@g" /etc/nginx/conf.d/$domain.d/$app.conf
sudo sed -i "s@__NAMETOCHANGE__@$app@g" /etc/nginx/conf.d/$domain.d/$app.conf
if [ "$is_public" = "Yes" ];
then
sudo yunohost app setting $app unprotected_uris -v "/"
sudo sed -i "s@#--PRIVATE--@@g" /etc/nginx/conf.d/$domain.d/$app.conf
fi
sudo service nginx reload
# Create the php-fpm pool config
POOL_FPM
# Public access for curl
ynh_app_setting_set $app unprotected_uris "/"
# Relaod SSOwat configuration
sudo yunohost app ssowatconf
# Reload php5-fpm and Nginx
sudo systemctl reload php5-fpm
sudo systemctl reload nginx
if [ "$is_public" = "No" ];
then
# Exit public access
ynh_app_setting_delete $app unprotected_uris
sudo yunohost app ssowatconf
fi

View file

@ -1,20 +1,25 @@
#!/bin/bash
# This is a multi-instance app, meaning it can be installed several times independently
# The id of the app as stated in the manifest is available as $YNH_APP_ID
# The instance number is available as $YNH_APP_INSTANCE_NUMBER (equals "1", "2", ...)
# The app instance name is available as $YNH_APP_INSTANCE_NAME
# - the first time the app is installed, YNH_APP_INSTANCE_NAME = ynhexample
# - the second time the app is installed, YNH_APP_INSTANCE_NAME = ynhexample__2
# - ynhexample__{N} for the subsequent installations, with N=3,4, ...
# The app instance name is probably what you are interested the most, since this is
# guaranteed to be unique. This is a good unique identifier to define installation path,
# db names, ...
# Exit on command errors and treat unset variables as an error
set -u
# Get multi-instances specific variables
app=$YNH_APP_INSTANCE_NAME
domain=$(sudo yunohost app setting $app domain)
# Source app helpers
. /usr/share/yunohost/helpers
sudo rm -rf /var/www/$app
sudo rm -f /etc/nginx/conf.d/$domain.d/$app.conf
# Retrieve app settings
domain=$(ynh_app_setting_get "$app" domain)
sudo service nginx reload
# Delete app directory and configurations
sudo rm -rf "/var/www/${app}"
sudo rm -f "/etc/php5/fpm/pool.d/${app}.conf"
sudo rm -f "/etc/php5/fpm/conf.d/20-${app}.ini"
[[ -n $domain ]] && sudo rm -f "/etc/nginx/conf.d/${domain}.d/${app}.conf"
# Reload services
sudo systemctl reload php5-fpm
sudo systemctl reload nginx
echo -e "\e[0m" # Restore normal color

View file

@ -1,63 +1,59 @@
#!/bin/bash
# This restore script is adapted to Yunohost >=2.4
# causes the shell to exit if any subcommand or pipeline returns a non-zero status
set -e
# Exit on command errors and treat unset variables as an error
set -eu
# Source YNH helpers
. /usr/share/yunohost/helpers
# This is a multi-instance app, meaning it can be installed several times independently
# The id of the app as stated in the manifest is available as $YNH_APP_ID
# The instance number is available as $YNH_APP_INSTANCE_NUMBER (equals "1", "2", ...)
# The app instance name is available as $YNH_APP_INSTANCE_NAME
# - the first time the app is installed, YNH_APP_INSTANCE_NAME = ynhexample
# - the second time the app is installed, YNH_APP_INSTANCE_NAME = ynhexample__2
# - ynhexample__{N} for the subsequent installations, with N=3,4, ...
# The app instance name is probably what you are interested the most, since this is
# guaranteed to be unique. This is a good unique identifier to define installation path,
# db names, ...
# The parameter $2 is the id of the app instance ex: ynhexample__2
app=$YNH_APP_INSTANCE_NAME
# Retrieve arguments
domain=$(sudo yunohost app setting $app domain)
# Source app helpers
source /usr/share/yunohost/helpers
# Get old parameter of the app
domain=$(sudo yunohost app setting $app domain)
path=$(sudo yunohost app setting $app path)
user=$(sudo yunohost app setting $app allowed_users)
is_public=$(sudo yunohost app setting $app is_public)
domain=$(ynh_app_setting_get $app domain)
path=$(ynh_app_setting_get $app path)
is_public=$(ynh_app_setting_get $app is_public)
# Check domain/path availability
sudo yunohost app checkurl $domain$path -a $app
if [[ ! $? -eq 0 ]]; then
echo "There is already an app on this URL : $domain$path" | sudo tee /dev/stderr
exit 1
fi
final_path=/var/www/$app
sudo yunohost app checkurl "${domain}${path}" -a "$app" \
|| ynh_die "Path not available: ${domain}${path}"
# Check $final_path
final_path="/var/www/${app}"
if [ -d $final_path ]; then
echo "There is already a directory: $final_path " | sudo tee /dev/stderr
exit 1
ynh_die "There is already a directory: $final_path"
fi
conf=/etc/nginx/conf.d/$domain.d/$app.conf
if [ -f $conf ]; then
echo "There is already a nginx conf file at this path: $conf " | sudo tee /dev/stderr
exit 1
# Check configuration files nginx
nginx_conf="/etc/nginx/conf.d/${domain}.d/${app}.conf"
if [ -f $nginx_conf ]; then
ynh_die "The NGINX configuration already exists at '${nginx_conf}'. You should safely delete it before restoring this app."
fi
# Check configuration files php-fpm
phpfpm_conf="/etc/php5/fpm/pool.d/${app}.conf"
if [ -f $phpfpm_conf ]; then
ynh_die "The PHP FPM configuration already exists at '${phpfpm_conf}'. You should safely delete it before restoring this app."
fi
phpfpm_ini="/etc/php5/fpm/conf.d/20-${app}.ini"
if [ -f $phpfpm_ini ]; then
ynh_die "The PHP FPM INI configuration already exists at '${phpfpm_ini}'. You should safely delete it before restoring this app."
fi
# Restore sources & data
sudo cp -a "./sources" $final_path
sudo cp -a ./sources "${final_path}"
# Restore conf files
sudo cp -a "./conf/nginx.conf" $conf
# Set permissions
sudo chown -R www-data: "${final_path}"
# Reload Nginx
sudo service nginx reload
# Restore nginx configuration files
sudo cp -a ./nginx.conf "${nginx_conf}"
# Restore php-fpm configuration files
sudo cp -a ./php-fpm.conf "${phpfpm_conf}"
sudo cp -a ./php-fpm.ini "${phpfpm_ini}"
# Set ssowat config
if [ "$is_public" = "Yes" ];
then
sudo yunohost app setting $app unprotected_uris -v "/"
fi
# Reload services
sudo systemctl reload php5-fpm
sudo systemctl reload nginx
sudo yunohost app ssowatconf

View file

@ -1,7 +1,11 @@
#!/bin/bash
# causes the shell to exit if any subcommand or pipeline returns a non-zero status
set -e
# Exit on command errors and treat unset variables as an error
set -eu
source .fonctions
# Source app helpers
source /usr/share/yunohost/helpers
# This is a multi-instance app, meaning it can be installed several times independently
# The id of the app as stated in the manifest is available as $YNH_APP_ID
@ -16,10 +20,11 @@ set -e
app=$YNH_APP_INSTANCE_NAME
# Retrieve app settings
domain=$(sudo yunohost app setting $app domain)
path=$(sudo yunohost app setting $app path)
admin=$(sudo yunohost app setting $app admin)
is_public=$(sudo yunohost app setting $app is_public)
domain=$(ynh_app_setting_get $app domain)
path=$(ynh_app_setting_get $app path)
admin=$(ynh_app_setting_get $app admin)
is_public=$(ynh_app_setting_get $app is_public)
multisite=$(ynh_app_setting_get $app multisite)
# Remove trailing slash to path
path=${path%/}
@ -30,17 +35,19 @@ location=${path:-/}
if [ -z "$admin" ];
then
admin=$(sudo yunohost user list | grep 'username' -m1 | awk '{print $2}')
sudo yunohost app setting $app is_public -v "$is_public"
sudo ynh_app_setting_set $app is_public -v "$is_public"
fi
# Modify dokuwiki conf
sed -i "s@YNH_ADMIN_USER@$admin@g" ../conf/dokuwiki.php
# Copy files to the right place
final_path=/var/www/$app
sudo mkdir -p $final_path
sudo cp -a ../sources/* $final_path
# Get source
SETUP_SOURCE
sudo cp ../conf/dokuwiki.php $final_path/conf
# Do not override ACL configuration file
@ -54,27 +61,59 @@ sudo touch $final_path/doku.php
# Remove deleted files
# See https://www.dokuwiki.org/install:unused_files
if [ -f "../sources/data/deleted.files" ]; then
grep -Ev '^($|#)' ../sources/data/deleted.files | xargs -I {} sudo rm -vrf $final_path/{}
fi
# Files owned by root, www-data can just read
sudo find $final_path -type f -print0 | sudo xargs -0 chmod 0644
sudo find $final_path -type d -print0 | sudo xargs -0 chmod 0755
sudo chown -R root: $final_path
# Change owner for all plugins
sudo chmod -R 755 $final_path/lib/plugins
# Update all plugins
for name_plugin in $(sudo -s cat $final_path/lib/plugins/*/plugin.info.txt | grep url | awk -F':' '{print $3}');
do
# Get a official plugin for dokuwiki, not update a no-official
sudo wget -nv --quiet "https://github.com/splitbrain/dokuwiki-plugin-${name_plugin}/zipball/master" -O "${name_plugin}.zip" -o /dev/null || true
if [ -s "${name_plugin}.zip" ]; then
sudo unzip ${name_plugin}.zip
sudo cp -a splitbrain-dokuwiki-plugin-${name_plugin}*/. "${final_path}/lib/plugins/${name_plugin}/"
fi
done
# Files owned by www-data can just read
# sudo find $final_path -type f -print0 | xargs -0 sudo chmod 0644
# sudo find $final_path -type d -print0 | xargs -0 sudo chmod 0755
sudo chown -R www-data: $final_path
# except for conf, data, some data subfolders, and lib/plugin, where www-data must have write permissions
sudo chown -R www-data:root $final_path/{conf,data,data/attic,data/cache,data/index,data/locks,data/media*,data/meta,data/pages,data/tmp,lib/plugins,lib/tpl}
sudo chmod -R 700 $final_path/{conf,data,data/attic,data/cache,data/index,data/locks,data/media*,data/meta,data/pages,data/tmp,lib/plugins,lib/tpl}
if [ -d "${final_path}/data/media" ]; then
sudo chown -R www-data:root $final_path/{data/attic,data/cache,data/index,data/locks,data/media*,data/meta,data/pages,data/tmp}
fi
sudo chown -R www-data:root $final_path/{conf,data,lib/plugins,lib/tpl}
sudo chmod -R 700 $final_path/conf
sudo chmod -R 700 $final_path/data
sudo chmod -R 700 $final_path/lib/plugins
sudo chmod -R 700 $final_path/lib/tpl
# Modify Nginx configuration file and copy it to Nginx conf directory
sed -i "s@YNH_WWW_LOCATION@$location@g" ../conf/nginx.conf
sed -i "s@YNH_WWW_PATH@$path@g" ../conf/nginx.conf
sed -i "s@YNH_WWW_ALIAS@$final_path/@g" ../conf/nginx.conf
sudo cp ../conf/nginx.conf /etc/nginx/conf.d/$domain.d/$app.conf
sudo sed -i "s@__PATHTOCHANGE__@$path@g" /etc/nginx/conf.d/$domain.d/$app.conf
sudo sed -i "s@__FINALPATH__@$final_path@g" /etc/nginx/conf.d/$domain.d/$app.conf
sudo sed -i "s@__NAMETOCHANGE__@$app@g" /etc/nginx/conf.d/$domain.d/$app.conf
if [ "$is_public" = "Yes" ];
then
sudo yunohost app setting $app skipped_uris -d
sudo yunohost app setting $app unprotected_uris -v "/"
sudo sed -i "s@#--PRIVATE--@@g" /etc/nginx/conf.d/$domain.d/$app.conf
fi
sudo service nginx reload
# Create the php-fpm pool config
POOL_FPM
# Setup SSOwat
ynh_app_setting_set "$app" is_public "$is_public"
if [ "$is_public" = "Yes" ];
then
ynh_app_setting_set "$app" unprotected_uris "/"
fi
sudo systemctl reload php5-fpm
sudo systemctl reload nginx
sudo yunohost app ssowatconf

View file

@ -1,35 +0,0 @@
## Enable this to restrict editing to logged in users only
## You should disable Indexes and MultiViews either here or in the
## global config. Symlinks maybe needed for URL rewriting.
#Options -Indexes -MultiViews +FollowSymLinks
## make sure nobody gets the htaccess, README, COPYING or VERSION files
<Files ~ "^([\._]ht|README$|VERSION$|COPYING$)">
Order allow,deny
Deny from all
</Files>
## Uncomment these rules if you want to have nice URLs using
## $conf['userewrite'] = 1 - not needed for rewrite mode 2
#RewriteEngine on
#
#RewriteRule ^_media/(.*) lib/exe/fetch.php?media=$1 [QSA,L]
#RewriteRule ^_detail/(.*) lib/exe/detail.php?media=$1 [QSA,L]
#RewriteRule ^_export/([^/]+)/(.*) doku.php?do=export_$1&id=$2 [QSA,L]
#RewriteRule ^$ doku.php [L]
#RewriteCond %{REQUEST_FILENAME} !-f
#RewriteCond %{REQUEST_FILENAME} !-d
#RewriteRule (.*) doku.php?id=$1 [QSA,L]
#RewriteRule ^index.php$ doku.php
#
## Not all installations will require the following line. If you do,
## change "/dokuwiki" to the path to your dokuwiki directory relative
## to your document root.
#RewriteBase /dokuwiki
#
## If you enable DokuWikis XML-RPC interface, you should consider to
## restrict access to it over HTTPS only! Uncomment the following two
## rules if your server setup allows HTTPS.
#RewriteCond %{HTTPS} !=on
#RewriteRule ^lib/exe/xmlrpc.php$ https://%{SERVER_NAME}%{REQUEST_URI} [L,R=301]

View file

@ -1,339 +0,0 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.

View file

@ -1,10 +0,0 @@
All documentation for DokuWiki is available online
at http://www.dokuwiki.org/
For Installation Instructions see
http://www.dokuwiki.org/install
DokuWiki - 2004-2016 (c) Andreas Gohr <andi@splitbrain.org>
and the DokuWiki Community
See COPYING and file headers for license info

View file

@ -1 +0,0 @@
2016-06-26a "Elenor of Tsort"

View file

@ -1,7 +0,0 @@
<IfModule mod_authz_host>
Require all denied
</IfModule>
<IfModule !mod_authz_host>
Order allow,deny
Deny from all
</IfModule>

View file

@ -1,318 +0,0 @@
#!/usr/bin/php
<?php
if(!defined('DOKU_INC')) define('DOKU_INC', realpath(dirname(__FILE__).'/../').'/');
define('NOSESSION', 1);
require_once(DOKU_INC.'inc/init.php');
/**
* Checkout and commit pages from the command line while maintaining the history
*/
class PageCLI extends DokuCLI {
protected $force = false;
protected $username = '';
/**
* Register options and arguments on the given $options object
*
* @param DokuCLI_Options $options
* @return void
*/
protected function setup(DokuCLI_Options $options) {
/* global */
$options->registerOption(
'force',
'force obtaining a lock for the page (generally bad idea)',
'f'
);
$options->registerOption(
'user',
'work as this user. defaults to current CLI user',
'u',
'username'
);
$options->setHelp(
'Utility to help command line Dokuwiki page editing, allow '.
'pages to be checked out for editing then committed after changes'
);
/* checkout command */
$options->registerCommand(
'checkout',
'Checks out a file from the repository, using the wiki id and obtaining '.
'a lock for the page. '."\n".
'If a working_file is specified, this is where the page is copied to. '.
'Otherwise defaults to the same as the wiki page in the current '.
'working directory.'
);
$options->registerArgument(
'wikipage',
'The wiki page to checkout',
true,
'checkout'
);
$options->registerArgument(
'workingfile',
'How to name the local checkout',
false,
'checkout'
);
/* commit command */
$options->registerCommand(
'commit',
'Checks in the working_file into the repository using the specified '.
'wiki id, archiving the previous version.'
);
$options->registerArgument(
'workingfile',
'The local file to commit',
true,
'commit'
);
$options->registerArgument(
'wikipage',
'The wiki page to create or update',
true,
'commit'
);
$options->registerOption(
'message',
'Summary describing the change (required)',
'm',
'summary',
'commit'
);
$options->registerOption(
'trivial',
'minor change',
't',
false,
'commit'
);
/* lock command */
$options->registerCommand(
'lock',
'Obtains or updates a lock for a wiki page'
);
$options->registerArgument(
'wikipage',
'The wiki page to lock',
true,
'lock'
);
/* unlock command */
$options->registerCommand(
'unlock',
'Removes a lock for a wiki page.'
);
$options->registerArgument(
'wikipage',
'The wiki page to unlock',
true,
'unlock'
);
}
/**
* Your main program
*
* Arguments and options have been parsed when this is run
*
* @param DokuCLI_Options $options
* @return void
*/
protected function main(DokuCLI_Options $options) {
$this->force = $options->getOpt('force', false);
$this->username = $options->getOpt('user', $this->getUser());
$command = $options->getCmd();
switch($command) {
case 'checkout':
$wiki_id = array_shift($options->args);
$localfile = array_shift($options->args);
$this->commandCheckout($wiki_id, $localfile);
break;
case 'commit':
$localfile = array_shift($options->args);
$wiki_id = array_shift($options->args);
$this->commandCommit(
$localfile,
$wiki_id,
$options->getOpt('message', ''),
$options->getOpt('trivial', false)
);
break;
case 'lock':
$wiki_id = array_shift($options->args);
$this->obtainLock($wiki_id);
$this->success("$wiki_id locked");
break;
case 'unlock':
$wiki_id = array_shift($options->args);
$this->clearLock($wiki_id);
$this->success("$wiki_id unlocked");
break;
default:
echo $options->help();
}
}
/**
* Check out a file
*
* @param string $wiki_id
* @param string $localfile
*/
protected function commandCheckout($wiki_id, $localfile) {
global $conf;
$wiki_id = cleanID($wiki_id);
$wiki_fn = wikiFN($wiki_id);
if(!file_exists($wiki_fn)) {
$this->fatal("$wiki_id does not yet exist");
}
if(empty($localfile)) {
$localfile = getcwd().'/'.utf8_basename($wiki_fn);
}
if(!file_exists(dirname($localfile))) {
$this->fatal("Directory ".dirname($localfile)." does not exist");
}
if(stristr(realpath(dirname($localfile)), realpath($conf['datadir'])) !== false) {
$this->fatal("Attempt to check out file into data directory - not allowed");
}
$this->obtainLock($wiki_id);
if(!copy($wiki_fn, $localfile)) {
$this->clearLock($wiki_id);
$this->fatal("Unable to copy $wiki_fn to $localfile");
}
$this->success("$wiki_id > $localfile");
}
/**
* Save a file as a new page revision
*
* @param string $localfile
* @param string $wiki_id
* @param string $message
* @param bool $minor
*/
protected function commandCommit($localfile, $wiki_id, $message, $minor) {
$wiki_id = cleanID($wiki_id);
$message = trim($message);
if(!file_exists($localfile)) {
$this->fatal("$localfile does not exist");
}
if(!is_readable($localfile)) {
$this->fatal("Cannot read from $localfile");
}
if(!$message) {
$this->fatal("Summary message required");
}
$this->obtainLock($wiki_id);
saveWikiText($wiki_id, file_get_contents($localfile), $message, $minor);
$this->clearLock($wiki_id);
$this->success("$localfile > $wiki_id");
}
/**
* Lock the given page or exit
*
* @param string $wiki_id
*/
protected function obtainLock($wiki_id) {
if($this->force) $this->deleteLock($wiki_id);
$_SERVER['REMOTE_USER'] = $this->username;
if(checklock($wiki_id)) {
$this->error("Page $wiki_id is already locked by another user");
exit(1);
}
lock($wiki_id);
if(checklock($wiki_id)) {
$this->error("Unable to obtain lock for $wiki_id ");
var_dump(checklock($wiki_id));
exit(1);
}
}
/**
* Clear the lock on the given page
*
* @param string $wiki_id
*/
protected function clearLock($wiki_id) {
if($this->force) $this->deleteLock($wiki_id);
$_SERVER['REMOTE_USER'] = $this->username;
if(checklock($wiki_id)) {
$this->error("Page $wiki_id is locked by another user");
exit(1);
}
unlock($wiki_id);
if(file_exists(wikiLockFN($wiki_id))) {
$this->error("Unable to clear lock for $wiki_id");
exit(1);
}
}
/**
* Forcefully remove a lock on the page given
*
* @param string $wiki_id
*/
protected function deleteLock($wiki_id) {
$wikiLockFN = wikiLockFN($wiki_id);
if(file_exists($wikiLockFN)) {
if(!unlink($wikiLockFN)) {
$this->error("Unable to delete $wikiLockFN");
exit(1);
}
}
}
/**
* Get the current user's username from the environment
*
* @return string
*/
protected function getUser() {
$user = getenv('USER');
if(empty ($user)) {
$user = getenv('USERNAME');
} else {
return $user;
}
if(empty ($user)) {
$user = 'admin';
}
return $user;
}
}
// Main
$cli = new PageCLI();
$cli->run();

View file

@ -1,336 +0,0 @@
#!/usr/bin/php
<?php
if(!defined('DOKU_INC')) define('DOKU_INC', realpath(dirname(__FILE__).'/../').'/');
define('NOSESSION', 1);
require_once(DOKU_INC.'inc/init.php');
/**
* Easily manage DokuWiki git repositories
*
* @author Andreas Gohr <andi@splitbrain.org>
*/
class GitToolCLI extends DokuCLI {
/**
* Register options and arguments on the given $options object
*
* @param DokuCLI_Options $options
* @return void
*/
protected function setup(DokuCLI_Options $options) {
$options->setHelp(
"Manage git repositories for DokuWiki and its plugins and templates.\n\n".
"$> ./bin/gittool.php clone gallery template:ach\n".
"$> ./bin/gittool.php repos\n".
"$> ./bin/gittool.php origin -v"
);
$options->registerArgument(
'command',
'Command to execute. See below',
true
);
$options->registerCommand(
'clone',
'Tries to install a known plugin or template (prefix with template:) via git. Uses the DokuWiki.org '.
'plugin repository to find the proper git repository. Multiple extensions can be given as parameters'
);
$options->registerArgument(
'extension',
'name of the extension to install, prefix with \'template:\' for templates',
true,
'clone'
);
$options->registerCommand(
'install',
'The same as clone, but when no git source repository can be found, the extension is installed via '.
'download'
);
$options->registerArgument(
'extension',
'name of the extension to install, prefix with \'template:\' for templates',
true,
'install'
);
$options->registerCommand(
'repos',
'Lists all git repositories found in this DokuWiki installation'
);
$options->registerCommand(
'*',
'Any unknown commands are assumed to be arguments to git and will be executed in all repositories '.
'found within this DokuWiki installation'
);
}
/**
* Your main program
*
* Arguments and options have been parsed when this is run
*
* @param DokuCLI_Options $options
* @return void
*/
protected function main(DokuCLI_Options $options) {
$command = $options->getCmd();
if(!$command) $command = array_shift($options->args);
switch($command) {
case '':
echo $options->help();
break;
case 'clone':
$this->cmd_clone($options->args);
break;
case 'install':
$this->cmd_install($options->args);
break;
case 'repo':
case 'repos':
$this->cmd_repos();
break;
default:
$this->cmd_git($command, $options->args);
}
}
/**
* Tries to install the given extensions using git clone
*
* @param array $extensions
*/
public function cmd_clone($extensions) {
$errors = array();
$succeeded = array();
foreach($extensions as $ext) {
$repo = $this->getSourceRepo($ext);
if(!$repo) {
$this->error("could not find a repository for $ext");
$errors[] = $ext;
} else {
if($this->cloneExtension($ext, $repo)) {
$succeeded[] = $ext;
} else {
$errors[] = $ext;
}
}
}
echo "\n";
if($succeeded) $this->success('successfully cloned the following extensions: '.join(', ', $succeeded));
if($errors) $this->error('failed to clone the following extensions: '.join(', ', $errors));
}
/**
* Tries to install the given extensions using git clone with fallback to install
*
* @param array $extensions
*/
public function cmd_install($extensions) {
$errors = array();
$succeeded = array();
foreach($extensions as $ext) {
$repo = $this->getSourceRepo($ext);
if(!$repo) {
$this->info("could not find a repository for $ext");
if($this->downloadExtension($ext)) {
$succeeded[] = $ext;
} else {
$errors[] = $ext;
}
} else {
if($this->cloneExtension($ext, $repo)) {
$succeeded[] = $ext;
} else {
$errors[] = $ext;
}
}
}
echo "\n";
if($succeeded) $this->success('successfully installed the following extensions: '.join(', ', $succeeded));
if($errors) $this->error('failed to install the following extensions: '.join(', ', $errors));
}
/**
* Executes the given git command in every repository
*
* @param $cmd
* @param $arg
*/
public function cmd_git($cmd, $arg) {
$repos = $this->findRepos();
$shell = array_merge(array('git', $cmd), $arg);
$shell = array_map('escapeshellarg', $shell);
$shell = join(' ', $shell);
foreach($repos as $repo) {
if(!@chdir($repo)) {
$this->error("Could not change into $repo");
continue;
}
echo "\n";
$this->info("executing $shell in $repo");
$ret = 0;
system($shell, $ret);
if($ret == 0) {
$this->success("git succeeded in $repo");
} else {
$this->error("git failed in $repo");
}
}
}
/**
* Simply lists the repositories
*/
public function cmd_repos() {
$repos = $this->findRepos();
foreach($repos as $repo) {
echo "$repo\n";
}
}
/**
* Install extension from the given download URL
*
* @param string $ext
* @return bool|null
*/
private function downloadExtension($ext) {
/** @var helper_plugin_extension_extension $plugin */
$plugin = plugin_load('helper', 'extension_extension');
if(!$ext) die("extension plugin not available, can't continue");
$plugin->setExtension($ext);
$url = $plugin->getDownloadURL();
if(!$url) {
$this->error("no download URL for $ext");
return false;
}
$ok = false;
try {
$this->info("installing $ext via download from $url");
$ok = $plugin->installFromURL($url);
} catch(Exception $e) {
$this->error($e->getMessage());
}
if($ok) {
$this->success("installed $ext via download");
return true;
} else {
$this->success("failed to install $ext via download");
return false;
}
}
/**
* Clones the extension from the given repository
*
* @param string $ext
* @param string $repo
* @return bool
*/
private function cloneExtension($ext, $repo) {
if(substr($ext, 0, 9) == 'template:') {
$target = fullpath(tpl_incdir().'../'.substr($ext, 9));
} else {
$target = DOKU_PLUGIN.$ext;
}
$this->info("cloning $ext from $repo to $target");
$ret = 0;
system("git clone $repo $target", $ret);
if($ret === 0) {
$this->success("cloning of $ext succeeded");
return true;
} else {
$this->error("cloning of $ext failed");
return false;
}
}
/**
* Returns all git repositories in this DokuWiki install
*
* Looks in root, template and plugin directories only.
*
* @return array
*/
private function findRepos() {
$this->info('Looking for .git directories');
$data = array_merge(
glob(DOKU_INC.'.git', GLOB_ONLYDIR),
glob(DOKU_PLUGIN.'*/.git', GLOB_ONLYDIR),
glob(fullpath(tpl_incdir().'../').'/*/.git', GLOB_ONLYDIR)
);
if(!$data) {
$this->error('Found no .git directories');
} else {
$this->success('Found '.count($data).' .git directories');
}
$data = array_map('fullpath', array_map('dirname', $data));
return $data;
}
/**
* Returns the repository for the given extension
*
* @param $extension
* @return false|string
*/
private function getSourceRepo($extension) {
/** @var helper_plugin_extension_extension $ext */
$ext = plugin_load('helper', 'extension_extension');
if(!$ext) die("extension plugin not available, can't continue");
$ext->setExtension($extension);
$repourl = $ext->getSourcerepoURL();
if(!$repourl) return false;
// match github repos
if(preg_match('/github\.com\/([^\/]+)\/([^\/]+)/i', $repourl, $m)) {
$user = $m[1];
$repo = $m[2];
return 'https://github.com/'.$user.'/'.$repo.'.git';
}
// match gitorious repos
if(preg_match('/gitorious.org\/([^\/]+)\/([^\/]+)?/i', $repourl, $m)) {
$user = $m[1];
$repo = $m[2];
if(!$repo) $repo = $user;
return 'https://git.gitorious.org/'.$user.'/'.$repo.'.git';
}
// match bitbucket repos - most people seem to use mercurial there though
if(preg_match('/bitbucket\.org\/([^\/]+)\/([^\/]+)/i', $repourl, $m)) {
$user = $m[1];
$repo = $m[2];
return 'https://bitbucket.org/'.$user.'/'.$repo.'.git';
}
return false;
}
}
// Main
$cli = new GitToolCLI();
$cli->run();

View file

@ -1,103 +0,0 @@
#!/usr/bin/php
<?php
if(!defined('DOKU_INC')) define('DOKU_INC', realpath(dirname(__FILE__).'/../').'/');
define('NOSESSION', 1);
require_once(DOKU_INC.'inc/init.php');
/**
* Update the Search Index from command line
*/
class IndexerCLI extends DokuCLI {
private $quiet = false;
private $clear = false;
/**
* Register options and arguments on the given $options object
*
* @param DokuCLI_Options $options
* @return void
*/
protected function setup(DokuCLI_Options $options) {
$options->setHelp(
'Updates the searchindex by indexing all new or changed pages. When the -c option is '.
'given the index is cleared first.'
);
$options->registerOption(
'clear',
'clear the index before updating',
'c'
);
$options->registerOption(
'quiet',
'don\'t produce any output',
'q'
);
}
/**
* Your main program
*
* Arguments and options have been parsed when this is run
*
* @param DokuCLI_Options $options
* @return void
*/
protected function main(DokuCLI_Options $options) {
$this->clear = $options->getOpt('clear');
$this->quiet = $options->getOpt('quiet');
if($this->clear) $this->clearindex();
$this->update();
}
/**
* Update the index
*/
function update() {
global $conf;
$data = array();
$this->quietecho("Searching pages... ");
search($data, $conf['datadir'], 'search_allpages', array('skipacl' => true));
$this->quietecho(count($data)." pages found.\n");
foreach($data as $val) {
$this->index($val['id']);
}
}
/**
* Index the given page
*
* @param string $id
*/
function index($id) {
$this->quietecho("$id... ");
idx_addPage($id, !$this->quiet, $this->clear);
$this->quietecho("done.\n");
}
/**
* Clear all index files
*/
function clearindex() {
$this->quietecho("Clearing index... ");
idx_get_indexer()->clear();
$this->quietecho("done.\n");
}
/**
* Print message if not supressed
*
* @param string $msg
*/
function quietecho($msg) {
if(!$this->quiet) echo $msg;
}
}
// Main
$cli = new IndexerCLI();
$cli->run();

View file

@ -1,61 +0,0 @@
#!/usr/bin/php
<?php
if(!defined('DOKU_INC')) define('DOKU_INC', realpath(dirname(__FILE__).'/../').'/');
define('NOSESSION', 1);
require_once(DOKU_INC.'inc/init.php');
/**
* A simple commandline tool to render some DokuWiki syntax with a given
* renderer.
*
* This may not work for plugins that expect a certain environment to be
* set up before rendering, but should work for most or even all standard
* DokuWiki markup
*
* @license GPL2
* @author Andreas Gohr <andi@splitbrain.org>
*/
class RenderCLI extends DokuCLI {
/**
* Register options and arguments on the given $options object
*
* @param DokuCLI_Options $options
* @return void
*/
protected function setup(DokuCLI_Options $options) {
$options->setHelp(
'A simple commandline tool to render some DokuWiki syntax with a given renderer.'.
"\n\n".
'This may not work for plugins that expect a certain environment to be '.
'set up before rendering, but should work for most or even all standard '.
'DokuWiki markup'
);
$options->registerOption('renderer', 'The renderer mode to use. Defaults to xhtml', 'r', 'mode');
}
/**
* Your main program
*
* Arguments and options have been parsed when this is run
*
* @param DokuCLI_Options $options
* @throws DokuCLI_Exception
* @return void
*/
protected function main(DokuCLI_Options $options) {
$renderer = $options->getOpt('renderer', 'xhtml');
// do the action
$source = stream_get_contents(STDIN);
$info = array();
$result = p_render($renderer, p_get_instructions($source), $info);
if(is_null($result)) throw new DokuCLI_Exception("No such renderer $renderer");
echo $result;
}
}
// Main
$cli = new RenderCLI();
$cli->run();

View file

@ -1,111 +0,0 @@
#!/usr/bin/php
<?php
if(!defined('DOKU_INC')) define('DOKU_INC', realpath(dirname(__FILE__).'/../').'/');
define('NOSESSION', 1);
require_once(DOKU_INC.'inc/init.php');
/**
* Remove unwanted languages from a DokuWiki install
*/
class StripLangsCLI extends DokuCLI {
/**
* Register options and arguments on the given $options object
*
* @param DokuCLI_Options $options
* @return void
*/
protected function setup(DokuCLI_Options $options) {
$options->setHelp(
'Remove all languages from the installation, besides the ones specified. English language '.
'is never removed!'
);
$options->registerOption(
'keep',
'Comma separated list of languages to keep in addition to English.',
'k',
'langcodes'
);
$options->registerOption(
'english-only',
'Remove all languages except English',
'e'
);
}
/**
* Your main program
*
* Arguments and options have been parsed when this is run
*
* @param DokuCLI_Options $options
* @return void
*/
protected function main(DokuCLI_Options $options) {
if($options->getOpt('keep')) {
$keep = explode(',', $options->getOpt('keep'));
if(!in_array('en', $keep)) $keep[] = 'en';
} elseif($options->getOpt('english-only')) {
$keep = array('en');
} else {
echo $options->help();
exit(0);
}
// Kill all language directories in /inc/lang and /lib/plugins besides those in $langs array
$this->stripDirLangs(realpath(dirname(__FILE__).'/../inc/lang'), $keep);
$this->processExtensions(realpath(dirname(__FILE__).'/../lib/plugins'), $keep);
$this->processExtensions(realpath(dirname(__FILE__).'/../lib/tpl'), $keep);
}
/**
* Strip languages from extensions
*
* @param string $path path to plugin or template dir
* @param array $keep_langs languages to keep
*/
protected function processExtensions($path, $keep_langs) {
if(is_dir($path)) {
$entries = scandir($path);
foreach($entries as $entry) {
if($entry != "." && $entry != "..") {
if(is_dir($path.'/'.$entry)) {
$plugin_langs = $path.'/'.$entry.'/lang';
if(is_dir($plugin_langs)) {
$this->stripDirLangs($plugin_langs, $keep_langs);
}
}
}
}
}
}
/**
* Strip languages from path
*
* @param string $path path to lang dir
* @param array $keep_langs languages to keep
*/
protected function stripDirLangs($path, $keep_langs) {
$dir = dir($path);
while(($cur_dir = $dir->read()) !== false) {
if($cur_dir != '.' and $cur_dir != '..' and is_dir($path.'/'.$cur_dir)) {
if(!in_array($cur_dir, $keep_langs, true)) {
io_rmdir($path.'/'.$cur_dir, true);
}
}
}
$dir->close();
}
}
$cli = new StripLangsCLI();
$cli->run();

View file

@ -1,153 +0,0 @@
#!/usr/bin/php
<?php
if(!defined('DOKU_INC')) define('DOKU_INC', realpath(dirname(__FILE__).'/../').'/');
define('NOSESSION', 1);
require_once(DOKU_INC.'inc/init.php');
/**
* Find wanted pages
*/
class WantedPagesCLI extends DokuCLI {
const DIR_CONTINUE = 1;
const DIR_NS = 2;
const DIR_PAGE = 3;
/**
* Register options and arguments on the given $options object
*
* @param DokuCLI_Options $options
* @return void
*/
protected function setup(DokuCLI_Options $options) {
$options->setHelp(
'Outputs a list of wanted pages (pages which have internal links but do not yet exist).'
);
$options->registerArgument(
'namespace',
'The namespace to lookup. Defaults to root namespace',
false
);
}
/**
* Your main program
*
* Arguments and options have been parsed when this is run
*
* @param DokuCLI_Options $options
* @return void
*/
protected function main(DokuCLI_Options $options) {
if($options->args) {
$startdir = dirname(wikiFN($options->args[0].':xxx'));
} else {
$startdir = dirname(wikiFN('xxx'));
}
$this->info("searching $startdir");
$wanted_pages = array();
foreach($this->get_pages($startdir) as $page) {
$wanted_pages = array_merge($wanted_pages, $this->internal_links($page));
}
$wanted_pages = array_unique($wanted_pages);
sort($wanted_pages);
foreach($wanted_pages as $page) {
print $page."\n";
}
}
/**
* Determine directions of the search loop
*
* @param string $entry
* @param string $basepath
* @return int
*/
protected function dir_filter($entry, $basepath) {
if($entry == '.' || $entry == '..') {
return WantedPagesCLI::DIR_CONTINUE;
}
if(is_dir($basepath.'/'.$entry)) {
if(strpos($entry, '_') === 0) {
return WantedPagesCLI::DIR_CONTINUE;
}
return WantedPagesCLI::DIR_NS;
}
if(preg_match('/\.txt$/', $entry)) {
return WantedPagesCLI::DIR_PAGE;
}
return WantedPagesCLI::DIR_CONTINUE;
}
/**
* Collects recursively the pages in a namespace
*
* @param string $dir
* @return array
* @throws DokuCLI_Exception
*/
protected function get_pages($dir) {
static $trunclen = null;
if(!$trunclen) {
global $conf;
$trunclen = strlen($conf['datadir'].':');
}
if(!is_dir($dir)) {
throw new DokuCLI_Exception("Unable to read directory $dir");
}
$pages = array();
$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));
} else {
$page = array(
'id' => pathID(substr($dir.'/'.$entry, $trunclen)),
'file' => $dir.'/'.$entry,
);
$pages[] = $page;
}
}
closedir($dh);
return $pages;
}
/**
* Parse instructions and returns the non-existing links
*
* @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;
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;
}
}
}
return $links;
}
}
// Main
$cli = new WantedPagesCLI();
$cli->run();

View file

@ -1,8 +0,0 @@
## no access to the conf directory
<IfModule mod_authz_host>
Require all denied
</IfModule>
<IfModule !mod_authz_host>
Order allow,deny
Deny from all
</IfModule>

View file

@ -1,21 +0,0 @@
# acl.auth.php
# <?php exit()?>
# Don't modify the lines above
#
# Access Control Lists
#
# Editing this file by hand shouldn't be necessary. Use the ACL
# Manager interface instead.
#
# If your auth backend allows special char like spaces in groups
# or user names you need to urlencode them (only chars <128, leave
# UTF-8 multibyte chars as is)
#
# none 0
# read 1
# edit 2
# create 4
# upload 8
# delete 16
* @ALL 8

View file

@ -1,61 +0,0 @@
# Acronyms.
ACL Access Control List
AFAICS As far as I can see
AFAIK As far as I know
AFAIR As far as I remember
API Application Programming Interface
ASAP As soon as possible
ASCII American Standard Code for Information Interchange
BTW By the way
CMS Content Management System
CSS Cascading Style Sheets
DNS Domain Name System
EOF End of file
EOL End of line
EOM End of message
EOT End of text
FAQ Frequently Asked Questions
FTP File Transfer Protocol
FOSS Free & Open-Source Software
FLOSS Free/Libre and Open Source Software
FUD Fear, Uncertainty, and Doubt
GB Gigabyte
GHz Gigahertz
GPL GNU General Public License
GUI Graphical User Interface
HTML HyperText Markup Language
IANAL I am not a lawyer (but)
IE Internet Explorer
IIRC If I remember correctly
IMHO In my humble opinion
IMO In my opinion
IOW In other words
IRC Internet Relay Chat
IRL In real life
KISS Keep it simple stupid
LAN Local Area Network
LGPL GNU Lesser General Public License
LOL Laughing out loud
MathML Mathematical Markup Language
MB Megabyte
MHz Megahertz
MSIE Microsoft Internet Explorer
OMG Oh my God
OS Operating System
OSS Open Source Software
OTOH On the other hand
PITA Pain in the Ass
RFC Request for Comments
ROTFL Rolling on the floor laughing
RTFM Read The Fine Manual
spec specification
TIA Thanks in advance
TL;DR Too long; didn't read
TOC Table of Contents
URI Uniform Resource Identifier
URL Uniform Resource Locator
W3C World Wide Web Consortium
WTF? What the f***
WYSIWYG What You See Is What You Get
YMMV Your mileage may vary

View file

@ -1,176 +0,0 @@
<?php
/**
* This is DokuWiki's Main Configuration file
*
* All the default values are kept here, you should not modify it but use
* a local.php file instead to override the settings from here.
*
* This is a piece of PHP code so PHP syntax applies!
*
* For help with the configuration and a more detailed explanation of the various options
* see http://www.dokuwiki.org/config
*/
/* Basic Settings */
$conf['title'] = 'DokuWiki'; //what to show in the title
$conf['start'] = 'start'; //name of start page
$conf['lang'] = 'en'; //your language
$conf['template'] = 'dokuwiki'; //see lib/tpl directory
$conf['tagline'] = ''; //tagline in header (if template supports it)
$conf['sidebar'] = 'sidebar'; //name of sidebar in root namespace (if template supports it)
$conf['license'] = 'cc-by-nc-sa'; //see conf/license.php
$conf['savedir'] = './data'; //where to store all the files
$conf['basedir'] = ''; //absolute dir from serveroot - blank for autodetection
$conf['baseurl'] = ''; //URL to server including protocol - blank for autodetect
$conf['cookiedir'] = ''; //path to use in cookies - blank for basedir
$conf['dmode'] = 0755; //set directory creation mode
$conf['fmode'] = 0644; //set file creation mode
$conf['allowdebug'] = 0; //allow debug output, enable if needed 0|1
/* Display Settings */
$conf['recent'] = 20; //how many entries to show in recent
$conf['recent_days'] = 7; //How many days of recent changes to keep. (days)
$conf['breadcrumbs'] = 10; //how many recent visited pages to show
$conf['youarehere'] = 0; //show "You are here" navigation? 0|1
$conf['fullpath'] = 0; //show full path of the document or relative to datadir only? 0|1
$conf['typography'] = 1; //smartquote conversion 0=off, 1=doublequotes, 2=all quotes
$conf['dformat'] = '%Y/%m/%d %H:%M'; //dateformat accepted by PHPs strftime() function
$conf['signature'] = ' --- //[[@MAIL@|@NAME@]] @DATE@//'; //signature see wiki page for details
$conf['showuseras'] = 'loginname'; // 'loginname' users login name
// 'username' users full name
// 'email' e-mail address (will be obfuscated as per mailguard)
// 'email_link' e-mail address as a mailto: link (obfuscated)
$conf['toptoclevel'] = 1; //Level starting with and below to include in AutoTOC (max. 5)
$conf['tocminheads'] = 3; //Minimum amount of headlines that determines if a TOC is built
$conf['maxtoclevel'] = 3; //Up to which level include into AutoTOC (max. 5)
$conf['maxseclevel'] = 3; //Up to which level create editable sections (max. 5)
$conf['camelcase'] = 0; //Use CamelCase for linking? (I don't like it) 0|1
$conf['deaccent'] = 1; //deaccented chars in pagenames (1) or romanize (2) or keep (0)?
$conf['useheading'] = 0; //use the first heading in a page as its name
$conf['sneaky_index']= 0; //check for namespace read permission in index view (0|1) (1 might cause unexpected behavior)
$conf['hidepages'] = ''; //Regexp for pages to be skipped from RSS, Search and Recent Changes
/* Authentication Settings */
$conf['useacl'] = 0; //Use Access Control Lists to restrict access?
$conf['autopasswd'] = 1; //autogenerate passwords and email them to user
$conf['authtype'] = 'authplain'; //which authentication backend should be used
$conf['passcrypt'] = 'smd5'; //Used crypt method (smd5,md5,sha1,ssha,crypt,mysql,my411)
$conf['defaultgroup']= 'user'; //Default groups new Users are added to
$conf['superuser'] = '!!not set!!'; //The admin can be user or @group or comma separated list user1,@group1,user2
$conf['manager'] = '!!not set!!'; //The manager can be user or @group or comma separated list user1,@group1,user2
$conf['profileconfirm'] = 1; //Require current password to confirm changes to user profile
$conf['rememberme'] = 1; //Enable/disable remember me on login
$conf['disableactions'] = ''; //comma separated list of actions to disable
$conf['auth_security_timeout'] = 900; //time (seconds) auth data is considered valid, set to 0 to recheck on every page view
$conf['securecookie'] = 1; //never send HTTPS cookies via HTTP
$conf['remote'] = 0; //Enable/disable remote interfaces
$conf['remoteuser'] = '!!not set!!'; //user/groups that have access to remote interface (comma separated)
/* Antispam Features */
$conf['usewordblock']= 1; //block spam based on words? 0|1
$conf['relnofollow'] = 1; //use rel="nofollow" for external links?
$conf['indexdelay'] = 60*60*24*5; //allow indexing after this time (seconds) default is 5 days
$conf['mailguard'] = 'hex'; //obfuscate email addresses against spam harvesters?
//valid entries are:
// 'visible' - replace @ with [at], . with [dot] and - with [dash]
// 'hex' - use hex entities to encode the mail address
// 'none' - do not obfuscate addresses
$conf['iexssprotect']= 1; // check for JavaScript and HTML in uploaded files 0|1
/* Editing Settings */
$conf['usedraft'] = 1; //automatically save a draft while editing (0|1)
$conf['htmlok'] = 0; //may raw HTML be embedded? This may break layout and XHTML validity 0|1
$conf['phpok'] = 0; //may PHP code be embedded? Never do this on the internet! 0|1
$conf['locktime'] = 15*60; //maximum age for lockfiles (defaults to 15 minutes)
$conf['cachetime'] = 60*60*24; //maximum age for cachefile in seconds (defaults to a day)
/* Link Settings */
// Set target to use when creating links - leave empty for same window
$conf['target']['wiki'] = '';
$conf['target']['interwiki'] = '';
$conf['target']['extern'] = '';
$conf['target']['media'] = '';
$conf['target']['windows'] = '';
/* Media Settings */
$conf['mediarevisions'] = 1; //enable/disable media revisions
$conf['refcheck'] = 1; //check for references before deleting media files
$conf['gdlib'] = 2; //the GDlib version (0, 1 or 2) 2 tries to autodetect
$conf['im_convert'] = ''; //path to ImageMagicks convert (will be used instead of GD)
$conf['jpg_quality'] = '70'; //quality of compression when scaling jpg images (0-100)
$conf['fetchsize'] = 0; //maximum size (bytes) fetch.php may download from extern, disabled by default
/* Notification Settings */
$conf['subscribers'] = 0; //enable change notice subscription support
$conf['subscribe_time'] = 24*60*60; //Time after which digests / lists are sent (in sec, default 1 day)
//Should be smaller than the time specified in recent_days
$conf['notify'] = ''; //send change info to this email (leave blank for nobody)
$conf['registernotify'] = ''; //send info about newly registered users to this email (leave blank for nobody)
$conf['mailfrom'] = ''; //use this email when sending mails
$conf['mailprefix'] = ''; //use this as prefix of outgoing mails
$conf['htmlmail'] = 1; //send HTML multipart mails
/* Syndication Settings */
$conf['sitemap'] = 0; //Create a google sitemap? How often? In days.
$conf['rss_type'] = 'rss1'; //type of RSS feed to provide, by default:
// 'rss' - RSS 0.91
// 'rss1' - RSS 1.0
// 'rss2' - RSS 2.0
// 'atom' - Atom 0.3
// 'atom1' - Atom 1.0
$conf['rss_linkto'] = 'diff'; //what page RSS entries link to:
// 'diff' - page showing revision differences
// 'page' - the revised page itself
// 'rev' - page showing all revisions
// 'current' - most recent revision of page
$conf['rss_content'] = 'abstract'; //what to put in the items by default?
// 'abstract' - plain text, first paragraph or so
// 'diff' - plain text unified diff wrapped in <pre> tags
// 'htmldiff' - diff as HTML table
// 'html' - the full page rendered in XHTML
$conf['rss_media'] = 'both'; //what should be listed?
// 'both' - page and media changes
// 'pages' - page changes only
// 'media' - media changes only
$conf['rss_update'] = 5*60; //Update the RSS feed every n seconds (defaults to 5 minutes)
$conf['rss_show_summary'] = 1; //Add revision summary to title? 0|1
/* Advanced Settings */
$conf['updatecheck'] = 1; //automatically check for new releases?
$conf['userewrite'] = 0; //this makes nice URLs: 0: off 1: .htaccess 2: internal
$conf['useslash'] = 0; //use slash instead of colon? only when rewrite is on
$conf['sepchar'] = '_'; //word separator character in page names; may be a
// letter, a digit, '_', '-', or '.'.
$conf['canonical'] = 0; //Should all URLs use full canonical http://... style?
$conf['fnencode'] = 'url'; //encode filenames (url|safe|utf-8)
$conf['autoplural'] = 0; //try (non)plural form of nonexisting files?
$conf['compression'] = 'gz'; //compress old revisions: (0: off) ('gz': gnuzip) ('bz2': bzip)
// bz2 generates smaller files, but needs more cpu-power
$conf['gzip_output'] = 0; //use gzip content encodeing for the output xhtml (if allowed by browser)
$conf['compress'] = 1; //Strip whitespaces and comments from Styles and JavaScript? 1|0
$conf['cssdatauri'] = 512; //Maximum byte size of small images to embed into CSS, won't work on IE<8
$conf['send404'] = 0; //Send a HTTP 404 status for non existing pages?
$conf['broken_iua'] = 0; //Platform with broken ignore_user_abort (IIS+CGI) 0|1
$conf['xsendfile'] = 0; //Use X-Sendfile (1 = lighttpd, 2 = standard)
$conf['renderer_xhtml'] = 'xhtml'; //renderer to use for main page generation
$conf['readdircache'] = 0; //time cache in second for the readdir operation, 0 to deactivate.
/* Network Settings */
$conf['dnslookups'] = 1; //disable to disallow IP to hostname lookups
// Proxy setup - if your Server needs a proxy to access the web set these
$conf['proxy']['host'] = '';
$conf['proxy']['port'] = '';
$conf['proxy']['user'] = '';
$conf['proxy']['pass'] = '';
$conf['proxy']['ssl'] = 0;
$conf['proxy']['except'] = '';
// Safemode Hack - read http://www.dokuwiki.org/config:safemodehack !
$conf['safemodehack'] = 0;
$conf['ftp']['host'] = 'localhost';
$conf['ftp']['port'] = '21';
$conf['ftp']['user'] = 'user';
$conf['ftp']['pass'] = 'password';
$conf['ftp']['root'] = '/home/user/htdocs';

View file

@ -1,22 +0,0 @@
# Typography replacements
#
# Order does matter!
#
# You can use HTML entities here, but it is not recommended because it may break
# non-HTML renderers. Use UTF-8 chars directly instead.
<-> ↔
-> →
<- ←
<=> ⇔
=> ⇒
<= ⇐
>> »
<< «
--- —
--
(c) ©
(tm) ™
(r) ®
... …

View file

@ -1,41 +0,0 @@
# Each URL may contain one of these placeholders
# {URL} is replaced by the URL encoded representation of the wikiname
# this is the right thing to do in most cases
# {NAME} this is replaced by the wikiname as given in the document
# only mandatory encoded is done, urlencoding if the link
# is an external URL, or encoding as a wikiname if it is an
# internal link (begins with a colon)
# {SCHEME}
# {HOST}
# {PORT}
# {PATH}
# {QUERY} these placeholders will be replaced with the appropriate part
# of the link when parsed as a URL
# If no placeholder is defined the urlencoded name is appended to the URL
# To prevent losing your added InterWiki shortcuts after an upgrade,
# you should add new ones to interwiki.local.conf
wp https://en.wikipedia.org/wiki/{NAME}
wpfr https://fr.wikipedia.org/wiki/{NAME}
wpde https://de.wikipedia.org/wiki/{NAME}
wpes https://es.wikipedia.org/wiki/{NAME}
wppl https://pl.wikipedia.org/wiki/{NAME}
wpjp https://ja.wikipedia.org/wiki/{NAME}
wpmeta https://meta.wikipedia.org/wiki/{NAME}
doku https://www.dokuwiki.org/
rfc https://tools.ietf.org/html/rfc
man http://man.cx/
amazon https://www.amazon.com/dp/{URL}?tag=splitbrain-20
amazon.de https://www.amazon.de/dp/{URL}?tag=splitbrain-21
amazon.uk https://www.amazon.co.uk/dp/{URL}
paypal https://www.paypal.com/cgi-bin/webscr?cmd=_xclick&amp;business=
phpfn https://secure.php.net/{NAME}
skype skype:{NAME}
google.de https://www.google.de/search?q=
go https://www.google.com/search?q={URL}&amp;btnI=lucky
user :user:{NAME}
# To support VoIP/SIP/TEL links
callto callto://{NAME}
tel tel:{NAME}

View file

@ -1,36 +0,0 @@
<?php
/**
* This file defines multiple available licenses you can license your
* wiki contents under. Do not change this file, but create a
* license.local.php instead.
*/
$license['cc-zero'] = array(
'name' => 'CC0 1.0 Universal',
'url' => 'http://creativecommons.org/publicdomain/zero/1.0/',
);
$license['publicdomain'] = array(
'name' => 'Public Domain',
'url' => 'http://creativecommons.org/licenses/publicdomain/',
);
$license['cc-by'] = array(
'name' => 'CC Attribution 4.0 International',
'url' => 'http://creativecommons.org/licenses/by/4.0/',
);
$license['cc-by-sa'] = array(
'name' => 'CC Attribution-Share Alike 4.0 International',
'url' => 'http://creativecommons.org/licenses/by-sa/4.0/',
);
$license['gnufdl'] = array(
'name' => 'GNU Free Documentation License 1.3',
'url' => 'http://www.gnu.org/licenses/fdl-1.3.html',
);
$license['cc-by-nc'] = array(
'name' => 'CC Attribution-Noncommercial 4.0 International',
'url' => 'http://creativecommons.org/licenses/by-nc/4.0/',
);
$license['cc-by-nc-sa'] = array(
'name' => 'CC Attribution-Noncommercial-Share Alike 4.0 International',
'url' => 'http://creativecommons.org/licenses/by-nc-sa/4.0/',
);

View file

@ -1,16 +0,0 @@
<?php
/**
* This is an example of how a local.php could look like.
* Simply copy the options you want to change from dokuwiki.php
* to this file and change them.
*
* When using the installer, a correct local.php file be generated for
* you automatically.
*/
//$conf['title'] = 'My Wiki'; //what to show in the title
//$conf['useacl'] = 1; //Use Access Control Lists to restrict access?
//$conf['superuser'] = 'joe';

View file

@ -1,91 +0,0 @@
<?php
/**
* This configures which meta data will be editable through
* the media manager. Each field of the array is an array with the
* following contents:
* fieldname - Where data will be saved (EXIF or IPTC field)
* label - key to lookup in the $lang var, if not found printed as is
* htmltype - 'text', 'textarea' or 'date'
* lookups - array additional fields to lookup the data (EXIF or IPTC fields)
*
* The fields are not ordered continously to make inserting additional items
* in between simpler.
*
* This is a PHP snippet, so PHP syntax applies.
*
* Note: $fields is not a global variable and will not be available to any
* other functions or templates later
*
* You may extend or overwrite this variable in a optional
* conf/mediameta.local.php file
*
* For a list of available EXIF/IPTC fields refer to
* http://www.dokuwiki.org/devel:templates:detail.php
*/
$fields = array(
10 => array('Iptc.Headline',
'img_title',
'text'),
20 => array('',
'img_date',
'date',
array('Date.EarliestTime')),
30 => array('',
'img_fname',
'text',
array('File.Name')),
40 => array('Iptc.Caption',
'img_caption',
'textarea',
array('Exif.UserComment',
'Exif.TIFFImageDescription',
'Exif.TIFFUserComment')),
50 => array('Iptc.Byline',
'img_artist',
'text',
array('Exif.TIFFArtist',
'Exif.Artist',
'Iptc.Credit')),
60 => array('Iptc.CopyrightNotice',
'img_copyr',
'text',
array('Exif.TIFFCopyright',
'Exif.Copyright')),
70 => array('',
'img_format',
'text',
array('File.Format')),
80 => array('',
'img_fsize',
'text',
array('File.NiceSize')),
90 => array('',
'img_width',
'text',
array('File.Width')),
100 => array('',
'img_height',
'text',
array('File.Height')),
110 => array('',
'img_camera',
'text',
array('Simple.Camera')),
120 => array('Iptc.Keywords',
'img_keywords',
'text',
array('Exif.Category')),
);

View file

@ -1,71 +0,0 @@
# Allowed uploadable file extensions and mimetypes are defined here.
# To extend this file it is recommended to create a mime.local.conf
# file. Mimetypes that should be downloadable and not be opened in the
# should be prefixed with a !
jpg image/jpeg
jpeg image/jpeg
gif image/gif
png image/png
ico image/vnd.microsoft.icon
mp3 audio/mpeg
ogg audio/ogg
wav audio/wav
webm video/webm
ogv video/ogg
mp4 video/mp4
tgz !application/octet-stream
tar !application/x-gtar
gz !application/octet-stream
bz2 !application/octet-stream
zip !application/zip
rar !application/rar
7z !application/x-7z-compressed
pdf application/pdf
ps !application/postscript
rpm !application/octet-stream
deb !application/octet-stream
doc !application/msword
xls !application/msexcel
ppt !application/mspowerpoint
rtf !application/msword
docx !application/vnd.openxmlformats-officedocument.wordprocessingml.document
xlsx !application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
pptx !application/vnd.openxmlformats-officedocument.presentationml.presentation
sxw !application/soffice
sxc !application/soffice
sxi !application/soffice
sxd !application/soffice
odc !application/vnd.oasis.opendocument.chart
odf !application/vnd.oasis.opendocument.formula
odg !application/vnd.oasis.opendocument.graphics
odi !application/vnd.oasis.opendocument.image
odp !application/vnd.oasis.opendocument.presentation
ods !application/vnd.oasis.opendocument.spreadsheet
odt !application/vnd.oasis.opendocument.text
# You should enable HTML and Text uploads only for restricted Wikis.
# Spammers are known to upload spam pages through unprotected Wikis.
# Note: Enabling HTML opens Cross Site Scripting vulnerabilities
# through JavaScript. Only enable this with trusted users. You
# need to disable the iexssprotect option additionally to
# adding the mime type here
#html text/html
#htm text/html
#txt text/plain
#conf text/plain
#xml text/xml
#csv text/csv
# Also flash may be able to execute arbitrary scripts in the website's
# context
#swf application/x-shockwave-flash

View file

@ -1,253 +0,0 @@
<?php
/*
* This is an example configuration for the mysql auth plugin.
*
* This SQL statements are optimized for following table structure.
* If you use a different one you have to change them accordingly.
* See comments of every statement for details.
*
* TABLE users
* uid login pass firstname lastname email
*
* TABLE groups
* gid name
*
* TABLE usergroup
* uid gid
*
* To use this configuration you have to copy them to local.protected.php
* or at least include this file in local.protected.php.
*/
/* Options to configure database access. You need to set up this
* options carefully, otherwise you won't be able to access you
* database.
*/
$conf['plugin']['authmysql']['server'] = '';
$conf['plugin']['authmysql']['user'] = '';
$conf['plugin']['authmysql']['password'] = '';
$conf['plugin']['authmysql']['database'] = '';
/* This option enables debug messages in the mysql plugin. It is
* mostly useful for system admins.
*/
$conf['plugin']['authmysql']['debug'] = 0;
/* Normally password encryption is done by DokuWiki (recommended) but for
* some reasons it might be usefull to let the database do the encryption.
* Set 'forwardClearPass' to '1' and the cleartext password is forwarded to
* the database, otherwise the encrypted one.
*/
$conf['plugin']['authmysql']['forwardClearPass'] = 0;
/* Multiple table operations will be protected by locks. This array tolds
* the plugin which tables to lock. If you use any aliases for table names
* these array must also contain these aliases. Any unamed alias will cause
* a warning during operation. See the example below.
*/
$conf['plugin']['authmysql']['TablesToLock']= array("users", "users AS u","groups", "groups AS g", "usergroup", "usergroup AS ug");
/***********************************************************************/
/* Basic SQL statements for user authentication (required) */
/***********************************************************************/
/* This statement is used to grant or deny access to the wiki. The result
* should be a table with exact one line containing at least the password
* of the user. If the result table is empty or contains more than one
* row, access will be denied.
*
* The plugin accesses the password as 'pass' so an alias might be necessary.
*
* Following patters will be replaced:
* %{user} user name
* %{pass} encrypted or clear text password (depends on 'encryptPass')
* %{dgroup} default group name
*/
$conf['plugin']['authmysql']['checkPass'] = "SELECT pass
FROM usergroup AS ug
JOIN users AS u ON u.uid=ug.uid
JOIN groups AS g ON g.gid=ug.gid
WHERE login='%{user}'
AND name='%{dgroup}'";
/* This statement should return a table with exact one row containing
* information about one user. The field needed are:
* 'pass' containing the encrypted or clear text password
* 'name' the user's full name
* 'mail' the user's email address
*
* Keep in mind that Dokuwiki will access thise information through the
* names listed above so aliasses might be neseccary.
*
* Following patters will be replaced:
* %{user} user name
*/
$conf['plugin']['authmysql']['getUserInfo'] = "SELECT pass, CONCAT(firstname,' ',lastname) AS name, email AS mail
FROM users
WHERE login='%{user}'";
/* This statement is used to get all groups a user is member of. The
* result should be a table containing all groups the given user is
* member of. The plugin accesses the group name as 'group' so an alias
* might be nessecary.
*
* Following patters will be replaced:
* %{user} user name
*/
$conf['plugin']['authmysql']['getGroups'] = "SELECT name as `group`
FROM groups g, users u, usergroup ug
WHERE u.uid = ug.uid
AND g.gid = ug.gid
AND u.login='%{user}'";
/***********************************************************************/
/* Additional minimum SQL statements to use the user manager */
/***********************************************************************/
/* This statement should return a table containing all user login names
* that meet certain filter criteria. The filter expressions will be added
* case dependend by the plugin. At the end a sort expression will be added.
* Important is that this list contains no double entries for a user. Each
* user name is only allowed once in the table.
*
* The login name will be accessed as 'user' to an alias might be neseccary.
* No patterns will be replaced in this statement but following patters
* will be replaced in the filter expressions:
* %{user} in FilterLogin user's login name
* %{name} in FilterName user's full name
* %{email} in FilterEmail user's email address
* %{group} in FilterGroup group name
*/
$conf['plugin']['authmysql']['getUsers'] = "SELECT DISTINCT login AS user
FROM users AS u
LEFT JOIN usergroup AS ug ON u.uid=ug.uid
LEFT JOIN groups AS g ON ug.gid=g.gid";
$conf['plugin']['authmysql']['FilterLogin'] = "login LIKE '%{user}'";
$conf['plugin']['authmysql']['FilterName'] = "CONCAT(firstname,' ',lastname) LIKE '%{name}'";
$conf['plugin']['authmysql']['FilterEmail'] = "email LIKE '%{email}'";
$conf['plugin']['authmysql']['FilterGroup'] = "name LIKE '%{group}'";
$conf['plugin']['authmysql']['SortOrder'] = "ORDER BY login";
/***********************************************************************/
/* Additional SQL statements to add new users with the user manager */
/***********************************************************************/
/* This statement should add a user to the database. Minimum information
* to store are: login name, password, email address and full name.
*
* Following patterns will be replaced:
* %{user} user's login name
* %{pass} password (encrypted or clear text, depends on 'encryptPass')
* %{email} email address
* %{name} user's full name
*/
$conf['plugin']['authmysql']['addUser'] = "INSERT INTO users
(login, pass, email, firstname, lastname)
VALUES ('%{user}', '%{pass}', '%{email}',
SUBSTRING_INDEX('%{name}',' ', 1),
SUBSTRING_INDEX('%{name}',' ', -1))";
/* This statement should add a group to the database.
* Following patterns will be replaced:
* %{group} group name
*/
$conf['plugin']['authmysql']['addGroup'] = "INSERT INTO groups (name)
VALUES ('%{group}')";
/* This statement should connect a user to a group (a user become member
* of that group).
* Following patterns will be replaced:
* %{user} user's login name
* %{uid} id of a user dataset
* %{group} group name
* %{gid} id of a group dataset
*/
$conf['plugin']['authmysql']['addUserGroup']= "INSERT INTO usergroup (uid, gid)
VALUES ('%{uid}', '%{gid}')";
/* This statement should remove a group fom the database.
* Following patterns will be replaced:
* %{group} group name
* %{gid} id of a group dataset
*/
$conf['plugin']['authmysql']['delGroup'] = "DELETE FROM groups
WHERE gid='%{gid}'";
/* This statement should return the database index of a given user name.
* The plugin will access the index with the name 'id' so an alias might be
* necessary.
* following patters will be replaced:
* %{user} user name
*/
$conf['plugin']['authmysql']['getUserID'] = "SELECT uid AS id
FROM users
WHERE login='%{user}'";
/***********************************************************************/
/* Additional SQL statements to delete users with the user manager */
/***********************************************************************/
/* This statement should remove a user fom the database.
* Following patterns will be replaced:
* %{user} user's login name
* %{uid} id of a user dataset
*/
$conf['plugin']['authmysql']['delUser'] = "DELETE FROM users
WHERE uid='%{uid}'";
/* This statement should remove all connections from a user to any group
* (a user quits membership of all groups).
* Following patterns will be replaced:
* %{uid} id of a user dataset
*/
$conf['plugin']['authmysql']['delUserRefs'] = "DELETE FROM usergroup
WHERE uid='%{uid}'";
/***********************************************************************/
/* Additional SQL statements to modify users with the user manager */
/***********************************************************************/
/* This statements should modify a user entry in the database. The
* statements UpdateLogin, UpdatePass, UpdateEmail and UpdateName will be
* added to updateUser on demand. Only changed parameters will be used.
*
* Following patterns will be replaced:
* %{user} user's login name
* %{pass} password (encrypted or clear text, depends on 'encryptPass')
* %{email} email address
* %{name} user's full name
* %{uid} user id that should be updated
*/
$conf['plugin']['authmysql']['updateUser'] = "UPDATE users SET";
$conf['plugin']['authmysql']['UpdateLogin'] = "login='%{user}'";
$conf['plugin']['authmysql']['UpdatePass'] = "pass='%{pass}'";
$conf['plugin']['authmysql']['UpdateEmail'] = "email='%{email}'";
$conf['plugin']['authmysql']['UpdateName'] = "firstname=SUBSTRING_INDEX('%{name}',' ', 1),
lastname=SUBSTRING_INDEX('%{name}',' ', -1)";
$conf['plugin']['authmysql']['UpdateTarget']= "WHERE uid=%{uid}";
/* This statement should remove a single connection from a user to a
* group (a user quits membership of that group).
*
* Following patterns will be replaced:
* %{user} user's login name
* %{uid} id of a user dataset
* %{group} group name
* %{gid} id of a group dataset
*/
$conf['plugin']['authmysql']['delUserGroup']= "DELETE FROM usergroup
WHERE uid='%{uid}'
AND gid='%{gid}'";
/* This statement should return the database index of a given group name.
* The plugin will access the index with the name 'id' so an alias might
* be necessary.
*
* Following patters will be replaced:
* %{group} group name
*/
$conf['plugin']['authmysql']['getGroupID'] = "SELECT gid AS id
FROM groups
WHERE name='%{group}'";

View file

@ -1,6 +0,0 @@
<?php
/**
* This file configures the default states of available plugins. All settings in
* the plugins.*.php files will override those here.
*/
$plugins['testing'] = 0;

View file

@ -1,12 +0,0 @@
<?php
/**
* This file configures the enabled/disabled status of plugins, which are also protected
* from changes by the extention manager. These settings will override any local settings.
* It is not recommended to change this file, as it is overwritten on DokuWiki upgrades.
*/
$plugins['acl'] = 1;
$plugins['authplain'] = 1;
$plugins['extension'] = 1;
$plugins['config'] = 1;
$plugins['usermanager'] = 1;
$plugins['template:dokuwiki'] = 1; // not a plugin, but this should not be uninstalled either

View file

@ -1,11 +0,0 @@
#Add URL schemes you want to be recognized as links here
http
https
telnet
gopher
wais
ftp
ed2k
irc
ldap

View file

@ -1,28 +0,0 @@
# Smileys configured here will be replaced by the
# configured images in the smiley directory
8-) icon_cool.gif
8-O icon_eek.gif
8-o icon_eek.gif
:-( icon_sad.gif
:-) icon_smile.gif
=) icon_smile2.gif
:-/ icon_doubt.gif
:-\ icon_doubt2.gif
:-? icon_confused.gif
:-D icon_biggrin.gif
:-P icon_razz.gif
:-o icon_surprised.gif
:-O icon_surprised.gif
:-x icon_silenced.gif
:-X icon_silenced.gif
:-| icon_neutral.gif
;-) icon_wink.gif
m( facepalm.gif
^_^ icon_fun.gif
:?: icon_question.gif
:!: icon_exclaim.gif
LOL icon_lol.gif
FIXME fixme.gif
DELETEME delete.gif

View file

@ -1,10 +0,0 @@
# users.auth.php
# <?php exit()?>
# Don't modify the lines above
#
# Userfile
#
# Format:
#
# login:passwordhash:Real Name:email:groups,comma,seperated

View file

@ -1,29 +0,0 @@
# This blacklist is maintained by the DokuWiki community
# patches welcome
#
https?:\/\/(\S*?)(-side-effects|top|pharm|pill|discount|discount-|deal|price|order|now|best|cheap|cheap-|online|buy|buy-|sale|sell)(\S*?)(cialis|viagra|prazolam|xanax|zanax|soma|vicodin|zenical|xenical|meridia|paxil|prozac|claritin|allegra|lexapro|wellbutrin|zoloft|retin|valium|levitra|phentermine)
https?:\/\/(\S*?)(bi\s*sex|gay\s*sex|fetish|incest|penis|\brape\b)
zoosex
gang\s*bang
facials
ladyboy
\btits\b
bolea\.com
52crystal
baida\.org
web-directory\.awardspace\.us
korsan-team\.com
BUDA TAMAMDIR
wow-powerleveling-wow\.com
wow gold
wow-gold\.dinmo\.cn
downgrade-vista\.com
downgradetowindowsxp\.com
elegantugg\.com
classicedhardy\.com
research-service\.com
https?:\/\/(\S*?)(2-pay-secure|911essay|academia-research|anypapers|applicationessay|bestbuyessay|bestdissertation|bestessay|bestresume|besttermpaper|businessessay|college-paper|customessay|custom-made-paper|custom-writing|degree-?result|dissertationblog|dissertation-service|dissertations?expert|essaybank|essay-?blog|essaycapital|essaylogic|essaymill|essayontime|essaypaper|essays?land|essaytownsucks|essay-?writ|fastessays|freelancercareers|genuinecontent|genuineessay|genuinepaper|goessay|grandresume|killer-content|ma-dissertation|managementessay|masterpaper|mightystudent|needessay|researchedge|researchpaper-blog|resumecvservice|resumesexperts|resumesplanet|rushessay|samedayessay|superiorcontent|superiorpaper|superiorthesis|term-paper|termpaper-blog|term-paper-research|thesisblog|universalresearch|valwriting|vdwriters|wisetranslation|writersassembly|writers\.com\.ph|writers\.ph)
flatsinmumbai\.co\.in
https?:\/\/(\S*?)penny-?stock
mattressreview\.biz
(just|simply) (my|a) profile (site|webpage|page)

View file

@ -1,7 +0,0 @@
<IfModule mod_authz_host>
Require all denied
</IfModule>
<IfModule !mod_authz_host>
Order allow,deny
Deny from all
</IfModule>

View file

@ -1 +0,0 @@
You can safely delete this file.

View file

@ -1 +0,0 @@
You can safely delete this file.

View file

@ -1 +0,0 @@
You can safely delete this file.

View file

@ -1,687 +0,0 @@
# This is a list of files that were present in previous DokuWiki releases
# but were removed later. An up to date DokuWiki should not have any of
# the files installed
# 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
inc/geshi/4cs.php
inc/geshi/6502acme.php
inc/geshi/6502kickass.php
inc/geshi/6502tasm.php
inc/geshi/68000devpac.php
inc/geshi/abap.php
inc/geshi/actionscript-french.php
inc/geshi/actionscript.php
inc/geshi/actionscript3.php
inc/geshi/ada.php
inc/geshi/algol68.php
inc/geshi/apache.php
inc/geshi/applescript.php
inc/geshi/apt_sources.php
inc/geshi/arm.php
inc/geshi/asm.php
inc/geshi/asp.php
inc/geshi/asymptote.php
inc/geshi/autoconf.php
inc/geshi/autohotkey.php
inc/geshi/autoit.php
inc/geshi/avisynth.php
inc/geshi/awk.php
inc/geshi/bascomavr.php
inc/geshi/bash.php
inc/geshi/basic4gl.php
inc/geshi/bf.php
inc/geshi/bibtex.php
inc/geshi/blitzbasic.php
inc/geshi/bnf.php
inc/geshi/boo.php
inc/geshi/c.php
inc/geshi/c_loadrunner.php
inc/geshi/c_mac.php
inc/geshi/caddcl.php
inc/geshi/cadlisp.php
inc/geshi/cfdg.php
inc/geshi/cfm.php
inc/geshi/chaiscript.php
inc/geshi/cil.php
inc/geshi/clojure.php
inc/geshi/cmake.php
inc/geshi/cobol.php
inc/geshi/coffeescript.php
inc/geshi/cpp-qt.php
inc/geshi/cpp.php
inc/geshi/csharp.php
inc/geshi/css.php
inc/geshi/cuesheet.php
inc/geshi/d.php
inc/geshi/dcl.php
inc/geshi/dcpu16.php
inc/geshi/dcs.php
inc/geshi/delphi.php
inc/geshi/diff.php
inc/geshi/div.php
inc/geshi/dos.php
inc/geshi/dot.php
inc/geshi/e.php
inc/geshi/ecmascript.php
inc/geshi/eiffel.php
inc/geshi/email.php
inc/geshi/epc.php
inc/geshi/erlang.php
inc/geshi/euphoria.php
inc/geshi/f1.php
inc/geshi/falcon.php
inc/geshi/fo.php
inc/geshi/fortran.php
inc/geshi/freebasic.php
inc/geshi/freeswitch.php
inc/geshi/fsharp.php
inc/geshi/gambas.php
inc/geshi/gdb.php
inc/geshi/genero.php
inc/geshi/genie.php
inc/geshi/gettext.php
inc/geshi/glsl.php
inc/geshi/gml.php
inc/geshi/gnuplot.php
inc/geshi/go.php
inc/geshi/groovy.php
inc/geshi/gwbasic.php
inc/geshi/haskell.php
inc/geshi/haxe.php
inc/geshi/hicest.php
inc/geshi/hq9plus.php
inc/geshi/html4strict.php
inc/geshi/html5.php
inc/geshi/icon.php
inc/geshi/idl.php
inc/geshi/ini.php
inc/geshi/inno.php
inc/geshi/intercal.php
inc/geshi/io.php
inc/geshi/j.php
inc/geshi/java.php
inc/geshi/java5.php
inc/geshi/javascript.php
inc/geshi/jquery.php
inc/geshi/kixtart.php
inc/geshi/klonec.php
inc/geshi/klonecpp.php
inc/geshi/latex.php
inc/geshi/lb.php
inc/geshi/ldif.php
inc/geshi/lisp.php
inc/geshi/llvm.php
inc/geshi/locobasic.php
inc/geshi/logtalk.php
inc/geshi/lolcode.php
inc/geshi/lotusformulas.php
inc/geshi/lotusscript.php
inc/geshi/lscript.php
inc/geshi/lsl2.php
inc/geshi/lua.php
inc/geshi/m68k.php
inc/geshi/magiksf.php
inc/geshi/make.php
inc/geshi/mapbasic.php
inc/geshi/matlab.php
inc/geshi/mirc.php
inc/geshi/mmix.php
inc/geshi/modula2.php
inc/geshi/modula3.php
inc/geshi/mpasm.php
inc/geshi/mxml.php
inc/geshi/mysql.php
inc/geshi/nagios.php
inc/geshi/netrexx.php
inc/geshi/newlisp.php
inc/geshi/nsis.php
inc/geshi/oberon2.php
inc/geshi/objc.php
inc/geshi/objeck.php
inc/geshi/ocaml-brief.php
inc/geshi/ocaml.php
inc/geshi/octave.php
inc/geshi/oobas.php
inc/geshi/oorexx.php
inc/geshi/oracle11.php
inc/geshi/oracle8.php
inc/geshi/oxygene.php
inc/geshi/oz.php
inc/geshi/parasail.php
inc/geshi/parigp.php
inc/geshi/pascal.php
inc/geshi/pcre.php
inc/geshi/per.php
inc/geshi/perl.php
inc/geshi/perl6.php
inc/geshi/pf.php
inc/geshi/php-brief.php
inc/geshi/php.php
inc/geshi/pic16.php
inc/geshi/pike.php
inc/geshi/pixelbender.php
inc/geshi/pli.php
inc/geshi/plsql.php
inc/geshi/postgresql.php
inc/geshi/povray.php
inc/geshi/powerbuilder.php
inc/geshi/powershell.php
inc/geshi/proftpd.php
inc/geshi/progress.php
inc/geshi/prolog.php
inc/geshi/properties.php
inc/geshi/providex.php
inc/geshi/purebasic.php
inc/geshi/pycon.php
inc/geshi/pys60.php
inc/geshi/python.php
inc/geshi/q.php
inc/geshi/qbasic.php
inc/geshi/rails.php
inc/geshi/rebol.php
inc/geshi/reg.php
inc/geshi/rexx.php
inc/geshi/robots.php
inc/geshi/rpmspec.php
inc/geshi/rsplus.php
inc/geshi/ruby.php
inc/geshi/sas.php
inc/geshi/scala.php
inc/geshi/scheme.php
inc/geshi/scilab.php
inc/geshi/sdlbasic.php
inc/geshi/smalltalk.php
inc/geshi/smarty.php
inc/geshi/spark.php
inc/geshi/sparql.php
inc/geshi/sql.php
inc/geshi/stonescript.php
inc/geshi/systemverilog.php
inc/geshi/tcl.php
inc/geshi/teraterm.php
inc/geshi/text.php
inc/geshi/thinbasic.php
inc/geshi/tsql.php
inc/geshi/typoscript.php
inc/geshi/unicon.php
inc/geshi/upc.php
inc/geshi/urbi.php
inc/geshi/uscript.php
inc/geshi/vala.php
inc/geshi/vb.php
inc/geshi/vbnet.php
inc/geshi/vedit.php
inc/geshi/verilog.php
inc/geshi/vhdl.php
inc/geshi/vim.php
inc/geshi/visualfoxpro.php
inc/geshi/visualprolog.php
inc/geshi/whitespace.php
inc/geshi/whois.php
inc/geshi/winbatch.php
inc/geshi/xbasic.php
inc/geshi/xml.php
inc/geshi/xorg_conf.php
inc/geshi/xpp.php
inc/geshi/yaml.php
inc/geshi/z80.php
inc/geshi/zxbasic.php
lib/images/interwiki/coral.gif
lib/images/interwiki/dokubug.gif
lib/images/interwiki/sb.gif
lib/scripts/drag.js
lib/scripts/jquery/jquery-ui-theme/images/animated-overlay.gif
lib/scripts/tw-sack.js
# removed in 2014-05-05
lib/images/fileicons/audio.png
lib/plugins/plugin/admin.php
lib/plugins/plugin/classes/ap_delete.class.php
lib/plugins/plugin/classes/ap_download.class.php
lib/plugins/plugin/classes/ap_enable.class.php
lib/plugins/plugin/classes/ap_info.class.php
lib/plugins/plugin/classes/ap_manage.class.php
lib/plugins/plugin/classes/ap_update.class.php
lib/plugins/plugin/lang/af/lang.php
lib/plugins/plugin/lang/ar/admin_plugin.txt
lib/plugins/plugin/lang/ar/lang.php
lib/plugins/plugin/lang/bg/admin_plugin.txt
lib/plugins/plugin/lang/bg/lang.php
lib/plugins/plugin/lang/ca-valencia/admin_plugin.txt
lib/plugins/plugin/lang/ca-valencia/lang.php
lib/plugins/plugin/lang/ca/admin_plugin.txt
lib/plugins/plugin/lang/ca/lang.php
lib/plugins/plugin/lang/cs/admin_plugin.txt
lib/plugins/plugin/lang/cs/lang.php
lib/plugins/plugin/lang/da/admin_plugin.txt
lib/plugins/plugin/lang/da/lang.php
lib/plugins/plugin/lang/de-informal/admin_plugin.txt
lib/plugins/plugin/lang/de-informal/lang.php
lib/plugins/plugin/lang/de/admin_plugin.txt
lib/plugins/plugin/lang/de/lang.php
lib/plugins/plugin/lang/el/admin_plugin.txt
lib/plugins/plugin/lang/el/lang.php
lib/plugins/plugin/lang/en/admin_plugin.txt
lib/plugins/plugin/lang/en/lang.php
lib/plugins/plugin/lang/eo/admin_plugin.txt
lib/plugins/plugin/lang/eo/lang.php
lib/plugins/plugin/lang/es/admin_plugin.txt
lib/plugins/plugin/lang/es/lang.php
lib/plugins/plugin/lang/et/lang.php
lib/plugins/plugin/lang/eu/admin_plugin.txt
lib/plugins/plugin/lang/eu/lang.php
lib/plugins/plugin/lang/fa/admin_plugin.txt
lib/plugins/plugin/lang/fa/lang.php
lib/plugins/plugin/lang/fi/admin_plugin.txt
lib/plugins/plugin/lang/fi/lang.php
lib/plugins/plugin/lang/fr/admin_plugin.txt
lib/plugins/plugin/lang/fr/lang.php
lib/plugins/plugin/lang/gl/admin_plugin.txt
lib/plugins/plugin/lang/gl/lang.php
lib/plugins/plugin/lang/he/admin_plugin.txt
lib/plugins/plugin/lang/he/lang.php
lib/plugins/plugin/lang/hi/lang.php
lib/plugins/plugin/lang/hr/lang.php
lib/plugins/plugin/lang/hu/admin_plugin.txt
lib/plugins/plugin/lang/hu/lang.php
lib/plugins/plugin/lang/ia/admin_plugin.txt
lib/plugins/plugin/lang/ia/lang.php
lib/plugins/plugin/lang/id-ni/lang.php
lib/plugins/plugin/lang/id/lang.php
lib/plugins/plugin/lang/is/lang.php
lib/plugins/plugin/lang/it/admin_plugin.txt
lib/plugins/plugin/lang/it/lang.php
lib/plugins/plugin/lang/ja/admin_plugin.txt
lib/plugins/plugin/lang/ja/lang.php
lib/plugins/plugin/lang/kk/lang.php
lib/plugins/plugin/lang/ko/admin_plugin.txt
lib/plugins/plugin/lang/ko/lang.php
lib/plugins/plugin/lang/la/admin_plugin.txt
lib/plugins/plugin/lang/la/lang.php
lib/plugins/plugin/lang/lb/admin_plugin.txt
lib/plugins/plugin/lang/lb/lang.php
lib/plugins/plugin/lang/lt/admin_plugin.txt
lib/plugins/plugin/lang/lt/lang.php
lib/plugins/plugin/lang/lv/admin_plugin.txt
lib/plugins/plugin/lang/lv/lang.php
lib/plugins/plugin/lang/mk/lang.php
lib/plugins/plugin/lang/mr/admin_plugin.txt
lib/plugins/plugin/lang/mr/lang.php
lib/plugins/plugin/lang/ms/lang.php
lib/plugins/plugin/lang/ne/lang.php
lib/plugins/plugin/lang/nl/admin_plugin.txt
lib/plugins/plugin/lang/nl/lang.php
lib/plugins/plugin/lang/no/admin_plugin.txt
lib/plugins/plugin/lang/no/lang.php
lib/plugins/plugin/lang/pl/admin_plugin.txt
lib/plugins/plugin/lang/pl/lang.php
lib/plugins/plugin/lang/pt-br/admin_plugin.txt
lib/plugins/plugin/lang/pt-br/lang.php
lib/plugins/plugin/lang/pt/admin_plugin.txt
lib/plugins/plugin/lang/pt/lang.php
lib/plugins/plugin/lang/ro/admin_plugin.txt
lib/plugins/plugin/lang/ro/lang.php
lib/plugins/plugin/lang/ru/admin_plugin.txt
lib/plugins/plugin/lang/ru/lang.php
lib/plugins/plugin/lang/sk/admin_plugin.txt
lib/plugins/plugin/lang/sk/lang.php
lib/plugins/plugin/lang/sl/admin_plugin.txt
lib/plugins/plugin/lang/sl/lang.php
lib/plugins/plugin/lang/sq/admin_plugin.txt
lib/plugins/plugin/lang/sq/lang.php
lib/plugins/plugin/lang/sr/admin_plugin.txt
lib/plugins/plugin/lang/sr/lang.php
lib/plugins/plugin/lang/sv/admin_plugin.txt
lib/plugins/plugin/lang/sv/lang.php
lib/plugins/plugin/lang/th/admin_plugin.txt
lib/plugins/plugin/lang/th/lang.php
lib/plugins/plugin/lang/tr/admin_plugin.txt
lib/plugins/plugin/lang/tr/lang.php
lib/plugins/plugin/lang/uk/admin_plugin.txt
lib/plugins/plugin/lang/uk/lang.php
lib/plugins/plugin/lang/vi/lang.php
lib/plugins/plugin/lang/zh-tw/admin_plugin.txt
lib/plugins/plugin/lang/zh-tw/lang.php
lib/plugins/plugin/lang/zh/admin_plugin.txt
lib/plugins/plugin/lang/zh/lang.php
lib/plugins/plugin/plugin.info.txt
lib/plugins/plugin/style.css
# removed in 2013-11-18
lib/images/arrow_down.gif
lib/images/arrow_up.gif
lib/images/at.gif
lib/images/close.png
lib/images/del.png
lib/images/edit.gif
lib/images/list-minus.gif
lib/images/list-plus.gif
lib/images/pencil.png
# removed in 2013-10-28
lib/images/interwiki/meatball.gif
lib/images/interwiki/wiki.gif
lib/plugins/acl/ajax.php
lib/tpl/default/_admin.css
lib/tpl/default/_fileuploader.css
lib/tpl/default/_linkwiz.css
lib/tpl/default/_mediamanager.css
lib/tpl/default/_mediaoptions.css
lib/tpl/default/_subscription.css
lib/tpl/default/_tabs.css
lib/tpl/default/design.css
lib/tpl/default/detail.php
lib/tpl/default/footer.html
lib/tpl/default/images/UWEB.png
lib/tpl/default/images/UWEBshadow.png
lib/tpl/default/images/apple-touch-icon.png
lib/tpl/default/images/bullet.gif
lib/tpl/default/images/button-cc.gif
lib/tpl/default/images/button-css.png
lib/tpl/default/images/button-donate.gif
lib/tpl/default/images/button-dw.png
lib/tpl/default/images/button-php.gif
lib/tpl/default/images/button-rss.png
lib/tpl/default/images/button-xhtml.png
lib/tpl/default/images/buttonshadow.png
lib/tpl/default/images/closed.gif
lib/tpl/default/images/favicon.ico
lib/tpl/default/images/inputshadow.png
lib/tpl/default/images/link_icon.gif
lib/tpl/default/images/mail_icon.gif
lib/tpl/default/images/open.gif
lib/tpl/default/images/resizecol.png
lib/tpl/default/images/tocdot2.gif
lib/tpl/default/images/windows.gif
lib/tpl/default/layout.css
lib/tpl/default/main.php
lib/tpl/default/media.css
lib/tpl/default/mediamanager.php
lib/tpl/default/print.css
lib/tpl/default/rtl.css
lib/tpl/default/style.ini
lib/tpl/default/template.info.txt
lib/tpl/dokuwiki/css/basic.css
lib/tpl/dokuwiki/css/content.css
lib/tpl/dokuwiki/css/design.css
lib/tpl/dokuwiki/css/includes.css
lib/tpl/dokuwiki/css/mobile.css
lib/tpl/dokuwiki/css/pagetools.css
lib/tpl/dokuwiki/css/structure.css
# removed in 2013-05-10
lib/plugins/info/lang/sl/lang.php
# removed in 2013-04-06
inc/adLDAP.php
inc/auth/ad.class.php
inc/auth/basic.class.php
inc/auth/ldap.class.php
inc/auth/mysql.class.php
inc/auth/pgsql.class.php
inc/auth/plain.class.php
# removed in 2012-09-10
lib/images/icon-file.png
lib/images/icon-thumb.png
lib/images/interwiki/skype.png
lib/plugins/acl/rtl.css
lib/plugins/config/rtl.css
lib/plugins/plugin/rtl.css
# removed in 2011-11-10
lib/_fla/.htaccess
lib/_fla/MultipleUpload.as
lib/_fla/README
lib/_fla/index.html
lib/_fla/multipleUpload.fla
lib/exe/multipleUpload.swf
lib/images/multiupload.png
lib/scripts/ajax.js
lib/scripts/events.js
lib/scripts/subscriptions.js
# removed in 2011-05-25
conf/words.aspell.dist
lib/styles/style.css
# removed in 2010-11-07
inc/lang/ar/subscribermail.txt
inc/lang/az/subscribermail.txt
inc/lang/bg/subscribermail.txt
inc/lang/ca/subscribermail.txt
inc/lang/ca-valencia/subscribermail.txt
inc/lang/cs/subscribermail.txt
inc/lang/da/subscribermail.txt
inc/lang/de-informal/subscribermail.txt
inc/lang/el/subscribermail.txt
inc/lang/eo/subscribermail.txt
inc/lang/es/subscribermail.txt
inc/lang/et/subscribermail.txt
inc/lang/eu/subscribermail.txt
inc/lang/fa/subscribermail.txt
inc/lang/fi/subscribermail.txt
inc/lang/fo/subscribermail.txt
inc/lang/fr/subscribermail.txt
inc/lang/gl/subscribermail.txt
inc/lang/he/subscribermail.txt
inc/lang/hr/subscribermail.txt
inc/lang/hu/subscribermail.txt
inc/lang/id/subscribermail.txt
inc/lang/is/subscribermail.txt
inc/lang/it/subscribermail.txt
inc/lang/ja/subscribermail.txt
inc/lang/ko/subscribermail.txt
inc/lang/ku/subscribermail.txt
inc/lang/lt/subscribermail.txt
inc/lang/lv/subscribermail.txt
inc/lang/mr/subscribermail.txt
inc/lang/ne/subscribermail.txt
inc/lang/nl/subscribermail.txt
inc/lang/no/subscribermail.txt
inc/lang/pl/subscribermail.txt
inc/lang/pt-br/subscribermail.txt
inc/lang/pt/subscribermail.txt
inc/lang/ro/subscribermail.txt
inc/lang/ru/subscribermail.txt
inc/lang/sk/subscribermail.txt
inc/lang/sr/subscribermail.txt
inc/lang/sv/subscribermail.txt
inc/lang/th/subscribermail.txt
inc/lang/tr/subscribermail.txt
inc/lang/uk/subscribermail.txt
inc/lang/zh/subscribermail.txt
inc/lang/zh-tw/subscribermail.txt
# removed in rc2010-10-07
conf/msg
inc/lang/bg/wordblock.txt
inc/lang/ca-valencia/wordblock.txt
inc/lang/ca/wordblock.txt
inc/lang/cs/wordblock.txt
inc/lang/da/wordblock.txt
inc/lang/de-informal/wordblock.txt
inc/lang/de/subscribermail.txt
inc/lang/de/wordblock.txt
inc/lang/el/wordblock.txt
inc/lang/en/subscribermail.txt
inc/lang/en/wordblock.txt
inc/lang/eo/wordblock.txt
inc/lang/es/wordblock.txt
inc/lang/et/wordblock.txt
inc/lang/eu/wordblock.txt
inc/lang/fa/wordblock.txt
inc/lang/fi/wordblock.txt
inc/lang/fo/wordblock.txt
inc/lang/fr/wordblock.txt
inc/lang/he/wordblock.txt
inc/lang/hr/wordblock.txt
inc/lang/hu/wordblock.txt
inc/lang/id/wordblock.txt
inc/lang/it/wordblock.txt
inc/lang/ja/wordblock.txt
inc/lang/ko/wordblock.txt
inc/lang/ku/wordblock.txt
inc/lang/lt/wordblock.txt
inc/lang/lv/wordblock.txt
inc/lang/mg/wordblock.txt
inc/lang/mr/wordblock.txt
inc/lang/nl/wordblock.txt
inc/lang/no/wordblock.txt
inc/lang/pl/wordblock.txt
inc/lang/pt-br/wordblock.txt
inc/lang/pt/wordblock.txt
inc/lang/ro/wordblock.txt
inc/lang/sk/wordblock.txt
inc/lang/sl/wordblock.txt
inc/lang/sr/wordblock.txt
inc/lang/sv/wordblock.txt
inc/lang/th/wordblock.txt
inc/lang/tr/wordblock.txt
inc/lang/uk/wordblock.txt
inc/lang/vi/wordblock.txt
inc/lang/zh-tw/wordblock.txt
inc/lang/zh/wordblock.txt
lib/scripts/pngbehavior.htc
# removed in rc2009-12-02
inc/lang/ar/wordblock.txt
inc/lang/ca-va/
lib/plugins/acl/lang/ca-va/
lib/plugins/config/lang/ca-va/
lib/plugins/plugin/lang/ca-va/
lib/plugins/popularity/lang/ca-va/
lib/plugins/revert/lang/ca-va/
lib/plugins/usermanager/lang/ca-va/
# removed in rc2009-01-30
lib/plugins/upgradeplugindirectory
lib/plugins/upgradeplugindirectory/action.php
# removed in rc2009-01-26
inc/auth/punbb.class.php
inc/lang/ko/edit.txt_bak
inc/lang/ko/lang.php_bak
inc/lang/ku/admin_acl.txt
inc/lang/mg/admin_acl.txt
lib/plugins/importoldchangelog
lib/plugins/importoldchangelog/action.php
lib/plugins/importoldindex
lib/plugins/importoldindex/action.php
lib/plugins/usermanager/images/no_user_edit.png
lib/plugins/usermanager/images/user_edit.png
lib/tpl/default/UWEB.css
# removed in rc2008-03-31
inc/aspell.php
inc/geshi/css-gen.cfg
inc/lang/fr/admin_acl.txt
lib/exe/spellcheck.php
lib/images/toolbar/spellcheck.png
lib/images/toolbar/spellnoerr.png
lib/images/toolbar/spellstop.png
lib/images/toolbar/spellwait.gif
lib/plugins/acl/lang/ar/intro.txt
lib/plugins/acl/lang/bg/intro.txt
lib/plugins/acl/lang/ca/intro.txt
lib/plugins/acl/lang/cs/intro.txt
lib/plugins/acl/lang/da/intro.txt
lib/plugins/acl/lang/de/intro.txt
lib/plugins/acl/lang/el/intro.txt
lib/plugins/acl/lang/en/intro.txt
lib/plugins/acl/lang/es/intro.txt
lib/plugins/acl/lang/et/intro.txt
lib/plugins/acl/lang/eu/intro.txt
lib/plugins/acl/lang/fi/intro.txt
lib/plugins/acl/lang/fr/intro.txt
lib/plugins/acl/lang/gl/intro.txt
lib/plugins/acl/lang/he/intro.txt
lib/plugins/acl/lang/id/intro.txt
lib/plugins/acl/lang/it/intro.txt
lib/plugins/acl/lang/ja/intro.txt
lib/plugins/acl/lang/ko/intro.txt
lib/plugins/acl/lang/lt/intro.txt
lib/plugins/acl/lang/lv/intro.txt
lib/plugins/acl/lang/nl/intro.txt
lib/plugins/acl/lang/no/intro.txt
lib/plugins/acl/lang/pl/intro.txt
lib/plugins/acl/lang/pt/intro.txt
lib/plugins/acl/lang/ru/intro.txt
lib/plugins/acl/lang/sk/intro.txt
lib/plugins/acl/lang/sr/intro.txt
lib/plugins/acl/lang/sv/intro.txt
lib/plugins/acl/lang/tr/intro.txt
lib/plugins/acl/lang/uk/intro.txt
lib/plugins/acl/lang/vi/intro.txt
lib/plugins/acl/lang/zh/intro.txt
lib/plugins/acl/lang/zh-tw/intro.txt
lib/scripts/spellcheck.js
lib/styles/spellcheck.css
# removed in 2007-06-26
inc/parser/wiki.php
lib/images/interwiki/bug.gif
lib/plugins/base.php
lib/plugins/plugin/inc
lib/plugins/plugin/inc/tarlib.class.php
lib/plugins/plugin/inc/zip.lib.php
lib/scripts/domLib.js
lib/scripts/domTT.js
# removed in 2006-11-06
inc/admin_acl.php
inc/magpie
inc/magpie/rss_cache.inc
inc/magpie/rss_fetch.inc
inc/magpie/rss_parse.inc
inc/magpie/rss_utils.inc
lib/exe/media.php
lib/tpl/default/mediaedit.php
lib/tpl/default/media.php
lib/tpl/default/mediaref.php
# removed in 2006-03-09
data/pages/wiki/playground.txt
inc/auth/ldap.php
inc/auth/mysql.php
inc/auth/pgsql.php
inc/auth/plain.php
inc/lang/ca/admin_acl.txt
inc/lang/cs/admin_acl.txt
inc/lang/da/admin_acl.txt
inc/lang/de/admin_acl.txt
inc/lang/en/admin_acl.txt
inc/lang/et/admin_acl.txt
inc/lang/eu/admin_acl.txt
inc/lang/fr/admin_acl.txt
inc/lang/it/admin_acl.txt
inc/lang/ja/admin_acl.txt
inc/lang/lt/admin_acl.txt
inc/lang/lv/admin_acl.txt
inc/lang/nl/admin_acl.txt
inc/lang/no/admin_acl.txt
inc/lang/pl/admin_acl.txt
inc/lang/pt/admin_acl.txt
inc/lang/vi/admin_acl.txt
inc/lang/zh-tw/admin_acl.txt
inc/parser/spamcheck.php
lib/images/favicon.ico
lib/images/thumbup.gif
lib/images/toolbar/code.png
lib/images/toolbar/empty.png
lib/images/toolbar/extlink.png
lib/images/toolbar/fonth1.png
lib/images/toolbar/fonth2.png
lib/images/toolbar/fonth3.png
lib/images/toolbar/fonth4.png
lib/images/toolbar/fonth5.png
lib/images/toolbar/list.png
lib/images/toolbar/list_ul.png
lib/images/toolbar/rule.png
lib/tpl/default/images/interwiki.png

View file

@ -1 +0,0 @@
You can safely delete this file.

View file

@ -1 +0,0 @@
You can safely delete this file.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

View file

@ -1 +0,0 @@
You can safely delete this file.

View file

@ -1 +0,0 @@
You can safely delete this file.

View file

@ -1 +0,0 @@
You can safely delete this file.

View file

@ -1 +0,0 @@
====== PlayGround ======

View file

@ -1,64 +0,0 @@
====== DokuWiki ======
[[doku>wiki:dokuwiki|{{wiki:dokuwiki-128.png }}]] DokuWiki is a simple to use and highly versatile Open Source [[wp>wiki]] software that doesn't require a database. It is loved by users for its clean and readable [[wiki:syntax]]. The ease of maintenance, backup and integration makes it an administrator's favorite. Built in [[doku>acl|access controls]] and [[doku>auth|authentication connectors]] make DokuWiki especially useful in the enterprise context and the large number of [[doku>plugins]] contributed by its vibrant community allow for a broad range of use cases beyond a traditional wiki.
Read the [[doku>manual|DokuWiki Manual]] to unleash the full power of DokuWiki.
===== Download =====
DokuWiki is available at http://download.dokuwiki.org/
===== Read More =====
All documentation and additional information besides the [[syntax|syntax description]] is maintained in the DokuWiki at [[doku>|www.dokuwiki.org]].
**About DokuWiki**
* [[doku>features|A feature list]] :!:
* [[doku>users|Happy Users]]
* [[doku>press|Who wrote about it]]
* [[doku>blogroll|What Bloggers think]]
* [[http://www.wikimatrix.org/show/DokuWiki|Compare it with other wiki software]]
**Installing DokuWiki**
* [[doku>requirements|System Requirements]]
* [[http://download.dokuwiki.org/|Download DokuWiki]] :!:
* [[doku>changes|Change Log]]
* [[doku>Install|How to install or upgrade]] :!:
* [[doku>config|Configuration]]
**Using DokuWiki**
* [[doku>syntax|Wiki Syntax]]
* [[doku>manual|The manual]] :!:
* [[doku>FAQ|Frequently Asked Questions (FAQ)]]
* [[doku>glossary|Glossary]]
* [[http://search.dokuwiki.org|Search for DokuWiki help and documentation]]
**Customizing DokuWiki**
* [[doku>tips|Tips and Tricks]]
* [[doku>Template|How to create and use templates]]
* [[doku>plugins|Installing plugins]]
* [[doku>development|Development Resources]]
**DokuWiki Feedback and Community**
* [[doku>newsletter|Subscribe to the newsletter]] :!:
* [[doku>mailinglist|Join the mailing list]]
* [[http://forum.dokuwiki.org|Check out the user forum]]
* [[doku>irc|Talk to other users in the IRC channel]]
* [[https://github.com/splitbrain/dokuwiki/issues|Submit bugs and feature wishes]]
* [[http://www.wikimatrix.org/forum/viewforum.php?id=10|Share your experiences in the WikiMatrix forum]]
* [[doku>thanks|Some humble thanks]]
===== Copyright =====
2004-2015 (c) Andreas Gohr <andi@splitbrain.org>((Please do not contact me for help and support -- use the [[doku>mailinglist]] or [[http://forum.dokuwiki.org|forum]] instead)) and the DokuWiki Community
The DokuWiki engine is licensed under [[http://www.gnu.org/licenses/gpl.html|GNU General Public License]] Version 2. If you use DokuWiki in your company, consider [[doku>donate|donating]] a few bucks ;-).
Not sure what this means? See the [[doku>faq:license|FAQ on the Licenses]].

View file

@ -1,523 +0,0 @@
====== Formatting Syntax ======
[[doku>DokuWiki]] supports some simple markup language, which tries to make the datafiles to be as readable as possible. This page contains all possible syntax you may use when editing the pages. Simply have a look at the source of this page by pressing "Edit this page". If you want to try something, just use the [[playground:playground|playground]] page. The simpler markup is easily accessible via [[doku>toolbar|quickbuttons]], too.
===== Basic Text Formatting =====
DokuWiki supports **bold**, //italic//, __underlined__ and ''monospaced'' texts. Of course you can **__//''combine''//__** all these.
DokuWiki supports **bold**, //italic//, __underlined__ and ''monospaced'' texts.
Of course you can **__//''combine''//__** all these.
You can use <sub>subscript</sub> and <sup>superscript</sup>, too.
You can use <sub>subscript</sub> and <sup>superscript</sup>, too.
You can mark something as <del>deleted</del> as well.
You can mark something as <del>deleted</del> as well.
**Paragraphs** are created from blank lines. If you want to **force a newline** without a paragraph, you can use two backslashes followed by a whitespace or the end of line.
This is some text with some linebreaks\\ Note that the
two backslashes are only recognized at the end of a line\\
or followed by\\ a whitespace \\this happens without it.
This is some text with some linebreaks\\ Note that the
two backslashes are only recognized at the end of a line\\
or followed by\\ a whitespace \\this happens without it.
You should use forced newlines only if really needed.
===== Links =====
DokuWiki supports multiple ways of creating links.
==== External ====
External links are recognized automagically: http://www.google.com or simply www.google.com - You can set the link text as well: [[http://www.google.com|This Link points to google]]. Email addresses like this one: <andi@splitbrain.org> are recognized, too.
DokuWiki supports multiple ways of creating links. External links are recognized
automagically: http://www.google.com or simply www.google.com - You can set
link text as well: [[http://www.google.com|This Link points to google]]. Email
addresses like this one: <andi@splitbrain.org> are recognized, too.
==== Internal ====
Internal links are created by using square brackets. You can either just give a [[pagename]] or use an additional [[pagename|link text]].
Internal links are created by using square brackets. You can either just give
a [[pagename]] or use an additional [[pagename|link text]].
[[doku>pagename|Wiki pagenames]] are converted to lowercase automatically, special characters are not allowed.
You can use [[some:namespaces]] by using a colon in the pagename.
You can use [[some:namespaces]] by using a colon in the pagename.
For details about namespaces see [[doku>namespaces]].
Linking to a specific section is possible, too. Just add the section name behind a hash character as known from HTML. This links to [[syntax#internal|this Section]].
This links to [[syntax#internal|this Section]].
Notes:
* Links to [[syntax|existing pages]] are shown in a different style from [[nonexisting]] ones.
* DokuWiki does not use [[wp>CamelCase]] to automatically create links by default, but this behavior can be enabled in the [[doku>config]] file. Hint: If DokuWiki is a link, then it's enabled.
* When a section's heading is changed, its bookmark changes, too. So don't rely on section linking too much.
==== Interwiki ====
DokuWiki supports [[doku>Interwiki]] links. These are quick links to other Wikis. For example this is a link to Wikipedia's page about Wikis: [[wp>Wiki]].
DokuWiki supports [[doku>Interwiki]] links. These are quick links to other Wikis.
For example this is a link to Wikipedia's page about Wikis: [[wp>Wiki]].
==== Windows Shares ====
Windows shares like [[\\server\share|this]] are recognized, too. Please note that these only make sense in a homogeneous user group like a corporate [[wp>Intranet]].
Windows Shares like [[\\server\share|this]] are recognized, too.
Notes:
* For security reasons direct browsing of windows shares only works in Microsoft Internet Explorer per default (and only in the "local zone").
* For Mozilla and Firefox it can be enabled through different workaround mentioned in the [[http://kb.mozillazine.org/Links_to_local_pages_do_not_work|Mozilla Knowledge Base]]. However, there will still be a JavaScript warning about trying to open a Windows Share. To remove this warning (for all users), put the following line in ''conf/lang/en/lang.php'' (more details at [[doku>localization#changing_some_localized_texts_and_strings_in_your_installation|localization]]): <code - conf/lang/en/lang.php>
<?php
/**
* Customization of the english language file
* Copy only the strings that needs to be modified
*/
$lang['js']['nosmblinks'] = '';
</code>
==== Image Links ====
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://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.
The whole [[#images_and_other_files|image]] and [[#links|link]] syntax is supported (including image resizing, internal and external images and URLs and interwiki links).
===== Footnotes =====
You can add footnotes ((This is a footnote)) by using double parentheses.
You can add footnotes ((This is a footnote)) by using double parentheses.
===== Sectioning =====
You can use up to five different levels of headlines to structure your content. If you have more than three headlines, a table of contents is generated automatically -- this can be disabled by including the string ''<nowiki>~~NOTOC~~</nowiki>'' in the document.
==== Headline Level 3 ====
=== Headline Level 4 ===
== Headline Level 5 ==
==== Headline Level 3 ====
=== Headline Level 4 ===
== Headline Level 5 ==
By using four or more dashes, you can make a horizontal line:
----
===== Media Files =====
You can include external and internal [[doku>images|images, videos and audio files]] with curly brackets. Optionally you can specify the size of them.
Real size: {{wiki:dokuwiki-128.png}}
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://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://php.net/images/php.gif?200x50}}
By using left or right whitespaces you can choose the alignment.
{{ wiki:dokuwiki-128.png}}
{{wiki:dokuwiki-128.png }}
{{ wiki:dokuwiki-128.png }}
{{ wiki:dokuwiki-128.png}}
{{wiki:dokuwiki-128.png }}
{{ wiki:dokuwiki-128.png }}
Of course, you can add a title (displayed as a tooltip by most browsers), too.
{{ wiki:dokuwiki-128.png |This is the caption}}
{{ wiki:dokuwiki-128.png |This is the caption}}
For linking an image to another page see [[#Image Links]] above.
==== Supported Media Formats ====
DokuWiki can embed the following media formats directly.
| Image | ''gif'', ''jpg'', ''png'' |
| Video | ''webm'', ''ogv'', ''mp4'' |
| Audio | ''ogg'', ''mp3'', ''wav'' |
| Flash | ''swf'' |
If you specify a filename that is not a supported media format, then it will be displayed as a link instead.
By adding ''?linkonly'' you provide a link to the media without displaying it inline
{{wiki:dokuwiki-128.png?linkonly}}
{{wiki:dokuwiki-128.png?linkonly}} This is just a link to the image.
==== Fallback Formats ====
Unfortunately not all browsers understand all video and audio formats. To mitigate the problem, you can upload your file in different formats for maximum browser compatibility.
For example consider this embedded mp4 video:
{{video.mp4|A funny video}}
When you upload a ''video.webm'' and ''video.ogv'' next to the referenced ''video.mp4'', DokuWiki will automatically add them as alternatives so that one of the three files is understood by your browser.
Additionally DokuWiki supports a "poster" image which will be shown before the video has started. That image needs to have the same filename as the video and be either a jpg or png file. In the example above a ''video.jpg'' file would work.
===== Lists =====
Dokuwiki supports ordered and unordered lists. To create a list item, indent your text by two spaces and use a ''*'' for unordered lists or a ''-'' for ordered ones.
* This is a list
* The second item
* You may have different levels
* Another item
- The same list but ordered
- Another item
- Just use indention for deeper levels
- That's it
<code>
* This is a list
* The second item
* You may have different levels
* Another item
- The same list but ordered
- Another item
- Just use indention for deeper levels
- That's it
</code>
Also take a look at the [[doku>faq:lists|FAQ on list items]].
===== Text Conversions =====
DokuWiki can convert certain pre-defined characters or strings into images or other text or HTML.
The text to image conversion is mainly done for smileys. And the text to HTML conversion is used for typography replacements, but can be configured to use other HTML as well.
==== Text to Image Conversions ====
DokuWiki converts commonly used [[wp>emoticon]]s to their graphical equivalents. Those [[doku>Smileys]] and other images can be configured and extended. Here is an overview of Smileys included in DokuWiki:
* 8-) %% 8-) %%
* 8-O %% 8-O %%
* :-( %% :-( %%
* :-) %% :-) %%
* =) %% =) %%
* :-/ %% :-/ %%
* :-\ %% :-\ %%
* :-? %% :-? %%
* :-D %% :-D %%
* :-P %% :-P %%
* :-O %% :-O %%
* :-X %% :-X %%
* :-| %% :-| %%
* ;-) %% ;-) %%
* ^_^ %% ^_^ %%
* :?: %% :?: %%
* :!: %% :!: %%
* LOL %% LOL %%
* FIXME %% FIXME %%
* DELETEME %% DELETEME %%
==== Text to HTML Conversions ====
Typography: [[DokuWiki]] can convert simple text characters to their typographically correct entities. Here is an example of recognized characters.
-> <- <-> => <= <=> >> << -- --- 640x480 (c) (tm) (r)
"He thought 'It's a man's world'..."
<code>
-> <- <-> => <= <=> >> << -- --- 640x480 (c) (tm) (r)
"He thought 'It's a man's world'..."
</code>
The same can be done to produce any kind of HTML, it just needs to be added to the [[doku>entities|pattern file]].
There are three exceptions which do not come from that pattern file: multiplication entity (640x480), 'single' and "double quotes". They can be turned off through a [[doku>config:typography|config option]].
===== Quoting =====
Some times you want to mark some text to show it's a reply or comment. You can use the following syntax:
<code>
I think we should do it
> No we shouldn't
>> Well, I say we should
> Really?
>> Yes!
>>> Then lets do it!
</code>
I think we should do it
> No we shouldn't
>> Well, I say we should
> Really?
>> Yes!
>>> Then lets do it!
===== Tables =====
DokuWiki supports a simple syntax to create tables.
^ Heading 1 ^ Heading 2 ^ Heading 3 ^
| Row 1 Col 1 | Row 1 Col 2 | Row 1 Col 3 |
| Row 2 Col 1 | some colspan (note the double pipe) ||
| Row 3 Col 1 | Row 3 Col 2 | Row 3 Col 3 |
Table rows have to start and end with a ''|'' for normal rows or a ''^'' for headers.
^ Heading 1 ^ Heading 2 ^ Heading 3 ^
| Row 1 Col 1 | Row 1 Col 2 | Row 1 Col 3 |
| Row 2 Col 1 | some colspan (note the double pipe) ||
| Row 3 Col 1 | Row 3 Col 2 | Row 3 Col 3 |
To connect cells horizontally, just make the next cell completely empty as shown above. Be sure to have always the same amount of cell separators!
Vertical tableheaders are possible, too.
| ^ Heading 1 ^ Heading 2 ^
^ Heading 3 | Row 1 Col 2 | Row 1 Col 3 |
^ Heading 4 | no colspan this time | |
^ Heading 5 | Row 2 Col 2 | Row 2 Col 3 |
As you can see, it's the cell separator before a cell which decides about the formatting:
| ^ Heading 1 ^ Heading 2 ^
^ Heading 3 | Row 1 Col 2 | Row 1 Col 3 |
^ Heading 4 | no colspan this time | |
^ Heading 5 | Row 2 Col 2 | Row 2 Col 3 |
You can have rowspans (vertically connected cells) by adding ''%%:::%%'' into the cells below the one to which they should connect.
^ Heading 1 ^ Heading 2 ^ Heading 3 ^
| Row 1 Col 1 | this cell spans vertically | Row 1 Col 3 |
| Row 2 Col 1 | ::: | Row 2 Col 3 |
| Row 3 Col 1 | ::: | Row 2 Col 3 |
Apart from the rowspan syntax those cells should not contain anything else.
^ Heading 1 ^ Heading 2 ^ Heading 3 ^
| Row 1 Col 1 | this cell spans vertically | Row 1 Col 3 |
| Row 2 Col 1 | ::: | Row 2 Col 3 |
| Row 3 Col 1 | ::: | Row 2 Col 3 |
You can align the table contents, too. Just add at least two whitespaces at the opposite end of your text: Add two spaces on the left to align right, two spaces on the right to align left and two spaces at least at both ends for centered text.
^ Table with alignment ^^^
| right| center |left |
|left | right| center |
| xxxxxxxxxxxx | xxxxxxxxxxxx | xxxxxxxxxxxx |
This is how it looks in the source:
^ Table with alignment ^^^
| right| center |left |
|left | right| center |
| xxxxxxxxxxxx | xxxxxxxxxxxx | xxxxxxxxxxxx |
Note: Vertical alignment is not supported.
===== No Formatting =====
If you need to display text exactly like it is typed (without any formatting), enclose the area either with ''%%<nowiki>%%'' tags or even simpler, with double percent signs ''<nowiki>%%</nowiki>''.
<nowiki>
This is some text which contains addresses like this: http://www.splitbrain.org and **formatting**, but nothing is done with it.
</nowiki>
The same is true for %%//__this__ text// with a smiley ;-)%%.
<nowiki>
This is some text which contains addresses like this: http://www.splitbrain.org and **formatting**, but nothing is done with it.
</nowiki>
The same is true for %%//__this__ text// with a smiley ;-)%%.
===== Code Blocks =====
You can include code blocks into your documents by either indenting them by at least two spaces (like used for the previous examples) or by using the tags ''%%<code>%%'' or ''%%<file>%%''.
This is text is indented by two spaces.
<code>
This is preformatted code all spaces are preserved: like <-this
</code>
<file>
This is pretty much the same, but you could use it to show that you quoted a file.
</file>
Those blocks were created by this source:
This is text is indented by two spaces.
<code>
This is preformatted code all spaces are preserved: like <-this
</code>
<file>
This is pretty much the same, but you could use it to show that you quoted a file.
</file>
==== Syntax Highlighting ====
[[wiki:DokuWiki]] can highlight sourcecode, which makes it easier to read. It uses the [[http://qbnz.com/highlighter/|GeSHi]] Generic Syntax Highlighter -- so any language supported by GeSHi is supported. The syntax uses the same code and file blocks described in the previous section, but this time the name of the language syntax to be highlighted is included inside the tag, e.g. ''<nowiki><code java></nowiki>'' or ''<nowiki><file java></nowiki>''.
<code java>
/**
* The HelloWorldApp class implements an application that
* simply displays "Hello World!" to the standard output.
*/
class HelloWorldApp {
public static void main(String[] args) {
System.out.println("Hello World!"); //Display the string.
}
}
</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//
==== Downloadable Code Blocks ====
When you use the ''%%<code>%%'' or ''%%<file>%%'' syntax as above, you might want to make the shown code available for download as well. You can do this by specifying a file name after language code like this:
<code>
<file php myexample.php>
<?php echo "hello world!"; ?>
</file>
</code>
<file php myexample.php>
<?php echo "hello world!"; ?>
</file>
If you don't want any highlighting but want a downloadable file, specify a dash (''-'') as the language code: ''%%<code - myfile.foo>%%''.
===== Embedding HTML and PHP =====
You can embed raw HTML or PHP code into your documents by using the ''%%<html>%%'' or ''%%<php>%%'' tags. (Use uppercase tags if you need to enclose block level elements.)
HTML example:
<code>
<html>
This is some <span style="color:red;font-size:150%;">inline HTML</span>
</html>
<HTML>
<p style="border:2px dashed red;">And this is some block HTML</p>
</HTML>
</code>
<html>
This is some <span style="color:red;font-size:150%;">inline HTML</span>
</html>
<HTML>
<p style="border:2px dashed red;">And this is some block HTML</p>
</HTML>
PHP example:
<code>
<php>
echo 'The PHP version: ';
echo phpversion();
echo ' (generated inline HTML)';
</php>
<PHP>
echo '<table class="inline"><tr><td>The same, but inside a block level element:</td>';
echo '<td>'.phpversion().'</td>';
echo '</tr></table>';
</PHP>
</code>
<php>
echo 'The PHP version: ';
echo phpversion();
echo ' (inline HTML)';
</php>
<PHP>
echo '<table class="inline"><tr><td>The same, but inside a block level element:</td>';
echo '<td>'.phpversion().'</td>';
echo '</tr></table>';
</PHP>
**Please Note**: HTML and PHP embedding is disabled by default in the configuration. If disabled, the code is displayed instead of executed.
===== RSS/ATOM Feed Aggregation =====
[[DokuWiki]] can integrate data from external XML feeds. For parsing the XML feeds, [[http://simplepie.org/|SimplePie]] is used. All formats understood by SimplePie can be used in DokuWiki as well. You can influence the rendering by multiple additional space separated parameters:
^ Parameter ^ Description ^
| any number | will be used as maximum number items to show, defaults to 8 |
| reverse | display the last items in the feed first |
| author | show item authors names |
| date | show item dates |
| description| show the item description. If [[doku>config:htmlok|HTML]] is disabled all tags will be stripped |
| nosort | do not sort the items in the feed |
| //n//[dhm] | refresh period, where d=days, h=hours, m=minutes. (e.g. 12h = 12 hours). |
The refresh period defaults to 4 hours. Any value below 10 minutes will be treated as 10 minutes. [[wiki:DokuWiki]] will generally try to supply a cached version of a page, obviously this is inappropriate when the page contains dynamic external content. The parameter tells [[wiki:DokuWiki]] to re-render the page if it is more than //refresh period// since the page was last rendered.
By default the feed will be sorted by date, newest items first. You can sort it by oldest first using the ''reverse'' parameter, or display the feed as is with ''nosort''.
**Example:**
{{rss>http://slashdot.org/index.rss 5 author date 1h }}
{{rss>http://slashdot.org/index.rss 5 author date 1h }}
===== Control Macros =====
Some syntax influences how DokuWiki renders a page without creating any output it self. The following control macros are availble:
^ Macro ^ Description |
| %%~~NOTOC~~%% | If this macro is found on the page, no table of contents will be created |
| %%~~NOCACHE~~%% | DokuWiki caches all output by default. Sometimes this might not be wanted (eg. when the %%<php>%% syntax above is used), adding this macro will force DokuWiki to rerender a page on every call |
===== Syntax Plugins =====
DokuWiki's syntax can be extended by [[doku>plugins|Plugins]]. How the installed plugins are used is described on their appropriate description pages. The following syntax plugins are available in this particular DokuWiki installation:
~~INFO:syntaxplugins~~

View file

@ -1,30 +0,0 @@
====== Welcome to your new DokuWiki ======
Congratulations, your wiki is now up and running. Here are a few more tips to get you started.
Enjoy your work with DokuWiki,\\
-- the developers
===== Create your first pages =====
Your wiki needs to have a start page. As long as it doesn't exist, this link will be red: [[:start]].
Go on, follow that link and create the page. If you need help with using the syntax you can always refer to the [[wiki:syntax|syntax page]].
You might also want to use a sidebar. To create it, just edit the [[:sidebar]] page. Everything in that page will be shown in a margin column on the side. Read our [[doku>faq:sidebar|FAQ on sidebars]] to learn more.
Please be aware that not all templates support sidebars.
===== Customize your Wiki =====
Once you're comfortable with creating and editing pages you might want to have a look at the [[this>doku.php?do=admin&page=config|configuration settings]] (be sure to login as superuser first).
You may also want to see what [[doku>plugins|plugins]] and [[doku>templates|templates]] are available at DokuWiki.org to extend the functionality and looks of your DokuWiki installation.
===== Join the Community =====
DokuWiki is an Open Source project that thrives through user contributions. A good way to stay informed on what's going on and to get useful tips in using DokuWiki is subscribing to the [[doku>newsletter]].
The [[http://forum.dokuwiki.org|DokuWiki User Forum]] is an excellent way to get in contact with other DokuWiki users and is just one of the many ways to get [[doku>faq:support|support]].
Of course we'd be more than happy to have you [[doku>teams:getting_involved|getting involved]] with DokuWiki.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

View file

@ -1 +0,0 @@
You can safely delete this file.

View file

@ -1,129 +0,0 @@
<?php
/**
* DokuWiki mainscript
*
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
* @author Andreas Gohr <andi@splitbrain.org>
*
* @global Input $INPUT
*/
// update message version - always use a string to avoid localized floats!
$updateVersion = "48.1";
// xdebug_start_profiling();
if(!defined('DOKU_INC')) define('DOKU_INC', dirname(__FILE__).'/');
// define all DokuWiki globals here (needed within test requests but also helps to keep track)
global $ACT, $INPUT, $QUERY, $ID, $REV, $DATE_AT, $IDX,
$DATE, $RANGE, $HIGH, $TEXT, $PRE, $SUF, $SUM, $INFO, $JSINFO;
if(isset($_SERVER['HTTP_X_DOKUWIKI_DO'])) {
$ACT = trim(strtolower($_SERVER['HTTP_X_DOKUWIKI_DO']));
} elseif(!empty($_REQUEST['idx'])) {
$ACT = 'index';
} elseif(isset($_REQUEST['do'])) {
$ACT = $_REQUEST['do'];
} else {
$ACT = 'show';
}
// load and initialize the core system
require_once(DOKU_INC.'inc/init.php');
//import variables
$INPUT->set('id', str_replace("\xC2\xAD", '', $INPUT->str('id'))); //soft-hyphen
$QUERY = trim($INPUT->str('id'));
$ID = getID();
$REV = $INPUT->int('rev');
$DATE_AT = $INPUT->str('at');
$IDX = $INPUT->str('idx');
$DATE = $INPUT->int('date');
$RANGE = $INPUT->str('range');
$HIGH = $INPUT->param('s');
if(empty($HIGH)) $HIGH = getGoogleQuery();
if($INPUT->post->has('wikitext')) {
$TEXT = cleanText($INPUT->post->str('wikitext'));
}
$PRE = cleanText(substr($INPUT->post->str('prefix'), 0, -1));
$SUF = cleanText($INPUT->post->str('suffix'));
$SUM = $INPUT->post->str('summary');
//parse DATE_AT
if($DATE_AT) {
$date_parse = strtotime($DATE_AT);
if($date_parse) {
$DATE_AT = $date_parse;
} 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));
$DATE_AT = null;
}
}
}
//check for existing $REV related to $DATE_AT
if($DATE_AT) {
$pagelog = new PageChangeLog($ID);
$rev_t = $pagelog->getLastRevisionAt($DATE_AT);
if($rev_t === '') { //current revision
$REV = null;
$DATE_AT = null;
} else if ($rev_t === false) { //page did not exist
$rev_n = $pagelog->getRelativeRevision($DATE_AT,+1);
msg(sprintf($lang['page_nonexist_rev'],
strftime($conf['dformat'],$DATE_AT),
wl($ID, array('rev' => $rev_n)),
strftime($conf['dformat'],$rev_n)));
$REV = $DATE_AT; //will result in a page not exists message
} else {
$REV = $rev_t;
}
}
//make infos about the selected page available
$INFO = pageinfo();
//export minimal info to JS, plugins can add more
$JSINFO['id'] = $ID;
$JSINFO['namespace'] = (string) $INFO['namespace'];
// handle debugging
if($conf['allowdebug'] && $ACT == 'debug') {
html_debug();
exit;
}
//send 404 for missing pages if configured or ID has special meaning to bots
if(!$INFO['exists'] &&
($conf['send404'] || preg_match('/^(robots\.txt|sitemap\.xml(\.gz)?|favicon\.ico|crossdomain\.xml)$/', $ID)) &&
($ACT == 'show' || (!is_array($ACT) && substr($ACT, 0, 7) == 'export_'))
) {
header('HTTP/1.0 404 Not Found');
}
//prepare breadcrumbs (initialize a static var)
if($conf['breadcrumbs']) breadcrumbs();
// check upstream
checkUpdateMessages();
$tmp = array(); // No event data
trigger_event('DOKUWIKI_STARTED', $tmp);
//close session
session_write_close();
//do the work (picks up what to do from global env)
act_dispatch();
$tmp = array(); // No event data
trigger_event('DOKUWIKI_DONE', $tmp);
// xdebug_dump_function_profile(1);

View file

@ -1,514 +0,0 @@
<?php
/**
* XML feed export
*
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
* @author Andreas Gohr <andi@splitbrain.org>
*
* @global array $conf
* @global Input $INPUT
*/
if(!defined('DOKU_INC')) define('DOKU_INC', dirname(__FILE__).'/');
require_once(DOKU_INC.'inc/init.php');
//close session
session_write_close();
//feed disabled?
if(!actionOK('rss')) {
http_status(404);
echo '<error>RSS feed is disabled.</error>';
exit;
}
// get params
$opt = rss_parseOptions();
// the feed is dynamic - we need a cache for each combo
// (but most people just use the default feed so it's still effective)
$key = join('', array_values($opt)).'$'.$_SERVER['REMOTE_USER'].'$'.$_SERVER['HTTP_HOST'].$_SERVER['SERVER_PORT'];
$cache = new cache($key, '.feed');
// prepare cache depends
$depends['files'] = getConfigFiles('main');
$depends['age'] = $conf['rss_update'];
$depends['purge'] = $INPUT->bool('purge');
// check cacheage and deliver if nothing has changed since last
// time or the update interval has not passed, also handles conditional requests
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Pragma: public');
header('Content-Type: application/xml; charset=utf-8');
header('X-Robots-Tag: noindex');
if($cache->useCache($depends)) {
http_conditionalRequest($cache->_time);
if($conf['allowdebug']) header("X-CacheUsed: $cache->cache");
print $cache->retrieveCache();
exit;
} else {
http_conditionalRequest(time());
}
// create new feed
$rss = new DokuWikiFeedCreator();
$rss->title = $conf['title'].(($opt['namespace']) ? ' '.$opt['namespace'] : '');
$rss->link = DOKU_URL;
$rss->syndicationURL = DOKU_URL.'feed.php';
$rss->cssStyleSheet = DOKU_URL.'lib/exe/css.php?s=feed';
$image = new FeedImage();
$image->title = $conf['title'];
$image->url = tpl_getMediaFile(array(':wiki:favicon.ico', ':favicon.ico', 'images/favicon.ico'), true);
$image->link = DOKU_URL;
$rss->image = $image;
$data = null;
$modes = array(
'list' => 'rssListNamespace',
'search' => 'rssSearch',
'recent' => 'rssRecentChanges'
);
if(isset($modes[$opt['feed_mode']])) {
$data = $modes[$opt['feed_mode']]($opt);
} else {
$eventData = array(
'opt' => &$opt,
'data' => &$data,
);
$event = new Doku_Event('FEED_MODE_UNKNOWN', $eventData);
if($event->advise_before(true)) {
echo sprintf('<error>Unknown feed mode %s</error>', hsc($opt['feed_mode']));
exit;
}
$event->advise_after();
}
rss_buildItems($rss, $data, $opt);
$feed = $rss->createFeed($opt['feed_type'], 'utf-8');
// save cachefile
$cache->storeCache($feed);
// finally deliver
print $feed;
// ---------------------------------------------------------------- //
/**
* Get URL parameters and config options and return an initialized option array
*
* @author Andreas Gohr <andi@splitbrain.org>
*/
function rss_parseOptions() {
global $conf;
global $INPUT;
$opt = array();
foreach(array(
// Basic feed properties
// Plugins may probably want to add new values to these
// properties for implementing own feeds
// One of: list, search, recent
'feed_mode' => array('str', 'mode', 'recent'),
// One of: diff, page, rev, current
'link_to' => array('str', 'linkto', $conf['rss_linkto']),
// One of: abstract, diff, htmldiff, html
'item_content' => array('str', 'content', $conf['rss_content']),
// Special feed properties
// These are only used by certain feed_modes
// String, used for feed title, in list and rc mode
'namespace' => array('str', 'ns', null),
// Positive integer, only used in rc mode
'items' => array('int', 'num', $conf['recent']),
// Boolean, only used in rc mode
'show_minor' => array('bool', 'minor', false),
// String, only used in list mode
'sort' => array('str', 'sort', 'natural'),
// String, only used in search mode
'search_query' => array('str', 'q', null),
// One of: pages, media, both
'content_type' => array('str', 'view', $conf['rss_media'])
) as $name => $val) {
$opt[$name] = $INPUT->{$val[0]}($val[1], $val[2], true);
}
$opt['items'] = max(0, (int) $opt['items']);
$opt['show_minor'] = (bool) $opt['show_minor'];
$opt['sort'] = valid_input_set('sort', array('default' => 'natural', 'date'), $opt);
$opt['guardmail'] = ($conf['mailguard'] != '' && $conf['mailguard'] != 'none');
$type = $INPUT->valid(
'type',
array( 'rss', 'rss2', 'atom', 'atom1', 'rss1'),
$conf['rss_type']
);
switch($type) {
case 'rss':
$opt['feed_type'] = 'RSS0.91';
$opt['mime_type'] = 'text/xml';
break;
case 'rss2':
$opt['feed_type'] = 'RSS2.0';
$opt['mime_type'] = 'text/xml';
break;
case 'atom':
$opt['feed_type'] = 'ATOM0.3';
$opt['mime_type'] = 'application/xml';
break;
case 'atom1':
$opt['feed_type'] = 'ATOM1.0';
$opt['mime_type'] = 'application/atom+xml';
break;
default:
$opt['feed_type'] = 'RSS1.0';
$opt['mime_type'] = 'application/xml';
}
$eventData = array(
'opt' => &$opt,
);
trigger_event('FEED_OPTS_POSTPROCESS', $eventData);
return $opt;
}
/**
* Add recent changed pages to a feed object
*
* @author Andreas Gohr <andi@splitbrain.org>
* @param FeedCreator $rss the FeedCreator Object
* @param array $data the items to add
* @param array $opt the feed options
*/
function rss_buildItems(&$rss, &$data, $opt) {
global $conf;
global $lang;
/* @var DokuWiki_Auth_Plugin $auth */
global $auth;
$eventData = array(
'rss' => &$rss,
'data' => &$data,
'opt' => &$opt,
);
$event = new Doku_Event('FEED_DATA_PROCESS', $eventData);
if($event->advise_before(false)) {
foreach($data as $ditem) {
if(!is_array($ditem)) {
// not an array? then only a list of IDs was given
$ditem = array('id' => $ditem);
}
$item = new FeedItem();
$id = $ditem['id'];
if(!$ditem['media']) {
$meta = p_get_metadata($id);
} else {
$meta = array();
}
// add date
if($ditem['date']) {
$date = $ditem['date'];
} elseif ($ditem['media']) {
$date = @filemtime(mediaFN($id));
} elseif (file_exists(wikiFN($id))) {
$date = @filemtime(wikiFN($id));
} elseif($meta['date']['modified']) {
$date = $meta['date']['modified'];
} else {
$date = 0;
}
if($date) $item->date = date('r', $date);
// add title
if($conf['useheading'] && $meta['title']) {
$item->title = $meta['title'];
} else {
$item->title = $ditem['id'];
}
if($conf['rss_show_summary'] && !empty($ditem['sum'])) {
$item->title .= ' - '.strip_tags($ditem['sum']);
}
// add item link
switch($opt['link_to']) {
case 'page':
if($ditem['media']) {
$item->link = media_managerURL(
array(
'image' => $id,
'ns' => getNS($id),
'rev' => $date
), '&', true
);
} else {
$item->link = wl($id, 'rev='.$date, true, '&');
}
break;
case 'rev':
if($ditem['media']) {
$item->link = media_managerURL(
array(
'image' => $id,
'ns' => getNS($id),
'rev' => $date,
'tab_details' => 'history'
), '&', true
);
} else {
$item->link = wl($id, 'do=revisions&rev='.$date, true, '&');
}
break;
case 'current':
if($ditem['media']) {
$item->link = media_managerURL(
array(
'image' => $id,
'ns' => getNS($id)
), '&', true
);
} else {
$item->link = wl($id, '', true, '&');
}
break;
case 'diff':
default:
if($ditem['media']) {
$item->link = media_managerURL(
array(
'image' => $id,
'ns' => getNS($id),
'rev' => $date,
'tab_details' => 'history',
'mediado' => 'diff'
), '&', true
);
} else {
$item->link = wl($id, 'rev='.$date.'&do=diff', true, '&');
}
}
// add item content
switch($opt['item_content']) {
case 'diff':
case 'htmldiff':
if($ditem['media']) {
$medialog = new MediaChangeLog($id);
$revs = $medialog->getRevisions(0, 1);
$rev = $revs[0];
$src_r = '';
$src_l = '';
if($size = media_image_preview_size($id, '', new JpegMeta(mediaFN($id)), 300)) {
$more = 'w='.$size[0].'&h='.$size[1].'&t='.@filemtime(mediaFN($id));
$src_r = ml($id, $more, true, '&amp;', true);
}
if($rev && $size = media_image_preview_size($id, $rev, new JpegMeta(mediaFN($id, $rev)), 300)) {
$more = 'rev='.$rev.'&w='.$size[0].'&h='.$size[1];
$src_l = ml($id, $more, true, '&amp;', true);
}
$content = '';
if($src_r) {
$content = '<table>';
$content .= '<tr><th width="50%">'.$rev.'</th>';
$content .= '<th width="50%">'.$lang['current'].'</th></tr>';
$content .= '<tr align="center"><td><img src="'.$src_l.'" alt="" /></td><td>';
$content .= '<img src="'.$src_r.'" alt="'.$id.'" /></td></tr>';
$content .= '</table>';
}
} else {
require_once(DOKU_INC.'inc/DifferenceEngine.php');
$pagelog = new PageChangeLog($id);
$revs = $pagelog->getRevisions(0, 1);
$rev = $revs[0];
if($rev) {
$df = new Diff(explode("\n", rawWiki($id, $rev)),
explode("\n", rawWiki($id, '')));
} else {
$df = new Diff(array(''),
explode("\n", rawWiki($id, '')));
}
if($opt['item_content'] == 'htmldiff') {
// note: no need to escape diff output, TableDiffFormatter provides 'safe' html
$tdf = new TableDiffFormatter();
$content = '<table>';
$content .= '<tr><th colspan="2" width="50%">'.$rev.'</th>';
$content .= '<th colspan="2" width="50%">'.$lang['current'].'</th></tr>';
$content .= $tdf->format($df);
$content .= '</table>';
} else {
// note: diff output must be escaped, UnifiedDiffFormatter provides plain text
$udf = new UnifiedDiffFormatter();
$content = "<pre>\n".hsc($udf->format($df))."\n</pre>";
}
}
break;
case 'html':
if($ditem['media']) {
if($size = media_image_preview_size($id, '', new JpegMeta(mediaFN($id)))) {
$more = 'w='.$size[0].'&h='.$size[1].'&t='.@filemtime(mediaFN($id));
$src = ml($id, $more, true, '&amp;', true);
$content = '<img src="'.$src.'" alt="'.$id.'" />';
} else {
$content = '';
}
} else {
if (@filemtime(wikiFN($id)) === $date) {
$content = p_wiki_xhtml($id, '', false);
} else {
$content = p_wiki_xhtml($id, $date, false);
}
// no TOC in feeds
$content = preg_replace('/(<!-- TOC START -->).*(<!-- TOC END -->)/s', '', $content);
// add alignment for images
$content = preg_replace('/(<img .*?class="medialeft")/s', '\\1 align="left"', $content);
$content = preg_replace('/(<img .*?class="mediaright")/s', '\\1 align="right"', $content);
// make URLs work when canonical is not set, regexp instead of rerendering!
if(!$conf['canonical']) {
$base = preg_quote(DOKU_REL, '/');
$content = preg_replace('/(<a href|<img src)="('.$base.')/s', '$1="'.DOKU_URL, $content);
}
}
break;
case 'abstract':
default:
if($ditem['media']) {
if($size = media_image_preview_size($id, '', new JpegMeta(mediaFN($id)))) {
$more = 'w='.$size[0].'&h='.$size[1].'&t='.@filemtime(mediaFN($id));
$src = ml($id, $more, true, '&amp;', true);
$content = '<img src="'.$src.'" alt="'.$id.'" />';
} else {
$content = '';
}
} else {
$content = $meta['description']['abstract'];
}
}
$item->description = $content; //FIXME a plugin hook here could be senseful
// add user
# FIXME should the user be pulled from metadata as well?
$user = @$ditem['user']; // the @ spares time repeating lookup
$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'];
} else {
$item->authorEmail = 'anonymous@'.$ditem['ip'];
}
// add category
if(isset($meta['subject'])) {
$item->category = $meta['subject'];
} else {
$cat = getNS($id);
if($cat) $item->category = $cat;
}
// finally add the item to the feed object, after handing it to registered plugins
$evdata = array(
'item' => &$item,
'opt' => &$opt,
'ditem' => &$ditem,
'rss' => &$rss
);
$evt = new Doku_Event('FEED_ITEM_ADD', $evdata);
if($evt->advise_before()) {
$rss->addItem($item);
}
$evt->advise_after(); // for completeness
}
}
$event->advise_after();
}
/**
* Add recent changed pages to the feed object
*
* @author Andreas Gohr <andi@splitbrain.org>
*/
function rssRecentChanges($opt) {
global $conf;
$flags = RECENTS_SKIP_DELETED;
if(!$opt['show_minor']) $flags += RECENTS_SKIP_MINORS;
if($opt['content_type'] == 'media' && $conf['mediarevisions']) $flags += RECENTS_MEDIA_CHANGES;
if($opt['content_type'] == 'both' && $conf['mediarevisions']) $flags += RECENTS_MEDIA_PAGES_MIXED;
$recents = getRecents(0, $opt['items'], $opt['namespace'], $flags);
return $recents;
}
/**
* Add all pages of a namespace to the feed object
*
* @author Andreas Gohr <andi@splitbrain.org>
*/
function rssListNamespace($opt) {
require_once(DOKU_INC.'inc/search.php');
global $conf;
$ns = ':'.cleanID($opt['namespace']);
$ns = utf8_encodeFN(str_replace(':', '/', $ns));
$data = array();
$search_opts = array(
'depth' => 1,
'pagesonly' => true,
'listfiles' => true
);
search($data, $conf['datadir'], 'search_universal', $search_opts, $ns, $lvl = 1, $opt['sort']);
return $data;
}
/**
* Add the result of a full text search to the feed object
*
* @author Andreas Gohr <andi@splitbrain.org>
*/
function rssSearch($opt) {
if(!$opt['search_query']) return array();
require_once(DOKU_INC.'inc/fulltext.php');
$data = ft_pageSearch($opt['search_query'], $poswords);
$data = array_keys($data);
return $data;
}
//Setup VIM: ex: et ts=4 :

View file

@ -1,8 +0,0 @@
## no access to the inc directory
<IfModule mod_authz_host>
Require all denied
</IfModule>
<IfModule !mod_authz_host>
Order allow,deny
Deny from all
</IfModule>

File diff suppressed because it is too large Load diff

View file

@ -1,191 +0,0 @@
<?php
/**
* EmailAddressValidator Class
*
* @author Dave Child <dave@addedbytes.com>
* @link http://code.google.com/p/php-email-address-validation/
* @license http://www.opensource.org/licenses/bsd-license.php
* @version SVN r10 + Issue 15 fix + Issue 12 fix
*/
class EmailAddressValidator {
/**
* Set true to allow addresses like me@localhost
*/
public $allowLocalAddresses = false;
/**
* Check email address validity
* @param string $strEmailAddress Email address to be checked
* @return bool True if email is valid, false if not
*/
public function check_email_address($strEmailAddress) {
// If magic quotes is "on", email addresses with quote marks will
// fail validation because of added escape characters. Uncommenting
// the next three lines will allow for this issue.
//if (get_magic_quotes_gpc()) {
// $strEmailAddress = stripslashes($strEmailAddress);
//}
// Control characters are not allowed
if (preg_match('/[\x00-\x1F\x7F-\xFF]/', $strEmailAddress)) {
return false;
}
// Check email length - min 3 (a@a), max 256
if (!$this->check_text_length($strEmailAddress, 3, 256)) {
return false;
}
// Split it into sections using last instance of "@"
$intAtSymbol = strrpos($strEmailAddress, '@');
if ($intAtSymbol === false) {
// No "@" symbol in email.
return false;
}
$arrEmailAddress[0] = substr($strEmailAddress, 0, $intAtSymbol);
$arrEmailAddress[1] = substr($strEmailAddress, $intAtSymbol + 1);
// Count the "@" symbols. Only one is allowed, except where
// contained in quote marks in the local part. Quickest way to
// check this is to remove anything in quotes. We also remove
// characters escaped with backslash, and the backslash
// character.
$arrTempAddress[0] = preg_replace('/\./'
,''
,$arrEmailAddress[0]);
$arrTempAddress[0] = preg_replace('/"[^"]+"/'
,''
,$arrTempAddress[0]);
$arrTempAddress[1] = $arrEmailAddress[1];
$strTempAddress = $arrTempAddress[0] . $arrTempAddress[1];
// Then check - should be no "@" symbols.
if (strrpos($strTempAddress, '@') !== false) {
// "@" symbol found
return false;
}
// Check local portion
if (!$this->check_local_portion($arrEmailAddress[0])) {
return false;
}
// Check domain portion
if (!$this->check_domain_portion($arrEmailAddress[1])) {
return false;
}
// If we're still here, all checks above passed. Email is valid.
return true;
}
/**
* Checks email section before "@" symbol for validity
* @param string $strLocalPortion Text to be checked
* @return bool True if local portion is valid, false if not
*/
protected function check_local_portion($strLocalPortion) {
// Local portion can only be from 1 to 64 characters, inclusive.
// Please note that servers are encouraged to accept longer local
// parts than 64 characters.
if (!$this->check_text_length($strLocalPortion, 1, 64)) {
return false;
}
// Local portion must be:
// 1) a dot-atom (strings separated by periods)
// 2) a quoted string
// 3) an obsolete format string (combination of the above)
$arrLocalPortion = explode('.', $strLocalPortion);
for ($i = 0, $max = sizeof($arrLocalPortion); $i < $max; $i++) {
if (!preg_match('.^('
. '([A-Za-z0-9!#$%&\'*+/=?^_`{|}~-]'
. '[A-Za-z0-9!#$%&\'*+/=?^_`{|}~-]{0,63})'
.'|'
. '("[^\\\"]{0,62}")'
.')$.'
,$arrLocalPortion[$i])) {
return false;
}
}
return true;
}
/**
* Checks email section after "@" symbol for validity
* @param string $strDomainPortion Text to be checked
* @return bool True if domain portion is valid, false if not
*/
protected function check_domain_portion($strDomainPortion) {
// Total domain can only be from 1 to 255 characters, inclusive
if (!$this->check_text_length($strDomainPortion, 1, 255)) {
return false;
}
// some IPv4/v6 regexps borrowed from Feyd
// see: http://forums.devnetwork.net/viewtopic.php?f=38&t=53479
$dec_octet = '(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|[0-9])';
$hex_digit = '[A-Fa-f0-9]';
$h16 = "{$hex_digit}{1,4}";
$IPv4Address = "$dec_octet\\.$dec_octet\\.$dec_octet\\.$dec_octet";
$ls32 = "(?:$h16:$h16|$IPv4Address)";
$IPv6Address =
"(?:(?:{$IPv4Address})|(?:".
"(?:$h16:){6}$ls32" .
"|::(?:$h16:){5}$ls32" .
"|(?:$h16)?::(?:$h16:){4}$ls32" .
"|(?:(?:$h16:){0,1}$h16)?::(?:$h16:){3}$ls32" .
"|(?:(?:$h16:){0,2}$h16)?::(?:$h16:){2}$ls32" .
"|(?:(?:$h16:){0,3}$h16)?::(?:$h16:){1}$ls32" .
"|(?:(?:$h16:){0,4}$h16)?::$ls32" .
"|(?:(?:$h16:){0,5}$h16)?::$h16" .
"|(?:(?:$h16:){0,6}$h16)?::" .
")(?:\\/(?:12[0-8]|1[0-1][0-9]|[1-9][0-9]|[0-9]))?)";
// Check if domain is IP, possibly enclosed in square brackets.
if (preg_match("/^($IPv4Address|\[$IPv4Address\]|\[$IPv6Address\])$/",
$strDomainPortion)){
return true;
} else {
$arrDomainPortion = explode('.', $strDomainPortion);
if (!$this->allowLocalAddresses && sizeof($arrDomainPortion) < 2) {
return false; // Not enough parts to domain
}
for ($i = 0, $max = sizeof($arrDomainPortion); $i < $max; $i++) {
// Each portion must be between 1 and 63 characters, inclusive
if (!$this->check_text_length($arrDomainPortion[$i], 1, 63)) {
return false;
}
if (!preg_match('/^(([A-Za-z0-9][A-Za-z0-9-]{0,61}[A-Za-z0-9])|'
.'([A-Za-z0-9]+))$/', $arrDomainPortion[$i])) {
return false;
}
if ($i == $max - 1) { // TLD cannot be only numbers
if (strlen(preg_replace('/[0-9]/', '', $arrDomainPortion[$i])) <= 0) {
return false;
}
}
}
}
return true;
}
/**
* Check given text length is between defined bounds
* @param string $strText Text to be checked
* @param int $intMinimum Minimum acceptable length
* @param int $intMaximum Maximum acceptable length
* @return bool True if string is within bounds (inclusive), false if not
*/
protected function check_text_length($strText, $intMinimum, $intMaximum) {
// Minimum and maximum are both inclusive
$intTextLength = strlen($strText);
if (($intTextLength < $intMinimum) || ($intTextLength > $intMaximum)) {
return false;
} else {
return true;
}
}
}

View file

@ -1,76 +0,0 @@
<?php
/**
* Class used to parse RSS and ATOM feeds
*
* @author Andreas Gohr <andi@splitbrain.org>
*/
if(!defined('DOKU_INC')) die('meh.');
/**
* We override some methods of the original SimplePie class here
*/
class FeedParser extends SimplePie {
/**
* Constructor. Set some defaults
*/
function __construct(){
parent::__construct();
$this->enable_cache(false);
$this->set_file_class('FeedParser_File');
}
/**
* Backward compatibility for older plugins
*/
function feed_url($url){
$this->set_feed_url($url);
}
}
/**
* Fetch an URL using our own HTTPClient
*
* Replaces SimplePie's own class
*/
class FeedParser_File extends SimplePie_File {
var $http;
var $useragent;
var $success = true;
var $headers = array();
var $body;
var $error;
/**
* Inititializes the HTTPClient
*
* We ignore all given parameters - they are set in DokuHTTPClient
*/
function __construct($url, $timeout=10, $redirects=5,
$headers=null, $useragent=null, $force_fsockopen=false) {
$this->http = new DokuHTTPClient();
$this->success = $this->http->sendRequest($url);
$this->headers = $this->http->resp_headers;
$this->body = $this->http->resp_body;
$this->error = $this->http->error;
$this->method = SIMPLEPIE_FILE_SOURCE_REMOTE | SIMPLEPIE_FILE_SOURCE_FSOCKOPEN;
return $this->success;
}
function headers(){
return $this->headers;
}
function body(){
return $this->body;
}
function close(){
return true;
}
}

View file

@ -1,34 +0,0 @@
<?php
namespace dokuwiki\Form;
/**
* Class ButtonElement
*
* Represents a simple button
*
* @package dokuwiki\Form
*/
class ButtonElement extends Element {
/** @var string HTML content */
protected $content = '';
/**
* @param string $name
* @param string $content HTML content of the button. You have to escape it yourself.
*/
function __construct($name, $content = '') {
parent::__construct('button', array('name' => $name, 'value' => 1));
$this->content = $content;
}
/**
* The HTML representation of this element
*
* @return string
*/
public function toHTML() {
return '<button ' . buildAttributes($this->attrs()) . '>'.$this->content.'</button>';
}
}

View file

@ -1,62 +0,0 @@
<?php
namespace dokuwiki\Form;
/**
* Class CheckableElement
*
* For Radio- and Checkboxes
*
* @package dokuwiki\Form
*/
class CheckableElement extends InputElement {
/**
* @param string $type The type of this element
* @param string $name The name of this form element
* @param string $label The label text for this element
*/
public function __construct($type, $name, $label) {
parent::__construct($type, $name, $label);
// default value is 1
$this->attr('value', 1);
}
/**
* Handles the useInput flag and sets the checked attribute accordingly
*/
protected function prefillInput() {
global $INPUT;
list($name, $key) = $this->getInputName();
$myvalue = $this->val();
if(!$INPUT->has($name)) return;
if($key === null) {
// no key - single value
$value = $INPUT->str($name);
if($value == $myvalue) {
$this->attr('checked', 'checked');
} else {
$this->rmattr('checked');
}
} else {
// we have an array, there might be several values in it
$input = $INPUT->arr($name);
if(isset($input[$key])) {
$this->rmattr('checked');
// values seem to be in another sub array
if(is_array($input[$key])) {
$input = $input[$key];
}
foreach($input as $value) {
if($value == $myvalue) {
$this->attr('checked', 'checked');
}
}
}
}
}
}

View file

@ -1,128 +0,0 @@
<?php
namespace dokuwiki\Form;
/**
* Class DropdownElement
*
* Represents a HTML select. Please note that this does not support multiple selected options!
*
* @package dokuwiki\Form
*/
class DropdownElement extends InputElement {
protected $options = array();
protected $value = '';
/**
* @param string $name The name of this form element
* @param string $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);
}
/**
* Get or set the options of the Dropdown
*
* 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_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;
}
}
$this->val(''); // set default value (empty or first)
return $this;
}
/**
* Gets or sets an attribute
*
* When no $value is given, the current content of the attribute is returned.
* An empty string is returned for unset attributes.
*
* When a $value is given, the content is set to that value and the Element
* itself is returned for easy chaining
*
* @param string $name Name of the attribute to access
* @param null|string $value New value to set
* @return string|$this
*/
public function attr($name, $value = null) {
if(strtolower($name) == 'multiple') {
throw new \InvalidArgumentException('Sorry, the dropdown element does not support the "multiple" attribute');
}
return parent::attr($name, $value);
}
/**
* Get or set the current value
*
* When setting a value that is not defined in the options, the value is ignored
* and the first option's value is selected instead
*
* @param null|string $value The value to set
* @return $this|string
*/
public function val($value = null) {
if($value === null) return $this->value;
if(isset($this->options[$value])) {
$this->value = $value;
} else {
// unknown value set, select first option instead
$keys = array_keys($this->options);
$this->value = (string) array_shift($keys);
}
return $this;
}
/**
* Create the HTML for the select it self
*
* @return string
*/
protected function mainElementHTML() {
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 .= '</select>';
return $html;
}
}

View file

@ -1,151 +0,0 @@
<?php
namespace dokuwiki\Form;
/**
* Class Element
*
* The basic building block of a form
*
* @package dokuwiki\Form
*/
abstract class Element {
/**
* @var array the attributes of this element
*/
protected $attributes = array();
/**
* @var string The type of this element
*/
protected $type;
/**
* @param string $type The type of this element
* @param array $attributes
*/
public function __construct($type, $attributes = array()) {
$this->type = $type;
$this->attributes = $attributes;
}
/**
* Type of this element
*
* @return string
*/
public function getType() {
return $this->type;
}
/**
* Gets or sets an attribute
*
* When no $value is given, the current content of the attribute is returned.
* An empty string is returned for unset attributes.
*
* When a $value is given, the content is set to that value and the Element
* itself is returned for easy chaining
*
* @param string $name Name of the attribute to access
* @param null|string $value New value to set
* @return string|$this
*/
public function attr($name, $value = null) {
// set
if($value !== null) {
$this->attributes[$name] = $value;
return $this;
}
// get
if(isset($this->attributes[$name])) {
return $this->attributes[$name];
} else {
return '';
}
}
/**
* Removes the given attribute if it exists
*
* @param string $name
* @return $this
*/
public function rmattr($name) {
if(isset($this->attributes[$name])) {
unset($this->attributes[$name]);
}
return $this;
}
/**
* Gets or adds a all given attributes at once
*
* @param array|null $attributes
* @return array|$this
*/
public function attrs($attributes = null) {
// set
if($attributes) {
foreach((array) $attributes as $key => $val) {
$this->attr($key, $val);
}
return $this;
}
// get
return $this->attributes;
}
/**
* Adds a class to the class attribute
*
* This is the preferred method of setting the element's class
*
* @param string $class the new class to add
* @return $this
*/
public function addClass($class) {
$classes = explode(' ', $this->attr('class'));
$classes[] = $class;
$classes = array_unique($classes);
$classes = array_filter($classes);
$this->attr('class', join(' ', $classes));
return $this;
}
/**
* Get or set the element's ID
*
* This is the preferred way of setting the element's ID
*
* @param null|string $id
* @return string|$this
*/
public function id($id = null) {
if(strpos($id, '__') === false) {
throw new \InvalidArgumentException('IDs in DokuWiki have to contain two subsequent underscores');
}
return $this->attr('id', $id);
}
/**
* Get or set the element's value
*
* This is the preferred way of setting the element's value
*
* @param null|string $value
* @return string|$this
*/
public function val($value = null) {
return $this->attr('value', $value);
}
/**
* The HTML representation of this element
*
* @return string
*/
abstract public function toHTML();
}

View file

@ -1,30 +0,0 @@
<?php
namespace dokuwiki\Form;
/**
* Class FieldsetCloseElement
*
* Closes an open Fieldset
*
* @package dokuwiki\Form
*/
class FieldsetCloseElement extends TagCloseElement {
/**
* @param array $attributes
*/
public function __construct($attributes = array()) {
parent::__construct('', $attributes);
$this->type = 'fieldsetclose';
}
/**
* The HTML representation of this element
*
* @return string
*/
public function toHTML() {
return '</fieldset>';
}
}

View file

@ -1,36 +0,0 @@
<?php
namespace dokuwiki\Form;
/**
* Class FieldsetOpenElement
*
* Opens a Fieldset with an optional legend
*
* @package dokuwiki\Form
*/
class FieldsetOpenElement extends TagOpenElement {
/**
* @param string $legend
* @param array $attributes
*/
public function __construct($legend='', $attributes = array()) {
// this is a bit messy and we just do it for the nicer class hierarchy
// the parent would expect the tag in $value but we're storing the
// legend there, so we have to set the type manually
parent::__construct($legend, $attributes);
$this->type = 'fieldsetopen';
}
/**
* The HTML representation of this element
*
* @return string
*/
public function toHTML() {
$html = '<fieldset '.buildAttributes($this->attrs()).'>';
$legend = $this->val();
if($legend) $html .= DOKU_LF.'<legend>'.hsc($legend).'</legend>';
return $html;
}
}

View file

@ -1,439 +0,0 @@
<?php
namespace dokuwiki\Form;
/**
* Class Form
*
* Represents the whole Form. This is what you work on, and add Elements to
*
* @package dokuwiki\Form
*/
class Form extends Element {
/**
* @var array name value pairs for hidden values
*/
protected $hidden = array();
/**
* @var Element[] the elements of the form
*/
protected $elements = array();
/**
* Creates a new, empty form with some default attributes
*
* @param array $attributes
*/
public function __construct($attributes = array()) {
global $ID;
parent::__construct('form', $attributes);
// use the current URL as default action
if(!$this->attr('action')) {
$get = $_GET;
if(isset($get['id'])) unset($get['id']);
$self = wl($ID, $get, false, '&'); //attributes are escaped later
$this->attr('action', $self);
}
// post is default
if(!$this->attr('method')) {
$this->attr('method', 'post');
}
// we like UTF-8
if(!$this->attr('accept-charset')) {
$this->attr('accept-charset', 'utf-8');
}
// add the security token by default
$this->setHiddenField('sectok', getSecurityToken());
// identify this as a new form based form in HTML
$this->addClass('doku_form');
}
/**
* Sets a hidden field
*
* @param string $name
* @param string $value
* @return $this
*/
public function setHiddenField($name, $value) {
$this->hidden[$name] = $value;
return $this;
}
#region element query function
/**
* Returns the numbers of elements in the form
*
* @return int
*/
public function elementCount() {
return count($this->elements);
}
/**
* Returns a reference to the element at a position.
* A position out-of-bounds will return either the
* first (underflow) or last (overflow) element.
*
* @param int $pos
* @return Element
*/
public function getElementAt($pos) {
if($pos < 0) $pos = count($this->elements) + $pos;
if($pos < 0) $pos = 0;
if($pos >= count($this->elements)) $pos = count($this->elements) - 1;
return $this->elements[$pos];
}
/**
* Gets the position of the first of a type of element
*
* @param string $type Element type to look for.
* @param int $offset search from this position onward
* @return false|int position of element if found, otherwise false
*/
public function findPositionByType($type, $offset = 0) {
$len = $this->elementCount();
for($pos = $offset; $pos < $len; $pos++) {
if($this->elements[$pos]->getType() == $type) {
return $pos;
}
}
return false;
}
/**
* Gets the position of the first element matching the attribute
*
* @param string $name Name of the attribute
* @param string $value Value the attribute should have
* @param int $offset search from this position onward
* @return false|int position of element if found, otherwise false
*/
public function findPositionByAttribute($name, $value, $offset = 0) {
$len = $this->elementCount();
for($pos = $offset; $pos < $len; $pos++) {
if($this->elements[$pos]->attr($name) == $value) {
return $pos;
}
}
return false;
}
#endregion
#region Element positioning functions
/**
* Adds or inserts an element to the form
*
* @param Element $element
* @param int $pos 0-based position in the form, -1 for at the end
* @return Element
*/
public function addElement(Element $element, $pos = -1) {
if(is_a($element, '\dokuwiki\Form\Form')) throw new \InvalidArgumentException('You can\'t add a form to a form');
if($pos < 0) {
$this->elements[] = $element;
} else {
array_splice($this->elements, $pos, 0, array($element));
}
return $element;
}
/**
* Replaces an existing element with a new one
*
* @param Element $element the new element
* @param int $pos 0-based position of the element to replace
*/
public function replaceElement(Element $element, $pos) {
if(is_a($element, '\dokuwiki\Form\Form')) throw new \InvalidArgumentException('You can\'t add a form to a form');
array_splice($this->elements, $pos, 1, array($element));
}
/**
* Remove an element from the form completely
*
* @param int $pos 0-based position of the element to remove
*/
public function removeElement($pos) {
array_splice($this->elements, $pos, 1);
}
#endregion
#region Element adding functions
/**
* Adds a text input field
*
* @param string $name
* @param string $label
* @param int $pos
* @return InputElement
*/
public function addTextInput($name, $label = '', $pos = -1) {
return $this->addElement(new InputElement('text', $name, $label), $pos);
}
/**
* Adds a password input field
*
* @param string $name
* @param string $label
* @param int $pos
* @return InputElement
*/
public function addPasswordInput($name, $label = '', $pos = -1) {
return $this->addElement(new InputElement('password', $name, $label), $pos);
}
/**
* Adds a radio button field
*
* @param string $name
* @param string $label
* @param int $pos
* @return CheckableElement
*/
public function addRadioButton($name, $label = '', $pos = -1) {
return $this->addElement(new CheckableElement('radio', $name, $label), $pos);
}
/**
* Adds a checkbox field
*
* @param string $name
* @param string $label
* @param int $pos
* @return CheckableElement
*/
public function addCheckbox($name, $label = '', $pos = -1) {
return $this->addElement(new CheckableElement('checkbox', $name, $label), $pos);
}
/**
* Adds a dropdown field
*
* @param string $name
* @param array $options
* @param string $label
* @param int $pos
* @return DropdownElement
*/
public function addDropdown($name, $options, $label = '', $pos = -1) {
return $this->addElement(new DropdownElement($name, $options, $label), $pos);
}
/**
* Adds a textarea field
*
* @param string $name
* @param string $label
* @param int $pos
* @return TextareaElement
*/
public function addTextarea($name, $label = '', $pos = -1) {
return $this->addElement(new TextareaElement($name, $label), $pos);
}
/**
* Adds a simple button, escapes the content for you
*
* @param string $name
* @param string $content
* @param int $pos
* @return Element
*/
public function addButton($name, $content, $pos = -1) {
return $this->addElement(new ButtonElement($name, hsc($content)), $pos);
}
/**
* Adds a simple button, allows HTML for content
*
* @param string $name
* @param string $html
* @param int $pos
* @return Element
*/
public function addButtonHTML($name, $html, $pos = -1) {
return $this->addElement(new ButtonElement($name, $html), $pos);
}
/**
* Adds a label referencing another input element, escapes the label for you
*
* @param string $label
* @param string $for
* @param int $pos
* @return Element
*/
public function addLabel($label, $for='', $pos = -1) {
return $this->addLabelHTML(hsc($label), $for, $pos);
}
/**
* Adds a label referencing another input element, allows HTML for content
*
* @param string $content
* @param string|Element $for
* @param int $pos
* @return Element
*/
public function addLabelHTML($content, $for='', $pos = -1) {
$element = new LabelElement(hsc($content));
if(is_a($for, '\dokuwiki\Form\Element')) {
/** @var Element $for */
$for = $for->id();
}
$for = (string) $for;
if($for !== '') {
$element->attr('for', $for);
}
return $this->addElement($element, $pos);
}
/**
* Add fixed HTML to the form
*
* @param string $html
* @param int $pos
* @return HTMLElement
*/
public function addHTML($html, $pos = -1) {
return $this->addElement(new HTMLElement($html), $pos);
}
/**
* Add a closed HTML tag to the form
*
* @param string $tag
* @param int $pos
* @return TagElement
*/
public function addTag($tag, $pos = -1) {
return $this->addElement(new TagElement($tag), $pos);
}
/**
* Add an open HTML tag to the form
*
* Be sure to close it again!
*
* @param string $tag
* @param int $pos
* @return TagOpenElement
*/
public function addTagOpen($tag, $pos = -1) {
return $this->addElement(new TagOpenElement($tag), $pos);
}
/**
* Add a closing HTML tag to the form
*
* Be sure it had been opened before
*
* @param string $tag
* @param int $pos
* @return TagCloseElement
*/
public function addTagClose($tag, $pos = -1) {
return $this->addElement(new TagCloseElement($tag), $pos);
}
/**
* Open a Fieldset
*
* @param string $legend
* @param int $pos
* @return FieldsetOpenElement
*/
public function addFieldsetOpen($legend = '', $pos = -1) {
return $this->addElement(new FieldsetOpenElement($legend), $pos);
}
/**
* Close a fieldset
*
* @param int $pos
* @return TagCloseElement
*/
public function addFieldsetClose($pos = -1) {
return $this->addElement(new FieldsetCloseElement(), $pos);
}
#endregion
/**
* Adjust the elements so that fieldset open and closes are matching
*/
protected function balanceFieldsets() {
$lastclose = 0;
$isopen = false;
$len = count($this->elements);
for($pos = 0; $pos < $len; $pos++) {
$type = $this->elements[$pos]->getType();
if($type == 'fieldsetopen') {
if($isopen) {
//close previous fieldset
$this->addFieldsetClose($pos);
$lastclose = $pos + 1;
$pos++;
$len++;
}
$isopen = true;
} else if($type == 'fieldsetclose') {
if(!$isopen) {
// make sure there was a fieldsetopen
// either right after the last close or at the begining
$this->addFieldsetOpen('', $lastclose);
$len++;
$pos++;
}
$lastclose = $pos;
$isopen = false;
}
}
// close open fieldset at the end
if($isopen) {
$this->addFieldsetClose();
}
}
/**
* The HTML representation of the whole form
*
* @return string
*/
public function toHTML() {
$this->balanceFieldsets();
$html = '<form ' . buildAttributes($this->attrs()) . '>';
foreach($this->hidden as $name => $value) {
$html .= '<input type="hidden" name="' . $name . '" value="' . formText($value) . '" />';
}
foreach($this->elements as $element) {
$html .= $element->toHTML();
}
$html .= '</form>';
return $html;
}
}

View file

@ -1,29 +0,0 @@
<?php
namespace dokuwiki\Form;
/**
* Class HTMLElement
*
* Holds arbitrary HTML that is added as is to the Form
*
* @package dokuwiki\Form
*/
class HTMLElement extends ValueElement {
/**
* @param string $html
*/
public function __construct($html) {
parent::__construct('html', $html);
}
/**
* The HTML representation of this element
*
* @return string
*/
public function toHTML() {
return $this->val();
}
}

View file

@ -1,159 +0,0 @@
<?php
namespace dokuwiki\Form;
/**
* Class InputElement
*
* Base class for all input elements. Uses a wrapping label when label
* text is given.
*
* @todo figure out how to make wrapping or related label configurable
* @package dokuwiki\Form
*/
class InputElement extends Element {
/**
* @var LabelElement
*/
protected $label = null;
/**
* @var bool if the element should reflect posted values
*/
protected $useInput = true;
/**
* @param string $type The type of this element
* @param string $name The name of this form element
* @param string $label The label text for this element (will be autoescaped)
*/
public function __construct($type, $name, $label = '') {
parent::__construct($type, array('name' => $name));
$this->attr('name', $name);
$this->attr('type', $type);
if($label) $this->label = new LabelElement($label);
}
/**
* Returns the label element if there's one set
*
* @return LabelElement|null
*/
public function getLabel() {
return $this->label;
}
/**
* Should the user sent input be used to initialize the input field
*
* The default is true. Any set values will be overwritten by the INPUT
* provided values.
*
* @param bool $useinput
* @return $this
*/
public function useInput($useinput) {
$this->useInput = (bool) $useinput;
return $this;
}
/**
* Get or set the element's ID
*
* @param null|string $id
* @return string|$this
*/
public function id($id = null) {
if($this->label) $this->label->attr('for', $id);
return parent::id($id);
}
/**
* Adds a class to the class attribute
*
* This is the preferred method of setting the element's class
*
* @param string $class the new class to add
* @return $this
*/
public function addClass($class) {
if($this->label) $this->label->addClass($class);
return parent::addClass($class);
}
/**
* Figures out how to access the value for this field from INPUT data
*
* The element's name could have been given as a simple string ('foo')
* or in array notation ('foo[bar]').
*
* Note: this function only handles one level of arrays. If your data
* is nested deeper, you should call useInput(false) and set the
* correct value yourself
*
* @return array name and array key (null if not an array)
*/
protected function getInputName() {
$name = $this->attr('name');
parse_str("$name=1", $parsed);
$name = array_keys($parsed);
$name = array_shift($name);
if(is_array($parsed[$name])) {
$key = array_keys($parsed[$name]);
$key = array_shift($key);
} else {
$key = null;
}
return array($name, $key);
}
/**
* Handles the useInput flag and set the value attribute accordingly
*/
protected function prefillInput() {
global $INPUT;
list($name, $key) = $this->getInputName();
if(!$INPUT->has($name)) return;
if($key === null) {
$value = $INPUT->str($name);
} else {
$value = $INPUT->arr($name);
if(isset($value[$key])) {
$value = $value[$key];
} else {
$value = '';
}
}
$this->val($value);
}
/**
* The HTML representation of this element
*
* @return string
*/
protected function mainElementHTML() {
if($this->useInput) $this->prefillInput();
return '<input ' . buildAttributes($this->attrs()) . ' />';
}
/**
* The HTML representation of this element wrapped in a label
*
* @return string
*/
public function toHTML() {
if($this->label) {
return '<label ' . buildAttributes($this->label->attrs()) . '>' . DOKU_LF .
'<span>' . hsc($this->label->val()) . '</span>' . DOKU_LF .
$this->mainElementHTML() . DOKU_LF .
'</label>';
} else {
return $this->mainElementHTML();
}
}
}

View file

@ -1,27 +0,0 @@
<?php
namespace dokuwiki\Form;
/**
* Class Label
* @package dokuwiki\Form
*/
class LabelElement extends ValueElement {
/**
* Creates a new Label
*
* @param string $label This is is raw HTML and will not be escaped
*/
public function __construct($label) {
parent::__construct('label', $label);
}
/**
* The HTML representation of this element
*
* @return string
*/
public function toHTML() {
return '<label ' . buildAttributes($this->attrs()) . '>' . $this->val() . '</label>';
}
}

View file

@ -1,181 +0,0 @@
<?php
namespace dokuwiki\Form;
/**
* Class LegacyForm
*
* Provides a compatibility layer to the old Doku_Form API
*
* This can be used to work with the modern API on forms provided by old events for
* example. When you start new forms, just use Form\Form
*
* @package dokuwiki\Form
*/
class LegacyForm extends Form {
/**
* Creates a new modern form from an old legacy Doku_Form
*
* @param \Doku_Form $oldform
*/
public function __construct(\Doku_Form $oldform) {
parent::__construct($oldform->params);
$this->hidden = $oldform->_hidden;
foreach($oldform->_content as $element) {
list($ctl, $attr) = $this->parseLegacyAttr($element);
if(is_array($element)) {
switch($ctl['elem']) {
case 'wikitext':
$this->addTextarea('wikitext')
->attrs($attr)
->id('wiki__text')
->val($ctl['text'])
->addClass($ctl['class']);
break;
case 'textfield':
$this->addTextInput($ctl['name'], $ctl['text'])
->attrs($attr)
->id($ctl['id'])
->addClass($ctl['class']);
break;
case 'passwordfield':
$this->addPasswordInput($ctl['name'], $ctl['text'])
->attrs($attr)
->id($ctl['id'])
->addClass($ctl['class']);
break;
case 'checkboxfield':
$this->addCheckbox($ctl['name'], $ctl['text'])
->attrs($attr)
->id($ctl['id'])
->addClass($ctl['class']);
break;
case 'radiofield':
$this->addRadioButton($ctl['name'], $ctl['text'])
->attrs($attr)
->id($ctl['id'])
->addClass($ctl['class']);
break;
case 'tag':
$this->addTag($ctl['tag'])
->attrs($attr)
->attr('name', $ctl['name'])
->id($ctl['id'])
->addClass($ctl['class']);
break;
case 'opentag':
$this->addTagOpen($ctl['tag'])
->attrs($attr)
->attr('name', $ctl['name'])
->id($ctl['id'])
->addClass($ctl['class']);
break;
case 'closetag':
$this->addTagClose($ctl['tag']);
break;
case 'openfieldset':
$this->addFieldsetOpen($ctl['legend'])
->attrs($attr)
->attr('name', $ctl['name'])
->id($ctl['id'])
->addClass($ctl['class']);
break;
case 'closefieldset':
$this->addFieldsetClose();
break;
case 'button':
case 'field':
case 'fieldright':
case 'filefield':
case 'menufield':
case 'listboxfield':
throw new \UnexpectedValueException('Unsupported legacy field ' . $ctl['elem']);
break;
default:
throw new \UnexpectedValueException('Unknown legacy field ' . $ctl['elem']);
}
} else {
$this->addHTML($element);
}
}
}
/**
* Parses out what is the elements attributes and what is control info
*
* @param array $legacy
* @return array
*/
protected function parseLegacyAttr($legacy) {
$attributes = array();
$control = array();
foreach($legacy as $key => $val) {
if($key{0} == '_') {
$control[substr($key, 1)] = $val;
} elseif($key == 'name') {
$control[$key] = $val;
} elseif($key == 'id') {
$control[$key] = $val;
} else {
$attributes[$key] = $val;
}
}
return array($control, $attributes);
}
/**
* Translates our types to the legacy types
*
* @param string $type
* @return string
*/
protected function legacyType($type) {
static $types = array(
'text' => 'textfield',
'password' => 'passwordfield',
'checkbox' => 'checkboxfield',
'radio' => 'radiofield',
'tagopen' => 'opentag',
'tagclose' => 'closetag',
'fieldsetopen' => 'openfieldset',
'fieldsetclose' => 'closefieldset',
);
if(isset($types[$type])) return $types[$type];
return $type;
}
/**
* Creates an old legacy form from this modern form's data
*
* @return \Doku_Form
*/
public function toLegacy() {
$this->balanceFieldsets();
$legacy = new \Doku_Form($this->attrs());
$legacy->_hidden = $this->hidden;
foreach($this->elements as $element) {
if(is_a($element, 'dokuwiki\Form\HTMLElement')) {
$legacy->_content[] = $element->toHTML();
} elseif(is_a($element, 'dokuwiki\Form\InputElement')) {
/** @var InputElement $element */
$data = $element->attrs();
$data['_elem'] = $this->legacyType($element->getType());
$label = $element->getLabel();
if($label) {
$data['_class'] = $label->attr('class');
}
$legacy->_content[] = $data;
}
}
return $legacy;
}
}

View file

@ -1,88 +0,0 @@
<?php
namespace dokuwiki\Form;
/**
* Class TagCloseElement
*
* Creates an HTML close tag. You have to make sure it has been opened
* before or this will produce invalid HTML
*
* @package dokuwiki\Form
*/
class TagCloseElement extends ValueElement {
/**
* @param string $tag
* @param array $attributes
*/
public function __construct($tag, $attributes = array()) {
parent::__construct('tagclose', $tag, $attributes);
}
/**
* do not call this
*
* @param string $class
* @return void
* @throws \BadMethodCallException
*/
public function addClass($class) {
throw new \BadMethodCallException('You can\t add classes to closing tag');
}
/**
* do not call this
*
* @param null|string $id
* @return string
* @throws \BadMethodCallException
*/
public function id($id = null) {
if ($id === null) {
return '';
} else {
throw new \BadMethodCallException('You can\t add ID to closing tag');
}
}
/**
* do not call this
*
* @param string $name
* @param null|string $value
* @return string
* @throws \BadMethodCallException
*/
public function attr($name, $value = null) {
if ($value === null) {
return '';
} else {
throw new \BadMethodCallException('You can\t add attributes to closing tag');
}
}
/**
* do not call this
*
* @param array|null $attributes
* @return array
* @throws \BadMethodCallException
*/
public function attrs($attributes = null) {
if ($attributes === null) {
return array();
} else {
throw new \BadMethodCallException('You can\t add attributes to closing tag');
}
}
/**
* The HTML representation of this element
*
* @return string
*/
public function toHTML() {
return '</'.$this->val().'>';
}
}

View file

@ -1,29 +0,0 @@
<?php
namespace dokuwiki\Form;
/**
* Class TagElement
*
* Creates a self closing HTML tag
*
* @package dokuwiki\Form
*/
class TagElement extends ValueElement {
/**
* @param string $tag
* @param array $attributes
*/
public function __construct($tag, $attributes = array()) {
parent::__construct('tag', $tag, $attributes);
}
/**
* The HTML representation of this element
*
* @return string
*/
public function toHTML() {
return '<'.$this->val().' '.buildAttributes($this->attrs()).' />';
}
}

View file

@ -1,30 +0,0 @@
<?php
namespace dokuwiki\Form;
/**
* Class TagOpenElement
*
* Creates an open HTML tag. You have to make sure you close it
* again or this will produce invalid HTML
*
* @package dokuwiki\Form
*/
class TagOpenElement extends ValueElement {
/**
* @param string $tag
* @param array $attributes
*/
public function __construct($tag, $attributes = array()) {
parent::__construct('tagopen', $tag, $attributes);
}
/**
* The HTML representation of this element
*
* @return string
*/
public function toHTML() {
return '<'.$this->val().' '.buildAttributes($this->attrs()).'>';
}
}

View file

@ -1,51 +0,0 @@
<?php
namespace dokuwiki\Form;
/**
* Class TextareaElement
* @package dokuwiki\Form
*/
class TextareaElement extends InputElement {
/**
* @var string the actual text within the area
*/
protected $text;
/**
* @param string $name The name of this form element
* @param string $label The label text for this element
*/
public function __construct($name, $label) {
parent::__construct('textarea', $name, $label);
$this->attr('dir', 'auto');
}
/**
* Get or set the element's value
*
* This is the preferred way of setting the element's value
*
* @param null|string $value
* @return string|$this
*/
public function val($value = null) {
if($value !== null) {
$this->text = cleanText($value);
return $this;
}
return $this->text;
}
/**
* The HTML representation of this element
*
* @return string
*/
protected function mainElementHTML() {
if($this->useInput) $this->prefillInput();
return '<textarea ' . buildAttributes($this->attrs()) . '>' .
formText($this->val()) . '</textarea>';
}
}

View file

@ -1,45 +0,0 @@
<?php
namespace dokuwiki\Form;
/**
* Class ValueElement
*
* Just like an Element but it's value is not part of its attributes
*
* What the value is (tag name, content, etc) is defined by the actual implementations
*
* @package dokuwiki\Form
*/
abstract class ValueElement extends Element {
/**
* @var string holds the element's value
*/
protected $value = '';
/**
* @param string $type
* @param string $value
* @param array $attributes
*/
public function __construct($type, $value, $attributes = array()) {
parent::__construct($type, $attributes);
$this->val($value);
}
/**
* Get or set the element's value
*
* @param null|string $value
* @return string|$this
*/
public function val($value = null) {
if($value !== null) {
$this->value = $value;
return $this;
}
return $this->value;
}
}

View file

@ -1,933 +0,0 @@
<?php
/**
* HTTP Client
*
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
* @author Andreas Goetz <cpuidle@gmx.de>
*/
define('HTTP_NL',"\r\n");
/**
* Adds DokuWiki specific configs to the HTTP client
*
* @author Andreas Goetz <cpuidle@gmx.de>
*/
class DokuHTTPClient extends HTTPClient {
/**
* Constructor.
*
* @author Andreas Gohr <andi@splitbrain.org>
*/
function __construct(){
global $conf;
// call parent constructor
parent::__construct();
// set some values from the config
$this->proxy_host = $conf['proxy']['host'];
$this->proxy_port = $conf['proxy']['port'];
$this->proxy_user = $conf['proxy']['user'];
$this->proxy_pass = conf_decodeString($conf['proxy']['pass']);
$this->proxy_ssl = $conf['proxy']['ssl'];
$this->proxy_except = $conf['proxy']['except'];
// allow enabling debugging via URL parameter (if debugging allowed)
if($conf['allowdebug']) {
if(
isset($_REQUEST['httpdebug']) ||
(
isset($_SERVER['HTTP_REFERER']) &&
strpos($_SERVER['HTTP_REFERER'], 'httpdebug') !== false
)
) {
$this->debug = true;
}
}
}
/**
* Wraps an event around the parent function
*
* @triggers HTTPCLIENT_REQUEST_SEND
* @author Andreas Gohr <andi@splitbrain.org>
*/
/**
* @param string $url
* @param string|array $data the post data either as array or raw data
* @param string $method
* @return bool
*/
function sendRequest($url,$data='',$method='GET'){
$httpdata = array('url' => $url,
'data' => $data,
'method' => $method);
$evt = new Doku_Event('HTTPCLIENT_REQUEST_SEND',$httpdata);
if($evt->advise_before()){
$url = $httpdata['url'];
$data = $httpdata['data'];
$method = $httpdata['method'];
}
$evt->advise_after();
unset($evt);
return parent::sendRequest($url,$data,$method);
}
}
/**
* Class HTTPClientException
*/
class HTTPClientException extends Exception { }
/**
* This class implements a basic HTTP client
*
* It supports POST and GET, Proxy usage, basic authentication,
* handles cookies and referers. It is based upon the httpclient
* function from the VideoDB project.
*
* @link http://www.splitbrain.org/go/videodb
* @author Andreas Goetz <cpuidle@gmx.de>
* @author Andreas Gohr <andi@splitbrain.org>
* @author Tobias Sarnowski <sarnowski@new-thoughts.org>
*/
class HTTPClient {
//set these if you like
var $agent; // User agent
var $http; // HTTP version defaults to 1.0
var $timeout; // read timeout (seconds)
var $cookies;
var $referer;
var $max_redirect;
var $max_bodysize;
var $max_bodysize_abort = true; // if set, abort if the response body is bigger than max_bodysize
var $header_regexp; // if set this RE must match against the headers, else abort
var $headers;
var $debug;
var $start = 0.0; // for timings
var $keep_alive = true; // keep alive rocks
// don't set these, read on error
var $error;
var $redirect_count;
// read these after a successful request
var $status;
var $resp_body;
var $resp_headers;
// set these to do basic authentication
var $user;
var $pass;
// set these if you need to use a proxy
var $proxy_host;
var $proxy_port;
var $proxy_user;
var $proxy_pass;
var $proxy_ssl; //boolean set to true if your proxy needs SSL
var $proxy_except; // regexp of URLs to exclude from proxy
// list of kept alive connections
static $connections = array();
// what we use as boundary on multipart/form-data posts
var $boundary = '---DokuWikiHTTPClient--4523452351';
/**
* Constructor.
*
* @author Andreas Gohr <andi@splitbrain.org>
*/
function __construct(){
$this->agent = 'Mozilla/4.0 (compatible; DokuWiki HTTP Client; '.PHP_OS.')';
$this->timeout = 15;
$this->cookies = array();
$this->referer = '';
$this->max_redirect = 3;
$this->redirect_count = 0;
$this->status = 0;
$this->headers = array();
$this->http = '1.0';
$this->debug = false;
$this->max_bodysize = 0;
$this->header_regexp= '';
if(extension_loaded('zlib')) $this->headers['Accept-encoding'] = 'gzip';
$this->headers['Accept'] = 'text/xml,application/xml,application/xhtml+xml,'.
'text/html,text/plain,image/png,image/jpeg,image/gif,*/*';
$this->headers['Accept-Language'] = 'en-us';
}
/**
* Simple function to do a GET request
*
* Returns the wanted page or false on an error;
*
* @param string $url The URL to fetch
* @param bool $sloppy304 Return body on 304 not modified
* @return false|string response body, false on error
*
* @author Andreas Gohr <andi@splitbrain.org>
*/
function get($url,$sloppy304=false){
if(!$this->sendRequest($url)) return false;
if($this->status == 304 && $sloppy304) return $this->resp_body;
if($this->status < 200 || $this->status > 206) return false;
return $this->resp_body;
}
/**
* Simple function to do a GET request with given parameters
*
* Returns the wanted page or false on an error.
*
* This is a convenience wrapper around get(). The given parameters
* will be correctly encoded and added to the given base URL.
*
* @param string $url The URL to fetch
* @param array $data Associative array of parameters
* @param bool $sloppy304 Return body on 304 not modified
* @return false|string response body, false on error
*
* @author Andreas Gohr <andi@splitbrain.org>
*/
function dget($url,$data,$sloppy304=false){
if(strpos($url,'?')){
$url .= '&';
}else{
$url .= '?';
}
$url .= $this->_postEncode($data);
return $this->get($url,$sloppy304);
}
/**
* Simple function to do a POST request
*
* Returns the resulting page or false on an error;
*
* @param string $url The URL to fetch
* @param array $data Associative array of parameters
* @return false|string response body, false on error
* @author Andreas Gohr <andi@splitbrain.org>
*/
function post($url,$data){
if(!$this->sendRequest($url,$data,'POST')) return false;
if($this->status < 200 || $this->status > 206) return false;
return $this->resp_body;
}
/**
* Send an HTTP request
*
* This method handles the whole HTTP communication. It respects set proxy settings,
* builds the request headers, follows redirects and parses the response.
*
* Post data should be passed as associative array. When passed as string it will be
* sent as is. You will need to setup your own Content-Type header then.
*
* @param string $url - the complete URL
* @param mixed $data - the post data either as array or raw data
* @param string $method - HTTP Method usually GET or POST.
* @return bool - true on success
*
* @author Andreas Goetz <cpuidle@gmx.de>
* @author Andreas Gohr <andi@splitbrain.org>
*/
function sendRequest($url,$data='',$method='GET'){
$this->start = $this->_time();
$this->error = '';
$this->status = 0;
$this->status = 0;
$this->resp_body = '';
$this->resp_headers = array();
// don't accept gzip if truncated bodies might occur
if($this->max_bodysize &&
!$this->max_bodysize_abort &&
$this->headers['Accept-encoding'] == 'gzip'){
unset($this->headers['Accept-encoding']);
}
// parse URL into bits
$uri = parse_url($url);
$server = $uri['host'];
$path = $uri['path'];
if(empty($path)) $path = '/';
if(!empty($uri['query'])) $path .= '?'.$uri['query'];
if(!empty($uri['port'])) $port = $uri['port'];
if(isset($uri['user'])) $this->user = $uri['user'];
if(isset($uri['pass'])) $this->pass = $uri['pass'];
// proxy setup
if($this->proxy_host && (!$this->proxy_except || !preg_match('/'.$this->proxy_except.'/i',$url)) ){
$request_url = $url;
$server = $this->proxy_host;
$port = $this->proxy_port;
if (empty($port)) $port = 8080;
$use_tls = $this->proxy_ssl;
}else{
$request_url = $path;
if (!isset($port)) $port = ($uri['scheme'] == 'https') ? 443 : 80;
$use_tls = ($uri['scheme'] == 'https');
}
// add SSL stream prefix if needed - needs SSL support in PHP
if($use_tls) {
if(!in_array('ssl', stream_get_transports())) {
$this->status = -200;
$this->error = 'This PHP version does not support SSL - cannot connect to server';
}
$server = 'ssl://'.$server;
}
// prepare headers
$headers = $this->headers;
$headers['Host'] = $uri['host'];
if(!empty($uri['port'])) $headers['Host'].= ':'.$uri['port'];
$headers['User-Agent'] = $this->agent;
$headers['Referer'] = $this->referer;
if($method == 'POST'){
if(is_array($data)){
if($headers['Content-Type'] == 'multipart/form-data'){
$headers['Content-Type'] = 'multipart/form-data; boundary='.$this->boundary;
$data = $this->_postMultipartEncode($data);
}else{
$headers['Content-Type'] = 'application/x-www-form-urlencoded';
$data = $this->_postEncode($data);
}
}
$headers['Content-Length'] = strlen($data);
}elseif($method == 'GET'){
$data = ''; //no data allowed on GET requests
}
if($this->user) {
$headers['Authorization'] = 'Basic '.base64_encode($this->user.':'.$this->pass);
}
if($this->proxy_user) {
$headers['Proxy-Authorization'] = 'Basic '.base64_encode($this->proxy_user.':'.$this->proxy_pass);
}
// already connected?
$connectionId = $this->_uniqueConnectionId($server,$port);
$this->_debug('connection pool', self::$connections);
$socket = null;
if (isset(self::$connections[$connectionId])) {
$this->_debug('reusing connection', $connectionId);
$socket = self::$connections[$connectionId];
}
if (is_null($socket) || feof($socket)) {
$this->_debug('opening connection', $connectionId);
// open socket
$socket = @fsockopen($server,$port,$errno, $errstr, $this->timeout);
if (!$socket){
$this->status = -100;
$this->error = "Could not connect to $server:$port\n$errstr ($errno)";
return false;
}
// try establish a CONNECT tunnel for SSL
try {
if($this->_ssltunnel($socket, $request_url)){
// no keep alive for tunnels
$this->keep_alive = false;
// tunnel is authed already
if(isset($headers['Proxy-Authentication'])) unset($headers['Proxy-Authentication']);
}
} catch (HTTPClientException $e) {
$this->status = $e->getCode();
$this->error = $e->getMessage();
fclose($socket);
return false;
}
// keep alive?
if ($this->keep_alive) {
self::$connections[$connectionId] = $socket;
} else {
unset(self::$connections[$connectionId]);
}
}
if ($this->keep_alive && !$this->proxy_host) {
// RFC 2068, section 19.7.1: A client MUST NOT send the Keep-Alive
// connection token to a proxy server. We still do keep the connection the
// proxy alive (well except for CONNECT tunnels)
$headers['Connection'] = 'Keep-Alive';
} else {
$headers['Connection'] = 'Close';
}
try {
//set non-blocking
stream_set_blocking($socket, 0);
// build request
$request = "$method $request_url HTTP/".$this->http.HTTP_NL;
$request .= $this->_buildHeaders($headers);
$request .= $this->_getCookies();
$request .= HTTP_NL;
$request .= $data;
$this->_debug('request',$request);
$this->_sendData($socket, $request, 'request');
// read headers from socket
$r_headers = '';
do{
$r_line = $this->_readLine($socket, 'headers');
$r_headers .= $r_line;
}while($r_line != "\r\n" && $r_line != "\n");
$this->_debug('response headers',$r_headers);
// check if expected body size exceeds allowance
if($this->max_bodysize && preg_match('/\r?\nContent-Length:\s*(\d+)\r?\n/i',$r_headers,$match)){
if($match[1] > $this->max_bodysize){
if ($this->max_bodysize_abort)
throw new HTTPClientException('Reported content length exceeds allowed response size');
else
$this->error = 'Reported content length exceeds allowed response size';
}
}
// get Status
if (!preg_match('/^HTTP\/(\d\.\d)\s*(\d+).*?\n/', $r_headers, $m))
throw new HTTPClientException('Server returned bad answer '.$r_headers);
$this->status = $m[2];
// handle headers and cookies
$this->resp_headers = $this->_parseHeaders($r_headers);
if(isset($this->resp_headers['set-cookie'])){
foreach ((array) $this->resp_headers['set-cookie'] as $cookie){
list($cookie) = explode(';',$cookie,2);
list($key,$val) = explode('=',$cookie,2);
$key = trim($key);
if($val == 'deleted'){
if(isset($this->cookies[$key])){
unset($this->cookies[$key]);
}
}elseif($key){
$this->cookies[$key] = $val;
}
}
}
$this->_debug('Object headers',$this->resp_headers);
// check server status code to follow redirect
if($this->status == 301 || $this->status == 302 ){
if (empty($this->resp_headers['location'])){
throw new HTTPClientException('Redirect but no Location Header found');
}elseif($this->redirect_count == $this->max_redirect){
throw new HTTPClientException('Maximum number of redirects exceeded');
}else{
// close the connection because we don't handle content retrieval here
// that's the easiest way to clean up the connection
fclose($socket);
unset(self::$connections[$connectionId]);
$this->redirect_count++;
$this->referer = $url;
// handle non-RFC-compliant relative redirects
if (!preg_match('/^http/i', $this->resp_headers['location'])){
if($this->resp_headers['location'][0] != '/'){
$this->resp_headers['location'] = $uri['scheme'].'://'.$uri['host'].':'.$uri['port'].
dirname($uri['path']).'/'.$this->resp_headers['location'];
}else{
$this->resp_headers['location'] = $uri['scheme'].'://'.$uri['host'].':'.$uri['port'].
$this->resp_headers['location'];
}
}
// perform redirected request, always via GET (required by RFC)
return $this->sendRequest($this->resp_headers['location'],array(),'GET');
}
}
// check if headers are as expected
if($this->header_regexp && !preg_match($this->header_regexp,$r_headers))
throw new HTTPClientException('The received headers did not match the given regexp');
//read body (with chunked encoding if needed)
$r_body = '';
if((isset($this->resp_headers['transfer-encoding']) && $this->resp_headers['transfer-encoding'] == 'chunked')
|| (isset($this->resp_headers['transfer-coding']) && $this->resp_headers['transfer-coding'] == 'chunked')){
$abort = false;
do {
$chunk_size = '';
while (preg_match('/^[a-zA-Z0-9]?$/',$byte=$this->_readData($socket,1,'chunk'))){
// read chunksize until \r
$chunk_size .= $byte;
if (strlen($chunk_size) > 128) // set an abritrary limit on the size of chunks
throw new HTTPClientException('Allowed response size exceeded');
}
$this->_readLine($socket, 'chunk'); // readtrailing \n
$chunk_size = hexdec($chunk_size);
if($this->max_bodysize && $chunk_size+strlen($r_body) > $this->max_bodysize){
if ($this->max_bodysize_abort)
throw new HTTPClientException('Allowed response size exceeded');
$this->error = 'Allowed response size exceeded';
$chunk_size = $this->max_bodysize - strlen($r_body);
$abort = true;
}
if ($chunk_size > 0) {
$r_body .= $this->_readData($socket, $chunk_size, 'chunk');
$this->_readData($socket, 2, 'chunk'); // read trailing \r\n
}
} while ($chunk_size && !$abort);
}elseif(isset($this->resp_headers['content-length']) && !isset($this->resp_headers['transfer-encoding'])){
/* RFC 2616
* If a message is received with both a Transfer-Encoding header field and a Content-Length
* header field, the latter MUST be ignored.
*/
// read up to the content-length or max_bodysize
// for keep alive we need to read the whole message to clean up the socket for the next read
if(!$this->keep_alive && $this->max_bodysize && $this->max_bodysize < $this->resp_headers['content-length']){
$length = $this->max_bodysize;
}else{
$length = $this->resp_headers['content-length'];
}
$r_body = $this->_readData($socket, $length, 'response (content-length limited)', true);
}elseif( !isset($this->resp_headers['transfer-encoding']) && $this->max_bodysize && !$this->keep_alive){
$r_body = $this->_readData($socket, $this->max_bodysize, 'response (content-length limited)', true);
}else{
// read entire socket
while (!feof($socket)) {
$r_body .= $this->_readData($socket, 4096, 'response (unlimited)', true);
}
}
// recheck body size, we might had to read the whole body, so we abort late or trim here
if($this->max_bodysize){
if(strlen($r_body) > $this->max_bodysize){
if ($this->max_bodysize_abort) {
throw new HTTPClientException('Allowed response size exceeded');
} else {
$this->error = 'Allowed response size exceeded';
}
}
}
} catch (HTTPClientException $err) {
$this->error = $err->getMessage();
if ($err->getCode())
$this->status = $err->getCode();
unset(self::$connections[$connectionId]);
fclose($socket);
return false;
}
if (!$this->keep_alive ||
(isset($this->resp_headers['connection']) && $this->resp_headers['connection'] == 'Close')) {
// close socket
fclose($socket);
unset(self::$connections[$connectionId]);
}
// decode gzip if needed
if(isset($this->resp_headers['content-encoding']) &&
$this->resp_headers['content-encoding'] == 'gzip' &&
strlen($r_body) > 10 && substr($r_body,0,3)=="\x1f\x8b\x08"){
$this->resp_body = @gzinflate(substr($r_body, 10));
if($this->resp_body === false){
$this->error = 'Failed to decompress gzip encoded content';
$this->resp_body = $r_body;
}
}else{
$this->resp_body = $r_body;
}
$this->_debug('response body',$this->resp_body);
$this->redirect_count = 0;
return true;
}
/**
* Tries to establish a CONNECT tunnel via Proxy
*
* Protocol, Servername and Port will be stripped from the request URL when a successful CONNECT happened
*
* @param resource &$socket
* @param string &$requesturl
* @throws HTTPClientException when a tunnel is needed but could not be established
* @return bool true if a tunnel was established
*/
function _ssltunnel(&$socket, &$requesturl){
if(!$this->proxy_host) return false;
$requestinfo = parse_url($requesturl);
if($requestinfo['scheme'] != 'https') return false;
if(!$requestinfo['port']) $requestinfo['port'] = 443;
// build request
$request = "CONNECT {$requestinfo['host']}:{$requestinfo['port']} HTTP/1.0".HTTP_NL;
$request .= "Host: {$requestinfo['host']}".HTTP_NL;
if($this->proxy_user) {
$request .= 'Proxy-Authorization: Basic '.base64_encode($this->proxy_user.':'.$this->proxy_pass).HTTP_NL;
}
$request .= HTTP_NL;
$this->_debug('SSL Tunnel CONNECT',$request);
$this->_sendData($socket, $request, 'SSL Tunnel CONNECT');
// read headers from socket
$r_headers = '';
do{
$r_line = $this->_readLine($socket, 'headers');
$r_headers .= $r_line;
}while($r_line != "\r\n" && $r_line != "\n");
$this->_debug('SSL Tunnel Response',$r_headers);
if(preg_match('/^HTTP\/1\.[01] 200/i',$r_headers)){
// set correct peer name for verification (enabled since PHP 5.6)
stream_context_set_option($socket, 'ssl', 'peer_name', $requestinfo['host']);
// because SSLv3 is mostly broken, we try TLS connections here first.
// according to https://github.com/splitbrain/dokuwiki/commit/c05ef534 we had problems with certain
// setups with this solution before, but we have no usable test for that and TLS should be the more
// common crypto by now
if (@stream_socket_enable_crypto($socket, true, STREAM_CRYPTO_METHOD_TLS_CLIENT)) {
$requesturl = $requestinfo['path'].
(!empty($requestinfo['query'])?'?'.$requestinfo['query']:'');
return true;
}
// if the above failed, this will most probably not work either, but we can try
if (@stream_socket_enable_crypto($socket, true, STREAM_CRYPTO_METHOD_SSLv3_CLIENT)) {
$requesturl = $requestinfo['path'].
(!empty($requestinfo['query'])?'?'.$requestinfo['query']:'');
return true;
}
throw new HTTPClientException('Failed to set up crypto for secure connection to '.$requestinfo['host'], -151);
}
throw new HTTPClientException('Failed to establish secure proxy connection', -150);
}
/**
* Safely write data to a socket
*
* @param resource $socket An open socket handle
* @param string $data The data to write
* @param string $message Description of what is being read
* @throws HTTPClientException
*
* @author Tom N Harris <tnharris@whoopdedo.org>
*/
function _sendData($socket, $data, $message) {
// send request
$towrite = strlen($data);
$written = 0;
while($written < $towrite){
// check timeout
$time_used = $this->_time() - $this->start;
if($time_used > $this->timeout)
throw new HTTPClientException(sprintf('Timeout while sending %s (%.3fs)',$message, $time_used), -100);
if(feof($socket))
throw new HTTPClientException("Socket disconnected while writing $message");
// select parameters
$sel_r = null;
$sel_w = array($socket);
$sel_e = null;
// wait for stream ready or timeout (1sec)
if(@stream_select($sel_r,$sel_w,$sel_e,1) === false){
usleep(1000);
continue;
}
// write to stream
$nbytes = fwrite($socket, substr($data,$written,4096));
if($nbytes === false)
throw new HTTPClientException("Failed writing to socket while sending $message", -100);
$written += $nbytes;
}
}
/**
* Safely read data from a socket
*
* Reads up to a given number of bytes or throws an exception if the
* response times out or ends prematurely.
*
* @param resource $socket An open socket handle in non-blocking mode
* @param int $nbytes Number of bytes to read
* @param string $message Description of what is being read
* @param bool $ignore_eof End-of-file is not an error if this is set
* @throws HTTPClientException
* @return string
*
* @author Tom N Harris <tnharris@whoopdedo.org>
*/
function _readData($socket, $nbytes, $message, $ignore_eof = false) {
$r_data = '';
// Does not return immediately so timeout and eof can be checked
if ($nbytes < 0) $nbytes = 0;
$to_read = $nbytes;
do {
$time_used = $this->_time() - $this->start;
if ($time_used > $this->timeout)
throw new HTTPClientException(
sprintf('Timeout while reading %s after %d bytes (%.3fs)', $message,
strlen($r_data), $time_used), -100);
if(feof($socket)) {
if(!$ignore_eof)
throw new HTTPClientException("Premature End of File (socket) while reading $message");
break;
}
if ($to_read > 0) {
// select parameters
$sel_r = array($socket);
$sel_w = null;
$sel_e = null;
// wait for stream ready or timeout (1sec)
if(@stream_select($sel_r,$sel_w,$sel_e,1) === false){
usleep(1000);
continue;
}
$bytes = fread($socket, $to_read);
if($bytes === false)
throw new HTTPClientException("Failed reading from socket while reading $message", -100);
$r_data .= $bytes;
$to_read -= strlen($bytes);
}
} while ($to_read > 0 && strlen($r_data) < $nbytes);
return $r_data;
}
/**
* Safely read a \n-terminated line from a socket
*
* Always returns a complete line, including the terminating \n.
*
* @param resource $socket An open socket handle in non-blocking mode
* @param string $message Description of what is being read
* @throws HTTPClientException
* @return string
*
* @author Tom N Harris <tnharris@whoopdedo.org>
*/
function _readLine($socket, $message) {
$r_data = '';
do {
$time_used = $this->_time() - $this->start;
if ($time_used > $this->timeout)
throw new HTTPClientException(
sprintf('Timeout while reading %s (%.3fs) >%s<', $message, $time_used, $r_data),
-100);
if(feof($socket))
throw new HTTPClientException("Premature End of File (socket) while reading $message");
// select parameters
$sel_r = array($socket);
$sel_w = null;
$sel_e = null;
// wait for stream ready or timeout (1sec)
if(@stream_select($sel_r,$sel_w,$sel_e,1) === false){
usleep(1000);
continue;
}
$r_data = fgets($socket, 1024);
} while (!preg_match('/\n$/',$r_data));
return $r_data;
}
/**
* print debug info
*
* Uses _debug_text or _debug_html depending on the SAPI name
*
* @author Andreas Gohr <andi@splitbrain.org>
*
* @param string $info
* @param mixed $var
*/
function _debug($info,$var=null){
if(!$this->debug) return;
if(php_sapi_name() == 'cli'){
$this->_debug_text($info, $var);
}else{
$this->_debug_html($info, $var);
}
}
/**
* print debug info as HTML
*
* @param string $info
* @param mixed $var
*/
function _debug_html($info, $var=null){
print '<b>'.$info.'</b> '.($this->_time() - $this->start).'s<br />';
if(!is_null($var)){
ob_start();
print_r($var);
$content = htmlspecialchars(ob_get_contents());
ob_end_clean();
print '<pre>'.$content.'</pre>';
}
}
/**
* prints debug info as plain text
*
* @param string $info
* @param mixed $var
*/
function _debug_text($info, $var=null){
print '*'.$info.'* '.($this->_time() - $this->start)."s\n";
if(!is_null($var)) print_r($var);
print "\n-----------------------------------------------\n";
}
/**
* Return current timestamp in microsecond resolution
*
* @return float
*/
static function _time(){
list($usec, $sec) = explode(" ", microtime());
return ((float)$usec + (float)$sec);
}
/**
* convert given header string to Header array
*
* All Keys are lowercased.
*
* @author Andreas Gohr <andi@splitbrain.org>
*
* @param string $string
* @return array
*/
function _parseHeaders($string){
$headers = array();
$lines = explode("\n",$string);
array_shift($lines); //skip first line (status)
foreach($lines as $line){
@list($key, $val) = explode(':',$line,2);
$key = trim($key);
$val = trim($val);
$key = strtolower($key);
if(!$key) continue;
if(isset($headers[$key])){
if(is_array($headers[$key])){
$headers[$key][] = $val;
}else{
$headers[$key] = array($headers[$key],$val);
}
}else{
$headers[$key] = $val;
}
}
return $headers;
}
/**
* convert given header array to header string
*
* @author Andreas Gohr <andi@splitbrain.org>
*
* @param array $headers
* @return string
*/
function _buildHeaders($headers){
$string = '';
foreach($headers as $key => $value){
if($value === '') continue;
$string .= $key.': '.$value.HTTP_NL;
}
return $string;
}
/**
* get cookies as http header string
*
* @author Andreas Goetz <cpuidle@gmx.de>
*
* @return string
*/
function _getCookies(){
$headers = '';
foreach ($this->cookies as $key => $val){
$headers .= "$key=$val; ";
}
$headers = substr($headers, 0, -2);
if ($headers) $headers = "Cookie: $headers".HTTP_NL;
return $headers;
}
/**
* Encode data for posting
*
* @author Andreas Gohr <andi@splitbrain.org>
*
* @param array $data
* @return string
*/
function _postEncode($data){
return http_build_query($data,'','&');
}
/**
* Encode data for posting using multipart encoding
*
* @fixme use of urlencode might be wrong here
* @author Andreas Gohr <andi@splitbrain.org>
*
* @param array $data
* @return string
*/
function _postMultipartEncode($data){
$boundary = '--'.$this->boundary;
$out = '';
foreach($data as $key => $val){
$out .= $boundary.HTTP_NL;
if(!is_array($val)){
$out .= 'Content-Disposition: form-data; name="'.urlencode($key).'"'.HTTP_NL;
$out .= HTTP_NL; // end of headers
$out .= $val;
$out .= HTTP_NL;
}else{
$out .= 'Content-Disposition: form-data; name="'.urlencode($key).'"';
if($val['filename']) $out .= '; filename="'.urlencode($val['filename']).'"';
$out .= HTTP_NL;
if($val['mimetype']) $out .= 'Content-Type: '.$val['mimetype'].HTTP_NL;
$out .= HTTP_NL; // end of headers
$out .= $val['body'];
$out .= HTTP_NL;
}
}
$out .= "$boundary--".HTTP_NL;
return $out;
}
/**
* Generates a unique identifier for a connection.
*
* @param string $server
* @param string $port
* @return string unique identifier
*/
function _uniqueConnectionId($server, $port) {
return "$server:$port";
}
}
//Setup VIM: ex: et ts=4 :

File diff suppressed because it is too large Load diff

View file

@ -1,335 +0,0 @@
<?php
/**
* Encapsulates access to the $_REQUEST array, making sure used parameters are initialized and
* have the correct type.
*
* All function access the $_REQUEST array by default, if you want to access $_POST or $_GET
* explicitly use the $post and $get members.
*
* @author Andreas Gohr <andi@splitbrain.org>
*/
class Input {
/** @var PostInput Access $_POST parameters */
public $post;
/** @var GetInput Access $_GET parameters */
public $get;
/** @var ServerInput Access $_SERVER parameters */
public $server;
protected $access;
/**
* @var Callable
*/
protected $filter;
/**
* Intilizes the Input class and it subcomponents
*/
function __construct() {
$this->access = &$_REQUEST;
$this->post = new PostInput();
$this->get = new GetInput();
$this->server = new ServerInput();
}
/**
* Apply the set filter to the given value
*
* @param string $data
* @return string
*/
protected function applyfilter($data){
if(!$this->filter) return $data;
return call_user_func($this->filter, $data);
}
/**
* Return a filtered copy of the input object
*
* Expects a callable that accepts one string parameter and returns a filtered string
*
* @param Callable|string $filter
* @return Input
*/
public function filter($filter='stripctl'){
$this->filter = $filter;
$clone = clone $this;
$this->filter = '';
return $clone;
}
/**
* Check if a parameter was set
*
* Basically a wrapper around isset. When called on the $post and $get subclasses,
* the parameter is set to $_POST or $_GET and to $_REQUEST
*
* @see isset
* @param string $name Parameter name
* @return bool
*/
public function has($name) {
return isset($this->access[$name]);
}
/**
* Remove a parameter from the superglobals
*
* Basically a wrapper around unset. When NOT called on the $post and $get subclasses,
* the parameter will also be removed from $_POST or $_GET
*
* @see isset
* @param string $name Parameter name
*/
public function remove($name) {
if(isset($this->access[$name])) {
unset($this->access[$name]);
}
// also remove from sub classes
if(isset($this->post) && isset($_POST[$name])) {
unset($_POST[$name]);
}
if(isset($this->get) && isset($_GET[$name])) {
unset($_GET[$name]);
}
}
/**
* Access a request parameter without any type conversion
*
* @param string $name Parameter name
* @param mixed $default Default to return if parameter isn't set
* @param bool $nonempty Return $default if parameter is set but empty()
* @return mixed
*/
public function param($name, $default = null, $nonempty = false) {
if(!isset($this->access[$name])) return $default;
$value = $this->applyfilter($this->access[$name]);
if($nonempty && empty($value)) return $default;
return $value;
}
/**
* Sets a parameter
*
* @param string $name Parameter name
* @param mixed $value Value to set
*/
public function set($name, $value) {
$this->access[$name] = $value;
}
/**
* Get a reference to a request parameter
*
* This avoids copying data in memory, when the parameter is not set it will be created
* and intialized with the given $default value before a reference is returned
*
* @param string $name Parameter name
* @param mixed $default If parameter is not set, initialize with this value
* @param bool $nonempty Init with $default if parameter is set but empty()
* @return mixed (reference)
*/
public function &ref($name, $default = '', $nonempty = false) {
if(!isset($this->access[$name]) || ($nonempty && empty($this->access[$name]))) {
$this->set($name, $default);
}
return $this->access[$name];
}
/**
* Access a request parameter as int
*
* @param string $name Parameter name
* @param int $default Default to return if parameter isn't set or is an array
* @param bool $nonempty Return $default if parameter is set but empty()
* @return int
*/
public function int($name, $default = 0, $nonempty = false) {
if(!isset($this->access[$name])) return $default;
if(is_array($this->access[$name])) return $default;
$value = $this->applyfilter($this->access[$name]);
if($value === '') return $default;
if($nonempty && empty($value)) return $default;
return (int) $value;
}
/**
* Access a request parameter as string
*
* @param string $name Parameter name
* @param string $default Default to return if parameter isn't set or is an array
* @param bool $nonempty Return $default if parameter is set but empty()
* @return string
*/
public function str($name, $default = '', $nonempty = false) {
if(!isset($this->access[$name])) return $default;
if(is_array($this->access[$name])) return $default;
$value = $this->applyfilter($this->access[$name]);
if($nonempty && empty($value)) return $default;
return (string) $value;
}
/**
* Access a request parameter and make sure it is has a valid value
*
* Please note that comparisons to the valid values are not done typesafe (request vars
* are always strings) however the function will return the correct type from the $valids
* array when an match was found.
*
* @param string $name Parameter name
* @param array $valids Array of valid values
* @param mixed $default Default to return if parameter isn't set or not valid
* @return null|mixed
*/
public function valid($name, $valids, $default = null) {
if(!isset($this->access[$name])) return $default;
if(is_array($this->access[$name])) return $default; // we don't allow arrays
$value = $this->applyfilter($this->access[$name]);
$found = array_search($value, $valids);
if($found !== false) return $valids[$found]; // return the valid value for type safety
return $default;
}
/**
* Access a request parameter as bool
*
* Note: $nonempty is here for interface consistency and makes not much sense for booleans
*
* @param string $name Parameter name
* @param mixed $default Default to return if parameter isn't set
* @param bool $nonempty Return $default if parameter is set but empty()
* @return bool
*/
public function bool($name, $default = false, $nonempty = false) {
if(!isset($this->access[$name])) return $default;
if(is_array($this->access[$name])) return $default;
$value = $this->applyfilter($this->access[$name]);
if($value === '') return $default;
if($nonempty && empty($value)) return $default;
return (bool) $value;
}
/**
* Access a request parameter as array
*
* @param string $name Parameter name
* @param mixed $default Default to return if parameter isn't set
* @param bool $nonempty Return $default if parameter is set but empty()
* @return array
*/
public function arr($name, $default = array(), $nonempty = false) {
if(!isset($this->access[$name])) return $default;
if(!is_array($this->access[$name])) return $default;
if($nonempty && empty($this->access[$name])) return $default;
return (array) $this->access[$name];
}
/**
* Create a simple key from an array key
*
* This is useful to access keys where the information is given as an array key or as a single array value.
* For example when the information was submitted as the name of a submit button.
*
* This function directly changes the access array.
*
* Eg. $_REQUEST['do']['save']='Speichern' becomes $_REQUEST['do'] = 'save'
*
* This function returns the $INPUT object itself for easy chaining
*
* @param string $name
* @return Input
*/
public function extract($name){
if(!isset($this->access[$name])) return $this;
if(!is_array($this->access[$name])) return $this;
$keys = array_keys($this->access[$name]);
if(!$keys){
// this was an empty array
$this->remove($name);
return $this;
}
// get the first key
$value = array_shift($keys);
if($value === 0){
// we had a numeric array, assume the value is not in the key
$value = array_shift($this->access[$name]);
}
$this->set($name, $value);
return $this;
}
}
/**
* Internal class used for $_POST access in Input class
*/
class PostInput extends Input {
protected $access;
/**
* Initialize the $access array, remove subclass members
*/
function __construct() {
$this->access = &$_POST;
}
/**
* Sets a parameter in $_POST and $_REQUEST
*
* @param string $name Parameter name
* @param mixed $value Value to set
*/
public function set($name, $value) {
parent::set($name, $value);
$_REQUEST[$name] = $value;
}
}
/**
* Internal class used for $_GET access in Input class
*/
class GetInput extends Input {
protected $access;
/**
* Initialize the $access array, remove subclass members
*/
function __construct() {
$this->access = &$_GET;
}
/**
* Sets a parameter in $_GET and $_REQUEST
*
* @param string $name Parameter name
* @param mixed $value Value to set
*/
public function set($name, $value) {
parent::set($name, $value);
$_REQUEST[$name] = $value;
}
}
/**
* Internal class used for $_SERVER access in Input class
*/
class ServerInput extends Input {
protected $access;
/**
* Initialize the $access array, remove subclass members
*/
function __construct() {
$this->access = &$_SERVER;
}
}

View file

@ -1,648 +0,0 @@
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
/**
* Converts to and from JSON format.
*
* JSON (JavaScript Object Notation) is a lightweight data-interchange
* format. It is easy for humans to read and write. It is easy for machines
* to parse and generate. It is based on a subset of the JavaScript
* Programming Language, Standard ECMA-262 3rd Edition - December 1999.
* This feature can also be found in Python. JSON is a text format that is
* completely language independent but uses conventions that are familiar
* to programmers of the C-family of languages, including C, C++, C#, Java,
* JavaScript, Perl, TCL, and many others. These properties make JSON an
* ideal data-interchange language.
*
* This package provides a simple encoder and decoder for JSON notation. It
* is intended for use with client-side Javascript applications that make
* use of HTTPRequest to perform server communication functions - data can
* be encoded into JSON notation for use in a client-side javascript, or
* decoded from incoming Javascript requests. JSON format is native to
* Javascript, and can be directly eval()'ed with no further parsing
* overhead
*
* All strings should be in ASCII or UTF-8 format!
*
* PHP versions 4 and 5
*
* LICENSE: Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met: Redistributions of source code must retain the
* above copyright notice, this list of conditions and the following
* disclaimer. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
* NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* @author Michal Migurski <mike-json@teczno.com>
* @author Matt Knapp <mdknapp[at]gmail[dot]com>
* @author Brett Stimmerman <brettstimmerman[at]gmail[dot]com>
* @copyright 2005 Michal Migurski
* @license http://www.freebsd.org/copyright/freebsd-license.html
* @link http://pear.php.net/pepr/pepr-proposal-show.php?id=198
*/
// for DokuWiki
if(!defined('DOKU_INC')) die('meh.');
/**
* Marker constant for JSON::decode(), used to flag stack state
*/
define('JSON_SLICE', 1);
/**
* Marker constant for JSON::decode(), used to flag stack state
*/
define('JSON_IN_STR', 2);
/**
* Marker constant for JSON::decode(), used to flag stack state
*/
define('JSON_IN_ARR', 4);
/**
* Marker constant for JSON::decode(), used to flag stack state
*/
define('JSON_IN_OBJ', 8);
/**
* Marker constant for JSON::decode(), used to flag stack state
*/
define('JSON_IN_CMT', 16);
/**
* Behavior switch for JSON::decode()
*/
define('JSON_LOOSE_TYPE', 10);
/**
* Behavior switch for JSON::decode()
*/
define('JSON_STRICT_TYPE', 11);
/**
* Converts to and from JSON format.
*/
class JSON {
/**
* Disables the use of PHP5's native json_decode()
*
* You shouldn't change this usually because the native function is much
* faster. However, this non-native will also parse slightly broken JSON
* which might be handy when talking to a non-conform endpoint
*/
public $skipnative = false;
/**
* constructs a new JSON instance
*
* @param int $use object behavior: when encoding or decoding,
* be loose or strict about object/array usage
*
* possible values:
* JSON_STRICT_TYPE - strict typing, default
* "{...}" syntax creates objects in decode.
* JSON_LOOSE_TYPE - loose typing
* "{...}" syntax creates associative arrays in decode.
*/
function __construct($use=JSON_STRICT_TYPE) {
$this->use = $use;
}
/**
* encodes an arbitrary variable into JSON format
* If available the native PHP JSON implementation is used.
*
* @param mixed $var any number, boolean, string, array, or object to be encoded.
* see argument 1 to JSON() above for array-parsing behavior.
* if var is a strng, note that encode() always expects it
* to be in ASCII or UTF-8 format!
*
* @return string JSON string representation of input var
* @access public
*/
function encode($var) {
if (!$this->skipnative && function_exists('json_encode')){
return json_encode($var);
}
switch (gettype($var)) {
case 'boolean':
return $var ? 'true' : 'false';
case 'NULL':
return 'null';
case 'integer':
return sprintf('%d', $var);
case 'double':
case 'float':
return sprintf('%f', $var);
case 'string':
// STRINGS ARE EXPECTED TO BE IN ASCII OR UTF-8 FORMAT
$ascii = '';
$strlen_var = strlen($var);
/*
* Iterate over every character in the string,
* escaping with a slash or encoding to UTF-8 where necessary
*/
for ($c = 0; $c < $strlen_var; ++$c) {
$ord_var_c = ord($var{$c});
switch ($ord_var_c) {
case 0x08:
$ascii .= '\b';
break;
case 0x09:
$ascii .= '\t';
break;
case 0x0A:
$ascii .= '\n';
break;
case 0x0C:
$ascii .= '\f';
break;
case 0x0D:
$ascii .= '\r';
break;
case 0x22:
case 0x2F:
case 0x5C:
// double quote, slash, slosh
$ascii .= '\\'.$var{$c};
break;
case (($ord_var_c >= 0x20) && ($ord_var_c <= 0x7F)):
// characters U-00000000 - U-0000007F (same as ASCII)
$ascii .= $var{$c};
break;
case (($ord_var_c & 0xE0) == 0xC0):
// characters U-00000080 - U-000007FF, mask 110XXXXX
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
$char = pack('C*', $ord_var_c, ord($var{$c+1}));
$c+=1;
//$utf16 = mb_convert_encoding($char, 'UTF-16', 'UTF-8');
$utf16 = utf8_to_utf16be($char);
$ascii .= sprintf('\u%04s', bin2hex($utf16));
break;
case (($ord_var_c & 0xF0) == 0xE0):
// characters U-00000800 - U-0000FFFF, mask 1110XXXX
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
$char = pack('C*', $ord_var_c,
ord($var{$c+1}),
ord($var{$c+2}));
$c+=2;
//$utf16 = mb_convert_encoding($char, 'UTF-16', 'UTF-8');
$utf16 = utf8_to_utf16be($char);
$ascii .= sprintf('\u%04s', bin2hex($utf16));
break;
case (($ord_var_c & 0xF8) == 0xF0):
// characters U-00010000 - U-001FFFFF, mask 11110XXX
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
$char = pack('C*', $ord_var_c,
ord($var{$c+1}),
ord($var{$c+2}),
ord($var{$c+3}));
$c+=3;
//$utf16 = mb_convert_encoding($char, 'UTF-16', 'UTF-8');
$utf16 = utf8_to_utf16be($char);
$ascii .= sprintf('\u%04s', bin2hex($utf16));
break;
case (($ord_var_c & 0xFC) == 0xF8):
// characters U-00200000 - U-03FFFFFF, mask 111110XX
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
$char = pack('C*', $ord_var_c,
ord($var{$c+1}),
ord($var{$c+2}),
ord($var{$c+3}),
ord($var{$c+4}));
$c+=4;
//$utf16 = mb_convert_encoding($char, 'UTF-16', 'UTF-8');
$utf16 = utf8_to_utf16be($char);
$ascii .= sprintf('\u%04s', bin2hex($utf16));
break;
case (($ord_var_c & 0xFE) == 0xFC):
// characters U-04000000 - U-7FFFFFFF, mask 1111110X
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
$char = pack('C*', $ord_var_c,
ord($var{$c+1}),
ord($var{$c+2}),
ord($var{$c+3}),
ord($var{$c+4}),
ord($var{$c+5}));
$c+=5;
//$utf16 = mb_convert_encoding($char, 'UTF-16', 'UTF-8');
$utf16 = utf8_to_utf16be($char);
$ascii .= sprintf('\u%04s', bin2hex($utf16));
break;
}
}
return '"'.$ascii.'"';
case 'array':
/*
* As per JSON spec if any array key is not an integer
* we must treat the the whole array as an object. We
* also try to catch a sparsely populated associative
* array with numeric keys here because some JS engines
* will create an array with empty indexes up to
* max_index which can cause memory issues and because
* the keys, which may be relevant, will be remapped
* otherwise.
*
* As per the ECMA and JSON specification an object may
* have any string as a property. Unfortunately due to
* a hole in the ECMA specification if the key is a
* ECMA reserved word or starts with a digit the
* parameter is only accessible using ECMAScript's
* bracket notation.
*/
// treat as a JSON object
if (is_array($var) && count($var) && (array_keys($var) !== range(0, count($var) - 1))) {
return sprintf('{%s}', join(',', array_map(array($this, 'name_value'),
array_keys($var),
array_values($var))));
}
// treat it like a regular array
return sprintf('[%s]', join(',', array_map(array($this, 'encode'), $var)));
case 'object':
$vars = get_object_vars($var);
return sprintf('{%s}', join(',', array_map(array($this, 'name_value'),
array_keys($vars),
array_values($vars))));
default:
return '';
}
}
/**
* encodes an arbitrary variable into JSON format, alias for encode()
*/
function enc($var) {
return $this->encode($var);
}
/** function name_value
* array-walking function for use in generating JSON-formatted name-value pairs
*
* @param string $name name of key to use
* @param mixed $value reference to an array element to be encoded
*
* @return string JSON-formatted name-value pair, like '"name":value'
* @access private
*/
function name_value($name, $value) {
return (sprintf("%s:%s", $this->encode(strval($name)), $this->encode($value)));
}
/**
* reduce a string by removing leading and trailing comments and whitespace
*
* @param $str string string value to strip of comments and whitespace
*
* @return string string value stripped of comments and whitespace
* @access private
*/
function reduce_string($str) {
$str = preg_replace(array(
// eliminate single line comments in '// ...' form
'#^\s*//(.+)$#m',
// eliminate multi-line comments in '/* ... */' form, at start of string
'#^\s*/\*(.+)\*/#Us',
// eliminate multi-line comments in '/* ... */' form, at end of string
'#/\*(.+)\*/\s*$#Us'
), '', $str);
// eliminate extraneous space
return trim($str);
}
/**
* decodes a JSON string into appropriate variable
* If available the native PHP JSON implementation is used.
*
* @param string $str JSON-formatted string
*
* @return mixed number, boolean, string, array, or object
* corresponding to given JSON input string.
* See argument 1 to JSON() above for object-output behavior.
* Note that decode() always returns strings
* in ASCII or UTF-8 format!
* @access public
*/
function decode($str) {
if (!$this->skipnative && function_exists('json_decode')){
return json_decode($str,($this->use == JSON_LOOSE_TYPE));
}
$str = $this->reduce_string($str);
switch (strtolower($str)) {
case 'true':
return true;
case 'false':
return false;
case 'null':
return null;
default:
if (is_numeric($str)) {
// Lookie-loo, it's a number
// This would work on its own, but I'm trying to be
// good about returning integers where appropriate:
// return (float)$str;
// Return float or int, as appropriate
return ((float)$str == (integer)$str)
? (integer)$str
: (float)$str;
} elseif (preg_match('/^("|\').+("|\')$/s', $str, $m) && $m[1] == $m[2]) {
// STRINGS RETURNED IN UTF-8 FORMAT
$delim = substr($str, 0, 1);
$chrs = substr($str, 1, -1);
$utf8 = '';
$strlen_chrs = strlen($chrs);
for ($c = 0; $c < $strlen_chrs; ++$c) {
$substr_chrs_c_2 = substr($chrs, $c, 2);
$ord_chrs_c = ord($chrs{$c});
switch ($substr_chrs_c_2) {
case '\b':
$utf8 .= chr(0x08);
$c+=1;
break;
case '\t':
$utf8 .= chr(0x09);
$c+=1;
break;
case '\n':
$utf8 .= chr(0x0A);
$c+=1;
break;
case '\f':
$utf8 .= chr(0x0C);
$c+=1;
break;
case '\r':
$utf8 .= chr(0x0D);
$c+=1;
break;
case '\\"':
case '\\\'':
case '\\\\':
case '\\/':
if (($delim == '"' && $substr_chrs_c_2 != '\\\'') ||
($delim == "'" && $substr_chrs_c_2 != '\\"')) {
$utf8 .= $chrs{++$c};
}
break;
default:
if (preg_match('/\\\u[0-9A-F]{4}/i', substr($chrs, $c, 6))) {
// single, escaped unicode character
$utf16 = chr(hexdec(substr($chrs, ($c+2), 2)))
. chr(hexdec(substr($chrs, ($c+4), 2)));
//$utf8 .= mb_convert_encoding($utf16, 'UTF-8', 'UTF-16');
$utf8 .= utf16be_to_utf8($utf16);
$c+=5;
} elseif(($ord_chrs_c >= 0x20) && ($ord_chrs_c <= 0x7F)) {
$utf8 .= $chrs{$c};
} elseif(($ord_chrs_c & 0xE0) == 0xC0) {
// characters U-00000080 - U-000007FF, mask 110XXXXX
//see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
$utf8 .= substr($chrs, $c, 2);
$c += 1;
} elseif(($ord_chrs_c & 0xF0) == 0xE0) {
// characters U-00000800 - U-0000FFFF, mask 1110XXXX
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
$utf8 .= substr($chrs, $c, 3);
$c += 2;
} elseif(($ord_chrs_c & 0xF8) == 0xF0) {
// characters U-00010000 - U-001FFFFF, mask 11110XXX
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
$utf8 .= substr($chrs, $c, 4);
$c += 3;
} elseif(($ord_chrs_c & 0xFC) == 0xF8) {
// characters U-00200000 - U-03FFFFFF, mask 111110XX
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
$utf8 .= substr($chrs, $c, 5);
$c += 4;
} elseif(($ord_chrs_c & 0xFE) == 0xFC) {
// characters U-04000000 - U-7FFFFFFF, mask 1111110X
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
$utf8 .= substr($chrs, $c, 6);
$c += 5;
}
break;
}
}
return $utf8;
} elseif (preg_match('/^\[.*\]$/s', $str) || preg_match('/^\{.*\}$/s', $str)) {
// array, or object notation
if ($str{0} == '[') {
$stk = array(JSON_IN_ARR);
$arr = array();
} else {
if ($this->use == JSON_LOOSE_TYPE) {
$stk = array(JSON_IN_OBJ);
$obj = array();
} else {
$stk = array(JSON_IN_OBJ);
$obj = new stdClass();
}
}
array_push($stk, array('what' => JSON_SLICE,
'where' => 0,
'delim' => false));
$chrs = substr($str, 1, -1);
$chrs = $this->reduce_string($chrs);
if ($chrs == '') {
if (reset($stk) == JSON_IN_ARR) {
return $arr;
} else {
return $obj;
}
}
//print("\nparsing {$chrs}\n");
$strlen_chrs = strlen($chrs);
for ($c = 0; $c <= $strlen_chrs; ++$c) {
$top = end($stk);
$substr_chrs_c_2 = substr($chrs, $c, 2);
if (($c == $strlen_chrs) || (($chrs{$c} == ',') && ($top['what'] == JSON_SLICE))) {
// found a comma that is not inside a string, array, etc.,
// OR we've reached the end of the character list
$slice = substr($chrs, $top['where'], ($c - $top['where']));
array_push($stk, array('what' => JSON_SLICE, 'where' => ($c + 1), 'delim' => false));
//print("Found split at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
if (reset($stk) == JSON_IN_ARR) {
// we are in an array, so just push an element onto the stack
array_push($arr, $this->decode($slice));
} elseif (reset($stk) == JSON_IN_OBJ) {
// we are in an object, so figure
// out the property name and set an
// element in an associative array,
// for now
if (preg_match('/^\s*(["\'].*[^\\\]["\'])\s*:\s*(\S.*),?$/Uis', $slice, $parts)) {
// "name":value pair
$key = $this->decode($parts[1]);
$val = $this->decode($parts[2]);
if ($this->use == JSON_LOOSE_TYPE) {
$obj[$key] = $val;
} else {
$obj->$key = $val;
}
} elseif (preg_match('/^\s*(\w+)\s*:\s*(\S.*),?$/Uis', $slice, $parts)) {
// name:value pair, where name is unquoted
$key = $parts[1];
$val = $this->decode($parts[2]);
if ($this->use == JSON_LOOSE_TYPE) {
$obj[$key] = $val;
} else {
$obj->$key = $val;
}
}
}
} elseif ((($chrs{$c} == '"') || ($chrs{$c} == "'")) && ($top['what'] != JSON_IN_STR)) {
// found a quote, and we are not inside a string
array_push($stk, array('what' => JSON_IN_STR, 'where' => $c, 'delim' => $chrs{$c}));
//print("Found start of string at {$c}\n");
} elseif (($chrs{$c} == $top['delim']) &&
($top['what'] == JSON_IN_STR) &&
((strlen(substr($chrs, 0, $c)) - strlen(rtrim(substr($chrs, 0, $c), '\\'))) % 2 != 1)) {
// found a quote, we're in a string, and it's not escaped
// we know that it's not escaped becase there is _not_ an
// odd number of backslashes at the end of the string so far
array_pop($stk);
//print("Found end of string at {$c}: ".substr($chrs, $top['where'], (1 + 1 + $c - $top['where']))."\n");
} elseif (($chrs{$c} == '[') &&
in_array($top['what'], array(JSON_SLICE, JSON_IN_ARR, JSON_IN_OBJ))) {
// found a left-bracket, and we are in an array, object, or slice
array_push($stk, array('what' => JSON_IN_ARR, 'where' => $c, 'delim' => false));
//print("Found start of array at {$c}\n");
} elseif (($chrs{$c} == ']') && ($top['what'] == JSON_IN_ARR)) {
// found a right-bracket, and we're in an array
array_pop($stk);
//print("Found end of array at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
} elseif (($chrs{$c} == '{') &&
in_array($top['what'], array(JSON_SLICE, JSON_IN_ARR, JSON_IN_OBJ))) {
// found a left-brace, and we are in an array, object, or slice
array_push($stk, array('what' => JSON_IN_OBJ, 'where' => $c, 'delim' => false));
//print("Found start of object at {$c}\n");
} elseif (($chrs{$c} == '}') && ($top['what'] == JSON_IN_OBJ)) {
// found a right-brace, and we're in an object
array_pop($stk);
//print("Found end of object at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
} elseif (($substr_chrs_c_2 == '/*') &&
in_array($top['what'], array(JSON_SLICE, JSON_IN_ARR, JSON_IN_OBJ))) {
// found a comment start, and we are in an array, object, or slice
array_push($stk, array('what' => JSON_IN_CMT, 'where' => $c, 'delim' => false));
$c++;
//print("Found start of comment at {$c}\n");
} elseif (($substr_chrs_c_2 == '*/') && ($top['what'] == JSON_IN_CMT)) {
// found a comment end, and we're in one now
array_pop($stk);
$c++;
for ($i = $top['where']; $i <= $c; ++$i)
$chrs = substr_replace($chrs, ' ', $i, 1);
//print("Found end of comment at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
}
}
if (reset($stk) == JSON_IN_ARR) {
return $arr;
} elseif (reset($stk) == JSON_IN_OBJ) {
return $obj;
}
}
}
}
/**
* decodes a JSON string into appropriate variable; alias for decode()
*/
function dec($var) {
return $this->decode($var);
}
}

File diff suppressed because it is too large Load diff

View file

@ -1,736 +0,0 @@
<?php
/**
* A class to build and send multi part mails (with HTML content and embedded
* attachments). All mails are assumed to be in UTF-8 encoding.
*
* Attachments are handled in memory so this shouldn't be used to send huge
* files, but then again mail shouldn't be used to send huge files either.
*
* @author Andreas Gohr <andi@splitbrain.org>
*/
// end of line for mail lines - RFC822 says CRLF but postfix (and other MTAs?)
// think different
if(!defined('MAILHEADER_EOL')) define('MAILHEADER_EOL', "\n");
#define('MAILHEADER_ASCIIONLY',1);
/**
* Mail Handling
*/
class Mailer {
protected $headers = array();
protected $attach = array();
protected $html = '';
protected $text = '';
protected $boundary = '';
protected $partid = '';
protected $sendparam = null;
/** @var EmailAddressValidator */
protected $validator = null;
protected $allowhtml = true;
protected $replacements = array('text'=> array(), 'html' => array());
/**
* Constructor
*
* Initializes the boundary strings, part counters and token replacements
*/
public function __construct() {
global $conf;
/* @var Input $INPUT */
global $INPUT;
$server = parse_url(DOKU_URL, PHP_URL_HOST);
if(strpos($server,'.') === false) $server = $server.'.localhost';
$this->partid = substr(md5(uniqid(rand(), true)),0, 8).'@'.$server;
$this->boundary = '__________'.md5(uniqid(rand(), true));
$listid = join('.', array_reverse(explode('/', DOKU_BASE))).$server;
$listid = strtolower(trim($listid, '.'));
$this->allowhtml = (bool)$conf['htmlmail'];
// add some default headers for mailfiltering FS#2247
$this->setHeader('X-Mailer', 'DokuWiki');
$this->setHeader('X-DokuWiki-User', $INPUT->server->str('REMOTE_USER'));
$this->setHeader('X-DokuWiki-Title', $conf['title']);
$this->setHeader('X-DokuWiki-Server', $server);
$this->setHeader('X-Auto-Response-Suppress', 'OOF');
$this->setHeader('List-Id', $conf['title'].' <'.$listid.'>');
$this->setHeader('Date', date('r'), false);
$this->prepareTokenReplacements();
}
/**
* Attach a file
*
* @param string $path Path to the file to attach
* @param string $mime Mimetype of the attached file
* @param string $name The filename to use
* @param string $embed Unique key to reference this file from the HTML part
*/
public function attachFile($path, $mime, $name = '', $embed = '') {
if(!$name) {
$name = utf8_basename($path);
}
$this->attach[] = array(
'data' => file_get_contents($path),
'mime' => $mime,
'name' => $name,
'embed' => $embed
);
}
/**
* Attach a file
*
* @param string $data The file contents to attach
* @param string $mime Mimetype of the attached file
* @param string $name The filename to use
* @param string $embed Unique key to reference this file from the HTML part
*/
public function attachContent($data, $mime, $name = '', $embed = '') {
if(!$name) {
list(, $ext) = explode('/', $mime);
$name = count($this->attach).".$ext";
}
$this->attach[] = array(
'data' => $data,
'mime' => $mime,
'name' => $name,
'embed' => $embed
);
}
/**
* Callback function to automatically embed images referenced in HTML templates
*
* @param array $matches
* @return string placeholder
*/
protected function autoembed_cb($matches) {
static $embeds = 0;
$embeds++;
// get file and mime type
$media = cleanID($matches[1]);
list(, $mime) = mimetype($media);
$file = mediaFN($media);
if(!file_exists($file)) return $matches[0]; //bad reference, keep as is
// attach it and set placeholder
$this->attachFile($file, $mime, '', 'autoembed'.$embeds);
return '%%autoembed'.$embeds.'%%';
}
/**
* Add an arbitrary header to the mail
*
* If an empy value is passed, the header is removed
*
* @param string $header the header name (no trailing colon!)
* @param string|string[] $value the value of the header
* @param bool $clean remove all non-ASCII chars and line feeds?
*/
public function setHeader($header, $value, $clean = true) {
$header = str_replace(' ', '-', ucwords(strtolower(str_replace('-', ' ', $header)))); // streamline casing
if($clean) {
$header = preg_replace('/[^a-zA-Z0-9_ \-\.\+\@]+/', '', $header);
$value = preg_replace('/[^a-zA-Z0-9_ \-\.\+\@<>]+/', '', $value);
}
// empty value deletes
if(is_array($value)){
$value = array_map('trim', $value);
$value = array_filter($value);
if(!$value) $value = '';
}else{
$value = trim($value);
}
if($value === '') {
if(isset($this->headers[$header])) unset($this->headers[$header]);
} else {
$this->headers[$header] = $value;
}
}
/**
* Set additional parameters to be passed to sendmail
*
* Whatever is set here is directly passed to PHP's mail() command as last
* parameter. Depending on the PHP setup this might break mailing alltogether
*
* @param string $param
*/
public function setParameters($param) {
$this->sendparam = $param;
}
/**
* Set the text and HTML body and apply replacements
*
* This function applies a whole bunch of default replacements in addition
* to the ones specified as parameters
*
* If you pass the HTML part or HTML replacements yourself you have to make
* sure you encode all HTML special chars correctly
*
* @param string $text plain text body
* @param array $textrep replacements to apply on the text part
* @param array $htmlrep replacements to apply on the HTML part, leave null to use $textrep
* @param string $html the HTML body, leave null to create it from $text
* @param bool $wrap wrap the HTML in the default header/Footer
*/
public function setBody($text, $textrep = null, $htmlrep = null, $html = null, $wrap = true) {
$htmlrep = (array)$htmlrep;
$textrep = (array)$textrep;
// create HTML from text if not given
if(is_null($html)) {
$html = $text;
$html = hsc($html);
$html = preg_replace('/^----+$/m', '<hr >', $html);
$html = nl2br($html);
}
if($wrap) {
$wrap = rawLocale('mailwrap', 'html');
$html = preg_replace('/\n-- <br \/>.*$/s', '', $html); //strip signature
$html = str_replace('@EMAILSIGNATURE@', '', $html); //strip @EMAILSIGNATURE@
$html = str_replace('@HTMLBODY@', $html, $wrap);
}
if(strpos($text, '@EMAILSIGNATURE@') === false) {
$text .= '@EMAILSIGNATURE@';
}
// copy over all replacements missing for HTML (autolink URLs)
foreach($textrep as $key => $value) {
if(isset($htmlrep[$key])) continue;
if(media_isexternal($value)) {
$htmlrep[$key] = '<a href="'.hsc($value).'">'.hsc($value).'</a>';
} else {
$htmlrep[$key] = hsc($value);
}
}
// embed media from templates
$html = preg_replace_callback(
'/@MEDIA\(([^\)]+)\)@/',
array($this, 'autoembed_cb'), $html
);
// add default token replacements
$trep = array_merge($this->replacements['text'], (array)$textrep);
$hrep = array_merge($this->replacements['html'], (array)$htmlrep);
// Apply replacements
foreach($trep as $key => $substitution) {
$text = str_replace('@'.strtoupper($key).'@', $substitution, $text);
}
foreach($hrep as $key => $substitution) {
$html = str_replace('@'.strtoupper($key).'@', $substitution, $html);
}
$this->setHTML($html);
$this->setText($text);
}
/**
* Set the HTML part of the mail
*
* Placeholders can be used to reference embedded attachments
*
* You probably want to use setBody() instead
*
* @param string $html
*/
public function setHTML($html) {
$this->html = $html;
}
/**
* Set the plain text part of the mail
*
* You probably want to use setBody() instead
*
* @param string $text
*/
public function setText($text) {
$this->text = $text;
}
/**
* Add the To: recipients
*
* @see cleanAddress
* @param string|string[] $address Multiple adresses separated by commas or as array
*/
public function to($address) {
$this->setHeader('To', $address, false);
}
/**
* Add the Cc: recipients
*
* @see cleanAddress
* @param string|string[] $address Multiple adresses separated by commas or as array
*/
public function cc($address) {
$this->setHeader('Cc', $address, false);
}
/**
* Add the Bcc: recipients
*
* @see cleanAddress
* @param string|string[] $address Multiple adresses separated by commas or as array
*/
public function bcc($address) {
$this->setHeader('Bcc', $address, false);
}
/**
* Add the From: address
*
* This is set to $conf['mailfrom'] when not specified so you shouldn't need
* to call this function
*
* @see cleanAddress
* @param string $address from address
*/
public function from($address) {
$this->setHeader('From', $address, false);
}
/**
* Add the mail's Subject: header
*
* @param string $subject the mail subject
*/
public function subject($subject) {
$this->headers['Subject'] = $subject;
}
/**
* Sets an email address header with correct encoding
*
* Unicode characters will be deaccented and encoded base64
* for headers. Addresses may not contain Non-ASCII data!
*
* Example:
* cc("föö <foo@bar.com>, me@somewhere.com","TBcc");
*
* @param string|string[] $addresses Multiple adresses separated by commas or as array
* @return false|string the prepared header (can contain multiple lines)
*/
public function cleanAddress($addresses) {
// No named recipients for To: in Windows (see FS#652)
$names = (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') ? false : true;
$headers = '';
if(!is_array($addresses)){
$addresses = explode(',', $addresses);
}
foreach($addresses as $part) {
$part = preg_replace('/[\r\n\0]+/', ' ', $part); // remove attack vectors
$part = trim($part);
// parse address
if(preg_match('#(.*?)<(.*?)>#', $part, $matches)) {
$text = trim($matches[1]);
$addr = $matches[2];
} else {
$addr = $part;
}
// skip empty ones
if(empty($addr)) {
continue;
}
// FIXME: is there a way to encode the localpart of a emailaddress?
if(!utf8_isASCII($addr)) {
msg(htmlspecialchars("E-Mail address <$addr> is not ASCII"), -1);
continue;
}
if(is_null($this->validator)) {
$this->validator = new EmailAddressValidator();
$this->validator->allowLocalAddresses = true;
}
if(!$this->validator->check_email_address($addr)) {
msg(htmlspecialchars("E-Mail address <$addr> is not valid"), -1);
continue;
}
// text was given
if(!empty($text) && $names) {
// add address quotes
$addr = "<$addr>";
if(defined('MAILHEADER_ASCIIONLY')) {
$text = utf8_deaccent($text);
$text = utf8_strip($text);
}
if(strpos($text, ',') !== false || !utf8_isASCII($text)) {
$text = '=?UTF-8?B?'.base64_encode($text).'?=';
}
} else {
$text = '';
}
// add to header comma seperated
if($headers != '') {
$headers .= ', ';
}
$headers .= $text.' '.$addr;
}
$headers = trim($headers);
if(empty($headers)) return false;
return $headers;
}
/**
* Prepare the mime multiparts for all attachments
*
* Replaces placeholders in the HTML with the correct CIDs
*
* @return string mime multiparts
*/
protected function prepareAttachments() {
$mime = '';
$part = 1;
// embedded attachments
foreach($this->attach as $media) {
$media['name'] = str_replace(':', '_', cleanID($media['name'], true));
// create content id
$cid = 'part'.$part.'.'.$this->partid;
// replace wildcards
if($media['embed']) {
$this->html = str_replace('%%'.$media['embed'].'%%', 'cid:'.$cid, $this->html);
}
$mime .= '--'.$this->boundary.MAILHEADER_EOL;
$mime .= $this->wrappedHeaderLine('Content-Type', $media['mime'].'; id="'.$cid.'"');
$mime .= $this->wrappedHeaderLine('Content-Transfer-Encoding', 'base64');
$mime .= $this->wrappedHeaderLine('Content-ID',"<$cid>");
if($media['embed']) {
$mime .= $this->wrappedHeaderLine('Content-Disposition', 'inline; filename='.$media['name']);
} else {
$mime .= $this->wrappedHeaderLine('Content-Disposition', 'attachment; filename='.$media['name']);
}
$mime .= MAILHEADER_EOL; //end of headers
$mime .= chunk_split(base64_encode($media['data']), 74, MAILHEADER_EOL);
$part++;
}
return $mime;
}
/**
* Build the body and handles multi part mails
*
* Needs to be called before prepareHeaders!
*
* @return string the prepared mail body, false on errors
*/
protected function prepareBody() {
// no HTML mails allowed? remove HTML body
if(!$this->allowhtml) {
$this->html = '';
}
// check for body
if(!$this->text && !$this->html) {
return false;
}
// add general headers
$this->headers['MIME-Version'] = '1.0';
$body = '';
if(!$this->html && !count($this->attach)) { // we can send a simple single part message
$this->headers['Content-Type'] = 'text/plain; charset=UTF-8';
$this->headers['Content-Transfer-Encoding'] = 'base64';
$body .= chunk_split(base64_encode($this->text), 72, MAILHEADER_EOL);
} else { // multi part it is
$body .= "This is a multi-part message in MIME format.".MAILHEADER_EOL;
// prepare the attachments
$attachments = $this->prepareAttachments();
// do we have alternative text content?
if($this->text && $this->html) {
$this->headers['Content-Type'] = 'multipart/alternative;'.MAILHEADER_EOL.
' boundary="'.$this->boundary.'XX"';
$body .= '--'.$this->boundary.'XX'.MAILHEADER_EOL;
$body .= 'Content-Type: text/plain; charset=UTF-8'.MAILHEADER_EOL;
$body .= 'Content-Transfer-Encoding: base64'.MAILHEADER_EOL;
$body .= MAILHEADER_EOL;
$body .= chunk_split(base64_encode($this->text), 72, MAILHEADER_EOL);
$body .= '--'.$this->boundary.'XX'.MAILHEADER_EOL;
$body .= 'Content-Type: multipart/related;'.MAILHEADER_EOL.
' boundary="'.$this->boundary.'";'.MAILHEADER_EOL.
' type="text/html"'.MAILHEADER_EOL;
$body .= MAILHEADER_EOL;
}
$body .= '--'.$this->boundary.MAILHEADER_EOL;
$body .= 'Content-Type: text/html; charset=UTF-8'.MAILHEADER_EOL;
$body .= 'Content-Transfer-Encoding: base64'.MAILHEADER_EOL;
$body .= MAILHEADER_EOL;
$body .= chunk_split(base64_encode($this->html), 72, MAILHEADER_EOL);
$body .= MAILHEADER_EOL;
$body .= $attachments;
$body .= '--'.$this->boundary.'--'.MAILHEADER_EOL;
// close open multipart/alternative boundary
if($this->text && $this->html) {
$body .= '--'.$this->boundary.'XX--'.MAILHEADER_EOL;
}
}
return $body;
}
/**
* Cleanup and encode the headers array
*/
protected function cleanHeaders() {
global $conf;
// clean up addresses
if(empty($this->headers['From'])) $this->from($conf['mailfrom']);
$addrs = array('To', 'From', 'Cc', 'Bcc', 'Reply-To', 'Sender');
foreach($addrs as $addr) {
if(isset($this->headers[$addr])) {
$this->headers[$addr] = $this->cleanAddress($this->headers[$addr]);
}
}
if(isset($this->headers['Subject'])) {
// add prefix to subject
if(empty($conf['mailprefix'])) {
if(utf8_strlen($conf['title']) < 20) {
$prefix = '['.$conf['title'].']';
} else {
$prefix = '['.utf8_substr($conf['title'], 0, 20).'...]';
}
} else {
$prefix = '['.$conf['mailprefix'].']';
}
$len = strlen($prefix);
if(substr($this->headers['Subject'], 0, $len) != $prefix) {
$this->headers['Subject'] = $prefix.' '.$this->headers['Subject'];
}
// encode subject
if(defined('MAILHEADER_ASCIIONLY')) {
$this->headers['Subject'] = utf8_deaccent($this->headers['Subject']);
$this->headers['Subject'] = utf8_strip($this->headers['Subject']);
}
if(!utf8_isASCII($this->headers['Subject'])) {
$this->headers['Subject'] = '=?UTF-8?B?'.base64_encode($this->headers['Subject']).'?=';
}
}
}
/**
* Returns a complete, EOL terminated header line, wraps it if necessary
*
* @param string $key
* @param string $val
* @return string line
*/
protected function wrappedHeaderLine($key, $val){
return wordwrap("$key: $val", 78, MAILHEADER_EOL.' ').MAILHEADER_EOL;
}
/**
* Create a string from the headers array
*
* @returns string the headers
*/
protected function prepareHeaders() {
$headers = '';
foreach($this->headers as $key => $val) {
if ($val === '' || is_null($val)) continue;
$headers .= $this->wrappedHeaderLine($key, $val);
}
return $headers;
}
/**
* return a full email with all headers
*
* This is mainly intended for debugging and testing but could also be
* used for MHT exports
*
* @return string the mail, false on errors
*/
public function dump() {
$this->cleanHeaders();
$body = $this->prepareBody();
if($body === false) return false;
$headers = $this->prepareHeaders();
return $headers.MAILHEADER_EOL.$body;
}
/**
* Prepare default token replacement strings
*
* Populates the '$replacements' property.
* Should be called by the class constructor
*/
protected function prepareTokenReplacements() {
global $INFO;
global $conf;
/* @var Input $INPUT */
global $INPUT;
global $lang;
$ip = clientIP();
$cip = gethostsbyaddrs($ip);
$this->replacements['text'] = array(
'DATE' => dformat(),
'BROWSER' => $INPUT->server->str('HTTP_USER_AGENT'),
'IPADDRESS' => $ip,
'HOSTNAME' => $cip,
'TITLE' => $conf['title'],
'DOKUWIKIURL' => DOKU_URL,
'USER' => $INPUT->server->str('REMOTE_USER'),
'NAME' => $INFO['userinfo']['name'],
'MAIL' => $INFO['userinfo']['mail']
);
$signature = str_replace('@DOKUWIKIURL@', $this->replacements['text']['DOKUWIKIURL'], $lang['email_signature_text']);
$this->replacements['text']['EMAILSIGNATURE'] = "\n-- \n" . $signature . "\n";
$this->replacements['html'] = array(
'DATE' => '<i>' . hsc(dformat()) . '</i>',
'BROWSER' => hsc($INPUT->server->str('HTTP_USER_AGENT')),
'IPADDRESS' => '<code>' . hsc($ip) . '</code>',
'HOSTNAME' => '<code>' . hsc($cip) . '</code>',
'TITLE' => hsc($conf['title']),
'DOKUWIKIURL' => '<a href="' . DOKU_URL . '">' . DOKU_URL . '</a>',
'USER' => hsc($INPUT->server->str('REMOTE_USER')),
'NAME' => hsc($INFO['userinfo']['name']),
'MAIL' => '<a href="mailto:"' . hsc($INFO['userinfo']['mail']) . '">' .
hsc($INFO['userinfo']['mail']) . '</a>'
);
$signature = $lang['email_signature_text'];
if(!empty($lang['email_signature_html'])) {
$signature = $lang['email_signature_html'];
}
$signature = str_replace(
array(
'@DOKUWIKIURL@',
"\n"
),
array(
$this->replacements['html']['DOKUWIKIURL'],
'<br />'
),
$signature
);
$this->replacements['html']['EMAILSIGNATURE'] = $signature;
}
/**
* Send the mail
*
* Call this after all data was set
*
* @triggers MAIL_MESSAGE_SEND
* @return bool true if the mail was successfully passed to the MTA
*/
public function send() {
$success = false;
// prepare hook data
$data = array(
// pass the whole mail class to plugin
'mail' => $this,
// pass references for backward compatibility
'to' => &$this->headers['To'],
'cc' => &$this->headers['Cc'],
'bcc' => &$this->headers['Bcc'],
'from' => &$this->headers['From'],
'subject' => &$this->headers['Subject'],
'body' => &$this->text,
'params' => &$this->sendparam,
'headers' => '', // plugins shouldn't use this
// signal if we mailed successfully to AFTER event
'success' => &$success,
);
// do our thing if BEFORE hook approves
$evt = new Doku_Event('MAIL_MESSAGE_SEND', $data);
if($evt->advise_before(true)) {
// clean up before using the headers
$this->cleanHeaders();
// any recipients?
if(trim($this->headers['To']) === '' &&
trim($this->headers['Cc']) === '' &&
trim($this->headers['Bcc']) === ''
) return false;
// The To: header is special
if(array_key_exists('To', $this->headers)) {
$to = (string)$this->headers['To'];
unset($this->headers['To']);
} else {
$to = '';
}
// so is the subject
if(array_key_exists('Subject', $this->headers)) {
$subject = (string)$this->headers['Subject'];
unset($this->headers['Subject']);
} else {
$subject = '';
}
// make the body
$body = $this->prepareBody();
if($body === false) return false;
// cook the headers
$headers = $this->prepareHeaders();
// add any headers set by legacy plugins
if(trim($data['headers'])) {
$headers .= MAILHEADER_EOL.trim($data['headers']);
}
// send the thing
if(is_null($this->sendparam)) {
$success = @mail($to, $subject, $body, $headers);
} else {
$success = @mail($to, $subject, $body, $headers, $this->sendparam);
}
}
// any AFTER actions?
$evt->advise_after();
return $success;
}
}

View file

@ -1,636 +0,0 @@
<?php
/**
* Password Hashing Class
*
* This class implements various mechanisms used to hash passwords
*
* @author Andreas Gohr <andi@splitbrain.org>
* @license LGPL2
*/
class PassHash {
/**
* Verifies a cleartext password against a crypted hash
*
* The method and salt used for the crypted hash is determined automatically,
* then the clear text password is crypted using the same method. If both hashs
* match true is is returned else false
*
* @author Andreas Gohr <andi@splitbrain.org>
*
* @param string $clear Clear-Text password
* @param string $hash Hash to compare against
* @return bool
*/
function verify_hash($clear, $hash) {
$method = '';
$salt = '';
$magic = '';
//determine the used method and salt
$len = strlen($hash);
if(preg_match('/^\$1\$([^\$]{0,8})\$/', $hash, $m)) {
$method = 'smd5';
$salt = $m[1];
$magic = '1';
} elseif(preg_match('/^\$apr1\$([^\$]{0,8})\$/', $hash, $m)) {
$method = 'apr1';
$salt = $m[1];
$magic = 'apr1';
} elseif(preg_match('/^\$P\$(.{31})$/', $hash, $m)) {
$method = 'pmd5';
$salt = $m[1];
$magic = 'P';
} elseif(preg_match('/^\$H\$(.{31})$/', $hash, $m)) {
$method = 'pmd5';
$salt = $m[1];
$magic = 'H';
} elseif(preg_match('/^pbkdf2_(\w+?)\$(\d+)\$(.{12})\$/', $hash, $m)) {
$method = 'djangopbkdf2';
$magic = array(
'algo' => $m[1],
'iter' => $m[2],
);
$salt = $m[3];
} elseif(preg_match('/^sha1\$(.{5})\$/', $hash, $m)) {
$method = 'djangosha1';
$salt = $m[1];
} elseif(preg_match('/^md5\$(.{5})\$/', $hash, $m)) {
$method = 'djangomd5';
$salt = $m[1];
} elseif(preg_match('/^\$2(a|y)\$(.{2})\$/', $hash, $m)) {
$method = 'bcrypt';
$salt = $hash;
} elseif(substr($hash, 0, 6) == '{SSHA}') {
$method = 'ssha';
$salt = substr(base64_decode(substr($hash, 6)), 20);
} elseif(substr($hash, 0, 6) == '{SMD5}') {
$method = 'lsmd5';
$salt = substr(base64_decode(substr($hash, 6)), 16);
} elseif(preg_match('/^:B:(.+?):.{32}$/', $hash, $m)) {
$method = 'mediawiki';
$salt = $m[1];
} elseif(preg_match('/^\$6\$(.+?)\$/', $hash, $m)) {
$method = 'sha512';
$salt = $m[1];
} elseif($len == 32) {
$method = 'md5';
} elseif($len == 40) {
$method = 'sha1';
} elseif($len == 16) {
$method = 'mysql';
} elseif($len == 41 && $hash[0] == '*') {
$method = 'my411';
} elseif($len == 34) {
$method = 'kmd5';
$salt = $hash;
} else {
$method = 'crypt';
$salt = substr($hash, 0, 2);
}
//crypt and compare
$call = 'hash_'.$method;
$newhash = $this->$call($clear, $salt, $magic);
if($newhash === $hash) {
return true;
}
return false;
}
/**
* Create a random salt
*
* @param int $len The length of the salt
* @return string
*/
public function gen_salt($len = 32) {
$salt = '';
$chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
for($i = 0; $i < $len; $i++) {
$salt .= $chars[$this->random(0, 61)];
}
return $salt;
}
/**
* Initialize the passed variable with a salt if needed.
*
* If $salt is not null, the value is kept, but the lenght restriction is
* applied (unless, $cut is false).
*
* @param string|null &$salt The salt, pass null if you want one generated
* @param int $len The length of the salt
* @param bool $cut Apply length restriction to existing salt?
*/
public function init_salt(&$salt, $len = 32, $cut = true) {
if(is_null($salt)) {
$salt = $this->gen_salt($len);
$cut = true; // for new hashes we alway apply length restriction
}
if(strlen($salt) > $len && $cut) $salt = substr($salt, 0, $len);
}
// Password hashing methods follow below
/**
* Password hashing method 'smd5'
*
* Uses salted MD5 hashs. Salt is 8 bytes long.
*
* The same mechanism is used by Apache's 'apr1' method. This will
* fallback to a implementation in pure PHP if MD5 support is not
* available in crypt()
*
* @author Andreas Gohr <andi@splitbrain.org>
* @author <mikey_nich at hotmail dot com>
* @link http://php.net/manual/en/function.crypt.php#73619
*
* @param string $clear The clear text to hash
* @param string $salt The salt to use, null for random
* @return string Hashed password
*/
public function hash_smd5($clear, $salt = null) {
$this->init_salt($salt, 8);
if(defined('CRYPT_MD5') && CRYPT_MD5 && $salt !== '') {
return crypt($clear, '$1$'.$salt.'$');
} else {
// Fall back to PHP-only implementation
return $this->hash_apr1($clear, $salt, '1');
}
}
/**
* Password hashing method 'lsmd5'
*
* Uses salted MD5 hashs. Salt is 8 bytes long.
*
* This is the format used by LDAP.
*
* @param string $clear The clear text to hash
* @param string $salt The salt to use, null for random
* @return string Hashed password
*/
public function hash_lsmd5($clear, $salt = null) {
$this->init_salt($salt, 8);
return "{SMD5}".base64_encode(md5($clear.$salt, true).$salt);
}
/**
* Password hashing method 'apr1'
*
* Uses salted MD5 hashs. Salt is 8 bytes long.
*
* This is basically the same as smd1 above, but as used by Apache.
*
* @author <mikey_nich at hotmail dot com>
* @link http://php.net/manual/en/function.crypt.php#73619
*
* @param string $clear The clear text to hash
* @param string $salt The salt to use, null for random
* @param string $magic The hash identifier (apr1 or 1)
* @return string Hashed password
*/
public function hash_apr1($clear, $salt = null, $magic = 'apr1') {
$this->init_salt($salt, 8);
$len = strlen($clear);
$text = $clear.'$'.$magic.'$'.$salt;
$bin = pack("H32", md5($clear.$salt.$clear));
for($i = $len; $i > 0; $i -= 16) {
$text .= substr($bin, 0, min(16, $i));
}
for($i = $len; $i > 0; $i >>= 1) {
$text .= ($i & 1) ? chr(0) : $clear{0};
}
$bin = pack("H32", md5($text));
for($i = 0; $i < 1000; $i++) {
$new = ($i & 1) ? $clear : $bin;
if($i % 3) $new .= $salt;
if($i % 7) $new .= $clear;
$new .= ($i & 1) ? $bin : $clear;
$bin = pack("H32", md5($new));
}
$tmp = '';
for($i = 0; $i < 5; $i++) {
$k = $i + 6;
$j = $i + 12;
if($j == 16) $j = 5;
$tmp = $bin[$i].$bin[$k].$bin[$j].$tmp;
}
$tmp = chr(0).chr(0).$bin[11].$tmp;
$tmp = strtr(
strrev(substr(base64_encode($tmp), 2)),
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",
"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
);
return '$'.$magic.'$'.$salt.'$'.$tmp;
}
/**
* Password hashing method 'md5'
*
* Uses MD5 hashs.
*
* @param string $clear The clear text to hash
* @return string Hashed password
*/
public function hash_md5($clear) {
return md5($clear);
}
/**
* Password hashing method 'sha1'
*
* Uses SHA1 hashs.
*
* @param string $clear The clear text to hash
* @return string Hashed password
*/
public function hash_sha1($clear) {
return sha1($clear);
}
/**
* Password hashing method 'ssha' as used by LDAP
*
* Uses salted SHA1 hashs. Salt is 4 bytes long.
*
* @param string $clear The clear text to hash
* @param string $salt The salt to use, null for random
* @return string Hashed password
*/
public function hash_ssha($clear, $salt = null) {
$this->init_salt($salt, 4);
return '{SSHA}'.base64_encode(pack("H*", sha1($clear.$salt)).$salt);
}
/**
* Password hashing method 'crypt'
*
* Uses salted crypt hashs. Salt is 2 bytes long.
*
* @param string $clear The clear text to hash
* @param string $salt The salt to use, null for random
* @return string Hashed password
*/
public function hash_crypt($clear, $salt = null) {
$this->init_salt($salt, 2);
return crypt($clear, $salt);
}
/**
* Password hashing method 'mysql'
*
* This method was used by old MySQL systems
*
* @link http://php.net/mysql
* @author <soren at byu dot edu>
* @param string $clear The clear text to hash
* @return string Hashed password
*/
public function hash_mysql($clear) {
$nr = 0x50305735;
$nr2 = 0x12345671;
$add = 7;
$charArr = preg_split("//", $clear);
foreach($charArr as $char) {
if(($char == '') || ($char == ' ') || ($char == '\t')) continue;
$charVal = ord($char);
$nr ^= ((($nr & 63) + $add) * $charVal) + ($nr << 8);
$nr2 += ($nr2 << 8) ^ $nr;
$add += $charVal;
}
return sprintf("%08x%08x", ($nr & 0x7fffffff), ($nr2 & 0x7fffffff));
}
/**
* Password hashing method 'my411'
*
* Uses SHA1 hashs. This method is used by MySQL 4.11 and above
*
* @param string $clear The clear text to hash
* @return string Hashed password
*/
public function hash_my411($clear) {
return '*'.sha1(pack("H*", sha1($clear)));
}
/**
* Password hashing method 'kmd5'
*
* Uses salted MD5 hashs.
*
* Salt is 2 bytes long, but stored at position 16, so you need to pass at
* least 18 bytes. You can pass the crypted hash as salt.
*
* @param string $clear The clear text to hash
* @param string $salt The salt to use, null for random
* @return string Hashed password
*/
public function hash_kmd5($clear, $salt = null) {
$this->init_salt($salt);
$key = substr($salt, 16, 2);
$hash1 = strtolower(md5($key.md5($clear)));
$hash2 = substr($hash1, 0, 16).$key.substr($hash1, 16);
return $hash2;
}
/**
* Password hashing method 'pmd5'
*
* Uses salted MD5 hashs. Salt is 1+8 bytes long, 1st byte is the
* iteration count when given, for null salts $compute is used.
*
* The actual iteration count is the given count squared, maximum is
* 30 (-> 1073741824). If a higher one is given, the function throws
* an exception.
*
* @link http://www.openwall.com/phpass/
*
* @param string $clear The clear text to hash
* @param string $salt The salt to use, null for random
* @param string $magic The hash identifier (P or H)
* @param int $compute The iteration count for new passwords
* @throws Exception
* @return string Hashed password
*/
public function hash_pmd5($clear, $salt = null, $magic = 'P', $compute = 8) {
$itoa64 = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
if(is_null($salt)) {
$this->init_salt($salt);
$salt = $itoa64[$compute].$salt; // prefix iteration count
}
$iterc = $salt[0]; // pos 0 of salt is iteration count
$iter = strpos($itoa64, $iterc);
if($iter > 30) {
throw new Exception("Too high iteration count ($iter) in ".
__CLASS__.'::'.__FUNCTION__);
}
$iter = 1 << $iter;
$salt = substr($salt, 1, 8);
// iterate
$hash = md5($salt.$clear, true);
do {
$hash = md5($hash.$clear, true);
} while(--$iter);
// encode
$output = '';
$count = 16;
$i = 0;
do {
$value = ord($hash[$i++]);
$output .= $itoa64[$value & 0x3f];
if($i < $count)
$value |= ord($hash[$i]) << 8;
$output .= $itoa64[($value >> 6) & 0x3f];
if($i++ >= $count)
break;
if($i < $count)
$value |= ord($hash[$i]) << 16;
$output .= $itoa64[($value >> 12) & 0x3f];
if($i++ >= $count)
break;
$output .= $itoa64[($value >> 18) & 0x3f];
} while($i < $count);
return '$'.$magic.'$'.$iterc.$salt.$output;
}
/**
* Alias for hash_pmd5
*/
public function hash_hmd5($clear, $salt = null, $magic = 'H', $compute = 8) {
return $this->hash_pmd5($clear, $salt, $magic, $compute);
}
/**
* Password hashing method 'djangosha1'
*
* Uses salted SHA1 hashs. Salt is 5 bytes long.
* This is used by the Django Python framework
*
* @link http://docs.djangoproject.com/en/dev/topics/auth/#passwords
*
* @param string $clear The clear text to hash
* @param string $salt The salt to use, null for random
* @return string Hashed password
*/
public function hash_djangosha1($clear, $salt = null) {
$this->init_salt($salt, 5);
return 'sha1$'.$salt.'$'.sha1($salt.$clear);
}
/**
* Password hashing method 'djangomd5'
*
* Uses salted MD5 hashs. Salt is 5 bytes long.
* This is used by the Django Python framework
*
* @link http://docs.djangoproject.com/en/dev/topics/auth/#passwords
*
* @param string $clear The clear text to hash
* @param string $salt The salt to use, null for random
* @return string Hashed password
*/
public function hash_djangomd5($clear, $salt = null) {
$this->init_salt($salt, 5);
return 'md5$'.$salt.'$'.md5($salt.$clear);
}
/**
* Password hashing method 'djangopbkdf2'
*
* An algorithm and iteration count should be given in the opts array.
* Defaults to sha256 and 24000 iterations
*
* @param string $clear The clear text to hash
* @param string $salt The salt to use, null for random
* @param array $opts ('algo' => hash algorithm, 'iter' => iterations)
* @return string Hashed password
* @throws Exception when PHP is missing support for the method/algo
*/
public function hash_djangopbkdf2($clear, $salt=null, $opts=array()) {
$this->init_salt($salt, 12);
if(empty($opts['algo'])) {
$algo = 'sha256';
} else {
$algo = $opts['algo'];
}
if(empty($opts['iter'])) {
$iter = 24000;
} else {
$iter = (int) $opts['iter'];
}
if(!function_exists('hash_pbkdf2')) {
throw new Exception('This PHP installation has no PBKDF2 support');
}
if(!in_array($algo, hash_algos())) {
throw new Exception("This PHP installation has no $algo support");
}
$hash = base64_encode(hash_pbkdf2($algo, $clear, $salt, $iter, 0, true));
return "pbkdf2_$algo\$$iter\$$salt\$$hash";
}
/**
* Alias for djangopbkdf2 defaulting to sha256 as hash algorithm
*
* @param string $clear The clear text to hash
* @param string $salt The salt to use, null for random
* @param array $opts ('iter' => iterations)
* @return string Hashed password
* @throws Exception when PHP is missing support for the method/algo
*/
public function hash_djangopbkdf2_sha256($clear, $salt=null, $opts=array()) {
$opts['algo'] = 'sha256';
return $this->hash_djangopbkdf2($clear, $salt, $opts);
}
/**
* Alias for djangopbkdf2 defaulting to sha1 as hash algorithm
*
* @param string $clear The clear text to hash
* @param string $salt The salt to use, null for random
* @param array $opts ('iter' => iterations)
* @return string Hashed password
* @throws Exception when PHP is missing support for the method/algo
*/
public function hash_djangopbkdf2_sha1($clear, $salt=null, $opts=array()) {
$opts['algo'] = 'sha1';
return $this->hash_djangopbkdf2($clear, $salt, $opts);
}
/**
* Passwordhashing method 'bcrypt'
*
* Uses a modified blowfish algorithm called eksblowfish
* This method works on PHP 5.3+ only and will throw an exception
* if the needed crypt support isn't available
*
* A full hash should be given as salt (starting with $a2$) or this
* will break. When no salt is given, the iteration count can be set
* through the $compute variable.
*
* @param string $clear The clear text to hash
* @param string $salt The salt to use, null for random
* @param int $compute The iteration count (between 4 and 31)
* @throws Exception
* @return string Hashed password
*/
public function hash_bcrypt($clear, $salt = null, $compute = 8) {
if(!defined('CRYPT_BLOWFISH') || CRYPT_BLOWFISH != 1) {
throw new Exception('This PHP installation has no bcrypt support');
}
if(is_null($salt)) {
if($compute < 4 || $compute > 31) $compute = 8;
$salt = '$2a$'.str_pad($compute, 2, '0', STR_PAD_LEFT).'$'.
$this->gen_salt(22);
}
return crypt($clear, $salt);
}
/**
* Password hashing method SHA512
*
* This is only supported on PHP 5.3.2 or higher and will throw an exception if
* the needed crypt support is not available
*
* @param string $clear The clear text to hash
* @param string $salt The salt to use, null for random
* @return string Hashed password
* @throws Exception
*/
public function hash_sha512($clear, $salt = null) {
if(!defined('CRYPT_SHA512') || CRYPT_SHA512 != 1) {
throw new Exception('This PHP installation has no SHA512 support');
}
$this->init_salt($salt, 8, false);
return crypt($clear, '$6$'.$salt.'$');
}
/**
* Password hashing method 'mediawiki'
*
* Uses salted MD5, this is referred to as Method B in MediaWiki docs. Unsalted md5
* method 'A' is not supported.
*
* @link http://www.mediawiki.org/wiki/Manual_talk:User_table#user_password_column
*
* @param string $clear The clear text to hash
* @param string $salt The salt to use, null for random
* @return string Hashed password
*/
public function hash_mediawiki($clear, $salt = null) {
$this->init_salt($salt, 8, false);
return ':B:'.$salt.':'.md5($salt.'-'.md5($clear));
}
/**
* Wraps around native hash_hmac() or reimplents it
*
* This is not directly used as password hashing method, and thus isn't callable via the
* verify_hash() method. It should be used to create signatures and might be used in other
* password hashing methods.
*
* @see hash_hmac()
* @author KC Cloyd
* @link http://php.net/manual/en/function.hash-hmac.php#93440
*
* @param string $algo Name of selected hashing algorithm (i.e. "md5", "sha256", "haval160,4",
* etc..) See hash_algos() for a list of supported algorithms.
* @param string $data Message to be hashed.
* @param string $key Shared secret key used for generating the HMAC variant of the message digest.
* @param bool $raw_output When set to TRUE, outputs raw binary data. FALSE outputs lowercase hexits.
* @return string
*/
public static function hmac($algo, $data, $key, $raw_output = false) {
// use native function if available and not in unit test
if(function_exists('hash_hmac') && !defined('SIMPLE_TEST')){
return hash_hmac($algo, $data, $key, $raw_output);
}
$algo = strtolower($algo);
$pack = 'H' . strlen($algo('test'));
$size = 64;
$opad = str_repeat(chr(0x5C), $size);
$ipad = str_repeat(chr(0x36), $size);
if(strlen($key) > $size) {
$key = str_pad(pack($pack, $algo($key)), $size, chr(0x00));
} else {
$key = str_pad($key, $size, chr(0x00));
}
for($i = 0; $i < strlen($key) - 1; $i++) {
$opad[$i] = $opad[$i] ^ $key[$i];
$ipad[$i] = $ipad[$i] ^ $key[$i];
}
$output = $algo($opad . pack($pack, $algo($ipad . $data)));
return ($raw_output) ? pack($pack, $output) : $output;
}
/**
* Use DokuWiki's secure random generator if available
*
* @param int $min
* @param int $max
* @return int
*/
protected function random($min, $max){
if(function_exists('auth_random')){
return auth_random($min, $max);
}else{
return mt_rand($min, $max);
}
}
}

View file

@ -1,954 +0,0 @@
<?php
/**
* Increased whenever the API is changed
*/
define('DOKU_API_VERSION', 10);
/**
* Provides the core methods for the remote API.
* The methods are ordered in 'wiki.<method>' and 'dokuwiki.<method>' namespaces
*/
class RemoteAPICore {
private $api;
/**
* @param RemoteAPI $api
*/
public function __construct(RemoteAPI $api) {
$this->api = $api;
}
/**
* Returns details about the core methods
*
* @return array
*/
public function __getRemoteInfo() {
return array(
'dokuwiki.getVersion' => array(
'args' => array(),
'return' => 'string',
'doc' => 'Returns the running DokuWiki version.'
), 'dokuwiki.login' => array(
'args' => array('string', 'string'),
'return' => 'int',
'doc' => 'Tries to login with the given credentials and sets auth cookies.',
'public' => '1'
), 'dokuwiki.logoff' => array(
'args' => array(),
'return' => 'int',
'doc' => 'Tries to logoff by expiring auth cookies and the associated PHP session.'
), 'dokuwiki.getPagelist' => array(
'args' => array('string', 'array'),
'return' => 'array',
'doc' => 'List all pages within the given namespace.',
'name' => 'readNamespace'
), 'dokuwiki.search' => array(
'args' => array('string'),
'return' => 'array',
'doc' => 'Perform a fulltext search and return a list of matching pages'
), 'dokuwiki.getTime' => array(
'args' => array(),
'return' => 'int',
'doc' => 'Returns the current time at the remote wiki server as Unix timestamp.',
), 'dokuwiki.setLocks' => array(
'args' => array('array'),
'return' => 'array',
'doc' => 'Lock or unlock pages.'
), 'dokuwiki.getTitle' => array(
'args' => array(),
'return' => 'string',
'doc' => 'Returns the wiki title.',
'public' => '1'
), 'dokuwiki.appendPage' => array(
'args' => array('string', 'string', 'array'),
'return' => 'bool',
'doc' => 'Append text to a wiki page.'
), 'wiki.getPage' => array(
'args' => array('string'),
'return' => 'string',
'doc' => 'Get the raw Wiki text of page, latest version.',
'name' => 'rawPage',
), 'wiki.getPageVersion' => array(
'args' => array('string', 'int'),
'name' => 'rawPage',
'return' => 'string',
'doc' => 'Return a raw wiki page'
), 'wiki.getPageHTML' => array(
'args' => array('string'),
'return' => 'string',
'doc' => 'Return page in rendered HTML, latest version.',
'name' => 'htmlPage'
), 'wiki.getPageHTMLVersion' => array(
'args' => array('string', 'int'),
'return' => 'string',
'doc' => 'Return page in rendered HTML.',
'name' => 'htmlPage'
), 'wiki.getAllPages' => array(
'args' => array(),
'return' => 'array',
'doc' => 'Returns a list of all pages. The result is an array of utf8 pagenames.',
'name' => 'listPages'
), 'wiki.getAttachments' => array(
'args' => array('string', 'array'),
'return' => 'array',
'doc' => 'Returns a list of all media files.',
'name' => 'listAttachments'
), 'wiki.getBackLinks' => array(
'args' => array('string'),
'return' => 'array',
'doc' => 'Returns the pages that link to this page.',
'name' => 'listBackLinks'
), 'wiki.getPageInfo' => array(
'args' => array('string'),
'return' => 'array',
'doc' => 'Returns a struct with info about the page, latest version.',
'name' => 'pageInfo'
), 'wiki.getPageInfoVersion' => array(
'args' => array('string', 'int'),
'return' => 'array',
'doc' => 'Returns a struct with info about the page.',
'name' => 'pageInfo'
), 'wiki.getPageVersions' => array(
'args' => array('string', 'int'),
'return' => 'array',
'doc' => 'Returns the available revisions of the page.',
'name' => 'pageVersions'
), 'wiki.putPage' => array(
'args' => array('string', 'string', 'array'),
'return' => 'bool',
'doc' => 'Saves a wiki page.'
), 'wiki.listLinks' => array(
'args' => array('string'),
'return' => 'array',
'doc' => 'Lists all links contained in a wiki page.'
), 'wiki.getRecentChanges' => array(
'args' => array('int'),
'return' => 'array',
'Returns a struct about all recent changes since given timestamp.'
), 'wiki.getRecentMediaChanges' => array(
'args' => array('int'),
'return' => 'array',
'Returns a struct about all recent media changes since given timestamp.'
), 'wiki.aclCheck' => array(
'args' => array('string', 'string', 'array'),
'return' => 'int',
'doc' => 'Returns the permissions of a given wiki page. By default, for current user/groups'
), 'wiki.putAttachment' => array(
'args' => array('string', 'file', 'array'),
'return' => 'array',
'doc' => 'Upload a file to the wiki.'
), 'wiki.deleteAttachment' => array(
'args' => array('string'),
'return' => 'int',
'doc' => 'Delete a file from the wiki.'
), 'wiki.getAttachment' => array(
'args' => array('string'),
'doc' => 'Return a media file',
'return' => 'file',
'name' => 'getAttachment',
), 'wiki.getAttachmentInfo' => array(
'args' => array('string'),
'return' => 'array',
'doc' => 'Returns a struct with info about the attachment.'
), 'dokuwiki.getXMLRPCAPIVersion' => array(
'args' => array(),
'name' => 'getAPIVersion',
'return' => 'int',
'doc' => 'Returns the XMLRPC API version.',
'public' => '1',
), 'wiki.getRPCVersionSupported' => array(
'args' => array(),
'name' => 'wiki_RPCVersion',
'return' => 'int',
'doc' => 'Returns 2 with the supported RPC API version.',
'public' => '1'
),
);
}
/**
* @return string
*/
public function getVersion() {
return getVersion();
}
/**
* @return int unix timestamp
*/
public function getTime() {
return time();
}
/**
* Return a raw wiki page
*
* @param string $id wiki page id
* @param int|string $rev revision timestamp of the page or empty string
* @return string page text.
* @throws RemoteAccessDeniedException if no permission for page
*/
public function rawPage($id,$rev=''){
$id = $this->resolvePageId($id);
if(auth_quickaclcheck($id) < AUTH_READ){
throw new RemoteAccessDeniedException('You are not allowed to read this file', 111);
}
$text = rawWiki($id,$rev);
if(!$text) {
return pageTemplate($id);
} else {
return $text;
}
}
/**
* Return a media file
*
* @author Gina Haeussge <osd@foosel.net>
*
* @param string $id file id
* @return mixed media file
* @throws RemoteAccessDeniedException no permission for media
* @throws RemoteException not exist
*/
public function getAttachment($id){
$id = cleanID($id);
if (auth_quickaclcheck(getNS($id).':*') < AUTH_READ) {
throw new RemoteAccessDeniedException('You are not allowed to read this file', 211);
}
$file = mediaFN($id);
if (!@ file_exists($file)) {
throw new RemoteException('The requested file does not exist', 221);
}
$data = io_readFile($file, false);
return $this->api->toFile($data);
}
/**
* Return info about a media file
*
* @author Gina Haeussge <osd@foosel.net>
*
* @param string $id page id
* @return array
*/
public function getAttachmentInfo($id){
$id = cleanID($id);
$info = array(
'lastModified' => $this->api->toDate(0),
'size' => 0,
);
$file = mediaFN($id);
if(auth_quickaclcheck(getNS($id) . ':*') >= AUTH_READ) {
if(file_exists($file)) {
$info['lastModified'] = $this->api->toDate(filemtime($file));
$info['size'] = filesize($file);
} else {
//Is it deleted media with changelog?
$medialog = new MediaChangeLog($id);
$revisions = $medialog->getRevisions(0, 1);
if(!empty($revisions)) {
$info['lastModified'] = $this->api->toDate($revisions[0]);
}
}
}
return $info;
}
/**
* Return a wiki page rendered to html
*
* @param string $id page id
* @param string|int $rev revision timestamp or empty string
* @return null|string html
* @throws RemoteAccessDeniedException no access to page
*/
public function htmlPage($id,$rev=''){
$id = $this->resolvePageId($id);
if(auth_quickaclcheck($id) < AUTH_READ){
throw new RemoteAccessDeniedException('You are not allowed to read this page', 111);
}
return p_wiki_xhtml($id,$rev,false);
}
/**
* List all pages - we use the indexer list here
*
* @return array
*/
public function listPages(){
$list = array();
$pages = idx_get_indexer()->getPages();
$pages = array_filter(array_filter($pages,'isVisiblePage'),'page_exists');
foreach(array_keys($pages) as $idx) {
$perm = auth_quickaclcheck($pages[$idx]);
if($perm < AUTH_READ) {
continue;
}
$page = array();
$page['id'] = trim($pages[$idx]);
$page['perms'] = $perm;
$page['size'] = @filesize(wikiFN($pages[$idx]));
$page['lastModified'] = $this->api->toDate(@filemtime(wikiFN($pages[$idx])));
$list[] = $page;
}
return $list;
}
/**
* List all pages in the given namespace (and below)
*
* @param string $ns
* @param array $opts
* $opts['depth'] recursion level, 0 for all
* $opts['hash'] do md5 sum of content?
* @return array
*/
public function readNamespace($ns,$opts){
global $conf;
if(!is_array($opts)) $opts=array();
$ns = cleanID($ns);
$dir = utf8_encodeFN(str_replace(':', '/', $ns));
$data = array();
$opts['skipacl'] = 0; // no ACL skipping for XMLRPC
search($data, $conf['datadir'], 'search_allpages', $opts, $dir);
return $data;
}
/**
* List all pages in the given namespace (and below)
*
* @param string $query
* @return array
*/
public function search($query){
$regex = array();
$data = ft_pageSearch($query,$regex);
$pages = array();
// prepare additional data
$idx = 0;
foreach($data as $id => $score){
$file = wikiFN($id);
if($idx < FT_SNIPPET_NUMBER){
$snippet = ft_snippet($id,$regex);
$idx++;
}else{
$snippet = '';
}
$pages[] = array(
'id' => $id,
'score' => intval($score),
'rev' => filemtime($file),
'mtime' => filemtime($file),
'size' => filesize($file),
'snippet' => $snippet,
'title' => useHeading('navigation') ? p_get_first_heading($id) : $id
);
}
return $pages;
}
/**
* Returns the wiki title.
*
* @return string
*/
public function getTitle(){
global $conf;
return $conf['title'];
}
/**
* List all media files.
*
* Available options are 'recursive' for also including the subnamespaces
* in the listing, and 'pattern' for filtering the returned files against
* a regular expression matching their name.
*
* @author Gina Haeussge <osd@foosel.net>
*
* @param string $ns
* @param array $options
* $options['depth'] recursion level, 0 for all
* $options['showmsg'] shows message if invalid media id is used
* $options['pattern'] check given pattern
* $options['hash'] add hashes to result list
* @return array
* @throws RemoteAccessDeniedException no access to the media files
*/
public function listAttachments($ns, $options = array()) {
global $conf;
$ns = cleanID($ns);
if (!is_array($options)) $options = array();
$options['skipacl'] = 0; // no ACL skipping for XMLRPC
if(auth_quickaclcheck($ns.':*') >= AUTH_READ) {
$dir = utf8_encodeFN(str_replace(':', '/', $ns));
$data = array();
search($data, $conf['mediadir'], 'search_media', $options, $dir);
$len = count($data);
if(!$len) return array();
for($i=0; $i<$len; $i++) {
unset($data[$i]['meta']);
$data[$i]['perms'] = $data[$i]['perm'];
unset($data[$i]['perm']);
$data[$i]['lastModified'] = $this->api->toDate($data[$i]['mtime']);
}
return $data;
} else {
throw new RemoteAccessDeniedException('You are not allowed to list media files.', 215);
}
}
/**
* Return a list of backlinks
*
* @param string $id page id
* @return array
*/
function listBackLinks($id){
return ft_backlinks($this->resolvePageId($id));
}
/**
* Return some basic data about a page
*
* @param string $id page id
* @param string|int $rev revision timestamp or empty string
* @return array
* @throws RemoteAccessDeniedException no access for page
* @throws RemoteException page not exist
*/
public function pageInfo($id,$rev=''){
$id = $this->resolvePageId($id);
if(auth_quickaclcheck($id) < AUTH_READ){
throw new RemoteAccessDeniedException('You are not allowed to read this page', 111);
}
$file = wikiFN($id,$rev);
$time = @filemtime($file);
if(!$time){
throw new RemoteException('The requested page does not exist', 121);
}
$pagelog = new PageChangeLog($id, 1024);
$info = $pagelog->getRevisionInfo($time);
$data = array(
'name' => $id,
'lastModified' => $this->api->toDate($time),
'author' => (($info['user']) ? $info['user'] : $info['ip']),
'version' => $time
);
return ($data);
}
/**
* Save a wiki page
*
* @author Michael Klier <chi@chimeric.de>
*
* @param string $id page id
* @param string $text wiki text
* @param array $params parameters: summary, minor edit
* @return bool
* @throws RemoteAccessDeniedException no write access for page
* @throws RemoteException no id, empty new page or locked
*/
public function putPage($id, $text, $params) {
global $TEXT;
global $lang;
$id = $this->resolvePageId($id);
$TEXT = cleanText($text);
$sum = $params['sum'];
$minor = $params['minor'];
if(empty($id)) {
throw new RemoteException('Empty page ID', 131);
}
if(!page_exists($id) && trim($TEXT) == '' ) {
throw new RemoteException('Refusing to write an empty new wiki page', 132);
}
if(auth_quickaclcheck($id) < AUTH_EDIT) {
throw new RemoteAccessDeniedException('You are not allowed to edit this page', 112);
}
// Check, if page is locked
if(checklock($id)) {
throw new RemoteException('The page is currently locked', 133);
}
// SPAM check
if(checkwordblock()) {
throw new RemoteException('Positive wordblock check', 134);
}
// autoset summary on new pages
if(!page_exists($id) && empty($sum)) {
$sum = $lang['created'];
}
// autoset summary on deleted pages
if(page_exists($id) && empty($TEXT) && empty($sum)) {
$sum = $lang['deleted'];
}
lock($id);
saveWikiText($id,$TEXT,$sum,$minor);
unlock($id);
// run the indexer if page wasn't indexed yet
idx_addPage($id);
return true;
}
/**
* Appends text to a wiki page.
*
* @param string $id page id
* @param string $text wiki text
* @param array $params such as summary,minor
* @return bool|string
*/
public function appendPage($id, $text, $params) {
$currentpage = $this->rawPage($id);
if (!is_string($currentpage)) {
return $currentpage;
}
return $this->putPage($id, $currentpage.$text, $params);
}
/**
* Uploads a file to the wiki.
*
* Michael Klier <chi@chimeric.de>
*
* @param string $id page id
* @param string $file
* @param array $params such as overwrite
* @return false|string
* @throws RemoteException
*/
public function putAttachment($id, $file, $params) {
$id = cleanID($id);
$auth = auth_quickaclcheck(getNS($id).':*');
if(!isset($id)) {
throw new RemoteException('Filename not given.', 231);
}
global $conf;
$ftmp = $conf['tmpdir'] . '/' . md5($id.clientIP());
// save temporary file
@unlink($ftmp);
io_saveFile($ftmp, $file);
$res = media_save(array('name' => $ftmp), $id, $params['ow'], $auth, 'rename');
if (is_array($res)) {
throw new RemoteException($res[0], -$res[1]);
} else {
return $res;
}
}
/**
* Deletes a file from the wiki.
*
* @author Gina Haeussge <osd@foosel.net>
*
* @param string $id page id
* @return int
* @throws RemoteAccessDeniedException no permissions
* @throws RemoteException file in use or not deleted
*/
public function deleteAttachment($id){
$id = cleanID($id);
$auth = auth_quickaclcheck(getNS($id).':*');
$res = media_delete($id, $auth);
if ($res & DOKU_MEDIA_DELETED) {
return 0;
} elseif ($res & DOKU_MEDIA_NOT_AUTH) {
throw new RemoteAccessDeniedException('You don\'t have permissions to delete files.', 212);
} elseif ($res & DOKU_MEDIA_INUSE) {
throw new RemoteException('File is still referenced', 232);
} else {
throw new RemoteException('Could not delete file', 233);
}
}
/**
* Returns the permissions of a given wiki page for the current user or another user
*
* @param string $id page id
* @param string|null $user username
* @param array|null $groups array of groups
* @return int permission level
*/
public function aclCheck($id, $user = null, $groups = null) {
/** @var DokuWiki_Auth_Plugin $auth */
global $auth;
$id = $this->resolvePageId($id);
if($user === null) {
return auth_quickaclcheck($id);
} else {
if($groups === null) {
$userinfo = $auth->getUserData($user);
if($userinfo === false) {
$groups = array();
} else {
$groups = $userinfo['grps'];
}
}
return auth_aclcheck($id, $user, $groups);
}
}
/**
* Lists all links contained in a wiki page
*
* @author Michael Klier <chi@chimeric.de>
*
* @param string $id page id
* @return array
* @throws RemoteAccessDeniedException no read access for page
*/
public function listLinks($id) {
$id = $this->resolvePageId($id);
if(auth_quickaclcheck($id) < AUTH_READ){
throw new RemoteAccessDeniedException('You are not allowed to read this page', 111);
}
$links = array();
// resolve page instructions
$ins = p_cached_instructions(wikiFN($id));
// instantiate new Renderer - needed for interwiki links
$Renderer = new Doku_Renderer_xhtml();
$Renderer->interwiki = getInterwiki();
// parse parse instructions
foreach($ins as $in) {
$link = array();
switch($in[0]) {
case 'internallink':
$link['type'] = 'local';
$link['page'] = $in[1][0];
$link['href'] = wl($in[1][0]);
array_push($links,$link);
break;
case 'externallink':
$link['type'] = 'extern';
$link['page'] = $in[1][0];
$link['href'] = $in[1][0];
array_push($links,$link);
break;
case 'interwikilink':
$url = $Renderer->_resolveInterWiki($in[1][2],$in[1][3]);
$link['type'] = 'extern';
$link['page'] = $url;
$link['href'] = $url;
array_push($links,$link);
break;
}
}
return ($links);
}
/**
* Returns a list of recent changes since give timestamp
*
* @author Michael Hamann <michael@content-space.de>
* @author Michael Klier <chi@chimeric.de>
*
* @param int $timestamp unix timestamp
* @return array
* @throws RemoteException no valid timestamp
*/
public function getRecentChanges($timestamp) {
if(strlen($timestamp) != 10) {
throw new RemoteException('The provided value is not a valid timestamp', 311);
}
$recents = getRecentsSince($timestamp);
$changes = array();
foreach ($recents as $recent) {
$change = array();
$change['name'] = $recent['id'];
$change['lastModified'] = $this->api->toDate($recent['date']);
$change['author'] = $recent['user'];
$change['version'] = $recent['date'];
$change['perms'] = $recent['perms'];
$change['size'] = @filesize(wikiFN($recent['id']));
array_push($changes, $change);
}
if (!empty($changes)) {
return $changes;
} else {
// in case we still have nothing at this point
throw new RemoteException('There are no changes in the specified timeframe', 321);
}
}
/**
* Returns a list of recent media changes since give timestamp
*
* @author Michael Hamann <michael@content-space.de>
* @author Michael Klier <chi@chimeric.de>
*
* @param int $timestamp unix timestamp
* @return array
* @throws RemoteException no valid timestamp
*/
public function getRecentMediaChanges($timestamp) {
if(strlen($timestamp) != 10)
throw new RemoteException('The provided value is not a valid timestamp', 311);
$recents = getRecentsSince($timestamp, null, '', RECENTS_MEDIA_CHANGES);
$changes = array();
foreach ($recents as $recent) {
$change = array();
$change['name'] = $recent['id'];
$change['lastModified'] = $this->api->toDate($recent['date']);
$change['author'] = $recent['user'];
$change['version'] = $recent['date'];
$change['perms'] = $recent['perms'];
$change['size'] = @filesize(mediaFN($recent['id']));
array_push($changes, $change);
}
if (!empty($changes)) {
return $changes;
} else {
// in case we still have nothing at this point
throw new RemoteException('There are no changes in the specified timeframe', 321);
}
}
/**
* Returns a list of available revisions of a given wiki page
* Number of returned pages is set by $conf['recent']
* However not accessible pages are skipped, so less than $conf['recent'] could be returned
*
* @author Michael Klier <chi@chimeric.de>
*
* @param string $id page id
* @param int $first skip the first n changelog lines (0 = from current(if exists), 1 = from 1st old rev, 2 = from 2nd old rev, etc)
* @return array
* @throws RemoteAccessDeniedException no read access for page
* @throws RemoteException empty id
*/
public function pageVersions($id, $first) {
$id = $this->resolvePageId($id);
if(auth_quickaclcheck($id) < AUTH_READ) {
throw new RemoteAccessDeniedException('You are not allowed to read this page', 111);
}
global $conf;
$versions = array();
if(empty($id)) {
throw new RemoteException('Empty page ID', 131);
}
$first = (int) $first;
$first_rev = $first - 1;
$first_rev = $first_rev < 0 ? 0 : $first_rev;
$pagelog = new PageChangeLog($id);
$revisions = $pagelog->getRevisions($first_rev, $conf['recent']);
if($first == 0) {
array_unshift($revisions, ''); // include current revision
if ( count($revisions) > $conf['recent'] ){
array_pop($revisions); // remove extra log entry
}
}
if(!empty($revisions)) {
foreach($revisions as $rev) {
$file = wikiFN($id,$rev);
$time = @filemtime($file);
// we check if the page actually exists, if this is not the
// case this can lead to less pages being returned than
// specified via $conf['recent']
if($time){
$pagelog->setChunkSize(1024);
$info = $pagelog->getRevisionInfo($time);
if(!empty($info)) {
$data = array();
$data['user'] = $info['user'];
$data['ip'] = $info['ip'];
$data['type'] = $info['type'];
$data['sum'] = $info['sum'];
$data['modified'] = $this->api->toDate($info['date']);
$data['version'] = $info['date'];
array_push($versions, $data);
}
}
}
return $versions;
} else {
return array();
}
}
/**
* The version of Wiki RPC API supported
*/
public function wiki_RPCVersion(){
return 2;
}
/**
* Locks or unlocks a given batch of pages
*
* Give an associative array with two keys: lock and unlock. Both should contain a
* list of pages to lock or unlock
*
* Returns an associative array with the keys locked, lockfail, unlocked and
* unlockfail, each containing lists of pages.
*
* @param array[] $set list pages with array('lock' => array, 'unlock' => array)
* @return array
*/
public function setLocks($set){
$locked = array();
$lockfail = array();
$unlocked = array();
$unlockfail = array();
foreach((array) $set['lock'] as $id){
$id = $this->resolvePageId($id);
if(auth_quickaclcheck($id) < AUTH_EDIT || checklock($id)){
$lockfail[] = $id;
}else{
lock($id);
$locked[] = $id;
}
}
foreach((array) $set['unlock'] as $id){
$id = $this->resolvePageId($id);
if(auth_quickaclcheck($id) < AUTH_EDIT || !unlock($id)){
$unlockfail[] = $id;
}else{
$unlocked[] = $id;
}
}
return array(
'locked' => $locked,
'lockfail' => $lockfail,
'unlocked' => $unlocked,
'unlockfail' => $unlockfail,
);
}
/**
* Return API version
*
* @return int
*/
public function getAPIVersion(){
return DOKU_API_VERSION;
}
/**
* Login
*
* @param string $user
* @param string $pass
* @return int
*/
public function login($user,$pass){
global $conf;
/** @var DokuWiki_Auth_Plugin $auth */
global $auth;
if(!$conf['useacl']) return 0;
if(!$auth) return 0;
@session_start(); // reopen session for login
if($auth->canDo('external')){
$ok = $auth->trustExternal($user,$pass,false);
}else{
$evdata = array(
'user' => $user,
'password' => $pass,
'sticky' => false,
'silent' => true,
);
$ok = trigger_event('AUTH_LOGIN_CHECK', $evdata, 'auth_login_wrapper');
}
session_write_close(); // we're done with the session
return $ok;
}
/**
* Log off
*
* @return int
*/
public function logoff(){
global $conf;
global $auth;
if(!$conf['useacl']) return 0;
if(!$auth) return 0;
auth_logoff();
return 1;
}
/**
* Resolve page id
*
* @param string $id page id
* @return string
*/
private function resolvePageId($id) {
$id = cleanID($id);
if(empty($id)) {
global $conf;
$id = cleanID($conf['start']);
}
return $id;
}
}

View file

@ -1,158 +0,0 @@
<?php
/**
* Class to safely store UTF-8 in a Filename
*
* Encodes a utf8 string using only the following characters 0-9a-z_.-%
* characters 0-9a-z in the original string are preserved, "plain".
* all other characters are represented in a substring that starts
* with '%' are "converted".
* The transition from converted substrings to plain characters is
* marked with a '.'
*
* @author Christopher Smith <chris@jalakai.co.uk>
* @date 2010-04-02
*/
class SafeFN {
// 'safe' characters are a superset of $plain, $pre_indicator and $post_indicator
private static $plain = '-./[_0123456789abcdefghijklmnopqrstuvwxyz'; // these characters aren't converted
private static $pre_indicator = '%';
private static $post_indicator = ']';
/**
* Convert an UTF-8 string to a safe ASCII String
*
* conversion process
* - if codepoint is a plain or post_indicator character,
* - if previous character was "converted", append post_indicator to output, clear "converted" flag
* - append ascii byte for character to output
* (continue to next character)
*
* - if codepoint is a pre_indicator character,
* - append ascii byte for character to output, set "converted" flag
* (continue to next character)
*
* (all remaining characters)
* - reduce codepoint value for non-printable ASCII characters (0x00 - 0x1f). Space becomes our zero.
* - convert reduced value to base36 (0-9a-z)
* - append $pre_indicator characater followed by base36 string to output, set converted flag
* (continue to next character)
*
* @param string $filename a utf8 string, should only include printable characters - not 0x00-0x1f
* @return string an encoded representation of $filename using only 'safe' ASCII characters
*
* @author Christopher Smith <chris@jalakai.co.uk>
*/
public static function encode($filename) {
return self::unicode_to_safe(utf8_to_unicode($filename));
}
/**
* decoding process
* - split the string into substrings at any occurrence of pre or post indicator characters
* - check the first character of the substring
* - if its not a pre_indicator character
* - if previous character was converted, skip over post_indicator character
* - copy codepoint values of remaining characters to the output array
* - clear any converted flag
* (continue to next substring)
*
* _ else (its a pre_indicator character)
* - if string length is 1, copy the post_indicator character to the output array
* (continue to next substring)
*
* - else (string length > 1)
* - skip the pre-indicator character and convert remaining string from base36 to base10
* - increase codepoint value for non-printable ASCII characters (add 0x20)
* - append codepoint to output array
* (continue to next substring)
*
* @param string $filename a 'safe' encoded ASCII string,
* @return string decoded utf8 representation of $filename
*
* @author Christopher Smith <chris@jalakai.co.uk>
*/
public static function decode($filename) {
return unicode_to_utf8(self::safe_to_unicode(strtolower($filename)));
}
public static function validate_printable_utf8($printable_utf8) {
return !preg_match('#[\x01-\x1f]#',$printable_utf8);
}
public static function validate_safe($safe) {
return !preg_match('#[^'.self::$plain.self::$post_indicator.self::$pre_indicator.']#',$safe);
}
/**
* convert an array of unicode codepoints into 'safe_filename' format
*
* @param array int $unicode an array of unicode codepoints
* @return string the unicode represented in 'safe_filename' format
*
* @author Christopher Smith <chris@jalakai.co.uk>
*/
private static function unicode_to_safe($unicode) {
$safe = '';
$converted = false;
foreach ($unicode as $codepoint) {
if ($codepoint < 127 && (strpos(self::$plain.self::$post_indicator,chr($codepoint))!==false)) {
if ($converted) {
$safe .= self::$post_indicator;
$converted = false;
}
$safe .= chr($codepoint);
} else if ($codepoint == ord(self::$pre_indicator)) {
$safe .= self::$pre_indicator;
$converted = true;
} else {
$safe .= self::$pre_indicator.base_convert((string)($codepoint-32),10,36);
$converted = true;
}
}
if($converted) $safe .= self::$post_indicator;
return $safe;
}
/**
* convert a 'safe_filename' string into an array of unicode codepoints
*
* @param string $safe a filename in 'safe_filename' format
* @return array int an array of unicode codepoints
*
* @author Christopher Smith <chris@jalakai.co.uk>
*/
private static function safe_to_unicode($safe) {
$unicode = array();
$split = preg_split('#(?=['.self::$post_indicator.self::$pre_indicator.'])#',$safe,-1,PREG_SPLIT_NO_EMPTY);
$converted = false;
foreach ($split as $sub) {
$len = strlen($sub);
if ($sub[0] != self::$pre_indicator) {
// plain (unconverted) characters, optionally starting with a post_indicator
// set initial value to skip any post_indicator
for ($i=($converted?1:0); $i < $len; $i++) {
$unicode[] = ord($sub[$i]);
}
$converted = false;
} else if ($len==1) {
// a pre_indicator character in the real data
$unicode[] = ord($sub);
$converted = true;
} else {
// a single codepoint in base36, adjusted for initial 32 non-printable chars
$unicode[] = 32 + (int)base_convert(substr($sub,1),36,10);
$converted = true;
}
}
return $unicode;
}
}

File diff suppressed because it is too large Load diff

View file

@ -1,220 +0,0 @@
<?php
/**
* Sitemap handling functions
*
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
* @author Michael Hamann <michael@content-space.de>
*/
if(!defined('DOKU_INC')) die('meh.');
/**
* A class for building sitemaps and pinging search engines with the sitemap URL.
*
* @author Michael Hamann
*/
class Sitemapper {
/**
* Builds a Google Sitemap of all public pages known to the indexer
*
* The map is placed in the cache directory named sitemap.xml.gz - This
* file needs to be writable!
*
* @author Michael Hamann
* @author Andreas Gohr
* @link https://www.google.com/webmasters/sitemaps/docs/en/about.html
* @link http://www.sitemaps.org/
*
* @return bool
*/
public static function generate(){
global $conf;
if($conf['sitemap'] < 1 || !is_numeric($conf['sitemap'])) return false;
$sitemap = Sitemapper::getFilePath();
if(file_exists($sitemap)){
if(!is_writable($sitemap)) return false;
}else{
if(!is_writable(dirname($sitemap))) return false;
}
if(@filesize($sitemap) &&
@filemtime($sitemap) > (time()-($conf['sitemap']*86400))){ // 60*60*24=86400
dbglog('Sitemapper::generate(): Sitemap up to date');
return false;
}
dbglog("Sitemapper::generate(): using $sitemap");
$pages = idx_get_indexer()->getPages();
dbglog('Sitemapper::generate(): creating sitemap using '.count($pages).' pages');
$items = array();
// build the sitemap items
foreach($pages as $id){
//skip hidden, non existing and restricted files
if(isHiddenPage($id)) continue;
if(auth_aclcheck($id,'',array()) < AUTH_READ) continue;
$item = SitemapItem::createFromID($id);
if ($item !== null)
$items[] = $item;
}
$eventData = array('items' => &$items, 'sitemap' => &$sitemap);
$event = new Doku_Event('SITEMAP_GENERATE', $eventData);
if ($event->advise_before(true)) {
//save the new sitemap
$event->result = io_saveFile($sitemap, Sitemapper::getXML($items));
}
$event->advise_after();
return $event->result;
}
/**
* Builds the sitemap XML string from the given array auf SitemapItems.
*
* @param $items array The SitemapItems that shall be included in the sitemap.
* @return string The sitemap XML.
*
* @author Michael Hamann
*/
private static function getXML($items) {
ob_start();
echo '<?xml version="1.0" encoding="UTF-8"?>'.NL;
echo '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">'.NL;
foreach ($items as $item) {
/** @var SitemapItem $item */
echo $item->toXML();
}
echo '</urlset>'.NL;
$result = ob_get_contents();
ob_end_clean();
return $result;
}
/**
* Helper function for getting the path to the sitemap file.
*
* @return string The path to the sitemap file.
*
* @author Michael Hamann
*/
public static function getFilePath() {
global $conf;
$sitemap = $conf['cachedir'].'/sitemap.xml';
if (self::sitemapIsCompressed()) {
$sitemap .= '.gz';
}
return $sitemap;
}
/**
* Helper function for checking if the sitemap is compressed
*
* @return bool If the sitemap file is compressed
*/
public static function sitemapIsCompressed() {
global $conf;
return $conf['compression'] === 'bz2' || $conf['compression'] === 'gz';
}
/**
* Pings search engines with the sitemap url. Plugins can add or remove
* urls to ping using the SITEMAP_PING event.
*
* @author Michael Hamann
*
* @return bool
*/
public static function pingSearchEngines() {
//ping search engines...
$http = new DokuHTTPClient();
$http->timeout = 8;
$encoded_sitemap_url = urlencode(wl('', array('do' => 'sitemap'), true, '&'));
$ping_urls = array(
'google' => 'http://www.google.com/webmasters/sitemaps/ping?sitemap='.$encoded_sitemap_url,
'microsoft' => 'http://www.bing.com/webmaster/ping.aspx?siteMap='.$encoded_sitemap_url,
'yandex' => 'http://blogs.yandex.ru/pings/?status=success&url='.$encoded_sitemap_url
);
$data = array('ping_urls' => $ping_urls,
'encoded_sitemap_url' => $encoded_sitemap_url
);
$event = new Doku_Event('SITEMAP_PING', $data);
if ($event->advise_before(true)) {
foreach ($data['ping_urls'] as $name => $url) {
dbglog("Sitemapper::PingSearchEngines(): pinging $name");
$resp = $http->get($url);
if($http->error) dbglog("Sitemapper:pingSearchengines(): $http->error");
dbglog('Sitemapper:pingSearchengines(): '.preg_replace('/[\n\r]/',' ',strip_tags($resp)));
}
}
$event->advise_after();
return true;
}
}
/**
* An item of a sitemap.
*
* @author Michael Hamann
*/
class SitemapItem {
public $url;
public $lastmod;
public $changefreq;
public $priority;
/**
* Create a new item.
*
* @param string $url The url of the item
* @param int $lastmod Timestamp of the last modification
* @param string $changefreq How frequently the item is likely to change. Valid values: always, hourly, daily, weekly, monthly, yearly, never.
* @param $priority float|string The priority of the item relative to other URLs on your site. Valid values range from 0.0 to 1.0.
*/
public function __construct($url, $lastmod, $changefreq = null, $priority = null) {
$this->url = $url;
$this->lastmod = $lastmod;
$this->changefreq = $changefreq;
$this->priority = $priority;
}
/**
* Helper function for creating an item for a wikipage id.
*
* @param string $id A wikipage id.
* @param string $changefreq How frequently the item is likely to change. Valid values: always, hourly, daily, weekly, monthly, yearly, never.
* @param float|string $priority The priority of the item relative to other URLs on your site. Valid values range from 0.0 to 1.0.
* @return SitemapItem The sitemap item.
*/
public static function createFromID($id, $changefreq = null, $priority = null) {
$id = trim($id);
$date = @filemtime(wikiFN($id));
if(!$date) return null;
return new SitemapItem(wl($id, '', true), $date, $changefreq, $priority);
}
/**
* Get the XML representation of the sitemap item.
*
* @return string The XML representation.
*/
public function toXML() {
$result = ' <url>'.NL
.' <loc>'.hsc($this->url).'</loc>'.NL
.' <lastmod>'.date_iso8601($this->lastmod).'</lastmod>'.NL;
if ($this->changefreq !== null)
$result .= ' <changefreq>'.hsc($this->changefreq).'</changefreq>'.NL;
if ($this->priority !== null)
$result .= ' <priority>'.hsc($this->priority).'</priority>'.NL;
$result .= ' </url>'.NL;
return $result;
}
}

View file

@ -1,648 +0,0 @@
<?php
/**
* This class allows the extraction of existing and the creation of new Unix TAR archives.
* To keep things simple, the modification of existing archives is not supported. It handles
* uncompressed, gzip and bzip2 compressed tar files.
*
* Long pathnames (>100 chars) are supported in POSIX ustar and GNU longlink formats.
*
* To list the contents of an existing TAR archive, open() it and use contents() on it:
*
* $tar = new Tar();
* $tar->open('myfile.tgz');
* $toc = $tar->contents();
* print_r($toc);
*
* To extract the contents of an existing TAR archive, open() it and use extract() on it:
*
* $tar = new Tar();
* $tar->open('myfile.tgz');
* $tar->extract('/tmp');
*
* To create a new TAR archive directly on the filesystem (low memory requirements), create() it,
* add*() files and close() it:
*
* $tar = new Tar();
* $tar->create('myfile.tgz');
* $tar->addFile(...);
* $tar->addData(...);
* ...
* $tar->close();
*
* To create a TAR archive directly in memory, create() it, add*() files and then either save()
* or getData() it:
*
* $tar = new Tar();
* $tar->create();
* $tar->addFile(...);
* $tar->addData(...);
* ...
* $tar->save('myfile.tgz'); // compresses and saves it
* echo $tar->getArchive(Tar::COMPRESS_GZIP); // compresses and returns it
*
* @author Andreas Gohr <andi@splitbrain.org>
* @author Bouchon <tarlib@bouchon.org> (Maxg)
* @license GPL 2
* @deprecated 2015-05-15 - use splitbrain\PHPArchive\Tar instead
*/
class Tar {
const COMPRESS_AUTO = 0;
const COMPRESS_NONE = 1;
const COMPRESS_GZIP = 2;
const COMPRESS_BZIP = 3;
protected $file = '';
protected $comptype = Tar::COMPRESS_AUTO;
/** @var resource|int */
protected $fh;
protected $memory = '';
protected $closed = true;
protected $writeaccess = false;
/**
* Open an existing TAR file for reading
*
* @param string $file
* @param int $comptype
* @throws TarIOException
*/
public function open($file, $comptype = Tar::COMPRESS_AUTO) {
// determine compression
if($comptype == Tar::COMPRESS_AUTO) $comptype = $this->filetype($file);
$this->compressioncheck($comptype);
$this->comptype = $comptype;
$this->file = $file;
if($this->comptype === Tar::COMPRESS_GZIP) {
$this->fh = @gzopen($this->file, 'rb');
} elseif($this->comptype === Tar::COMPRESS_BZIP) {
$this->fh = @bzopen($this->file, 'r');
} else {
$this->fh = @fopen($this->file, 'rb');
}
if(!$this->fh) throw new TarIOException('Could not open file for reading: '.$this->file);
$this->closed = false;
}
/**
* Read the contents of a TAR archive
*
* This function lists the files stored in the archive, and returns an indexed array of associative
* arrays containing for each file the following information:
*
* checksum Tar Checksum of the file
* filename The full name of the stored file (up to 100 c.)
* mode UNIX permissions in DECIMAL, not octal
* uid The Owner ID
* gid The Group ID
* size Uncompressed filesize
* mtime Timestamp of last modification
* typeflag Empty for files, set for folders
* link Is it a symlink?
* uname Owner name
* gname Group name
*
* The archive is closed afer reading the contents, because rewinding is not possible in bzip2 streams.
* Reopen the file with open() again if you want to do additional operations
*
* @return array
* @throws TarIOException
*/
public function contents() {
if($this->closed || !$this->file) throw new TarIOException('Can not read from a closed archive');
$result = array();
while($read = $this->readbytes(512)) {
$header = $this->parseHeader($read);
if(!is_array($header)) continue;
$this->skipbytes(ceil($header['size'] / 512) * 512);
$result[] = $header;
}
$this->close();
return $result;
}
/**
* Extract an existing TAR archive
*
* The $strip parameter allows you to strip a certain number of path components from the filenames
* found in the tar file, similar to the --strip-components feature of GNU tar. This is triggered when
* an integer is passed as $strip.
* Alternatively a fixed string prefix may be passed in $strip. If the filename matches this prefix,
* the prefix will be stripped. It is recommended to give prefixes with a trailing slash.
*
* By default this will extract all files found in the archive. You can restrict the output using the $include
* and $exclude parameter. Both expect a full regular expression (including delimiters and modifiers). If
* $include is set only files that match this expression will be extracted. Files that match the $exclude
* expression will never be extracted. Both parameters can be used in combination. Expressions are matched against
* stripped filenames as described above.
*
* The archive is closed afer reading the contents, because rewinding is not possible in bzip2 streams.
* Reopen the file with open() again if you want to do additional operations
*
* @param string $outdir the target directory for extracting
* @param int|string $strip either the number of path components or a fixed prefix to strip
* @param string $exclude a regular expression of files to exclude
* @param string $include a regular expression of files to include
* @throws TarIOException
* @return array
*/
function extract($outdir, $strip = '', $exclude = '', $include = '') {
if($this->closed || !$this->file) throw new TarIOException('Can not read from a closed archive');
$outdir = rtrim($outdir, '/');
io_mkdir_p($outdir);
$striplen = strlen($strip);
$extracted = array();
while($dat = $this->readbytes(512)) {
// read the file header
$header = $this->parseHeader($dat);
if(!is_array($header)) continue;
if(!$header['filename']) continue;
// strip prefix
$filename = $this->cleanPath($header['filename']);
if(is_int($strip)) {
// if $strip is an integer we strip this many path components
$parts = explode('/', $filename);
if(!$header['typeflag']) {
$base = array_pop($parts); // keep filename itself
} else {
$base = '';
}
$filename = join('/', array_slice($parts, $strip));
if($base) $filename .= "/$base";
} else {
// ifstrip is a string, we strip a prefix here
if(substr($filename, 0, $striplen) == $strip) $filename = substr($filename, $striplen);
}
// check if this should be extracted
$extract = true;
if(!$filename) {
$extract = false;
} else {
if($include) {
if(preg_match($include, $filename)) {
$extract = true;
} else {
$extract = false;
}
}
if($exclude && preg_match($exclude, $filename)) {
$extract = false;
}
}
// Now do the extraction (or not)
if($extract) {
$extracted[] = $header;
$output = "$outdir/$filename";
$directory = ($header['typeflag']) ? $output : dirname($output);
io_mkdir_p($directory);
// is this a file?
if(!$header['typeflag']) {
$fp = fopen($output, "wb");
if(!$fp) throw new TarIOException('Could not open file for writing: '.$output);
$size = floor($header['size'] / 512);
for($i = 0; $i < $size; $i++) {
fwrite($fp, $this->readbytes(512), 512);
}
if(($header['size'] % 512) != 0) fwrite($fp, $this->readbytes(512), $header['size'] % 512);
fclose($fp);
touch($output, $header['mtime']);
chmod($output, $header['perm']);
} else {
$this->skipbytes(ceil($header['size'] / 512) * 512); // the size is usually 0 for directories
}
} else {
$this->skipbytes(ceil($header['size'] / 512) * 512);
}
}
$this->close();
return $extracted;
}
/**
* Create a new TAR file
*
* If $file is empty, the tar file will be created in memory
*
* @param string $file
* @param int $comptype
* @param int $complevel
* @throws TarIOException
* @throws TarIllegalCompressionException
*/
public function create($file = '', $comptype = Tar::COMPRESS_AUTO, $complevel = 9) {
// determine compression
if($comptype == Tar::COMPRESS_AUTO) $comptype = $this->filetype($file);
$this->compressioncheck($comptype);
$this->comptype = $comptype;
$this->file = $file;
$this->memory = '';
$this->fh = 0;
if($this->file) {
if($this->comptype === Tar::COMPRESS_GZIP) {
$this->fh = @gzopen($this->file, 'wb'.$complevel);
} elseif($this->comptype === Tar::COMPRESS_BZIP) {
$this->fh = @bzopen($this->file, 'w');
} else {
$this->fh = @fopen($this->file, 'wb');
}
if(!$this->fh) throw new TarIOException('Could not open file for writing: '.$this->file);
}
$this->writeaccess = true;
$this->closed = false;
}
/**
* Add a file to the current TAR archive using an existing file in the filesystem
*
* @todo handle directory adding
*
* @param string $file the original file
* @param string $name the name to use for the file in the archive
* @throws TarIOException
*/
public function addFile($file, $name = '') {
if($this->closed) throw new TarIOException('Archive has been closed, files can no longer be added');
if(!$name) $name = $file;
$name = $this->cleanPath($name);
$fp = fopen($file, 'rb');
if(!$fp) throw new TarIOException('Could not open file for reading: '.$file);
// create file header and copy all stat info from the original file
clearstatcache(false, $file);
$stat = stat($file);
$this->writeFileHeader(
$name,
$stat[4],
$stat[5],
fileperms($file),
filesize($file),
filemtime($file)
);
while(!feof($fp)) {
$data = fread($fp, 512);
if($data === false) break;
if($data === '') break;
$packed = pack("a512", $data);
$this->writebytes($packed);
}
fclose($fp);
}
/**
* Add a file to the current TAR archive using the given $data as content
*
* @param string $name
* @param string $data
* @param int $uid
* @param int $gid
* @param int $perm
* @param int $mtime
* @throws TarIOException
*/
public function addData($name, $data, $uid = 0, $gid = 0, $perm = 0666, $mtime = 0) {
if($this->closed) throw new TarIOException('Archive has been closed, files can no longer be added');
$name = $this->cleanPath($name);
$len = strlen($data);
$this->writeFileHeader(
$name,
$uid,
$gid,
$perm,
$len,
($mtime) ? $mtime : time()
);
for($s = 0; $s < $len; $s += 512) {
$this->writebytes(pack("a512", substr($data, $s, 512)));
}
}
/**
* Add the closing footer to the archive if in write mode, close all file handles
*
* After a call to this function no more data can be added to the archive, for
* read access no reading is allowed anymore
*
* "Physically, an archive consists of a series of file entries terminated by an end-of-archive entry, which
* consists of two 512 blocks of zero bytes"
*
* @link http://www.gnu.org/software/tar/manual/html_chapter/tar_8.html#SEC134
*/
public function close() {
if($this->closed) return; // we did this already
// write footer
if($this->writeaccess) {
$this->writebytes(pack("a512", ""));
$this->writebytes(pack("a512", ""));
}
// close file handles
if($this->file) {
if($this->comptype === Tar::COMPRESS_GZIP) {
gzclose($this->fh);
} elseif($this->comptype === Tar::COMPRESS_BZIP) {
bzclose($this->fh);
} else {
fclose($this->fh);
}
$this->file = '';
$this->fh = 0;
}
$this->closed = true;
}
/**
* Returns the created in-memory archive data
*
* This implicitly calls close() on the Archive
*
* @param int $comptype
* @param int $complevel
* @return mixed|string
*/
public function getArchive($comptype = Tar::COMPRESS_AUTO, $complevel = 9) {
$this->close();
if($comptype === Tar::COMPRESS_AUTO) $comptype = $this->comptype;
$this->compressioncheck($comptype);
if($comptype === Tar::COMPRESS_GZIP) return gzcompress($this->memory, $complevel);
if($comptype === Tar::COMPRESS_BZIP) return bzcompress($this->memory);
return $this->memory;
}
/**
* Save the created in-memory archive data
*
* Note: It more memory effective to specify the filename in the create() function and
* let the library work on the new file directly.
*
* @param string $file
* @param int $comptype
* @param int $complevel
* @throws TarIOException
*/
public function save($file, $comptype = Tar::COMPRESS_AUTO, $complevel = 9) {
if($comptype === Tar::COMPRESS_AUTO) $comptype = $this->filetype($file);
if(!file_put_contents($file, $this->getArchive($comptype, $complevel))) {
throw new TarIOException('Could not write to file: '.$file);
}
}
/**
* Read from the open file pointer
*
* @param int $length bytes to read
* @return string
*/
protected function readbytes($length) {
if($this->comptype === Tar::COMPRESS_GZIP) {
return @gzread($this->fh, $length);
} elseif($this->comptype === Tar::COMPRESS_BZIP) {
return @bzread($this->fh, $length);
} else {
return @fread($this->fh, $length);
}
}
/**
* Write to the open filepointer or memory
*
* @param string $data
* @throws TarIOException
* @return int number of bytes written
*/
protected function writebytes($data) {
if(!$this->file) {
$this->memory .= $data;
$written = strlen($data);
} elseif($this->comptype === Tar::COMPRESS_GZIP) {
$written = @gzwrite($this->fh, $data);
} elseif($this->comptype === Tar::COMPRESS_BZIP) {
$written = @bzwrite($this->fh, $data);
} else {
$written = @fwrite($this->fh, $data);
}
if($written === false) throw new TarIOException('Failed to write to archive stream');
return $written;
}
/**
* Skip forward in the open file pointer
*
* This is basically a wrapper around seek() (and a workaround for bzip2)
*
* @param int $bytes seek to this position
*/
function skipbytes($bytes) {
if($this->comptype === Tar::COMPRESS_GZIP) {
@gzseek($this->fh, $bytes, SEEK_CUR);
} elseif($this->comptype === Tar::COMPRESS_BZIP) {
// there is no seek in bzip2, we simply read on
@bzread($this->fh, $bytes);
} else {
@fseek($this->fh, $bytes, SEEK_CUR);
}
}
/**
* Write a file header
*
* @param string $name
* @param int $uid
* @param int $gid
* @param int $perm
* @param int $size
* @param int $mtime
* @param string $typeflag Set to '5' for directories
*/
protected function writeFileHeader($name, $uid, $gid, $perm, $size, $mtime, $typeflag = '') {
// handle filename length restrictions
$prefix = '';
$namelen = strlen($name);
if($namelen > 100) {
$file = basename($name);
$dir = dirname($name);
if(strlen($file) > 100 || strlen($dir) > 155) {
// we're still too large, let's use GNU longlink
$this->writeFileHeader('././@LongLink', 0, 0, 0, $namelen, 0, 'L');
for($s = 0; $s < $namelen; $s += 512) {
$this->writebytes(pack("a512", substr($name, $s, 512)));
}
$name = substr($name, 0, 100); // cut off name
} else {
// we're fine when splitting, use POSIX ustar
$prefix = $dir;
$name = $file;
}
}
// values are needed in octal
$uid = sprintf("%6s ", decoct($uid));
$gid = sprintf("%6s ", decoct($gid));
$perm = sprintf("%6s ", decoct($perm));
$size = sprintf("%11s ", decoct($size));
$mtime = sprintf("%11s", decoct($mtime));
$data_first = pack("a100a8a8a8a12A12", $name, $perm, $uid, $gid, $size, $mtime);
$data_last = pack("a1a100a6a2a32a32a8a8a155a12", $typeflag, '', 'ustar', '', '', '', '', '', $prefix, "");
for($i = 0, $chks = 0; $i < 148; $i++)
$chks += ord($data_first[$i]);
for($i = 156, $chks += 256, $j = 0; $i < 512; $i++, $j++)
$chks += ord($data_last[$j]);
$this->writebytes($data_first);
$chks = pack("a8", sprintf("%6s ", decoct($chks)));
$this->writebytes($chks.$data_last);
}
/**
* Decode the given tar file header
*
* @param string $block a 512 byte block containign the header data
* @return false|array
*/
protected function parseHeader($block) {
if(!$block || strlen($block) != 512) return false;
for($i = 0, $chks = 0; $i < 148; $i++)
$chks += ord($block[$i]);
for($i = 156, $chks += 256; $i < 512; $i++)
$chks += ord($block[$i]);
$header = @unpack("a100filename/a8perm/a8uid/a8gid/a12size/a12mtime/a8checksum/a1typeflag/a100link/a6magic/a2version/a32uname/a32gname/a8devmajor/a8devminor/a155prefix", $block);
if(!$header) return false;
$return = array();
$return['checksum'] = OctDec(trim($header['checksum']));
if($return['checksum'] != $chks) return false;
$return['filename'] = trim($header['filename']);
$return['perm'] = OctDec(trim($header['perm']));
$return['uid'] = OctDec(trim($header['uid']));
$return['gid'] = OctDec(trim($header['gid']));
$return['size'] = OctDec(trim($header['size']));
$return['mtime'] = OctDec(trim($header['mtime']));
$return['typeflag'] = $header['typeflag'];
$return['link'] = trim($header['link']);
$return['uname'] = trim($header['uname']);
$return['gname'] = trim($header['gname']);
// Handle ustar Posix compliant path prefixes
if(trim($header['prefix'])) $return['filename'] = trim($header['prefix']).'/'.$return['filename'];
// Handle Long-Link entries from GNU Tar
if($return['typeflag'] == 'L') {
// following data block(s) is the filename
$filename = trim($this->readbytes(ceil($header['size'] / 512) * 512));
// next block is the real header
$block = $this->readbytes(512);
$return = $this->parseHeader($block);
// overwrite the filename
$return['filename'] = $filename;
}
return $return;
}
/**
* Cleans up a path and removes relative parts, also strips leading slashes
*
* @param string $path
* @return string
*/
public function cleanPath($path) {
$path=explode('/', $path);
$newpath=array();
foreach($path as $p) {
if ($p === '' || $p === '.') continue;
if ($p==='..') {
array_pop($newpath);
continue;
}
array_push($newpath, $p);
}
return trim(implode('/', $newpath), '/');
}
/**
* Checks if the given compression type is available and throws an exception if not
*
* @param int $comptype
* @throws TarIllegalCompressionException
*/
protected function compressioncheck($comptype) {
if($comptype === Tar::COMPRESS_GZIP && !function_exists('gzopen')) {
throw new TarIllegalCompressionException('No gzip support available');
}
if($comptype === Tar::COMPRESS_BZIP && !function_exists('bzopen')) {
throw new TarIllegalCompressionException('No bzip2 support available');
}
}
/**
* Guesses the wanted compression from the given filename extension
*
* You don't need to call this yourself. It's used when you pass Tar::COMPRESS_AUTO somewhere
*
* @param string $file
* @return int
*/
public function filetype($file) {
$file = strtolower($file);
if(substr($file, -3) == '.gz' || substr($file, -4) == '.tgz') {
$comptype = Tar::COMPRESS_GZIP;
} elseif(substr($file, -4) == '.bz2' || substr($file, -4) == '.tbz') {
$comptype = Tar::COMPRESS_BZIP;
} else {
$comptype = Tar::COMPRESS_NONE;
}
return $comptype;
}
}
/**
* Class TarIOException
*/
class TarIOException extends Exception {
}
/**
* Class TarIllegalCompressionException
*/
class TarIllegalCompressionException extends Exception {
}

View file

@ -1,576 +0,0 @@
<?php
/**
* @author bouchon
* @link http://dev.maxg.info
* @link http://forum.maxg.info
*
* Modified for Dokuwiki
* @deprecated 2015-05-15 - use splitbrain\PHPArchive\Zip instead
* @author Christopher Smith <chris@jalakai.co.uk>
*/
class ZipLib {
var $datasec;
var $ctrl_dir = array();
var $eof_ctrl_dir = "\x50\x4b\x05\x06\x00\x00\x00\x00";
var $old_offset = 0;
var $dirs = Array(".");
/**
* @param string $zip_name filename path to file
* @return array|int
*/
function get_List($zip_name) {
$zip = @fopen($zip_name, 'rb');
if(!$zip) return(0);
$centd = $this->ReadCentralDir($zip,$zip_name);
@rewind($zip);
@fseek($zip, $centd['offset']);
$ret = array();
for ($i=0; $i<$centd['entries']; $i++) {
$header = $this->ReadCentralFileHeaders($zip);
$header['index'] = $i;
$info = array();
$info['filename'] = $header['filename'];
$info['stored_filename'] = $header['stored_filename'];
$info['size'] = $header['size'];
$info['compressed_size'] = $header['compressed_size'];
$info['crc'] = strtoupper(dechex( $header['crc'] ));
$info['mtime'] = $header['mtime'];
$info['comment'] = $header['comment'];
$info['folder'] = ($header['external']==0x41FF0010||$header['external']==16)?1:0;
$info['index'] = $header['index'];
$info['status'] = $header['status'];
$ret[]=$info;
unset($header);
}
return $ret;
}
/**
* @param array $files array filled with array(string filename, string data)
* @param bool $compact
* @return array
*/
function Add($files,$compact) {
if(!is_array($files[0])) $files=Array($files);
$ret = array();
for($i=0;$files[$i];$i++){
$fn = $files[$i];
if(!in_Array(dirname($fn[0]),$this->dirs))
$this->add_Dir(dirname($fn[0]));
if(utf8_basename($fn[0]))
$ret[utf8_basename($fn[0])]=$this->add_File($fn[1],$fn[0],$compact);
}
return $ret;
}
/**
* Zips recursively the $folder directory, from the $basedir directory
*
* @param string $folder filename path to file
* @param string|null $basedir
* @param string|null $parent
*/
function Compress($folder, $basedir=null, $parent=null) {
$full_path = $basedir."/".$parent.$folder;
$zip_path = $parent.$folder;
if ($zip_path) {
$zip_path .= "/";
$this->add_dir($zip_path);
}
$dir = new DirectoryIterator($full_path);
foreach($dir as $file) {
/** @var DirectoryIterator $file */
if(!$file->isDot()) {
$filename = $file->getFilename();
if($file->isDir()) {
$this->Compress($filename, $basedir, $zip_path);
} else {
$content = join('', file($full_path.'/'.$filename));
$this->add_File($content, $zip_path.$filename);
}
}
}
}
/**
* Returns the Zip file
*
* @return string
*/
function get_file() {
$data = implode('', $this -> datasec);
$ctrldir = implode('', $this -> ctrl_dir);
return $data . $ctrldir . $this -> eof_ctrl_dir .
pack('v', count($this->ctrl_dir)).pack('v', count($this->ctrl_dir)).
pack('V', strlen($ctrldir)) . pack('V', strlen($data)) . "\x00\x00";
}
/**
* @param string $name the name of the directory
*/
function add_dir($name) {
$name = str_replace("\\", "/", $name);
$fr = "\x50\x4b\x03\x04\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00";
$fr .= pack("V",0).pack("V",0).pack("V",0).pack("v", strlen($name) );
$fr .= pack("v", 0 ).$name.pack("V", 0).pack("V", 0).pack("V", 0);
$this -> datasec[] = $fr;
$new_offset = strlen(implode("", $this->datasec));
$cdrec = "\x50\x4b\x01\x02\x00\x00\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00";
$cdrec .= pack("V",0).pack("V",0).pack("V",0).pack("v", strlen($name) );
$cdrec .= pack("v", 0 ).pack("v", 0 ).pack("v", 0 ).pack("v", 0 );
$ext = "\xff\xff\xff\xff";
$cdrec .= pack("V", 16 ).pack("V", $this -> old_offset ).$name;
$this -> ctrl_dir[] = $cdrec;
$this -> old_offset = $new_offset;
$this -> dirs[] = $name;
}
/**
* Add a file named $name from a string $data
*
* @param string $data
* @param string $name filename
* @param bool $compact
* @return bool
*/
function add_File($data, $name, $compact = true) {
$name = str_replace('\\', '/', $name);
$dtime = dechex($this->DosTime());
$hexdtime = pack('H*',$dtime[6].$dtime[7].
$dtime[4].$dtime[5].
$dtime[2].$dtime[3].
$dtime[0].$dtime[1]);
if($compact){
$fr = "\x50\x4b\x03\x04\x14\x00\x00\x00\x08\x00".$hexdtime;
}else{
$fr = "\x50\x4b\x03\x04\x0a\x00\x00\x00\x00\x00".$hexdtime;
}
$unc_len = strlen($data);
$crc = crc32($data);
if($compact){
$zdata = gzcompress($data);
$c_len = strlen($zdata);
$zdata = substr(substr($zdata, 0, strlen($zdata) - 4), 2);
}else{
$zdata = $data;
}
$c_len=strlen($zdata);
$fr .= pack('V', $crc).pack('V', $c_len).pack('V', $unc_len);
$fr .= pack('v', strlen($name)).pack('v', 0).$name.$zdata;
$fr .= pack('V', $crc).pack('V', $c_len).pack('V', $unc_len);
$this -> datasec[] = $fr;
$new_offset = strlen(implode('', $this->datasec));
if($compact) {
$cdrec = "\x50\x4b\x01\x02\x00\x00\x14\x00\x00\x00\x08\x00";
} else {
$cdrec = "\x50\x4b\x01\x02\x14\x00\x0a\x00\x00\x00\x00\x00";
}
$cdrec .= $hexdtime.pack('V', $crc).pack('V', $c_len).pack('V', $unc_len);
$cdrec .= pack('v', strlen($name) ).pack('v', 0 ).pack('v', 0 );
$cdrec .= pack('v', 0 ).pack('v', 0 ).pack('V', 32 );
$cdrec .= pack('V', $this -> old_offset );
$this -> old_offset = $new_offset;
$cdrec .= $name;
$this -> ctrl_dir[] = $cdrec;
return true;
}
/**
* @return int
*/
function DosTime() {
$timearray = getdate();
if ($timearray['year'] < 1980) {
$timearray['year'] = 1980;
$timearray['mon'] = 1;
$timearray['mday'] = 1;
$timearray['hours'] = 0;
$timearray['minutes'] = 0;
$timearray['seconds'] = 0;
}
return (($timearray['year'] - 1980) << 25) |
($timearray['mon'] << 21) |
($timearray['mday'] << 16) |
($timearray['hours'] << 11) |
($timearray['minutes'] << 5) |
($timearray['seconds'] >> 1);
}
/**
* Extract a zip file $zn to the $to directory
*
* @param string $zn filename
* @param string $to filename path to file
* @param array $index
* @return array|int
*/
function Extract ( $zn, $to, $index = Array(-1) ) {
if(!@is_dir($to)) $this->_mkdir($to);
$zip = @fopen($zn,'rb');
if(!$zip) return(-1);
$cdir = $this->ReadCentralDir($zip,$zn);
$pos_entry = $cdir['offset'];
if(!is_array($index)){
$index = array($index);
}
for($i=0; isset($index[$i]);$i++){
if(intval($index[$i])!=$index[$i]||$index[$i]>$cdir['entries'])
return(-1);
}
$stat = array();
for ($i=0; $i<$cdir['entries']; $i++) {
@fseek($zip, $pos_entry);
$header = $this->ReadCentralFileHeaders($zip);
$header['index'] = $i;
$pos_entry = ftell($zip);
@rewind($zip);
fseek($zip, $header['offset']);
if(in_array("-1",$index)||in_array($i,$index)){
$stat[$header['filename']]=$this->ExtractFile($header, $to, $zip);
}
}
fclose($zip);
return $stat;
}
/**
* @param resource $zip
* @param array $header
* @return array
*/
function ReadFileHeader($zip, $header) {
$binary_data = fread($zip, 30);
$data = unpack('vchk/vid/vversion/vflag/vcompression/vmtime/vmdate/Vcrc/Vcompressed_size/Vsize/vfilename_len/vextra_len', $binary_data);
$header['filename'] = fread($zip, $data['filename_len']);
if ($data['extra_len'] != 0) {
$header['extra'] = fread($zip, $data['extra_len']);
} else {
$header['extra'] = '';
}
$header['compression'] = $data['compression'];
foreach (array('size','compressed_size','crc') as $hd) { // On ODT files, these headers are 0. Keep the previous value.
if ($data[$hd] != 0) $header[$hd] = $data[$hd];
}
$header['flag'] = $data['flag'];
$header['mdate'] = $data['mdate'];
$header['mtime'] = $data['mtime'];
if ($header['mdate'] && $header['mtime']){
$hour = ($header['mtime']&0xF800)>>11;
$minute = ($header['mtime']&0x07E0)>>5;
$seconde = ($header['mtime']&0x001F)*2;
$year = (($header['mdate']&0xFE00)>>9)+1980;
$month = ($header['mdate']&0x01E0)>>5;
$day = $header['mdate']&0x001F;
$header['mtime'] = mktime($hour, $minute, $seconde, $month, $day, $year);
} else {
$header['mtime'] = time();
}
$header['stored_filename'] = $header['filename'];
$header['status'] = "ok";
return $header;
}
/**
* @param resource $zip
* @return array
*/
function ReadCentralFileHeaders($zip){
$binary_data = fread($zip, 46);
$header = unpack('vchkid/vid/vversion/vversion_extracted/vflag/vcompression/vmtime/vmdate/Vcrc/Vcompressed_size/Vsize/vfilename_len/vextra_len/vcomment_len/vdisk/vinternal/Vexternal/Voffset', $binary_data);
if ($header['filename_len'] != 0){
$header['filename'] = fread($zip,$header['filename_len']);
}else{
$header['filename'] = '';
}
if ($header['extra_len'] != 0){
$header['extra'] = fread($zip, $header['extra_len']);
}else{
$header['extra'] = '';
}
if ($header['comment_len'] != 0){
$header['comment'] = fread($zip, $header['comment_len']);
}else{
$header['comment'] = '';
}
if ($header['mdate'] && $header['mtime']) {
$hour = ($header['mtime'] & 0xF800) >> 11;
$minute = ($header['mtime'] & 0x07E0) >> 5;
$seconde = ($header['mtime'] & 0x001F)*2;
$year = (($header['mdate'] & 0xFE00) >> 9) + 1980;
$month = ($header['mdate'] & 0x01E0) >> 5;
$day = $header['mdate'] & 0x001F;
$header['mtime'] = mktime($hour, $minute, $seconde, $month, $day, $year);
} else {
$header['mtime'] = time();
}
$header['stored_filename'] = $header['filename'];
$header['status'] = 'ok';
if (substr($header['filename'], -1) == '/') $header['external'] = 0x41FF0010;
return $header;
}
/**
* @param resource $zip
* @param string $zip_name filename path to file
* @return array
*/
function ReadCentralDir($zip,$zip_name) {
$size = filesize($zip_name);
if ($size < 277){
$maximum_size = $size;
} else {
$maximum_size=277;
}
@fseek($zip, $size-$maximum_size);
$pos = ftell($zip);
$bytes = 0x00000000;
while ($pos < $size) {
$byte = @fread($zip, 1);
$bytes=(($bytes << 8) & 0xFFFFFFFF) | Ord($byte);
if ($bytes == 0x504b0506){
$pos++;
break;
}
$pos++;
}
$data=unpack('vdisk/vdisk_start/vdisk_entries/ventries/Vsize/Voffset/vcomment_size',
fread($zip, 18));
$centd = array();
if ($data['comment_size'] != 0){
$centd['comment'] = fread($zip, $data['comment_size']);
} else {
$centd['comment'] = '';
}
$centd['entries'] = $data['entries'];
$centd['disk_entries'] = $data['disk_entries'];
$centd['offset'] = $data['offset'];
$centd['disk_start'] = $data['disk_start'];
$centd['size'] = $data['size'];
$centd['disk'] = $data['disk'];
return $centd;
}
/**
* @param array $header
* @param string $to filename path to file
* @param resource $zip
* @return bool|int
*/
function ExtractFile($header,$to,$zip) {
$header = $this->readfileheader($zip, $header);
if(substr($to,-1)!="/") $to.="/";
if(substr($header['filename'],-1)=="/") {
$this->_mkdir($to.$header['filename']);
return +2;
}
if (!$this->_mkdir($to.dirname($header['filename']))) return (-1);
if (!array_key_exists("external", $header) || (!($header['external']==0x41FF0010)&&!($header['external']==16))) {
if ($header['compression']==0) {
$fp = @fopen($to.$header['filename'], 'wb');
if(!$fp) return(-1);
$size = $header['compressed_size'];
while ($size != 0) {
$read_size = ($size < 2048 ? $size : 2048);
$buffer = fread($zip, $read_size);
$binary_data = pack('a'.$read_size, $buffer);
@fwrite($fp, $binary_data, $read_size);
$size -= $read_size;
}
fclose($fp);
touch($to.$header['filename'], $header['mtime']);
}else{
if (!is_dir(dirname($to.$header['filename']))) $this->_mkdir(dirname($to.$header['filename']));
$fp = fopen($to.$header['filename'].'.gz','wb');
if(!$fp) return(-1);
$binary_data = pack('va1a1Va1a1', 0x8b1f, Chr($header['compression']),
Chr(0x00), time(), Chr(0x00), Chr(3));
fwrite($fp, $binary_data, 10);
$size = $header['compressed_size'];
while ($size != 0) {
$read_size = ($size < 1024 ? $size : 1024);
$buffer = fread($zip, $read_size);
$binary_data = pack('a'.$read_size, $buffer);
@fwrite($fp, $binary_data, $read_size);
$size -= $read_size;
}
$binary_data = pack('VV', $header['crc'], $header['size']);
fwrite($fp, $binary_data,8);
fclose($fp);
$gzp = @gzopen($to.$header['filename'].'.gz','rb');
if(!$gzp){
@gzclose($gzp);
@unlink($to.$header['filename']);
die("Archive is compressed whereas ZLIB is not enabled.");
}
$fp = @fopen($to.$header['filename'],'wb');
if(!$fp) return(-1);
$size = $header['size'];
while ($size != 0) {
$read_size = ($size < 2048 ? $size : 2048);
$buffer = gzread($gzp, $read_size);
$binary_data = pack('a'.$read_size, $buffer);
@fwrite($fp, $binary_data, $read_size);
$size -= $read_size;
}
fclose($fp);
gzclose($gzp);
touch($to.$header['filename'], $header['mtime']);
@unlink($to.$header['filename'].'.gz');
}
}
return true;
}
/**
* centralize mkdir calls and use dokuwiki io functions
*
* @author Christopher Smith <chris@jalakai.co.uk>
*
* @param string $d filename path to file
* @return bool|int|string
*/
function _mkdir($d) {
return io_mkdir_p($d);
}
/**
* @param string $zn
* @param string $name
* @return null|string
*/
function ExtractStr($zn, $name) {
$zip = @fopen($zn,'rb');
if(!$zip) return(null);
$cdir = $this->ReadCentralDir($zip,$zn);
$pos_entry = $cdir['offset'];
for ($i=0; $i<$cdir['entries']; $i++) {
@fseek($zip, $pos_entry);
$header = $this->ReadCentralFileHeaders($zip);
$header['index'] = $i;
$pos_entry = ftell($zip);
@rewind($zip);
fseek($zip, $header['offset']);
if ($name == $header['stored_filename'] || $name == $header['filename']) {
$str = $this->ExtractStrFile($header, $zip);
fclose($zip);
return $str;
}
}
fclose($zip);
return null;
}
/**
* @param array $header
* @param resource $zip
* @return null|string
*/
function ExtractStrFile($header,$zip) {
$hdr = $this->readfileheader($zip, $header);
$binary_data = '';
if (!($header['external']==0x41FF0010) && !($header['external']==16)) {
if ($header['compression']==0) {
while ($size != 0) {
$read_size = ($size < 2048 ? $size : 2048);
$buffer = fread($zip, $read_size);
$binary_data .= pack('a'.$read_size, $buffer);
$size -= $read_size;
}
return $binary_data;
} else {
$size = $header['compressed_size'];
if ($size == 0) {
return '';
}
//Just in case
if ($size > ($this->_ret_bytes(ini_get('memory_limit'))/2)) {
die("Compressed file is to huge to be uncompress in memory.");
}
while ($size != 0)
{
$read_size = ($size < 2048 ? $size : 2048);
$buffer = fread($zip, $read_size);
$binary_data .= pack('a'.$read_size, $buffer);
$size -= $read_size;
}
$str = gzinflate($binary_data, $header['size']);
if ($header['crc'] == crc32($str)) {
return $str;
} else {
die("Crc Error");
}
}
}
return null;
}
/**
* @param string $val
* @return int|string
*/
function _ret_bytes($val) {
$val = trim($val);
$last = $val{strlen($val)-1};
switch($last) {
case 'k':
case 'K':
return (int) $val * 1024;
break;
case 'm':
case 'M':
return (int) $val * 1048576;
break;
default:
return $val;
}
}
}

View file

@ -1,861 +0,0 @@
<?php
/**
* DokuWiki Actions
*
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
* @author Andreas Gohr <andi@splitbrain.org>
*/
if(!defined('DOKU_INC')) die('meh.');
/**
* Call the needed action handlers
*
* @author Andreas Gohr <andi@splitbrain.org>
* @triggers ACTION_ACT_PREPROCESS
* @triggers ACTION_HEADERS_SEND
*/
function act_dispatch(){
global $ACT;
global $ID;
global $INFO;
global $QUERY;
/* @var Input $INPUT */
global $INPUT;
global $lang;
global $conf;
$preact = $ACT;
// give plugins an opportunity to process the action
$evt = new Doku_Event('ACTION_ACT_PREPROCESS',$ACT);
$headers = array();
if ($evt->advise_before()) {
//sanitize $ACT
$ACT = act_validate($ACT);
//check if searchword was given - else just show
$s = cleanID($QUERY);
if($ACT == 'search' && empty($s)){
$ACT = 'show';
}
//login stuff
if(in_array($ACT,array('login','logout'))){
$ACT = act_auth($ACT);
}
//check if user is asking to (un)subscribe a page
if($ACT == 'subscribe') {
try {
$ACT = act_subscription($ACT);
} catch (Exception $e) {
msg($e->getMessage(), -1);
}
}
//display some info
if($ACT == 'check'){
check();
$ACT = 'show';
}
//check permissions
$ACT = act_permcheck($ACT);
//sitemap
if ($ACT == 'sitemap'){
act_sitemap($ACT);
}
//recent changes
if ($ACT == 'recent'){
$show_changes = $INPUT->str('show_changes');
if (!empty($show_changes)) {
set_doku_pref('show_changes', $show_changes);
}
}
//diff
if ($ACT == 'diff'){
$difftype = $INPUT->str('difftype');
if (!empty($difftype)) {
set_doku_pref('difftype', $difftype);
}
}
//register
if($ACT == 'register' && $INPUT->post->bool('save') && register()){
$ACT = 'login';
}
if ($ACT == 'resendpwd' && act_resendpwd()) {
$ACT = 'login';
}
// user profile changes
if (in_array($ACT, array('profile','profile_delete'))) {
if(!$INPUT->server->str('REMOTE_USER')) {
$ACT = 'login';
} else {
switch ($ACT) {
case 'profile' :
if(updateprofile()) {
msg($lang['profchanged'],1);
$ACT = 'show';
}
break;
case 'profile_delete' :
if(auth_deleteprofile()){
msg($lang['profdeleted'],1);
$ACT = 'show';
} else {
$ACT = 'profile';
}
break;
}
}
}
//revert
if($ACT == 'revert'){
if(checkSecurityToken()){
$ACT = act_revert($ACT);
}else{
$ACT = 'show';
}
}
//save
if($ACT == 'save'){
if(checkSecurityToken()){
$ACT = act_save($ACT);
}else{
$ACT = 'preview';
}
}
//cancel conflicting edit
if($ACT == 'cancel')
$ACT = 'show';
//draft deletion
if($ACT == 'draftdel')
$ACT = act_draftdel($ACT);
//draft saving on preview
if($ACT == 'preview') {
$headers[] = "X-XSS-Protection: 0";
$ACT = act_draftsave($ACT);
}
//edit
if(in_array($ACT, array('edit', 'preview', 'recover'))) {
$ACT = act_edit($ACT);
}else{
unlock($ID); //try to unlock
}
//handle export
if(substr($ACT,0,7) == 'export_')
$ACT = act_export($ACT);
//handle admin tasks
if($ACT == 'admin'){
// retrieve admin plugin name from $_REQUEST['page']
if (($page = $INPUT->str('page', '', true)) != '') {
/** @var $plugin DokuWiki_Admin_Plugin */
if ($plugin = plugin_getRequestAdminPlugin()){
$plugin->handle();
}
}
}
// check permissions again - the action may have changed
$ACT = act_permcheck($ACT);
} // end event ACTION_ACT_PREPROCESS default action
$evt->advise_after();
// Make sure plugs can handle 'denied'
if($conf['send404'] && $ACT == 'denied') {
http_status(403);
}
unset($evt);
// when action 'show', the intial not 'show' and POST, do a redirect
if($ACT == 'show' && $preact != 'show' && strtolower($INPUT->server->str('REQUEST_METHOD')) == 'post'){
act_redirect($ID,$preact);
}
global $INFO;
global $conf;
global $license;
//call template FIXME: all needed vars available?
$headers[] = 'Content-Type: text/html; charset=utf-8';
trigger_event('ACTION_HEADERS_SEND',$headers,'act_sendheaders');
include(template('main.php'));
// output for the commands is now handled in inc/templates.php
// in function tpl_content()
}
/**
* Send the given headers using header()
*
* @param array $headers The headers that shall be sent
*/
function act_sendheaders($headers) {
foreach ($headers as $hdr) header($hdr);
}
/**
* Sanitize the action command
*
* @author Andreas Gohr <andi@splitbrain.org>
*
* @param array|string $act
* @return string
*/
function act_clean($act){
// check if the action was given as array key
if(is_array($act)){
list($act) = array_keys($act);
}
//remove all bad chars
$act = strtolower($act);
$act = preg_replace('/[^1-9a-z_]+/','',$act);
if($act == 'export_html') $act = 'export_xhtml';
if($act == 'export_htmlbody') $act = 'export_xhtmlbody';
if($act === '') $act = 'show';
return $act;
}
/**
* Sanitize and validate action commands.
*
* Add all allowed commands here.
*
* @author Andreas Gohr <andi@splitbrain.org>
*
* @param array|string $act
* @return string
*/
function act_validate($act) {
global $conf;
global $INFO;
$act = act_clean($act);
// check if action is disabled
if(!actionOK($act)){
msg('Command disabled: '.htmlspecialchars($act),-1);
return 'show';
}
//disable all acl related commands if ACL is disabled
if(!$conf['useacl'] && in_array($act,array('login','logout','register','admin',
'subscribe','unsubscribe','profile','revert',
'resendpwd','profile_delete'))){
msg('Command unavailable: '.htmlspecialchars($act),-1);
return 'show';
}
//is there really a draft?
if($act == 'draft' && !file_exists($INFO['draft'])) return 'edit';
if(!in_array($act,array('login','logout','register','save','cancel','edit','draft',
'preview','search','show','check','index','revisions',
'diff','recent','backlink','admin','subscribe','revert',
'unsubscribe','profile','profile_delete','resendpwd','recover',
'draftdel','sitemap','media')) && substr($act,0,7) != 'export_' ) {
msg('Command unknown: '.htmlspecialchars($act),-1);
return 'show';
}
return $act;
}
/**
* Run permissionchecks
*
* @author Andreas Gohr <andi@splitbrain.org>
*
* @param string $act action command
* @return string action command
*/
function act_permcheck($act){
global $INFO;
if(in_array($act,array('save','preview','edit','recover'))){
if($INFO['exists']){
if($act == 'edit'){
//the edit function will check again and do a source show
//when no AUTH_EDIT available
$permneed = AUTH_READ;
}else{
$permneed = AUTH_EDIT;
}
}else{
$permneed = AUTH_CREATE;
}
}elseif(in_array($act,array('login','search','recent','profile','profile_delete','index', 'sitemap'))){
$permneed = AUTH_NONE;
}elseif($act == 'revert'){
$permneed = AUTH_ADMIN;
if($INFO['ismanager']) $permneed = AUTH_EDIT;
}elseif($act == 'register'){
$permneed = AUTH_NONE;
}elseif($act == 'resendpwd'){
$permneed = AUTH_NONE;
}elseif($act == 'admin'){
if($INFO['ismanager']){
// if the manager has the needed permissions for a certain admin
// action is checked later
$permneed = AUTH_READ;
}else{
$permneed = AUTH_ADMIN;
}
}else{
$permneed = AUTH_READ;
}
if($INFO['perm'] >= $permneed) return $act;
return 'denied';
}
/**
* Handle 'draftdel'
*
* Deletes the draft for the current page and user
*
* @param string $act action command
* @return string action command
*/
function act_draftdel($act){
global $INFO;
@unlink($INFO['draft']);
$INFO['draft'] = null;
return 'show';
}
/**
* Saves a draft on preview
*
* @todo this currently duplicates code from ajax.php :-/
*
* @param string $act action command
* @return string action command
*/
function act_draftsave($act){
global $INFO;
global $ID;
global $INPUT;
global $conf;
if($conf['usedraft'] && $INPUT->post->has('wikitext')) {
$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;
}
}
return $act;
}
/**
* Handle 'save'
*
* Checks for spam and conflicts and saves the page.
* Does a redirect to show the page afterwards or
* returns a new action.
*
* @author Andreas Gohr <andi@splitbrain.org>
*
* @param string $act action command
* @return string action command
*/
function act_save($act){
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);
return 'edit';
}
//conflict check
if($DATE != 0 && $INFO['meta']['date']['modified'] > $DATE )
return 'conflict';
//save it
saveWikiText($ID,con($PRE,$TEXT,$SUF,true),$SUM,$INPUT->bool('minor')); //use pretty mode for con
//unlock it
unlock($ID);
//delete draft
act_draftdel($act);
session_write_close();
// when done, show page
return 'show';
}
/**
* Revert to a certain revision
*
* @author Andreas Gohr <andi@splitbrain.org>
*
* @param string $act action command
* @return string action command
*/
function act_revert($act){
global $ID;
global $REV;
global $lang;
/* @var Input $INPUT */
global $INPUT;
// FIXME $INFO['writable'] currently refers to the attic version
// global $INFO;
// if (!$INFO['writable']) {
// return 'show';
// }
// 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) return 'show'; //something went wrong
$sum = sprintf($lang['restored'], dformat($REV));
}
// spam check
if (checkwordblock($text)) {
msg($lang['wordblock'], -1);
return 'edit';
}
saveWikiText($ID,$text,$sum,false);
msg($sum,1);
//delete any draft
act_draftdel($act);
session_write_close();
// when done, show current page
$INPUT->server->set('REQUEST_METHOD','post'); //should force a redirect
$REV = '';
return 'show';
}
/**
* Do a redirect after receiving post data
*
* Tries to add the section id as hash mark after section editing
*
* @param string $id page id
* @param string $preact action command before redirect
*/
function act_redirect($id,$preact){
global $PRE;
global $TEXT;
$opts = array(
'id' => $id,
'preact' => $preact
);
//get section name when coming from section edit
if($PRE && preg_match('/^\s*==+([^=\n]+)/',$TEXT,$match)){
$check = false; //Byref
$opts['fragment'] = sectionID($match[0], $check);
}
trigger_event('ACTION_SHOW_REDIRECT',$opts,'act_redirect_execute');
}
/**
* Execute the redirect
*
* @param array $opts id and fragment for the redirect and the preact
*/
function act_redirect_execute($opts){
$go = wl($opts['id'],'',true);
if(isset($opts['fragment'])) $go .= '#'.$opts['fragment'];
//show it
send_redirect($go);
}
/**
* Handle 'login', 'logout'
*
* @author Andreas Gohr <andi@splitbrain.org>
*
* @param string $act action command
* @return string action command
*/
function act_auth($act){
global $ID;
global $INFO;
/* @var Input $INPUT */
global $INPUT;
//already logged in?
if($INPUT->server->has('REMOTE_USER') && $act=='login'){
return 'show';
}
//handle logout
if($act=='logout'){
$lockedby = checklock($ID); //page still locked?
if($lockedby == $INPUT->server->str('REMOTE_USER')){
unlock($ID); //try to unlock
}
// do the logout stuff
auth_logoff();
// rebuild info array
$INFO = pageinfo();
act_redirect($ID,'login');
}
return $act;
}
/**
* Handle 'edit', 'preview', 'recover'
*
* @author Andreas Gohr <andi@splitbrain.org>
*
* @param string $act action command
* @return string action command
*/
function act_edit($act){
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
//do not lock when the user can't edit anyway
if ($INFO['writable']) {
$lockedby = checklock($ID);
if($lockedby) return 'locked';
lock($ID);
}
return $act;
}
/**
* 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>
*
* @param string $act action command
* @return string action command
*/
function act_export($act){
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($act,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;
$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;
}
return 'show';
}
/**
* Handle sitemap delivery
*
* @author Michael Hamann <michael@content-space.de>
*
* @param string $act action command
*/
function act_sitemap($act) {
global $conf;
if ($conf['sitemap'] < 1 || !is_numeric($conf['sitemap'])) {
http_status(404);
print "Sitemap generation is disabled.";
exit;
}
$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;
}
http_status(500);
print "Could not read the sitemap file - bad permissions?";
exit;
}
/**
* Handle page 'subscribe'
*
* Throws exception on error.
*
* @author Adrian Lang <lang@cosmocode.de>
*
* @param string $act action command
* @return string action command
* @throws Exception if (un)subscribing fails
*/
function act_subscription($act){
global $lang;
global $INFO;
global $ID;
/* @var Input $INPUT */
global $INPUT;
// subcriptions work for logged in users only
if(!$INPUT->server->str('REMOTE_USER')) return 'show';
// 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 $act;
// Handle POST data, may throw exception.
trigger_event('ACTION_HANDLE_SUBSCRIBE', $params, 'subscription_handle_post');
$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);
act_redirect($ID, $act);
} else {
throw new Exception(sprintf($lang["subscr_{$action}_error"],
hsc($INFO['userinfo']['name']),
prettyprint_id($target)));
}
// Assure that we have valid data if act_redirect somehow fails.
$INFO['subscribed'] = $sub->user_subscription();
return 'show';
}
/**
* 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
*/
function subscription_handle_post(&$params) {
global $INFO;
global $lang;
/* @var Input $INPUT */
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');
}
//Setup VIM: ex: et ts=2 :

File diff suppressed because it is too large Load diff

View file

@ -1,515 +0,0 @@
<?php
/* vim: set expandtab sw=4 ts=4 sts=4: */
/**
* The Cipher_blowfish:: class implements the Cipher interface enryption data
* using the Blowfish algorithm.
*
* $Horde: horde/lib/Cipher/blowfish.php,v 1.2.2.3 2003/01/03 13:23:22 jan Exp $
*
* Copyright 2002-2003 Mike Cochrane <mike@graftonhall.co.nz>
*
* See the enclosed file COPYING for license information (LGPL). If you
* did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
*
* @author Mike Cochrane <mike@graftonhall.co.nz>
* @version $Id: blowfish.php 11081 2008-01-25 09:35:48Z cybot_tm $
* @since Horde 2.2
* @package horde.cipher
*/
// Change for phpMyAdmin by lem9:
//class Horde_Cipher_blowfish extends Horde_Cipher {
class Horde_Cipher_blowfish
{
/* Pi Array */
var $p = array(
0x243F6A88, 0x85A308D3, 0x13198A2E, 0x03707344,
0xA4093822, 0x299F31D0, 0x082EFA98, 0xEC4E6C89,
0x452821E6, 0x38D01377, 0xBE5466CF, 0x34E90C6C,
0xC0AC29B7, 0xC97C50DD, 0x3F84D5B5, 0xB5470917,
0x9216D5D9, 0x8979FB1B);
/* S Boxes */
var $s1 = array(
0xD1310BA6, 0x98DFB5AC, 0x2FFD72DB, 0xD01ADFB7,
0xB8E1AFED, 0x6A267E96, 0xBA7C9045, 0xF12C7F99,
0x24A19947, 0xB3916CF7, 0x0801F2E2, 0x858EFC16,
0x636920D8, 0x71574E69, 0xA458FEA3, 0xF4933D7E,
0x0D95748F, 0x728EB658, 0x718BCD58, 0x82154AEE,
0x7B54A41D, 0xC25A59B5, 0x9C30D539, 0x2AF26013,
0xC5D1B023, 0x286085F0, 0xCA417918, 0xB8DB38EF,
0x8E79DCB0, 0x603A180E, 0x6C9E0E8B, 0xB01E8A3E,
0xD71577C1, 0xBD314B27, 0x78AF2FDA, 0x55605C60,
0xE65525F3, 0xAA55AB94, 0x57489862, 0x63E81440,
0x55CA396A, 0x2AAB10B6, 0xB4CC5C34, 0x1141E8CE,
0xA15486AF, 0x7C72E993, 0xB3EE1411, 0x636FBC2A,
0x2BA9C55D, 0x741831F6, 0xCE5C3E16, 0x9B87931E,
0xAFD6BA33, 0x6C24CF5C, 0x7A325381, 0x28958677,
0x3B8F4898, 0x6B4BB9AF, 0xC4BFE81B, 0x66282193,
0x61D809CC, 0xFB21A991, 0x487CAC60, 0x5DEC8032,
0xEF845D5D, 0xE98575B1, 0xDC262302, 0xEB651B88,
0x23893E81, 0xD396ACC5, 0x0F6D6FF3, 0x83F44239,
0x2E0B4482, 0xA4842004, 0x69C8F04A, 0x9E1F9B5E,
0x21C66842, 0xF6E96C9A, 0x670C9C61, 0xABD388F0,
0x6A51A0D2, 0xD8542F68, 0x960FA728, 0xAB5133A3,
0x6EEF0B6C, 0x137A3BE4, 0xBA3BF050, 0x7EFB2A98,
0xA1F1651D, 0x39AF0176, 0x66CA593E, 0x82430E88,
0x8CEE8619, 0x456F9FB4, 0x7D84A5C3, 0x3B8B5EBE,
0xE06F75D8, 0x85C12073, 0x401A449F, 0x56C16AA6,
0x4ED3AA62, 0x363F7706, 0x1BFEDF72, 0x429B023D,
0x37D0D724, 0xD00A1248, 0xDB0FEAD3, 0x49F1C09B,
0x075372C9, 0x80991B7B, 0x25D479D8, 0xF6E8DEF7,
0xE3FE501A, 0xB6794C3B, 0x976CE0BD, 0x04C006BA,
0xC1A94FB6, 0x409F60C4, 0x5E5C9EC2, 0x196A2463,
0x68FB6FAF, 0x3E6C53B5, 0x1339B2EB, 0x3B52EC6F,
0x6DFC511F, 0x9B30952C, 0xCC814544, 0xAF5EBD09,
0xBEE3D004, 0xDE334AFD, 0x660F2807, 0x192E4BB3,
0xC0CBA857, 0x45C8740F, 0xD20B5F39, 0xB9D3FBDB,
0x5579C0BD, 0x1A60320A, 0xD6A100C6, 0x402C7279,
0x679F25FE, 0xFB1FA3CC, 0x8EA5E9F8, 0xDB3222F8,
0x3C7516DF, 0xFD616B15, 0x2F501EC8, 0xAD0552AB,
0x323DB5FA, 0xFD238760, 0x53317B48, 0x3E00DF82,
0x9E5C57BB, 0xCA6F8CA0, 0x1A87562E, 0xDF1769DB,
0xD542A8F6, 0x287EFFC3, 0xAC6732C6, 0x8C4F5573,
0x695B27B0, 0xBBCA58C8, 0xE1FFA35D, 0xB8F011A0,
0x10FA3D98, 0xFD2183B8, 0x4AFCB56C, 0x2DD1D35B,
0x9A53E479, 0xB6F84565, 0xD28E49BC, 0x4BFB9790,
0xE1DDF2DA, 0xA4CB7E33, 0x62FB1341, 0xCEE4C6E8,
0xEF20CADA, 0x36774C01, 0xD07E9EFE, 0x2BF11FB4,
0x95DBDA4D, 0xAE909198, 0xEAAD8E71, 0x6B93D5A0,
0xD08ED1D0, 0xAFC725E0, 0x8E3C5B2F, 0x8E7594B7,
0x8FF6E2FB, 0xF2122B64, 0x8888B812, 0x900DF01C,
0x4FAD5EA0, 0x688FC31C, 0xD1CFF191, 0xB3A8C1AD,
0x2F2F2218, 0xBE0E1777, 0xEA752DFE, 0x8B021FA1,
0xE5A0CC0F, 0xB56F74E8, 0x18ACF3D6, 0xCE89E299,
0xB4A84FE0, 0xFD13E0B7, 0x7CC43B81, 0xD2ADA8D9,
0x165FA266, 0x80957705, 0x93CC7314, 0x211A1477,
0xE6AD2065, 0x77B5FA86, 0xC75442F5, 0xFB9D35CF,
0xEBCDAF0C, 0x7B3E89A0, 0xD6411BD3, 0xAE1E7E49,
0x00250E2D, 0x2071B35E, 0x226800BB, 0x57B8E0AF,
0x2464369B, 0xF009B91E, 0x5563911D, 0x59DFA6AA,
0x78C14389, 0xD95A537F, 0x207D5BA2, 0x02E5B9C5,
0x83260376, 0x6295CFA9, 0x11C81968, 0x4E734A41,
0xB3472DCA, 0x7B14A94A, 0x1B510052, 0x9A532915,
0xD60F573F, 0xBC9BC6E4, 0x2B60A476, 0x81E67400,
0x08BA6FB5, 0x571BE91F, 0xF296EC6B, 0x2A0DD915,
0xB6636521, 0xE7B9F9B6, 0xFF34052E, 0xC5855664,
0x53B02D5D, 0xA99F8FA1, 0x08BA4799, 0x6E85076A);
var $s2 = array(
0x4B7A70E9, 0xB5B32944, 0xDB75092E, 0xC4192623,
0xAD6EA6B0, 0x49A7DF7D, 0x9CEE60B8, 0x8FEDB266,
0xECAA8C71, 0x699A17FF, 0x5664526C, 0xC2B19EE1,
0x193602A5, 0x75094C29, 0xA0591340, 0xE4183A3E,
0x3F54989A, 0x5B429D65, 0x6B8FE4D6, 0x99F73FD6,
0xA1D29C07, 0xEFE830F5, 0x4D2D38E6, 0xF0255DC1,
0x4CDD2086, 0x8470EB26, 0x6382E9C6, 0x021ECC5E,
0x09686B3F, 0x3EBAEFC9, 0x3C971814, 0x6B6A70A1,
0x687F3584, 0x52A0E286, 0xB79C5305, 0xAA500737,
0x3E07841C, 0x7FDEAE5C, 0x8E7D44EC, 0x5716F2B8,
0xB03ADA37, 0xF0500C0D, 0xF01C1F04, 0x0200B3FF,
0xAE0CF51A, 0x3CB574B2, 0x25837A58, 0xDC0921BD,
0xD19113F9, 0x7CA92FF6, 0x94324773, 0x22F54701,
0x3AE5E581, 0x37C2DADC, 0xC8B57634, 0x9AF3DDA7,
0xA9446146, 0x0FD0030E, 0xECC8C73E, 0xA4751E41,
0xE238CD99, 0x3BEA0E2F, 0x3280BBA1, 0x183EB331,
0x4E548B38, 0x4F6DB908, 0x6F420D03, 0xF60A04BF,
0x2CB81290, 0x24977C79, 0x5679B072, 0xBCAF89AF,
0xDE9A771F, 0xD9930810, 0xB38BAE12, 0xDCCF3F2E,
0x5512721F, 0x2E6B7124, 0x501ADDE6, 0x9F84CD87,
0x7A584718, 0x7408DA17, 0xBC9F9ABC, 0xE94B7D8C,
0xEC7AEC3A, 0xDB851DFA, 0x63094366, 0xC464C3D2,
0xEF1C1847, 0x3215D908, 0xDD433B37, 0x24C2BA16,
0x12A14D43, 0x2A65C451, 0x50940002, 0x133AE4DD,
0x71DFF89E, 0x10314E55, 0x81AC77D6, 0x5F11199B,
0x043556F1, 0xD7A3C76B, 0x3C11183B, 0x5924A509,
0xF28FE6ED, 0x97F1FBFA, 0x9EBABF2C, 0x1E153C6E,
0x86E34570, 0xEAE96FB1, 0x860E5E0A, 0x5A3E2AB3,
0x771FE71C, 0x4E3D06FA, 0x2965DCB9, 0x99E71D0F,
0x803E89D6, 0x5266C825, 0x2E4CC978, 0x9C10B36A,
0xC6150EBA, 0x94E2EA78, 0xA5FC3C53, 0x1E0A2DF4,
0xF2F74EA7, 0x361D2B3D, 0x1939260F, 0x19C27960,
0x5223A708, 0xF71312B6, 0xEBADFE6E, 0xEAC31F66,
0xE3BC4595, 0xA67BC883, 0xB17F37D1, 0x018CFF28,
0xC332DDEF, 0xBE6C5AA5, 0x65582185, 0x68AB9802,
0xEECEA50F, 0xDB2F953B, 0x2AEF7DAD, 0x5B6E2F84,
0x1521B628, 0x29076170, 0xECDD4775, 0x619F1510,
0x13CCA830, 0xEB61BD96, 0x0334FE1E, 0xAA0363CF,
0xB5735C90, 0x4C70A239, 0xD59E9E0B, 0xCBAADE14,
0xEECC86BC, 0x60622CA7, 0x9CAB5CAB, 0xB2F3846E,
0x648B1EAF, 0x19BDF0CA, 0xA02369B9, 0x655ABB50,
0x40685A32, 0x3C2AB4B3, 0x319EE9D5, 0xC021B8F7,
0x9B540B19, 0x875FA099, 0x95F7997E, 0x623D7DA8,
0xF837889A, 0x97E32D77, 0x11ED935F, 0x16681281,
0x0E358829, 0xC7E61FD6, 0x96DEDFA1, 0x7858BA99,
0x57F584A5, 0x1B227263, 0x9B83C3FF, 0x1AC24696,
0xCDB30AEB, 0x532E3054, 0x8FD948E4, 0x6DBC3128,
0x58EBF2EF, 0x34C6FFEA, 0xFE28ED61, 0xEE7C3C73,
0x5D4A14D9, 0xE864B7E3, 0x42105D14, 0x203E13E0,
0x45EEE2B6, 0xA3AAABEA, 0xDB6C4F15, 0xFACB4FD0,
0xC742F442, 0xEF6ABBB5, 0x654F3B1D, 0x41CD2105,
0xD81E799E, 0x86854DC7, 0xE44B476A, 0x3D816250,
0xCF62A1F2, 0x5B8D2646, 0xFC8883A0, 0xC1C7B6A3,
0x7F1524C3, 0x69CB7492, 0x47848A0B, 0x5692B285,
0x095BBF00, 0xAD19489D, 0x1462B174, 0x23820E00,
0x58428D2A, 0x0C55F5EA, 0x1DADF43E, 0x233F7061,
0x3372F092, 0x8D937E41, 0xD65FECF1, 0x6C223BDB,
0x7CDE3759, 0xCBEE7460, 0x4085F2A7, 0xCE77326E,
0xA6078084, 0x19F8509E, 0xE8EFD855, 0x61D99735,
0xA969A7AA, 0xC50C06C2, 0x5A04ABFC, 0x800BCADC,
0x9E447A2E, 0xC3453484, 0xFDD56705, 0x0E1E9EC9,
0xDB73DBD3, 0x105588CD, 0x675FDA79, 0xE3674340,
0xC5C43465, 0x713E38D8, 0x3D28F89E, 0xF16DFF20,
0x153E21E7, 0x8FB03D4A, 0xE6E39F2B, 0xDB83ADF7);
var $s3 = array(
0xE93D5A68, 0x948140F7, 0xF64C261C, 0x94692934,
0x411520F7, 0x7602D4F7, 0xBCF46B2E, 0xD4A20068,
0xD4082471, 0x3320F46A, 0x43B7D4B7, 0x500061AF,
0x1E39F62E, 0x97244546, 0x14214F74, 0xBF8B8840,
0x4D95FC1D, 0x96B591AF, 0x70F4DDD3, 0x66A02F45,
0xBFBC09EC, 0x03BD9785, 0x7FAC6DD0, 0x31CB8504,
0x96EB27B3, 0x55FD3941, 0xDA2547E6, 0xABCA0A9A,
0x28507825, 0x530429F4, 0x0A2C86DA, 0xE9B66DFB,
0x68DC1462, 0xD7486900, 0x680EC0A4, 0x27A18DEE,
0x4F3FFEA2, 0xE887AD8C, 0xB58CE006, 0x7AF4D6B6,
0xAACE1E7C, 0xD3375FEC, 0xCE78A399, 0x406B2A42,
0x20FE9E35, 0xD9F385B9, 0xEE39D7AB, 0x3B124E8B,
0x1DC9FAF7, 0x4B6D1856, 0x26A36631, 0xEAE397B2,
0x3A6EFA74, 0xDD5B4332, 0x6841E7F7, 0xCA7820FB,
0xFB0AF54E, 0xD8FEB397, 0x454056AC, 0xBA489527,
0x55533A3A, 0x20838D87, 0xFE6BA9B7, 0xD096954B,
0x55A867BC, 0xA1159A58, 0xCCA92963, 0x99E1DB33,
0xA62A4A56, 0x3F3125F9, 0x5EF47E1C, 0x9029317C,
0xFDF8E802, 0x04272F70, 0x80BB155C, 0x05282CE3,
0x95C11548, 0xE4C66D22, 0x48C1133F, 0xC70F86DC,
0x07F9C9EE, 0x41041F0F, 0x404779A4, 0x5D886E17,
0x325F51EB, 0xD59BC0D1, 0xF2BCC18F, 0x41113564,
0x257B7834, 0x602A9C60, 0xDFF8E8A3, 0x1F636C1B,
0x0E12B4C2, 0x02E1329E, 0xAF664FD1, 0xCAD18115,
0x6B2395E0, 0x333E92E1, 0x3B240B62, 0xEEBEB922,
0x85B2A20E, 0xE6BA0D99, 0xDE720C8C, 0x2DA2F728,
0xD0127845, 0x95B794FD, 0x647D0862, 0xE7CCF5F0,
0x5449A36F, 0x877D48FA, 0xC39DFD27, 0xF33E8D1E,
0x0A476341, 0x992EFF74, 0x3A6F6EAB, 0xF4F8FD37,
0xA812DC60, 0xA1EBDDF8, 0x991BE14C, 0xDB6E6B0D,
0xC67B5510, 0x6D672C37, 0x2765D43B, 0xDCD0E804,
0xF1290DC7, 0xCC00FFA3, 0xB5390F92, 0x690FED0B,
0x667B9FFB, 0xCEDB7D9C, 0xA091CF0B, 0xD9155EA3,
0xBB132F88, 0x515BAD24, 0x7B9479BF, 0x763BD6EB,
0x37392EB3, 0xCC115979, 0x8026E297, 0xF42E312D,
0x6842ADA7, 0xC66A2B3B, 0x12754CCC, 0x782EF11C,
0x6A124237, 0xB79251E7, 0x06A1BBE6, 0x4BFB6350,
0x1A6B1018, 0x11CAEDFA, 0x3D25BDD8, 0xE2E1C3C9,
0x44421659, 0x0A121386, 0xD90CEC6E, 0xD5ABEA2A,
0x64AF674E, 0xDA86A85F, 0xBEBFE988, 0x64E4C3FE,
0x9DBC8057, 0xF0F7C086, 0x60787BF8, 0x6003604D,
0xD1FD8346, 0xF6381FB0, 0x7745AE04, 0xD736FCCC,
0x83426B33, 0xF01EAB71, 0xB0804187, 0x3C005E5F,
0x77A057BE, 0xBDE8AE24, 0x55464299, 0xBF582E61,
0x4E58F48F, 0xF2DDFDA2, 0xF474EF38, 0x8789BDC2,
0x5366F9C3, 0xC8B38E74, 0xB475F255, 0x46FCD9B9,
0x7AEB2661, 0x8B1DDF84, 0x846A0E79, 0x915F95E2,
0x466E598E, 0x20B45770, 0x8CD55591, 0xC902DE4C,
0xB90BACE1, 0xBB8205D0, 0x11A86248, 0x7574A99E,
0xB77F19B6, 0xE0A9DC09, 0x662D09A1, 0xC4324633,
0xE85A1F02, 0x09F0BE8C, 0x4A99A025, 0x1D6EFE10,
0x1AB93D1D, 0x0BA5A4DF, 0xA186F20F, 0x2868F169,
0xDCB7DA83, 0x573906FE, 0xA1E2CE9B, 0x4FCD7F52,
0x50115E01, 0xA70683FA, 0xA002B5C4, 0x0DE6D027,
0x9AF88C27, 0x773F8641, 0xC3604C06, 0x61A806B5,
0xF0177A28, 0xC0F586E0, 0x006058AA, 0x30DC7D62,
0x11E69ED7, 0x2338EA63, 0x53C2DD94, 0xC2C21634,
0xBBCBEE56, 0x90BCB6DE, 0xEBFC7DA1, 0xCE591D76,
0x6F05E409, 0x4B7C0188, 0x39720A3D, 0x7C927C24,
0x86E3725F, 0x724D9DB9, 0x1AC15BB4, 0xD39EB8FC,
0xED545578, 0x08FCA5B5, 0xD83D7CD3, 0x4DAD0FC4,
0x1E50EF5E, 0xB161E6F8, 0xA28514D9, 0x6C51133C,
0x6FD5C7E7, 0x56E14EC4, 0x362ABFCE, 0xDDC6C837,
0xD79A3234, 0x92638212, 0x670EFA8E, 0x406000E0);
var $s4 = array(
0x3A39CE37, 0xD3FAF5CF, 0xABC27737, 0x5AC52D1B,
0x5CB0679E, 0x4FA33742, 0xD3822740, 0x99BC9BBE,
0xD5118E9D, 0xBF0F7315, 0xD62D1C7E, 0xC700C47B,
0xB78C1B6B, 0x21A19045, 0xB26EB1BE, 0x6A366EB4,
0x5748AB2F, 0xBC946E79, 0xC6A376D2, 0x6549C2C8,
0x530FF8EE, 0x468DDE7D, 0xD5730A1D, 0x4CD04DC6,
0x2939BBDB, 0xA9BA4650, 0xAC9526E8, 0xBE5EE304,
0xA1FAD5F0, 0x6A2D519A, 0x63EF8CE2, 0x9A86EE22,
0xC089C2B8, 0x43242EF6, 0xA51E03AA, 0x9CF2D0A4,
0x83C061BA, 0x9BE96A4D, 0x8FE51550, 0xBA645BD6,
0x2826A2F9, 0xA73A3AE1, 0x4BA99586, 0xEF5562E9,
0xC72FEFD3, 0xF752F7DA, 0x3F046F69, 0x77FA0A59,
0x80E4A915, 0x87B08601, 0x9B09E6AD, 0x3B3EE593,
0xE990FD5A, 0x9E34D797, 0x2CF0B7D9, 0x022B8B51,
0x96D5AC3A, 0x017DA67D, 0xD1CF3ED6, 0x7C7D2D28,
0x1F9F25CF, 0xADF2B89B, 0x5AD6B472, 0x5A88F54C,
0xE029AC71, 0xE019A5E6, 0x47B0ACFD, 0xED93FA9B,
0xE8D3C48D, 0x283B57CC, 0xF8D56629, 0x79132E28,
0x785F0191, 0xED756055, 0xF7960E44, 0xE3D35E8C,
0x15056DD4, 0x88F46DBA, 0x03A16125, 0x0564F0BD,
0xC3EB9E15, 0x3C9057A2, 0x97271AEC, 0xA93A072A,
0x1B3F6D9B, 0x1E6321F5, 0xF59C66FB, 0x26DCF319,
0x7533D928, 0xB155FDF5, 0x03563482, 0x8ABA3CBB,
0x28517711, 0xC20AD9F8, 0xABCC5167, 0xCCAD925F,
0x4DE81751, 0x3830DC8E, 0x379D5862, 0x9320F991,
0xEA7A90C2, 0xFB3E7BCE, 0x5121CE64, 0x774FBE32,
0xA8B6E37E, 0xC3293D46, 0x48DE5369, 0x6413E680,
0xA2AE0810, 0xDD6DB224, 0x69852DFD, 0x09072166,
0xB39A460A, 0x6445C0DD, 0x586CDECF, 0x1C20C8AE,
0x5BBEF7DD, 0x1B588D40, 0xCCD2017F, 0x6BB4E3BB,
0xDDA26A7E, 0x3A59FF45, 0x3E350A44, 0xBCB4CDD5,
0x72EACEA8, 0xFA6484BB, 0x8D6612AE, 0xBF3C6F47,
0xD29BE463, 0x542F5D9E, 0xAEC2771B, 0xF64E6370,
0x740E0D8D, 0xE75B1357, 0xF8721671, 0xAF537D5D,
0x4040CB08, 0x4EB4E2CC, 0x34D2466A, 0x0115AF84,
0xE1B00428, 0x95983A1D, 0x06B89FB4, 0xCE6EA048,
0x6F3F3B82, 0x3520AB82, 0x011A1D4B, 0x277227F8,
0x611560B1, 0xE7933FDC, 0xBB3A792B, 0x344525BD,
0xA08839E1, 0x51CE794B, 0x2F32C9B7, 0xA01FBAC9,
0xE01CC87E, 0xBCC7D1F6, 0xCF0111C3, 0xA1E8AAC7,
0x1A908749, 0xD44FBD9A, 0xD0DADECB, 0xD50ADA38,
0x0339C32A, 0xC6913667, 0x8DF9317C, 0xE0B12B4F,
0xF79E59B7, 0x43F5BB3A, 0xF2D519FF, 0x27D9459C,
0xBF97222C, 0x15E6FC2A, 0x0F91FC71, 0x9B941525,
0xFAE59361, 0xCEB69CEB, 0xC2A86459, 0x12BAA8D1,
0xB6C1075E, 0xE3056A0C, 0x10D25065, 0xCB03A442,
0xE0EC6E0E, 0x1698DB3B, 0x4C98A0BE, 0x3278E964,
0x9F1F9532, 0xE0D392DF, 0xD3A0342B, 0x8971F21E,
0x1B0A7441, 0x4BA3348C, 0xC5BE7120, 0xC37632D8,
0xDF359F8D, 0x9B992F2E, 0xE60B6F47, 0x0FE3F11D,
0xE54CDA54, 0x1EDAD891, 0xCE6279CF, 0xCD3E7E6F,
0x1618B166, 0xFD2C1D05, 0x848FD2C5, 0xF6FB2299,
0xF523F357, 0xA6327623, 0x93A83531, 0x56CCCD02,
0xACF08162, 0x5A75EBB5, 0x6E163697, 0x88D273CC,
0xDE966292, 0x81B949D0, 0x4C50901B, 0x71C65614,
0xE6C6C7BD, 0x327A140A, 0x45E1D006, 0xC3F27B9A,
0xC9AA53FD, 0x62A80F00, 0xBB25BFE2, 0x35BDD2F6,
0x71126905, 0xB2040222, 0xB6CBCF7C, 0xCD769C2B,
0x53113EC0, 0x1640E3D3, 0x38ABBD60, 0x2547ADF0,
0xBA38209C, 0xF746CE76, 0x77AFA1C5, 0x20756060,
0x85CBFE4E, 0x8AE88DD8, 0x7AAAF9B0, 0x4CF9AA7E,
0x1948C25C, 0x02FB8A8C, 0x01C36AE4, 0xD6EBE1F9,
0x90D4F869, 0xA65CDEA0, 0x3F09252D, 0xC208E69F,
0xB74E6132, 0xCE77E25B, 0x578FDFE3, 0x3AC372E6);
/* The number of rounds to do */
var $_rounds = 16;
/**
* Set the key to be used for en/decryption
*
* @param String $key The key to use
*/
function setKey($key) {
$key = $this->_formatKey($key);
$keyPos = $keyXor = 0;
$iMax = count($this->p);
$keyLen = count($key);
for ($i = 0; $i < $iMax; $i++) {
for ($t = 0; $t < 4; $t++) {
$keyXor = ($keyXor << 8) | (($key[$keyPos]) & 0x0ff);
if (++$keyPos == $keyLen) {
$keyPos = 0;
}
}
$this->p[$i] = $this->p[$i] ^ $keyXor;
}
$encZero = array('L' => 0, 'R' => 0);
for ($i = 0; $i + 1 < $iMax; $i += 2) {
$encZero = $this->_encryptBlock($encZero['L'], $encZero['R']);
$this->p[$i] = $encZero['L'];
$this->p[$i + 1] = $encZero['R'];
}
$iMax = count($this->s1);
for ($i = 0; $i < $iMax; $i += 2) {
$encZero = $this->_encryptBlock($encZero['L'], $encZero['R']);
$this->s1[$i] = $encZero['L'];
$this->s1[$i + 1] = $encZero['R'];
}
$iMax = count($this->s2);
for ($i = 0; $i < $iMax; $i += 2) {
$encZero = $this->_encryptBlock($encZero['L'], $encZero['R']);
$this->s2[$i] = $encZero['L'];
$this->s2[$i + 1] = $encZero['R'];
}
$iMax = count($this->s3);
for ($i = 0; $i < $iMax; $i += 2) {
$encZero = $this->_encryptBlock($encZero['L'], $encZero['R']);
$this->s3[$i] = $encZero['L'];
$this->s3[$i + 1] = $encZero['R'];
}
$iMax = count($this->s4);
for ($i = 0; $i < $iMax; $i += 2) {
$encZero = $this->_encryptBlock($encZero['L'], $encZero['R']);
$this->s4[$i] = $encZero['L'];
$this->s4[$i + 1] = $encZero['R'];
}
}
/**
* Encrypt a block on data.
*
* @param String $block The data to encrypt
* @param String $key optional The key to use
*
* @return String the encrypted output
*/
function encryptBlock($block, $key = null) {
if (!is_null($key)) {
$this->setKey($key);
}
list($L, $R) = array_values(unpack('N*', $block));
$parts = $this->_encryptBlock($L, $R);
return pack("NN", $parts['L'], $parts['R']);
}
/**
* Encrypt a block on data.
*
* @param String $L The data to encrypt.
* @param String $R The data to encrypt.
*
* @return String The encrypted output.
*/
function _encryptBlock($L, $R) {
$L ^= $this->p[0];
$R ^= ((($this->s1[($L >> 24) & 0xFF] + $this->s2[($L >> 16) & 0x0ff]) ^ $this->s3[($L >> 8) & 0x0ff]) + $this->s4[$L & 0x0ff]) ^ $this->p[1];
$L ^= ((($this->s1[($R >> 24) & 0xFF] + $this->s2[($R >> 16) & 0x0ff]) ^ $this->s3[($R >> 8) & 0x0ff]) + $this->s4[$R & 0x0ff]) ^ $this->p[2];
$R ^= ((($this->s1[($L >> 24) & 0xFF] + $this->s2[($L >> 16) & 0x0ff]) ^ $this->s3[($L >> 8) & 0x0ff]) + $this->s4[$L & 0x0ff]) ^ $this->p[3];
$L ^= ((($this->s1[($R >> 24) & 0xFF] + $this->s2[($R >> 16) & 0x0ff]) ^ $this->s3[($R >> 8) & 0x0ff]) + $this->s4[$R & 0x0ff]) ^ $this->p[4];
$R ^= ((($this->s1[($L >> 24) & 0xFF] + $this->s2[($L >> 16) & 0x0ff]) ^ $this->s3[($L >> 8) & 0x0ff]) + $this->s4[$L & 0x0ff]) ^ $this->p[5];
$L ^= ((($this->s1[($R >> 24) & 0xFF] + $this->s2[($R >> 16) & 0x0ff]) ^ $this->s3[($R >> 8) & 0x0ff]) + $this->s4[$R & 0x0ff]) ^ $this->p[6];
$R ^= ((($this->s1[($L >> 24) & 0xFF] + $this->s2[($L >> 16) & 0x0ff]) ^ $this->s3[($L >> 8) & 0x0ff]) + $this->s4[$L & 0x0ff]) ^ $this->p[7];
$L ^= ((($this->s1[($R >> 24) & 0xFF] + $this->s2[($R >> 16) & 0x0ff]) ^ $this->s3[($R >> 8) & 0x0ff]) + $this->s4[$R & 0x0ff]) ^ $this->p[8];
$R ^= ((($this->s1[($L >> 24) & 0xFF] + $this->s2[($L >> 16) & 0x0ff]) ^ $this->s3[($L >> 8) & 0x0ff]) + $this->s4[$L & 0x0ff]) ^ $this->p[9];
$L ^= ((($this->s1[($R >> 24) & 0xFF] + $this->s2[($R >> 16) & 0x0ff]) ^ $this->s3[($R >> 8) & 0x0ff]) + $this->s4[$R & 0x0ff]) ^ $this->p[10];
$R ^= ((($this->s1[($L >> 24) & 0xFF] + $this->s2[($L >> 16) & 0x0ff]) ^ $this->s3[($L >> 8) & 0x0ff]) + $this->s4[$L & 0x0ff]) ^ $this->p[11];
$L ^= ((($this->s1[($R >> 24) & 0xFF] + $this->s2[($R >> 16) & 0x0ff]) ^ $this->s3[($R >> 8) & 0x0ff]) + $this->s4[$R & 0x0ff]) ^ $this->p[12];
$R ^= ((($this->s1[($L >> 24) & 0xFF] + $this->s2[($L >> 16) & 0x0ff]) ^ $this->s3[($L >> 8) & 0x0ff]) + $this->s4[$L & 0x0ff]) ^ $this->p[13];
$L ^= ((($this->s1[($R >> 24) & 0xFF] + $this->s2[($R >> 16) & 0x0ff]) ^ $this->s3[($R >> 8) & 0x0ff]) + $this->s4[$R & 0x0ff]) ^ $this->p[14];
$R ^= ((($this->s1[($L >> 24) & 0xFF] + $this->s2[($L >> 16) & 0x0ff]) ^ $this->s3[($L >> 8) & 0x0ff]) + $this->s4[$L & 0x0ff]) ^ $this->p[15];
$L ^= ((($this->s1[($R >> 24) & 0xFF] + $this->s2[($R >> 16) & 0x0ff]) ^ $this->s3[($R >> 8) & 0x0ff]) + $this->s4[$R & 0x0ff]) ^ $this->p[16];
$R ^= $this->p[17];
return array('L' => $R, 'R' => $L);
}
/**
* Decrypt a block on data.
*
* @param String $block The data to decrypt
* @param String $key optional The key to use
*
* @return String the decrypted output
*/
function decryptBlock($block, $key = null) {
if (!is_null($key)) {
$this->setKey($key);
}
// change for phpMyAdmin
$L = null;
$R = null;
$retarray = array_values(unpack('N*', $block));
if (isset($retarray[0])) {
$L = $retarray[0];
}
if (isset($retarray[1])) {
$R = $retarray[1];
}
// end change for phpMyAdmin
$L ^= $this->p[17];
$R ^= ((($this->s1[($L >> 24) & 0xFF] + $this->s2[($L >> 16) & 0x0ff]) ^ $this->s3[($L >> 8) & 0x0ff]) + $this->s4[$L & 0x0ff]) ^ $this->p[16];
$L ^= ((($this->s1[($R >> 24) & 0xFF] + $this->s2[($R >> 16) & 0x0ff]) ^ $this->s3[($R >> 8) & 0x0ff]) + $this->s4[$R & 0x0ff]) ^ $this->p[15];
$R ^= ((($this->s1[($L >> 24) & 0xFF] + $this->s2[($L >> 16) & 0x0ff]) ^ $this->s3[($L >> 8) & 0x0ff]) + $this->s4[$L & 0x0ff]) ^ $this->p[14];
$L ^= ((($this->s1[($R >> 24) & 0xFF] + $this->s2[($R >> 16) & 0x0ff]) ^ $this->s3[($R >> 8) & 0x0ff]) + $this->s4[$R & 0x0ff]) ^ $this->p[13];
$R ^= ((($this->s1[($L >> 24) & 0xFF] + $this->s2[($L >> 16) & 0x0ff]) ^ $this->s3[($L >> 8) & 0x0ff]) + $this->s4[$L & 0x0ff]) ^ $this->p[12];
$L ^= ((($this->s1[($R >> 24) & 0xFF] + $this->s2[($R >> 16) & 0x0ff]) ^ $this->s3[($R >> 8) & 0x0ff]) + $this->s4[$R & 0x0ff]) ^ $this->p[11];
$R ^= ((($this->s1[($L >> 24) & 0xFF] + $this->s2[($L >> 16) & 0x0ff]) ^ $this->s3[($L >> 8) & 0x0ff]) + $this->s4[$L & 0x0ff]) ^ $this->p[10];
$L ^= ((($this->s1[($R >> 24) & 0xFF] + $this->s2[($R >> 16) & 0x0ff]) ^ $this->s3[($R >> 8) & 0x0ff]) + $this->s4[$R & 0x0ff]) ^ $this->p[9];
$R ^= ((($this->s1[($L >> 24) & 0xFF] + $this->s2[($L >> 16) & 0x0ff]) ^ $this->s3[($L >> 8) & 0x0ff]) + $this->s4[$L & 0x0ff]) ^ $this->p[8];
$L ^= ((($this->s1[($R >> 24) & 0xFF] + $this->s2[($R >> 16) & 0x0ff]) ^ $this->s3[($R >> 8) & 0x0ff]) + $this->s4[$R & 0x0ff]) ^ $this->p[7];
$R ^= ((($this->s1[($L >> 24) & 0xFF] + $this->s2[($L >> 16) & 0x0ff]) ^ $this->s3[($L >> 8) & 0x0ff]) + $this->s4[$L & 0x0ff]) ^ $this->p[6];
$L ^= ((($this->s1[($R >> 24) & 0xFF] + $this->s2[($R >> 16) & 0x0ff]) ^ $this->s3[($R >> 8) & 0x0ff]) + $this->s4[$R & 0x0ff]) ^ $this->p[5];
$R ^= ((($this->s1[($L >> 24) & 0xFF] + $this->s2[($L >> 16) & 0x0ff]) ^ $this->s3[($L >> 8) & 0x0ff]) + $this->s4[$L & 0x0ff]) ^ $this->p[4];
$L ^= ((($this->s1[($R >> 24) & 0xFF] + $this->s2[($R >> 16) & 0x0ff]) ^ $this->s3[($R >> 8) & 0x0ff]) + $this->s4[$R & 0x0ff]) ^ $this->p[3];
$R ^= ((($this->s1[($L >> 24) & 0xFF] + $this->s2[($L >> 16) & 0x0ff]) ^ $this->s3[($L >> 8) & 0x0ff]) + $this->s4[$L & 0x0ff]) ^ $this->p[2];
$L ^= ((($this->s1[($R >> 24) & 0xFF] + $this->s2[($R >> 16) & 0x0ff]) ^ $this->s3[($R >> 8) & 0x0ff]) + $this->s4[$R & 0x0ff]) ^ $this->p[1];
$decrypted = pack("NN", $R ^ $this->p[0], $L);
return $decrypted;
}
/**
* Converts a text key into an array.
*
* @param string $key
* @return array The key.
*/
function _formatKey($key) {
return array_values(unpack('C*', $key));
}
}
// higher-level functions:
/**
* Encryption using blowfish algorithm
*
* @param string $data original data
* @param string $secret the secret
*
* @return string the encrypted result
*
* @access public
*
* @author lem9
*/
function PMA_blowfish_encrypt($data, $secret) {
$pma_cipher = new Horde_Cipher_blowfish;
$encrypt = '';
$data .= '_'; // triming fixed for DokuWiki FS#1690 FS#1713
$mod = strlen($data) % 8;
if ($mod > 0) {
$data .= str_repeat("\0", 8 - $mod);
}
foreach (str_split($data, 8) as $chunk) {
$encrypt .= $pma_cipher->encryptBlock($chunk, $secret);
}
return base64_encode($encrypt);
}
/**
* Decryption using blowfish algorithm
*
* @param string $encdata encrypted data
* @param string $secret the secret
*
* @return string original data
*
* @access public
*
* @author lem9
*/
function PMA_blowfish_decrypt($encdata, $secret) {
$pma_cipher = new Horde_Cipher_blowfish;
$decrypt = '';
$data = base64_decode($encdata);
foreach (str_split($data, 8) as $chunk) {
$decrypt .= $pma_cipher->decryptBlock($chunk, $secret);
}
return substr(rtrim($decrypt, "\0"), 0, -1); // triming fixed for DokuWiki FS#1690 FS#1713
}

View file

@ -1,337 +0,0 @@
<?php
/**
* Generic class to handle caching
*
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
* @author Chris Smith <chris@jalakai.co.uk>
*/
if(!defined('DOKU_INC')) die('meh.');
/**
* Generic handling of caching
*/
class cache {
public $key = ''; // primary identifier for this item
public $ext = ''; // file ext for cache data, secondary identifier for this item
public $cache = ''; // cache file name
public $depends = array(); // array containing cache dependency information,
// used by _useCache to determine cache validity
var $_event = ''; // event to be triggered during useCache
var $_time;
var $_nocache = false; // if set to true, cache will not be used or stored
/**
* @param string $key primary identifier
* @param string $ext file extension
*/
public function __construct($key,$ext) {
$this->key = $key;
$this->ext = $ext;
$this->cache = getCacheName($key,$ext);
}
/**
* public method to determine whether the cache can be used
*
* to assist in centralisation of event triggering and calculation of cache statistics,
* don't override this function override _useCache()
*
* @param array $depends array of cache dependencies, support dependecies:
* 'age' => max age of the cache in seconds
* 'files' => cache must be younger than mtime of each file
* (nb. dependency passes if file doesn't exist)
*
* @return bool true if cache can be used, false otherwise
*/
public function useCache($depends=array()) {
$this->depends = $depends;
$this->_addDependencies();
if ($this->_event) {
return $this->_stats(trigger_event($this->_event, $this, array($this,'_useCache')));
} else {
return $this->_stats($this->_useCache());
}
}
/**
* private method containing cache use decision logic
*
* this function processes the following keys in the depends array
* purge - force a purge on any non empty value
* age - expire cache if older than age (seconds)
* files - expire cache if any file in this array was updated more recently than the cache
*
* Note that this function needs to be public as it is used as callback for the event handler
*
* can be overridden
*
* @return bool see useCache()
*/
public function _useCache() {
if ($this->_nocache) return false; // caching turned off
if (!empty($this->depends['purge'])) return false; // purge requested?
if (!($this->_time = @filemtime($this->cache))) return false; // cache exists?
// cache too old?
if (!empty($this->depends['age']) && ((time() - $this->_time) > $this->depends['age'])) return false;
if (!empty($this->depends['files'])) {
foreach ($this->depends['files'] as $file) {
if ($this->_time <= @filemtime($file)) return false; // cache older than files it depends on?
}
}
return true;
}
/**
* add dependencies to the depends array
*
* this method should only add dependencies,
* it should not remove any existing dependencies and
* it should only overwrite a dependency when the new value is more stringent than the old
*/
protected function _addDependencies() {
global $INPUT;
if ($INPUT->has('purge')) $this->depends['purge'] = true; // purge requested
}
/**
* retrieve the cached data
*
* @param bool $clean true to clean line endings, false to leave line endings alone
* @return string cache contents
*/
public function retrieveCache($clean=true) {
return io_readFile($this->cache, $clean);
}
/**
* cache $data
*
* @param string $data the data to be cached
* @return bool true on success, false otherwise
*/
public function storeCache($data) {
if ($this->_nocache) return false;
return io_savefile($this->cache, $data);
}
/**
* remove any cached data associated with this cache instance
*/
public function removeCache() {
@unlink($this->cache);
}
/**
* Record cache hits statistics.
* (Only when debugging allowed, to reduce overhead.)
*
* @param bool $success result of this cache use attempt
* @return bool pass-thru $success value
*/
protected function _stats($success) {
global $conf;
static $stats = null;
static $file;
if (!$conf['allowdebug']) { return $success; }
if (is_null($stats)) {
$file = $conf['cachedir'].'/cache_stats.txt';
$lines = explode("\n",io_readFile($file));
foreach ($lines as $line) {
$i = strpos($line,',');
$stats[substr($line,0,$i)] = $line;
}
}
if (isset($stats[$this->ext])) {
list($ext,$count,$hits) = explode(',',$stats[$this->ext]);
} else {
$ext = $this->ext;
$count = 0;
$hits = 0;
}
$count++;
if ($success) $hits++;
$stats[$this->ext] = "$ext,$count,$hits";
io_saveFile($file,join("\n",$stats));
return $success;
}
}
/**
* Parser caching
*/
class cache_parser extends cache {
public $file = ''; // source file for cache
public $mode = ''; // input mode (represents the processing the input file will undergo)
public $page = '';
var $_event = 'PARSER_CACHE_USE';
/**
*
* @param string $id page id
* @param string $file source file for cache
* @param string $mode input mode
*/
public function __construct($id, $file, $mode) {
if ($id) $this->page = $id;
$this->file = $file;
$this->mode = $mode;
parent::__construct($file.$_SERVER['HTTP_HOST'].$_SERVER['SERVER_PORT'],'.'.$mode);
}
/**
* method contains cache use decision logic
*
* @return bool see useCache()
*/
public function _useCache() {
if (!file_exists($this->file)) return false; // source exists?
return parent::_useCache();
}
protected function _addDependencies() {
// parser cache file dependencies ...
$files = array($this->file, // ... source
DOKU_INC.'inc/parser/parser.php', // ... parser
DOKU_INC.'inc/parser/handler.php', // ... handler
);
$files = array_merge($files, getConfigFiles('main')); // ... wiki settings
$this->depends['files'] = !empty($this->depends['files']) ? array_merge($files, $this->depends['files']) : $files;
parent::_addDependencies();
}
}
/**
* Caching of data of renderer
*/
class cache_renderer extends cache_parser {
/**
* method contains cache use decision logic
*
* @return bool see useCache()
*/
public function _useCache() {
global $conf;
if (!parent::_useCache()) return false;
if (!isset($this->page)) {
return true;
}
if ($this->_time < @filemtime(metaFN($this->page,'.meta'))) return false; // meta cache older than file it depends on?
// check current link existence is consistent with cache version
// first check the purgefile
// - if the cache is more recent than the purgefile we know no links can have been updated
if ($this->_time >= @filemtime($conf['cachedir'].'/purgefile')) {
return true;
}
// for wiki pages, check metadata dependencies
$metadata = p_get_metadata($this->page);
if (!isset($metadata['relation']['references']) ||
empty($metadata['relation']['references'])) {
return true;
}
foreach ($metadata['relation']['references'] as $id => $exists) {
if ($exists != page_exists($id,'',false)) return false;
}
return true;
}
protected function _addDependencies() {
global $conf;
// default renderer cache file 'age' is dependent on 'cachetime' setting, two special values:
// -1 : do not cache (should not be overridden)
// 0 : cache never expires (can be overridden) - no need to set depends['age']
if ($conf['cachetime'] == -1) {
$this->_nocache = true;
return;
} elseif ($conf['cachetime'] > 0) {
$this->depends['age'] = isset($this->depends['age']) ?
min($this->depends['age'],$conf['cachetime']) : $conf['cachetime'];
}
// renderer cache file dependencies ...
$files = array(
DOKU_INC.'inc/parser/'.$this->mode.'.php', // ... the renderer
);
// page implies metadata and possibly some other dependencies
if (isset($this->page)) {
$valid = p_get_metadata($this->page, 'date valid'); // for xhtml this will render the metadata if needed
if (!empty($valid['age'])) {
$this->depends['age'] = isset($this->depends['age']) ?
min($this->depends['age'],$valid['age']) : $valid['age'];
}
}
$this->depends['files'] = !empty($this->depends['files']) ? array_merge($files, $this->depends['files']) : $files;
parent::_addDependencies();
}
}
/**
* Caching of parser instructions
*/
class cache_instructions extends cache_parser {
/**
* @param string $id page id
* @param string $file source file for cache
*/
public function __construct($id, $file) {
parent::__construct($id, $file, 'i');
}
/**
* retrieve the cached data
*
* @param bool $clean true to clean line endings, false to leave line endings alone
* @return array cache contents
*/
public function retrieveCache($clean=true) {
$contents = io_readFile($this->cache, false);
return !empty($contents) ? unserialize($contents) : array();
}
/**
* cache $instructions
*
* @param array $instructions the instruction to be cached
* @return bool true on success, false otherwise
*/
public function storeCache($instructions) {
if ($this->_nocache) return false;
return io_savefile($this->cache,serialize($instructions));
}
}

File diff suppressed because it is too large Load diff

View file

@ -1,652 +0,0 @@
<?php
/**
* Class DokuCLI
*
* All DokuWiki commandline scripts should inherit from this class and implement the abstract methods.
*
* @author Andreas Gohr <andi@splitbrain.org>
*/
abstract class DokuCLI {
/** @var string the executed script itself */
protected $bin;
/** @var DokuCLI_Options the option parser */
protected $options;
/** @var DokuCLI_Colors */
public $colors;
/**
* constructor
*
* Initialize the arguments, set up helper classes and set up the CLI environment
*/
public function __construct() {
set_exception_handler(array($this, 'fatal'));
$this->options = new DokuCLI_Options();
$this->colors = new DokuCLI_Colors();
}
/**
* Register options and arguments on the given $options object
*
* @param DokuCLI_Options $options
* @return void
*/
abstract protected function setup(DokuCLI_Options $options);
/**
* Your main program
*
* Arguments and options have been parsed when this is run
*
* @param DokuCLI_Options $options
* @return void
*/
abstract protected function main(DokuCLI_Options $options);
/**
* Execute the CLI program
*
* Executes the setup() routine, adds default options, initiate the options parsing and argument checking
* and finally executes main()
*/
public function run() {
if('cli' != php_sapi_name()) throw new DokuCLI_Exception('This has to be run from the command line');
// setup
$this->setup($this->options);
$this->options->registerOption(
'no-colors',
'Do not use any colors in output. Useful when piping output to other tools or files.'
);
$this->options->registerOption(
'help',
'Display this help screen and exit immeadiately.',
'h'
);
// parse
$this->options->parseOptions();
// handle defaults
if($this->options->getOpt('no-colors')) {
$this->colors->disable();
}
if($this->options->getOpt('help')) {
echo $this->options->help();
exit(0);
}
// check arguments
$this->options->checkArguments();
// execute
$this->main($this->options);
exit(0);
}
/**
* Exits the program on a fatal error
*
* @param Exception|string $error either an exception or an error message
*/
public function fatal($error) {
$code = 0;
if(is_object($error) && is_a($error, 'Exception')) {
/** @var Exception $error */
$code = $error->getCode();
$error = $error->getMessage();
}
if(!$code) $code = DokuCLI_Exception::E_ANY;
$this->error($error);
exit($code);
}
/**
* Print an error message
*
* @param string $string
*/
public function error($string) {
$this->colors->ptln("E: $string", 'red', STDERR);
}
/**
* Print a success message
*
* @param string $string
*/
public function success($string) {
$this->colors->ptln("S: $string", 'green', STDERR);
}
/**
* Print an info message
*
* @param string $string
*/
public function info($string) {
$this->colors->ptln("I: $string", 'cyan', STDERR);
}
}
/**
* Class DokuCLI_Colors
*
* Handles color output on (Linux) terminals
*
* @author Andreas Gohr <andi@splitbrain.org>
*/
class DokuCLI_Colors {
/** @var array known color names */
protected $colors = array(
'reset' => "\33[0m",
'black' => "\33[0;30m",
'darkgray' => "\33[1;30m",
'blue' => "\33[0;34m",
'lightblue' => "\33[1;34m",
'green' => "\33[0;32m",
'lightgreen' => "\33[1;32m",
'cyan' => "\33[0;36m",
'lightcyan' => "\33[1;36m",
'red' => "\33[0;31m",
'lightred' => "\33[1;31m",
'purple' => "\33[0;35m",
'lightpurple' => "\33[1;35m",
'brown' => "\33[0;33m",
'yellow' => "\33[1;33m",
'lightgray' => "\33[0;37m",
'white' => "\33[1;37m",
);
/** @var bool should colors be used? */
protected $enabled = true;
/**
* Constructor
*
* Tries to disable colors for non-terminals
*/
public function __construct() {
if(function_exists('posix_isatty') && !posix_isatty(STDOUT)) {
$this->enabled = false;
return;
}
if(!getenv('TERM')) {
$this->enabled = false;
return;
}
}
/**
* enable color output
*/
public function enable() {
$this->enabled = true;
}
/**
* disable color output
*/
public function disable() {
$this->enabled = false;
}
/**
* Convenience function to print a line in a given color
*
* @param string $line
* @param string $color
* @param resource $channel
*/
public function ptln($line, $color, $channel = STDOUT) {
$this->set($color);
fwrite($channel, rtrim($line)."\n");
$this->reset();
}
/**
* Set the given color for consecutive output
*
* @param string $color one of the supported color names
* @throws DokuCLI_Exception
*/
public function set($color) {
if(!$this->enabled) return;
if(!isset($this->colors[$color])) throw new DokuCLI_Exception("No such color $color");
echo $this->colors[$color];
}
/**
* reset the terminal color
*/
public function reset() {
$this->set('reset');
}
}
/**
* Class DokuCLI_Options
*
* Parses command line options passed to the CLI script. Allows CLI scripts to easily register all accepted options and
* commands and even generates a help text from this setup.
*
* @author Andreas Gohr <andi@splitbrain.org>
*/
class DokuCLI_Options {
/** @var array keeps the list of options to parse */
protected $setup;
/** @var array store parsed options */
protected $options = array();
/** @var string current parsed command if any */
protected $command = '';
/** @var array passed non-option arguments */
public $args = array();
/** @var string the executed script */
protected $bin;
/**
* Constructor
*/
public function __construct() {
$this->setup = array(
'' => array(
'opts' => array(),
'args' => array(),
'help' => ''
)
); // default command
$this->args = $this->readPHPArgv();
$this->bin = basename(array_shift($this->args));
$this->options = array();
}
/**
* Sets the help text for the tool itself
*
* @param string $help
*/
public function setHelp($help) {
$this->setup['']['help'] = $help;
}
/**
* Register the names of arguments for help generation and number checking
*
* This has to be called in the order arguments are expected
*
* @param string $arg argument name (just for help)
* @param string $help help text
* @param bool $required is this a required argument
* @param string $command if theses apply to a sub command only
* @throws DokuCLI_Exception
*/
public function registerArgument($arg, $help, $required = true, $command = '') {
if(!isset($this->setup[$command])) throw new DokuCLI_Exception("Command $command not registered");
$this->setup[$command]['args'][] = array(
'name' => $arg,
'help' => $help,
'required' => $required
);
}
/**
* This registers a sub command
*
* Sub commands have their own options and use their own function (not main()).
*
* @param string $command
* @param string $help
* @throws DokuCLI_Exception
*/
public function registerCommand($command, $help) {
if(isset($this->setup[$command])) throw new DokuCLI_Exception("Command $command already registered");
$this->setup[$command] = array(
'opts' => array(),
'args' => array(),
'help' => $help
);
}
/**
* Register an option for option parsing and help generation
*
* @param string $long multi character option (specified with --)
* @param string $help help text for this option
* @param string|null $short one character option (specified with -)
* @param bool|string $needsarg does this option require an argument? give it a name here
* @param string $command what command does this option apply to
* @throws DokuCLI_Exception
*/
public function registerOption($long, $help, $short = null, $needsarg = false, $command = '') {
if(!isset($this->setup[$command])) throw new DokuCLI_Exception("Command $command not registered");
$this->setup[$command]['opts'][$long] = array(
'needsarg' => $needsarg,
'help' => $help,
'short' => $short
);
if($short) {
if(strlen($short) > 1) throw new DokuCLI_Exception("Short options should be exactly one ASCII character");
$this->setup[$command]['short'][$short] = $long;
}
}
/**
* Checks the actual number of arguments against the required number
*
* Throws an exception if arguments are missing. Called from parseOptions()
*
* @throws DokuCLI_Exception
*/
public function checkArguments() {
$argc = count($this->args);
$req = 0;
foreach($this->setup[$this->command]['args'] as $arg) {
if(!$arg['required']) break; // last required arguments seen
$req++;
}
if($req > $argc) throw new DokuCLI_Exception("Not enough arguments", DokuCLI_Exception::E_OPT_ARG_REQUIRED);
}
/**
* Parses the given arguments for known options and command
*
* The given $args array should NOT contain the executed file as first item anymore! The $args
* array is stripped from any options and possible command. All found otions can be accessed via the
* getOpt() function
*
* Note that command options will overwrite any global options with the same name
*
* @throws DokuCLI_Exception
*/
public function parseOptions() {
$non_opts = array();
$argc = count($this->args);
for($i = 0; $i < $argc; $i++) {
$arg = $this->args[$i];
// The special element '--' means explicit end of options. Treat the rest of the arguments as non-options
// and end the loop.
if($arg == '--') {
$non_opts = array_merge($non_opts, array_slice($this->args, $i + 1));
break;
}
// '-' is stdin - a normal argument
if($arg == '-') {
$non_opts = array_merge($non_opts, array_slice($this->args, $i));
break;
}
// first non-option
if($arg{0} != '-') {
$non_opts = array_merge($non_opts, array_slice($this->args, $i));
break;
}
// long option
if(strlen($arg) > 1 && $arg{1} == '-') {
list($opt, $val) = explode('=', substr($arg, 2), 2);
if(!isset($this->setup[$this->command]['opts'][$opt])) {
throw new DokuCLI_Exception("No such option $arg", DokuCLI_Exception::E_UNKNOWN_OPT);
}
// argument required?
if($this->setup[$this->command]['opts'][$opt]['needsarg']) {
if(is_null($val) && $i + 1 < $argc && !preg_match('/^--?[\w]/', $this->args[$i + 1])) {
$val = $this->args[++$i];
}
if(is_null($val)) {
throw new DokuCLI_Exception("Option $arg requires an argument", DokuCLI_Exception::E_OPT_ARG_REQUIRED);
}
$this->options[$opt] = $val;
} else {
$this->options[$opt] = true;
}
continue;
}
// short option
$opt = substr($arg, 1);
if(!isset($this->setup[$this->command]['short'][$opt])) {
throw new DokuCLI_Exception("No such option $arg", DokuCLI_Exception::E_UNKNOWN_OPT);
} else {
$opt = $this->setup[$this->command]['short'][$opt]; // store it under long name
}
// argument required?
if($this->setup[$this->command]['opts'][$opt]['needsarg']) {
$val = null;
if($i + 1 < $argc && !preg_match('/^--?[\w]/', $this->args[$i + 1])) {
$val = $this->args[++$i];
}
if(is_null($val)) {
throw new DokuCLI_Exception("Option $arg requires an argument", DokuCLI_Exception::E_OPT_ARG_REQUIRED);
}
$this->options[$opt] = $val;
} else {
$this->options[$opt] = true;
}
}
// parsing is now done, update args array
$this->args = $non_opts;
// if not done yet, check if first argument is a command and reexecute argument parsing if it is
if(!$this->command && $this->args && isset($this->setup[$this->args[0]])) {
// it is a command!
$this->command = array_shift($this->args);
$this->parseOptions(); // second pass
}
}
/**
* Get the value of the given option
*
* Please note that all options are accessed by their long option names regardless of how they were
* specified on commandline.
*
* Can only be used after parseOptions() has been run
*
* @param string $option
* @param bool|string $default what to return if the option was not set
* @return bool|string
*/
public function getOpt($option, $default = false) {
if(isset($this->options[$option])) return $this->options[$option];
return $default;
}
/**
* Return the found command if any
*
* @return string
*/
public function getCmd() {
return $this->command;
}
/**
* Builds a help screen from the available options. You may want to call it from -h or on error
*
* @return string
*/
public function help() {
$text = '';
$hascommands = (count($this->setup) > 1);
foreach($this->setup as $command => $config) {
$hasopts = (bool) $this->setup[$command]['opts'];
$hasargs = (bool) $this->setup[$command]['args'];
if(!$command) {
$text .= 'USAGE: '.$this->bin;
} else {
$text .= "\n$command";
}
if($hasopts) $text .= ' <OPTIONS>';
foreach($this->setup[$command]['args'] as $arg) {
if($arg['required']) {
$text .= ' <'.$arg['name'].'>';
} else {
$text .= ' [<'.$arg['name'].'>]';
}
}
$text .= "\n";
if($this->setup[$command]['help']) {
$text .= "\n";
$text .= $this->tableFormat(
array(2, 72),
array('', $this->setup[$command]['help']."\n")
);
}
if($hasopts) {
$text .= "\n OPTIONS\n\n";
foreach($this->setup[$command]['opts'] as $long => $opt) {
$name = '';
if($opt['short']) {
$name .= '-'.$opt['short'];
if($opt['needsarg']) $name .= ' <'.$opt['needsarg'].'>';
$name .= ', ';
}
$name .= "--$long";
if($opt['needsarg']) $name .= ' <'.$opt['needsarg'].'>';
$text .= $this->tableFormat(
array(2, 20, 52),
array('', $name, $opt['help'])
);
$text .= "\n";
}
}
if($hasargs) {
$text .= "\n";
foreach($this->setup[$command]['args'] as $arg) {
$name = '<'.$arg['name'].'>';
$text .= $this->tableFormat(
array(2, 20, 52),
array('', $name, $arg['help'])
);
}
}
if($command == '' && $hascommands) {
$text .= "\nThis tool accepts a command as first parameter as outlined below:\n";
}
}
return $text;
}
/**
* Safely read the $argv PHP array across different PHP configurations.
* Will take care on register_globals and register_argc_argv ini directives
*
* @throws DokuCLI_Exception
* @return array the $argv PHP array or PEAR error if not registered
*/
private function readPHPArgv() {
global $argv;
if(!is_array($argv)) {
if(!@is_array($_SERVER['argv'])) {
if(!@is_array($GLOBALS['HTTP_SERVER_VARS']['argv'])) {
throw new DokuCLI_Exception(
"Could not read cmd args (register_argc_argv=Off?)",
DOKU_CLI_OPTS_ARG_READ
);
}
return $GLOBALS['HTTP_SERVER_VARS']['argv'];
}
return $_SERVER['argv'];
}
return $argv;
}
/**
* Displays text in multiple word wrapped columns
*
* @param int[] $widths list of column widths (in characters)
* @param string[] $texts list of texts for each column
* @return string
*/
private function tableFormat($widths, $texts) {
$wrapped = array();
$maxlen = 0;
foreach($widths as $col => $width) {
$wrapped[$col] = explode("\n", wordwrap($texts[$col], $width - 1, "\n", true)); // -1 char border
$len = count($wrapped[$col]);
if($len > $maxlen) $maxlen = $len;
}
$out = '';
for($i = 0; $i < $maxlen; $i++) {
foreach($widths as $col => $width) {
if(isset($wrapped[$col][$i])) {
$val = $wrapped[$col][$i];
} else {
$val = '';
}
$out .= sprintf('%-'.$width.'s', $val);
}
$out .= "\n";
}
return $out;
}
}
/**
* Class DokuCLI_Exception
*
* The code is used as exit code for the CLI tool. This should probably be extended. Many cases just fall back to the
* E_ANY code.
*
* @author Andreas Gohr <andi@splitbrain.org>
*/
class DokuCLI_Exception extends Exception {
const E_ANY = -1; // no error code specified
const E_UNKNOWN_OPT = 1; //Unrecognized option
const E_OPT_ARG_REQUIRED = 2; //Option requires argument
const E_OPT_ARG_DENIED = 3; //Option not allowed argument
const E_OPT_ABIGUOUS = 4; //Option abiguous
const E_ARG_READ = 5; //Could not read argv
/**
* @param string $message The Exception message to throw.
* @param int $code The Exception code
* @param Exception $previous The previous exception used for the exception chaining.
*/
public function __construct($message = "", $code = 0, Exception $previous = null) {
if(!$code) $code = DokuCLI_Exception::E_ANY;
parent::__construct($message, $code, $previous);
}
}

File diff suppressed because it is too large Load diff

View file

@ -1,82 +0,0 @@
<?php
/**
* compatibility functions
*
* This file contains a few functions that might be missing from the PHP build
*/
if(!function_exists('ctype_space')) {
/**
* Check for whitespace character(s)
*
* @see ctype_space
* @param string $text
* @return bool
*/
function ctype_space($text) {
if(!is_string($text)) return false; #FIXME original treats between -128 and 255 inclusive as ASCII chars
if(trim($text) === '') return true;
return false;
}
}
if(!function_exists('ctype_digit')) {
/**
* Check for numeric character(s)
*
* @see ctype_digit
* @param string $text
* @return bool
*/
function ctype_digit($text) {
if(!is_string($text)) return false; #FIXME original treats between -128 and 255 inclusive as ASCII chars
if(preg_match('/^\d+$/', $text)) return true;
return false;
}
}
if(!function_exists('gzopen') && function_exists('gzopen64')) {
/**
* work around for PHP compiled against certain zlib versions #865
*
* @link http://stackoverflow.com/questions/23417519/php-zlib-gzopen-not-exists
*
* @param string $filename
* @param string $mode
* @param int $use_include_path
* @return mixed
*/
function gzopen($filename, $mode, $use_include_path = 0) {
return gzopen64($filename, $mode, $use_include_path);
}
}
if(!function_exists('gzseek') && function_exists('gzseek64')) {
/**
* work around for PHP compiled against certain zlib versions #865
*
* @link http://stackoverflow.com/questions/23417519/php-zlib-gzopen-not-exists
*
* @param resource $zp
* @param int $offset
* @param int $whence
* @return int
*/
function gzseek($zp, $offset, $whence = SEEK_SET) {
return gzseek64($zp, $offset, $whence);
}
}
if(!function_exists('gztell') && function_exists('gztell64')) {
/**
* work around for PHP compiled against certain zlib versions #865
*
* @link http://stackoverflow.com/questions/23417519/php-zlib-gzopen-not-exists
*
* @param resource $zp
* @return int
*/
function gztell($zp) {
return gztell64($zp);
}
}

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