From 51de8ca123f3789b5a6a98852fd9a8c4b938873b Mon Sep 17 00:00:00 2001 From: Christopher Smith Date: Mon, 18 Feb 2013 14:47:52 +0000 Subject: add comments for recent settings class additions to extra.class.php --- lib/plugins/config/settings/config.metadata.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/plugins/config/settings/config.metadata.php b/lib/plugins/config/settings/config.metadata.php index 22e76a013..4731ffc16 100644 --- a/lib/plugins/config/settings/config.metadata.php +++ b/lib/plugins/config/settings/config.metadata.php @@ -42,6 +42,8 @@ * 'im_convert' - as 'setting', input must exist and be an im_convert module * 'disableactions' - as 'setting' * 'compression' - no additional parameters. checks php installation supports possible compression alternatives + * 'licence' - as multichoice, selection constructed from licence strings in language files + * 'renderer' - as multichoice, selection constructed from enabled renderer plugins which canRender() * * Any setting commented or missing will use 'setting' class - text input, minimal validation, quoted output * -- cgit v1.2.3 From c89ab3e93dc9b6fadb29518a47e4b32a49666729 Mon Sep 17 00:00:00 2001 From: Christopher Smith Date: Mon, 18 Feb 2013 14:49:42 +0000 Subject: remove php_strip_whitespace() alternate, no longer required as php min req't ensures its always present --- lib/plugins/config/settings/config.class.php | 94 ---------------------------- 1 file changed, 94 deletions(-) diff --git a/lib/plugins/config/settings/config.class.php b/lib/plugins/config/settings/config.class.php index e5e09d8f8..427178c40 100644 --- a/lib/plugins/config/settings/config.class.php +++ b/lib/plugins/config/settings/config.class.php @@ -1083,97 +1083,3 @@ if (!class_exists('setting_multicheckbox')) { } } } - -/** - * Provide php_strip_whitespace (php5 function) functionality - * - * @author Chris Smith - */ -if (!function_exists('php_strip_whitespace')) { - - if (function_exists('token_get_all')) { - - if (!defined('T_ML_COMMENT')) { - define('T_ML_COMMENT', T_COMMENT); - } else { - define('T_DOC_COMMENT', T_ML_COMMENT); - } - - /** - * modified from original - * source Google Groups, php.general, by David Otton - */ - function php_strip_whitespace($file) { - if (!@is_readable($file)) return ''; - - $in = join('',@file($file)); - $out = ''; - - $tokens = token_get_all($in); - - foreach ($tokens as $token) { - if (is_string ($token)) { - $out .= $token; - } else { - list ($id, $text) = $token; - switch ($id) { - case T_COMMENT : // fall thru - case T_ML_COMMENT : // fall thru - case T_DOC_COMMENT : // fall thru - case T_WHITESPACE : - break; - default : $out .= $text; break; - } - } - } - return ($out); - } - - } else { - - function is_whitespace($c) { return (strpos("\t\n\r ",$c) !== false); } - function is_quote($c) { return (strpos("\"'",$c) !== false); } - function is_escaped($s,$i) { - $idx = $i-1; - while(($idx>=0) && ($s{$idx} == '\\')) $idx--; - return (($i - $idx + 1) % 2); - } - - function is_commentopen($str, $i) { - if ($str{$i} == '#') return "\n"; - if ($str{$i} == '/') { - if ($str{$i+1} == '/') return "\n"; - if ($str{$i+1} == '*') return "*/"; - } - - return false; - } - - function php_strip_whitespace($file) { - - if (!@is_readable($file)) return ''; - - $contents = join('',@file($file)); - $out = ''; - - $state = 0; - for ($i=0; $i Date: Mon, 18 Feb 2013 15:14:51 +0000 Subject: remove no longer used email pattern, validation is done by mail_* functions --- lib/plugins/config/settings/config.class.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/plugins/config/settings/config.class.php b/lib/plugins/config/settings/config.class.php index 427178c40..ec5f73fa5 100644 --- a/lib/plugins/config/settings/config.class.php +++ b/lib/plugins/config/settings/config.class.php @@ -659,10 +659,8 @@ if (!class_exists('setting_password')) { } if (!class_exists('setting_email')) { - if (!defined('SETTING_EMAIL_PATTERN')) define('SETTING_EMAIL_PATTERN','<^'.PREG_PATTERN_VALID_EMAIL.'$>'); class setting_email extends setting_string { - var $_pattern = SETTING_EMAIL_PATTERN; // no longer required, retained for backward compatibility - FIXME, may not be necessary var $_multiple = false; var $_placeholders = false; -- cgit v1.2.3 From d110fb0d68e5a037b6db151d7bfd4881c48ccdec Mon Sep 17 00:00:00 2001 From: Christopher Smith Date: Mon, 18 Feb 2013 15:51:06 +0000 Subject: FS#2722 add settings_regex class, use it for hidepages --- lib/plugins/config/settings/config.class.php | 37 +++++++++++++++++++++++++ lib/plugins/config/settings/config.metadata.php | 8 +++++- 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/lib/plugins/config/settings/config.class.php b/lib/plugins/config/settings/config.class.php index ec5f73fa5..bbb25b695 100644 --- a/lib/plugins/config/settings/config.class.php +++ b/lib/plugins/config/settings/config.class.php @@ -1081,3 +1081,40 @@ if (!class_exists('setting_multicheckbox')) { } } } + +if (!class_exists('setting_regex')){ + class setting_regex extends setting_string { + + var $_delimiter = '/'; // regex delimiter to be used in testing input + var $_pregflags = 'ui'; // regex pattern modifiers to be used in testing input + + /** + * update changed setting with user provided value $input + * - if changed value fails error check, save it to $this->_input (to allow echoing later) + * - if changed value passes error check, set $this->_local to the new value + * + * @param mixed $input the new value + * @return boolean true if changed, false otherwise (incl. on error) + */ + function update($input) { + + // let parent do basic checks, value, not changed, etc. + $local = $this->_local; + if (!parent::update($input)) return false; + $this->_local = $local; + + // see if the regex compiles and runs (we don't check for effectiveness) + $regex = $this->_delimiter . $input . $this->_delimiter . $this->_pregflags; + $lastError = error_get_last(); + $ok = @preg_match($regex,'testdata'); + if (preg_last_error() != PREG_NO_ERROR || error_get_last() != $lastError) { + $this->_input = $input; + $this->_error = true; + return false; + } + + $this->_local = $input; + return true; + } + } +} \ No newline at end of file diff --git a/lib/plugins/config/settings/config.metadata.php b/lib/plugins/config/settings/config.metadata.php index 4731ffc16..5aedaa6f1 100644 --- a/lib/plugins/config/settings/config.metadata.php +++ b/lib/plugins/config/settings/config.metadata.php @@ -33,6 +33,9 @@ * 'array' - a simple (one dimensional) array of string values, shown as comma separated list in the * config manager but saved as PHP array(). Values may not contain commas themselves. * _pattern matching on the array values supported. + * 'regex' - regular expression string, normally without delimiters; as for string, in addition tested + * to see if will compile & run as a regex. in addition to _pattern, also accepts _delimiter + * (default '/') and _pregflags (default 'ui') * * Single Setting (source: settings/extra.class.php) * ------------------------------------------------- @@ -60,6 +63,9 @@ * '_code' - encoding method to use, accepted values: 'base64','uuencode','plain'. defaults to plain. * '_min' - minimum numeric value, optional for 'numeric' and 'numericopt', ignored by others * '_max' - maximum numeric value, optional for 'numeric' and 'numericopt', ignored by others + * '_delimiter' - string, default '/', a single character used as a delimiter for testing regex input values + * '_pregflags' - string, default 'ui', valid preg pattern modifiers used when testing regex input values, for more + * information see http://uk1.php.net/manual/en/reference.pcre.pattern.modifiers.php * * @author Chris Smith */ @@ -115,7 +121,7 @@ $meta['camelcase'] = array('onoff'); $meta['deaccent'] = array('multichoice','_choices' => array(0,1,2)); $meta['useheading'] = array('multichoice','_choices' => array(0,'navigation','content',1)); $meta['sneaky_index'] = array('onoff'); -$meta['hidepages'] = array('string'); +$meta['hidepages'] = array('regex'); $meta['_authentication'] = array('fieldset'); $meta['useacl'] = array('onoff'); -- cgit v1.2.3 From d433710d8084d65218569a93034cec1e28bbeb43 Mon Sep 17 00:00:00 2001 From: Christopher Smith Date: Mon, 18 Feb 2013 17:32:13 +0000 Subject: fix security caution for 'remote' setting (was 'xmlrpc') --- lib/plugins/config/settings/config.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/plugins/config/settings/config.class.php b/lib/plugins/config/settings/config.class.php index bbb25b695..f7ab6606b 100644 --- a/lib/plugins/config/settings/config.class.php +++ b/lib/plugins/config/settings/config.class.php @@ -370,7 +370,7 @@ if (!class_exists('setting')) { var $_cautionList = array( 'basedir' => 'danger', 'baseurl' => 'danger', 'savedir' => 'danger', 'cookiedir' => 'danger', 'useacl' => 'danger', 'authtype' => 'danger', 'superuser' => 'danger', 'userewrite' => 'danger', 'start' => 'warning', 'camelcase' => 'warning', 'deaccent' => 'warning', 'sepchar' => 'warning', 'compression' => 'warning', 'xsendfile' => 'warning', 'renderer_xhtml' => 'warning', 'fnencode' => 'warning', - 'allowdebug' => 'security', 'htmlok' => 'security', 'phpok' => 'security', 'iexssprotect' => 'security', 'xmlrpc' => 'security', 'fullpath' => 'security' + 'allowdebug' => 'security', 'htmlok' => 'security', 'phpok' => 'security', 'iexssprotect' => 'security', 'remote' => 'security', 'fullpath' => 'security' ); function setting($key, $params=null) { -- cgit v1.2.3 From 9dc3b8ab758eb9236e8f1933309f2bc539cf3f5e Mon Sep 17 00:00:00 2001 From: Christopher Smith Date: Mon, 18 Feb 2013 17:51:45 +0000 Subject: replace preset _cautionList property with _caution config metadata parameter, plugins can now easily set cautions on their settings --- lib/plugins/config/settings/config.class.php | 27 +++++++++++---- lib/plugins/config/settings/config.metadata.php | 45 +++++++++++++------------ 2 files changed, 43 insertions(+), 29 deletions(-) diff --git a/lib/plugins/config/settings/config.class.php b/lib/plugins/config/settings/config.class.php index f7ab6606b..1c7d8f680 100644 --- a/lib/plugins/config/settings/config.class.php +++ b/lib/plugins/config/settings/config.class.php @@ -366,12 +366,11 @@ if (!class_exists('setting')) { var $_pattern = ''; var $_error = false; // only used by those classes which error check var $_input = null; // only used by those classes which error check + var $_caution = null; // used by any setting to provide an alert along with the setting + // valid alerts, 'warning', 'danger', 'security' + // images matching the alerts are in the plugin's images directory - var $_cautionList = array( - 'basedir' => 'danger', 'baseurl' => 'danger', 'savedir' => 'danger', 'cookiedir' => 'danger', 'useacl' => 'danger', 'authtype' => 'danger', 'superuser' => 'danger', 'userewrite' => 'danger', - 'start' => 'warning', 'camelcase' => 'warning', 'deaccent' => 'warning', 'sepchar' => 'warning', 'compression' => 'warning', 'xsendfile' => 'warning', 'renderer_xhtml' => 'warning', 'fnencode' => 'warning', - 'allowdebug' => 'security', 'htmlok' => 'security', 'phpok' => 'security', 'iexssprotect' => 'security', 'remote' => 'security', 'fullpath' => 'security' - ); + static protected $_validCautions = array('warning','danger','security'); function setting($key, $params=null) { $this->_key = $key; @@ -473,8 +472,22 @@ if (!class_exists('setting')) { function error() { return $this->_error; } function caution() { - if (!array_key_exists($this->_key, $this->_cautionList)) return false; - return $this->_cautionList[$this->_key]; + if (!empty($this->_caution)) { + if (!in_array($this->_caution, setting::$_validCautions)) { + trigger_error('Invalid caution string ('.$this->_caution.') in metadata for setting "'.$this->_key.'"', E_USER_WARNING); + return false; + } + return $this->_caution; + } + // compatibility with previous cautionList + // TODO: check if any plugins use; remove + if (!empty($this->_cautionList[$this->_key])) { + $this->_caution = $this->_cautionList[$this->_key]; + unset($this->_cautionList); + + return $this->caution(); + } + return false; } function _out_key($pretty=false,$url=false) { diff --git a/lib/plugins/config/settings/config.metadata.php b/lib/plugins/config/settings/config.metadata.php index 5aedaa6f1..08003a3e4 100644 --- a/lib/plugins/config/settings/config.metadata.php +++ b/lib/plugins/config/settings/config.metadata.php @@ -51,6 +51,7 @@ * Any setting commented or missing will use 'setting' class - text input, minimal validation, quoted output * * Defined parameters: + * '_caution' - no value (default) or 'warning', 'danger', 'security'. display an alert along with the setting * '_pattern' - string, a preg pattern. input is tested against this pattern before being accepted * optional all classes, except onoff & multichoice which ignore it * '_choices' - array of choices. used to populate a selection box. choice will be replaced by a localised @@ -89,26 +90,26 @@ $config['heading'] = 'Dokuwiki\'s Main Configuration File - Local Settings'; $meta['_basic'] = array('fieldset'); $meta['title'] = array('string'); -$meta['start'] = array('string','_pattern' => '!^[^:;/]+$!'); // don't accept namespaces +$meta['start'] = array('string','_caution' => 'warning','_pattern' => '!^[^:;/]+$!'); // don't accept namespaces $meta['lang'] = array('dirchoice','_dir' => DOKU_INC.'inc/lang/'); $meta['template'] = array('dirchoice','_dir' => DOKU_INC.'lib/tpl/','_pattern' => '/^[\w-]+$/'); $meta['tagline'] = array('string'); $meta['sidebar'] = array('string'); $meta['license'] = array('license'); -$meta['savedir'] = array('savedir'); -$meta['basedir'] = array('string'); -$meta['baseurl'] = array('string'); -$meta['cookiedir'] = array('string'); +$meta['savedir'] = array('savedir','_caution' => 'danger'); +$meta['basedir'] = array('string','_caution' => 'danger'); +$meta['baseurl'] = array('string','_caution' => 'danger'); +$meta['cookiedir'] = array('string','_caution' => 'danger'); $meta['dmode'] = array('numeric','_pattern' => '/0[0-7]{3,4}/'); // only accept octal representation $meta['fmode'] = array('numeric','_pattern' => '/0[0-7]{3,4}/'); // only accept octal representation -$meta['allowdebug'] = array('onoff'); +$meta['allowdebug'] = array('onoff','_caution' => 'security'); $meta['_display'] = array('fieldset'); $meta['recent'] = array('numeric'); $meta['recent_days'] = array('numeric'); $meta['breadcrumbs'] = array('numeric','_min' => 0); $meta['youarehere'] = array('onoff'); -$meta['fullpath'] = array('onoff'); +$meta['fullpath'] = array('onoff','_caution' => 'security'); $meta['typography'] = array('multichoice','_choices' => array(0,1,2)); $meta['dformat'] = array('string'); $meta['signature'] = array('string'); @@ -117,19 +118,19 @@ $meta['toptoclevel'] = array('multichoice','_choices' => array(1,2,3,4,5)); // $meta['tocminheads'] = array('multichoice','_choices' => array(0,1,2,3,4,5,10,15,20)); $meta['maxtoclevel'] = array('multichoice','_choices' => array(0,1,2,3,4,5)); $meta['maxseclevel'] = array('multichoice','_choices' => array(0,1,2,3,4,5)); // 0 for no sec edit buttons -$meta['camelcase'] = array('onoff'); -$meta['deaccent'] = array('multichoice','_choices' => array(0,1,2)); +$meta['camelcase'] = array('onoff','_caution' => 'warning'); +$meta['deaccent'] = array('multichoice','_choices' => array(0,1,2),'_caution' => 'warning'); $meta['useheading'] = array('multichoice','_choices' => array(0,'navigation','content',1)); $meta['sneaky_index'] = array('onoff'); $meta['hidepages'] = array('regex'); $meta['_authentication'] = array('fieldset'); -$meta['useacl'] = array('onoff'); +$meta['useacl'] = array('onoff','_caution' => 'danger'); $meta['autopasswd'] = array('onoff'); -$meta['authtype'] = array('authtype'); +$meta['authtype'] = array('authtype','_caution' => 'danger'); $meta['passcrypt'] = array('multichoice','_choices' => array('smd5','md5','apr1','sha1','ssha','lsmd5','crypt','mysql','my411','kmd5','pmd5','hmd5','mediawiki','bcrypt','djangomd5','djangosha1','sha512')); $meta['defaultgroup']= array('string'); -$meta['superuser'] = array('string'); +$meta['superuser'] = array('string','_caution' => 'danger'); $meta['manager'] = array('string'); $meta['profileconfirm'] = array('onoff'); $meta['rememberme'] = array('onoff'); @@ -138,7 +139,7 @@ $meta['disableactions'] = array('disableactions', '_combine' => array('subscription' => array('subscribe','unsubscribe'), 'wikicode' => array('source','export_raw'))); $meta['auth_security_timeout'] = array('numeric'); $meta['securecookie'] = array('onoff'); -$meta['remote'] = array('onoff'); +$meta['remote'] = array('onoff','_caution' => 'security'); $meta['remoteuser'] = array('string'); $meta['_anti_spam'] = array('fieldset'); @@ -146,12 +147,12 @@ $meta['usewordblock']= array('onoff'); $meta['relnofollow'] = array('onoff'); $meta['indexdelay'] = array('numeric'); $meta['mailguard'] = array('multichoice','_choices' => array('visible','hex','none')); -$meta['iexssprotect']= array('onoff'); +$meta['iexssprotect']= array('onoff','_caution' => 'security'); $meta['_editing'] = array('fieldset'); $meta['usedraft'] = array('onoff'); -$meta['htmlok'] = array('onoff'); -$meta['phpok'] = array('onoff'); +$meta['htmlok'] = array('onoff','_caution' => 'security'); +$meta['phpok'] = array('onoff','_caution' => 'security'); $meta['locktime'] = array('numeric'); $meta['cachetime'] = array('numeric'); @@ -191,20 +192,20 @@ $meta['rss_show_summary'] = array('onoff'); $meta['_advanced'] = array('fieldset'); $meta['updatecheck'] = array('onoff'); -$meta['userewrite'] = array('multichoice','_choices' => array(0,1,2)); +$meta['userewrite'] = array('multichoice','_choices' => array(0,1,2),'_caution' => 'danger'); $meta['useslash'] = array('onoff'); -$meta['sepchar'] = array('sepchar'); +$meta['sepchar'] = array('sepchar','_caution' => 'warning'); $meta['canonical'] = array('onoff'); -$meta['fnencode'] = array('multichoice','_choices' => array('url','safe','utf-8')); +$meta['fnencode'] = array('multichoice','_choices' => array('url','safe','utf-8'),'_caution' => 'warning'); $meta['autoplural'] = array('onoff'); $meta['compress'] = array('onoff'); $meta['cssdatauri'] = array('numeric','_pattern' => '/^\d+$/'); $meta['gzip_output'] = array('onoff'); $meta['send404'] = array('onoff'); -$meta['compression'] = array('compression'); +$meta['compression'] = array('compression','_caution' => 'warning'); $meta['broken_iua'] = array('onoff'); -$meta['xsendfile'] = array('multichoice','_choices' => array(0,1,2,3)); -$meta['renderer_xhtml'] = array('renderer','_format' => 'xhtml','_choices' => array('xhtml')); +$meta['xsendfile'] = array('multichoice','_choices' => array(0,1,2,3),'_caution' => 'warning'); +$meta['renderer_xhtml'] = array('renderer','_format' => 'xhtml','_choices' => array('xhtml'),'_caution' => 'warning'); $meta['readdircache'] = array('numeric'); $meta['_network'] = array('fieldset'); -- cgit v1.2.3 From 64b85cca2e8112341456bb9413ed2dc33050b607 Mon Sep 17 00:00:00 2001 From: Christopher Smith Date: Mon, 18 Feb 2013 18:51:01 +0000 Subject: change tpl_actiondropdown request method to 'get' --- inc/template.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/inc/template.php b/inc/template.php index a5bcabf1e..e9c0f1699 100644 --- a/inc/template.php +++ b/inc/template.php @@ -1373,7 +1373,7 @@ function tpl_actiondropdown($empty = '', $button = '>') { global $REV; global $lang; - echo '
'; + echo ''; echo '
'; echo ''; if($REV) echo ''; -- cgit v1.2.3 From f2cf18dae6f9e86142c9c20294266562f69fe641 Mon Sep 17 00:00:00 2001 From: Christopher Smith Date: Mon, 18 Feb 2013 18:55:33 +0000 Subject: remove security token from tpl_actiondropdown - its not necessary, we're not posting any system change --- inc/template.php | 1 - 1 file changed, 1 deletion(-) diff --git a/inc/template.php b/inc/template.php index e9c0f1699..1734b08a0 100644 --- a/inc/template.php +++ b/inc/template.php @@ -1377,7 +1377,6 @@ function tpl_actiondropdown($empty = '', $button = '>') { echo '
'; echo ''; if($REV) echo ''; - echo ''; echo ''; if($REV) echo ''; + if ($_SERVER['REMOTE_USER']) { + echo ''; + } echo ''; -- cgit v1.2.3 From b6235013d0c936d6852299af46d0f6a7eb907665 Mon Sep 17 00:00:00 2001 From: Michael Hamann Date: Wed, 20 Feb 2013 19:43:29 +0100 Subject: Fix handling of failed authentication loading In the case of a failed authentication initialization, the authentication setup was simply continued with an unset $auth object. This restores the previous behavior (before merging #141) of simply returning after unsetting $auth. Furthermore this re-introduces the check if $auth is set before checking $auth and removes a useless check if $auth is true (could never be false). --- inc/auth.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/inc/auth.php b/inc/auth.php index d82b8b5dd..92a56e163 100644 --- a/inc/auth.php +++ b/inc/auth.php @@ -54,16 +54,17 @@ function auth_setup() { } } - if(!$auth){ + if(!isset($auth) || !$auth){ msg($lang['authtempfail'], -1); return false; } - if ($auth && $auth->success == false) { + if ($auth->success == false) { // degrade to unauthenticated user unset($auth); auth_logoff(); msg($lang['authtempfail'], -1); + return false; } // do the login either by cookie or provided credentials XXX -- cgit v1.2.3 From e8baa2279f46cfaaf18a54d75c1329d266a4ca47 Mon Sep 17 00:00:00 2001 From: Michael Hamann Date: Wed, 20 Feb 2013 20:18:59 +0100 Subject: Revert the search depth behavior changes from #154 This reverts parts of the changes from #154: Before merging the pull request, a depth of 1 returned just the pages in the root namespace. With the changes in the pull request, a depth of 1 also returned pages in subnamespaces of the root namespace (as it was also tested in the test case). This reverts this part of the changes and a depth of 1 returns just the pages in the root namespace again. --- _test/tests/inc/search/search.test.php | 4 ++-- inc/search.php | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/_test/tests/inc/search/search.test.php b/_test/tests/inc/search/search.test.php index 9c854a661..33d4e9d8d 100644 --- a/_test/tests/inc/search/search.test.php +++ b/_test/tests/inc/search/search.test.php @@ -22,9 +22,9 @@ class search_test extends DokuWikiTest { search($data, dirname(__FILE__) . '/data', 'search_allpages', array('depth' => 1), 'ns1/ns3'); $this->assertEquals(0, count($data)); - //depth is 1 so I should get only pages from ns1 + //depth is 2 so I should get only pages from ns1 $data = array(); - search($data, dirname(__FILE__) . '/data', 'search_allpages', array('depth' => 1), 'ns1'); + search($data, dirname(__FILE__) . '/data', 'search_allpages', array('depth' => 2), 'ns1'); $this->assertEquals(2, count($data)); } diff --git a/inc/search.php b/inc/search.php index e4aa3b9eb..6927fff5f 100644 --- a/inc/search.php +++ b/inc/search.php @@ -243,8 +243,8 @@ function search_pagename(&$data,$base,$file,$type,$lvl,$opts){ function search_allpages(&$data,$base,$file,$type,$lvl,$opts){ if(isset($opts['depth']) && $opts['depth']){ $parts = explode('/',ltrim($file,'/')); - if(($type == 'd' && count($parts) > $opts['depth']) - || ($type != 'd' && count($parts) > $opts['depth'] + 1)){ + if(($type == 'd' && count($parts) >= $opts['depth']) + || ($type != 'd' && count($parts) > $opts['depth'])){ return false; // depth reached } } -- cgit v1.2.3 From 9507770d8c13e47b975bf35fe25264448da3f28a Mon Sep 17 00:00:00 2001 From: Michael Hamann Date: Wed, 20 Feb 2013 20:26:05 +0100 Subject: Fix remaining missing $INPUT uses FS#2577 This adds $INPUT in all places where it was still missing and available. $INPUT is now also used in places where using $_REQUEST/... was okay in order to make the code consistent. --- doku.php | 2 +- inc/auth.php | 2 +- lib/plugins/authad/auth.php | 5 +++-- lib/plugins/plugin/admin.php | 3 ++- lib/plugins/revert/admin.php | 13 +++++++------ lib/plugins/usermanager/admin.php | 25 +++++++++++++------------ 6 files changed, 27 insertions(+), 23 deletions(-) diff --git a/doku.php b/doku.php index 607303ca4..68976ebb3 100644 --- a/doku.php +++ b/doku.php @@ -29,7 +29,7 @@ if(isset($_SERVER['HTTP_X_DOKUWIKI_DO'])) { require_once(DOKU_INC.'inc/init.php'); //import variables -$_REQUEST['id'] = str_replace("\xC2\xAD", '', $INPUT->str('id')); //soft-hyphen +$INPUT->set('id', str_replace("\xC2\xAD", '', $INPUT->str('id'))); //soft-hyphen $QUERY = trim($INPUT->str('id')); $ID = getID(); diff --git a/inc/auth.php b/inc/auth.php index 92a56e163..68b6b438d 100644 --- a/inc/auth.php +++ b/inc/auth.php @@ -92,7 +92,7 @@ function auth_setup() { // apply cleaning if (true === $auth->success) { - $_REQUEST['u'] = $auth->cleanUser($_REQUEST['u']); + $INPUT->set('u', $auth->cleanUser($INPUT->str('u'))); } if($INPUT->str('authtok')) { diff --git a/lib/plugins/authad/auth.php b/lib/plugins/authad/auth.php index f651d87a1..6c49eafbb 100644 --- a/lib/plugins/authad/auth.php +++ b/lib/plugins/authad/auth.php @@ -71,6 +71,7 @@ class auth_plugin_authad extends DokuWiki_Auth_Plugin { * Constructor */ public function __construct() { + global $INPUT; parent::__construct(); // we load the config early to modify it a bit here @@ -99,8 +100,8 @@ class auth_plugin_authad extends DokuWiki_Auth_Plugin { // we need to simulate a login if(empty($_COOKIE[DOKU_COOKIE])) { - $_REQUEST['u'] = $_SERVER['REMOTE_USER']; - $_REQUEST['p'] = 'sso_only'; + $INPUT->set('u', $_SERVER['REMOTE_USER']); + $INPUT->set('p', 'sso_only'); } } diff --git a/lib/plugins/plugin/admin.php b/lib/plugins/plugin/admin.php index 8b1ee3c7d..de4de6aef 100644 --- a/lib/plugins/plugin/admin.php +++ b/lib/plugins/plugin/admin.php @@ -61,11 +61,12 @@ class admin_plugin_plugin extends DokuWiki_Admin_Plugin { * handle user request */ function handle() { + global $INPUT; // enable direct access to language strings $this->setupLocale(); - $fn = $_REQUEST['fn']; + $fn = $INPUT->param('fn'); if (is_array($fn)) { $this->cmd = key($fn); $this->plugin = is_array($fn[$this->cmd]) ? key($fn[$this->cmd]) : null; diff --git a/lib/plugins/revert/admin.php b/lib/plugins/revert/admin.php index fcdaa230d..847e38876 100644 --- a/lib/plugins/revert/admin.php +++ b/lib/plugins/revert/admin.php @@ -44,15 +44,16 @@ class admin_plugin_revert extends DokuWiki_Admin_Plugin { * output appropriate html */ function html() { + global $INPUT; echo $this->plugin_locale_xhtml('intro'); $this->_searchform(); - if(is_array($_REQUEST['revert']) && checkSecurityToken()){ - $this->_revert($_REQUEST['revert'],$_REQUEST['filter']); - }elseif(isset($_REQUEST['filter'])){ - $this->_list($_REQUEST['filter']); + if(is_array($INPUT->param('revert')) && checkSecurityToken()){ + $this->_revert($INPUT->arr('revert'),$INPUT->str('filter')); + }elseif($INPUT->has('filter')){ + $this->_list($INPUT->str('filter')); } } @@ -60,10 +61,10 @@ class admin_plugin_revert extends DokuWiki_Admin_Plugin { * Display the form for searching spam pages */ function _searchform(){ - global $lang; + global $lang, $INPUT; echo '
'; echo ''; - echo ''; + echo ''; echo ' '; echo ' '.$this->getLang('note1').''; echo '


'; diff --git a/lib/plugins/usermanager/admin.php b/lib/plugins/usermanager/admin.php index cf8963e64..01f4a4cdb 100644 --- a/lib/plugins/usermanager/admin.php +++ b/lib/plugins/usermanager/admin.php @@ -73,11 +73,12 @@ class admin_plugin_usermanager extends DokuWiki_Admin_Plugin { * handle user request */ function handle() { + global $INPUT; if (is_null($this->_auth)) return false; // extract the command and any specific parameters // submit button name is of the form - fn[cmd][param(s)] - $fn = $_REQUEST['fn']; + $fn = $INPUT->param('fn'); if (is_array($fn)) { $cmd = key($fn); @@ -88,8 +89,7 @@ class admin_plugin_usermanager extends DokuWiki_Admin_Plugin { } if ($cmd != "search") { - if (!empty($_REQUEST['start'])) - $this->_start = $_REQUEST['start']; + $this->_start = $INPUT->int('start', 0); $this->_filter = $this->_retrieveFilter(); } @@ -345,6 +345,7 @@ class admin_plugin_usermanager extends DokuWiki_Admin_Plugin { } function _addUser(){ + global $INPUT; if (!checkSecurityToken()) return false; if (!$this->_auth->canDo('addUser')) return false; @@ -353,7 +354,7 @@ class admin_plugin_usermanager extends DokuWiki_Admin_Plugin { if ($this->_auth->canDo('modPass')){ if (empty($pass)){ - if(!empty($_REQUEST['usernotify'])){ + if($INPUT->has('usernotify')){ $pass = auth_pwgen(); } else { msg($this->lang['add_fail'], -1); @@ -393,7 +394,7 @@ class admin_plugin_usermanager extends DokuWiki_Admin_Plugin { msg($this->lang['add_ok'], 1); - if (!empty($_REQUEST['usernotify']) && $pass) { + if ($INPUT->has('usernotify') && $pass) { $this->_notifyUser($user,$pass); } } else { @@ -407,13 +408,13 @@ class admin_plugin_usermanager extends DokuWiki_Admin_Plugin { * Delete user */ function _deleteUser(){ - global $conf; + global $conf, $INPUT; if (!checkSecurityToken()) return false; if (!$this->_auth->canDo('delUser')) return false; - $selected = $_REQUEST['delete']; - if (!is_array($selected) || empty($selected)) return false; + $selected = $INPUT->arr('delete'); + if (empty($selected)) return false; $selected = array_keys($selected); if(in_array($_SERVER['REMOTE_USER'], $selected)) { @@ -463,13 +464,13 @@ class admin_plugin_usermanager extends DokuWiki_Admin_Plugin { * Modify user (modified user data has been recieved) */ function _modifyUser(){ - global $conf; + global $conf, $INPUT; if (!checkSecurityToken()) return false; if (!$this->_auth->canDo('UserMod')) return false; // get currently valid user data - $olduser = cleanID(preg_replace('/.*:/','',$_REQUEST['userid_old'])); + $olduser = cleanID(preg_replace('/.*:/','',$INPUT->str('userid_old'))); $oldinfo = $this->_auth->getUserData($olduser); // get new user data subject to change @@ -494,7 +495,7 @@ class admin_plugin_usermanager extends DokuWiki_Admin_Plugin { } // generate password if left empty and notification is on - if(!empty($_REQUEST['usernotify']) && empty($newpass)){ + if($INPUT->has('usernotify') && empty($newpass)){ $newpass = auth_pwgen(); } @@ -510,7 +511,7 @@ class admin_plugin_usermanager extends DokuWiki_Admin_Plugin { if ($ok = $this->_auth->triggerUserMod('modify', array($olduser, $changes))) { msg($this->lang['update_ok'],1); - if (!empty($_REQUEST['usernotify']) && $newpass) { + if ($INPUT->has('usernotify') && $newpass) { $notify = empty($changes['user']) ? $olduser : $newuser; $this->_notifyUser($notify,$newpass); } -- cgit v1.2.3 From 5ab3b7775958f5a1f8db8c791eed4c4a035c284a Mon Sep 17 00:00:00 2001 From: Christopher Smith Date: Thu, 21 Feb 2013 21:59:05 +0000 Subject: add unit test for pageinfo() --- _test/tests/inc/common_pageinfo.test.php | 299 +++++++++++++++++++++++++++++++ 1 file changed, 299 insertions(+) create mode 100644 _test/tests/inc/common_pageinfo.test.php diff --git a/_test/tests/inc/common_pageinfo.test.php b/_test/tests/inc/common_pageinfo.test.php new file mode 100644 index 000000000..c54fbce26 --- /dev/null +++ b/_test/tests/inc/common_pageinfo.test.php @@ -0,0 +1,299 @@ + + */ +class common_pageinfo_test extends DokuWikiTest { + + function setup(){ + parent::setup(); + + global $USERINFO; + $USERINFO = array( + 'pass' => '179ad45c6ce2cb97cf1029e212046e81', + 'name' => 'Arthur Dent', + 'mail' => 'arthur@example.com', + 'grps' => array ('admin','user'), + ); + $_SERVER['REMOTE_USER'] = 'testuser'; + $_SERVER['REMOTE_ADDR'] = '1.2.3.4'; + } + + function _get_expected_pageinfo() { + global $USERINFO; + $info = array ( + 'isadmin' => true, + 'ismanager' => true, + 'userinfo' => $USERINFO, + 'perm' => 255, + 'namespace' => false, + 'ismobile' => false, + 'client' => 'testuser', + ); + $info['rev'] = null; + $info['subscribed'] = false; + $info['locked'] = false; + $info['exists'] = false; + $info['writable'] = true; + $info['editable'] = true; + $info['lastmod'] = false; + $info['meta'] = array(); + $info['ip'] = null; + $info['user'] = null; + $info['sum'] = null; + $info['editor'] = null; + + return $info; + } + + /** + * check info keys and values for a non-existent page & admin user + */ + function test_basic_nonexistentpage(){ + global $ID,$conf; + $ID = 'wiki:start'; + + $info = $this->_get_expected_pageinfo(); + $info['id'] = 'wiki:start'; + $info['namespace'] = 'wiki'; + $info['filepath'] = $conf['datadir'].'/wiki/start.txt'; + + $this->assertEquals($info, pageinfo()); + } + + /** + * check info keys and values for a existing page & admin user + */ + function test_basic_existingpage(){ + global $ID,$conf; + $ID = 'wiki:syntax'; + $filename = $conf['datadir'].'/wiki/syntax.txt'; + $rev = filemtime($filename); + + $info = $this->_get_expected_pageinfo(); + $info['id'] = 'wiki:syntax'; + $info['namespace'] = 'wiki'; + $info['filepath'] = $filename; + $info['exists'] = true; + $info['lastmod'] = $rev; + $info['meta'] = p_get_metadata($ID); + + $this->assertEquals($info, pageinfo()); + } + + /** + * check info keys and values for anonymous user + */ + function test_anonymoususer(){ + global $ID,$conf,$REV; + + unset($_SERVER['REMOTE_USER']); + global $USERINFO; $USERINFO = array(); + + $ID = 'wiki:syntax'; + $filename = $conf['datadir'].'/wiki/syntax.txt'; + $rev = filemtime($filename); + + $info = $this->_get_expected_pageinfo(); + $info['id'] = 'wiki:syntax'; + $info['namespace'] = 'wiki'; + $info['filepath'] = $filename; + $info['exists'] = true; + $info['lastmod'] = $rev; + $info['meta'] = p_get_metadata($ID); + $info['rev'] = ''; + + $info = array_merge($info, array( + 'isadmin' => false, + 'ismanager' => false, + 'perm' => 8, + 'client' => '1.2.3.4', + )); + unset($info['userinfo']); + $this->assertEquals($info, pageinfo()); + } + + /** + * check info keys and values with $REV + * (also see $RANGE tests) + */ + function test_rev(){ + global $ID,$conf,$REV; + + $ID = 'wiki:syntax'; + $filename = $conf['datadir'].'/wiki/syntax.txt'; + $rev = filemtime($filename); + $REV = $rev - 100; + + $info = $this->_get_expected_pageinfo(); + $info['id'] = 'wiki:syntax'; + $info['namespace'] = 'wiki'; + $info['meta'] = p_get_metadata($ID); + $info['rev'] = $REV; + $info['filepath'] = str_replace('pages','attic',substr($filename,0,-3).$REV.'.txt.gz'); + + $this->assertEquals($info, pageinfo()); + $this->assertEquals($rev-100, $REV); + } + + /** + * check info keys and values with $RANGE + */ + function test_range(){ + global $ID,$conf,$REV,$RANGE; + + $ID = 'wiki:syntax'; + $filename = $conf['datadir'].'/wiki/syntax.txt'; + $rev = filemtime($filename); + $range = '1000-2000'; + + $info = $this->_get_expected_pageinfo(); + $info['id'] = 'wiki:syntax'; + $info['namespace'] = 'wiki'; + $info['exists'] = true; + $info['lastmod'] = $rev; + $info['meta'] = p_get_metadata($ID); + $info['filepath'] = $filename; + + // check $RANGE without $REV + // expected result $RANGE unchanged + $RANGE = $range; + + $this->assertEquals($info, pageinfo()); + $this->assertFalse(isset($REV)); + $this->assertEquals($range,$RANGE); + + // check $RANGE with $REV = current + // expected result: $RANGE unchanged, $REV cleared + $REV = $rev; + $info['rev'] = ''; + + $this->assertEquals($info, pageinfo()); + $this->assertEquals('',$REV); + $this->assertEquals($range,$RANGE); + + // check with a real $REV + // expected result: $REV and $RANGE are cleared + $REV = $rev - 100; + + $this->assertEquals($info, pageinfo()); + $this->assertEquals('',$REV); + $this->assertEquals('',$RANGE); + } + + /** + * test editor entry and external edit + */ + function test_editor_and_externaledits(){ + global $ID,$conf; + $ID = 'wiki:syntax'; + $filename = $conf['datadir'].'/wiki/syntax.txt'; + $rev = filemtime($filename); + + $info = $this->_get_expected_pageinfo(); + $info['id'] = 'wiki:syntax'; + $info['namespace'] = 'wiki'; + $info['filepath'] = $filename; + $info['exists'] = true; + $info['lastmod'] = $rev; + $info['meta'] = p_get_metadata($ID); // need $INFO set correctly for addLogEntry() + + global $INFO; + $INFO = $info; + + // add an editor for the current version of $ID + addLogEntry($rev, $ID); + + $info['meta'] = p_get_metadata($ID); + $info['editor'] = $_SERVER['REMOTE_USER']; + $info['user'] = $_SERVER['REMOTE_USER']; + $info['ip'] = $_SERVER['REMOTE_ADDR']; + $info['sum'] = ''; + + // with an editor ... + $this->assertEquals($info, pageinfo()); + + // clear the meta['last_change'] value, pageinfo should restore it + p_set_metadata($ID,array('last_change' => false)); + + $this->assertEquals($info, pageinfo()); + $this->assertEquals($info['meta']['last_change'], p_get_metadata($ID,'last_change')); + + // fake an external edit, pageinfo should clear the last change from meta data + // and not return any editor data + $now = time()+10; + touch($filename,$now); + + $info['lastmod'] = $now; + $info['meta']['last_change'] = false; + $info['ip'] = null; + $info['user'] = null; + $info['sum'] = null; + $info['editor'] = null; + + $this->assertEquals($info, pageinfo()); + $this->assertEquals($info['meta'], p_get_metadata($ID)); // check metadata has been updated correctly + } + + /** + * check draft + */ + function test_draft(){ + global $ID,$conf; + $ID = 'wiki:syntax'; + $filename = $conf['datadir'].'/wiki/syntax.txt'; + $rev = filemtime($filename); + + $info = $this->_get_expected_pageinfo(); + $info['id'] = 'wiki:syntax'; + $info['namespace'] = 'wiki'; + $info['filepath'] = $filename; + $info['exists'] = true; + $info['lastmod'] = $rev; + $info['meta'] = p_get_metadata($ID); + + // setup a draft, make it more recent than the current page + // - pageinfo should recognise it and keep it + $draft = getCacheName($info['client'].$ID,'.draft'); + touch($draft,$rev + 10); + + $info['draft'] = $draft; + + $this->assertEquals($info, pageinfo()); + $this->assertFileExists($draft); + + // make the draft older than the current page + // - pageinfo should remove it and not return the 'draft' key + touch($draft,$rev - 10); + unset($info['draft']); + + $this->assertEquals($info, pageinfo()); + $this->assertFalse(file_exists($draft)); + } + + /** + * check ismobile + */ + function test_ismobile(){ + global $ID,$conf; + $ID = 'wiki:start'; + + $info = $this->_get_expected_pageinfo(); + $info['id'] = 'wiki:start'; + $info['namespace'] = 'wiki'; + $info['filepath'] = $conf['datadir'].'/wiki/start.txt'; + + // overkill, ripped from clientismobile() as we aren't testing detection - but forcing it + $_SERVER['HTTP_X_WAP_PROFILE'] = 'a fake url'; + $_SERVER['HTTP_ACCEPT'] .= ';wap'; + $_SERVER['HTTP_USER_AGENT'] = 'blackberry,symbian,hand,mobi,phone'; + + $info['ismobile'] = clientismobile(); + + $this->assertTrue(clientismobile()); // ensure THIS test fails if clientismobile() returns false + $this->assertEquals($info, pageinfo()); // it would be a test failure not a pageinfo failure. + } +} + +//Setup VIM: ex: et ts=4 : -- cgit v1.2.3 From 11a53a83f01bf75d24afb7f184a4030d596958b4 Mon Sep 17 00:00:00 2001 From: Andreas Gohr Date: Fri, 22 Feb 2013 09:46:43 +0100 Subject: little change to syntax we had on the life site --- data/pages/wiki/syntax.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/data/pages/wiki/syntax.txt b/data/pages/wiki/syntax.txt index 55bbabab2..f2c2864ed 100644 --- a/data/pages/wiki/syntax.txt +++ b/data/pages/wiki/syntax.txt @@ -83,9 +83,9 @@ Windows shares like [[\\server\share|this]] are recognized, too. Please note tha 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/local.protected.php'': + * 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/userscript.js'': - $lang['js']['nosmblinks'] = ''; + LANG.nosmblinks = ''; ==== Image Links ==== -- cgit v1.2.3 From 64e8e116217f7559802d6cab15365d167714f191 Mon Sep 17 00:00:00 2001 From: Michael Hamann Date: Sat, 23 Feb 2013 12:35:57 +0100 Subject: Fix double encoding in rss syntax FS#2731 --- inc/parser/xhtml.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/inc/parser/xhtml.php b/inc/parser/xhtml.php index 4dd8c5e78..84a999e56 100644 --- a/inc/parser/xhtml.php +++ b/inc/parser/xhtml.php @@ -889,7 +889,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer { // title is escaped by SimplePie, we unescape here because it // is escaped again in externallink() FS#1705 $this->externallink($item->get_permalink(), - htmlspecialchars_decode($item->get_title())); + html_entity_decode($item->get_title(), ENT_QUOTES, 'UTF-8')); }else{ $this->doc .= ' '.$item->get_title(); } -- cgit v1.2.3 From a4655683f1e9b4bf77a25334cd447b4b50e1c151 Mon Sep 17 00:00:00 2001 From: Lorenzo Radaelli Date: Sun, 24 Feb 2013 10:36:18 +0100 Subject: Italian language update --- inc/lang/it/lang.php | 8 ++++++++ lib/plugins/authad/lang/it/settings.php | 5 +++++ lib/plugins/authldap/lang/it/settings.php | 5 +++++ lib/plugins/authmysql/lang/it/settings.php | 5 +++++ lib/plugins/authpgsql/lang/it/settings.php | 5 +++++ lib/plugins/config/lang/it/lang.php | 1 + 6 files changed, 29 insertions(+) create mode 100644 lib/plugins/authad/lang/it/settings.php create mode 100644 lib/plugins/authldap/lang/it/settings.php create mode 100644 lib/plugins/authmysql/lang/it/settings.php create mode 100644 lib/plugins/authpgsql/lang/it/settings.php diff --git a/inc/lang/it/lang.php b/inc/lang/it/lang.php index 307e7292f..92bf5fea8 100644 --- a/inc/lang/it/lang.php +++ b/inc/lang/it/lang.php @@ -205,6 +205,7 @@ $lang['mail_new_user'] = 'nuovo utente:'; $lang['mail_upload'] = 'file caricato:'; $lang['changes_type'] = 'Guarda cambiamenti di'; $lang['pages_changes'] = 'Pagine'; +$lang['media_changes'] = 'File multimediali'; $lang['both_changes'] = 'Sia pagine che media files'; $lang['qb_bold'] = 'Grassetto'; $lang['qb_italic'] = 'Corsivo'; @@ -263,6 +264,8 @@ $lang['subscr_m_unsubscribe'] = 'Rimuovi sottoscrizione'; $lang['subscr_m_subscribe'] = 'Sottoscrivi'; $lang['subscr_m_receive'] = 'Ricevi'; $lang['subscr_style_every'] = 'email per ogni modifica'; +$lang['subscr_style_digest'] = 'email di riassunto dei cambiamenti per ogni pagina (ogni %.2f giorni)'; +$lang['subscr_style_list'] = 'lista delle pagine cambiate dall\'ultima email (ogni %.2f giorni)'; $lang['authmodfailed'] = 'La configurazione dell\'autenticazione non è corretta. Informa l\'amministratore di questo wiki.'; $lang['authtempfail'] = 'L\'autenticazione è temporaneamente non disponibile. Se questa situazione persiste, informa l\'amministratore di questo wiki.'; $lang['authpwdexpire'] = 'La tua password scadrà in %d giorni, dovresti cambiarla quanto prima.'; @@ -290,6 +293,9 @@ $lang['i_pol1'] = 'Wiki Pubblico (lettura per tutti, scrittura e $lang['i_pol2'] = 'Wiki Chiuso (lettura, scrittura, caricamento file solamente per gli utenti registrati)'; $lang['i_retry'] = 'Riprova'; $lang['i_license'] = 'Per favore scegli la licenza sotto cui vuoi rilasciare il contenuto:'; +$lang['i_license_none'] = 'Non mostrare informazioni sulla licenza'; +$lang['i_pop_field'] = 'Per favore, aiutaci ad incrementare la conoscenza di DokuWiki:'; +$lang['i_pop_label'] = 'Mensilmente invia una statistica d\'uso anonima di DokuWiki agli sviluppatori'; $lang['recent_global'] = 'Stai attualmente vedendo le modifiche effettuate nell\'area %s. Puoi anche vedere le modifiche recenti dell\'intero wiki.'; $lang['years'] = '%d anni fa'; $lang['months'] = '%d mesi fa'; @@ -314,8 +320,10 @@ $lang['media_files'] = 'File in %s'; $lang['media_upload'] = 'Upload al %s'; $lang['media_search'] = 'Cerca in %s'; $lang['media_view'] = '%s'; +$lang['media_viewold'] = '%s a %s'; $lang['media_edit'] = 'Modifica %s'; $lang['media_history'] = 'Storia di %s'; +$lang['media_meta_edited'] = 'metadata modificati'; $lang['media_perm_read'] = 'Spiacente, non hai abbastanza privilegi per leggere i files.'; $lang['media_perm_upload'] = 'Spiacente, non hai abbastanza privilegi per caricare files.'; $lang['media_update'] = 'Carica nuova versione'; diff --git a/lib/plugins/authad/lang/it/settings.php b/lib/plugins/authad/lang/it/settings.php new file mode 100644 index 000000000..10ae72f87 --- /dev/null +++ b/lib/plugins/authad/lang/it/settings.php @@ -0,0 +1,5 @@ + Date: Sun, 24 Feb 2013 10:37:45 +0100 Subject: Simplified Chinese language update --- inc/lang/zh/lang.php | 3 +++ lib/plugins/authad/lang/zh/settings.php | 18 ++++++++++++++ lib/plugins/authldap/lang/zh/settings.php | 20 +++++++++++++++ lib/plugins/authmysql/lang/zh/settings.php | 40 ++++++++++++++++++++++++++++++ lib/plugins/authpgsql/lang/zh/settings.php | 37 +++++++++++++++++++++++++++ 5 files changed, 118 insertions(+) create mode 100644 lib/plugins/authad/lang/zh/settings.php create mode 100644 lib/plugins/authldap/lang/zh/settings.php create mode 100644 lib/plugins/authmysql/lang/zh/settings.php create mode 100644 lib/plugins/authpgsql/lang/zh/settings.php diff --git a/inc/lang/zh/lang.php b/inc/lang/zh/lang.php index e6e568cb5..f404010ba 100644 --- a/inc/lang/zh/lang.php +++ b/inc/lang/zh/lang.php @@ -298,6 +298,9 @@ $lang['i_pol1'] = '公共的维基(任何人都有读的权限 $lang['i_pol2'] = '关闭的维基(只有注册用户才有读、写、上传的权限)'; $lang['i_retry'] = '重试'; $lang['i_license'] = '请选择您希望的内容发布许可协议:'; +$lang['i_license_none'] = '不要显示任何许可协议信息'; +$lang['i_pop_field'] = '请帮助我们改进 Dokuwiki 的体验:'; +$lang['i_pop_label'] = '每个月向 Dokuwiki 开发者发送匿名的使用数据'; $lang['recent_global'] = '您当前看到的是%s 名称空间的变动。你还可以在查看整个维基的近期变动。'; $lang['years'] = '%d年前'; $lang['months'] = '%d月前'; diff --git a/lib/plugins/authad/lang/zh/settings.php b/lib/plugins/authad/lang/zh/settings.php new file mode 100644 index 000000000..9fd3c4e35 --- /dev/null +++ b/lib/plugins/authad/lang/zh/settings.php @@ -0,0 +1,18 @@ + + */ +$lang['account_suffix'] = '您的账户后缀。例如 @my.domain.org'; +$lang['base_dn'] = '您的基本分辨名。例如 DC=my,DC=domain,DC=org'; +$lang['domain_controllers'] = '逗号分隔的域名控制器列表。例如 srv1.domain.org,srv2.domain.org'; +$lang['ad_username'] = '一个活动目录的特权用户,可以查看其他所有用户的数据。可选,但对某些活动例如发送订阅邮件是必须的。'; +$lang['ad_password'] = '上述用户的密码。'; +$lang['sso'] = '是否使用经由 Kerberos 和 NTLM 的 Single-Sign-On?'; +$lang['real_primarygroup'] = ' 是否解析真实的主要组,而不是假设为“域用户” (较慢)'; +$lang['use_ssl'] = '使用 SSL 连接?如果是,不要激活下面的 TLS。'; +$lang['use_tls'] = '使用 TLS 连接?如果是 ,不要激活上面的 SSL。'; +$lang['debug'] = '有错误时显示额外的调试信息?'; +$lang['expirywarn'] = '提前多少天警告用户密码即将到期。0 则禁用。'; +$lang['additional'] = '需要从用户数据中获取的额外 AD 属性的列表,以逗号分隔。用于某些插件。'; diff --git a/lib/plugins/authldap/lang/zh/settings.php b/lib/plugins/authldap/lang/zh/settings.php new file mode 100644 index 000000000..e84511b42 --- /dev/null +++ b/lib/plugins/authldap/lang/zh/settings.php @@ -0,0 +1,20 @@ + + */ +$lang['server'] = '您的 LDAP 服务器。填写主机名 (localhost) 或者完整的 URL (ldap://server.tld:389)'; +$lang['port'] = 'LDAP 服务器端口 (如果上面没有给出完整的 URL)'; +$lang['usertree'] = '何处查找用户账户。例如 ou=People, dc=server, dc=tld'; +$lang['grouptree'] = '何处查找用户组。例如 ou=Group, dc=server, dc=tld'; +$lang['userfilter'] = '用于搜索用户账户的 LDAP 筛选器。例如 (&(uid=%{user})(objectClass=posixAccount))'; +$lang['groupfilter'] = '用于搜索组的 LDAP 筛选器。例如 (&(objectClass=posixGroup)(|(gidNumber=%{gid})(memberUID=%{user})))'; +$lang['version'] = '使用的协议版本。您或许需要设置为 3'; +$lang['starttls'] = '使用 TLS 连接?'; +$lang['referrals'] = '是否允许引用 (referrals)?'; +$lang['binddn'] = '一个可选的绑定用户的 DN (如果匿名绑定不满足要求)。例如 Eg. cn=admin, dc=my, dc=home'; +$lang['bindpw'] = '上述用户的密码'; +$lang['userscope'] = '限制用户搜索的范围'; +$lang['groupscope'] = '限制组搜索的范围'; +$lang['debug'] = '有错误时显示额外的调试信息'; diff --git a/lib/plugins/authmysql/lang/zh/settings.php b/lib/plugins/authmysql/lang/zh/settings.php new file mode 100644 index 000000000..43cfbb3c0 --- /dev/null +++ b/lib/plugins/authmysql/lang/zh/settings.php @@ -0,0 +1,40 @@ + + */ +$lang['server'] = '您的 MySQL 服务器'; +$lang['user'] = 'MySQL 用户名'; +$lang['password'] = '上述用户的密码'; +$lang['database'] = '使用的数据库'; +$lang['debug'] = '显示额外调试信息'; +$lang['forwardClearPass'] = '将用户密码以明文形式传送给下面的 SQL 语句,而不使用 passcrypt 密码加密选项'; +$lang['TablesToLock'] = '在写操作时需要锁定的数据表列表,以逗号分隔'; +$lang['checkPass'] = '检查密码的 SQL 语句'; +$lang['getUserInfo'] = '获取用户信息的 SQL 语句'; +$lang['getGroups'] = '或许用户的组成员身份的 SQL 语句'; +$lang['getUsers'] = '列出所有用户的 SQL 语句'; +$lang['FilterLogin'] = '根据登录名筛选用户的 SQL 子句'; +$lang['FilterName'] = '根据全名筛选用户的 SQL 子句'; +$lang['FilterEmail'] = '根据电子邮件地址筛选用户的 SQL 子句'; +$lang['FilterGroup'] = '根据组成员身份筛选用户的 SQL 子句'; +$lang['SortOrder'] = '对用户排序的 SQL 子句'; +$lang['addUser'] = '添加新用户的 SQL 语句'; +$lang['addGroup'] = '添加新组的 SQL 语句'; +$lang['addUserGroup'] = '将用户添加到现有组的 SQL 语句'; +$lang['delGroup'] = '删除组的 SQL 语句'; +$lang['getUserID'] = '获取用户主键的 SQL 语句'; +$lang['delUser'] = '删除用户的 SQL 语句'; +$lang['delUserRefs'] = '从所有组中删除一个用户的 SQL 语句'; +$lang['updateUser'] = '更新用户信息的 SQL 语句'; +$lang['UpdateLogin'] = '更新用户登录名的 Update 子句'; +$lang['UpdatePass'] = '更新用户密码的 Update 子句'; +$lang['UpdateEmail'] = '更新用户电子邮件地址的 Update 子句'; +$lang['UpdateName'] = '更新用户全名的 Update 子句'; +$lang['UpdateTarget'] = '更新时识别用户的 Limit 子句'; +$lang['delUserGroup'] = '从指定组删除用户的 SQL 语句'; +$lang['getGroupID'] = '获取指定组主键的 SQL 语句'; +$lang['debug_o_0'] = '无'; +$lang['debug_o_1'] = '仅在有错误时'; +$lang['debug_o_2'] = '所有 SQL 查询'; diff --git a/lib/plugins/authpgsql/lang/zh/settings.php b/lib/plugins/authpgsql/lang/zh/settings.php new file mode 100644 index 000000000..dc7223d89 --- /dev/null +++ b/lib/plugins/authpgsql/lang/zh/settings.php @@ -0,0 +1,37 @@ + + */ +$lang['server'] = '您的 PostgreSQL 服务器'; +$lang['port'] = '您的 PostgreSQL 服务器端口'; +$lang['user'] = 'PostgreSQL 用户名'; +$lang['password'] = '上述用户的密码'; +$lang['database'] = '使用的数据库'; +$lang['debug'] = '显示额外调试信息'; +$lang['forwardClearPass'] = '将用户密码以明文形式传送给下面的 SQL 语句,而不使用 passcrypt 密码加密选项'; +$lang['checkPass'] = '检查密码的 SQL 语句'; +$lang['getUserInfo'] = '获取用户信息的 SQL 语句'; +$lang['getGroups'] = '获取用户的组成员身份的 SQL 语句'; +$lang['getUsers'] = '列出所有用户的 SQL 语句'; +$lang['FilterLogin'] = '根据登录名筛选用户的 SQL 子句'; +$lang['FilterName'] = '根据全名筛选用户的 SQL 子句'; +$lang['FilterEmail'] = '根据电子邮件地址筛选用户的 SQL 子句'; +$lang['FilterGroup'] = '根据组成员身份筛选用户的 SQL 子句'; +$lang['SortOrder'] = '对用户排序的 SQL 子句'; +$lang['addUser'] = '添加新用户的 SQL 语句'; +$lang['addGroup'] = '添加新组的 SQL 语句'; +$lang['addUserGroup'] = '将用户添加到现有组的 SQL 语句'; +$lang['delGroup'] = '删除组的 SQL 语句'; +$lang['getUserID'] = '获取用户主键的 SQL 语句'; +$lang['delUser'] = '删除用户的 SQL 语句'; +$lang['delUserRefs'] = '从所有组中删除一个用户的 SQL 语句'; +$lang['updateUser'] = '更新用户信息的 SQL 语句'; +$lang['UpdateLogin'] = '更新用户登录名的 Update 子句'; +$lang['UpdatePass'] = '更新用户密码的 Update 子句'; +$lang['UpdateEmail'] = '更新用户电子邮件地址的 Update 子句'; +$lang['UpdateName'] = '更新用户全名的 Update 子句'; +$lang['UpdateTarget'] = '更新时识别用户的 Limit 子句'; +$lang['delUserGroup'] = '从指定组删除用户的 SQL 语句'; +$lang['getGroupID'] = '获取指定组主键的 SQL 语句'; -- cgit v1.2.3 From bdac741579f8c6f00248d5d3ec635d4c2e08fb1e Mon Sep 17 00:00:00 2001 From: Andreas Gohr Date: Sun, 24 Feb 2013 10:39:52 +0100 Subject: fixed typos --- lib/plugins/authldap/lang/en/settings.php | 4 ++-- lib/plugins/authpgsql/lang/en/settings.php | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/plugins/authldap/lang/en/settings.php b/lib/plugins/authldap/lang/en/settings.php index 0bb397be5..ddedf8ae3 100644 --- a/lib/plugins/authldap/lang/en/settings.php +++ b/lib/plugins/authldap/lang/en/settings.php @@ -1,14 +1,14 @@ localhost) or full qualified URL (ldap://server.tld:389)'; $lang['port'] = 'LDAP server port if no full URL was given above'; -$lang['usertree'] = 'Where to finde the user accounts. Eg. ou=People, dc=server, dc=tld'; +$lang['usertree'] = 'Where to find the user accounts. Eg. ou=People, dc=server, dc=tld'; $lang['grouptree'] = 'Where to find the user groups. Eg. ou=Group, dc=server, dc=tld'; $lang['userfilter'] = 'LDAP filter to search for user accounts. Eg. (&(uid=%{user})(objectClass=posixAccount))'; $lang['groupfilter'] = 'LDAP filter to search for groups. Eg. (&(objectClass=posixGroup)(|(gidNumber=%{gid})(memberUID=%{user})))'; $lang['version'] = 'The protocol version to use. You may need to set this to 3'; $lang['starttls'] = 'Use TLS connections?'; $lang['referrals'] = 'Shall referrals be followed?'; -$lang['binddn'] = 'DN of an ptional bind user if anonymous bind is not sufficient. Eg. cn=admin, dc=my, dc=home'; +$lang['binddn'] = 'DN of an optional bind user if anonymous bind is not sufficient. Eg. cn=admin, dc=my, dc=home'; $lang['bindpw'] = 'Password of above user'; $lang['userscope'] = 'Limit search scope for user search'; $lang['groupscope'] = 'Limit search scope for group search'; diff --git a/lib/plugins/authpgsql/lang/en/settings.php b/lib/plugins/authpgsql/lang/en/settings.php index 74a1c1cc9..8c048fa0f 100644 --- a/lib/plugins/authpgsql/lang/en/settings.php +++ b/lib/plugins/authpgsql/lang/en/settings.php @@ -20,7 +20,7 @@ $lang['addUser'] = 'SQL statement to add a new user'; $lang['addGroup'] = 'SQL statement to add a new group'; $lang['addUserGroup'] = 'SQL statment to add a user to an existing group'; $lang['delGroup'] = 'SQL statement to remove a group'; -$lang['getUserID'] = 'SQL statement to get the primary ey of a user'; +$lang['getUserID'] = 'SQL statement to get the primary key of a user'; $lang['delUser'] = 'SQL statement to delete a user'; $lang['delUserRefs'] = 'SQL statement to remove a user from all groups'; $lang['updateUser'] = 'SQL statement to update a user profile'; -- cgit v1.2.3 From bc1e9ee1b1fffcb554afced8504270032c97341f Mon Sep 17 00:00:00 2001 From: Anika Henke Date: Mon, 4 Mar 2013 10:04:57 +0000 Subject: added loggedIn class to main tpl container --- lib/tpl/dokuwiki/detail.php | 2 +- lib/tpl/dokuwiki/main.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/tpl/dokuwiki/detail.php b/lib/tpl/dokuwiki/detail.php index a8c5fef8a..f20301a89 100644 --- a/lib/tpl/dokuwiki/detail.php +++ b/lib/tpl/dokuwiki/detail.php @@ -29,7 +29,7 @@ if (!defined('DOKU_INC')) die();
+ class="dokuwiki site mode_ "> diff --git a/lib/tpl/dokuwiki/main.php b/lib/tpl/dokuwiki/main.php index 963750a1c..cd5a66ad4 100644 --- a/lib/tpl/dokuwiki/main.php +++ b/lib/tpl/dokuwiki/main.php @@ -29,7 +29,7 @@ $showSidebar = $hasSidebar && ($ACT=='show');
+ ?> "> -- cgit v1.2.3 From ba9015b07d229ba195e7a9a3f23c3b038374c88c Mon Sep 17 00:00:00 2001 From: Klap-in Date: Tue, 21 May 2013 21:32:54 +0200 Subject: tests for fetch.php of external files --- .../lib/exe/fetch_statuscodes_external.test.php | 116 +++++++++++++++++++++ 1 file changed, 116 insertions(+) create mode 100644 _test/tests/lib/exe/fetch_statuscodes_external.test.php diff --git a/_test/tests/lib/exe/fetch_statuscodes_external.test.php b/_test/tests/lib/exe/fetch_statuscodes_external.test.php new file mode 100644 index 000000000..1a2164828 --- /dev/null +++ b/_test/tests/lib/exe/fetch_statuscodes_external.test.php @@ -0,0 +1,116 @@ +markTestSkipped('headers not returned, perhaps your sapi does not return headers, try xdebug'); + } else { + header_remove('X-Test'); + } + + parent::setUp(); + + global $conf; + $conf['fetchsize'] = 500*1024; //500kb + $conf['xsendfile'] = 0; + + global $MIME, $EXT, $CACHE, $INPUT; // variables fetch creates in global scope -- should this be in fetch? + } + + function getUri($hash=null) { + $w = $this->width ? 'w='.$this->width.'&' : ''; + $h = $this->height ? 'h='.$this->height.'&' : ''; + if($hash === null) { + $hash = 'hash='.substr(md5(auth_cookiesalt().$this->media), 0, 6).'&'; + } + + return '/lib/exe/fetch.php?'.$hash.$w.$h.'{%token%}media='.rawurlencode($this->media); + } + + function fetchResponse($token, $hash=null){ + $request = new TestRequest(); + return $request->get(array(),str_replace('{%token%}',$token,$this->getUri($hash))); + } + + /** + * modified image request with invalid hash + * expect: 412 status code + */ + function test_invalid_hash() { + $invalid_hash = 'hash='.substr(md5(auth_cookiesalt().'junk'), 0, 6).'&'; + $token = 'tok='.media_get_token($this->media, $this->width, $this->height).'&'; + + $this->assertEquals(412,$this->fetchResponse($token, $invalid_hash)->getStatusCode()); + + } + + /** + * modified image request with valid token + * expect: header with mime-type + * expect: content + * expect: no error response + */ + function test_valid_token(){ + $valid_token = 'tok='.media_get_token($this->media, $this->width, $this->height).'&'; + + $response = $this->fetchResponse($valid_token); + $this->assertTrue((bool)$response->getHeader('Content-Type')); + $this->assertTrue((bool)($response->getContent())); + + $status_code = $response->getStatusCode(); + $this->assertTrue(is_null($status_code) || (200 == $status_code)); + } + + /** + * modified image request with invalid token + * expect: 412 status code + */ + function test_invalid_token(){ + $invalid_token = 'tok='.media_get_token('junk',200,100).'&'; + $this->assertEquals(412,$this->fetchResponse($invalid_token)->getStatusCode()); + } + + /** + * modified image request with no token + * expect: 412 status code + */ + function test_missing_token(){ + $no_token = ''; + $this->assertEquals(412,$this->fetchResponse($no_token)->getStatusCode()); + } + + /** + * native image request which doesn't require a token + * try: with a token & without a token + * expect: (for both) header with mime-type, content matching source image filesize & no error response + */ + function test_no_token_required(){ + $this->width = $this->height = 0; // no width & height, means image request at native dimensions + $any_token = 'tok='.media_get_token('junk',200,100).'&'; + $no_token = ''; + $file = media_get_from_URL($this->media,'png', -1); + $bytes = filesize($file); + + foreach(array($any_token, $no_token) as $token) { + $response = $this->fetchResponse($token); + $this->assertTrue((bool)$response->getHeader('Content-Type')); + $this->assertEquals(strlen($response->getContent()), $bytes); + + $status_code = $response->getStatusCode(); + $this->assertTrue(is_null($status_code) || (200 == $status_code)); + } + } + +} +//Setup VIM: ex: et ts=4 : -- cgit v1.2.3 From d572baf83c5a6d61a7f97aa4d115eba76c5f106c Mon Sep 17 00:00:00 2001 From: Klap-in Date: Tue, 21 May 2013 21:40:37 +0200 Subject: Add check for token when resizing and caching external images --- inc/fetch.functions.php | 4 ++++ lib/exe/fetch.php | 1 + 2 files changed, 5 insertions(+) diff --git a/inc/fetch.functions.php b/inc/fetch.functions.php index 5801e96fa..59a76a798 100644 --- a/inc/fetch.functions.php +++ b/inc/fetch.functions.php @@ -108,6 +108,10 @@ function checkFileStatus(&$media, &$file, $rev = '', $width=0, $height=0) { //download failed - redirect to original URL return array(302, $media); } + // check token for resized and cached images + if (($width || $height) && media_get_token($media, $width, $height) !== $INPUT->str('tok')) { + return array(412, 'Precondition Failed'); + } } else { $media = cleanID($media); if(empty($media)) { diff --git a/lib/exe/fetch.php b/lib/exe/fetch.php index 7a2250373..5967494bf 100644 --- a/lib/exe/fetch.php +++ b/lib/exe/fetch.php @@ -60,6 +60,7 @@ if (defined('SIMPLE_TEST')) { if($evt->advise_before()) { // redirects if($data['status'] > 300 && $data['status'] <= 304) { + if (defined('SIMPLE_TEST')) return; //TestResponse doesn't recognize redirects send_redirect($data['statusmessage']); } // send any non 200 status -- cgit v1.2.3 From a38a6f25d7e46f47a8f358bb16c766f5b96dae45 Mon Sep 17 00:00:00 2001 From: Klap-in Date: Tue, 21 May 2013 21:41:40 +0200 Subject: fix some minor typos in fetch_imagetoken.test.php --- _test/tests/lib/exe/fetch_imagetoken.test.php | 44 +++++++++++++-------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/_test/tests/lib/exe/fetch_imagetoken.test.php b/_test/tests/lib/exe/fetch_imagetoken.test.php index 9e5b6e4a2..99e642557 100644 --- a/_test/tests/lib/exe/fetch_imagetoken.test.php +++ b/_test/tests/lib/exe/fetch_imagetoken.test.php @@ -23,10 +23,10 @@ class fetch_imagetoken_test extends DokuWikiTest { parent::setUp(); global $conf; - $conf['sendfile'] = 0; + $conf['xsendfile'] = 0; global $MIME, $EXT, $CACHE, $INPUT; // variables fetch creates in global scope -- should this be in fetch? - } + } function getUri() { $w = $this->width ? 'w='.$this->width.'&' : ''; @@ -39,14 +39,14 @@ class fetch_imagetoken_test extends DokuWikiTest { $request = new TestRequest(); return $request->get(array(),str_replace('{%token%}',$token,$this->getUri())); } - - /** + + /** * modified image request with valid token * expect: header with mime-type * expect: content * expect: no error response - */ - function test_valid_token(){ + */ + function test_valid_token(){ $valid_token = 'tok='.media_get_token($this->media, $this->width, $this->height).'&'; $response = $this->fetchResponse($valid_token); $this->assertTrue((bool)$response->getHeader('Content-Type')); @@ -54,24 +54,24 @@ class fetch_imagetoken_test extends DokuWikiTest { $status_code = $response->getStatusCode(); $this->assertTrue(is_null($status_code) || (200 == $status_code)); - } - - /** + } + + /** * modified image request with invalid token - * expect: 412 status code - */ - function test_invalid_token(){ - $invalid_token = 'tok='.media_get_token('junk',200,100).'&'; - $this->assertEquals(412,$this->fetchResponse($invalid_token)->getStatusCode()); - } - - /** - * modified image request with no token * expect: 412 status code - */ - function test_missing_token(){ - $no_token = ''; - $this->assertEquals(412,$this->fetchResponse($notoken)->getStatusCode()); + */ + function test_invalid_token(){ + $invalid_token = 'tok='.media_get_token('junk',200,100).'&'; + $this->assertEquals(412,$this->fetchResponse($invalid_token)->getStatusCode()); + } + + /** + * modified image request with no token + * expect: 412 status code + */ + function test_missing_token(){ + $no_token = ''; + $this->assertEquals(412,$this->fetchResponse($no_token)->getStatusCode()); } /** -- cgit v1.2.3 From fa3ed26bfbafa4d05ec77a799259d4a46baadd9a Mon Sep 17 00:00:00 2001 From: Klap-in Date: Sun, 9 Jun 2013 22:16:08 +0200 Subject: update hashes in tests --- _test/tests/lib/exe/fetch_statuscodes_external.test.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/_test/tests/lib/exe/fetch_statuscodes_external.test.php b/_test/tests/lib/exe/fetch_statuscodes_external.test.php index 1a2164828..bd7b2f93b 100644 --- a/_test/tests/lib/exe/fetch_statuscodes_external.test.php +++ b/_test/tests/lib/exe/fetch_statuscodes_external.test.php @@ -32,9 +32,8 @@ class fetch_statuscodes_external_test extends DokuWikiTest { $w = $this->width ? 'w='.$this->width.'&' : ''; $h = $this->height ? 'h='.$this->height.'&' : ''; if($hash === null) { - $hash = 'hash='.substr(md5(auth_cookiesalt().$this->media), 0, 6).'&'; + $hash = 'hash='.substr(PassHash::hmac('md5', $this->media, auth_cookiesalt()), 0, 6).'&'; } - return '/lib/exe/fetch.php?'.$hash.$w.$h.'{%token%}media='.rawurlencode($this->media); } @@ -48,7 +47,7 @@ class fetch_statuscodes_external_test extends DokuWikiTest { * expect: 412 status code */ function test_invalid_hash() { - $invalid_hash = 'hash='.substr(md5(auth_cookiesalt().'junk'), 0, 6).'&'; + $invalid_hash = 'hash='.substr(PassHash::hmac('md5', 'junk', auth_cookiesalt()), 0, 6).'&'; $token = 'tok='.media_get_token($this->media, $this->width, $this->height).'&'; $this->assertEquals(412,$this->fetchResponse($token, $invalid_hash)->getStatusCode()); -- cgit v1.2.3 From 88833bac87e7fb295c0479a8260d1d63051bca8d Mon Sep 17 00:00:00 2001 From: flammy Date: Mon, 24 Jun 2013 15:05:59 +0300 Subject: Fixes validation problems with base64 encoded images in CSS. --- lib/exe/css.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/exe/css.php b/lib/exe/css.php index 1e662c64a..768c8eda4 100644 --- a/lib/exe/css.php +++ b/lib/exe/css.php @@ -314,7 +314,7 @@ function css_datauri($match){ $data = base64_encode(file_get_contents($local)); } if($data){ - $url = 'data:image/'.$ext.';base64,'.$data; + $url = '\'data:image/'.$ext.';base64,'.$data.'\''; }else{ $url = $base.$url; } -- cgit v1.2.3 From f91bd3d821fdaba4fb431006fbacb2d99744ecf0 Mon Sep 17 00:00:00 2001 From: flammy Date: Mon, 24 Jun 2013 15:38:28 +0300 Subject: Fixes validation problems with base64 encoded images in CSS. --- lib/tpl/dokuwiki/css/basic.css | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/tpl/dokuwiki/css/basic.css b/lib/tpl/dokuwiki/css/basic.css index a0a60d295..eef7a03e2 100644 --- a/lib/tpl/dokuwiki/css/basic.css +++ b/lib/tpl/dokuwiki/css/basic.css @@ -401,7 +401,7 @@ button, .qq-upload-button { color: #333; background-color: #eee; - background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIHZpZXdCb3g9IjAgMCAxIDEiIHByZXNlcnZlQXNwZWN0UmF0aW89Im5vbmUiPgo8bGluZWFyR3JhZGllbnQgaWQ9Imc4MjQiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIiB4MT0iMCUiIHkxPSIwJSIgeDI9IjAlIiB5Mj0iMTAwJSI+CjxzdG9wIHN0b3AtY29sb3I9IiNGRkZGRkYiIG9mZnNldD0iMCIvPjxzdG9wIHN0b3AtY29sb3I9IiNGNEY0RjQiIG9mZnNldD0iMC4zIi8+PHN0b3Agc3RvcC1jb2xvcj0iI0VFRUVFRSIgb2Zmc2V0PSIwLjk5Ii8+PHN0b3Agc3RvcC1jb2xvcj0iI0NDQ0NDQyIgb2Zmc2V0PSIuOTkiLz4KPC9saW5lYXJHcmFkaWVudD4KPHJlY3QgeD0iMCIgeT0iMCIgd2lkdGg9IjEiIGhlaWdodD0iMSIgZmlsbD0idXJsKCNnODI0KSIgLz4KPC9zdmc+); + background-image: url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIHZpZXdCb3g9IjAgMCAxIDEiIHByZXNlcnZlQXNwZWN0UmF0aW89Im5vbmUiPgo8bGluZWFyR3JhZGllbnQgaWQ9Imc4MjQiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIiB4MT0iMCUiIHkxPSIwJSIgeDI9IjAlIiB5Mj0iMTAwJSI+CjxzdG9wIHN0b3AtY29sb3I9IiNGRkZGRkYiIG9mZnNldD0iMCIvPjxzdG9wIHN0b3AtY29sb3I9IiNGNEY0RjQiIG9mZnNldD0iMC4zIi8+PHN0b3Agc3RvcC1jb2xvcj0iI0VFRUVFRSIgb2Zmc2V0PSIwLjk5Ii8+PHN0b3Agc3RvcC1jb2xvcj0iI0NDQ0NDQyIgb2Zmc2V0PSIuOTkiLz4KPC9saW5lYXJHcmFkaWVudD4KPHJlY3QgeD0iMCIgeT0iMCIgd2lkdGg9IjEiIGhlaWdodD0iMSIgZmlsbD0idXJsKCNnODI0KSIgLz4KPC9zdmc+'); background: -moz-linear-gradient( top, #ffffff 0%, #f4f4f4 30%, #eeeeee 99%, #cccccc 99%); background: -webkit-linear-gradient(top, #ffffff 0%, #f4f4f4 30%, #eeeeee 99%, #cccccc 99%); background: -o-linear-gradient( top, #ffffff 0%, #f4f4f4 30%, #eeeeee 99%, #cccccc 99%); @@ -439,7 +439,7 @@ button:focus, .qq-upload-button:hover { border-color: #999; background-color: #ddd; - background-image:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIHZpZXdCb3g9IjAgMCAxIDEiIHByZXNlcnZlQXNwZWN0UmF0aW89Im5vbmUiPgo8bGluZWFyR3JhZGllbnQgaWQ9Imc2NzAiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIiB4MT0iMCUiIHkxPSIwJSIgeDI9IjAlIiB5Mj0iMTAwJSI+CjxzdG9wIHN0b3AtY29sb3I9IiNGRkZGRkYiIG9mZnNldD0iMCIvPjxzdG9wIHN0b3AtY29sb3I9IiNGNEY0RjQiIG9mZnNldD0iMC4zIi8+PHN0b3Agc3RvcC1jb2xvcj0iI0RERERERCIgb2Zmc2V0PSIwLjk5Ii8+PHN0b3Agc3RvcC1jb2xvcj0iI0JCQkJCQiIgb2Zmc2V0PSIuOTkiLz4KPC9saW5lYXJHcmFkaWVudD4KPHJlY3QgeD0iMCIgeT0iMCIgd2lkdGg9IjEiIGhlaWdodD0iMSIgZmlsbD0idXJsKCNnNjcwKSIgLz4KPC9zdmc+); + background-image:url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIHZpZXdCb3g9IjAgMCAxIDEiIHByZXNlcnZlQXNwZWN0UmF0aW89Im5vbmUiPgo8bGluZWFyR3JhZGllbnQgaWQ9Imc2NzAiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIiB4MT0iMCUiIHkxPSIwJSIgeDI9IjAlIiB5Mj0iMTAwJSI+CjxzdG9wIHN0b3AtY29sb3I9IiNGRkZGRkYiIG9mZnNldD0iMCIvPjxzdG9wIHN0b3AtY29sb3I9IiNGNEY0RjQiIG9mZnNldD0iMC4zIi8+PHN0b3Agc3RvcC1jb2xvcj0iI0RERERERCIgb2Zmc2V0PSIwLjk5Ii8+PHN0b3Agc3RvcC1jb2xvcj0iI0JCQkJCQiIgb2Zmc2V0PSIuOTkiLz4KPC9saW5lYXJHcmFkaWVudD4KPHJlY3QgeD0iMCIgeT0iMCIgd2lkdGg9IjEiIGhlaWdodD0iMSIgZmlsbD0idXJsKCNnNjcwKSIgLz4KPC9zdmc+'); background: -moz-linear-gradient( top, #ffffff 0%, #f4f4f4 30%, #dddddd 99%, #bbbbbb 99%); background: -webkit-linear-gradient(top, #ffffff 0%, #f4f4f4 30%, #dddddd 99%, #bbbbbb 99%); background: -o-linear-gradient( top, #ffffff 0%, #f4f4f4 30%, #dddddd 99%, #bbbbbb 99%); -- cgit v1.2.3 From 935ecb0ef751ac1d658932316e06410e70c483e0 Mon Sep 17 00:00:00 2001 From: haobug Date: Fri, 28 Jun 2013 05:18:19 +0800 Subject: Improve Linkwizard, make it can be used more than once. As reported in https://forum.dokuwiki.org/thread/9988 the previous implementation can not handle the situation of use the linkwiz more than once. Now you can use in you toolbar plugin 'type' => 'linkwiz' to make use of the handy Linkwizard for choosing the wiki pages. --- lib/scripts/linkwiz.js | 24 ++++++++++++++++++------ lib/scripts/toolbar.js | 5 +++-- 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/lib/scripts/linkwiz.js b/lib/scripts/linkwiz.js index c55650d68..875d4a995 100644 --- a/lib/scripts/linkwiz.js +++ b/lib/scripts/linkwiz.js @@ -22,6 +22,8 @@ var dw_linkwiz = { var pos = $editor.position(); // create HTML Structure + if(dw_linkwiz.$wiz) + return; dw_linkwiz.$wiz = jQuery(document.createElement('div')) .dialog({ autoOpen: false, @@ -235,15 +237,25 @@ var dw_linkwiz = { link = ':' + link; } - var so = link.length+3; - link = '[['+link+'|'; - if(stxt) { - link += stxt; + var so = link.length; + var eo = 0; + if(dw_linkwiz.val){ + if(dw_linkwiz.val.open) { + so += dw_linkwiz.val.open.length; + link = dw_linkwiz.val.open+link; + } + if(stxt) { + link += '|'+stxt; + so += 1; + } + if(dw_linkwiz.val.close) { + link += dw_linkwiz.val.close; + eo = dw_linkwiz.val.close.length; + } } - link += ']]'; - pasteText(sel,link,{startofs: so, endofs: 2}); + pasteText(sel,link,{startofs: so, endofs: eo}); dw_linkwiz.hide(); // reset the entry to the parent namespace diff --git a/lib/scripts/toolbar.js b/lib/scripts/toolbar.js index 6d75215e0..e33fa8677 100644 --- a/lib/scripts/toolbar.js +++ b/lib/scripts/toolbar.js @@ -211,9 +211,10 @@ function addBtnActionPicker($btn, props, edid) { * @return boolean If button should be appended * @author Andreas Gohr */ -function addBtnActionLinkwiz(btn, props, edid) { +function addBtnActionLinkwiz($btn, props, edid) { dw_linkwiz.init(jQuery('#'+edid)); - jQuery(btn).click(function(){ + jQuery($btn).click(function(){ + dw_linkwiz.val = props; dw_linkwiz.toggle(); return false; }); -- cgit v1.2.3 From 0a8f03d88cd0597d1317cf5164383dea2ae29ca4 Mon Sep 17 00:00:00 2001 From: Andreas Gohr Date: Fri, 12 Jul 2013 19:53:46 +0200 Subject: add TEMPLATE_DOKUWIKI_PAGETOOLFLOAT_DISPLAY event to template This adds a custom event to the 'dokuwiki' template that allows plugin authors to easily integrate custom pagetool buttons into the template. --- lib/tpl/dokuwiki/detail.php | 22 +++++++++++++++++----- lib/tpl/dokuwiki/main.php | 23 +++++++++++++++++------ 2 files changed, 34 insertions(+), 11 deletions(-) diff --git a/lib/tpl/dokuwiki/detail.php b/lib/tpl/dokuwiki/detail.php index d2ed530a3..1768b665e 100644 --- a/lib/tpl/dokuwiki/detail.php +++ b/lib/tpl/dokuwiki/detail.php @@ -109,16 +109,28 @@ header('X-UA-Compatible: IE=edge,chrome=1');

    - = AUTH_UPLOAD) && function_exists('media_managerURL')) { $mmURL = media_managerURL(array('ns' => $imgNS, 'image' => $IMG)); - echo '
  • '.$lang['img_manager'].'
  • '; + $data['mediaManager'] = '
  • '.$lang['img_manager'].'
  • '; } - ?> - '.$lang['img_backto'].' '.$ID.''; + + // Back to [ID]; @todo: transfer logic to backend + $data['img_backto'] = '
  • '.$lang['img_backto'].' '.$ID.'
  • '; + + // the page tools can be ammended through a custom plugin hook + $evt = new Doku_Event('TEMPLATE_DOKUWIKI_PAGETOOLFLOAT_DISPLAY', $data); + if($evt->advise_before()){ + foreach($evt->data as $k => $html) echo $html; + } + $evt->advise_after(); + unset($data); + unset($evt); ?>
diff --git a/lib/tpl/dokuwiki/main.php b/lib/tpl/dokuwiki/main.php index 43a0c0da7..30cd4dda9 100644 --- a/lib/tpl/dokuwiki/main.php +++ b/lib/tpl/dokuwiki/main.php @@ -75,12 +75,23 @@ $showSidebar = $hasSidebar && ($ACT=='show');
    ', ''); - tpl_action('revert', 1, 'li', 0, '', ''); - tpl_action('revisions', 1, 'li', 0, '', ''); - tpl_action('backlink', 1, 'li', 0, '', ''); - tpl_action('subscribe', 1, 'li', 0, '', ''); - tpl_action('top', 1, 'li', 0, '', ''); + $data = array( + 'edit' => tpl_action('edit', 1, 'li', 1, '', ''), + 'revert' => tpl_action('revert', 1, 'li', 1, '', ''), + 'revisions' => tpl_action('revisions', 1, 'li', 1, '', ''), + 'backlink' => tpl_action('backlink', 1, 'li', 1, '', ''), + 'subscribe' => tpl_action('subscribe', 1, 'li', 1, '', ''), + 'top' => tpl_action('top', 1, 'li', 1, '', '') + ); + + // the page tools can be ammended through a custom plugin hook + $evt = new Doku_Event('TEMPLATE_DOKUWIKI_PAGETOOLFLOAT_DISPLAY', $data); + if($evt->advise_before()){ + foreach($evt->data as $k => $html) echo $html; + } + $evt->advise_after(); + unset($data); + unset($evt); ?>
-- cgit v1.2.3 From 3fc4f82997eb93a407074db4473cade1a76b6971 Mon Sep 17 00:00:00 2001 From: Klap-in Date: Sat, 20 Jul 2013 01:28:07 +0200 Subject: Added tests for getRevisions and getRevisionInfo from page changelog --- _test/data/meta/mailinglist.changes | 24 +++ _test/data/pages/mailinglist.txt | 11 ++ .../tests/inc/changelog_getRevisionInfo.class.php | 120 +++++++++++++ _test/tests/inc/changelog_getRevisions.class.php | 200 +++++++++++++++++++++ 4 files changed, 355 insertions(+) create mode 100644 _test/data/meta/mailinglist.changes create mode 100644 _test/data/pages/mailinglist.txt create mode 100644 _test/tests/inc/changelog_getRevisionInfo.class.php create mode 100644 _test/tests/inc/changelog_getRevisions.class.php diff --git a/_test/data/meta/mailinglist.changes b/_test/data/meta/mailinglist.changes new file mode 100644 index 000000000..348f8258f --- /dev/null +++ b/_test/data/meta/mailinglist.changes @@ -0,0 +1,24 @@ +1360110636 127.0.0.1 C mailinglist pubcie aangemaakt +1361901536 127.0.0.1 E mailinglist pubcie +1362524799 127.0.0.1 E mailinglist pubcie +1362525145 127.0.0.1 E mailinglist pubcie +1362525359 127.0.0.1 E mailinglist pubcie [Data entry] +1362525899 127.0.0.1 E mailinglist pubcie [Data entry] +1362525926 127.0.0.1 E mailinglist pubcie +1362526039 127.0.0.1 E mailinglist pubcie [Data entry] +1362526119 127.0.0.1 E mailinglist pubcie +1362526167 127.0.0.1 E mailinglist pubcie [Data entry] +1362526767 127.0.0.1 E mailinglist pubcie [Data entry] +1362526861 127.0.0.1 E mailinglist pubcie [Data entry] +1362527046 127.0.0.1 E mailinglist pubcie [Data entry] +1362527164 127.0.0.1 E mailinglist pubcie [Data entry] +1363436892 127.0.0.1 E mailinglist pubcie +1368575634 127.0.0.1 E mailinglist pubcie +1368609772 127.0.0.1 E mailinglist pubcie +1368612506 127.0.0.1 E mailinglist pubcie [Data entry] +1368612599 127.0.0.1 E mailinglist pubcie [Data entry] +1368622152 127.0.0.1 E mailinglist pubcie [Data entry] +1368622195 127.0.0.1 E mailinglist pubcie +1368622240 127.0.0.1 E mailinglist pubcie [Data entry] +1371579614 127.0.0.1 E mailinglist pubcie +1374261194 127.0.0.1 E mailinglist pubcie diff --git a/_test/data/pages/mailinglist.txt b/_test/data/pages/mailinglist.txt new file mode 100644 index 000000000..3fbe91b67 --- /dev/null +++ b/_test/data/pages/mailinglist.txt @@ -0,0 +1,11 @@ +====== Mailing Lists ====== + +[[DokuWiki]]'s development is coordinated through multiple Mailinglists hosted by [[http://www.freelists.org|freelists.org]]. + +===== Using the lists ===== + +First you should subscribe to one or several of the mailing lists presented below. After subscribing you can send emails to the list(s) by using the mailing list address stated in its description. If you rather want to use the mailing list through a news group interface, please read the section [[#News group interface]]. + +If you are new to mailing lists in general, please read [[rfc>1855|RFC 1855 - Netiquette Guidelines]], especially the sections 3.1.1 and 3.1.2. Before you ask any questions you should also have a look at [[http://www.catb.org/~esr/faqs/smart-questions.html|How To Ask Questions The Smart Way]]. + +:!: Please note that these documents are linked here solely for the purpose of information. Their respective authors have nothing do to with [[DokuWiki]] and in **no case** should you send email to them, asking for help related to [[DokuWiki]]! diff --git a/_test/tests/inc/changelog_getRevisionInfo.class.php b/_test/tests/inc/changelog_getRevisionInfo.class.php new file mode 100644 index 000000000..9637d21c8 --- /dev/null +++ b/_test/tests/inc/changelog_getRevisionInfo.class.php @@ -0,0 +1,120 @@ +assertEquals($revsexpected, $revs); + } + + /** + * request existing rev + */ + function test_requestrev() { + $rev = 1362525899; + $infoexpected = parseChangelogLine($this->logline); + + $info = getRevisionInfo($this->pageid, $rev, $chunk_size = 8192, $media = false); + $this->assertEquals($infoexpected, $info); + //returns cached value + $info = getRevisionInfo($this->pageid, $rev, $chunk_size = 8192, $media = false); + $this->assertEquals($infoexpected, $info); + } + + /** + * request existing rev with chucked reading + */ + function test_requestrev_chuncked() { + $rev = 1362525899; + $infoexpected = parseChangelogLine($this->logline); + + $info = getRevisionInfo($this->pageid, $rev, $chunk_size = 512, $media = false); + $this->assertEquals($infoexpected, $info); + } + + /** + * request current version + */ + function test_requestrecentestlogline() { + $rev = 1374261194; + $infoexpected = parseChangelogLine($this->firstlogline); + + $info = getRevisionInfo($this->pageid, $rev, $chunk_size = 8192, $media = false); + $this->assertEquals($infoexpected, $info); + //returns cached value + $info = getRevisionInfo($this->pageid, $rev, $chunk_size = 8192, $media = false); + $this->assertEquals($infoexpected, $info); + } + + /** + * request current version, with chuncked reading + */ + function test_requestrecentestlogline_chuncked() { + $rev = 1374261194; + $infoexpected = parseChangelogLine($this->firstlogline); + + $info = getRevisionInfo($this->pageid, $rev, $chunk_size = 512, $media = false); + $this->assertEquals($infoexpected, $info); + } + + /** + * request negative revision + */ + function test_negativerev() { + $rev = -10; + + $info = getRevisionInfo($this->pageid, $rev, $chunk_size = 8192, $media = false); + $this->assertEquals(false, $info); + } + + /** + * request non existing revision somewhere between existing revisions + */ + function test_notexistingrev() { + $rev = 1362525890; + + $info = getRevisionInfo($this->pageid, $rev, $chunk_size = 8192, $media = false); + $this->assertEquals(false, $info); + } + + /** + * sometimes chuncksize is set to true + */ + function test_chuncksizetrue() { + $rev = 1362525899; + $infoexpected = parseChangelogLine($this->logline); + + $info = getRevisionInfo($this->pageid, $rev, true); + $this->assertEquals($infoexpected, $info); + } +} \ No newline at end of file diff --git a/_test/tests/inc/changelog_getRevisions.class.php b/_test/tests/inc/changelog_getRevisions.class.php new file mode 100644 index 000000000..a9be26dae --- /dev/null +++ b/_test/tests/inc/changelog_getRevisions.class.php @@ -0,0 +1,200 @@ +assertEquals($revsexpected, $revs); + } + + /** + * request first recentest revision + * (so skips first line which belongs to the current existing page) + */ + function test_requestlastrev() { + $first = 0; + $num = 1; + $revsexpected = array($this->revsexpected[1]); + + $revs = getRevisions($this->pageid, $first, $num, $chunk_size = 8192, $media = false); + $this->assertEquals($revsexpected, $revs); + + $revs = getRevisions($this->pageid, $first, $num, $chunk_size = 512, $media = false); + $this->assertEquals($revsexpected, $revs); + } + + /** + * request first recentest revision + * (so skips first line which belongs to the current existing page) + */ + function test_requestonebutlastrev() { + $first = 1; + $num = 1; + $revsexpected = array($this->revsexpected[2]); + + $revs = getRevisions($this->pageid, $first, $num, $chunk_size = 8192, $media = false); + $this->assertEquals($revsexpected, $revs); + + $revs = getRevisions($this->pageid, $first, $num, $chunk_size = 512, $media = false); + $this->assertEquals($revsexpected, $revs); + } + + /** + * request first recentest revision + * (so skips first line of current existing page) + */ + function test_requestrevswithoffset() { + $first = 10; + $num = 5; + $revsexpected = array_slice($this->revsexpected, $first + 1, $num); + + $revs = getRevisions($this->pageid, $first, $num, $chunk_size = 8192, $media = false); + $this->assertEquals($revsexpected, $revs); + + $revs = getRevisions($this->pageid, $first, $num, $chunk_size = 512, $media = false); + $this->assertEquals($revsexpected, $revs); + } + + /** + * first = -1 requests recentest logline, without skipping + */ + function test_requestrecentestlogline() { + $first = -1; + $num = 1; + $revsexpected = array($this->revsexpected[0]); + + $revs = getRevisions($this->pageid, $first, $num, $chunk_size = 8192, $media = false); + $this->assertEquals($revsexpected, $revs); + + $revs = getRevisions($this->pageid, $first, $num, $chunk_size = 512, $media = false); + $this->assertEquals($revsexpected, $revs); + } + + /** + * chunck size = 0 skips chuncked loading + */ + function test_wholefile() { + $first = 0; + $num = 1000; + $revsexpected = array_slice($this->revsexpected, 1); + + $revs = getRevisions($this->pageid, $first, $num, $chunk_size = 0, $media = false); + $this->assertEquals($revsexpected, $revs); + } + + /** + * Negative range returns no result + */ + function test_negativenum() { + $first = 0; + $num = -10; + $revsexpected = array(); + + $revs = getRevisions($this->pageid, $first, $num, $chunk_size = 8192, $media = false); + $this->assertEquals($revsexpected, $revs); + + $revs = getRevisions($this->pageid, $first, $num, $chunk_size = 512, $media = false); + $this->assertEquals($revsexpected, $revs); + } + + /** + * Negative range returns no result + */ + function test_negativennumoffset() { + $first = 2; + $num = -10; + $revsexpected = array(); + + $revs = getRevisions($this->pageid, $first, $num, $chunk_size = 8192, $media = false); + $this->assertEquals($revsexpected, $revs); + + $revs = getRevisions($this->pageid, $first, $num, $chunk_size = 512, $media = false); + $this->assertEquals($revsexpected, $revs); + } + + /** + * zero range returns no result + */ + function test_zeronum() { + $first = 5; + $num = 0; + $revsexpected = array(); + + $revs = getRevisions($this->pageid, $first, $num, $chunk_size = 8192, $media = false); + $this->assertEquals($revsexpected, $revs); + + $revs = getRevisions($this->pageid, $first, $num, $chunk_size = 512, $media = false); + $this->assertEquals($revsexpected, $revs); + } + + /** + * get oldest revisions + */ + function test_requestlargeoffset() { + $first = 22; + $num = 50; + $revsexpected = array_slice($this->revsexpected, $first + 1); + + $revs = getRevisions($this->pageid, $first, $num, $chunk_size = 8192, $media = false); + $this->assertEquals($revsexpected, $revs); + } + + /** + * request with too large offset and range + */ + function test_requesttoolargenumberrevs() { + $first = 50; + $num = 50; + $revsexpected = array(); + + $revs = getRevisions($this->pageid, $first, $num, $chunk_size = 8192, $media = false); + $this->assertEquals($revsexpected, $revs); + } + +} \ No newline at end of file -- cgit v1.2.3 From 51bd6f039e782dca456022514893aa80bd7c52b9 Mon Sep 17 00:00:00 2001 From: Klap-in Date: Sat, 20 Jul 2013 02:31:50 +0200 Subject: Fixed file names of test classes --- .../tests/inc/changelog_getRevisionInfo.class.php | 120 ------------- _test/tests/inc/changelog_getRevisions.class.php | 200 --------------------- _test/tests/inc/changelog_getrevisioninfo.test.php | 120 +++++++++++++ _test/tests/inc/changelog_getrevisions.test.php | 200 +++++++++++++++++++++ 4 files changed, 320 insertions(+), 320 deletions(-) delete mode 100644 _test/tests/inc/changelog_getRevisionInfo.class.php delete mode 100644 _test/tests/inc/changelog_getRevisions.class.php create mode 100644 _test/tests/inc/changelog_getrevisioninfo.test.php create mode 100644 _test/tests/inc/changelog_getrevisions.test.php diff --git a/_test/tests/inc/changelog_getRevisionInfo.class.php b/_test/tests/inc/changelog_getRevisionInfo.class.php deleted file mode 100644 index 9637d21c8..000000000 --- a/_test/tests/inc/changelog_getRevisionInfo.class.php +++ /dev/null @@ -1,120 +0,0 @@ -assertEquals($revsexpected, $revs); - } - - /** - * request existing rev - */ - function test_requestrev() { - $rev = 1362525899; - $infoexpected = parseChangelogLine($this->logline); - - $info = getRevisionInfo($this->pageid, $rev, $chunk_size = 8192, $media = false); - $this->assertEquals($infoexpected, $info); - //returns cached value - $info = getRevisionInfo($this->pageid, $rev, $chunk_size = 8192, $media = false); - $this->assertEquals($infoexpected, $info); - } - - /** - * request existing rev with chucked reading - */ - function test_requestrev_chuncked() { - $rev = 1362525899; - $infoexpected = parseChangelogLine($this->logline); - - $info = getRevisionInfo($this->pageid, $rev, $chunk_size = 512, $media = false); - $this->assertEquals($infoexpected, $info); - } - - /** - * request current version - */ - function test_requestrecentestlogline() { - $rev = 1374261194; - $infoexpected = parseChangelogLine($this->firstlogline); - - $info = getRevisionInfo($this->pageid, $rev, $chunk_size = 8192, $media = false); - $this->assertEquals($infoexpected, $info); - //returns cached value - $info = getRevisionInfo($this->pageid, $rev, $chunk_size = 8192, $media = false); - $this->assertEquals($infoexpected, $info); - } - - /** - * request current version, with chuncked reading - */ - function test_requestrecentestlogline_chuncked() { - $rev = 1374261194; - $infoexpected = parseChangelogLine($this->firstlogline); - - $info = getRevisionInfo($this->pageid, $rev, $chunk_size = 512, $media = false); - $this->assertEquals($infoexpected, $info); - } - - /** - * request negative revision - */ - function test_negativerev() { - $rev = -10; - - $info = getRevisionInfo($this->pageid, $rev, $chunk_size = 8192, $media = false); - $this->assertEquals(false, $info); - } - - /** - * request non existing revision somewhere between existing revisions - */ - function test_notexistingrev() { - $rev = 1362525890; - - $info = getRevisionInfo($this->pageid, $rev, $chunk_size = 8192, $media = false); - $this->assertEquals(false, $info); - } - - /** - * sometimes chuncksize is set to true - */ - function test_chuncksizetrue() { - $rev = 1362525899; - $infoexpected = parseChangelogLine($this->logline); - - $info = getRevisionInfo($this->pageid, $rev, true); - $this->assertEquals($infoexpected, $info); - } -} \ No newline at end of file diff --git a/_test/tests/inc/changelog_getRevisions.class.php b/_test/tests/inc/changelog_getRevisions.class.php deleted file mode 100644 index a9be26dae..000000000 --- a/_test/tests/inc/changelog_getRevisions.class.php +++ /dev/null @@ -1,200 +0,0 @@ -assertEquals($revsexpected, $revs); - } - - /** - * request first recentest revision - * (so skips first line which belongs to the current existing page) - */ - function test_requestlastrev() { - $first = 0; - $num = 1; - $revsexpected = array($this->revsexpected[1]); - - $revs = getRevisions($this->pageid, $first, $num, $chunk_size = 8192, $media = false); - $this->assertEquals($revsexpected, $revs); - - $revs = getRevisions($this->pageid, $first, $num, $chunk_size = 512, $media = false); - $this->assertEquals($revsexpected, $revs); - } - - /** - * request first recentest revision - * (so skips first line which belongs to the current existing page) - */ - function test_requestonebutlastrev() { - $first = 1; - $num = 1; - $revsexpected = array($this->revsexpected[2]); - - $revs = getRevisions($this->pageid, $first, $num, $chunk_size = 8192, $media = false); - $this->assertEquals($revsexpected, $revs); - - $revs = getRevisions($this->pageid, $first, $num, $chunk_size = 512, $media = false); - $this->assertEquals($revsexpected, $revs); - } - - /** - * request first recentest revision - * (so skips first line of current existing page) - */ - function test_requestrevswithoffset() { - $first = 10; - $num = 5; - $revsexpected = array_slice($this->revsexpected, $first + 1, $num); - - $revs = getRevisions($this->pageid, $first, $num, $chunk_size = 8192, $media = false); - $this->assertEquals($revsexpected, $revs); - - $revs = getRevisions($this->pageid, $first, $num, $chunk_size = 512, $media = false); - $this->assertEquals($revsexpected, $revs); - } - - /** - * first = -1 requests recentest logline, without skipping - */ - function test_requestrecentestlogline() { - $first = -1; - $num = 1; - $revsexpected = array($this->revsexpected[0]); - - $revs = getRevisions($this->pageid, $first, $num, $chunk_size = 8192, $media = false); - $this->assertEquals($revsexpected, $revs); - - $revs = getRevisions($this->pageid, $first, $num, $chunk_size = 512, $media = false); - $this->assertEquals($revsexpected, $revs); - } - - /** - * chunck size = 0 skips chuncked loading - */ - function test_wholefile() { - $first = 0; - $num = 1000; - $revsexpected = array_slice($this->revsexpected, 1); - - $revs = getRevisions($this->pageid, $first, $num, $chunk_size = 0, $media = false); - $this->assertEquals($revsexpected, $revs); - } - - /** - * Negative range returns no result - */ - function test_negativenum() { - $first = 0; - $num = -10; - $revsexpected = array(); - - $revs = getRevisions($this->pageid, $first, $num, $chunk_size = 8192, $media = false); - $this->assertEquals($revsexpected, $revs); - - $revs = getRevisions($this->pageid, $first, $num, $chunk_size = 512, $media = false); - $this->assertEquals($revsexpected, $revs); - } - - /** - * Negative range returns no result - */ - function test_negativennumoffset() { - $first = 2; - $num = -10; - $revsexpected = array(); - - $revs = getRevisions($this->pageid, $first, $num, $chunk_size = 8192, $media = false); - $this->assertEquals($revsexpected, $revs); - - $revs = getRevisions($this->pageid, $first, $num, $chunk_size = 512, $media = false); - $this->assertEquals($revsexpected, $revs); - } - - /** - * zero range returns no result - */ - function test_zeronum() { - $first = 5; - $num = 0; - $revsexpected = array(); - - $revs = getRevisions($this->pageid, $first, $num, $chunk_size = 8192, $media = false); - $this->assertEquals($revsexpected, $revs); - - $revs = getRevisions($this->pageid, $first, $num, $chunk_size = 512, $media = false); - $this->assertEquals($revsexpected, $revs); - } - - /** - * get oldest revisions - */ - function test_requestlargeoffset() { - $first = 22; - $num = 50; - $revsexpected = array_slice($this->revsexpected, $first + 1); - - $revs = getRevisions($this->pageid, $first, $num, $chunk_size = 8192, $media = false); - $this->assertEquals($revsexpected, $revs); - } - - /** - * request with too large offset and range - */ - function test_requesttoolargenumberrevs() { - $first = 50; - $num = 50; - $revsexpected = array(); - - $revs = getRevisions($this->pageid, $first, $num, $chunk_size = 8192, $media = false); - $this->assertEquals($revsexpected, $revs); - } - -} \ No newline at end of file diff --git a/_test/tests/inc/changelog_getrevisioninfo.test.php b/_test/tests/inc/changelog_getrevisioninfo.test.php new file mode 100644 index 000000000..9637d21c8 --- /dev/null +++ b/_test/tests/inc/changelog_getrevisioninfo.test.php @@ -0,0 +1,120 @@ +assertEquals($revsexpected, $revs); + } + + /** + * request existing rev + */ + function test_requestrev() { + $rev = 1362525899; + $infoexpected = parseChangelogLine($this->logline); + + $info = getRevisionInfo($this->pageid, $rev, $chunk_size = 8192, $media = false); + $this->assertEquals($infoexpected, $info); + //returns cached value + $info = getRevisionInfo($this->pageid, $rev, $chunk_size = 8192, $media = false); + $this->assertEquals($infoexpected, $info); + } + + /** + * request existing rev with chucked reading + */ + function test_requestrev_chuncked() { + $rev = 1362525899; + $infoexpected = parseChangelogLine($this->logline); + + $info = getRevisionInfo($this->pageid, $rev, $chunk_size = 512, $media = false); + $this->assertEquals($infoexpected, $info); + } + + /** + * request current version + */ + function test_requestrecentestlogline() { + $rev = 1374261194; + $infoexpected = parseChangelogLine($this->firstlogline); + + $info = getRevisionInfo($this->pageid, $rev, $chunk_size = 8192, $media = false); + $this->assertEquals($infoexpected, $info); + //returns cached value + $info = getRevisionInfo($this->pageid, $rev, $chunk_size = 8192, $media = false); + $this->assertEquals($infoexpected, $info); + } + + /** + * request current version, with chuncked reading + */ + function test_requestrecentestlogline_chuncked() { + $rev = 1374261194; + $infoexpected = parseChangelogLine($this->firstlogline); + + $info = getRevisionInfo($this->pageid, $rev, $chunk_size = 512, $media = false); + $this->assertEquals($infoexpected, $info); + } + + /** + * request negative revision + */ + function test_negativerev() { + $rev = -10; + + $info = getRevisionInfo($this->pageid, $rev, $chunk_size = 8192, $media = false); + $this->assertEquals(false, $info); + } + + /** + * request non existing revision somewhere between existing revisions + */ + function test_notexistingrev() { + $rev = 1362525890; + + $info = getRevisionInfo($this->pageid, $rev, $chunk_size = 8192, $media = false); + $this->assertEquals(false, $info); + } + + /** + * sometimes chuncksize is set to true + */ + function test_chuncksizetrue() { + $rev = 1362525899; + $infoexpected = parseChangelogLine($this->logline); + + $info = getRevisionInfo($this->pageid, $rev, true); + $this->assertEquals($infoexpected, $info); + } +} \ No newline at end of file diff --git a/_test/tests/inc/changelog_getrevisions.test.php b/_test/tests/inc/changelog_getrevisions.test.php new file mode 100644 index 000000000..a9be26dae --- /dev/null +++ b/_test/tests/inc/changelog_getrevisions.test.php @@ -0,0 +1,200 @@ +assertEquals($revsexpected, $revs); + } + + /** + * request first recentest revision + * (so skips first line which belongs to the current existing page) + */ + function test_requestlastrev() { + $first = 0; + $num = 1; + $revsexpected = array($this->revsexpected[1]); + + $revs = getRevisions($this->pageid, $first, $num, $chunk_size = 8192, $media = false); + $this->assertEquals($revsexpected, $revs); + + $revs = getRevisions($this->pageid, $first, $num, $chunk_size = 512, $media = false); + $this->assertEquals($revsexpected, $revs); + } + + /** + * request first recentest revision + * (so skips first line which belongs to the current existing page) + */ + function test_requestonebutlastrev() { + $first = 1; + $num = 1; + $revsexpected = array($this->revsexpected[2]); + + $revs = getRevisions($this->pageid, $first, $num, $chunk_size = 8192, $media = false); + $this->assertEquals($revsexpected, $revs); + + $revs = getRevisions($this->pageid, $first, $num, $chunk_size = 512, $media = false); + $this->assertEquals($revsexpected, $revs); + } + + /** + * request first recentest revision + * (so skips first line of current existing page) + */ + function test_requestrevswithoffset() { + $first = 10; + $num = 5; + $revsexpected = array_slice($this->revsexpected, $first + 1, $num); + + $revs = getRevisions($this->pageid, $first, $num, $chunk_size = 8192, $media = false); + $this->assertEquals($revsexpected, $revs); + + $revs = getRevisions($this->pageid, $first, $num, $chunk_size = 512, $media = false); + $this->assertEquals($revsexpected, $revs); + } + + /** + * first = -1 requests recentest logline, without skipping + */ + function test_requestrecentestlogline() { + $first = -1; + $num = 1; + $revsexpected = array($this->revsexpected[0]); + + $revs = getRevisions($this->pageid, $first, $num, $chunk_size = 8192, $media = false); + $this->assertEquals($revsexpected, $revs); + + $revs = getRevisions($this->pageid, $first, $num, $chunk_size = 512, $media = false); + $this->assertEquals($revsexpected, $revs); + } + + /** + * chunck size = 0 skips chuncked loading + */ + function test_wholefile() { + $first = 0; + $num = 1000; + $revsexpected = array_slice($this->revsexpected, 1); + + $revs = getRevisions($this->pageid, $first, $num, $chunk_size = 0, $media = false); + $this->assertEquals($revsexpected, $revs); + } + + /** + * Negative range returns no result + */ + function test_negativenum() { + $first = 0; + $num = -10; + $revsexpected = array(); + + $revs = getRevisions($this->pageid, $first, $num, $chunk_size = 8192, $media = false); + $this->assertEquals($revsexpected, $revs); + + $revs = getRevisions($this->pageid, $first, $num, $chunk_size = 512, $media = false); + $this->assertEquals($revsexpected, $revs); + } + + /** + * Negative range returns no result + */ + function test_negativennumoffset() { + $first = 2; + $num = -10; + $revsexpected = array(); + + $revs = getRevisions($this->pageid, $first, $num, $chunk_size = 8192, $media = false); + $this->assertEquals($revsexpected, $revs); + + $revs = getRevisions($this->pageid, $first, $num, $chunk_size = 512, $media = false); + $this->assertEquals($revsexpected, $revs); + } + + /** + * zero range returns no result + */ + function test_zeronum() { + $first = 5; + $num = 0; + $revsexpected = array(); + + $revs = getRevisions($this->pageid, $first, $num, $chunk_size = 8192, $media = false); + $this->assertEquals($revsexpected, $revs); + + $revs = getRevisions($this->pageid, $first, $num, $chunk_size = 512, $media = false); + $this->assertEquals($revsexpected, $revs); + } + + /** + * get oldest revisions + */ + function test_requestlargeoffset() { + $first = 22; + $num = 50; + $revsexpected = array_slice($this->revsexpected, $first + 1); + + $revs = getRevisions($this->pageid, $first, $num, $chunk_size = 8192, $media = false); + $this->assertEquals($revsexpected, $revs); + } + + /** + * request with too large offset and range + */ + function test_requesttoolargenumberrevs() { + $first = 50; + $num = 50; + $revsexpected = array(); + + $revs = getRevisions($this->pageid, $first, $num, $chunk_size = 8192, $media = false); + $this->assertEquals($revsexpected, $revs); + } + +} \ No newline at end of file -- cgit v1.2.3 From c71db656795e82055d114764ad93f71a968a2f28 Mon Sep 17 00:00:00 2001 From: Anika Henke Date: Sun, 21 Jul 2013 21:20:44 +0100 Subject: added tpl_classes() to return useful layout classes --- inc/template.php | 18 ++++++++++++++++++ lib/tpl/dokuwiki/detail.php | 4 ++-- lib/tpl/dokuwiki/main.php | 5 ++--- 3 files changed, 22 insertions(+), 5 deletions(-) diff --git a/inc/template.php b/inc/template.php index a87650b84..087e2f9df 100644 --- a/inc/template.php +++ b/inc/template.php @@ -1748,5 +1748,23 @@ function tpl_media() { echo '
'.NL; } +/** + * Return useful layout classes + * + * @author Anika Henke + */ +function tpl_classes() { + global $ACT, $conf, $ID, $INFO; + $classes = array( + 'dokuwiki', + 'mode_'.$ACT, + 'tpl_'.$conf['template'], + ($_SERVER['REMOTE_USER']) ? 'loggedIn' : '', + ($INFO['exists']) ? '' : 'notFound', + ($ID == $conf['start']) ? 'home' : '', + ); + return join(' ', $classes); +} + //Setup VIM: ex: et ts=4 : diff --git a/lib/tpl/dokuwiki/detail.php b/lib/tpl/dokuwiki/detail.php index 9108504f1..c44a697dd 100644 --- a/lib/tpl/dokuwiki/detail.php +++ b/lib/tpl/dokuwiki/detail.php @@ -28,8 +28,8 @@ header('X-UA-Compatible: IE=edge,chrome=1'); -
+
diff --git a/lib/tpl/dokuwiki/main.php b/lib/tpl/dokuwiki/main.php index d432a701e..016146275 100644 --- a/lib/tpl/dokuwiki/main.php +++ b/lib/tpl/dokuwiki/main.php @@ -27,9 +27,8 @@ $showSidebar = $hasSidebar && ($ACT=='show'); -
+
-- cgit v1.2.3 From 6b0ec830e5ac0044252908630e52d4494f1df570 Mon Sep 17 00:00:00 2001 From: Michael Hamann Date: Sun, 21 Jul 2013 22:59:27 +0200 Subject: In debug mode: catch and log JS errors with file information When debugging is enabled (allowdebug enabled) JS errors are now catched for each non-core JS file and logged with the additional information from which file they came. This should make it easier to find out which plugin is the cause for broken JS code. The feature isn't enabled by default as defining functions inside try-clauses isn't allowed in strict mode and causes a warning at least in Firefox. --- lib/exe/js.php | 3 +++ lib/scripts/helpers.js | 15 +++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/lib/exe/js.php b/lib/exe/js.php index 4ff48133e..06769d895 100644 --- a/lib/exe/js.php +++ b/lib/exe/js.php @@ -104,10 +104,13 @@ function js_out(){ // load files foreach($files as $file){ $ismin = (substr($file,-7) == '.min.js'); + $debugjs = ($conf['allowdebug'] && strpos($file, DOKU_INC.'lib/scripts/') !== 0); echo "\n\n/* XXXXXXXXXX begin of ".str_replace(DOKU_INC, '', $file) ." XXXXXXXXXX */\n\n"; if($ismin) echo "\n/* BEGIN NOCOMPRESS */\n"; + if ($debugjs) echo "\ntry {\n"; js_load($file); + if ($debugjs) echo "\n} catch (e) {\n logError(e, '".str_replace(DOKU_INC, '', $file)."');\n}\n"; if($ismin) echo "\n/* END NOCOMPRESS */\n"; echo "\n\n/* XXXXXXXXXX end of " . str_replace(DOKU_INC, '', $file) . " XXXXXXXXXX */\n\n"; } diff --git a/lib/scripts/helpers.js b/lib/scripts/helpers.js index d6f36967d..fdac13b71 100644 --- a/lib/scripts/helpers.js +++ b/lib/scripts/helpers.js @@ -68,3 +68,18 @@ function bind(fnc/*, ... */) { static_args.concat(Aps.call(arguments, 0))); }; } + +/** + * Report an error from a JS file to the console + * + * @param e The error object + * @param file The file in which the error occurred + */ +function logError(e, file) { + if (window.console && console.error) { + console.error('The error "%s: %s" occurred in file "%s". ' + + 'If this is in a plugin try updating or disabling the plugin, ' + + 'if this is in a template try updating the template or switching to the "default" or "dokuwiki" template.', + e.name, e.message, file); + } +} \ No newline at end of file -- cgit v1.2.3 From 654436fbc9a7765d9faacab950c7d3e8508b747c Mon Sep 17 00:00:00 2001 From: Anika Henke Date: Sun, 21 Jul 2013 23:21:00 +0100 Subject: fixed references to images in old template (FS#2816) --- install.php | 4 ++-- lib/exe/opensearch.php | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/install.php b/install.php index ab0fad121..9f1ad0dc1 100644 --- a/install.php +++ b/install.php @@ -148,8 +148,8 @@ header('Content-Type: text/html; charset=utf-8');
- driven by DokuWiki - powered by PHP + driven by DokuWiki + powered by PHP
diff --git a/lib/exe/opensearch.php b/lib/exe/opensearch.php index 73939c347..98f5f52d5 100644 --- a/lib/exe/opensearch.php +++ b/lib/exe/opensearch.php @@ -21,7 +21,7 @@ if(file_exists(DOKU_INC.'favicon.ico')){ }elseif(file_exists(tpl_incdir().'favicon.ico')){ $ico = DOKU_URL.'lib/tpl/'.$conf['template'].'/favicon.ico'; }else{ - $ico = DOKU_URL.'lib/tpl/default/images/favicon.ico'; + $ico = DOKU_URL.'lib/tpl/dokuwiki/images/favicon.ico'; } // output -- cgit v1.2.3 From b3fd863955b2c6c1987f36b9206b806da6e487c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EB=AA=85=EC=A7=84?= Date: Sun, 28 Jul 2013 02:00:10 +0200 Subject: Korean language update --- inc/lang/ko/edit.txt | 2 +- inc/lang/ko/index.txt | 2 +- inc/lang/ko/install.html | 9 ++------- inc/lang/ko/lang.php | 8 ++++---- inc/lang/ko/read.txt | 2 +- inc/lang/ko/register.txt | 2 +- lib/plugins/acl/lang/ko/help.txt | 2 +- lib/plugins/authldap/lang/ko/settings.php | 5 +++++ lib/plugins/config/lang/ko/intro.txt | 6 +++--- lib/plugins/config/lang/ko/lang.php | 4 ++-- lib/plugins/plugin/lang/ko/admin_plugin.txt | 2 +- lib/plugins/plugin/lang/ko/lang.php | 4 ++-- lib/plugins/popularity/lang/ko/intro.txt | 2 +- 13 files changed, 25 insertions(+), 25 deletions(-) diff --git a/inc/lang/ko/edit.txt b/inc/lang/ko/edit.txt index 97927b7fe..87d1a9a95 100644 --- a/inc/lang/ko/edit.txt +++ b/inc/lang/ko/edit.txt @@ -1 +1 @@ -문서를 편집하고 **저장**을 누르세요. 위키 구문은 [[wiki:syntax]] 또는 [[wiki:ko_syntax|(한국어) 구문]]을 참고하세요. 이 문서를 **더 좋게 만들 자신이 있을 때**에만 편집하세요. 연습을 하고 싶다면 먼저 [[playground:playground|연습장]]에 가서 연습하세요. \ No newline at end of file +문서를 편집하고 **저장**을 누르세요. 위키 구문은 [[wiki:syntax]]를 참고하세요. 이 문서를 **더 좋게 만들 자신이 있을 때**에만 편집하세요. 연습을 하고 싶다면 먼저 [[playground:playground|연습장]]에 가서 연습하세요. \ No newline at end of file diff --git a/inc/lang/ko/index.txt b/inc/lang/ko/index.txt index 058f04254..a98bf877e 100644 --- a/inc/lang/ko/index.txt +++ b/inc/lang/ko/index.txt @@ -1,3 +1,3 @@ ====== 사이트맵 ====== -[[doku>namespaces|이름공간]]에서 정렬한 모든 문서의 목록입니다. \ No newline at end of file +[[doku>ko:namespaces|이름공간]]에서 정렬한 모든 문서의 목록입니다. \ No newline at end of file diff --git a/inc/lang/ko/install.html b/inc/lang/ko/install.html index a9961b47e..886ed2d30 100644 --- a/inc/lang/ko/install.html +++ b/inc/lang/ko/install.html @@ -1,6 +1,5 @@

이 페이지는 Dokuwiki 설치와 환경 설정을 도와줍니다. -설치 과정에 대한 더 자세한 정보는 (한국어) 설치 문서와 -(영어) 설치 문서를 참고하시기 바랍니다.

+설치 과정에 대한 더 자세한 정보는 관련 문서를 참고하시기 바랍니다.

DokuWiki는 위키 문서와 문서와 관련된 정보(예를 들어 그림, 검색 색인, 이전 판 문서)를 저장하기 위해 일반적인 텍스트 파일을 사용합니다. 정상적으로 DokuWiki를 사용하려면 이 파일을 담고 있는 디렉토리에 대한 쓰기 권한을 가지고 있어야 합니다. 현재 설치 과정 중에는 디렉토리 권한 설정이 불가능합니다. 보통 직접 셸 명령어를 사용하거나, 호스팅을 사용한다면 FTP나 호스팅 제어판(예를 들어 CPanel)을 사용해서 설정해야 합니다.

@@ -8,8 +7,4 @@

현재 설치 과정중에 관리자로 로그인 후 DokuWiki의 관리 메뉴(플러그인 설치, 사용자 관리, 위키 문서 접근 권한 관리, 옵션 설정)를 가능하게 ACL에 대한 환경 설정을 수행합니다. DokuWiki가 동작하는데 필요한 사항은 아니지만, 어쨌든 더 쉽게 관리자가 관리할 수 있도록 해줍니다.

-

숙련된 사용자나 특별한 설치 과정이 필요한 경우에 다음 링크를 참고하시기 바랍니다: -설치 과정 (한국어) -과 환경 설정 (한국어), -설치 과정 (영어) -과 환경 설정 (영어)

\ No newline at end of file +

숙련된 사용자나 특별한 설치 과정이 필요한 경우에는 설치 과정환경 설정 링크를 참고하시기 바랍니다.

\ No newline at end of file diff --git a/inc/lang/ko/lang.php b/inc/lang/ko/lang.php index 76684659c..71edc2a3e 100644 --- a/inc/lang/ko/lang.php +++ b/inc/lang/ko/lang.php @@ -71,8 +71,8 @@ $lang['regmissing'] = '모든 항목을 입력해야 합니다.'; $lang['reguexists'] = '같은 이름을 사용하는 사용자가 있습니다.'; $lang['regsuccess'] = '사용자를 만들었으며 비밀번호는 이메일로 보냈습니다.'; $lang['regsuccess2'] = '사용자를 만들었습니다.'; -$lang['regmailfail'] = '비밀번호를 이메일로 보낼 때 오류가 발생했습니다. 관리자에게 문의하시기 바랍니다!'; -$lang['regbadmail'] = '이메일 주소가 잘못됐습니다 - 오류라고 생각하면 관리자에게 문의하시기 바랍니다'; +$lang['regmailfail'] = '비밀번호를 이메일로 보낼 때 오류가 발생했습니다. 관리자에게 문의하세요!'; +$lang['regbadmail'] = '이메일 주소가 잘못됐습니다 - 오류라고 생각하면 관리자에게 문의하세요'; $lang['regbadpass'] = '새 비밀번호가 일치하지 않습니다. 다시 입력하세요.'; $lang['regpwmail'] = 'DokuWiki 비밀번호'; $lang['reghere'] = '계정이 없나요? 계정을 등록할 수 있습니다'; @@ -109,7 +109,7 @@ $lang['js']['mediaalign'] = '배치'; $lang['js']['mediasize'] = '그림 크기'; $lang['js']['mediatarget'] = '링크 목표'; $lang['js']['mediaclose'] = '닫기'; -$lang['js']['mediainsert'] = '삽입'; +$lang['js']['mediainsert'] = '넣기'; $lang['js']['mediadisplayimg'] = '그림을 보여줍니다.'; $lang['js']['mediadisplaylnk'] = '링크만 보여줍니다.'; $lang['js']['mediasmall'] = '작게'; @@ -272,7 +272,7 @@ $lang['i_enableacl'] = 'ACL 기능 사용 (권장)'; $lang['i_superuser'] = '슈퍼 유저'; $lang['i_problems'] = '설치하는 동안 아래와 같은 문제가 발생했습니다. 문제를 해결한 후 설치를 계속하세요.'; $lang['i_modified'] = '보안 상의 이유로 이 스크립트는 수정되지 않은 새 Dokuwiki 설치에서만 동작됩니다. -다운로드한 압축 패키지를 다시 설치하거나 DokuWiki 설치 과정을 참고해서 설치하세요.'; +다운로드한 압축 패키지를 다시 설치하거나 DokuWiki 설치 과정을 참고해서 설치하세요.'; $lang['i_funcna'] = '%s PHP 함수의 사용이 불가능합니다. 호스트 제공자가 어떤 이유에서인지 막아 놓았을지 모릅니다.'; $lang['i_phpver'] = 'PHP %s 버전은 필요한 %s 버전보다 오래되었습니다. PHP를 업그레이드할 필요가 있습니다.'; $lang['i_permfail'] = 'DokuWiki는 %s에 쓰기 가능 권한이 없습니다. 먼저 이 디렉토리에 쓰기 권한이 설정되어야 합니다!'; diff --git a/inc/lang/ko/read.txt b/inc/lang/ko/read.txt index 8f080fcb1..079b8e130 100644 --- a/inc/lang/ko/read.txt +++ b/inc/lang/ko/read.txt @@ -1 +1 @@ -이 문서는 읽기 전용입니다. 내용을 볼 수는 있지만 바꿀 수는 없습니다. 문제가 있다고 생각하면 관리자에게 문의하세요. \ No newline at end of file +이 문서는 읽기 전용입니다. 원본을 볼 수는 있지만 바꿀 수는 없습니다. 문제가 있다고 생각하면 관리자에게 문의하세요. \ No newline at end of file diff --git a/inc/lang/ko/register.txt b/inc/lang/ko/register.txt index 6509bed91..4df968896 100644 --- a/inc/lang/ko/register.txt +++ b/inc/lang/ko/register.txt @@ -1,3 +1,3 @@ ====== 새 사용자 등록 ====== -이 위키에 새 계정을 만드려면 아래의 모든 내용을 입력하세요. **올바른 이메일 주소**를 사용하세요. 비밀번호를 입력하는 곳이 없다면 비밀번호는 이 이메일로 보내집니다. 사용자 이름은 올바른 [[doku>pagename|pagename]]이어야 합니다. \ No newline at end of file +이 위키에 새 계정을 만드려면 아래의 모든 내용을 입력하세요. **올바른 이메일 주소**를 사용하세요. 비밀번호를 입력하는 곳이 없다면 비밀번호는 이 이메일로 보내집니다. 사용자 이름은 올바른 [[doku>ko:pagename|문서이름]]이어야 합니다. \ No newline at end of file diff --git a/lib/plugins/acl/lang/ko/help.txt b/lib/plugins/acl/lang/ko/help.txt index 0386b5990..ba3dd6d9f 100644 --- a/lib/plugins/acl/lang/ko/help.txt +++ b/lib/plugins/acl/lang/ko/help.txt @@ -5,4 +5,4 @@ * 위쪽 입력 양식에서 선택된 사용자와 그룹의 접근 권한을 보거나 바꿀 수 있습니다. * 아래 테이블에서 현재 설정된 모든 접근 제어 규칙을 볼 수 있으며, 즉시 여러 규칙을 삭제하거나 바꿀 수 있습니다. -DokuWiki에서 접근 제어가 어떻게 동작되는지 알아보려면 [[doku>acl|ACL 공식 문서]]를 읽어보시기 바랍니다. \ No newline at end of file +DokuWiki에서 접근 제어가 어떻게 동작되는지 알아보려면 [[doku>ko:acl|ACL 공식 문서]]를 읽어보시기 바랍니다. \ No newline at end of file diff --git a/lib/plugins/authldap/lang/ko/settings.php b/lib/plugins/authldap/lang/ko/settings.php index 7f7efe8d0..6200a03b9 100644 --- a/lib/plugins/authldap/lang/ko/settings.php +++ b/lib/plugins/authldap/lang/ko/settings.php @@ -13,9 +13,14 @@ $lang['groupfilter'] = '그룹을 찾을 LDAP 필터. 예를 들어 ko:config|설정 문서 (한국어)]]와 [[doku>config|설정 문서 (영어)]]를 참고하세요. +DokuWiki 설치할 때 설정을 바꾸기 위해 사용하는 페이지입니다. 각 설정에 대한 자세한 도움말이 필요하다면 [[doku>ko:config|설정]] 문서를 참고하세요. 플러그인에 대한 자세한 정보가 필요하다면 [[doku>ko:plugin:config|플러그인 설정]] 문서를 참고하세요. -플러그인에 대한 자세한 정보가 필요하다면 [[doku>plugin:config|플러그인 설정]] 문서를 참고하세요. 빨간 배경색으로 보이는 설정은 이 플러그인에서 바꾸지 못하도록 되어있습니다. 파란 배경색으로 보이는 설정은 기본 설정값을 가지고 있습니다. 하얀 배경색으로 보이는 설정은 특별한 설치를 위해 설정되어 있습니다. 파란색과 하얀색 배경으로 된 설정은 바꿀 수 있습니다. +빨간 배경색으로 보이는 설정은 이 플러그인에서 바꾸지 못하도록 되어있습니다. 파란 배경색으로 보이는 설정은 기본 설정값을 가지고 있습니다. 하얀 배경색으로 보이는 설정은 특별한 설치를 위해 설정되어 있습니다. 파란색과 하얀색 배경으로 된 설정은 바꿀 수 있습니다. 이 페이지를 떠나기 전에 **저장** 버튼을 누르지 않으면 바뀐 값은 적용되지 않습니다. \ No newline at end of file diff --git a/lib/plugins/config/lang/ko/lang.php b/lib/plugins/config/lang/ko/lang.php index da155bcef..f0f7f60fa 100644 --- a/lib/plugins/config/lang/ko/lang.php +++ b/lib/plugins/config/lang/ko/lang.php @@ -62,7 +62,7 @@ $lang['youarehere'] = '계층형 위치 추적 (다음 위의 옵션 $lang['fullpath'] = '문서 하단에 전체 경로 보여주기'; $lang['typography'] = '기호 대체'; $lang['dformat'] = '날짜 형식 (PHP strftime 기능 참고)'; -$lang['signature'] = '편집기에서 서명 버튼을 누를 때 삽입할 내용'; +$lang['signature'] = '편집기에서 서명 버튼을 누를 때 넣을 내용'; $lang['showuseras'] = '마지막에 문서를 편집한 사용자를 보여줄지 여부'; $lang['toptoclevel'] = '목차 최상위 항목'; $lang['tocminheads'] = '목차 표시 여부를 결정할 최소한의 문단 제목 항목의 수'; @@ -86,7 +86,7 @@ $lang['rememberme'] = '항상 로그인 정보 저장 허용 (기억 $lang['disableactions'] = 'DokuWiki 활동 비활성화'; $lang['disableactions_check'] = '검사'; $lang['disableactions_subscription'] = '구독 신청/구독 취소'; -$lang['disableactions_wikicode'] = '내용 보기/원본 내보내기'; +$lang['disableactions_wikicode'] = '원본 보기/원본 내보내기'; $lang['disableactions_other'] = '다른 활동 (쉼표로 구분)'; $lang['auth_security_timeout'] = '인증 보안 초과 시간 (초)'; $lang['securecookie'] = 'HTTPS로 보내진 쿠키는 HTTPS에만 적용 할까요? 위키의 로그인 페이지만 SSL로 암호화하고 위키 문서는 그렇지 않은 경우 비활성화 합니다.'; diff --git a/lib/plugins/plugin/lang/ko/admin_plugin.txt b/lib/plugins/plugin/lang/ko/admin_plugin.txt index 7cbd08f7a..aeef5fedf 100644 --- a/lib/plugins/plugin/lang/ko/admin_plugin.txt +++ b/lib/plugins/plugin/lang/ko/admin_plugin.txt @@ -1,3 +1,3 @@ ====== 플러그인 관리 ====== -이 페이지에서 Dokuwiki [[doku>plugins|플러그인]]에 관련된 모든 관리 작업을 합니다. 플러그인을 다운로드하거나 설치하기 위해서는 웹 서버가 플러그인 디렉토리에 대해 쓰기 권한을 가지고 있어야 합니다. \ No newline at end of file +이 페이지에서 Dokuwiki [[doku>ko:plugins|플러그인]]에 관련된 모든 관리 작업을 합니다. 플러그인을 다운로드하거나 설치하기 위해서는 웹 서버가 플러그인 디렉토리에 대해 쓰기 권한을 가지고 있어야 합니다. \ No newline at end of file diff --git a/lib/plugins/plugin/lang/ko/lang.php b/lib/plugins/plugin/lang/ko/lang.php index 447fe667b..4e615b118 100644 --- a/lib/plugins/plugin/lang/ko/lang.php +++ b/lib/plugins/plugin/lang/ko/lang.php @@ -10,7 +10,7 @@ * @author erial2@gmail.com * @author Myeongjin */ -$lang['menu'] = '플러그인 관리자'; +$lang['menu'] = '플러그인 관리'; $lang['download'] = '새 플러그인 다운로드 및 설치'; $lang['manage'] = '이미 설치한 플러그인'; $lang['btn_info'] = '정보'; @@ -22,7 +22,7 @@ $lang['btn_enable'] = '저장'; $lang['url'] = 'URL'; $lang['installed'] = '설치됨:'; $lang['lastupdate'] = '가장 나중에 업데이트됨:'; -$lang['source'] = '내용:'; +$lang['source'] = '원본:'; $lang['unknown'] = '알 수 없음'; $lang['updating'] = '업데이트 중 ...'; $lang['updated'] = '%s 플러그인을 성공적으로 업데이트했습니다'; diff --git a/lib/plugins/popularity/lang/ko/intro.txt b/lib/plugins/popularity/lang/ko/intro.txt index c75c57ba5..0c884546a 100644 --- a/lib/plugins/popularity/lang/ko/intro.txt +++ b/lib/plugins/popularity/lang/ko/intro.txt @@ -1,6 +1,6 @@ ====== 인기도 조사 ====== -설치된 위키의 익명 정보를 DokuWiki 개발자에게 보냅니다. 이 [[doku>popularity|도구]]는 DokuWiki가 실제 사용자에게 어떻게 사용되는지 DokuWiki 개발자에게 알려줌으로써 이 후 개발 시 참고가 됩니다. +설치된 위키의 익명 정보를 DokuWiki 개발자에게 보냅니다. 이 [[doku>ko:popularity|도구]]는 DokuWiki가 실제 사용자에게 어떻게 사용되는지 DokuWiki 개발자에게 알려줌으로써 이 후 개발 시 참고가 됩니다. 설치된 위키가 커짐에 따라서 이 과정을 반복할 필요가 있습니다. 반복된 데이터는 익명 ID로 구별되어집니다. -- cgit v1.2.3 From 4b0e9be14f53973587becf18a79ad97e0b8ae195 Mon Sep 17 00:00:00 2001 From: Maciej Matejczuk Date: Sun, 28 Jul 2013 02:11:25 +0200 Subject: Polish language update --- lib/plugins/authad/lang/pl/settings.php | 10 ++++++++++ lib/plugins/authldap/lang/pl/settings.php | 7 +++++++ lib/plugins/authmysql/lang/pl/settings.php | 10 ++++++++++ lib/plugins/authpgsql/lang/pl/settings.php | 5 +++++ 4 files changed, 32 insertions(+) create mode 100644 lib/plugins/authad/lang/pl/settings.php create mode 100644 lib/plugins/authldap/lang/pl/settings.php create mode 100644 lib/plugins/authmysql/lang/pl/settings.php create mode 100644 lib/plugins/authpgsql/lang/pl/settings.php diff --git a/lib/plugins/authad/lang/pl/settings.php b/lib/plugins/authad/lang/pl/settings.php new file mode 100644 index 000000000..9113c0e51 --- /dev/null +++ b/lib/plugins/authad/lang/pl/settings.php @@ -0,0 +1,10 @@ +@my.domain.org'; +$lang['admin_password'] = 'Hasło dla powyższego użytkownika.'; +$lang['use_ssl'] = 'Użyć połączenie SSL? Jeśli tak to nie aktywuj TLS poniżej.'; +$lang['use_tls'] = 'Użyć połączenie TLS? Jeśli tak to nie aktywuj SSL powyżej.'; +$lang['expirywarn'] = 'Dni poprzedzających powiadomienie użytkownika o wygasającym haśle. 0 aby wyłączyć.'; diff --git a/lib/plugins/authldap/lang/pl/settings.php b/lib/plugins/authldap/lang/pl/settings.php new file mode 100644 index 000000000..44641f514 --- /dev/null +++ b/lib/plugins/authldap/lang/pl/settings.php @@ -0,0 +1,7 @@ + Date: Sun, 28 Jul 2013 02:12:20 +0200 Subject: Hungarian language update --- inc/lang/hu/diff.txt | 2 +- inc/lang/hu/draft.txt | 2 +- inc/lang/hu/edit.txt | 2 +- inc/lang/hu/install.html | 4 +- inc/lang/hu/lang.php | 168 +++++++++++++++++++---------- inc/lang/hu/locked.txt | 2 +- inc/lang/hu/mailwrap.html | 13 +++ inc/lang/hu/norev.txt | 2 +- inc/lang/hu/preview.txt | 3 +- inc/lang/hu/pwconfirm.txt | 4 +- inc/lang/hu/read.txt | 3 +- inc/lang/hu/register.txt | 2 +- inc/lang/hu/resendpwd.txt | 2 +- inc/lang/hu/resetpwd.txt | 3 + inc/lang/hu/searchpage.txt | 2 +- inc/lang/hu/subscr_digest.txt | 3 +- inc/lang/hu/subscr_list.txt | 5 +- inc/lang/hu/subscr_single.txt | 2 +- lib/plugins/acl/lang/hu/lang.php | 15 +-- lib/plugins/authad/lang/hu/settings.php | 18 ++++ lib/plugins/authldap/lang/hu/settings.php | 26 +++++ lib/plugins/authmysql/lang/hu/settings.php | 41 +++++++ lib/plugins/authpgsql/lang/hu/settings.php | 37 +++++++ lib/plugins/config/lang/hu/lang.php | 121 +++++++++++---------- lib/plugins/plugin/lang/hu/lang.php | 29 ++--- lib/plugins/popularity/lang/hu/lang.php | 1 + lib/plugins/revert/lang/hu/lang.php | 3 +- lib/plugins/usermanager/lang/hu/lang.php | 9 +- 28 files changed, 366 insertions(+), 158 deletions(-) create mode 100644 inc/lang/hu/mailwrap.html create mode 100644 inc/lang/hu/resetpwd.txt create mode 100644 lib/plugins/authad/lang/hu/settings.php create mode 100644 lib/plugins/authldap/lang/hu/settings.php create mode 100644 lib/plugins/authmysql/lang/hu/settings.php create mode 100644 lib/plugins/authpgsql/lang/hu/settings.php diff --git a/inc/lang/hu/diff.txt b/inc/lang/hu/diff.txt index 6a09cdea2..50bd067e9 100644 --- a/inc/lang/hu/diff.txt +++ b/inc/lang/hu/diff.txt @@ -1,4 +1,4 @@ ====== Különbségek ====== -A kiválasztott változat és az aktuális verzió közötti különbséget mutatjuk. +A kiválasztott változat és az aktuális verzió közötti különbségek a következők. diff --git a/inc/lang/hu/draft.txt b/inc/lang/hu/draft.txt index 4d12e2e0c..cae980aa5 100644 --- a/inc/lang/hu/draft.txt +++ b/inc/lang/hu/draft.txt @@ -2,4 +2,4 @@ Az oldal utolsó szerkesztését nem fejezted be rendesen. A DokuWiki elmentette piszkozatként, így most folytathatod a szerkesztést. Lent látható, amit az utolsó szerkesztésből elmentettünk. -Válassz a //helyreállítás// vagy a //törlés// opciók közül a piszkozat sorsát illetően. \ No newline at end of file +Válassz a //helyreállítás// vagy a //törlés// opciók közül a piszkozat sorsát illetően vagy //megszakíthatod// a szerkesztési folyamatot. \ No newline at end of file diff --git a/inc/lang/hu/edit.txt b/inc/lang/hu/edit.txt index 898387cf2..0992723c1 100644 --- a/inc/lang/hu/edit.txt +++ b/inc/lang/hu/edit.txt @@ -1 +1 @@ -Szerkeszd az oldalt majd üsd le a ''Mentés'' gombot. Lásd a [[wiki:syntax|nyelvtan]] oldalt a formázási lehetőségekért. Kérünk, hogy csak akkor szerkeszd az oldalt ha **jobbítani** tudod. Ha ki akarsz próbálni dolgokat akkor az első lépéseid a [[playground:playground|játszótéren]] (playground) tedd. +Szerkeszd az oldalt majd kattints a ''Mentés'' gombra! Lásd a [[wiki:syntax|formázás]] oldalt a formázási lehetőségekért. Kérünk, hogy csak akkor szerkeszd az oldalt ha **javítani** tudsz rajta. Ha ki akarsz próbálni dolgokat, akkor az első lépéseid a [[playground:playground|játszótéren]] tedd. diff --git a/inc/lang/hu/install.html b/inc/lang/hu/install.html index a7d681667..c0373932e 100644 --- a/inc/lang/hu/install.html +++ b/inc/lang/hu/install.html @@ -15,12 +15,12 @@ vagy a tárhelyszolgáltató által rendelkezésre bocsátott beállítóeszköz

A Beállító Varázsló felkészíti ezt a DokuWikit a hozzáférési listák (ACL-ek) használatára. Így -a Wiki-gazda felhasználóval hozzáférünk az admin menühöz, mellyel +az Adminisztrátor felhasználóval hozzáférünk az admin menühöz, mellyel bővítményeket telepíthetünk, felhasználókat és hozzáférési jogokat kezelhetünk, valamint változtathatunk a konfigurációs beállításokon. Ez tulajdonképpen nem szükséges a DokuWiki működéséhez, de megkönnyíti az adminisztrációt.

Szakértők illetve speciális beállítást igénylő felhasználók további információkat -találnak a következő oldalakon telepítéssel +találnak a következő oldalakon a telepítéssel és konfigurálási lehetőségekkel kapcsolatban.

diff --git a/inc/lang/hu/lang.php b/inc/lang/hu/lang.php index 275fb15d5..b332b9a83 100644 --- a/inc/lang/hu/lang.php +++ b/inc/lang/hu/lang.php @@ -10,6 +10,7 @@ * @author Szabó Dávid * @author Sándor TIHANYI * @author David Szabo + * @author Marton Sebok */ $lang['encoding'] = 'utf-8'; $lang['direction'] = 'ltr'; @@ -42,14 +43,17 @@ $lang['btn_delete'] = 'Törlés'; $lang['btn_back'] = 'Vissza'; $lang['btn_backlink'] = 'Hivatkozások'; $lang['btn_backtomedia'] = 'Vissza a médiafájlok kezeléséhez'; -$lang['btn_subscribe'] = 'Oldalváltozások-hírlevél feliratkozás'; +$lang['btn_subscribe'] = 'Feliratkozás az oldalváltozásokra'; $lang['btn_profile'] = 'Személyes beállítások'; $lang['btn_reset'] = 'Alaphelyzet'; +$lang['btn_resendpwd'] = 'Jelszóváltoztatás'; $lang['btn_draft'] = 'Piszkozat szerkesztése'; $lang['btn_recover'] = 'Piszkozat folytatása'; $lang['btn_draftdel'] = 'Piszkozat törlése'; $lang['btn_revert'] = 'Helyreállítás'; $lang['btn_register'] = 'Regisztráció'; +$lang['btn_apply'] = 'Alkalmaz'; +$lang['btn_media'] = 'Médiakezelő'; $lang['loggedinas'] = 'Belépett felhasználó: '; $lang['user'] = 'Azonosító'; $lang['pass'] = 'Jelszó'; @@ -60,16 +64,16 @@ $lang['remember'] = 'Emlékezz rám'; $lang['fullname'] = 'Teljes név'; $lang['email'] = 'E-Mail'; $lang['profile'] = 'Személyes beállítások'; -$lang['badlogin'] = 'Sajnáljuk, az azonosító, vagy a jelszó nem jó.'; +$lang['badlogin'] = 'Sajnáljuk, az azonosító vagy a jelszó nem jó.'; $lang['minoredit'] = 'Apróbb változások'; $lang['draftdate'] = 'Piszkozat elmentve:'; -$lang['nosecedit'] = 'Időközben megváltozott az oldal, emiatt a szakasz nem friss. Töltse újra az egész oldalt!'; +$lang['nosecedit'] = 'Időközben megváltozott az oldal, emiatt a szakasz nem friss. Töltsd újra az egész oldalt!'; $lang['regmissing'] = 'Sajnáljuk, az összes mezőt ki kell töltened.'; $lang['reguexists'] = 'Sajnáljuk, ilyen azonosítójú felhasználónk már van.'; $lang['regsuccess'] = 'A felhasználói azonosítót létrehoztuk. A jelszót postáztuk.'; $lang['regsuccess2'] = 'A felhasználói azonosítót létrehoztuk.'; -$lang['regmailfail'] = 'Úgy tűnik hiba történt a jelszó postázása során. Kérjük lépj kapcsolatba a Wiki-gazdával!!'; -$lang['regbadmail'] = 'A megadott e-mail cím érvénytelennek tűnik. Ha úgy gondolod ez hiba, lépj kapcsolatba Wiki-gazdával!'; +$lang['regmailfail'] = 'Úgy tűnik hiba történt a jelszó postázása során. Kérjük lépj kapcsolatba az Adminisztrátorokkal!'; +$lang['regbadmail'] = 'A megadott e-mail cím érvénytelennek tűnik. Ha úgy gondolod ez hiba, lépj kapcsolatba az Adminisztrátorokkal!'; $lang['regbadpass'] = 'A két megadott jelszó nem egyezik, próbáld újra!'; $lang['regpwmail'] = 'A DokuWiki jelszavad'; $lang['reghere'] = 'Még nincs azonosítód? Itt kérhetsz'; @@ -79,21 +83,23 @@ $lang['profnoempty'] = 'A név és e-mail mező nem maradhat üresen!' $lang['profchanged'] = 'A személyes beállítások változtatása megtörtént.'; $lang['pwdforget'] = 'Elfelejtetted a jelszavad? Itt kérhetsz újat'; $lang['resendna'] = 'Ez a wiki nem támogatja a jelszó újraküldést.'; +$lang['resendpwd'] = 'Új jelszó beállítása a következőhöz:'; $lang['resendpwdmissing'] = 'Sajnáljuk, az összes mezőt ki kell töltened.'; $lang['resendpwdnouser'] = 'Sajnáljuk, ilyen azonosítójú felhasználónk nem létezik.'; -$lang['resendpwdbadauth'] = 'Sajnáljuk, ez a megerősítő kód nem helyes. Biztos, hogy a teljes megerősítés linket beírtad pontosan?'; -$lang['resendpwdconfirm'] = 'A megerősítés linket e-mailben elküldtük.'; +$lang['resendpwdbadauth'] = 'Sajnáljuk, ez a megerősítő kód nem helyes. Biztos, hogy a teljes megerősítő linket pontosan beírtad?'; +$lang['resendpwdconfirm'] = 'A megerősítő linket e-mailben elküldtük.'; $lang['resendpwdsuccess'] = 'Az új jelszavadat elküldtük e-mailben.'; $lang['license'] = 'Hacsak máshol nincs egyéb rendelkezés, ezen wiki tartalma a következő licenc alatt érhető el:'; $lang['licenseok'] = 'Megjegyzés: az oldal szerkesztésével elfogadja, hogy a tartalom a következő licenc alatt lesz elérhető:'; $lang['searchmedia'] = 'Keresett fájl neve:'; $lang['searchmedia_in'] = 'Keresés a következőben: %s'; $lang['txt_upload'] = 'Válaszd ki a feltöltendő fájlt'; -$lang['txt_filename'] = 'feltöltési név (elhagyható)'; +$lang['txt_filename'] = 'Feltöltési név (elhagyható)'; $lang['txt_overwrt'] = 'Létező fájl felülírása'; +$lang['maxuploadsize'] = 'Maximum %s méretű fájlokat tölthetsz fel.'; $lang['lockedby'] = 'Jelenleg zárolta:'; $lang['lockexpire'] = 'A zárolás lejár:'; -$lang['js']['willexpire'] = 'Az oldalszerkesztési zárolásod körülbelül egy percen belül lejár.\nAz ütközések elkerülése végett használd az előnézet gombot a zárolási időzítés frissítéséhez.'; +$lang['js']['willexpire'] = 'Az oldalszerkesztési zárolásod körülbelül egy percen belül lejár.\nAz ütközések elkerülése végett használd az előnézet gombot a zárolásod frissítéséhez.'; $lang['js']['notsavedyet'] = 'Elmentetlen változások vannak, amelyek el fognak veszni. Tényleg ezt akarod?'; $lang['js']['searchmedia'] = 'Fájlok keresése'; @@ -103,50 +109,60 @@ $lang['js']['mediatitle'] = 'Link beállítások'; $lang['js']['mediadisplay'] = 'Link típusa'; $lang['js']['mediaalign'] = 'Igazítás'; $lang['js']['mediasize'] = 'Képméret'; -$lang['js']['mediatarget'] = 'Link'; +$lang['js']['mediatarget'] = 'Link célja'; $lang['js']['mediaclose'] = 'Bezárás'; $lang['js']['mediainsert'] = 'Beillesztés'; $lang['js']['mediadisplayimg'] = 'Kép megtekintése.'; $lang['js']['mediadisplaylnk'] = 'Link megtekintése.'; -$lang['js']['mediasmall'] = 'Kisebb méret'; +$lang['js']['mediasmall'] = 'Kis méret'; $lang['js']['mediamedium'] = 'Közepes méret'; -$lang['js']['medialarge'] = 'Nagyobb méret'; -$lang['js']['mediaoriginal'] = 'Eredeti'; +$lang['js']['medialarge'] = 'Nagy méret'; +$lang['js']['mediaoriginal'] = 'Eredeti verzió'; $lang['js']['medialnk'] = 'Link a részletekre'; $lang['js']['mediadirect'] = 'Közvetlen link az eredetire'; -$lang['js']['medianolnk'] = 'Nincsen link'; +$lang['js']['medianolnk'] = 'Nincs link'; $lang['js']['medianolink'] = 'Ne linkelje a képet'; $lang['js']['medialeft'] = 'Kép igazítása balra.'; $lang['js']['mediaright'] = 'Kép igazítása jobbra.'; $lang['js']['mediacenter'] = 'Kép igazítása középre.'; $lang['js']['medianoalign'] = 'Nem legyen igazítás.'; -$lang['js']['nosmblinks'] = 'A Windows megosztott könyvtárak kereszthivatkozása csak Microsoft Internet Explorerben működik közvetlenül. -A hivatkozást másolni és beszúrni ettől fügetlenül mndig tudod.'; +$lang['js']['nosmblinks'] = 'A Windows megosztott könyvtárak kereszthivatkozása csak Microsoft Internet Explorerben működik közvetlenül.\nA hivatkozást másolni és beszúrni ettől függetlenül mindig tudod.'; $lang['js']['linkwiz'] = 'Hivatkozás varázsló'; $lang['js']['linkto'] = 'Hivatkozás erre:'; $lang['js']['del_confirm'] = 'Valóban törölni akarod a kiválasztott elem(ek)et?'; -$lang['rssfailed'] = 'Hiba történt ennek a betöltésekor: '; -$lang['nothingfound'] = 'Semmit sem találtam.'; +$lang['js']['restore_confirm'] = 'Valóban visszaállítod ezt a verziót?'; +$lang['js']['media_diff'] = 'Különbségek megtekintése:'; +$lang['js']['media_diff_both'] = 'Egymás mellett'; +$lang['js']['media_diff_opacity'] = 'Áttetszően'; +$lang['js']['media_diff_portions'] = 'Húzással'; +$lang['js']['media_select'] = 'Fájlok kiválasztása...'; +$lang['js']['media_upload_btn'] = 'Feltöltés'; +$lang['js']['media_done_btn'] = 'Kész'; +$lang['js']['media_drop'] = 'Húzd ide a fájlokat a feltöltéshez'; +$lang['js']['media_cancel'] = 'eltávolítás'; +$lang['js']['media_overwrt'] = 'Meglévő fájlok felülírása'; +$lang['rssfailed'] = 'Hiba történt a hírfolyam betöltésekor: '; +$lang['nothingfound'] = 'Üres mappa.'; $lang['mediaselect'] = 'Médiafájl kiválasztása'; $lang['fileupload'] = 'Médiafájl feltöltése'; -$lang['uploadsucc'] = 'A feltöltés sikerült'; +$lang['uploadsucc'] = 'Sikeres feltöltés'; $lang['uploadfail'] = 'A feltöltés nem sikerült. Talán rosszak a jogosultságok?'; -$lang['uploadwrong'] = 'A feltöltés megtagadva. Ez a fájl kiterjesztés tiltott.'; +$lang['uploadwrong'] = 'A feltöltés megtagadva. Ez a fájlkiterjesztés tiltott.'; $lang['uploadexist'] = 'A fájl már létezik, nem történt semmi.'; -$lang['uploadbadcontent'] = 'A feltöltött tartalom nem egyezik a %s fájl kiterjesztéssel.'; +$lang['uploadbadcontent'] = 'A feltöltött tartalom nem egyezik a %s fájlkiterjesztéssel.'; $lang['uploadspam'] = 'A feltöltést visszautasítottuk spam-gyanú miatt.'; $lang['uploadxss'] = 'A feltöltést visszautasítottuk, mert lehetséges, hogy kártékony kódot tartalmaz.'; $lang['uploadsize'] = 'A feltöltött fájl túl nagy. (max. %s)'; $lang['deletesucc'] = 'A "%s" fájlt töröltük.'; -$lang['deletefail'] = 'A "%s" fájl nem törölhető. - Ellenőrizd a jogosultságokat!'; -$lang['mediainuse'] = 'A "%s" fájl nem törlődött - még használat alatt van.'; -$lang['namespaces'] = 'Névtér'; +$lang['deletefail'] = 'A "%s" fájl nem törölhető - ellenőrizd a jogosultságokat!'; +$lang['mediainuse'] = 'A "%s" fájl nem törlődött - még használat alatt van!'; +$lang['namespaces'] = 'Névterek'; $lang['mediafiles'] = 'Elérhető fájlok itt:'; -$lang['accessdenied'] = 'Nincsen jogod az oldal megtekintésére.'; -$lang['mediausage'] = 'A következő formában hivatkozhatsz erre az állományra:'; -$lang['mediaview'] = 'Eredeti állomány megtekintése'; +$lang['accessdenied'] = 'Nincs jogod az oldal megtekintésére.'; +$lang['mediausage'] = 'A következő formában hivatkozhatsz erre a fájlra:'; +$lang['mediaview'] = 'Eredeti fájl megtekintése'; $lang['mediaroot'] = 'kiindulási hely'; -$lang['mediaupload'] = 'Itt tölthetsz fel állományt az aktuális névtérbe. Al-névtér létrehozásához a "Feltöltési név" mezőben kell kettősponttal elválasztva megadnod azt.'; +$lang['mediaupload'] = 'Itt tölthetsz fel állományt az aktuális névtérbe. Alnévtér létrehozásához a "Feltöltési név" mezőben kell kettősponttal elválasztva megadnod azt.'; $lang['mediaextchange'] = 'Az állomány kiterjesztése erről: .%s erre: .%s változott!'; $lang['reference'] = 'Hivatkozások'; $lang['ref_inuse'] = 'A fájl nem törölhető, mert a következő oldalakon használják:'; @@ -155,34 +171,44 @@ $lang['hits'] = 'Találatok'; $lang['quickhits'] = 'Illeszkedő oldalnevek'; $lang['toc'] = 'Tartalomjegyzék'; $lang['current'] = 'aktuális'; -$lang['yours'] = 'A te változatod'; -$lang['diff'] = 'a különbségeket mutatja az aktuális változathoz képest'; -$lang['diff2'] = 'a különbségeket mutatja a kiválasztott változatok között'; +$lang['yours'] = 'A Te változatod'; +$lang['diff'] = 'Különbségek az aktuális változathoz képest'; +$lang['diff2'] = 'Különbségek a kiválasztott változatok között'; $lang['difflink'] = 'Összehasonlító nézet linkje'; $lang['diff_type'] = 'Összehasonlítás módja:'; $lang['diff_inline'] = 'Sorok között'; -$lang['diff_side'] = 'Kétoldalas'; -$lang['line'] = 'sorszám'; +$lang['diff_side'] = 'Egymás mellett'; +$lang['line'] = 'Sor'; $lang['breadcrumb'] = 'Nyomvonal'; $lang['youarehere'] = 'Itt vagy'; $lang['lastmod'] = 'Utolsó módosítás'; $lang['by'] = 'szerkesztette:'; $lang['deleted'] = 'eltávolítva'; $lang['created'] = 'létrehozva'; -$lang['restored'] = 'az előző változat helyreállítva (%s)'; +$lang['restored'] = 'régebbi változat helyreállítva (%s)'; $lang['external_edit'] = 'külső szerkesztés'; $lang['summary'] = 'A változások összefoglalása'; $lang['noflash'] = 'Ennek a tartalomnak a megtekintéséhez Adobe Flash Plugin szükséges.'; $lang['download'] = 'Kódrészlet letöltése'; +$lang['tools'] = 'Eszközök'; +$lang['user_tools'] = 'Felhasználói eszközök'; +$lang['site_tools'] = 'Eszközök a webhelyen'; +$lang['page_tools'] = 'Eszközök az oldalon'; +$lang['skip_to_content'] = 'ugrás a tartalomhoz'; +$lang['sidebar'] = 'Oldalsáv'; $lang['mail_newpage'] = 'új oldal jött létre:'; $lang['mail_changed'] = 'oldal megváltozott:'; $lang['mail_subscribe_list'] = 'oldalak megváltoztak ebben a névtérben:'; -$lang['mail_new_user'] = 'Új felhasználó:'; -$lang['mail_upload'] = 'állományt töltöttek fel:'; +$lang['mail_new_user'] = 'új felhasználó:'; +$lang['mail_upload'] = 'új állományt töltöttek fel:'; +$lang['changes_type'] = 'A következő változásainak megtekintése:'; +$lang['pages_changes'] = 'Oldalak'; +$lang['media_changes'] = 'Médiafájlok'; +$lang['both_changes'] = 'Oldalak és médiafájlok'; $lang['qb_bold'] = 'Félkövér szöveg'; $lang['qb_italic'] = 'Dőlt szöveg'; $lang['qb_underl'] = 'Aláhúzott szöveg'; -$lang['qb_code'] = 'Forráskód szöveg'; +$lang['qb_code'] = 'Forráskód'; $lang['qb_strike'] = 'Áthúzott szöveg'; $lang['qb_h1'] = '1. szintű címsor'; $lang['qb_h2'] = '2. szintű címsor'; @@ -198,16 +224,16 @@ $lang['qb_link'] = 'Belső hivatkozás'; $lang['qb_extlink'] = 'Külső hivatkozás'; $lang['qb_hr'] = 'Vízszintes elválasztó vonal'; $lang['qb_ol'] = 'Sorszámozott lista elem'; -$lang['qb_ul'] = 'Felsorolás lista elem'; +$lang['qb_ul'] = 'Felsorolásos lista elem'; $lang['qb_media'] = 'Képek és más fájlok hozzáadása'; $lang['qb_sig'] = 'Aláírás beszúrása'; -$lang['qb_smileys'] = 'Szmájlik'; +$lang['qb_smileys'] = 'Smiley-k'; $lang['qb_chars'] = 'Speciális karakterek'; -$lang['upperns'] = 'Ugrás a szülő névtérhez'; +$lang['upperns'] = 'ugrás a tartalmazó névtérhez'; $lang['admin_register'] = 'Új felhasználó'; -$lang['metaedit'] = 'Meta-adatok szerkesztése'; -$lang['metasaveerr'] = 'A meta-adatok írása meghiúsult '; -$lang['metasaveok'] = 'Meta-adatok elmentve'; +$lang['metaedit'] = 'Metaadatok szerkesztése'; +$lang['metasaveerr'] = 'A metaadatok írása nem sikerült'; +$lang['metasaveok'] = 'Metaadatok elmentve'; $lang['img_backto'] = 'Vissza'; $lang['img_title'] = 'Cím'; $lang['img_caption'] = 'Képaláírás'; @@ -215,17 +241,20 @@ $lang['img_date'] = 'Dátum'; $lang['img_fname'] = 'Fájlnév'; $lang['img_fsize'] = 'Méret'; $lang['img_artist'] = 'Készítette'; -$lang['img_copyr'] = 'Copyright'; +$lang['img_copyr'] = 'Szerzői jogok'; $lang['img_format'] = 'Formátum'; -$lang['img_camera'] = 'Fényképező típusa'; +$lang['img_camera'] = 'Fényképezőgép típusa'; $lang['img_keywords'] = 'Kulcsszavak'; +$lang['img_width'] = 'Szélesség'; +$lang['img_height'] = 'Magasság'; +$lang['img_manager'] = 'Megtekintés a médiakezelőben'; $lang['subscr_subscribe_success'] = '%s hozzáadva az értesítési listához: %s'; $lang['subscr_subscribe_error'] = 'Hiba történt %s hozzáadásakor az értesítési listához: %s'; -$lang['subscr_subscribe_noaddress'] = 'Nincsen e-mail cím megadva az adataidnál, így a rendszer nem tudott hozzáadni az értesítési listához'; +$lang['subscr_subscribe_noaddress'] = 'Nincs e-mail cím megadva az adataidnál, így a rendszer nem tudott hozzáadni az értesítési listához'; $lang['subscr_unsubscribe_success'] = '%s eltávolítva az értesítési listából: %s'; $lang['subscr_unsubscribe_error'] = 'Hiba történt %s eltávolításakor az értesítési listából: %s'; $lang['subscr_already_subscribed'] = '%s már feliratkozott erre: %s'; -$lang['subscr_not_subscribed'] = '%s nincsen feliratkozva erre: %s'; +$lang['subscr_not_subscribed'] = '%s nincs feliratkozva erre: %s'; $lang['subscr_m_not_subscribed'] = 'Jelenleg nem vagy feliratkozva erre az oldalra vagy névtérre'; $lang['subscr_m_new_header'] = 'Feliratkozás hozzáadása'; $lang['subscr_m_current_header'] = 'Feliratkozások'; @@ -235,13 +264,14 @@ $lang['subscr_m_receive'] = 'Küldj'; $lang['subscr_style_every'] = 'e-mailt minden változásról'; $lang['subscr_style_digest'] = 'összefoglaló e-mailt oldalanként (minden %.2f nap)'; $lang['subscr_style_list'] = 'egy listát a módosított oldalakról a legutóbbi e-mail óta (minden %.2f nap)'; -$lang['authmodfailed'] = 'Hibás felhasználó-aznosítási módszer van beállítva. Légy szíves értesítsd a Wiki-gazdát!'; -$lang['authtempfail'] = 'A felhasználó azonosítás átmenetileg nem működik. Ha sokáig így lenne, légy szíves értesítsd a Wiki-gazdát!'; +$lang['authmodfailed'] = 'Hibás felhasználó-azonosítási módszer van beállítva. Légy szíves értesítsd az Adminisztrátorokat!'; +$lang['authtempfail'] = 'A felhasználó azonosítás átmenetileg nem működik. Ha sokáig így lenne, légy szíves értesítsd az Adminisztrátorokat!'; +$lang['authpwdexpire'] = 'A jelszavad %d nap múlva lejár, hamarosan meg kell változtatnod.'; $lang['i_chooselang'] = 'Válassz nyelvet'; $lang['i_installer'] = 'DokuWiki Beállító Varázsló'; $lang['i_wikiname'] = 'A Wiki neve'; $lang['i_enableacl'] = 'Hozzáférési listák engedélyezése (ajánlott)'; -$lang['i_superuser'] = 'Wiki-gazda'; +$lang['i_superuser'] = 'Adminisztrátor'; $lang['i_problems'] = 'A Beállító Varázsló a következő problémák miatt megakadt. Nem tudjuk folytatni, amíg ezek nincsenek elhárítva!'; $lang['i_modified'] = 'Biztonsági okokból ez a Varázsló csak új és módosítatlan DokuWiki változaton működik. Csomagold ki újra a fájlokat a letöltött csomagból, vagy nézd meg a teljes Dokuwiki telepítési útmutatót.'; @@ -254,12 +284,15 @@ $lang['i_badhash'] = 'A dokuwiki.php nem felismerhető vagy módosí $lang['i_badval'] = '%s - nem helyes vagy üres érték'; $lang['i_success'] = 'A beállítás sikeresen befejeződött. Most már letörölhető az install.php fájl. Látogasd meg az új DokuWikidet!'; $lang['i_failure'] = 'Hiba lépett fel a konfigurációs állományok írásakor. Ki kell javítanod kézzel, mielőtt használni kezded az új DokuWikidet.'; -$lang['i_policy'] = 'Kezdeti hozzáférési politika'; -$lang['i_pol0'] = 'Nyitott Wiki (mindenki olvashatja, írhatja, és fájlokat tölthet fel)'; -$lang['i_pol1'] = 'Publikus Wiki (mindenki olvashatja, de csak regisztrált felhasználók írhatják, és tölthetnek fel fájlokat)'; -$lang['i_pol2'] = 'Zárt Wiki (csak regisztrált felhasználók olvashatják, írhatják és tölthetnek fel fájlokat)'; +$lang['i_policy'] = 'Kezdeti hozzáférési lista házirend'; +$lang['i_pol0'] = 'Nyitott wiki (mindenki olvashatja, írhatja és fájlokat tölthet fel)'; +$lang['i_pol1'] = 'Publikus wiki (mindenki olvashatja, de csak regisztrált felhasználók írhatják és tölthetnek fel fájlokat)'; +$lang['i_pol2'] = 'Zárt wiki (csak regisztrált felhasználók olvashatják, írhatják és tölthetnek fel fájlokat)'; $lang['i_retry'] = 'Újra'; -$lang['i_license'] = 'Kérlek válassz licenszt a feltöltött tartalomhoz:'; +$lang['i_license'] = 'Kérlek, válassz licencet a feltöltött tartalomhoz:'; +$lang['i_license_none'] = 'Ne jelenítsen meg licenc információt'; +$lang['i_pop_field'] = 'Kérjük, segíts a DokuWiki továbbfejlesztésében:'; +$lang['i_pop_label'] = 'Havonta egyszer névtelen üzenet küldése a DokuWiki fejlesztőinek'; $lang['recent_global'] = 'Jelenleg csak a %s névtér friss változásai látszanak. Megtekinthetők a teljes wiki friss változásai is.'; $lang['years'] = '%d évvel ezelőtt'; $lang['months'] = '%d hónappal ezelőtt'; @@ -268,4 +301,27 @@ $lang['days'] = '%d nappal ezelőtt'; $lang['hours'] = '%d órával ezelőtt'; $lang['minutes'] = '%d perccel ezelőtt'; $lang['seconds'] = '%d másodperccel ezelőtt'; -$lang['wordblock'] = 'A változásokat nem sikerült menteni, mert tiltott tartalom van benne (spam)'; +$lang['wordblock'] = 'A változásokat nem sikerült menteni, mert tiltott tartalom van benne (spam).'; +$lang['media_uploadtab'] = 'Feltöltés'; +$lang['media_searchtab'] = 'Keresés'; +$lang['media_file'] = 'Fájl'; +$lang['media_viewtab'] = 'Megtekintés'; +$lang['media_edittab'] = 'Szerkesztés'; +$lang['media_historytab'] = 'Korábbi változatok'; +$lang['media_list_thumbs'] = 'Bélyegképek'; +$lang['media_list_rows'] = 'Sorok'; +$lang['media_sort_name'] = 'Név'; +$lang['media_sort_date'] = 'Dátum'; +$lang['media_namespaces'] = 'Névtér kiválasztása'; +$lang['media_files'] = 'Fájlok itt: %s'; +$lang['media_upload'] = 'Feltöltés ide: %s'; +$lang['media_search'] = 'Keresés itt: %s'; +$lang['media_view'] = '%s'; +$lang['media_viewold'] = '%s itt: %s'; +$lang['media_edit'] = '%s szerkesztése'; +$lang['media_history'] = '%s korábbi változatai'; +$lang['media_meta_edited'] = 'metaadatot szerkesztve'; +$lang['media_perm_read'] = 'Sajnáljuk, nincs jogod a fájlok olvasásához.'; +$lang['media_perm_upload'] = 'Sajnáljuk, nincs jogod a feltöltéshez.'; +$lang['media_update'] = 'Új verzió feltöltése'; +$lang['media_restore'] = 'Ezen verzió visszaállítása'; diff --git a/inc/lang/hu/locked.txt b/inc/lang/hu/locked.txt index 229141674..004c46191 100644 --- a/inc/lang/hu/locked.txt +++ b/inc/lang/hu/locked.txt @@ -1,4 +1,4 @@ ====== Az oldal zárolva ====== -Ezt az oldalt épp szerkeszti egy másik felhasználó. Várnod kell, amíg a másik felhasználó befejezi, vagy amíg a zárolási időzítő le nem jár. +Ezt az oldalt épp szerkeszti egy másik felhasználó. Várnod kell, amíg a másik felhasználó befejezi, vagy amíg a zárolási ideje le nem jár. diff --git a/inc/lang/hu/mailwrap.html b/inc/lang/hu/mailwrap.html new file mode 100644 index 000000000..50fc497fd --- /dev/null +++ b/inc/lang/hu/mailwrap.html @@ -0,0 +1,13 @@ + + +@TITLE@ + + + + +@HTMLBODY@ + +

+Ezt a levelet a @DOKUWIKIURL@ DokuWiki generálta. + + \ No newline at end of file diff --git a/inc/lang/hu/norev.txt b/inc/lang/hu/norev.txt index 4dd408459..1f4e6725b 100644 --- a/inc/lang/hu/norev.txt +++ b/inc/lang/hu/norev.txt @@ -1,5 +1,5 @@ ====== Nincs ilyen változat ====== -A megadott változat nem létezik. Használd az ''Előző változatok'' nyomógombot az előzmények listájának megtekintéséhez. +A megadott változat nem létezik. Használd az ''Előző változatok'' gombot az előzmények listájának megtekintéséhez. diff --git a/inc/lang/hu/preview.txt b/inc/lang/hu/preview.txt index ad7f7d4b0..e04b2c838 100644 --- a/inc/lang/hu/preview.txt +++ b/inc/lang/hu/preview.txt @@ -1,4 +1,3 @@ ====== Előnézet ====== -Ez a szöveged előnézete, így fog kinézni. Figyelj jól: ez **még nincs elmentve**! - +Ez a szöveged előnézete, így fog kinézni élesben. Viszont ez **még nincs elmentve**! diff --git a/inc/lang/hu/pwconfirm.txt b/inc/lang/hu/pwconfirm.txt index 617419ee8..da677d151 100644 --- a/inc/lang/hu/pwconfirm.txt +++ b/inc/lang/hu/pwconfirm.txt @@ -5,8 +5,8 @@ címen lévő @TITLE@ wiki felhasználódhoz. Ha nem kértél ilyet, hagyd figyelmen kívül ezt a levelet. -Ha Te voltál, az új jelszó kérelmed megerősítéséhez a -következő linkre kattints, vagy másold a böngésződbe: +Ha Te voltál, az új jelszó kérelmed megerősítéséhez kattints a +következő linkre vagy másold a böngésződbe: @CONFIRM@ diff --git a/inc/lang/hu/read.txt b/inc/lang/hu/read.txt index 89ac96338..223a6fe1c 100644 --- a/inc/lang/hu/read.txt +++ b/inc/lang/hu/read.txt @@ -1,2 +1 @@ -Ez az oldal csak olvasható. Megtekintheted a forrását, de nem változtathatod meg. Ha úgy gondolod, hogy ez helytelen, kérdezd a Wiki-gazdát. - +Ez az oldal csak olvasható. Megtekintheted a forrását, de nem változtathatod meg. Ha úgy gondolod, hogy ez helytelen, kérdezd az Adminisztrátorokat! diff --git a/inc/lang/hu/register.txt b/inc/lang/hu/register.txt index 2745c4d77..523b720e7 100644 --- a/inc/lang/hu/register.txt +++ b/inc/lang/hu/register.txt @@ -1,4 +1,4 @@ ====== Új felhasználó regisztrálása ====== -Töltsd ki az összes alábbi adatot az új Wiki felhasználói azonosítód létrehozásához. Győződj meg róla, hogy **érvényes e-mail címet** adtál meg -- az új jelszavad erre a címre küldjük el. Az azonosítód érvényes [[doku>pagename|oldalnév]] kell legyen. +Töltsd ki az összes alábbi adatot az új Wiki felhasználói azonosítód létrehozásához. Győződj meg róla, hogy **érvényes e-mail címet** adtál meg, mivel az új jelszavad erre a címre küldjük el. Az azonosítód érvényes [[doku>pagename|oldalnév]] kell legyen. diff --git a/inc/lang/hu/resendpwd.txt b/inc/lang/hu/resendpwd.txt index 24931a7ed..b73fa42b2 100644 --- a/inc/lang/hu/resendpwd.txt +++ b/inc/lang/hu/resendpwd.txt @@ -1,3 +1,3 @@ ===== Új jelszó kérése ===== -Kérlek add meg a felhasználó neved az új jelszó elküldéséhez. A jelszó cseréjéhez szükséges megerősítő linket a regisztrált e-mail címedre küldjük. \ No newline at end of file +Kérlek, add meg a felhasználói azonosítód az új jelszó elküldéséhez. A jelszó cseréjéhez szükséges megerősítő linket elküldjük a regisztrált e-mail címedre. \ No newline at end of file diff --git a/inc/lang/hu/resetpwd.txt b/inc/lang/hu/resetpwd.txt new file mode 100644 index 000000000..53b28d75c --- /dev/null +++ b/inc/lang/hu/resetpwd.txt @@ -0,0 +1,3 @@ +====== Új jelszó beállítása ====== + +Kérlek, add meg az új jelszót a felhasználódhoz. \ No newline at end of file diff --git a/inc/lang/hu/searchpage.txt b/inc/lang/hu/searchpage.txt index b1defed84..ffde87b66 100644 --- a/inc/lang/hu/searchpage.txt +++ b/inc/lang/hu/searchpage.txt @@ -1,5 +1,5 @@ ====== Keresés ====== -A keresés eredményét lentebb láthatod. Ha nem találtad meg amit kerestél, akkor létrehozhatsz egy új oldalt a keresésed alapján ''Az oldal szerkesztése'' gombbal. +A keresés eredményét lentebb láthatod. Ha nem találtad meg amit kerestél, akkor létrehozhatsz egy új oldalt a keresésed alapján ''Az oldal szerkesztése'' gombbal. ===== Eredmény(ek) ===== \ No newline at end of file diff --git a/inc/lang/hu/subscr_digest.txt b/inc/lang/hu/subscr_digest.txt index 62e777faf..b00e0bba7 100644 --- a/inc/lang/hu/subscr_digest.txt +++ b/inc/lang/hu/subscr_digest.txt @@ -13,5 +13,4 @@ Régi verzió: @OLDPAGE@ Ha nem szeretnél értesítéseket kapni, jelentkezz be a wiki-be itt: @DOKUWIKIURL@, majd ezen az oldalon tudsz leiratkozni: @SUBSCRIBE@. -- -Ezt a levelet a DokuWiki generálta -@DOKUWIKIURL@ \ No newline at end of file +Ezt a levelet a @DOKUWIKIURL@ DokuWiki generálta. \ No newline at end of file diff --git a/inc/lang/hu/subscr_list.txt b/inc/lang/hu/subscr_list.txt index f68e6fc0a..13295ff41 100644 --- a/inc/lang/hu/subscr_list.txt +++ b/inc/lang/hu/subscr_list.txt @@ -1,7 +1,7 @@ Szia, A @PAGE@ névtérhez tartozó oldalak megváltoztak a @TITLE wikiben. -Itt vannak a módosított oldalak: +A módosított oldalak a következők: -------------------------------------------------------- @DIFF@ @@ -10,5 +10,4 @@ Itt vannak a módosított oldalak: Ha nem szeretnél értesítéseket kapni, jelentkezz be a wiki-be itt: @DOKUWIKIURL@, majd ezen az oldalon tudsz leiratkozni: @SUBSCRIBE@. -- -Ezt a levelet a DokuWiki generálta -@DOKUWIKIURL@ \ No newline at end of file +Ezt a levelet a @DOKUWIKIURL@ DokuWiki generálta. \ No newline at end of file diff --git a/inc/lang/hu/subscr_single.txt b/inc/lang/hu/subscr_single.txt index a17a98cfd..e28226de5 100644 --- a/inc/lang/hu/subscr_single.txt +++ b/inc/lang/hu/subscr_single.txt @@ -1,7 +1,7 @@ Szia, A @PAGE@ oldal a @TITLE wikiben megváltozott. -Itt vannak az eltérések: +Az eltérések a következők: -------------------------------------------------------- @DIFF@ diff --git a/lib/plugins/acl/lang/hu/lang.php b/lib/plugins/acl/lang/hu/lang.php index 255d838b6..9565eddc3 100644 --- a/lib/plugins/acl/lang/hu/lang.php +++ b/lib/plugins/acl/lang/hu/lang.php @@ -8,25 +8,26 @@ * @author Szabó Dávid * @author Sándor TIHANYI * @author David Szabo + * @author Marton Sebok */ $lang['admin_acl'] = 'Hozzáférési lista (ACL) kezelő'; $lang['acl_group'] = 'Csoport:'; $lang['acl_user'] = 'Felhasználó:'; $lang['acl_perms'] = 'Jogosultság ehhez:'; -$lang['page'] = 'oldal'; -$lang['namespace'] = 'névtér'; +$lang['page'] = 'Oldal'; +$lang['namespace'] = 'Névtér'; $lang['btn_select'] = 'Kiválaszt'; $lang['p_user_id'] = 'A(z) %s felhasználónak jelenleg a következő jogosultsága van ezen az oldalon: %s: %s.'; $lang['p_user_ns'] = 'A(z) %s felhasználónak jelenleg a következő jogosultsága van ebben a névtérben: %s: %s.'; $lang['p_group_id'] = 'A(z) %s csoport tagjainak jelenleg a következő jogosultsága van ezen az oldalon: %s: %s.'; $lang['p_group_ns'] = 'A(z) %s csoport tagjainak jelenleg a következő jogosultsága van ebben a névtérben: %s: %s.'; -$lang['p_choose_id'] = 'A felső formon adjon meg egy felhasználót vagy csoportot, akinek a(z) %s oldalhoz beállított jogosultságait megtekinteni vagy változtatni szeretné.'; -$lang['p_choose_ns'] = 'A felső formon adjon meg egy felhasználót vagy csoportot, akinek a(z) %s névtérhez beállított jogosultságait megtekinteni vagy változtatni szeretné.'; +$lang['p_choose_id'] = 'A felső űrlapon adjon meg egy felhasználót vagy csoportot, akinek a(z) %s oldalhoz beállított jogosultságait megtekinteni vagy változtatni szeretné.'; +$lang['p_choose_ns'] = 'A felső űrlapon adj meg egy felhasználót vagy csoportot, akinek a(z) %s névtérhez beállított jogosultságait megtekinteni vagy változtatni szeretnéd.'; $lang['p_inherited'] = 'Megjegyzés: ezek a jogok nem itt lettek explicit beállítva, hanem öröklődtek egyéb csoportokból vagy felsőbb névterekből.'; -$lang['p_isadmin'] = 'Megjegyzés: a kiválasztott csoportnak vagy felhasználónak mindig teljes jogosultsága lesz, mert Wiki-gazdának van beállítva.'; -$lang['p_include'] = 'A magasabb jogok tartalmazzák az alacsonyabbakat. A Létrehozás, Feltöltés és Törlés jogosultságok csak névterekre alkalmazhatók, az egyes oldalakra nem.'; +$lang['p_isadmin'] = 'Megjegyzés: a kiválasztott csoportnak vagy felhasználónak mindig teljes jogosultsága lesz, mert Adminisztrátornak van beállítva.'; +$lang['p_include'] = 'A magasabb szintű jogok tartalmazzák az alacsonyabbakat. A Létrehozás, Feltöltés és Törlés jogosultságok csak névterekre alkalmazhatók, az egyes oldalakra nem.'; $lang['current'] = 'Jelenlegi hozzáférési szabályok'; -$lang['where'] = 'Oldal/névtér'; +$lang['where'] = 'Oldal/Névtér'; $lang['who'] = 'Felhasználó/Csoport'; $lang['perm'] = 'Jogosultságok'; $lang['acl_perm0'] = 'Semmi'; diff --git a/lib/plugins/authad/lang/hu/settings.php b/lib/plugins/authad/lang/hu/settings.php new file mode 100644 index 000000000..c2cab410f --- /dev/null +++ b/lib/plugins/authad/lang/hu/settings.php @@ -0,0 +1,18 @@ + + */ +$lang['account_suffix'] = 'Felhasználói azonosító végződése, pl. @my.domain.org.'; +$lang['base_dn'] = 'Bázis DN, pl. DC=my,DC=domain,DC=org.'; +$lang['domain_controllers'] = 'Tartománykezelők listája vesszővel elválasztva, pl. srv1.domain.org,srv2.domain.org.'; +$lang['admin_username'] = 'Privilegizált AD felhasználó, aki az összes feéhasználó adatait elérheti. Elhagyható, de bizonyos funkciókhoz, például a feliratkozási e-mailek kiküldéséhez szükséges.'; +$lang['admin_password'] = 'Ehhez tartozó jelszó.'; +$lang['sso'] = 'Single-Sign-On Kerberos-szal vagy NTML használata?'; +$lang['real_primarygroup'] = 'A valódi elsődleges csoport feloldása a "Tartományfelhasználók" csoport használata helyett? (lassabb)'; +$lang['use_ssl'] = 'SSL használata? Ha használjuk, tiltsuk le a TLS-t!'; +$lang['use_tls'] = 'TLS használata? Ha használjuk, tiltsuk le az SSL-t!'; +$lang['debug'] = 'Debug-üzenetek megjelenítése?'; +$lang['expirywarn'] = 'Felhasználók értesítése ennyi nappal a jelszavuk lejárata előtt. 0 a funkció kikapcsolásához.'; +$lang['additional'] = 'Vesszővel elválasztott lista a további AD attribútumok lekéréshez. Néhány plugin használhatja.'; diff --git a/lib/plugins/authldap/lang/hu/settings.php b/lib/plugins/authldap/lang/hu/settings.php new file mode 100644 index 000000000..b4b28d0a0 --- /dev/null +++ b/lib/plugins/authldap/lang/hu/settings.php @@ -0,0 +1,26 @@ + + */ +$lang['server'] = 'LDAP-szerver. Hosztnév (localhost) vagy abszolút URL portszámmal (ldap://server.tld:389)'; +$lang['port'] = 'LDAP-szerver port, ha nem URL lett megadva'; +$lang['usertree'] = 'Hol találom a felhasználókat? Pl. ou=People, dc=server, dc=tld'; +$lang['grouptree'] = 'Hol találom a csoportokat? Pl. ou=Group, dc=server, dc=tld'; +$lang['userfilter'] = 'LDAP szűrő a felhasználók kereséséhez, pl. (&(uid=%{user})(objectClass=posixAccount))'; +$lang['groupfilter'] = 'LDAP szűrő a csoportok kereséséhez, pl. (&(objectClass=posixGroup)(|(gidNumber=%{gid})(memberUID=%{user})))'; +$lang['version'] = 'A használt protokollverzió. Valószínűleg a 3 megfelelő'; +$lang['starttls'] = 'TLS használata?'; +$lang['referrals'] = 'Hivatkozások követése?'; +$lang['deref'] = 'Hogyan fejtsük vissza az aliasokat?'; +$lang['binddn'] = 'Egy hozzáféréshez használt felhasználó DN-je, ha nincs névtelen hozzáférés. Pl. cn=admin, dc=my, dc=home'; +$lang['bindpw'] = 'Ehhez tartozó jelszó.'; +$lang['userscope'] = 'A keresési tartomány korlátozása erre a felhasználókra való keresésnél'; +$lang['groupscope'] = 'A keresési tartomány korlátozása erre a csoportokra való keresésnél'; +$lang['groupkey'] = 'Csoport meghatározása a következő attribútumból (az alapértelmezett AD csoporttagság helyett), pl. a szervezeti egység vagy a telefonszám'; +$lang['debug'] = 'Debug-üzenetek megjelenítése?'; +$lang['deref_o_0'] = 'LDAP_DEREF_NEVER'; +$lang['deref_o_1'] = 'LDAP_DEREF_SEARCHING'; +$lang['deref_o_2'] = 'LDAP_DEREF_FINDING'; +$lang['deref_o_3'] = 'LDAP_DEREF_ALWAYS'; diff --git a/lib/plugins/authmysql/lang/hu/settings.php b/lib/plugins/authmysql/lang/hu/settings.php new file mode 100644 index 000000000..9489c73f9 --- /dev/null +++ b/lib/plugins/authmysql/lang/hu/settings.php @@ -0,0 +1,41 @@ + + */ +$lang['server'] = 'MySQL-szerver'; +$lang['user'] = 'MySQL felhasználónév'; +$lang['password'] = 'Ehhez a jelszó'; +$lang['database'] = 'Adatbázis'; +$lang['charset'] = 'Az adatbázisban használt karakterkészlet'; +$lang['debug'] = 'Debug-üzenetek megjelenítése?'; +$lang['forwardClearPass'] = 'A jelszó nyílt szövegben való átadása a következő SQL utasításokban a passcrypt opció használata helyett'; +$lang['TablesToLock'] = 'Az íráskor zárolandó táblák vesszővel elválasztott listája'; +$lang['checkPass'] = 'SQL utasítás a jelszavak ellenőrzéséhez'; +$lang['getUserInfo'] = 'SQL utasítás a felhasználói információk lekérdezéséhez'; +$lang['getGroups'] = 'SQL utasítás egy felhasználó csoporttagságainak lekérdezéséhez'; +$lang['getUsers'] = 'SQL utasítás a felhasználók listázásához'; +$lang['FilterLogin'] = 'SQL kifejezés a felhasználók azonosító alapú szűréséhez'; +$lang['FilterName'] = 'SQL kifejezés a felhasználók név alapú szűréséhez'; +$lang['FilterEmail'] = 'SQL kifejezés a felhasználók e-mail cím alapú szűréséhez'; +$lang['FilterGroup'] = 'SQL kifejezés a felhasználók csoporttagság alapú szűréséhez'; +$lang['SortOrder'] = 'SQL kifejezés a felhasználók rendezéséhez'; +$lang['addUser'] = 'SQL utasítás új felhasználó hozzáadásához'; +$lang['addGroup'] = 'SQL utasítás új csoport hozzáadásához'; +$lang['addUserGroup'] = 'SQL utasítás egy felhasználó egy meglévő csoporthoz való hozzáadásához'; +$lang['delGroup'] = 'SQL utasítás egy csoport törléséhez'; +$lang['getUserID'] = 'SQL utasítás egy felhasználó elsődleges kulcsának lekérdezéséhez'; +$lang['delUser'] = 'SQL utasítás egy felhasználó törléséhez'; +$lang['delUserRefs'] = 'SQL utasítás egy felhasználó eltávolításához az összes csoportból'; +$lang['updateUser'] = 'SQL utasítás egy felhasználó profiljának frissítéséhez'; +$lang['UpdateLogin'] = 'SQL kifejezés a felhasználó azonosítójának frissítéséhez'; +$lang['UpdatePass'] = 'SQL kifejezés a felhasználó jelszavának frissítéséhez'; +$lang['UpdateEmail'] = 'SQL kifejezés a felhasználó e-mail címének frissítéséhez'; +$lang['UpdateName'] = 'SQL kifejezés a felhasználó nevének frissítéséhez'; +$lang['UpdateTarget'] = 'SQL kifejezés a felhasználó kiválasztásához az adatok frissítésekor'; +$lang['delUserGroup'] = 'SQL utasítás egy felhasználó eltávolításához egy adott csoportból'; +$lang['getGroupID'] = 'SQL utasítás egy csoport elsődleges kulcsának lekérdezéséhez'; +$lang['debug_o_0'] = 'nem'; +$lang['debug_o_1'] = 'csak hiba esetén'; +$lang['debug_o_2'] = 'minden SQL-lekérdezésnél'; diff --git a/lib/plugins/authpgsql/lang/hu/settings.php b/lib/plugins/authpgsql/lang/hu/settings.php new file mode 100644 index 000000000..7b9393256 --- /dev/null +++ b/lib/plugins/authpgsql/lang/hu/settings.php @@ -0,0 +1,37 @@ + + */ +$lang['server'] = 'PostgreSQL-szerver'; +$lang['port'] = 'PostgreSQL-port'; +$lang['user'] = 'PostgreSQL felhasználónév'; +$lang['password'] = 'Ehhez a jelszó'; +$lang['database'] = 'Adatbázis'; +$lang['debug'] = 'Debug-üzenetek megjelenítése?'; +$lang['forwardClearPass'] = 'A jelszó nyílt szövegben való átadása a következő SQL utasításokban a passcrypt opció használata helyett'; +$lang['checkPass'] = 'SQL utasítás a jelszavak ellenőrzéséhez'; +$lang['getUserInfo'] = 'SQL utasítás a felhasználói információk lekérdezéséhez'; +$lang['getGroups'] = 'SQL utasítás egy felhasználó csoporttagságainak lekérdezéséhez'; +$lang['getUsers'] = 'SQL utasítás a felhasználók listázásához'; +$lang['FilterLogin'] = 'SQL kifejezés a felhasználók azonosító alapú szűréséhez'; +$lang['FilterName'] = 'SQL kifejezés a felhasználók név alapú szűréséhez'; +$lang['FilterEmail'] = 'SQL kifejezés a felhasználók e-mail cím alapú szűréséhez'; +$lang['FilterGroup'] = 'SQL kifejezés a felhasználók csoporttagság alapú szűréséhez'; +$lang['SortOrder'] = 'SQL kifejezés a felhasználók rendezéséhez'; +$lang['addUser'] = 'SQL utasítás új felhasználó hozzáadásához'; +$lang['addGroup'] = 'SQL utasítás új csoport hozzáadásához'; +$lang['addUserGroup'] = 'SQL utasítás egy felhasználó egy meglévő csoporthoz való hozzáadásához'; +$lang['delGroup'] = 'SQL utasítás egy csoport törléséhez'; +$lang['getUserID'] = 'SQL utasítás egy felhasználó elsődleges kulcsának lekérdezéséhez'; +$lang['delUser'] = 'SQL utasítás egy felhasználó törléséhez'; +$lang['delUserRefs'] = 'SQL utasítás egy felhasználó eltávolításához az összes csoportból'; +$lang['updateUser'] = 'SQL utasítás egy felhasználó profiljának frissítéséhez'; +$lang['UpdateLogin'] = 'SQL kifejezés a felhasználó azonosítójának frissítéséhez'; +$lang['UpdatePass'] = 'SQL kifejezés a felhasználó jelszavának frissítéséhez'; +$lang['UpdateEmail'] = 'SQL kifejezés a felhasználó e-mail címének frissítéséhez'; +$lang['UpdateName'] = 'SQL kifejezés a felhasználó nevének frissítéséhez'; +$lang['UpdateTarget'] = 'SQL kifejezés a felhasználó kiválasztásához az adatok frissítésekor'; +$lang['delUserGroup'] = 'SQL utasítás egy felhasználó eltávolításához egy adott csoportból'; +$lang['getGroupID'] = 'SQL utasítás egy csoport elsődleges kulcsának lekérdezéséhez'; diff --git a/lib/plugins/config/lang/hu/lang.php b/lib/plugins/config/lang/hu/lang.php index a1de94160..c68cf4337 100644 --- a/lib/plugins/config/lang/hu/lang.php +++ b/lib/plugins/config/lang/hu/lang.php @@ -8,8 +8,9 @@ * @author Szabó Dávid * @author Sándor TIHANYI * @author David Szabo + * @author Marton Sebok */ -$lang['menu'] = 'Beállító Központ'; +$lang['menu'] = 'Beállítóközpont'; $lang['error'] = 'Helytelen érték miatt a módosítások nem mentődtek. Nézd át a módosításokat, és ments újra.
A helytelen érték(ek)et piros kerettel jelöljük.'; $lang['updated'] = 'A módosítások sikeresen beállítva.'; @@ -19,7 +20,7 @@ Nézd meg, hogy a fájl neve és jogosultságai helyesen vannak-e beállítva!'; $lang['danger'] = 'Figyelem: ezt a beállítást megváltoztatva a konfigurációs menü hozzáférhetetlenné válhat.'; $lang['warning'] = 'Figyelmeztetés: a beállítás megváltoztatása nem kívánt viselkedést okozhat.'; $lang['security'] = 'Biztonsági figyelmeztetés: a beállítás megváltoztatása biztonsági veszélyforrást okozhat.'; -$lang['_configuration_manager'] = 'Beállító Központ'; +$lang['_configuration_manager'] = 'Beállítóközpont'; $lang['_header_dokuwiki'] = 'DokuWiki beállítások'; $lang['_header_plugin'] = 'Bővítmények beállításai'; $lang['_header_template'] = 'Sablon beállítások'; @@ -30,33 +31,39 @@ $lang['_authentication'] = 'Azonosítás beállításai'; $lang['_anti_spam'] = 'Anti-Spam beállítások'; $lang['_editing'] = 'Szerkesztési beállítások'; $lang['_links'] = 'Link beállítások'; -$lang['_media'] = 'Media beállítások'; +$lang['_media'] = 'Média beállítások'; +$lang['_notifications'] = 'Értesítési beállítások'; +$lang['_syndication'] = 'Hírfolyam beállítások'; $lang['_advanced'] = 'Haladó beállítások'; $lang['_network'] = 'Hálózati beállítások'; $lang['_plugin_sufix'] = 'Bővítmények beállításai'; $lang['_template_sufix'] = 'Sablon beállítások'; -$lang['_msg_setting_undefined'] = 'Nincs beállított meta-adat.'; +$lang['_msg_setting_undefined'] = 'Nincs beállított metaadat.'; $lang['_msg_setting_no_class'] = 'Nincs beállított osztály.'; $lang['_msg_setting_no_default'] = 'Nincs alapértelmezett érték.'; -$lang['fmode'] = 'Fájl létrehozási maszk'; -$lang['dmode'] = 'Könyvtár létrehozási maszk'; -$lang['lang'] = 'Nyelv'; -$lang['basedir'] = 'Báziskönyvtár'; -$lang['baseurl'] = 'Alap URL'; -$lang['savedir'] = 'Könyvtár az adatok mentésére'; +$lang['title'] = 'Wiki neve'; $lang['start'] = 'Kezdőoldal neve'; -$lang['title'] = 'Wiki címe'; +$lang['lang'] = 'Nyelv'; $lang['template'] = 'Sablon'; +$lang['tagline'] = 'Lábléc (ha a sablon támogatja)'; +$lang['sidebar'] = 'Oldalsáv oldal neve (ha a sablon támogatja), az üres mező letiltja az oldalsáv megjelenítését'; $lang['license'] = 'Milyen licenc alatt érhető el a tartalom?'; -$lang['fullpath'] = 'Az oldalak teljes útvonalának mutatása a láblécben'; +$lang['savedir'] = 'Könyvtár az adatok mentésére'; +$lang['basedir'] = 'Báziskönyvtár (pl. /dokuwiki/). Hagyd üresen az automatikus beállításhoz!'; +$lang['baseurl'] = 'Báziscím (pl. http://www.yourserver.com). Hagyd üresen az automatikus beállításhoz!'; +$lang['cookiedir'] = 'Sütik címe. Hagy üresen a báziscím használatához!'; +$lang['dmode'] = 'Könyvtár létrehozási maszk'; +$lang['fmode'] = 'Fájl létrehozási maszk'; +$lang['allowdebug'] = 'Debug üzemmód Kapcsold ki, hacsak biztos nem szükséges!'; $lang['recent'] = 'Utolsó változatok száma'; +$lang['recent_days'] = 'Hány napig tartsuk meg a korábbi változatokat?'; $lang['breadcrumbs'] = 'Nyomvonal elemszám'; $lang['youarehere'] = 'Hierarchikus nyomvonal'; +$lang['fullpath'] = 'Az oldalak teljes útvonalának mutatása a láblécben'; $lang['typography'] = 'Legyen-e tipográfiai csere'; -$lang['htmlok'] = 'Beágyazott HTML engedélyezése'; -$lang['phpok'] = 'Beágyazott PHP engedélyezése'; $lang['dformat'] = 'Dátum formázás (lásd a PHP strftime függvényt)'; $lang['signature'] = 'Aláírás'; +$lang['showuseras'] = 'A felhasználó melyik adatát mutassunk az utolsó változtatás adatainál?'; $lang['toptoclevel'] = 'A tartalomjegyzék felső szintje'; $lang['tocminheads'] = 'Legalább ennyi címsor hatására generálódjon tartalomjegyzék'; $lang['maxtoclevel'] = 'A tartalomjegyzék mélysége'; @@ -64,75 +71,81 @@ $lang['maxseclevel'] = 'A szakasz-szerkesztés maximális szintje'; $lang['camelcase'] = 'CamelCase használata hivatkozásként'; $lang['deaccent'] = 'Oldalnevek ékezettelenítése'; $lang['useheading'] = 'Az első fejléc legyen az oldalnév'; -$lang['refcheck'] = 'Médiafájlok hivatkozásainak ellenőrzése'; -$lang['refshow'] = 'Média-hivatkozások maximálisan mutatott szintje'; -$lang['allowdebug'] = 'Debug üzemmód Kapcsold ki, hacsak biztos nem szükséges!'; -$lang['usewordblock'] = 'Szólista alapú spam-szűrés'; -$lang['indexdelay'] = 'Várakozás indexelés előtt (másodperc)'; -$lang['relnofollow'] = 'rel="nofollow" beállítás használata külső hivatkozásokra'; -$lang['mailguard'] = 'Email címek olvashatatlanná tétele címgyűjtők számára'; -$lang['iexssprotect'] = 'Feltöltött fájlok ellenőrzése kártékony JavaScript vagy HTML kód elkerülésére'; -$lang['showuseras'] = 'A felhasználó melyik adatát mutassunk az utolsó változtatás adatainál?'; +$lang['sneaky_index'] = 'Alapértelmezetten minden névtér látszik a DokuWiki áttekintő (index) oldalán. Ezen opció bekapcsolása után azok nem jelennek meg, melyekhez a felhasználónak nincs olvasás joga. De ezzel eltakarhatunk egyébként elérhető al-névtereket is, így bizonyos ACL beállításoknál használhatatlan indexet eredményez ez a beállítás.'; +$lang['hidepages'] = 'Az itt megadott oldalak elrejtése (reguláris kifejezés)'; $lang['useacl'] = 'Hozzáférési listák (ACL) használata'; $lang['autopasswd'] = 'Jelszavak automatikus generálása'; $lang['authtype'] = 'Authentikációs háttérrendszer'; $lang['passcrypt'] = 'Jelszó titkosítási módszer'; $lang['defaultgroup'] = 'Alapértelmezett csoport'; -$lang['superuser'] = 'Szuper-felhasználó (Wiki-gazda) - csoport vagy felhasználó, aki teljes hozzáférési joggal rendelkezik az oldalakhoz és funkciókhoz, a hozzáférési jogosultságoktól függetlenül'; +$lang['superuser'] = 'Adminisztrátor - csoport vagy felhasználó, aki teljes hozzáférési joggal rendelkezik az oldalakhoz és funkciókhoz, a hozzáférési jogosultságoktól függetlenül'; $lang['manager'] = 'Menedzser - csoport vagy felhasználó, aki bizonyos menedzsment funkciókhoz hozzáfér'; $lang['profileconfirm'] = 'Beállítások változtatásának megerősítése jelszóval'; +$lang['rememberme'] = 'Állandó sütik engedélyezése (az "emlékezz rám" funkcióhoz)'; $lang['disableactions'] = 'Bizonyos DokuWiki tevékenységek (action) tiltása'; $lang['disableactions_check'] = 'Ellenőrzés'; $lang['disableactions_subscription'] = 'Feliratkozás/Leiratkozás'; $lang['disableactions_wikicode'] = 'Forrás megtekintése/Nyers adat exportja'; $lang['disableactions_other'] = 'Egyéb tevékenységek (vesszővel elválasztva)'; -$lang['sneaky_index'] = 'Alapértelmezetten minden névtér látszik a DokuWiki áttekintő (index) oldalán. Ezen opció bekapcsolása után azok nem jelennek meg, melyekhez a felhasználónak nincs olvasás joga. De ezzel eltakarhatunk egyébként elérhető al-névtereket is, így bizonyos ACL beállításoknál használhatatlan indexet eredményez ez a beállítás.'; $lang['auth_security_timeout'] = 'Authentikációs biztonsági időablak (másodperc)'; $lang['securecookie'] = 'A böngészők a HTTPS felett beállított sütijüket csak HTTPS felett küldhetik? Kapcsoljuk ki ezt az opciót, ha csak a bejelentkezést védjük SSL-lel, a wiki tartalmának böngészése nyílt forgalommal történik.'; +$lang['remote'] = 'Távoli API engedélyezése. Ezzel más alkalmazások XML-RPC-n keresztül hozzáférhetnek a wikihez.'; +$lang['remoteuser'] = 'A távoli API hozzáférés korlátozása a következő felhasználókra vagy csoportokra. Hagyd üresen, ha mindenki számára elérhető!'; +$lang['usewordblock'] = 'Szólista alapú spam-szűrés'; +$lang['relnofollow'] = 'rel="nofollow" beállítás használata külső hivatkozásokra'; +$lang['indexdelay'] = 'Várakozás indexelés előtt (másodperc)'; +$lang['mailguard'] = 'Email címek olvashatatlanná tétele címgyűjtők számára'; +$lang['iexssprotect'] = 'Feltöltött fájlok ellenőrzése kártékony JavaScript vagy HTML kód elkerülésére'; +$lang['usedraft'] = 'Piszkozat automatikus mentése szerkesztés alatt'; +$lang['htmlok'] = 'Beágyazott HTML engedélyezése'; +$lang['phpok'] = 'Beágyazott PHP engedélyezése'; +$lang['locktime'] = 'Oldal-zárolás maximális időtartama (másodperc)'; +$lang['cachetime'] = 'A gyorsítótár maximális élettartama (másodperc)'; +$lang['target____wiki'] = 'Cél-ablak belső hivatkozásokhoz'; +$lang['target____interwiki'] = 'Cél-ablak interwiki hivatkozásokhoz'; +$lang['target____extern'] = 'Cél-ablak külső hivatkozásokhoz'; +$lang['target____media'] = 'Cél-ablak média-fájl hivatkozásokhoz'; +$lang['target____windows'] = 'Cél-ablak Windows hivatkozásokhoz'; +$lang['mediarevisions'] = 'Médiafájlok verziókövetésének engedélyezése'; +$lang['refcheck'] = 'Médiafájlok hivatkozásainak ellenőrzése'; +$lang['refshow'] = 'Médiafájlok hivatkozásainak maximálisan mutatott szintje'; +$lang['gdlib'] = 'GD Lib verzió'; +$lang['im_convert'] = 'Útvonal az ImageMagick csomag convert parancsához'; +$lang['jpg_quality'] = 'JPG tömörítés minősége (0-100)'; +$lang['fetchsize'] = 'Maximális méret (bájtban), amit a fetch.php letölthet kívülről'; +$lang['subscribers'] = 'Oldalváltozás-listára feliratkozás engedélyezése'; +$lang['subscribe_time'] = 'Az értesítések kiküldésének késleltetése (másodperc); Érdemes kisebbet választani, mint a változások megőrzésének maximális ideje.'; +$lang['notify'] = 'Az oldal-változásokat erre az e-mail címre küldje'; +$lang['registernotify'] = 'Értesítés egy újonnan regisztrált felhasználóról erre az e-mail címre'; +$lang['mailfrom'] = 'Az automatikusan küldött levelekben használt e-mail cím'; +$lang['mailprefix'] = 'Előtag az automatikus e-mailek tárgyában'; +$lang['htmlmail'] = 'Szebb, de nagyobb méretű HTML multipart e-mailek küldése. Tiltsd le a nyers szöveges üzenetekhez!'; +$lang['sitemap'] = 'Hány naponként generáljunk Google sitemap-ot?'; +$lang['rss_type'] = 'XML hírfolyam típus'; +$lang['rss_linkto'] = 'XML hírfolyam hivatkozás'; +$lang['rss_content'] = 'Mit mutassunk az XML hírfolyam elemekben?'; +$lang['rss_update'] = 'Hány másodpercenként frissítsük az XML hírfolyamot?'; +$lang['rss_show_summary'] = 'A hírfolyam címébe összefoglaló helyezése'; +$lang['rss_media'] = 'Milyen változások legyenek felsorolva az XML hírfolyamban?'; $lang['updatecheck'] = 'Frissítések és biztonsági figyelmeztetések figyelése. Ehhez a DokuWikinek kapcsolatba kell lépnie a update.dokuwiki.org-gal.'; $lang['userewrite'] = 'Szép URL-ek használata'; $lang['useslash'] = 'Per-jel használata névtér-elválasztóként az URL-ekben'; -$lang['usedraft'] = 'Piszkozat automatikus mentése szerkesztés alatt'; $lang['sepchar'] = 'Szó elválasztó az oldalnevekben'; $lang['canonical'] = 'Teljesen kanonikus URL-ek használata'; $lang['fnencode'] = 'A nem ASCII fájlnevek dekódolási módja'; $lang['autoplural'] = 'Többes szám ellenőrzés a hivatkozásokban (angol)'; $lang['compression'] = 'Tömörítés használata a törölt lapokhoz'; -$lang['cachetime'] = 'A gyorsítótár maximális élettartama (másodperc)'; -$lang['locktime'] = 'Oldal-zárolás maximális időtartama (másodperc)'; -$lang['fetchsize'] = 'Maximális méret (bájtban), amit a fetch.php letölthet kívülről'; -$lang['notify'] = 'Az oldal-változásokat erre az e-mail címre küldje'; -$lang['registernotify'] = 'Értesítés egy újonnan regisztrált felhasználóról erre az e-mail címre'; -$lang['mailfrom'] = 'Az automatikusan küldött levelekben használt e-mail cím'; -$lang['mailprefix'] = 'Előtag az automatikus e-mailek tárgyában'; $lang['gzip_output'] = 'gzip tömörítés használata xhtml-hez (Content-Encoding)'; -$lang['gdlib'] = 'GD Lib verzió'; -$lang['im_convert'] = 'Útvonal az ImageMagick csomag convert parancsához'; -$lang['jpg_quality'] = 'JPG tömörítés minősége (0-100)'; -$lang['subscribers'] = 'Oldalváltozás-listára feliratkozás engedélyezése'; -$lang['subscribe_time'] = 'Az értesítések kiküldésének késleltetése (másodperc); Érdemes kisebbet választani, mint a változások megőrzésének maximális ideje.'; $lang['compress'] = 'CSS és JavaScript fájlok tömörítése'; -$lang['hidepages'] = 'Az itt megadott oldalak elrejtése (reguláris kifejezés)'; +$lang['cssdatauri'] = 'Mérethatár bájtokban, ami alatti CSS-ben hivatkozott fájlok közvetlenül beágyazódjanak a stíluslapba. Ez IE 7-ben és alatta nem fog működni! 400-600 bájt ideális érték. Állítsd 0-ra a beágyazás kikapcsolásához!'; $lang['send404'] = '"HTTP 404/Page Not Found" küldése nemlétező oldalak esetén'; -$lang['sitemap'] = 'Hány naponként generáljunk Google sitemap-ot?'; $lang['broken_iua'] = 'Az ignore_user_abort függvény hibát dob a rendszereden? Ez nem működő keresési indexet eredményezhet. Az IIS+PHP/CGI összeállításról tudjuk, hogy hibát dob. Lásd a Bug 852 oldalt a további infóért.'; $lang['xsendfile'] = 'Használjuk az X-Sendfile fejlécet, hogy a webszerver statikus állományokat tudjon küldeni? A webszervernek is támogatnia kell ezt a funkciót.'; $lang['renderer_xhtml'] = 'Az elsődleges (xhtml) wiki kimenet generálója'; $lang['renderer__core'] = '%s (dokuwiki mag)'; $lang['renderer__plugin'] = '%s (bővítmény)'; -$lang['rememberme'] = 'Állandó sütik engedélyezése (az "emlékezz rám" funkcióhoz)'; -$lang['rss_type'] = 'XML hírfolyam típus'; -$lang['rss_linkto'] = 'XML hírfolyam hivatkozás'; -$lang['rss_content'] = 'Mit mutassunk az XML hírfolyam elemekben?'; -$lang['rss_update'] = 'Hány másodpercenként frissítsük az XML hírfolyamot?'; -$lang['recent_days'] = 'Hány napig tartsuk meg a korábbi változatokat?'; -$lang['rss_show_summary'] = 'A hírfolyam címébe összefoglaló helyezése'; -$lang['target____wiki'] = 'Cél-ablak belső hivatkozásokhoz'; -$lang['target____interwiki'] = 'Cél-ablak interwiki hivatkozásokhoz'; -$lang['target____extern'] = 'Cél-ablak külső hivatkozásokhoz'; -$lang['target____media'] = 'Cél-ablak média-fájl hivatkozásokhoz'; -$lang['target____windows'] = 'Cél-ablak Windows hivatkozásokhoz'; -$lang['proxy____host'] = 'Proxy szerver neve'; +$lang['dnslookups'] = 'A DokuWiki megpróbál hosztneveket keresni a távoli IP-címekhez. Amennyiben lassú, vagy nem működő DNS-szervered van vagy csak nem szeretnéd ezt a funkciót, tiltsd le ezt az opciót!'; +$lang['proxy____host'] = 'Proxy-szerver neve'; $lang['proxy____port'] = 'Proxy port'; $lang['proxy____user'] = 'Proxy felhasználó név'; $lang['proxy____pass'] = 'Proxy jelszó'; @@ -174,7 +187,7 @@ $lang['compression_o_0'] = 'nincs tömörítés'; $lang['compression_o_gz'] = 'gzip'; $lang['compression_o_bz2'] = 'bz2'; $lang['xsendfile_o_0'] = 'nincs használatban'; -$lang['xsendfile_o_1'] = 'lighttpd saját fejléc (1.5-ös verzió előtti)'; +$lang['xsendfile_o_1'] = 'Lighttpd saját fejléc (1.5-ös verzió előtti)'; $lang['xsendfile_o_2'] = 'Standard X-Sendfile fejléc'; $lang['xsendfile_o_3'] = 'Nginx saját X-Accel-Redirect fejléce'; $lang['showuseras_o_loginname'] = 'Azonosító'; diff --git a/lib/plugins/plugin/lang/hu/lang.php b/lib/plugins/plugin/lang/hu/lang.php index 34309a53f..235d33a0e 100644 --- a/lib/plugins/plugin/lang/hu/lang.php +++ b/lib/plugins/plugin/lang/hu/lang.php @@ -8,6 +8,7 @@ * @author Szabó Dávid * @author Sándor TIHANYI * @author David Szabo + * @author Marton Sebok */ $lang['menu'] = 'Bővítménykezelő'; $lang['download'] = 'Új bővítmény letöltése és telepítése'; @@ -18,24 +19,24 @@ $lang['btn_delete'] = 'törlés'; $lang['btn_settings'] = 'beállítások'; $lang['btn_download'] = 'Letöltés'; $lang['btn_enable'] = 'Mentés'; -$lang['url'] = 'URL:'; +$lang['url'] = 'Cím'; $lang['installed'] = 'Telepítve:'; $lang['lastupdate'] = 'Utolsó frissítés:'; $lang['source'] = 'Forrás:'; $lang['unknown'] = 'ismeretlen'; $lang['updating'] = 'Frissítés...'; -$lang['updated'] = 'A %s bővítmény sikeresen frissült.'; -$lang['updates'] = 'A következő bővítmények sikeresen frissültek:'; +$lang['updated'] = 'A %s bővítmény frissítése sikeres'; +$lang['updates'] = 'A következő bővítmények frissítése sikeres:'; $lang['update_none'] = 'Nem találtam újabb verziót.'; $lang['deleting'] = 'Törlés...'; -$lang['deleted'] = 'A %s bővítményt eltávolítottam.'; +$lang['deleted'] = 'A %s bővítményt eltávolítva.'; $lang['downloading'] = 'Letöltés...'; -$lang['downloaded'] = 'A %s bővítmény sikeresen feltelepült.'; -$lang['downloads'] = 'A következő bővítmények sikeresen feltelepültek:'; -$lang['download_none'] = 'Nem találtam bővítményt, vagy ismeretlen hiba történt a letöltés/telepítés közben.'; +$lang['downloaded'] = 'A %s bővítmény telepítése sikeres.'; +$lang['downloads'] = 'A következő bővítmények telepítése sikeres.'; +$lang['download_none'] = 'Nem találtam bővítményt vagy ismeretlen hiba történt a letöltés/telepítés közben.'; $lang['plugin'] = 'Bővítmény:'; $lang['components'] = 'Részek'; -$lang['noinfo'] = 'Ez a bővítmény nem tartalmaz infót, lehet, hogy hibás.'; +$lang['noinfo'] = 'Ez a bővítmény nem tartalmaz információt, lehet, hogy hibás.'; $lang['name'] = 'Név:'; $lang['date'] = 'Dátum:'; $lang['type'] = 'Típus:'; @@ -43,14 +44,14 @@ $lang['desc'] = 'Leírás:'; $lang['author'] = 'Szerző:'; $lang['www'] = 'Web:'; $lang['error'] = 'Ismeretlen hiba lépett fel.'; -$lang['error_download'] = 'Nem tudom letölteni a bővítmény fájlt: %s'; +$lang['error_download'] = 'Nem tudom letölteni a fájlt a bővítményhez: %s'; $lang['error_badurl'] = 'Feltehetően rossz URL - nem tudom meghatározni a fájlnevet az URL-ből.'; $lang['error_dircreate'] = 'Nem tudom létrehozni az átmeneti könyvtárat a letöltéshez.'; $lang['error_decompress'] = 'A Bővítménykezelő nem tudta a letöltött állományt kicsomagolni. Ennek oka lehet hibás letöltés, ebben az esetben újra letöltéssel próbálkozhatsz, esetleg a tömörítés módja ismeretlen, ebben az esetben kézzel kell letölteni és telepíteni a bővítményt.'; -$lang['error_copy'] = 'Fájl másolási hiba történt a(z) %s bővítmény telepítése közben: vagy a lemezterület fogyott el, vagy az állomány hozzáférési jogosultságok nem megfelelőek. Emiatt előfordulhat, hogy a bővítményt csak részben sikerült telepíteni, és a wiki összeomolhat.'; -$lang['error_delete'] = 'Hiba történt a(z) %s bővítmény eltávolítása közben. A legvalószínűbb ok, hogy a könyvtár vagy állomány hozzáférési jogosultságok nem megfelelőek.'; +$lang['error_copy'] = 'Fájl másolási hiba történt a(z) %s bővítmény telepítése közben: vagy a lemezterület fogyott el, vagy az állomány hozzáférési jogosultságai nem megfelelőek. Emiatt előfordulhat, hogy a bővítményt csak részben sikerült telepíteni és a wiki összeomolhat.'; +$lang['error_delete'] = 'Hiba történt a(z) %s bővítmény eltávolítása közben. A legvalószínűbb ok, hogy a könyvtár vagy állomány hozzáférési jogosultságai nem megfelelőek.'; $lang['enabled'] = 'A(z) %s bővítmény bekapcsolva.'; -$lang['notenabled'] = 'A(z) %s bővítmény engedélyezése nem sikerült. Ellenőrizze a fájl-hozzáférési engedélyeket.'; +$lang['notenabled'] = 'A(z) %s bővítmény engedélyezése nem sikerült. Ellenőrizze a fájlhozzáférési jogosultságokat.'; $lang['disabled'] = 'A(z) %s bővítmény kikapcsolva.'; -$lang['notdisabled'] = 'A(z) %s bővítmény kikapcsolása nem sikerült. Ellenőrizze a fájl-hozzáférési engedélyeket.'; -$lang['packageinstalled'] = 'A bővítmény csomag(ok) feltelepült(ek): %d plugin(s): %s'; +$lang['notdisabled'] = 'A(z) %s bővítmény kikapcsolása nem sikerült. Ellenőrizze a fájlhozzáférési jogosultságokat.'; +$lang['packageinstalled'] = 'A bővítménycsomag(ok) feltelepült(ek): %d plugin(s): %s'; diff --git a/lib/plugins/popularity/lang/hu/lang.php b/lib/plugins/popularity/lang/hu/lang.php index 5dcd1adf0..5ee40eacc 100644 --- a/lib/plugins/popularity/lang/hu/lang.php +++ b/lib/plugins/popularity/lang/hu/lang.php @@ -8,6 +8,7 @@ * @author Szabó Dávid * @author Sándor TIHANYI * @author David Szabo + * @author Marton Sebok */ $lang['name'] = 'Visszajelzés a DokuWiki használatáról (sok időt vehet igénybe a betöltése)'; $lang['submit'] = 'Adatok elküldése'; diff --git a/lib/plugins/revert/lang/hu/lang.php b/lib/plugins/revert/lang/hu/lang.php index 058a63196..051e7b7d7 100644 --- a/lib/plugins/revert/lang/hu/lang.php +++ b/lib/plugins/revert/lang/hu/lang.php @@ -8,6 +8,7 @@ * @author Szabó Dávid * @author Sándor TIHANYI * @author David Szabo + * @author Marton Sebok */ $lang['menu'] = 'Visszaállítás kezelő (anti-SPAM)'; $lang['filter'] = 'SPAM tartalmú oldalak keresése'; @@ -16,5 +17,5 @@ $lang['reverted'] = '%s a következő változatra lett visszaállí $lang['removed'] = '%s törölve'; $lang['revstart'] = 'A visszaállítási folyamat elindult. Ez hosszú ideig eltarthat. Ha időtúllépés miatt nem tud lefutni, kisebb darabbal kell próbálkozni.'; $lang['revstop'] = 'A visszaállítási folyamat sikeresen befejeződött.'; -$lang['note1'] = 'Megjegyzés: a keresés kisbetű-nagybetűre érzékeny'; +$lang['note1'] = 'Megjegyzés: a keresés kisbetű-nagybetű érzékeny'; $lang['note2'] = 'Megjegyzés: Az oldalt az utolsó olyan változatra állítjuk vissza, ami nem tartalmazza a megadott spam kifejezést: %s.'; diff --git a/lib/plugins/usermanager/lang/hu/lang.php b/lib/plugins/usermanager/lang/hu/lang.php index 9b9740cb0..71a5b4bc9 100644 --- a/lib/plugins/usermanager/lang/hu/lang.php +++ b/lib/plugins/usermanager/lang/hu/lang.php @@ -8,12 +8,13 @@ * @author Szabó Dávid * @author Sándor TIHANYI * @author David Szabo + * @author Marton Sebok */ $lang['menu'] = 'Felhasználók kezelése'; $lang['noauth'] = '(A felhasználói azonosítás nem működik.)'; $lang['nosupport'] = '(A felhasználók kezelése nem támogatott.)'; $lang['badauth'] = 'nem érvényes autentikációs technika'; -$lang['user_id'] = 'Felhasználó azonosító'; +$lang['user_id'] = 'Felhasználói azonosító'; $lang['user_pass'] = 'Jelszó'; $lang['user_name'] = 'Név'; $lang['user_mail'] = 'E-mail'; @@ -30,8 +31,8 @@ $lang['search'] = 'Keresés'; $lang['search_prompt'] = 'Keresés'; $lang['clear'] = 'Keresési szűrés törlése'; $lang['filter'] = 'Szűrés'; -$lang['summary'] = '%1$d-%2$d. felhasználókat mutatom a(z) %3$d megtalált felhasználóból. %4$d felhasználó van összesen.'; -$lang['nonefound'] = 'Nem találtam ilyen felhasználót. %d felhasználó van összesen.'; +$lang['summary'] = '%1$d-%2$d. felhasználók megjelenítése a(z) %3$d megtalált felhasználóból. %4$d felhasználó van összesen.'; +$lang['nonefound'] = 'Nincs ilyen felhasználó. %d felhasználó van összesen.'; $lang['delete_ok'] = '%d felhasználó törölve.'; $lang['delete_fail'] = '%d felhasználót nem sikerült törölni.'; $lang['update_ok'] = 'A felhasználó adatait sikeresen elmentettem.'; @@ -45,7 +46,7 @@ $lang['edit_usermissing'] = 'A kiválasztott felhasználót nem találom, a $lang['user_notify'] = 'Felhasználó értesítése'; $lang['note_notify'] = 'Csak akkor küld értesítő e-mailt, ha a felhasználó új jelszót kapott.'; $lang['note_group'] = 'Ha nincs csoport meghatározva, az új felhasználó az alapértelmezett csoportba (%s) kerül.'; -$lang['note_pass'] = 'Ha a baloldali mező üres, és a felhasználó értesítés aktív, akkor generált jelszó lesz.'; +$lang['note_pass'] = 'Ha a baloldali mező üres és a felhasználó értesítés aktív, akkor a jelszót a rendszer generálja.'; $lang['add_ok'] = 'A felhasználó sikeresen hozzáadva.'; $lang['add_fail'] = 'A felhasználó hozzáadása nem sikerült.'; $lang['notify_ok'] = 'Értesítő levél elküldve.'; -- cgit v1.2.3 From 9b136f13f2219fd6d292ab3064122bec0ec33d0d Mon Sep 17 00:00:00 2001 From: Anika Henke Date: Sun, 28 Jul 2013 13:48:36 +0100 Subject: fixed typo in commented section indenting css --- lib/tpl/dokuwiki/css/content.css | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/lib/tpl/dokuwiki/css/content.css b/lib/tpl/dokuwiki/css/content.css index 119859e38..b1498d4de 100644 --- a/lib/tpl/dokuwiki/css/content.css +++ b/lib/tpl/dokuwiki/css/content.css @@ -8,16 +8,16 @@ /*____________ section indenting ____________ -.dokuwiki.page h1 {margin-left: 0;} -.dokuwiki.page h2 {margin-left: .666em;} -.dokuwiki.page h3 {margin-left: 1.776em;} -.dokuwiki.page h4 {margin-left: 3em;} -.dokuwiki.page h5 {margin-left: 4.5712em;} -.dokuwiki.page div.level1 {margin-left: 0;} -.dokuwiki.page div.level2 {margin-left: 1em;} -.dokuwiki.page div.level3 {margin-left: 2em;} -.dokuwiki.page div.level4 {margin-left: 3em;} -.dokuwiki.page div.level5 {margin-left: 4em;} +.dokuwiki .page h1 {margin-left: 0;} +.dokuwiki .page h2 {margin-left: .666em;} +.dokuwiki .page h3 {margin-left: 1.776em;} +.dokuwiki .page h4 {margin-left: 3em;} +.dokuwiki .page h5 {margin-left: 4.5712em;} +.dokuwiki .page div.level1 {margin-left: 0;} +.dokuwiki .page div.level2 {margin-left: 1em;} +.dokuwiki .page div.level3 {margin-left: 2em;} +.dokuwiki .page div.level4 {margin-left: 3em;} +.dokuwiki .page div.level5 {margin-left: 4em;} [dir=rtl] .dokuwiki .page h1 {margin-left: 0; margin-right: 0;} [dir=rtl] .dokuwiki .page h2 {margin-left: 0; margin-right: .666em;} -- cgit v1.2.3 From 7d8a6abbb21979fd77dca10275ebb8e01a04b6e4 Mon Sep 17 00:00:00 2001 From: Michael Hamann Date: Mon, 29 Jul 2013 16:33:44 +0200 Subject: Fix popularity data submission in the backend FS#2808 The POST data contained the raw data instead of an array with the data that should be submitted like in the requests from the browser. The server backend has been fixed to be able to process both versions. --- lib/plugins/popularity/helper.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/plugins/popularity/helper.php b/lib/plugins/popularity/helper.php index 5bbeddba0..0e38bcb88 100644 --- a/lib/plugins/popularity/helper.php +++ b/lib/plugins/popularity/helper.php @@ -85,7 +85,7 @@ class helper_plugin_popularity extends Dokuwiki_Plugin { function sendData($data){ $error = ''; $httpClient = new DokuHTTPClient(); - $status = $httpClient->sendRequest($this->submitUrl, $data, 'POST'); + $status = $httpClient->sendRequest($this->submitUrl, array('data' => $data), 'POST'); if ( ! $status ){ $error = $httpClient->error; } -- cgit v1.2.3 From d4a1ece8f011dd69db05b83d2f98e3207f1a7e48 Mon Sep 17 00:00:00 2001 From: Andreas Gohr Date: Mon, 29 Jul 2013 20:06:01 +0200 Subject: add LESS support still needs testing --- inc/load.php | 1 + lib/exe/css.php | 19 ++++++++++++++++++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/inc/load.php b/inc/load.php index 5ca9b4cd8..258713e88 100644 --- a/inc/load.php +++ b/inc/load.php @@ -82,6 +82,7 @@ function load_autoload($name){ 'RemoteAPI' => DOKU_INC.'inc/remote.php', 'RemoteAPICore' => DOKU_INC.'inc/RemoteAPICore.php', 'Subscription' => DOKU_INC.'inc/subscription.php', + 'lessc' => DOKU_INC.'inc/lessc.inc.php', 'DokuWiki_Action_Plugin' => DOKU_PLUGIN.'action.php', 'DokuWiki_Admin_Plugin' => DOKU_PLUGIN.'admin.php', diff --git a/lib/exe/css.php b/lib/exe/css.php index 1e662c64a..4a9c825c1 100644 --- a/lib/exe/css.php +++ b/lib/exe/css.php @@ -154,7 +154,11 @@ function css_out(){ // apply style replacements $css = css_applystyle($css,$tplinc); - // place all @import statements at the top of the file + // parse LESS + $less = new lessc(); + $css = $less->compile($css); + + // place all remaining @import statements at the top of the file $css = css_moveimports($css); // compress whitespace and comments @@ -175,6 +179,9 @@ function css_out(){ * Does placeholder replacements in the style according to * the ones defined in a templates style.ini file * + * This also adds the ini defined placeholders as less variables + * (sans the surrounding __ and with a ini_ prefix) + * * @author Andreas Gohr */ function css_applystyle($css,$tplinc){ @@ -182,6 +189,13 @@ function css_applystyle($css,$tplinc){ if($styleini){ $css = strtr($css,$styleini['replacements']); + + $less = ''; + foreach($styleini as $key => $value){ + $key = trim($key, '_'); + $key = '@ini_'.$key; + $less .= "$key: $value\n"; + } } return $css; } @@ -333,14 +347,17 @@ function css_pluginstyles($mediatype='screen'){ $plugins = plugin_list(); foreach ($plugins as $p){ $list[DOKU_PLUGIN."$p/$mediatype.css"] = DOKU_BASE."lib/plugins/$p/"; + $list[DOKU_PLUGIN."$p/$mediatype.less"] = DOKU_BASE."lib/plugins/$p/"; // alternative for screen.css if ($mediatype=='screen') { $list[DOKU_PLUGIN."$p/style.css"] = DOKU_BASE."lib/plugins/$p/"; + $list[DOKU_PLUGIN."$p/style.less"] = DOKU_BASE."lib/plugins/$p/"; } // @deprecated 2012-04-09: rtl will cease to be a mode of its own, // please use "[dir=rtl]" in any css file in all, screen or print mode instead if($lang['direction'] == 'rtl'){ $list[DOKU_PLUGIN."$p/rtl.css"] = DOKU_BASE."lib/plugins/$p/"; + $list[DOKU_PLUGIN."$p/rtl.less"] = DOKU_BASE."lib/plugins/$p/"; } } return $list; -- cgit v1.2.3 From d90a68f39f7f78f2ce0b475700f22750ae3f0b14 Mon Sep 17 00:00:00 2001 From: Mohamed Amine BERGAOUI Date: Tue, 30 Jul 2013 10:13:14 +0200 Subject: adding ACL handlers to xmlrpc --- inc/RemoteAPICore.php | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/inc/RemoteAPICore.php b/inc/RemoteAPICore.php index 4c940b39e..022dc37ed 100644 --- a/inc/RemoteAPICore.php +++ b/inc/RemoteAPICore.php @@ -149,8 +149,17 @@ class RemoteAPICore { 'return' => 'int', 'doc' => 'Returns 2 with the supported RPC API version.', 'public' => '1' - ), - + ), 'dokuwiki.addAcl' => array( + 'args' => array('string','string','int'), + 'return' => 'int', + 'name' => 'addAcl', + 'doc' => 'Adds a new ACL rule.' + ), 'dokuwiki.delAcl' => array( + 'args' => array('string','string'), + 'return' => 'int', + 'name' => 'delAcl', + 'doc' => 'Delete an existing ACL rule.' + ), ); } @@ -767,6 +776,17 @@ class RemoteAPICore { return $ok; } + + + function addAcl($scope, $user, $level){ + $apa = new admin_plugin_acl(); + return $apa->_acl_add($scope, $user, $level); + } + + function delAcl($scope, $user){ + $apa = new admin_plugin_acl(); + return $apa->_acl_del($scope, $user); + } private function resolvePageId($id) { $id = cleanID($id); @@ -779,3 +799,4 @@ class RemoteAPICore { } + -- cgit v1.2.3 From 5f0edceddab88f91bec7fecf5efa606bbe273fb2 Mon Sep 17 00:00:00 2001 From: Andreas Gohr Date: Tue, 30 Jul 2013 10:15:57 +0200 Subject: added test case for FS#1442 --- _test/tests/inc/tar.test.php | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/_test/tests/inc/tar.test.php b/_test/tests/inc/tar.test.php index 90bc2e49e..28e709cc3 100644 --- a/_test/tests/inc/tar.test.php +++ b/_test/tests/inc/tar.test.php @@ -248,6 +248,28 @@ class Tar_TestCase extends DokuWikiTest { } } + // FS#1442 + public function test_createlongfile() { + $tar = new Tar(); + $tmp = tempnam(sys_get_temp_dir(), 'dwtartest'); + + $path = '0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789.txt'; + + $tar->create($tmp, Tar::COMPRESS_NONE); + $tar->addData($path, 'testcontent1'); + $tar->close(); + + $this->assertTrue(filesize($tmp) > 30); //arbitrary non-zero number + $data = file_get_contents($tmp); + + // We should find the complete path and a longlink entry + $this->assertTrue(strpos($data, 'testcontent1') !== false, 'content in TAR'); + $this->assertTrue(strpos($data, $path) !== false, 'path in TAR'); + $this->assertTrue(strpos($data, '@LongLink') !== false, '@LongLink in TAR'); + + @unlink($tmp); + } + public function test_createlongpathustar() { $tar = new Tar(); $tmp = tempnam(sys_get_temp_dir(), 'dwtartest'); @@ -360,4 +382,4 @@ class Tar_TestCase extends DokuWikiTest { $this->assertEquals(512*4, strlen($file)); // 1 header block + data block + 2 footer blocks } -} \ No newline at end of file +} -- cgit v1.2.3 From 559615acce5ffe51bd54e87dc1ab02dd5769b0ff Mon Sep 17 00:00:00 2001 From: Andreas Gohr Date: Tue, 30 Jul 2013 10:38:06 +0200 Subject: added missing lessc library --- inc/lessc.inc.php | 3481 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 3481 insertions(+) create mode 100644 inc/lessc.inc.php diff --git a/inc/lessc.inc.php b/inc/lessc.inc.php new file mode 100644 index 000000000..5c81ad2a9 --- /dev/null +++ b/inc/lessc.inc.php @@ -0,0 +1,3481 @@ + + * Licensed under MIT or GPLv3, see LICENSE + */ + + +/** + * The less compiler and parser. + * + * Converting LESS to CSS is a three stage process. The incoming file is parsed + * by `lessc_parser` into a syntax tree, then it is compiled into another tree + * representing the CSS structure by `lessc`. The CSS tree is fed into a + * formatter, like `lessc_formatter` which then outputs CSS as a string. + * + * During the first compile, all values are *reduced*, which means that their + * types are brought to the lowest form before being dump as strings. This + * handles math equations, variable dereferences, and the like. + * + * The `parse` function of `lessc` is the entry point. + * + * In summary: + * + * The `lessc` class creates an intstance of the parser, feeds it LESS code, + * then transforms the resulting tree to a CSS tree. This class also holds the + * evaluation context, such as all available mixins and variables at any given + * time. + * + * The `lessc_parser` class is only concerned with parsing its input. + * + * The `lessc_formatter` takes a CSS tree, and dumps it to a formatted string, + * handling things like indentation. + */ +class lessc { + static public $VERSION = "v0.3.9"; + static protected $TRUE = array("keyword", "true"); + static protected $FALSE = array("keyword", "false"); + + protected $libFunctions = array(); + protected $registeredVars = array(); + protected $preserveComments = false; + + public $vPrefix = '@'; // prefix of abstract properties + public $mPrefix = '$'; // prefix of abstract blocks + public $parentSelector = '&'; + + public $importDisabled = false; + public $importDir = ''; + + protected $numberPrecision = null; + + // set to the parser that generated the current line when compiling + // so we know how to create error messages + protected $sourceParser = null; + protected $sourceLoc = null; + + static public $defaultValue = array("keyword", ""); + + static protected $nextImportId = 0; // uniquely identify imports + + // attempts to find the path of an import url, returns null for css files + protected function findImport($url) { + foreach ((array)$this->importDir as $dir) { + $full = $dir.(substr($dir, -1) != '/' ? '/' : '').$url; + if ($this->fileExists($file = $full.'.less') || $this->fileExists($file = $full)) { + return $file; + } + } + + return null; + } + + protected function fileExists($name) { + return is_file($name); + } + + static public function compressList($items, $delim) { + if (!isset($items[1]) && isset($items[0])) return $items[0]; + else return array('list', $delim, $items); + } + + static public function preg_quote($what) { + return preg_quote($what, '/'); + } + + protected function tryImport($importPath, $parentBlock, $out) { + if ($importPath[0] == "function" && $importPath[1] == "url") { + $importPath = $this->flattenList($importPath[2]); + } + + $str = $this->coerceString($importPath); + if ($str === null) return false; + + $url = $this->compileValue($this->lib_e($str)); + + // don't import if it ends in css + if (substr_compare($url, '.css', -4, 4) === 0) return false; + + $realPath = $this->findImport($url); + if ($realPath === null) return false; + + if ($this->importDisabled) { + return array(false, "/* import disabled */"); + } + + $this->addParsedFile($realPath); + $parser = $this->makeParser($realPath); + $root = $parser->parse(file_get_contents($realPath)); + + // set the parents of all the block props + foreach ($root->props as $prop) { + if ($prop[0] == "block") { + $prop[1]->parent = $parentBlock; + } + } + + // copy mixins into scope, set their parents + // bring blocks from import into current block + // TODO: need to mark the source parser these came from this file + foreach ($root->children as $childName => $child) { + if (isset($parentBlock->children[$childName])) { + $parentBlock->children[$childName] = array_merge( + $parentBlock->children[$childName], + $child); + } else { + $parentBlock->children[$childName] = $child; + } + } + + $pi = pathinfo($realPath); + $dir = $pi["dirname"]; + + list($top, $bottom) = $this->sortProps($root->props, true); + $this->compileImportedProps($top, $parentBlock, $out, $parser, $dir); + + return array(true, $bottom, $parser, $dir); + } + + protected function compileImportedProps($props, $block, $out, $sourceParser, $importDir) { + $oldSourceParser = $this->sourceParser; + + $oldImport = $this->importDir; + + // TODO: this is because the importDir api is stupid + $this->importDir = (array)$this->importDir; + array_unshift($this->importDir, $importDir); + + foreach ($props as $prop) { + $this->compileProp($prop, $block, $out); + } + + $this->importDir = $oldImport; + $this->sourceParser = $oldSourceParser; + } + + /** + * Recursively compiles a block. + * + * A block is analogous to a CSS block in most cases. A single LESS document + * is encapsulated in a block when parsed, but it does not have parent tags + * so all of it's children appear on the root level when compiled. + * + * Blocks are made up of props and children. + * + * Props are property instructions, array tuples which describe an action + * to be taken, eg. write a property, set a variable, mixin a block. + * + * The children of a block are just all the blocks that are defined within. + * This is used to look up mixins when performing a mixin. + * + * Compiling the block involves pushing a fresh environment on the stack, + * and iterating through the props, compiling each one. + * + * See lessc::compileProp() + * + */ + protected function compileBlock($block) { + switch ($block->type) { + case "root": + $this->compileRoot($block); + break; + case null: + $this->compileCSSBlock($block); + break; + case "media": + $this->compileMedia($block); + break; + case "directive": + $name = "@" . $block->name; + if (!empty($block->value)) { + $name .= " " . $this->compileValue($this->reduce($block->value)); + } + + $this->compileNestedBlock($block, array($name)); + break; + default: + $this->throwError("unknown block type: $block->type\n"); + } + } + + protected function compileCSSBlock($block) { + $env = $this->pushEnv(); + + $selectors = $this->compileSelectors($block->tags); + $env->selectors = $this->multiplySelectors($selectors); + $out = $this->makeOutputBlock(null, $env->selectors); + + $this->scope->children[] = $out; + $this->compileProps($block, $out); + + $block->scope = $env; // mixins carry scope with them! + $this->popEnv(); + } + + protected function compileMedia($media) { + $env = $this->pushEnv($media); + $parentScope = $this->mediaParent($this->scope); + + $query = $this->compileMediaQuery($this->multiplyMedia($env)); + + $this->scope = $this->makeOutputBlock($media->type, array($query)); + $parentScope->children[] = $this->scope; + + $this->compileProps($media, $this->scope); + + if (count($this->scope->lines) > 0) { + $orphanSelelectors = $this->findClosestSelectors(); + if (!is_null($orphanSelelectors)) { + $orphan = $this->makeOutputBlock(null, $orphanSelelectors); + $orphan->lines = $this->scope->lines; + array_unshift($this->scope->children, $orphan); + $this->scope->lines = array(); + } + } + + $this->scope = $this->scope->parent; + $this->popEnv(); + } + + protected function mediaParent($scope) { + while (!empty($scope->parent)) { + if (!empty($scope->type) && $scope->type != "media") { + break; + } + $scope = $scope->parent; + } + + return $scope; + } + + protected function compileNestedBlock($block, $selectors) { + $this->pushEnv($block); + $this->scope = $this->makeOutputBlock($block->type, $selectors); + $this->scope->parent->children[] = $this->scope; + + $this->compileProps($block, $this->scope); + + $this->scope = $this->scope->parent; + $this->popEnv(); + } + + protected function compileRoot($root) { + $this->pushEnv(); + $this->scope = $this->makeOutputBlock($root->type); + $this->compileProps($root, $this->scope); + $this->popEnv(); + } + + protected function compileProps($block, $out) { + foreach ($this->sortProps($block->props) as $prop) { + $this->compileProp($prop, $block, $out); + } + } + + protected function sortProps($props, $split = false) { + $vars = array(); + $imports = array(); + $other = array(); + + foreach ($props as $prop) { + switch ($prop[0]) { + case "assign": + if (isset($prop[1][0]) && $prop[1][0] == $this->vPrefix) { + $vars[] = $prop; + } else { + $other[] = $prop; + } + break; + case "import": + $id = self::$nextImportId++; + $prop[] = $id; + $imports[] = $prop; + $other[] = array("import_mixin", $id); + break; + default: + $other[] = $prop; + } + } + + if ($split) { + return array(array_merge($vars, $imports), $other); + } else { + return array_merge($vars, $imports, $other); + } + } + + protected function compileMediaQuery($queries) { + $compiledQueries = array(); + foreach ($queries as $query) { + $parts = array(); + foreach ($query as $q) { + switch ($q[0]) { + case "mediaType": + $parts[] = implode(" ", array_slice($q, 1)); + break; + case "mediaExp": + if (isset($q[2])) { + $parts[] = "($q[1]: " . + $this->compileValue($this->reduce($q[2])) . ")"; + } else { + $parts[] = "($q[1])"; + } + break; + case "variable": + $parts[] = $this->compileValue($this->reduce($q)); + break; + } + } + + if (count($parts) > 0) { + $compiledQueries[] = implode(" and ", $parts); + } + } + + $out = "@media"; + if (!empty($parts)) { + $out .= " " . + implode($this->formatter->selectorSeparator, $compiledQueries); + } + return $out; + } + + protected function multiplyMedia($env, $childQueries = null) { + if (is_null($env) || + !empty($env->block->type) && $env->block->type != "media") + { + return $childQueries; + } + + // plain old block, skip + if (empty($env->block->type)) { + return $this->multiplyMedia($env->parent, $childQueries); + } + + $out = array(); + $queries = $env->block->queries; + if (is_null($childQueries)) { + $out = $queries; + } else { + foreach ($queries as $parent) { + foreach ($childQueries as $child) { + $out[] = array_merge($parent, $child); + } + } + } + + return $this->multiplyMedia($env->parent, $out); + } + + protected function expandParentSelectors(&$tag, $replace) { + $parts = explode("$&$", $tag); + $count = 0; + foreach ($parts as &$part) { + $part = str_replace($this->parentSelector, $replace, $part, $c); + $count += $c; + } + $tag = implode($this->parentSelector, $parts); + return $count; + } + + protected function findClosestSelectors() { + $env = $this->env; + $selectors = null; + while ($env !== null) { + if (isset($env->selectors)) { + $selectors = $env->selectors; + break; + } + $env = $env->parent; + } + + return $selectors; + } + + + // multiply $selectors against the nearest selectors in env + protected function multiplySelectors($selectors) { + // find parent selectors + + $parentSelectors = $this->findClosestSelectors(); + if (is_null($parentSelectors)) { + // kill parent reference in top level selector + foreach ($selectors as &$s) { + $this->expandParentSelectors($s, ""); + } + + return $selectors; + } + + $out = array(); + foreach ($parentSelectors as $parent) { + foreach ($selectors as $child) { + $count = $this->expandParentSelectors($child, $parent); + + // don't prepend the parent tag if & was used + if ($count > 0) { + $out[] = trim($child); + } else { + $out[] = trim($parent . ' ' . $child); + } + } + } + + return $out; + } + + // reduces selector expressions + protected function compileSelectors($selectors) { + $out = array(); + + foreach ($selectors as $s) { + if (is_array($s)) { + list(, $value) = $s; + $out[] = trim($this->compileValue($this->reduce($value))); + } else { + $out[] = $s; + } + } + + return $out; + } + + protected function eq($left, $right) { + return $left == $right; + } + + protected function patternMatch($block, $callingArgs) { + // match the guards if it has them + // any one of the groups must have all its guards pass for a match + if (!empty($block->guards)) { + $groupPassed = false; + foreach ($block->guards as $guardGroup) { + foreach ($guardGroup as $guard) { + $this->pushEnv(); + $this->zipSetArgs($block->args, $callingArgs); + + $negate = false; + if ($guard[0] == "negate") { + $guard = $guard[1]; + $negate = true; + } + + $passed = $this->reduce($guard) == self::$TRUE; + if ($negate) $passed = !$passed; + + $this->popEnv(); + + if ($passed) { + $groupPassed = true; + } else { + $groupPassed = false; + break; + } + } + + if ($groupPassed) break; + } + + if (!$groupPassed) { + return false; + } + } + + $numCalling = count($callingArgs); + + if (empty($block->args)) { + return $block->isVararg || $numCalling == 0; + } + + $i = -1; // no args + // try to match by arity or by argument literal + foreach ($block->args as $i => $arg) { + switch ($arg[0]) { + case "lit": + if (empty($callingArgs[$i]) || !$this->eq($arg[1], $callingArgs[$i])) { + return false; + } + break; + case "arg": + // no arg and no default value + if (!isset($callingArgs[$i]) && !isset($arg[2])) { + return false; + } + break; + case "rest": + $i--; // rest can be empty + break 2; + } + } + + if ($block->isVararg) { + return true; // not having enough is handled above + } else { + $numMatched = $i + 1; + // greater than becuase default values always match + return $numMatched >= $numCalling; + } + } + + protected function patternMatchAll($blocks, $callingArgs) { + $matches = null; + foreach ($blocks as $block) { + if ($this->patternMatch($block, $callingArgs)) { + $matches[] = $block; + } + } + + return $matches; + } + + // attempt to find blocks matched by path and args + protected function findBlocks($searchIn, $path, $args, $seen=array()) { + if ($searchIn == null) return null; + if (isset($seen[$searchIn->id])) return null; + $seen[$searchIn->id] = true; + + $name = $path[0]; + + if (isset($searchIn->children[$name])) { + $blocks = $searchIn->children[$name]; + if (count($path) == 1) { + $matches = $this->patternMatchAll($blocks, $args); + if (!empty($matches)) { + // This will return all blocks that match in the closest + // scope that has any matching block, like lessjs + return $matches; + } + } else { + $matches = array(); + foreach ($blocks as $subBlock) { + $subMatches = $this->findBlocks($subBlock, + array_slice($path, 1), $args, $seen); + + if (!is_null($subMatches)) { + foreach ($subMatches as $sm) { + $matches[] = $sm; + } + } + } + + return count($matches) > 0 ? $matches : null; + } + } + + if ($searchIn->parent === $searchIn) return null; + return $this->findBlocks($searchIn->parent, $path, $args, $seen); + } + + // sets all argument names in $args to either the default value + // or the one passed in through $values + protected function zipSetArgs($args, $values) { + $i = 0; + $assignedValues = array(); + foreach ($args as $a) { + if ($a[0] == "arg") { + if ($i < count($values) && !is_null($values[$i])) { + $value = $values[$i]; + } elseif (isset($a[2])) { + $value = $a[2]; + } else $value = null; + + $value = $this->reduce($value); + $this->set($a[1], $value); + $assignedValues[] = $value; + } + $i++; + } + + // check for a rest + $last = end($args); + if ($last[0] == "rest") { + $rest = array_slice($values, count($args) - 1); + $this->set($last[1], $this->reduce(array("list", " ", $rest))); + } + + $this->env->arguments = $assignedValues; + } + + // compile a prop and update $lines or $blocks appropriately + protected function compileProp($prop, $block, $out) { + // set error position context + $this->sourceLoc = isset($prop[-1]) ? $prop[-1] : -1; + + switch ($prop[0]) { + case 'assign': + list(, $name, $value) = $prop; + if ($name[0] == $this->vPrefix) { + $this->set($name, $value); + } else { + $out->lines[] = $this->formatter->property($name, + $this->compileValue($this->reduce($value))); + } + break; + case 'block': + list(, $child) = $prop; + $this->compileBlock($child); + break; + case 'mixin': + list(, $path, $args, $suffix) = $prop; + + $args = array_map(array($this, "reduce"), (array)$args); + $mixins = $this->findBlocks($block, $path, $args); + + if ($mixins === null) { + // fwrite(STDERR,"failed to find block: ".implode(" > ", $path)."\n"); + break; // throw error here?? + } + + foreach ($mixins as $mixin) { + if ($mixin === $block && !$args) { + continue; + } + + $haveScope = false; + if (isset($mixin->parent->scope)) { + $haveScope = true; + $mixinParentEnv = $this->pushEnv(); + $mixinParentEnv->storeParent = $mixin->parent->scope; + } + + $haveArgs = false; + if (isset($mixin->args)) { + $haveArgs = true; + $this->pushEnv(); + $this->zipSetArgs($mixin->args, $args); + } + + $oldParent = $mixin->parent; + if ($mixin != $block) $mixin->parent = $block; + + foreach ($this->sortProps($mixin->props) as $subProp) { + if ($suffix !== null && + $subProp[0] == "assign" && + is_string($subProp[1]) && + $subProp[1]{0} != $this->vPrefix) + { + $subProp[2] = array( + 'list', ' ', + array($subProp[2], array('keyword', $suffix)) + ); + } + + $this->compileProp($subProp, $mixin, $out); + } + + $mixin->parent = $oldParent; + + if ($haveArgs) $this->popEnv(); + if ($haveScope) $this->popEnv(); + } + + break; + case 'raw': + $out->lines[] = $prop[1]; + break; + case "directive": + list(, $name, $value) = $prop; + $out->lines[] = "@$name " . $this->compileValue($this->reduce($value)).';'; + break; + case "comment": + $out->lines[] = $prop[1]; + break; + case "import"; + list(, $importPath, $importId) = $prop; + $importPath = $this->reduce($importPath); + + if (!isset($this->env->imports)) { + $this->env->imports = array(); + } + + $result = $this->tryImport($importPath, $block, $out); + + $this->env->imports[$importId] = $result === false ? + array(false, "@import " . $this->compileValue($importPath).";") : + $result; + + break; + case "import_mixin": + list(,$importId) = $prop; + $import = $this->env->imports[$importId]; + if ($import[0] === false) { + $out->lines[] = $import[1]; + } else { + list(, $bottom, $parser, $importDir) = $import; + $this->compileImportedProps($bottom, $block, $out, $parser, $importDir); + } + + break; + default: + $this->throwError("unknown op: {$prop[0]}\n"); + } + } + + + /** + * Compiles a primitive value into a CSS property value. + * + * Values in lessphp are typed by being wrapped in arrays, their format is + * typically: + * + * array(type, contents [, additional_contents]*) + * + * The input is expected to be reduced. This function will not work on + * things like expressions and variables. + */ + protected function compileValue($value) { + switch ($value[0]) { + case 'list': + // [1] - delimiter + // [2] - array of values + return implode($value[1], array_map(array($this, 'compileValue'), $value[2])); + case 'raw_color': + if (!empty($this->formatter->compressColors)) { + return $this->compileValue($this->coerceColor($value)); + } + return $value[1]; + case 'keyword': + // [1] - the keyword + return $value[1]; + case 'number': + list(, $num, $unit) = $value; + // [1] - the number + // [2] - the unit + if ($this->numberPrecision !== null) { + $num = round($num, $this->numberPrecision); + } + return $num . $unit; + case 'string': + // [1] - contents of string (includes quotes) + list(, $delim, $content) = $value; + foreach ($content as &$part) { + if (is_array($part)) { + $part = $this->compileValue($part); + } + } + return $delim . implode($content) . $delim; + case 'color': + // [1] - red component (either number or a %) + // [2] - green component + // [3] - blue component + // [4] - optional alpha component + list(, $r, $g, $b) = $value; + $r = round($r); + $g = round($g); + $b = round($b); + + if (count($value) == 5 && $value[4] != 1) { // rgba + return 'rgba('.$r.','.$g.','.$b.','.$value[4].')'; + } + + $h = sprintf("#%02x%02x%02x", $r, $g, $b); + + if (!empty($this->formatter->compressColors)) { + // Converting hex color to short notation (e.g. #003399 to #039) + if ($h[1] === $h[2] && $h[3] === $h[4] && $h[5] === $h[6]) { + $h = '#' . $h[1] . $h[3] . $h[5]; + } + } + + return $h; + + case 'function': + list(, $name, $args) = $value; + return $name.'('.$this->compileValue($args).')'; + default: // assumed to be unit + $this->throwError("unknown value type: $value[0]"); + } + } + + protected function lib_isnumber($value) { + return $this->toBool($value[0] == "number"); + } + + protected function lib_isstring($value) { + return $this->toBool($value[0] == "string"); + } + + protected function lib_iscolor($value) { + return $this->toBool($this->coerceColor($value)); + } + + protected function lib_iskeyword($value) { + return $this->toBool($value[0] == "keyword"); + } + + protected function lib_ispixel($value) { + return $this->toBool($value[0] == "number" && $value[2] == "px"); + } + + protected function lib_ispercentage($value) { + return $this->toBool($value[0] == "number" && $value[2] == "%"); + } + + protected function lib_isem($value) { + return $this->toBool($value[0] == "number" && $value[2] == "em"); + } + + protected function lib_isrem($value) { + return $this->toBool($value[0] == "number" && $value[2] == "rem"); + } + + protected function lib_rgbahex($color) { + $color = $this->coerceColor($color); + if (is_null($color)) + $this->throwError("color expected for rgbahex"); + + return sprintf("#%02x%02x%02x%02x", + isset($color[4]) ? $color[4]*255 : 255, + $color[1],$color[2], $color[3]); + } + + protected function lib_argb($color){ + return $this->lib_rgbahex($color); + } + + // utility func to unquote a string + protected function lib_e($arg) { + switch ($arg[0]) { + case "list": + $items = $arg[2]; + if (isset($items[0])) { + return $this->lib_e($items[0]); + } + return self::$defaultValue; + case "string": + $arg[1] = ""; + return $arg; + case "keyword": + return $arg; + default: + return array("keyword", $this->compileValue($arg)); + } + } + + protected function lib__sprintf($args) { + if ($args[0] != "list") return $args; + $values = $args[2]; + $string = array_shift($values); + $template = $this->compileValue($this->lib_e($string)); + + $i = 0; + if (preg_match_all('/%[dsa]/', $template, $m)) { + foreach ($m[0] as $match) { + $val = isset($values[$i]) ? + $this->reduce($values[$i]) : array('keyword', ''); + + // lessjs compat, renders fully expanded color, not raw color + if ($color = $this->coerceColor($val)) { + $val = $color; + } + + $i++; + $rep = $this->compileValue($this->lib_e($val)); + $template = preg_replace('/'.self::preg_quote($match).'/', + $rep, $template, 1); + } + } + + $d = $string[0] == "string" ? $string[1] : '"'; + return array("string", $d, array($template)); + } + + protected function lib_floor($arg) { + $value = $this->assertNumber($arg); + return array("number", floor($value), $arg[2]); + } + + protected function lib_ceil($arg) { + $value = $this->assertNumber($arg); + return array("number", ceil($value), $arg[2]); + } + + protected function lib_round($arg) { + $value = $this->assertNumber($arg); + return array("number", round($value), $arg[2]); + } + + protected function lib_unit($arg) { + if ($arg[0] == "list") { + list($number, $newUnit) = $arg[2]; + return array("number", $this->assertNumber($number), + $this->compileValue($this->lib_e($newUnit))); + } else { + return array("number", $this->assertNumber($arg), ""); + } + } + + /** + * Helper function to get arguments for color manipulation functions. + * takes a list that contains a color like thing and a percentage + */ + protected function colorArgs($args) { + if ($args[0] != 'list' || count($args[2]) < 2) { + return array(array('color', 0, 0, 0), 0); + } + list($color, $delta) = $args[2]; + $color = $this->assertColor($color); + $delta = floatval($delta[1]); + + return array($color, $delta); + } + + protected function lib_darken($args) { + list($color, $delta) = $this->colorArgs($args); + + $hsl = $this->toHSL($color); + $hsl[3] = $this->clamp($hsl[3] - $delta, 100); + return $this->toRGB($hsl); + } + + protected function lib_lighten($args) { + list($color, $delta) = $this->colorArgs($args); + + $hsl = $this->toHSL($color); + $hsl[3] = $this->clamp($hsl[3] + $delta, 100); + return $this->toRGB($hsl); + } + + protected function lib_saturate($args) { + list($color, $delta) = $this->colorArgs($args); + + $hsl = $this->toHSL($color); + $hsl[2] = $this->clamp($hsl[2] + $delta, 100); + return $this->toRGB($hsl); + } + + protected function lib_desaturate($args) { + list($color, $delta) = $this->colorArgs($args); + + $hsl = $this->toHSL($color); + $hsl[2] = $this->clamp($hsl[2] - $delta, 100); + return $this->toRGB($hsl); + } + + protected function lib_spin($args) { + list($color, $delta) = $this->colorArgs($args); + + $hsl = $this->toHSL($color); + + $hsl[1] = $hsl[1] + $delta % 360; + if ($hsl[1] < 0) $hsl[1] += 360; + + return $this->toRGB($hsl); + } + + protected function lib_fadeout($args) { + list($color, $delta) = $this->colorArgs($args); + $color[4] = $this->clamp((isset($color[4]) ? $color[4] : 1) - $delta/100); + return $color; + } + + protected function lib_fadein($args) { + list($color, $delta) = $this->colorArgs($args); + $color[4] = $this->clamp((isset($color[4]) ? $color[4] : 1) + $delta/100); + return $color; + } + + protected function lib_hue($color) { + $hsl = $this->toHSL($this->assertColor($color)); + return round($hsl[1]); + } + + protected function lib_saturation($color) { + $hsl = $this->toHSL($this->assertColor($color)); + return round($hsl[2]); + } + + protected function lib_lightness($color) { + $hsl = $this->toHSL($this->assertColor($color)); + return round($hsl[3]); + } + + // get the alpha of a color + // defaults to 1 for non-colors or colors without an alpha + protected function lib_alpha($value) { + if (!is_null($color = $this->coerceColor($value))) { + return isset($color[4]) ? $color[4] : 1; + } + } + + // set the alpha of the color + protected function lib_fade($args) { + list($color, $alpha) = $this->colorArgs($args); + $color[4] = $this->clamp($alpha / 100.0); + return $color; + } + + protected function lib_percentage($arg) { + $num = $this->assertNumber($arg); + return array("number", $num*100, "%"); + } + + // mixes two colors by weight + // mix(@color1, @color2, [@weight: 50%]); + // http://sass-lang.com/docs/yardoc/Sass/Script/Functions.html#mix-instance_method + protected function lib_mix($args) { + if ($args[0] != "list" || count($args[2]) < 2) + $this->throwError("mix expects (color1, color2, weight)"); + + list($first, $second) = $args[2]; + $first = $this->assertColor($first); + $second = $this->assertColor($second); + + $first_a = $this->lib_alpha($first); + $second_a = $this->lib_alpha($second); + + if (isset($args[2][2])) { + $weight = $args[2][2][1] / 100.0; + } else { + $weight = 0.5; + } + + $w = $weight * 2 - 1; + $a = $first_a - $second_a; + + $w1 = (($w * $a == -1 ? $w : ($w + $a)/(1 + $w * $a)) + 1) / 2.0; + $w2 = 1.0 - $w1; + + $new = array('color', + $w1 * $first[1] + $w2 * $second[1], + $w1 * $first[2] + $w2 * $second[2], + $w1 * $first[3] + $w2 * $second[3], + ); + + if ($first_a != 1.0 || $second_a != 1.0) { + $new[] = $first_a * $weight + $second_a * ($weight - 1); + } + + return $this->fixColor($new); + } + + protected function lib_contrast($args) { + if ($args[0] != 'list' || count($args[2]) < 3) { + return array(array('color', 0, 0, 0), 0); + } + + list($inputColor, $darkColor, $lightColor) = $args[2]; + + $inputColor = $this->assertColor($inputColor); + $darkColor = $this->assertColor($darkColor); + $lightColor = $this->assertColor($lightColor); + $hsl = $this->toHSL($inputColor); + + if ($hsl[3] > 50) { + return $darkColor; + } + + return $lightColor; + } + + protected function assertColor($value, $error = "expected color value") { + $color = $this->coerceColor($value); + if (is_null($color)) $this->throwError($error); + return $color; + } + + protected function assertNumber($value, $error = "expecting number") { + if ($value[0] == "number") return $value[1]; + $this->throwError($error); + } + + protected function toHSL($color) { + if ($color[0] == 'hsl') return $color; + + $r = $color[1] / 255; + $g = $color[2] / 255; + $b = $color[3] / 255; + + $min = min($r, $g, $b); + $max = max($r, $g, $b); + + $L = ($min + $max) / 2; + if ($min == $max) { + $S = $H = 0; + } else { + if ($L < 0.5) + $S = ($max - $min)/($max + $min); + else + $S = ($max - $min)/(2.0 - $max - $min); + + if ($r == $max) $H = ($g - $b)/($max - $min); + elseif ($g == $max) $H = 2.0 + ($b - $r)/($max - $min); + elseif ($b == $max) $H = 4.0 + ($r - $g)/($max - $min); + + } + + $out = array('hsl', + ($H < 0 ? $H + 6 : $H)*60, + $S*100, + $L*100, + ); + + if (count($color) > 4) $out[] = $color[4]; // copy alpha + return $out; + } + + protected function toRGB_helper($comp, $temp1, $temp2) { + if ($comp < 0) $comp += 1.0; + elseif ($comp > 1) $comp -= 1.0; + + if (6 * $comp < 1) return $temp1 + ($temp2 - $temp1) * 6 * $comp; + if (2 * $comp < 1) return $temp2; + if (3 * $comp < 2) return $temp1 + ($temp2 - $temp1)*((2/3) - $comp) * 6; + + return $temp1; + } + + /** + * Converts a hsl array into a color value in rgb. + * Expects H to be in range of 0 to 360, S and L in 0 to 100 + */ + protected function toRGB($color) { + if ($color[0] == 'color') return $color; + + $H = $color[1] / 360; + $S = $color[2] / 100; + $L = $color[3] / 100; + + if ($S == 0) { + $r = $g = $b = $L; + } else { + $temp2 = $L < 0.5 ? + $L*(1.0 + $S) : + $L + $S - $L * $S; + + $temp1 = 2.0 * $L - $temp2; + + $r = $this->toRGB_helper($H + 1/3, $temp1, $temp2); + $g = $this->toRGB_helper($H, $temp1, $temp2); + $b = $this->toRGB_helper($H - 1/3, $temp1, $temp2); + } + + // $out = array('color', round($r*255), round($g*255), round($b*255)); + $out = array('color', $r*255, $g*255, $b*255); + if (count($color) > 4) $out[] = $color[4]; // copy alpha + return $out; + } + + protected function clamp($v, $max = 1, $min = 0) { + return min($max, max($min, $v)); + } + + /** + * Convert the rgb, rgba, hsl color literals of function type + * as returned by the parser into values of color type. + */ + protected function funcToColor($func) { + $fname = $func[1]; + if ($func[2][0] != 'list') return false; // need a list of arguments + $rawComponents = $func[2][2]; + + if ($fname == 'hsl' || $fname == 'hsla') { + $hsl = array('hsl'); + $i = 0; + foreach ($rawComponents as $c) { + $val = $this->reduce($c); + $val = isset($val[1]) ? floatval($val[1]) : 0; + + if ($i == 0) $clamp = 360; + elseif ($i < 3) $clamp = 100; + else $clamp = 1; + + $hsl[] = $this->clamp($val, $clamp); + $i++; + } + + while (count($hsl) < 4) $hsl[] = 0; + return $this->toRGB($hsl); + + } elseif ($fname == 'rgb' || $fname == 'rgba') { + $components = array(); + $i = 1; + foreach ($rawComponents as $c) { + $c = $this->reduce($c); + if ($i < 4) { + if ($c[0] == "number" && $c[2] == "%") { + $components[] = 255 * ($c[1] / 100); + } else { + $components[] = floatval($c[1]); + } + } elseif ($i == 4) { + if ($c[0] == "number" && $c[2] == "%") { + $components[] = 1.0 * ($c[1] / 100); + } else { + $components[] = floatval($c[1]); + } + } else break; + + $i++; + } + while (count($components) < 3) $components[] = 0; + array_unshift($components, 'color'); + return $this->fixColor($components); + } + + return false; + } + + protected function reduce($value, $forExpression = false) { + switch ($value[0]) { + case "interpolate": + $reduced = $this->reduce($value[1]); + $var = $this->compileValue($reduced); + $res = $this->reduce(array("variable", $this->vPrefix . $var)); + + if (empty($value[2])) $res = $this->lib_e($res); + + return $res; + case "variable": + $key = $value[1]; + if (is_array($key)) { + $key = $this->reduce($key); + $key = $this->vPrefix . $this->compileValue($this->lib_e($key)); + } + + $seen =& $this->env->seenNames; + + if (!empty($seen[$key])) { + $this->throwError("infinite loop detected: $key"); + } + + $seen[$key] = true; + $out = $this->reduce($this->get($key, self::$defaultValue)); + $seen[$key] = false; + return $out; + case "list": + foreach ($value[2] as &$item) { + $item = $this->reduce($item, $forExpression); + } + return $value; + case "expression": + return $this->evaluate($value); + case "string": + foreach ($value[2] as &$part) { + if (is_array($part)) { + $strip = $part[0] == "variable"; + $part = $this->reduce($part); + if ($strip) $part = $this->lib_e($part); + } + } + return $value; + case "escape": + list(,$inner) = $value; + return $this->lib_e($this->reduce($inner)); + case "function": + $color = $this->funcToColor($value); + if ($color) return $color; + + list(, $name, $args) = $value; + if ($name == "%") $name = "_sprintf"; + $f = isset($this->libFunctions[$name]) ? + $this->libFunctions[$name] : array($this, 'lib_'.$name); + + if (is_callable($f)) { + if ($args[0] == 'list') + $args = self::compressList($args[2], $args[1]); + + $ret = call_user_func($f, $this->reduce($args, true), $this); + + if (is_null($ret)) { + return array("string", "", array( + $name, "(", $args, ")" + )); + } + + // convert to a typed value if the result is a php primitive + if (is_numeric($ret)) $ret = array('number', $ret, ""); + elseif (!is_array($ret)) $ret = array('keyword', $ret); + + return $ret; + } + + // plain function, reduce args + $value[2] = $this->reduce($value[2]); + return $value; + case "unary": + list(, $op, $exp) = $value; + $exp = $this->reduce($exp); + + if ($exp[0] == "number") { + switch ($op) { + case "+": + return $exp; + case "-": + $exp[1] *= -1; + return $exp; + } + } + return array("string", "", array($op, $exp)); + } + + if ($forExpression) { + switch ($value[0]) { + case "keyword": + if ($color = $this->coerceColor($value)) { + return $color; + } + break; + case "raw_color": + return $this->coerceColor($value); + } + } + + return $value; + } + + + // coerce a value for use in color operation + protected function coerceColor($value) { + switch($value[0]) { + case 'color': return $value; + case 'raw_color': + $c = array("color", 0, 0, 0); + $colorStr = substr($value[1], 1); + $num = hexdec($colorStr); + $width = strlen($colorStr) == 3 ? 16 : 256; + + for ($i = 3; $i > 0; $i--) { // 3 2 1 + $t = $num % $width; + $num /= $width; + + $c[$i] = $t * (256/$width) + $t * floor(16/$width); + } + + return $c; + case 'keyword': + $name = $value[1]; + if (isset(self::$cssColors[$name])) { + $rgba = explode(',', self::$cssColors[$name]); + + if(isset($rgba[3])) + return array('color', $rgba[0], $rgba[1], $rgba[2], $rgba[3]); + + return array('color', $rgba[0], $rgba[1], $rgba[2]); + } + return null; + } + } + + // make something string like into a string + protected function coerceString($value) { + switch ($value[0]) { + case "string": + return $value; + case "keyword": + return array("string", "", array($value[1])); + } + return null; + } + + // turn list of length 1 into value type + protected function flattenList($value) { + if ($value[0] == "list" && count($value[2]) == 1) { + return $this->flattenList($value[2][0]); + } + return $value; + } + + protected function toBool($a) { + if ($a) return self::$TRUE; + else return self::$FALSE; + } + + // evaluate an expression + protected function evaluate($exp) { + list(, $op, $left, $right, $whiteBefore, $whiteAfter) = $exp; + + $left = $this->reduce($left, true); + $right = $this->reduce($right, true); + + if ($leftColor = $this->coerceColor($left)) { + $left = $leftColor; + } + + if ($rightColor = $this->coerceColor($right)) { + $right = $rightColor; + } + + $ltype = $left[0]; + $rtype = $right[0]; + + // operators that work on all types + if ($op == "and") { + return $this->toBool($left == self::$TRUE && $right == self::$TRUE); + } + + if ($op == "=") { + return $this->toBool($this->eq($left, $right) ); + } + + if ($op == "+" && !is_null($str = $this->stringConcatenate($left, $right))) { + return $str; + } + + // type based operators + $fname = "op_${ltype}_${rtype}"; + if (is_callable(array($this, $fname))) { + $out = $this->$fname($op, $left, $right); + if (!is_null($out)) return $out; + } + + // make the expression look it did before being parsed + $paddedOp = $op; + if ($whiteBefore) $paddedOp = " " . $paddedOp; + if ($whiteAfter) $paddedOp .= " "; + + return array("string", "", array($left, $paddedOp, $right)); + } + + protected function stringConcatenate($left, $right) { + if ($strLeft = $this->coerceString($left)) { + if ($right[0] == "string") { + $right[1] = ""; + } + $strLeft[2][] = $right; + return $strLeft; + } + + if ($strRight = $this->coerceString($right)) { + array_unshift($strRight[2], $left); + return $strRight; + } + } + + + // make sure a color's components don't go out of bounds + protected function fixColor($c) { + foreach (range(1, 3) as $i) { + if ($c[$i] < 0) $c[$i] = 0; + if ($c[$i] > 255) $c[$i] = 255; + } + + return $c; + } + + protected function op_number_color($op, $lft, $rgt) { + if ($op == '+' || $op == '*') { + return $this->op_color_number($op, $rgt, $lft); + } + } + + protected function op_color_number($op, $lft, $rgt) { + if ($rgt[0] == '%') $rgt[1] /= 100; + + return $this->op_color_color($op, $lft, + array_fill(1, count($lft) - 1, $rgt[1])); + } + + protected function op_color_color($op, $left, $right) { + $out = array('color'); + $max = count($left) > count($right) ? count($left) : count($right); + foreach (range(1, $max - 1) as $i) { + $lval = isset($left[$i]) ? $left[$i] : 0; + $rval = isset($right[$i]) ? $right[$i] : 0; + switch ($op) { + case '+': + $out[] = $lval + $rval; + break; + case '-': + $out[] = $lval - $rval; + break; + case '*': + $out[] = $lval * $rval; + break; + case '%': + $out[] = $lval % $rval; + break; + case '/': + if ($rval == 0) $this->throwError("evaluate error: can't divide by zero"); + $out[] = $lval / $rval; + break; + default: + $this->throwError('evaluate error: color op number failed on op '.$op); + } + } + return $this->fixColor($out); + } + + function lib_red($color){ + $color = $this->coerceColor($color); + if (is_null($color)) { + $this->throwError('color expected for red()'); + } + + return $color[1]; + } + + function lib_green($color){ + $color = $this->coerceColor($color); + if (is_null($color)) { + $this->throwError('color expected for green()'); + } + + return $color[2]; + } + + function lib_blue($color){ + $color = $this->coerceColor($color); + if (is_null($color)) { + $this->throwError('color expected for blue()'); + } + + return $color[3]; + } + + + // operator on two numbers + protected function op_number_number($op, $left, $right) { + $unit = empty($left[2]) ? $right[2] : $left[2]; + + $value = 0; + switch ($op) { + case '+': + $value = $left[1] + $right[1]; + break; + case '*': + $value = $left[1] * $right[1]; + break; + case '-': + $value = $left[1] - $right[1]; + break; + case '%': + $value = $left[1] % $right[1]; + break; + case '/': + if ($right[1] == 0) $this->throwError('parse error: divide by zero'); + $value = $left[1] / $right[1]; + break; + case '<': + return $this->toBool($left[1] < $right[1]); + case '>': + return $this->toBool($left[1] > $right[1]); + case '>=': + return $this->toBool($left[1] >= $right[1]); + case '=<': + return $this->toBool($left[1] <= $right[1]); + default: + $this->throwError('parse error: unknown number operator: '.$op); + } + + return array("number", $value, $unit); + } + + + /* environment functions */ + + protected function makeOutputBlock($type, $selectors = null) { + $b = new stdclass; + $b->lines = array(); + $b->children = array(); + $b->selectors = $selectors; + $b->type = $type; + $b->parent = $this->scope; + return $b; + } + + // the state of execution + protected function pushEnv($block = null) { + $e = new stdclass; + $e->parent = $this->env; + $e->store = array(); + $e->block = $block; + + $this->env = $e; + return $e; + } + + // pop something off the stack + protected function popEnv() { + $old = $this->env; + $this->env = $this->env->parent; + return $old; + } + + // set something in the current env + protected function set($name, $value) { + $this->env->store[$name] = $value; + } + + + // get the highest occurrence entry for a name + protected function get($name, $default=null) { + $current = $this->env; + + $isArguments = $name == $this->vPrefix . 'arguments'; + while ($current) { + if ($isArguments && isset($current->arguments)) { + return array('list', ' ', $current->arguments); + } + + if (isset($current->store[$name])) + return $current->store[$name]; + else { + $current = isset($current->storeParent) ? + $current->storeParent : $current->parent; + } + } + + return $default; + } + + // inject array of unparsed strings into environment as variables + protected function injectVariables($args) { + $this->pushEnv(); + $parser = new lessc_parser($this, __METHOD__); + foreach ($args as $name => $strValue) { + if ($name{0} != '@') $name = '@'.$name; + $parser->count = 0; + $parser->buffer = (string)$strValue; + if (!$parser->propertyValue($value)) { + throw new Exception("failed to parse passed in variable $name: $strValue"); + } + + $this->set($name, $value); + } + } + + /** + * Initialize any static state, can initialize parser for a file + * $opts isn't used yet + */ + public function __construct($fname = null) { + if ($fname !== null) { + // used for deprecated parse method + $this->_parseFile = $fname; + } + } + + public function compile($string, $name = null) { + $locale = setlocale(LC_NUMERIC, 0); + setlocale(LC_NUMERIC, "C"); + + $this->parser = $this->makeParser($name); + $root = $this->parser->parse($string); + + $this->env = null; + $this->scope = null; + + $this->formatter = $this->newFormatter(); + + if (!empty($this->registeredVars)) { + $this->injectVariables($this->registeredVars); + } + + $this->sourceParser = $this->parser; // used for error messages + $this->compileBlock($root); + + ob_start(); + $this->formatter->block($this->scope); + $out = ob_get_clean(); + setlocale(LC_NUMERIC, $locale); + return $out; + } + + public function compileFile($fname, $outFname = null) { + if (!is_readable($fname)) { + throw new Exception('load error: failed to find '.$fname); + } + + $pi = pathinfo($fname); + + $oldImport = $this->importDir; + + $this->importDir = (array)$this->importDir; + $this->importDir[] = $pi['dirname'].'/'; + + $this->allParsedFiles = array(); + $this->addParsedFile($fname); + + $out = $this->compile(file_get_contents($fname), $fname); + + $this->importDir = $oldImport; + + if ($outFname !== null) { + return file_put_contents($outFname, $out); + } + + return $out; + } + + // compile only if changed input has changed or output doesn't exist + public function checkedCompile($in, $out) { + if (!is_file($out) || filemtime($in) > filemtime($out)) { + $this->compileFile($in, $out); + return true; + } + return false; + } + + /** + * Execute lessphp on a .less file or a lessphp cache structure + * + * The lessphp cache structure contains information about a specific + * less file having been parsed. It can be used as a hint for future + * calls to determine whether or not a rebuild is required. + * + * The cache structure contains two important keys that may be used + * externally: + * + * compiled: The final compiled CSS + * updated: The time (in seconds) the CSS was last compiled + * + * The cache structure is a plain-ol' PHP associative array and can + * be serialized and unserialized without a hitch. + * + * @param mixed $in Input + * @param bool $force Force rebuild? + * @return array lessphp cache structure + */ + public function cachedCompile($in, $force = false) { + // assume no root + $root = null; + + if (is_string($in)) { + $root = $in; + } elseif (is_array($in) and isset($in['root'])) { + if ($force or ! isset($in['files'])) { + // If we are forcing a recompile or if for some reason the + // structure does not contain any file information we should + // specify the root to trigger a rebuild. + $root = $in['root']; + } elseif (isset($in['files']) and is_array($in['files'])) { + foreach ($in['files'] as $fname => $ftime ) { + if (!file_exists($fname) or filemtime($fname) > $ftime) { + // One of the files we knew about previously has changed + // so we should look at our incoming root again. + $root = $in['root']; + break; + } + } + } + } else { + // TODO: Throw an exception? We got neither a string nor something + // that looks like a compatible lessphp cache structure. + return null; + } + + if ($root !== null) { + // If we have a root value which means we should rebuild. + $out = array(); + $out['root'] = $root; + $out['compiled'] = $this->compileFile($root); + $out['files'] = $this->allParsedFiles(); + $out['updated'] = time(); + return $out; + } else { + // No changes, pass back the structure + // we were given initially. + return $in; + } + + } + + // parse and compile buffer + // This is deprecated + public function parse($str = null, $initialVariables = null) { + if (is_array($str)) { + $initialVariables = $str; + $str = null; + } + + $oldVars = $this->registeredVars; + if ($initialVariables !== null) { + $this->setVariables($initialVariables); + } + + if ($str == null) { + if (empty($this->_parseFile)) { + throw new exception("nothing to parse"); + } + + $out = $this->compileFile($this->_parseFile); + } else { + $out = $this->compile($str); + } + + $this->registeredVars = $oldVars; + return $out; + } + + protected function makeParser($name) { + $parser = new lessc_parser($this, $name); + $parser->writeComments = $this->preserveComments; + + return $parser; + } + + public function setFormatter($name) { + $this->formatterName = $name; + } + + protected function newFormatter() { + $className = "lessc_formatter_lessjs"; + if (!empty($this->formatterName)) { + if (!is_string($this->formatterName)) + return $this->formatterName; + $className = "lessc_formatter_$this->formatterName"; + } + + return new $className; + } + + public function setPreserveComments($preserve) { + $this->preserveComments = $preserve; + } + + public function registerFunction($name, $func) { + $this->libFunctions[$name] = $func; + } + + public function unregisterFunction($name) { + unset($this->libFunctions[$name]); + } + + public function setVariables($variables) { + $this->registeredVars = array_merge($this->registeredVars, $variables); + } + + public function unsetVariable($name) { + unset($this->registeredVars[$name]); + } + + public function setImportDir($dirs) { + $this->importDir = (array)$dirs; + } + + public function addImportDir($dir) { + $this->importDir = (array)$this->importDir; + $this->importDir[] = $dir; + } + + public function allParsedFiles() { + return $this->allParsedFiles; + } + + protected function addParsedFile($file) { + $this->allParsedFiles[realpath($file)] = filemtime($file); + } + + /** + * Uses the current value of $this->count to show line and line number + */ + protected function throwError($msg = null) { + if ($this->sourceLoc >= 0) { + $this->sourceParser->throwError($msg, $this->sourceLoc); + } + throw new exception($msg); + } + + // compile file $in to file $out if $in is newer than $out + // returns true when it compiles, false otherwise + public static function ccompile($in, $out, $less = null) { + if ($less === null) { + $less = new self; + } + return $less->checkedCompile($in, $out); + } + + public static function cexecute($in, $force = false, $less = null) { + if ($less === null) { + $less = new self; + } + return $less->cachedCompile($in, $force); + } + + static protected $cssColors = array( + 'aliceblue' => '240,248,255', + 'antiquewhite' => '250,235,215', + 'aqua' => '0,255,255', + 'aquamarine' => '127,255,212', + 'azure' => '240,255,255', + 'beige' => '245,245,220', + 'bisque' => '255,228,196', + 'black' => '0,0,0', + 'blanchedalmond' => '255,235,205', + 'blue' => '0,0,255', + 'blueviolet' => '138,43,226', + 'brown' => '165,42,42', + 'burlywood' => '222,184,135', + 'cadetblue' => '95,158,160', + 'chartreuse' => '127,255,0', + 'chocolate' => '210,105,30', + 'coral' => '255,127,80', + 'cornflowerblue' => '100,149,237', + 'cornsilk' => '255,248,220', + 'crimson' => '220,20,60', + 'cyan' => '0,255,255', + 'darkblue' => '0,0,139', + 'darkcyan' => '0,139,139', + 'darkgoldenrod' => '184,134,11', + 'darkgray' => '169,169,169', + 'darkgreen' => '0,100,0', + 'darkgrey' => '169,169,169', + 'darkkhaki' => '189,183,107', + 'darkmagenta' => '139,0,139', + 'darkolivegreen' => '85,107,47', + 'darkorange' => '255,140,0', + 'darkorchid' => '153,50,204', + 'darkred' => '139,0,0', + 'darksalmon' => '233,150,122', + 'darkseagreen' => '143,188,143', + 'darkslateblue' => '72,61,139', + 'darkslategray' => '47,79,79', + 'darkslategrey' => '47,79,79', + 'darkturquoise' => '0,206,209', + 'darkviolet' => '148,0,211', + 'deeppink' => '255,20,147', + 'deepskyblue' => '0,191,255', + 'dimgray' => '105,105,105', + 'dimgrey' => '105,105,105', + 'dodgerblue' => '30,144,255', + 'firebrick' => '178,34,34', + 'floralwhite' => '255,250,240', + 'forestgreen' => '34,139,34', + 'fuchsia' => '255,0,255', + 'gainsboro' => '220,220,220', + 'ghostwhite' => '248,248,255', + 'gold' => '255,215,0', + 'goldenrod' => '218,165,32', + 'gray' => '128,128,128', + 'green' => '0,128,0', + 'greenyellow' => '173,255,47', + 'grey' => '128,128,128', + 'honeydew' => '240,255,240', + 'hotpink' => '255,105,180', + 'indianred' => '205,92,92', + 'indigo' => '75,0,130', + 'ivory' => '255,255,240', + 'khaki' => '240,230,140', + 'lavender' => '230,230,250', + 'lavenderblush' => '255,240,245', + 'lawngreen' => '124,252,0', + 'lemonchiffon' => '255,250,205', + 'lightblue' => '173,216,230', + 'lightcoral' => '240,128,128', + 'lightcyan' => '224,255,255', + 'lightgoldenrodyellow' => '250,250,210', + 'lightgray' => '211,211,211', + 'lightgreen' => '144,238,144', + 'lightgrey' => '211,211,211', + 'lightpink' => '255,182,193', + 'lightsalmon' => '255,160,122', + 'lightseagreen' => '32,178,170', + 'lightskyblue' => '135,206,250', + 'lightslategray' => '119,136,153', + 'lightslategrey' => '119,136,153', + 'lightsteelblue' => '176,196,222', + 'lightyellow' => '255,255,224', + 'lime' => '0,255,0', + 'limegreen' => '50,205,50', + 'linen' => '250,240,230', + 'magenta' => '255,0,255', + 'maroon' => '128,0,0', + 'mediumaquamarine' => '102,205,170', + 'mediumblue' => '0,0,205', + 'mediumorchid' => '186,85,211', + 'mediumpurple' => '147,112,219', + 'mediumseagreen' => '60,179,113', + 'mediumslateblue' => '123,104,238', + 'mediumspringgreen' => '0,250,154', + 'mediumturquoise' => '72,209,204', + 'mediumvioletred' => '199,21,133', + 'midnightblue' => '25,25,112', + 'mintcream' => '245,255,250', + 'mistyrose' => '255,228,225', + 'moccasin' => '255,228,181', + 'navajowhite' => '255,222,173', + 'navy' => '0,0,128', + 'oldlace' => '253,245,230', + 'olive' => '128,128,0', + 'olivedrab' => '107,142,35', + 'orange' => '255,165,0', + 'orangered' => '255,69,0', + 'orchid' => '218,112,214', + 'palegoldenrod' => '238,232,170', + 'palegreen' => '152,251,152', + 'paleturquoise' => '175,238,238', + 'palevioletred' => '219,112,147', + 'papayawhip' => '255,239,213', + 'peachpuff' => '255,218,185', + 'peru' => '205,133,63', + 'pink' => '255,192,203', + 'plum' => '221,160,221', + 'powderblue' => '176,224,230', + 'purple' => '128,0,128', + 'red' => '255,0,0', + 'rosybrown' => '188,143,143', + 'royalblue' => '65,105,225', + 'saddlebrown' => '139,69,19', + 'salmon' => '250,128,114', + 'sandybrown' => '244,164,96', + 'seagreen' => '46,139,87', + 'seashell' => '255,245,238', + 'sienna' => '160,82,45', + 'silver' => '192,192,192', + 'skyblue' => '135,206,235', + 'slateblue' => '106,90,205', + 'slategray' => '112,128,144', + 'slategrey' => '112,128,144', + 'snow' => '255,250,250', + 'springgreen' => '0,255,127', + 'steelblue' => '70,130,180', + 'tan' => '210,180,140', + 'teal' => '0,128,128', + 'thistle' => '216,191,216', + 'tomato' => '255,99,71', + 'transparent' => '0,0,0,0', + 'turquoise' => '64,224,208', + 'violet' => '238,130,238', + 'wheat' => '245,222,179', + 'white' => '255,255,255', + 'whitesmoke' => '245,245,245', + 'yellow' => '255,255,0', + 'yellowgreen' => '154,205,50' + ); +} + +// responsible for taking a string of LESS code and converting it into a +// syntax tree +class lessc_parser { + static protected $nextBlockId = 0; // used to uniquely identify blocks + + static protected $precedence = array( + '=<' => 0, + '>=' => 0, + '=' => 0, + '<' => 0, + '>' => 0, + + '+' => 1, + '-' => 1, + '*' => 2, + '/' => 2, + '%' => 2, + ); + + static protected $whitePattern; + static protected $commentMulti; + + static protected $commentSingle = "//"; + static protected $commentMultiLeft = "/*"; + static protected $commentMultiRight = "*/"; + + // regex string to match any of the operators + static protected $operatorString; + + // these properties will supress division unless it's inside parenthases + static protected $supressDivisionProps = + array('/border-radius$/i', '/^font$/i'); + + protected $blockDirectives = array("font-face", "keyframes", "page", "-moz-document", "viewport", "-moz-viewport", "-o-viewport", "-ms-viewport"); + protected $lineDirectives = array("charset"); + + /** + * if we are in parens we can be more liberal with whitespace around + * operators because it must evaluate to a single value and thus is less + * ambiguous. + * + * Consider: + * property1: 10 -5; // is two numbers, 10 and -5 + * property2: (10 -5); // should evaluate to 5 + */ + protected $inParens = false; + + // caches preg escaped literals + static protected $literalCache = array(); + + public function __construct($lessc, $sourceName = null) { + $this->eatWhiteDefault = true; + // reference to less needed for vPrefix, mPrefix, and parentSelector + $this->lessc = $lessc; + + $this->sourceName = $sourceName; // name used for error messages + + $this->writeComments = false; + + if (!self::$operatorString) { + self::$operatorString = + '('.implode('|', array_map(array('lessc', 'preg_quote'), + array_keys(self::$precedence))).')'; + + $commentSingle = lessc::preg_quote(self::$commentSingle); + $commentMultiLeft = lessc::preg_quote(self::$commentMultiLeft); + $commentMultiRight = lessc::preg_quote(self::$commentMultiRight); + + self::$commentMulti = $commentMultiLeft.'.*?'.$commentMultiRight; + self::$whitePattern = '/'.$commentSingle.'[^\n]*\s*|('.self::$commentMulti.')\s*|\s+/Ais'; + } + } + + public function parse($buffer) { + $this->count = 0; + $this->line = 1; + + $this->env = null; // block stack + $this->buffer = $this->writeComments ? $buffer : $this->removeComments($buffer); + $this->pushSpecialBlock("root"); + $this->eatWhiteDefault = true; + $this->seenComments = array(); + + // trim whitespace on head + // if (preg_match('/^\s+/', $this->buffer, $m)) { + // $this->line += substr_count($m[0], "\n"); + // $this->buffer = ltrim($this->buffer); + // } + $this->whitespace(); + + // parse the entire file + $lastCount = $this->count; + while (false !== $this->parseChunk()); + + if ($this->count != strlen($this->buffer)) + $this->throwError(); + + // TODO report where the block was opened + if (!is_null($this->env->parent)) + throw new exception('parse error: unclosed block'); + + return $this->env; + } + + /** + * Parse a single chunk off the head of the buffer and append it to the + * current parse environment. + * Returns false when the buffer is empty, or when there is an error. + * + * This function is called repeatedly until the entire document is + * parsed. + * + * This parser is most similar to a recursive descent parser. Single + * functions represent discrete grammatical rules for the language, and + * they are able to capture the text that represents those rules. + * + * Consider the function lessc::keyword(). (all parse functions are + * structured the same) + * + * The function takes a single reference argument. When calling the + * function it will attempt to match a keyword on the head of the buffer. + * If it is successful, it will place the keyword in the referenced + * argument, advance the position in the buffer, and return true. If it + * fails then it won't advance the buffer and it will return false. + * + * All of these parse functions are powered by lessc::match(), which behaves + * the same way, but takes a literal regular expression. Sometimes it is + * more convenient to use match instead of creating a new function. + * + * Because of the format of the functions, to parse an entire string of + * grammatical rules, you can chain them together using &&. + * + * But, if some of the rules in the chain succeed before one fails, then + * the buffer position will be left at an invalid state. In order to + * avoid this, lessc::seek() is used to remember and set buffer positions. + * + * Before parsing a chain, use $s = $this->seek() to remember the current + * position into $s. Then if a chain fails, use $this->seek($s) to + * go back where we started. + */ + protected function parseChunk() { + if (empty($this->buffer)) return false; + $s = $this->seek(); + + // setting a property + if ($this->keyword($key) && $this->assign() && + $this->propertyValue($value, $key) && $this->end()) + { + $this->append(array('assign', $key, $value), $s); + return true; + } else { + $this->seek($s); + } + + + // look for special css blocks + if ($this->literal('@', false)) { + $this->count--; + + // media + if ($this->literal('@media')) { + if (($this->mediaQueryList($mediaQueries) || true) + && $this->literal('{')) + { + $media = $this->pushSpecialBlock("media"); + $media->queries = is_null($mediaQueries) ? array() : $mediaQueries; + return true; + } else { + $this->seek($s); + return false; + } + } + + if ($this->literal("@", false) && $this->keyword($dirName)) { + if ($this->isDirective($dirName, $this->blockDirectives)) { + if (($this->openString("{", $dirValue, null, array(";")) || true) && + $this->literal("{")) + { + $dir = $this->pushSpecialBlock("directive"); + $dir->name = $dirName; + if (isset($dirValue)) $dir->value = $dirValue; + return true; + } + } elseif ($this->isDirective($dirName, $this->lineDirectives)) { + if ($this->propertyValue($dirValue) && $this->end()) { + $this->append(array("directive", $dirName, $dirValue)); + return true; + } + } + } + + $this->seek($s); + } + + // setting a variable + if ($this->variable($var) && $this->assign() && + $this->propertyValue($value) && $this->end()) + { + $this->append(array('assign', $var, $value), $s); + return true; + } else { + $this->seek($s); + } + + if ($this->import($importValue)) { + $this->append($importValue, $s); + return true; + } + + // opening parametric mixin + if ($this->tag($tag, true) && $this->argumentDef($args, $isVararg) && + ($this->guards($guards) || true) && + $this->literal('{')) + { + $block = $this->pushBlock($this->fixTags(array($tag))); + $block->args = $args; + $block->isVararg = $isVararg; + if (!empty($guards)) $block->guards = $guards; + return true; + } else { + $this->seek($s); + } + + // opening a simple block + if ($this->tags($tags) && $this->literal('{')) { + $tags = $this->fixTags($tags); + $this->pushBlock($tags); + return true; + } else { + $this->seek($s); + } + + // closing a block + if ($this->literal('}', false)) { + try { + $block = $this->pop(); + } catch (exception $e) { + $this->seek($s); + $this->throwError($e->getMessage()); + } + + $hidden = false; + if (is_null($block->type)) { + $hidden = true; + if (!isset($block->args)) { + foreach ($block->tags as $tag) { + if (!is_string($tag) || $tag{0} != $this->lessc->mPrefix) { + $hidden = false; + break; + } + } + } + + foreach ($block->tags as $tag) { + if (is_string($tag)) { + $this->env->children[$tag][] = $block; + } + } + } + + if (!$hidden) { + $this->append(array('block', $block), $s); + } + + // this is done here so comments aren't bundled into he block that + // was just closed + $this->whitespace(); + return true; + } + + // mixin + if ($this->mixinTags($tags) && + ($this->argumentValues($argv) || true) && + ($this->keyword($suffix) || true) && $this->end()) + { + $tags = $this->fixTags($tags); + $this->append(array('mixin', $tags, $argv, $suffix), $s); + return true; + } else { + $this->seek($s); + } + + // spare ; + if ($this->literal(';')) return true; + + return false; // got nothing, throw error + } + + protected function isDirective($dirname, $directives) { + // TODO: cache pattern in parser + $pattern = implode("|", + array_map(array("lessc", "preg_quote"), $directives)); + $pattern = '/^(-[a-z-]+-)?(' . $pattern . ')$/i'; + + return preg_match($pattern, $dirname); + } + + protected function fixTags($tags) { + // move @ tags out of variable namespace + foreach ($tags as &$tag) { + if ($tag{0} == $this->lessc->vPrefix) + $tag[0] = $this->lessc->mPrefix; + } + return $tags; + } + + // a list of expressions + protected function expressionList(&$exps) { + $values = array(); + + while ($this->expression($exp)) { + $values[] = $exp; + } + + if (count($values) == 0) return false; + + $exps = lessc::compressList($values, ' '); + return true; + } + + /** + * Attempt to consume an expression. + * @link http://en.wikipedia.org/wiki/Operator-precedence_parser#Pseudo-code + */ + protected function expression(&$out) { + if ($this->value($lhs)) { + $out = $this->expHelper($lhs, 0); + + // look for / shorthand + if (!empty($this->env->supressedDivision)) { + unset($this->env->supressedDivision); + $s = $this->seek(); + if ($this->literal("/") && $this->value($rhs)) { + $out = array("list", "", + array($out, array("keyword", "/"), $rhs)); + } else { + $this->seek($s); + } + } + + return true; + } + return false; + } + + /** + * recursively parse infix equation with $lhs at precedence $minP + */ + protected function expHelper($lhs, $minP) { + $this->inExp = true; + $ss = $this->seek(); + + while (true) { + $whiteBefore = isset($this->buffer[$this->count - 1]) && + ctype_space($this->buffer[$this->count - 1]); + + // If there is whitespace before the operator, then we require + // whitespace after the operator for it to be an expression + $needWhite = $whiteBefore && !$this->inParens; + + if ($this->match(self::$operatorString.($needWhite ? '\s' : ''), $m) && self::$precedence[$m[1]] >= $minP) { + if (!$this->inParens && isset($this->env->currentProperty) && $m[1] == "/" && empty($this->env->supressedDivision)) { + foreach (self::$supressDivisionProps as $pattern) { + if (preg_match($pattern, $this->env->currentProperty)) { + $this->env->supressedDivision = true; + break 2; + } + } + } + + + $whiteAfter = isset($this->buffer[$this->count - 1]) && + ctype_space($this->buffer[$this->count - 1]); + + if (!$this->value($rhs)) break; + + // peek for next operator to see what to do with rhs + if ($this->peek(self::$operatorString, $next) && self::$precedence[$next[1]] > self::$precedence[$m[1]]) { + $rhs = $this->expHelper($rhs, self::$precedence[$next[1]]); + } + + $lhs = array('expression', $m[1], $lhs, $rhs, $whiteBefore, $whiteAfter); + $ss = $this->seek(); + + continue; + } + + break; + } + + $this->seek($ss); + + return $lhs; + } + + // consume a list of values for a property + public function propertyValue(&$value, $keyName = null) { + $values = array(); + + if ($keyName !== null) $this->env->currentProperty = $keyName; + + $s = null; + while ($this->expressionList($v)) { + $values[] = $v; + $s = $this->seek(); + if (!$this->literal(',')) break; + } + + if ($s) $this->seek($s); + + if ($keyName !== null) unset($this->env->currentProperty); + + if (count($values) == 0) return false; + + $value = lessc::compressList($values, ', '); + return true; + } + + protected function parenValue(&$out) { + $s = $this->seek(); + + // speed shortcut + if (isset($this->buffer[$this->count]) && $this->buffer[$this->count] != "(") { + return false; + } + + $inParens = $this->inParens; + if ($this->literal("(") && + ($this->inParens = true) && $this->expression($exp) && + $this->literal(")")) + { + $out = $exp; + $this->inParens = $inParens; + return true; + } else { + $this->inParens = $inParens; + $this->seek($s); + } + + return false; + } + + // a single value + protected function value(&$value) { + $s = $this->seek(); + + // speed shortcut + if (isset($this->buffer[$this->count]) && $this->buffer[$this->count] == "-") { + // negation + if ($this->literal("-", false) && + (($this->variable($inner) && $inner = array("variable", $inner)) || + $this->unit($inner) || + $this->parenValue($inner))) + { + $value = array("unary", "-", $inner); + return true; + } else { + $this->seek($s); + } + } + + if ($this->parenValue($value)) return true; + if ($this->unit($value)) return true; + if ($this->color($value)) return true; + if ($this->func($value)) return true; + if ($this->string($value)) return true; + + if ($this->keyword($word)) { + $value = array('keyword', $word); + return true; + } + + // try a variable + if ($this->variable($var)) { + $value = array('variable', $var); + return true; + } + + // unquote string (should this work on any type? + if ($this->literal("~") && $this->string($str)) { + $value = array("escape", $str); + return true; + } else { + $this->seek($s); + } + + // css hack: \0 + if ($this->literal('\\') && $this->match('([0-9]+)', $m)) { + $value = array('keyword', '\\'.$m[1]); + return true; + } else { + $this->seek($s); + } + + return false; + } + + // an import statement + protected function import(&$out) { + $s = $this->seek(); + if (!$this->literal('@import')) return false; + + // @import "something.css" media; + // @import url("something.css") media; + // @import url(something.css) media; + + if ($this->propertyValue($value)) { + $out = array("import", $value); + return true; + } + } + + protected function mediaQueryList(&$out) { + if ($this->genericList($list, "mediaQuery", ",", false)) { + $out = $list[2]; + return true; + } + return false; + } + + protected function mediaQuery(&$out) { + $s = $this->seek(); + + $expressions = null; + $parts = array(); + + if (($this->literal("only") && ($only = true) || $this->literal("not") && ($not = true) || true) && $this->keyword($mediaType)) { + $prop = array("mediaType"); + if (isset($only)) $prop[] = "only"; + if (isset($not)) $prop[] = "not"; + $prop[] = $mediaType; + $parts[] = $prop; + } else { + $this->seek($s); + } + + + if (!empty($mediaType) && !$this->literal("and")) { + // ~ + } else { + $this->genericList($expressions, "mediaExpression", "and", false); + if (is_array($expressions)) $parts = array_merge($parts, $expressions[2]); + } + + if (count($parts) == 0) { + $this->seek($s); + return false; + } + + $out = $parts; + return true; + } + + protected function mediaExpression(&$out) { + $s = $this->seek(); + $value = null; + if ($this->literal("(") && + $this->keyword($feature) && + ($this->literal(":") && $this->expression($value) || true) && + $this->literal(")")) + { + $out = array("mediaExp", $feature); + if ($value) $out[] = $value; + return true; + } elseif ($this->variable($variable)) { + $out = array('variable', $variable); + return true; + } + + $this->seek($s); + return false; + } + + // an unbounded string stopped by $end + protected function openString($end, &$out, $nestingOpen=null, $rejectStrs = null) { + $oldWhite = $this->eatWhiteDefault; + $this->eatWhiteDefault = false; + + $stop = array("'", '"', "@{", $end); + $stop = array_map(array("lessc", "preg_quote"), $stop); + // $stop[] = self::$commentMulti; + + if (!is_null($rejectStrs)) { + $stop = array_merge($stop, $rejectStrs); + } + + $patt = '(.*?)('.implode("|", $stop).')'; + + $nestingLevel = 0; + + $content = array(); + while ($this->match($patt, $m, false)) { + if (!empty($m[1])) { + $content[] = $m[1]; + if ($nestingOpen) { + $nestingLevel += substr_count($m[1], $nestingOpen); + } + } + + $tok = $m[2]; + + $this->count-= strlen($tok); + if ($tok == $end) { + if ($nestingLevel == 0) { + break; + } else { + $nestingLevel--; + } + } + + if (($tok == "'" || $tok == '"') && $this->string($str)) { + $content[] = $str; + continue; + } + + if ($tok == "@{" && $this->interpolation($inter)) { + $content[] = $inter; + continue; + } + + if (!empty($rejectStrs) && in_array($tok, $rejectStrs)) { + break; + } + + $content[] = $tok; + $this->count+= strlen($tok); + } + + $this->eatWhiteDefault = $oldWhite; + + if (count($content) == 0) return false; + + // trim the end + if (is_string(end($content))) { + $content[count($content) - 1] = rtrim(end($content)); + } + + $out = array("string", "", $content); + return true; + } + + protected function string(&$out) { + $s = $this->seek(); + if ($this->literal('"', false)) { + $delim = '"'; + } elseif ($this->literal("'", false)) { + $delim = "'"; + } else { + return false; + } + + $content = array(); + + // look for either ending delim , escape, or string interpolation + $patt = '([^\n]*?)(@\{|\\\\|' . + lessc::preg_quote($delim).')'; + + $oldWhite = $this->eatWhiteDefault; + $this->eatWhiteDefault = false; + + while ($this->match($patt, $m, false)) { + $content[] = $m[1]; + if ($m[2] == "@{") { + $this->count -= strlen($m[2]); + if ($this->interpolation($inter, false)) { + $content[] = $inter; + } else { + $this->count += strlen($m[2]); + $content[] = "@{"; // ignore it + } + } elseif ($m[2] == '\\') { + $content[] = $m[2]; + if ($this->literal($delim, false)) { + $content[] = $delim; + } + } else { + $this->count -= strlen($delim); + break; // delim + } + } + + $this->eatWhiteDefault = $oldWhite; + + if ($this->literal($delim)) { + $out = array("string", $delim, $content); + return true; + } + + $this->seek($s); + return false; + } + + protected function interpolation(&$out) { + $oldWhite = $this->eatWhiteDefault; + $this->eatWhiteDefault = true; + + $s = $this->seek(); + if ($this->literal("@{") && + $this->openString("}", $interp, null, array("'", '"', ";")) && + $this->literal("}", false)) + { + $out = array("interpolate", $interp); + $this->eatWhiteDefault = $oldWhite; + if ($this->eatWhiteDefault) $this->whitespace(); + return true; + } + + $this->eatWhiteDefault = $oldWhite; + $this->seek($s); + return false; + } + + protected function unit(&$unit) { + // speed shortcut + if (isset($this->buffer[$this->count])) { + $char = $this->buffer[$this->count]; + if (!ctype_digit($char) && $char != ".") return false; + } + + if ($this->match('([0-9]+(?:\.[0-9]*)?|\.[0-9]+)([%a-zA-Z]+)?', $m)) { + $unit = array("number", $m[1], empty($m[2]) ? "" : $m[2]); + return true; + } + return false; + } + + // a # color + protected function color(&$out) { + if ($this->match('(#(?:[0-9a-f]{8}|[0-9a-f]{6}|[0-9a-f]{3}))', $m)) { + if (strlen($m[1]) > 7) { + $out = array("string", "", array($m[1])); + } else { + $out = array("raw_color", $m[1]); + } + return true; + } + + return false; + } + + // consume a list of property values delimited by ; and wrapped in () + protected function argumentValues(&$args, $delim = ',') { + $s = $this->seek(); + if (!$this->literal('(')) return false; + + $values = array(); + while (true) { + if ($this->expressionList($value)) $values[] = $value; + if (!$this->literal($delim)) break; + else { + if ($value == null) $values[] = null; + $value = null; + } + } + + if (!$this->literal(')')) { + $this->seek($s); + return false; + } + + $args = $values; + return true; + } + + // consume an argument definition list surrounded by () + // each argument is a variable name with optional value + // or at the end a ... or a variable named followed by ... + protected function argumentDef(&$args, &$isVararg, $delim = ',') { + $s = $this->seek(); + if (!$this->literal('(')) return false; + + $values = array(); + + $isVararg = false; + while (true) { + if ($this->literal("...")) { + $isVararg = true; + break; + } + + if ($this->variable($vname)) { + $arg = array("arg", $vname); + $ss = $this->seek(); + if ($this->assign() && $this->expressionList($value)) { + $arg[] = $value; + } else { + $this->seek($ss); + if ($this->literal("...")) { + $arg[0] = "rest"; + $isVararg = true; + } + } + $values[] = $arg; + if ($isVararg) break; + continue; + } + + if ($this->value($literal)) { + $values[] = array("lit", $literal); + } + + if (!$this->literal($delim)) break; + } + + if (!$this->literal(')')) { + $this->seek($s); + return false; + } + + $args = $values; + + return true; + } + + // consume a list of tags + // this accepts a hanging delimiter + protected function tags(&$tags, $simple = false, $delim = ',') { + $tags = array(); + while ($this->tag($tt, $simple)) { + $tags[] = $tt; + if (!$this->literal($delim)) break; + } + if (count($tags) == 0) return false; + + return true; + } + + // list of tags of specifying mixin path + // optionally separated by > (lazy, accepts extra >) + protected function mixinTags(&$tags) { + $s = $this->seek(); + $tags = array(); + while ($this->tag($tt, true)) { + $tags[] = $tt; + $this->literal(">"); + } + + if (count($tags) == 0) return false; + + return true; + } + + // a bracketed value (contained within in a tag definition) + protected function tagBracket(&$value) { + // speed shortcut + if (isset($this->buffer[$this->count]) && $this->buffer[$this->count] != "[") { + return false; + } + + $s = $this->seek(); + if ($this->literal('[') && $this->to(']', $c, true) && $this->literal(']', false)) { + $value = '['.$c.']'; + // whitespace? + if ($this->whitespace()) $value .= " "; + + // escape parent selector, (yuck) + $value = str_replace($this->lessc->parentSelector, "$&$", $value); + return true; + } + + $this->seek($s); + return false; + } + + protected function tagExpression(&$value) { + $s = $this->seek(); + if ($this->literal("(") && $this->expression($exp) && $this->literal(")")) { + $value = array('exp', $exp); + return true; + } + + $this->seek($s); + return false; + } + + // a space separated list of selectors + protected function tag(&$tag, $simple = false) { + if ($simple) + $chars = '^@,:;{}\][>\(\) "\''; + else + $chars = '^@,;{}["\''; + + $s = $this->seek(); + + if (!$simple && $this->tagExpression($tag)) { + return true; + } + + $hasExpression = false; + $parts = array(); + while ($this->tagBracket($first)) $parts[] = $first; + + $oldWhite = $this->eatWhiteDefault; + $this->eatWhiteDefault = false; + + while (true) { + if ($this->match('(['.$chars.'0-9]['.$chars.']*)', $m)) { + $parts[] = $m[1]; + if ($simple) break; + + while ($this->tagBracket($brack)) { + $parts[] = $brack; + } + continue; + } + + if (isset($this->buffer[$this->count]) && $this->buffer[$this->count] == "@") { + if ($this->interpolation($interp)) { + $hasExpression = true; + $interp[2] = true; // don't unescape + $parts[] = $interp; + continue; + } + + if ($this->literal("@")) { + $parts[] = "@"; + continue; + } + } + + if ($this->unit($unit)) { // for keyframes + $parts[] = $unit[1]; + $parts[] = $unit[2]; + continue; + } + + break; + } + + $this->eatWhiteDefault = $oldWhite; + if (!$parts) { + $this->seek($s); + return false; + } + + if ($hasExpression) { + $tag = array("exp", array("string", "", $parts)); + } else { + $tag = trim(implode($parts)); + } + + $this->whitespace(); + return true; + } + + // a css function + protected function func(&$func) { + $s = $this->seek(); + + if ($this->match('(%|[\w\-_][\w\-_:\.]+|[\w_])', $m) && $this->literal('(')) { + $fname = $m[1]; + + $sPreArgs = $this->seek(); + + $args = array(); + while (true) { + $ss = $this->seek(); + // this ugly nonsense is for ie filter properties + if ($this->keyword($name) && $this->literal('=') && $this->expressionList($value)) { + $args[] = array("string", "", array($name, "=", $value)); + } else { + $this->seek($ss); + if ($this->expressionList($value)) { + $args[] = $value; + } + } + + if (!$this->literal(',')) break; + } + $args = array('list', ',', $args); + + if ($this->literal(')')) { + $func = array('function', $fname, $args); + return true; + } elseif ($fname == 'url') { + // couldn't parse and in url? treat as string + $this->seek($sPreArgs); + if ($this->openString(")", $string) && $this->literal(")")) { + $func = array('function', $fname, $string); + return true; + } + } + } + + $this->seek($s); + return false; + } + + // consume a less variable + protected function variable(&$name) { + $s = $this->seek(); + if ($this->literal($this->lessc->vPrefix, false) && + ($this->variable($sub) || $this->keyword($name))) + { + if (!empty($sub)) { + $name = array('variable', $sub); + } else { + $name = $this->lessc->vPrefix.$name; + } + return true; + } + + $name = null; + $this->seek($s); + return false; + } + + /** + * Consume an assignment operator + * Can optionally take a name that will be set to the current property name + */ + protected function assign($name = null) { + if ($name) $this->currentProperty = $name; + return $this->literal(':') || $this->literal('='); + } + + // consume a keyword + protected function keyword(&$word) { + if ($this->match('([\w_\-\*!"][\w\-_"]*)', $m)) { + $word = $m[1]; + return true; + } + return false; + } + + // consume an end of statement delimiter + protected function end() { + if ($this->literal(';')) { + return true; + } elseif ($this->count == strlen($this->buffer) || $this->buffer[$this->count] == '}') { + // if there is end of file or a closing block next then we don't need a ; + return true; + } + return false; + } + + protected function guards(&$guards) { + $s = $this->seek(); + + if (!$this->literal("when")) { + $this->seek($s); + return false; + } + + $guards = array(); + + while ($this->guardGroup($g)) { + $guards[] = $g; + if (!$this->literal(",")) break; + } + + if (count($guards) == 0) { + $guards = null; + $this->seek($s); + return false; + } + + return true; + } + + // a bunch of guards that are and'd together + // TODO rename to guardGroup + protected function guardGroup(&$guardGroup) { + $s = $this->seek(); + $guardGroup = array(); + while ($this->guard($guard)) { + $guardGroup[] = $guard; + if (!$this->literal("and")) break; + } + + if (count($guardGroup) == 0) { + $guardGroup = null; + $this->seek($s); + return false; + } + + return true; + } + + protected function guard(&$guard) { + $s = $this->seek(); + $negate = $this->literal("not"); + + if ($this->literal("(") && $this->expression($exp) && $this->literal(")")) { + $guard = $exp; + if ($negate) $guard = array("negate", $guard); + return true; + } + + $this->seek($s); + return false; + } + + /* raw parsing functions */ + + protected function literal($what, $eatWhitespace = null) { + if ($eatWhitespace === null) $eatWhitespace = $this->eatWhiteDefault; + + // shortcut on single letter + if (!isset($what[1]) && isset($this->buffer[$this->count])) { + if ($this->buffer[$this->count] == $what) { + if (!$eatWhitespace) { + $this->count++; + return true; + } + // goes below... + } else { + return false; + } + } + + if (!isset(self::$literalCache[$what])) { + self::$literalCache[$what] = lessc::preg_quote($what); + } + + return $this->match(self::$literalCache[$what], $m, $eatWhitespace); + } + + protected function genericList(&$out, $parseItem, $delim="", $flatten=true) { + $s = $this->seek(); + $items = array(); + while ($this->$parseItem($value)) { + $items[] = $value; + if ($delim) { + if (!$this->literal($delim)) break; + } + } + + if (count($items) == 0) { + $this->seek($s); + return false; + } + + if ($flatten && count($items) == 1) { + $out = $items[0]; + } else { + $out = array("list", $delim, $items); + } + + return true; + } + + + // advance counter to next occurrence of $what + // $until - don't include $what in advance + // $allowNewline, if string, will be used as valid char set + protected function to($what, &$out, $until = false, $allowNewline = false) { + if (is_string($allowNewline)) { + $validChars = $allowNewline; + } else { + $validChars = $allowNewline ? "." : "[^\n]"; + } + if (!$this->match('('.$validChars.'*?)'.lessc::preg_quote($what), $m, !$until)) return false; + if ($until) $this->count -= strlen($what); // give back $what + $out = $m[1]; + return true; + } + + // try to match something on head of buffer + protected function match($regex, &$out, $eatWhitespace = null) { + if ($eatWhitespace === null) $eatWhitespace = $this->eatWhiteDefault; + + $r = '/'.$regex.($eatWhitespace && !$this->writeComments ? '\s*' : '').'/Ais'; + if (preg_match($r, $this->buffer, $out, null, $this->count)) { + $this->count += strlen($out[0]); + if ($eatWhitespace && $this->writeComments) $this->whitespace(); + return true; + } + return false; + } + + // match some whitespace + protected function whitespace() { + if ($this->writeComments) { + $gotWhite = false; + while (preg_match(self::$whitePattern, $this->buffer, $m, null, $this->count)) { + if (isset($m[1]) && empty($this->commentsSeen[$this->count])) { + $this->append(array("comment", $m[1])); + $this->commentsSeen[$this->count] = true; + } + $this->count += strlen($m[0]); + $gotWhite = true; + } + return $gotWhite; + } else { + $this->match("", $m); + return strlen($m[0]) > 0; + } + } + + // match something without consuming it + protected function peek($regex, &$out = null, $from=null) { + if (is_null($from)) $from = $this->count; + $r = '/'.$regex.'/Ais'; + $result = preg_match($r, $this->buffer, $out, null, $from); + + return $result; + } + + // seek to a spot in the buffer or return where we are on no argument + protected function seek($where = null) { + if ($where === null) return $this->count; + else $this->count = $where; + return true; + } + + /* misc functions */ + + public function throwError($msg = "parse error", $count = null) { + $count = is_null($count) ? $this->count : $count; + + $line = $this->line + + substr_count(substr($this->buffer, 0, $count), "\n"); + + if (!empty($this->sourceName)) { + $loc = "$this->sourceName on line $line"; + } else { + $loc = "line: $line"; + } + + // TODO this depends on $this->count + if ($this->peek("(.*?)(\n|$)", $m, $count)) { + throw new exception("$msg: failed at `$m[1]` $loc"); + } else { + throw new exception("$msg: $loc"); + } + } + + protected function pushBlock($selectors=null, $type=null) { + $b = new stdclass; + $b->parent = $this->env; + + $b->type = $type; + $b->id = self::$nextBlockId++; + + $b->isVararg = false; // TODO: kill me from here + $b->tags = $selectors; + + $b->props = array(); + $b->children = array(); + + $this->env = $b; + return $b; + } + + // push a block that doesn't multiply tags + protected function pushSpecialBlock($type) { + return $this->pushBlock(null, $type); + } + + // append a property to the current block + protected function append($prop, $pos = null) { + if ($pos !== null) $prop[-1] = $pos; + $this->env->props[] = $prop; + } + + // pop something off the stack + protected function pop() { + $old = $this->env; + $this->env = $this->env->parent; + return $old; + } + + // remove comments from $text + // todo: make it work for all functions, not just url + protected function removeComments($text) { + $look = array( + 'url(', '//', '/*', '"', "'" + ); + + $out = ''; + $min = null; + while (true) { + // find the next item + foreach ($look as $token) { + $pos = strpos($text, $token); + if ($pos !== false) { + if (!isset($min) || $pos < $min[1]) $min = array($token, $pos); + } + } + + if (is_null($min)) break; + + $count = $min[1]; + $skip = 0; + $newlines = 0; + switch ($min[0]) { + case 'url(': + if (preg_match('/url\(.*?\)/', $text, $m, 0, $count)) + $count += strlen($m[0]) - strlen($min[0]); + break; + case '"': + case "'": + if (preg_match('/'.$min[0].'.*?'.$min[0].'/', $text, $m, 0, $count)) + $count += strlen($m[0]) - 1; + break; + case '//': + $skip = strpos($text, "\n", $count); + if ($skip === false) $skip = strlen($text) - $count; + else $skip -= $count; + break; + case '/*': + if (preg_match('/\/\*.*?\*\//s', $text, $m, 0, $count)) { + $skip = strlen($m[0]); + $newlines = substr_count($m[0], "\n"); + } + break; + } + + if ($skip == 0) $count += strlen($min[0]); + + $out .= substr($text, 0, $count).str_repeat("\n", $newlines); + $text = substr($text, $count + $skip); + + $min = null; + } + + return $out.$text; + } + +} + +class lessc_formatter_classic { + public $indentChar = " "; + + public $break = "\n"; + public $open = " {"; + public $close = "}"; + public $selectorSeparator = ", "; + public $assignSeparator = ":"; + + public $openSingle = " { "; + public $closeSingle = " }"; + + public $disableSingle = false; + public $breakSelectors = false; + + public $compressColors = false; + + public function __construct() { + $this->indentLevel = 0; + } + + public function indentStr($n = 0) { + return str_repeat($this->indentChar, max($this->indentLevel + $n, 0)); + } + + public function property($name, $value) { + return $name . $this->assignSeparator . $value . ";"; + } + + protected function isEmpty($block) { + if (empty($block->lines)) { + foreach ($block->children as $child) { + if (!$this->isEmpty($child)) return false; + } + + return true; + } + return false; + } + + public function block($block) { + if ($this->isEmpty($block)) return; + + $inner = $pre = $this->indentStr(); + + $isSingle = !$this->disableSingle && + is_null($block->type) && count($block->lines) == 1; + + if (!empty($block->selectors)) { + $this->indentLevel++; + + if ($this->breakSelectors) { + $selectorSeparator = $this->selectorSeparator . $this->break . $pre; + } else { + $selectorSeparator = $this->selectorSeparator; + } + + echo $pre . + implode($selectorSeparator, $block->selectors); + if ($isSingle) { + echo $this->openSingle; + $inner = ""; + } else { + echo $this->open . $this->break; + $inner = $this->indentStr(); + } + + } + + if (!empty($block->lines)) { + $glue = $this->break.$inner; + echo $inner . implode($glue, $block->lines); + if (!$isSingle && !empty($block->children)) { + echo $this->break; + } + } + + foreach ($block->children as $child) { + $this->block($child); + } + + if (!empty($block->selectors)) { + if (!$isSingle && empty($block->children)) echo $this->break; + + if ($isSingle) { + echo $this->closeSingle . $this->break; + } else { + echo $pre . $this->close . $this->break; + } + + $this->indentLevel--; + } + } +} + +class lessc_formatter_compressed extends lessc_formatter_classic { + public $disableSingle = true; + public $open = "{"; + public $selectorSeparator = ","; + public $assignSeparator = ":"; + public $break = ""; + public $compressColors = true; + + public function indentStr($n = 0) { + return ""; + } +} + +class lessc_formatter_lessjs extends lessc_formatter_classic { + public $disableSingle = true; + public $breakSelectors = true; + public $assignSeparator = ": "; + public $selectorSeparator = ","; +} + + -- cgit v1.2.3 From 627fc03f93cc74f443af98f4fbf25564cc24d3fc Mon Sep 17 00:00:00 2001 From: Guy Brand Date: Tue, 30 Jul 2013 11:10:34 +0200 Subject: Fix for the FS#1833 parser error --- inc/parser/parser.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/inc/parser/parser.php b/inc/parser/parser.php index 915899f53..6aef3fda5 100644 --- a/inc/parser/parser.php +++ b/inc/parser/parser.php @@ -454,8 +454,8 @@ class Doku_Parser_Mode_table extends Doku_Parser_Mode { } function connectTo($mode) { - $this->Lexer->addEntryPattern('\n\^',$mode,'table'); - $this->Lexer->addEntryPattern('\n\|',$mode,'table'); + $this->Lexer->addEntryPattern('\s*\n\^',$mode,'table'); + $this->Lexer->addEntryPattern('\s*\n\|',$mode,'table'); } function postConnect() { -- cgit v1.2.3 From 9f8068d2077ef7add4108b4a8593764a39518d8d Mon Sep 17 00:00:00 2001 From: Mohamed Amine BERGAOUI Date: Tue, 30 Jul 2013 11:21:18 +0200 Subject: moving ACL remote functions to the ACL plugin --- inc/RemoteAPICore.php | 25 ++----------------------- lib/plugins/acl/remote.php | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 23 deletions(-) create mode 100644 lib/plugins/acl/remote.php diff --git a/inc/RemoteAPICore.php b/inc/RemoteAPICore.php index 022dc37ed..4c940b39e 100644 --- a/inc/RemoteAPICore.php +++ b/inc/RemoteAPICore.php @@ -149,17 +149,8 @@ class RemoteAPICore { 'return' => 'int', 'doc' => 'Returns 2 with the supported RPC API version.', 'public' => '1' - ), 'dokuwiki.addAcl' => array( - 'args' => array('string','string','int'), - 'return' => 'int', - 'name' => 'addAcl', - 'doc' => 'Adds a new ACL rule.' - ), 'dokuwiki.delAcl' => array( - 'args' => array('string','string'), - 'return' => 'int', - 'name' => 'delAcl', - 'doc' => 'Delete an existing ACL rule.' - ), + ), + ); } @@ -776,17 +767,6 @@ class RemoteAPICore { return $ok; } - - - function addAcl($scope, $user, $level){ - $apa = new admin_plugin_acl(); - return $apa->_acl_add($scope, $user, $level); - } - - function delAcl($scope, $user){ - $apa = new admin_plugin_acl(); - return $apa->_acl_del($scope, $user); - } private function resolvePageId($id) { $id = cleanID($id); @@ -799,4 +779,3 @@ class RemoteAPICore { } - diff --git a/lib/plugins/acl/remote.php b/lib/plugins/acl/remote.php new file mode 100644 index 000000000..8210e5414 --- /dev/null +++ b/lib/plugins/acl/remote.php @@ -0,0 +1,32 @@ + array( + 'args' => array('string','string','int'), + 'return' => 'int', + 'name' => 'addAcl', + 'doc' => 'Adds a new ACL rule.' + ), 'plugin.delAcl' => array( + 'args' => array('string','string'), + 'return' => 'int', + 'name' => 'delAcl', + 'doc' => 'Delete an existing ACL rule.' + ), + ); + } + + + function addAcl($scope, $user, $level){ + $apa = new admin_plugin_acl(); + return $apa->_acl_add($scope, $user, $level); + } + + function delAcl($scope, $user){ + $apa = new admin_plugin_acl(); + return $apa->_acl_del($scope, $user); + } +} + +?> -- cgit v1.2.3 From 1b7fc214a838c5f460f865cc7712364a8ec8f3e7 Mon Sep 17 00:00:00 2001 From: Mohamed Amine BERGAOUI Date: Tue, 30 Jul 2013 12:03:23 +0200 Subject: corrected coding style, deleted ?>, renamed function keys and used plugin_load --- lib/plugins/acl/remote.php | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/lib/plugins/acl/remote.php b/lib/plugins/acl/remote.php index 8210e5414..8f6dfbcd9 100644 --- a/lib/plugins/acl/remote.php +++ b/lib/plugins/acl/remote.php @@ -1,32 +1,30 @@ array( + 'addAcl' => array( 'args' => array('string','string','int'), 'return' => 'int', 'name' => 'addAcl', 'doc' => 'Adds a new ACL rule.' - ), 'plugin.delAcl' => array( + ), 'delAcl' => array( 'args' => array('string','string'), 'return' => 'int', 'name' => 'delAcl', 'doc' => 'Delete an existing ACL rule.' - ), + ), ); } - - function addAcl($scope, $user, $level){ - $apa = new admin_plugin_acl(); - return $apa->_acl_add($scope, $user, $level); - } + function addAcl($scope, $user, $level){ + $apa = plugin_load('admin', 'acl'); + return $apa->_acl_add($scope, $user, $level); + } - function delAcl($scope, $user){ - $apa = new admin_plugin_acl(); - return $apa->_acl_del($scope, $user); - } + function delAcl($scope, $user){ + $apa = plugin_load('admin', 'acl'); + return $apa->_acl_del($scope, $user); + } } -?> -- cgit v1.2.3 From c51b334ee77310dc0055311092f224be0342cd65 Mon Sep 17 00:00:00 2001 From: Andreas Gohr Date: Tue, 30 Jul 2013 12:07:15 +0200 Subject: fixed ini replacement to less variables stuff --- lib/exe/css.php | 6 +- lib/tpl/dokuwiki/css/design.css | 405 --------------------------------------- lib/tpl/dokuwiki/css/design.less | 405 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 409 insertions(+), 407 deletions(-) delete mode 100644 lib/tpl/dokuwiki/css/design.css create mode 100644 lib/tpl/dokuwiki/css/design.less diff --git a/lib/exe/css.php b/lib/exe/css.php index 4a9c825c1..04516e8ba 100644 --- a/lib/exe/css.php +++ b/lib/exe/css.php @@ -191,11 +191,13 @@ function css_applystyle($css,$tplinc){ $css = strtr($css,$styleini['replacements']); $less = ''; - foreach($styleini as $key => $value){ + foreach($styleini['replacements'] as $key => $value){ $key = trim($key, '_'); $key = '@ini_'.$key; - $less .= "$key: $value\n"; + $less .= "$key: $value;\n"; } + + $css = $less.$css; } return $css; } diff --git a/lib/tpl/dokuwiki/css/design.css b/lib/tpl/dokuwiki/css/design.css deleted file mode 100644 index 457414839..000000000 --- a/lib/tpl/dokuwiki/css/design.css +++ /dev/null @@ -1,405 +0,0 @@ -/** - * This file provides the main design styles for the - * bits that surround the content. - * - * @author Anika Henke - * @author Andreas Gohr - * @author Clarence Lee - */ - -/* header -********************************************************************/ - -#dokuwiki__header { - padding: 2em 0 1.5em; -} - -#dokuwiki__header .headings, -#dokuwiki__header .tools { - margin-bottom: 1.5em; - width: 49%; -} -#dokuwiki__header h1 img { - float: left; - margin-right: .5em; -} -[dir=rtl] #dokuwiki__header h1 img { - float: right; - margin-left: .5em; - margin-right: 0; -} -#dokuwiki__header h1 span { - display: block; - padding-top: 10px; -} -#dokuwiki__header h1 { - margin: 0; - font-size: 1.5em; - font-weight: normal; -} -#dokuwiki__header h1 a { - text-decoration: none; - color: __text__; - background-color: inherit; -} -#dokuwiki__header h1 a:hover, -#dokuwiki__header h1 a:active, -#dokuwiki__header h1 a:focus { -} -#dokuwiki__header p.claim { - margin-bottom: 0; - font-size: 0.875em; -} - -#dokuwiki__header .tools { - margin-top: .2em; -} - - -/* tools -********************************************************************/ - -/* highlight selected tool */ -.mode_admin a.action.admin, -.mode_login a.action.login, -.mode_register a.action.register, -.mode_profile a.action.profile, -.mode_recent a.action.recent, -.mode_index a.action.index, -.mode_media a.action.media, -.mode_revisions a.action.revs, -.mode_backlink a.action.backlink, -.mode_subscribe a.action.subscribe { - font-weight: bold; -} - -#dokuwiki__header .tools ul { - padding-left: 0; - margin-bottom: 0; -} -#dokuwiki__header .tools li { - font-size: 0.875em; - margin-left: 1em; - list-style: none; - display: inline; -} -[dir=rtl] #dokuwiki__header .tools li { - margin-right: 1em; - margin-left: 0; -} -#dokuwiki__header .tools form.search div.ajax_qsearch li { - font-size: 1em; - margin-left: 0; - display: block; - overflow: hidden; - text-overflow: ellipsis; -} - -#dokuwiki__usertools a.action { - padding-left: 20px; - background: transparent url(images/usertools.png) no-repeat 0 0; -} -[dir=rtl] #dokuwiki__usertools a.action { - padding-left: 0; - padding-right: 20px; -} -[dir=rtl] #IE7 #dokuwiki__usertools a.action { - display: inline-block; -} - - -#dokuwiki__header .mobileTools { - display: none; /* hide mobile tools dropdown to only show in mobile view */ -} - -/*____________ user tools ____________*/ - -#dokuwiki__usertools { - position: absolute; - top: .5em; - right: .5em; - text-align: right; - width: 100%; -} -[dir=rtl] #dokuwiki__usertools { - text-align: left; - left: 40px; - right: auto; -} -#dokuwiki__usertools ul { - margin: 0 auto; - padding: 0; - max-width: __site_width__; -} -#dokuwiki__usertools ul li.user { -} - -#dokuwiki__usertools a.action.admin { - background-position: left 0; -} -[dir=rtl] #dokuwiki__usertools a.action.admin { - background-position: right 0; -} -#dokuwiki__usertools a.action.profile { - background-position: left -32px; -} -[dir=rtl] #dokuwiki__usertools a.action.profile { - background-position: right -32px; -} -#dokuwiki__usertools a.action.register { - background-position: left -64px; -} -[dir=rtl] #dokuwiki__usertools a.action.register { - background-position: right -64px; -} -#dokuwiki__usertools a.action.login { - background-position: left -96px; -} -[dir=rtl] #dokuwiki__usertools a.action.login { - background-position: right -96px; -} -#dokuwiki__usertools a.action.logout { - background-position: left -128px; -} -[dir=rtl] #dokuwiki__usertools a.action.logout { - background-position: right -128px; -} - - -/*____________ site tools ____________*/ - -#dokuwiki__sitetools { - text-align: right; -} -[dir=rtl] #dokuwiki__sitetools { - text-align: left; -} - -#dokuwiki__sitetools form.search { - display: block; - font-size: 0.875em; - position: relative; -} -#IE7 #dokuwiki__sitetools form.search { - min-height: 1px; - z-index: 21; -} -#dokuwiki__sitetools form.search input.edit { - width: 18em; - padding: .35em 22px .35em .1em; -} -[dir=rtl] #dokuwiki__sitetools form.search input.edit { - padding: .35em .1em .35em 22px; -} -#dokuwiki__sitetools form.search input.button { - background: transparent url(images/search.png) no-repeat 0 0; - border-width: 0; - width: 19px; - height: 14px; - text-indent: -99999px; - margin-left: -20px; - box-shadow: none; - padding: 0; -} -[dir=rtl] #dokuwiki__sitetools form.search input.button { - background-position: 5px 0; - margin-left: 0; - margin-right: -20px; - position: relative; -} - -#dokuwiki__sitetools ul { - margin-top: 0.5em; -} -#dokuwiki__sitetools li { -} - -/*____________ breadcrumbs ____________*/ - -.dokuwiki div.breadcrumbs { - border-top: 1px solid __border__; - border-bottom: 1px solid __background__; - margin-bottom: .5em; - font-size: 0.875em; - clear: both; -} -.dokuwiki div.breadcrumbs div { - padding: .1em .35em; -} - -.dokuwiki div.breadcrumbs div:only-child { - border-top: 1px solid __background__; - border-bottom: 1px solid __border__; -} -.dokuwiki div.breadcrumbs div:first-child { - border-top: 1px solid __background__; -} -#IE7 .dokuwiki div.breadcrumbs div, -#IE8 .dokuwiki div.breadcrumbs div { - border-bottom: 1px solid __border__; -} -.dokuwiki div.breadcrumbs div:last-child { - border-bottom: 1px solid __border__; -} - -.dokuwiki div.breadcrumbs a { - color: __link__; - background-color: inherit; -} -.dokuwiki div.breadcrumbs .bcsep { - font-size: 0.75em; -} - - -/* sidebar -********************************************************************/ - -#dokuwiki__aside { -} -#dokuwiki__aside > .pad { - font-size: 0.875em; - overflow: hidden; - word-wrap: break-word; -} - -/* make sidebar more condensed */ - -#dokuwiki__aside h1 { - font-size: 1.714em; - margin-bottom: .292em; -} -#dokuwiki__aside h2 { - margin-bottom: .333em; -} -#dokuwiki__aside h3 { - margin-bottom: .444em; -} -#dokuwiki__aside h4 { - margin-bottom: .5em; -} -#dokuwiki__aside h5 { - margin-bottom: .5714em; -} - -#dokuwiki__aside p, -#dokuwiki__aside ul, -#dokuwiki__aside ol, -#dokuwiki__aside dl, -#dokuwiki__aside pre, -#dokuwiki__aside table, -#dokuwiki__aside fieldset, -#dokuwiki__aside hr, -#dokuwiki__aside blockquote, -#dokuwiki__aside address { - margin-bottom: .7em; -} - -#dokuwiki__aside ul, -#dokuwiki__aside ol { - padding-left: .5em; -} -[dir=rtl] #dokuwiki__aside ul, -[dir=rtl] #dokuwiki__aside ol { - padding-right: .5em; -} -#dokuwiki__aside li ul, -#dokuwiki__aside li ol { - margin-bottom: 0; - padding: 0; -} - -#dokuwiki__aside a:link, -#dokuwiki__aside a:visited { - color: __link__; - background-color: inherit; -} - - -/* content -********************************************************************/ - -#dokuwiki__content { -} - -.dokuwiki .pageId { - position: absolute; - top: -2.3em; - right: -1em; - overflow: hidden; - padding: 1em 1em 0; -} -[dir=rtl] .dokuwiki .pageId { - right: auto; - left: -1em; -} -.dokuwiki .pageId span { - font-size: 0.875em; - border: solid __background_alt__; - border-width: 1px 1px 0; - background-color: __background__; - color: __text_alt__; - padding: .1em .35em; - border-top-left-radius: 2px; - border-top-right-radius: 2px; - box-shadow: 0 0 .5em __text_alt__; - display: block; -} - -.dokuwiki div.page { - background: __background__; - color: inherit; - border: 1px solid __background_alt__; - box-shadow: 0 0 .5em __text_alt__; - border-radius: 2px; - padding: 1.556em 2em 2em; - margin-bottom: .5em; - overflow: hidden; - word-wrap: break-word; -} - -.dokuwiki .docInfo { - font-size: 0.875em; - text-align: right; -} -[dir=rtl] .dokuwiki .docInfo { - text-align: left; -} - -/* license note under edit window */ -.dokuwiki div.license { - font-size: 93.75%; -} - - -/* footer -********************************************************************/ - -.dokuwiki .wrapper { - margin-bottom: 1.4em; -} - -#dokuwiki__footer { - margin-bottom: 1em; - text-align: center; -} -#dokuwiki__footer > .pad { - font-size: 0.875em; -} - -#dokuwiki__footer div.license { - margin-bottom: 0.5em; - font-size: 100%; -} - -[dir=rtl] #dokuwiki__footer .license img { - margin: 0 0 0 .5em; -} - -#dokuwiki__footer div.buttons a img { - opacity: 0.5; -} -#dokuwiki__footer div.buttons a:hover img, -#dokuwiki__footer div.buttons a:active img, -#dokuwiki__footer div.buttons a:focus img { - opacity: 1; -} diff --git a/lib/tpl/dokuwiki/css/design.less b/lib/tpl/dokuwiki/css/design.less new file mode 100644 index 000000000..457414839 --- /dev/null +++ b/lib/tpl/dokuwiki/css/design.less @@ -0,0 +1,405 @@ +/** + * This file provides the main design styles for the + * bits that surround the content. + * + * @author Anika Henke + * @author Andreas Gohr + * @author Clarence Lee + */ + +/* header +********************************************************************/ + +#dokuwiki__header { + padding: 2em 0 1.5em; +} + +#dokuwiki__header .headings, +#dokuwiki__header .tools { + margin-bottom: 1.5em; + width: 49%; +} +#dokuwiki__header h1 img { + float: left; + margin-right: .5em; +} +[dir=rtl] #dokuwiki__header h1 img { + float: right; + margin-left: .5em; + margin-right: 0; +} +#dokuwiki__header h1 span { + display: block; + padding-top: 10px; +} +#dokuwiki__header h1 { + margin: 0; + font-size: 1.5em; + font-weight: normal; +} +#dokuwiki__header h1 a { + text-decoration: none; + color: __text__; + background-color: inherit; +} +#dokuwiki__header h1 a:hover, +#dokuwiki__header h1 a:active, +#dokuwiki__header h1 a:focus { +} +#dokuwiki__header p.claim { + margin-bottom: 0; + font-size: 0.875em; +} + +#dokuwiki__header .tools { + margin-top: .2em; +} + + +/* tools +********************************************************************/ + +/* highlight selected tool */ +.mode_admin a.action.admin, +.mode_login a.action.login, +.mode_register a.action.register, +.mode_profile a.action.profile, +.mode_recent a.action.recent, +.mode_index a.action.index, +.mode_media a.action.media, +.mode_revisions a.action.revs, +.mode_backlink a.action.backlink, +.mode_subscribe a.action.subscribe { + font-weight: bold; +} + +#dokuwiki__header .tools ul { + padding-left: 0; + margin-bottom: 0; +} +#dokuwiki__header .tools li { + font-size: 0.875em; + margin-left: 1em; + list-style: none; + display: inline; +} +[dir=rtl] #dokuwiki__header .tools li { + margin-right: 1em; + margin-left: 0; +} +#dokuwiki__header .tools form.search div.ajax_qsearch li { + font-size: 1em; + margin-left: 0; + display: block; + overflow: hidden; + text-overflow: ellipsis; +} + +#dokuwiki__usertools a.action { + padding-left: 20px; + background: transparent url(images/usertools.png) no-repeat 0 0; +} +[dir=rtl] #dokuwiki__usertools a.action { + padding-left: 0; + padding-right: 20px; +} +[dir=rtl] #IE7 #dokuwiki__usertools a.action { + display: inline-block; +} + + +#dokuwiki__header .mobileTools { + display: none; /* hide mobile tools dropdown to only show in mobile view */ +} + +/*____________ user tools ____________*/ + +#dokuwiki__usertools { + position: absolute; + top: .5em; + right: .5em; + text-align: right; + width: 100%; +} +[dir=rtl] #dokuwiki__usertools { + text-align: left; + left: 40px; + right: auto; +} +#dokuwiki__usertools ul { + margin: 0 auto; + padding: 0; + max-width: __site_width__; +} +#dokuwiki__usertools ul li.user { +} + +#dokuwiki__usertools a.action.admin { + background-position: left 0; +} +[dir=rtl] #dokuwiki__usertools a.action.admin { + background-position: right 0; +} +#dokuwiki__usertools a.action.profile { + background-position: left -32px; +} +[dir=rtl] #dokuwiki__usertools a.action.profile { + background-position: right -32px; +} +#dokuwiki__usertools a.action.register { + background-position: left -64px; +} +[dir=rtl] #dokuwiki__usertools a.action.register { + background-position: right -64px; +} +#dokuwiki__usertools a.action.login { + background-position: left -96px; +} +[dir=rtl] #dokuwiki__usertools a.action.login { + background-position: right -96px; +} +#dokuwiki__usertools a.action.logout { + background-position: left -128px; +} +[dir=rtl] #dokuwiki__usertools a.action.logout { + background-position: right -128px; +} + + +/*____________ site tools ____________*/ + +#dokuwiki__sitetools { + text-align: right; +} +[dir=rtl] #dokuwiki__sitetools { + text-align: left; +} + +#dokuwiki__sitetools form.search { + display: block; + font-size: 0.875em; + position: relative; +} +#IE7 #dokuwiki__sitetools form.search { + min-height: 1px; + z-index: 21; +} +#dokuwiki__sitetools form.search input.edit { + width: 18em; + padding: .35em 22px .35em .1em; +} +[dir=rtl] #dokuwiki__sitetools form.search input.edit { + padding: .35em .1em .35em 22px; +} +#dokuwiki__sitetools form.search input.button { + background: transparent url(images/search.png) no-repeat 0 0; + border-width: 0; + width: 19px; + height: 14px; + text-indent: -99999px; + margin-left: -20px; + box-shadow: none; + padding: 0; +} +[dir=rtl] #dokuwiki__sitetools form.search input.button { + background-position: 5px 0; + margin-left: 0; + margin-right: -20px; + position: relative; +} + +#dokuwiki__sitetools ul { + margin-top: 0.5em; +} +#dokuwiki__sitetools li { +} + +/*____________ breadcrumbs ____________*/ + +.dokuwiki div.breadcrumbs { + border-top: 1px solid __border__; + border-bottom: 1px solid __background__; + margin-bottom: .5em; + font-size: 0.875em; + clear: both; +} +.dokuwiki div.breadcrumbs div { + padding: .1em .35em; +} + +.dokuwiki div.breadcrumbs div:only-child { + border-top: 1px solid __background__; + border-bottom: 1px solid __border__; +} +.dokuwiki div.breadcrumbs div:first-child { + border-top: 1px solid __background__; +} +#IE7 .dokuwiki div.breadcrumbs div, +#IE8 .dokuwiki div.breadcrumbs div { + border-bottom: 1px solid __border__; +} +.dokuwiki div.breadcrumbs div:last-child { + border-bottom: 1px solid __border__; +} + +.dokuwiki div.breadcrumbs a { + color: __link__; + background-color: inherit; +} +.dokuwiki div.breadcrumbs .bcsep { + font-size: 0.75em; +} + + +/* sidebar +********************************************************************/ + +#dokuwiki__aside { +} +#dokuwiki__aside > .pad { + font-size: 0.875em; + overflow: hidden; + word-wrap: break-word; +} + +/* make sidebar more condensed */ + +#dokuwiki__aside h1 { + font-size: 1.714em; + margin-bottom: .292em; +} +#dokuwiki__aside h2 { + margin-bottom: .333em; +} +#dokuwiki__aside h3 { + margin-bottom: .444em; +} +#dokuwiki__aside h4 { + margin-bottom: .5em; +} +#dokuwiki__aside h5 { + margin-bottom: .5714em; +} + +#dokuwiki__aside p, +#dokuwiki__aside ul, +#dokuwiki__aside ol, +#dokuwiki__aside dl, +#dokuwiki__aside pre, +#dokuwiki__aside table, +#dokuwiki__aside fieldset, +#dokuwiki__aside hr, +#dokuwiki__aside blockquote, +#dokuwiki__aside address { + margin-bottom: .7em; +} + +#dokuwiki__aside ul, +#dokuwiki__aside ol { + padding-left: .5em; +} +[dir=rtl] #dokuwiki__aside ul, +[dir=rtl] #dokuwiki__aside ol { + padding-right: .5em; +} +#dokuwiki__aside li ul, +#dokuwiki__aside li ol { + margin-bottom: 0; + padding: 0; +} + +#dokuwiki__aside a:link, +#dokuwiki__aside a:visited { + color: __link__; + background-color: inherit; +} + + +/* content +********************************************************************/ + +#dokuwiki__content { +} + +.dokuwiki .pageId { + position: absolute; + top: -2.3em; + right: -1em; + overflow: hidden; + padding: 1em 1em 0; +} +[dir=rtl] .dokuwiki .pageId { + right: auto; + left: -1em; +} +.dokuwiki .pageId span { + font-size: 0.875em; + border: solid __background_alt__; + border-width: 1px 1px 0; + background-color: __background__; + color: __text_alt__; + padding: .1em .35em; + border-top-left-radius: 2px; + border-top-right-radius: 2px; + box-shadow: 0 0 .5em __text_alt__; + display: block; +} + +.dokuwiki div.page { + background: __background__; + color: inherit; + border: 1px solid __background_alt__; + box-shadow: 0 0 .5em __text_alt__; + border-radius: 2px; + padding: 1.556em 2em 2em; + margin-bottom: .5em; + overflow: hidden; + word-wrap: break-word; +} + +.dokuwiki .docInfo { + font-size: 0.875em; + text-align: right; +} +[dir=rtl] .dokuwiki .docInfo { + text-align: left; +} + +/* license note under edit window */ +.dokuwiki div.license { + font-size: 93.75%; +} + + +/* footer +********************************************************************/ + +.dokuwiki .wrapper { + margin-bottom: 1.4em; +} + +#dokuwiki__footer { + margin-bottom: 1em; + text-align: center; +} +#dokuwiki__footer > .pad { + font-size: 0.875em; +} + +#dokuwiki__footer div.license { + margin-bottom: 0.5em; + font-size: 100%; +} + +[dir=rtl] #dokuwiki__footer .license img { + margin: 0 0 0 .5em; +} + +#dokuwiki__footer div.buttons a img { + opacity: 0.5; +} +#dokuwiki__footer div.buttons a:hover img, +#dokuwiki__footer div.buttons a:active img, +#dokuwiki__footer div.buttons a:focus img { + opacity: 1; +} -- cgit v1.2.3 From c19c611efcf1cdfe0c1798defdda02809fb19be9 Mon Sep 17 00:00:00 2001 From: Andreas Gohr Date: Tue, 30 Jul 2013 12:09:59 +0200 Subject: lessyfied the first of template's CSS files --- lib/tpl/dokuwiki/css/design.less | 582 +++++++++++++++++++++------------------ lib/tpl/dokuwiki/style.ini | 2 +- 2 files changed, 311 insertions(+), 273 deletions(-) diff --git a/lib/tpl/dokuwiki/css/design.less b/lib/tpl/dokuwiki/css/design.less index 457414839..aba9c9c7b 100644 --- a/lib/tpl/dokuwiki/css/design.less +++ b/lib/tpl/dokuwiki/css/design.less @@ -12,49 +12,49 @@ #dokuwiki__header { padding: 2em 0 1.5em; -} -#dokuwiki__header .headings, -#dokuwiki__header .tools { - margin-bottom: 1.5em; - width: 49%; -} -#dokuwiki__header h1 img { - float: left; - margin-right: .5em; + .headings, + .tools { + margin-bottom: 1.5em; + width: 49%; + } + .tools { + margin-top: .2em; + } + + h1 { + margin: 0; + font-size: 1.5em; + font-weight: normal; + + img { + float: left; + margin-right: .5em; + } + + span { + display: block; + padding-top: 10px; + } + + a { + text-decoration: none; + color: @ini_text; + background-color: inherit; + } + } + + p.claim { + margin-bottom: 0; + font-size: 0.875em; + } } + [dir=rtl] #dokuwiki__header h1 img { float: right; margin-left: .5em; margin-right: 0; } -#dokuwiki__header h1 span { - display: block; - padding-top: 10px; -} -#dokuwiki__header h1 { - margin: 0; - font-size: 1.5em; - font-weight: normal; -} -#dokuwiki__header h1 a { - text-decoration: none; - color: __text__; - background-color: inherit; -} -#dokuwiki__header h1 a:hover, -#dokuwiki__header h1 a:active, -#dokuwiki__header h1 a:focus { -} -#dokuwiki__header p.claim { - margin-bottom: 0; - font-size: 0.875em; -} - -#dokuwiki__header .tools { - margin-top: .2em; -} - /* tools ********************************************************************/ @@ -73,41 +73,49 @@ font-weight: bold; } -#dokuwiki__header .tools ul { - padding-left: 0; - margin-bottom: 0; -} -#dokuwiki__header .tools li { - font-size: 0.875em; - margin-left: 1em; - list-style: none; - display: inline; +#dokuwiki__header .tools { + ul { + padding-left: 0; + margin-bottom: 0; + } + + li { + font-size: 0.875em; + margin-left: 1em; + list-style: none; + display: inline; + } + + form.search div.ajax_qsearch li { + font-size: 1em; + margin-left: 0; + display: block; + overflow: hidden; + text-overflow: ellipsis; + } } + [dir=rtl] #dokuwiki__header .tools li { margin-right: 1em; margin-left: 0; } -#dokuwiki__header .tools form.search div.ajax_qsearch li { - font-size: 1em; - margin-left: 0; - display: block; - overflow: hidden; - text-overflow: ellipsis; -} -#dokuwiki__usertools a.action { - padding-left: 20px; - background: transparent url(images/usertools.png) no-repeat 0 0; +#dokuwiki__usertools { + a.action { + padding-left: 20px; + background: transparent url(images/usertools.png) no-repeat 0 0; + } } + [dir=rtl] #dokuwiki__usertools a.action { padding-left: 0; padding-right: 20px; } + [dir=rtl] #IE7 #dokuwiki__usertools a.action { display: inline-block; } - #dokuwiki__header .mobileTools { display: none; /* hide mobile tools dropdown to only show in mobile view */ } @@ -120,257 +128,285 @@ right: .5em; text-align: right; width: 100%; + + ul { + margin: 0 auto; + padding: 0; + max-width: @ini_site_width; + } + + a.action.admin { + background-position: left 0; + } + + a.action.profile { + background-position: left -32px; + } + + a.action.register { + background-position: left -64px; + } + + a.action.login { + background-position: left -96px; + } + + a.action.logout { + background-position: left -128px; + } } + [dir=rtl] #dokuwiki__usertools { text-align: left; left: 40px; right: auto; -} -#dokuwiki__usertools ul { - margin: 0 auto; - padding: 0; - max-width: __site_width__; -} -#dokuwiki__usertools ul li.user { -} -#dokuwiki__usertools a.action.admin { - background-position: left 0; -} -[dir=rtl] #dokuwiki__usertools a.action.admin { - background-position: right 0; -} -#dokuwiki__usertools a.action.profile { - background-position: left -32px; -} -[dir=rtl] #dokuwiki__usertools a.action.profile { - background-position: right -32px; -} -#dokuwiki__usertools a.action.register { - background-position: left -64px; -} -[dir=rtl] #dokuwiki__usertools a.action.register { - background-position: right -64px; -} -#dokuwiki__usertools a.action.login { - background-position: left -96px; -} -[dir=rtl] #dokuwiki__usertools a.action.login { - background-position: right -96px; -} -#dokuwiki__usertools a.action.logout { - background-position: left -128px; -} -[dir=rtl] #dokuwiki__usertools a.action.logout { - background-position: right -128px; -} + a.action.admin { + background-position: right 0; + } + + a.action.profile { + background-position: right -32px; + } + a.action.register { + background-position: right -64px; + } + + a.action.login { + background-position: right -96px; + } + + a.action.logout { + background-position: right -128px; + } +} /*____________ site tools ____________*/ #dokuwiki__sitetools { text-align: right; + + form.search { + display: block; + font-size: 0.875em; + position: relative; + + input.edit { + width: 18em; + padding: .35em 22px .35em .1em; + } + + input.button { + background: transparent url(images/search.png) no-repeat 0 0; + border-width: 0; + width: 19px; + height: 14px; + text-indent: -99999px; + margin-left: -20px; + box-shadow: none; + padding: 0; + } + } + + ul { + margin-top: 0.5em; + } } + [dir=rtl] #dokuwiki__sitetools { text-align: left; -} -#dokuwiki__sitetools form.search { - display: block; - font-size: 0.875em; - position: relative; + form.search { + input.edit { + padding: .35em .1em .35em 22px; + } + + input.button { + background-position: 5px 0; + margin-left: 0; + margin-right: -20px; + position: relative; + } + } } + #IE7 #dokuwiki__sitetools form.search { min-height: 1px; z-index: 21; } -#dokuwiki__sitetools form.search input.edit { - width: 18em; - padding: .35em 22px .35em .1em; -} -[dir=rtl] #dokuwiki__sitetools form.search input.edit { - padding: .35em .1em .35em 22px; -} -#dokuwiki__sitetools form.search input.button { - background: transparent url(images/search.png) no-repeat 0 0; - border-width: 0; - width: 19px; - height: 14px; - text-indent: -99999px; - margin-left: -20px; - box-shadow: none; - padding: 0; -} -[dir=rtl] #dokuwiki__sitetools form.search input.button { - background-position: 5px 0; - margin-left: 0; - margin-right: -20px; - position: relative; -} - -#dokuwiki__sitetools ul { - margin-top: 0.5em; -} -#dokuwiki__sitetools li { -} /*____________ breadcrumbs ____________*/ .dokuwiki div.breadcrumbs { - border-top: 1px solid __border__; - border-bottom: 1px solid __background__; + border-top: 1px solid @ini_border; + border-bottom: 1px solid @ini_background; margin-bottom: .5em; font-size: 0.875em; clear: both; -} -.dokuwiki div.breadcrumbs div { - padding: .1em .35em; -} -.dokuwiki div.breadcrumbs div:only-child { - border-top: 1px solid __background__; - border-bottom: 1px solid __border__; -} -.dokuwiki div.breadcrumbs div:first-child { - border-top: 1px solid __background__; + div { + padding: .1em .35em; + } + + div:only-child { + border-top: 1px solid @ini_background; + border-bottom: 1px solid @ini_border; + } + + div:first-child { + border-top: 1px solid @ini_background; + } + + div:last-child { + border-bottom: 1px solid @ini_border; + } + + a { + color: @ini_link; + background-color: inherit; + } + + .bcsep { + font-size: 0.75em; + } } + #IE7 .dokuwiki div.breadcrumbs div, #IE8 .dokuwiki div.breadcrumbs div { - border-bottom: 1px solid __border__; -} -.dokuwiki div.breadcrumbs div:last-child { - border-bottom: 1px solid __border__; -} - -.dokuwiki div.breadcrumbs a { - color: __link__; - background-color: inherit; -} -.dokuwiki div.breadcrumbs .bcsep { - font-size: 0.75em; + border-bottom: 1px solid @ini_border; } - /* sidebar ********************************************************************/ #dokuwiki__aside { -} -#dokuwiki__aside > .pad { - font-size: 0.875em; - overflow: hidden; - word-wrap: break-word; -} -/* make sidebar more condensed */ - -#dokuwiki__aside h1 { - font-size: 1.714em; - margin-bottom: .292em; -} -#dokuwiki__aside h2 { - margin-bottom: .333em; -} -#dokuwiki__aside h3 { - margin-bottom: .444em; -} -#dokuwiki__aside h4 { - margin-bottom: .5em; -} -#dokuwiki__aside h5 { - margin-bottom: .5714em; -} - -#dokuwiki__aside p, -#dokuwiki__aside ul, -#dokuwiki__aside ol, -#dokuwiki__aside dl, -#dokuwiki__aside pre, -#dokuwiki__aside table, -#dokuwiki__aside fieldset, -#dokuwiki__aside hr, -#dokuwiki__aside blockquote, -#dokuwiki__aside address { - margin-bottom: .7em; + > .pad { + font-size: 0.875em; + overflow: hidden; + word-wrap: break-word; + } + + /* make sidebar more condensed */ + + h1 { + font-size: 1.714em; + margin-bottom: .292em; + } + + h2 { + margin-bottom: .333em; + } + + h3 { + margin-bottom: .444em; + } + + h4 { + margin-bottom: .5em; + } + + h5 { + margin-bottom: .5714em; + } + + p, + ul, + ol, + dl, + pre, + table, + fieldset, + hr, + blockquote, + address { + margin-bottom: .7em; + } + + ul, + ol { + padding-left: .5em; + } + + li ul, + li ol { + margin-bottom: 0; + padding: 0; + } + + a:link, + a:visited { + color: @ini_link; + background-color: inherit; + } } -#dokuwiki__aside ul, -#dokuwiki__aside ol { - padding-left: .5em; -} [dir=rtl] #dokuwiki__aside ul, [dir=rtl] #dokuwiki__aside ol { padding-right: .5em; } -#dokuwiki__aside li ul, -#dokuwiki__aside li ol { - margin-bottom: 0; - padding: 0; -} - -#dokuwiki__aside a:link, -#dokuwiki__aside a:visited { - color: __link__; - background-color: inherit; -} - /* content ********************************************************************/ -#dokuwiki__content { -} - -.dokuwiki .pageId { - position: absolute; - top: -2.3em; - right: -1em; - overflow: hidden; - padding: 1em 1em 0; -} -[dir=rtl] .dokuwiki .pageId { - right: auto; - left: -1em; -} -.dokuwiki .pageId span { - font-size: 0.875em; - border: solid __background_alt__; - border-width: 1px 1px 0; - background-color: __background__; - color: __text_alt__; - padding: .1em .35em; - border-top-left-radius: 2px; - border-top-right-radius: 2px; - box-shadow: 0 0 .5em __text_alt__; - display: block; -} - -.dokuwiki div.page { - background: __background__; - color: inherit; - border: 1px solid __background_alt__; - box-shadow: 0 0 .5em __text_alt__; - border-radius: 2px; - padding: 1.556em 2em 2em; - margin-bottom: .5em; - overflow: hidden; - word-wrap: break-word; -} - -.dokuwiki .docInfo { - font-size: 0.875em; - text-align: right; -} -[dir=rtl] .dokuwiki .docInfo { - text-align: left; -} - -/* license note under edit window */ -.dokuwiki div.license { - font-size: 93.75%; +.dokuwiki { + + .pageId { + position: absolute; + top: -2.3em; + right: -1em; + overflow: hidden; + padding: 1em 1em 0; + } + + .pageId span { + font-size: 0.875em; + border: solid @ini_background_alt; + border-width: 1px 1px 0; + background-color: @ini_background; + color: @ini_text_alt; + padding: .1em .35em; + border-top-left-radius: 2px; + border-top-right-radius: 2px; + box-shadow: 0 0 .5em @ini_text_alt; + display: block; + } + + div.page { + background: @ini_background; + color: inherit; + border: 1px solid @ini_background_alt; + box-shadow: 0 0 .5em @ini_text_alt; + border-radius: 2px; + padding: 1.556em 2em 2em; + margin-bottom: .5em; + overflow: hidden; + word-wrap: break-word; + } + + .docInfo { + font-size: 0.875em; + text-align: right; + } + + /* license note under edit window */ + div.license { + font-size: 93.75%; + } +} + +[dir=rtl] .dokuwiki { + .docInfo { + text-align: left; + } + + .pageId { + right: auto; + left: -1em; + } } - /* footer ********************************************************************/ @@ -381,25 +417,27 @@ #dokuwiki__footer { margin-bottom: 1em; text-align: center; -} -#dokuwiki__footer > .pad { - font-size: 0.875em; -} -#dokuwiki__footer div.license { - margin-bottom: 0.5em; - font-size: 100%; + > .pad { + font-size: 0.875em; + } + + div.license { + margin-bottom: 0.5em; + font-size: 100%; + } + + div.buttons a img { + opacity: 0.5; + } + + div.buttons a:hover img, + div.buttons a:active img, + div.buttons a:focus img { + opacity: 1; + } } [dir=rtl] #dokuwiki__footer .license img { margin: 0 0 0 .5em; } - -#dokuwiki__footer div.buttons a img { - opacity: 0.5; -} -#dokuwiki__footer div.buttons a:hover img, -#dokuwiki__footer div.buttons a:active img, -#dokuwiki__footer div.buttons a:focus img { - opacity: 1; -} diff --git a/lib/tpl/dokuwiki/style.ini b/lib/tpl/dokuwiki/style.ini index 77bb98236..e4725a4fd 100644 --- a/lib/tpl/dokuwiki/style.ini +++ b/lib/tpl/dokuwiki/style.ini @@ -29,7 +29,7 @@ css/_modal.css = screen css/_forms.css = screen css/_admin.css = screen css/structure.css = screen -css/design.css = screen +css/design.less = screen css/pagetools.css = screen css/content.css = screen css/includes.css = screen -- cgit v1.2.3 From bd9a4965eaaebb5de8ad1c502d2af32c6897e6f1 Mon Sep 17 00:00:00 2001 From: Andreas Gohr Date: Tue, 30 Jul 2013 13:24:13 +0200 Subject: lessyfied another one --- lib/tpl/dokuwiki/css/content.css | 362 ----------------------------------- lib/tpl/dokuwiki/css/content.less | 391 ++++++++++++++++++++++++++++++++++++++ lib/tpl/dokuwiki/css/mixins.less | 15 ++ lib/tpl/dokuwiki/style.ini | 2 + 4 files changed, 408 insertions(+), 362 deletions(-) delete mode 100644 lib/tpl/dokuwiki/css/content.css create mode 100644 lib/tpl/dokuwiki/css/content.less create mode 100644 lib/tpl/dokuwiki/css/mixins.less diff --git a/lib/tpl/dokuwiki/css/content.css b/lib/tpl/dokuwiki/css/content.css deleted file mode 100644 index b1498d4de..000000000 --- a/lib/tpl/dokuwiki/css/content.css +++ /dev/null @@ -1,362 +0,0 @@ -/** - * This file provides the main design styles for the page content. - * - * @author Anika Henke - * @author Andreas Gohr - * @author Clarence Lee - */ - -/*____________ section indenting ____________ - -.dokuwiki .page h1 {margin-left: 0;} -.dokuwiki .page h2 {margin-left: .666em;} -.dokuwiki .page h3 {margin-left: 1.776em;} -.dokuwiki .page h4 {margin-left: 3em;} -.dokuwiki .page h5 {margin-left: 4.5712em;} -.dokuwiki .page div.level1 {margin-left: 0;} -.dokuwiki .page div.level2 {margin-left: 1em;} -.dokuwiki .page div.level3 {margin-left: 2em;} -.dokuwiki .page div.level4 {margin-left: 3em;} -.dokuwiki .page div.level5 {margin-left: 4em;} - -[dir=rtl] .dokuwiki .page h1 {margin-left: 0; margin-right: 0;} -[dir=rtl] .dokuwiki .page h2 {margin-left: 0; margin-right: .666em;} -[dir=rtl] .dokuwiki .page h3 {margin-left: 0; margin-right: 1.776em;} -[dir=rtl] .dokuwiki .page h4 {margin-left: 0; margin-right: 3em;} -[dir=rtl] .dokuwiki .page h5 {margin-left: 0; margin-right: 4.5712em;} -[dir=rtl] .dokuwiki .page div.level1 {margin-left: 0; margin-right: 0;} -[dir=rtl] .dokuwiki .page div.level2 {margin-left: 0; margin-right: 1em;} -[dir=rtl] .dokuwiki .page div.level3 {margin-left: 0; margin-right: 2em;} -[dir=rtl] .dokuwiki .page div.level4 {margin-left: 0; margin-right: 3em;} -[dir=rtl] .dokuwiki .page div.level5 {margin-left: 0; margin-right: 4em;} -*/ -/* hx margin-left = (1 / font-size) * .levelx-margin */ - - -/*____________ links to wiki pages (addition to _links) ____________*/ - -/* existing wikipage */ -.dokuwiki a.wikilink1 { - color: __existing__; - background-color: inherit; -} -/* not existing wikipage */ -.dokuwiki a.wikilink2 { - color: __missing__; - background-color: inherit; -} - - -/*____________ images ____________*/ - -/* embedded images (styles are already partly set in lib/styles/all.css) */ -.dokuwiki img.media { - margin: .2em 0; -} -.dokuwiki img.medialeft { - margin: .2em 1em .2em 0; -} -.dokuwiki img.mediaright { - margin: .2em 0 .2em 1em; -} -.dokuwiki img.mediacenter { - margin: .2em auto; -} - - -/*____________ lists ____________*/ - -#dokuwiki__content ul li, -#dokuwiki__aside ul li { - color: __text_alt__; -} -#dokuwiki__content ol li, -#dokuwiki__aside ol li { - color: __text_neu__; -} -#dokuwiki__content li .li, -#dokuwiki__aside li .li { - color: __text__; -} - - -/*____________ tables ____________*/ - -/* div around each table */ -.dokuwiki div.table { - overflow-x: auto; - margin-bottom: 1.4em; -} -.dokuwiki div.table table { - margin-bottom: 0; -} - -.dokuwiki table.inline { - min-width: 50%; -} -.dokuwiki table.inline tr:hover td { - background-color: __background_alt__; -} -.dokuwiki table.inline tr:hover th { - background-color: __border__; -} - - -/*____________ code ____________*/ - -/* fix if background-color hides underlining */ -.dokuwiki em.u code { - text-decoration: underline; -} - -/* for code in */ -.dokuwiki pre.file { -} - -/* filenames for downloadable file and code blocks */ -.dokuwiki dl.code, -.dokuwiki dl.file { -} - -.dokuwiki dl.code dt, -.dokuwiki dl.file dt { - background-color: __background_site__; - background: -moz-linear-gradient( top, __background_alt__ 0%, __background_site__ 100%); - background: -webkit-linear-gradient(top, __background_alt__ 0%, __background_site__ 100%); - background: -o-linear-gradient( top, __background_alt__ 0%, __background_site__ 100%); - background: -ms-linear-gradient( top, __background_alt__ 0%, __background_site__ 100%); - background: linear-gradient( top, __background_alt__ 0%, __background_site__ 100%); - color: inherit; - border: 1px solid __border__; - border-bottom-color: __background_site__; - border-top-left-radius: .3em; - border-top-right-radius: .3em; - padding: .3em .6em .1em; - margin-bottom: -1px; - float: left; -} -[dir=rtl] .dokuwiki dl.code dt, -[dir=rtl] .dokuwiki dl.file dt { - float: right; -} -.dokuwiki dl.code dt a, -.dokuwiki dl.file dt a { - background-color: transparent; - font-size: 0.875em; - font-weight: normal; - display: block; - min-height: 16px; -} - -.dokuwiki dl.code dd, -.dokuwiki dl.file dd { - margin: 0; - clear: left; - min-height: 1px; /* for IE7 */ -} -[dir=rtl] .dokuwiki dl.code dd, -[dir=rtl] .dokuwiki dl.file dd { - clear: right; -} - -.dokuwiki dl.code pre, -.dokuwiki dl.file pre { - box-shadow: inset -4px -4px .5em -.3em __border__; -} - - -/*____________ JS popup ____________*/ - -.JSpopup { - background-color: __background__; - color: __text__; - border: 1px solid __border__; - box-shadow: .1em .1em .1em __border__; - border-radius: 2px; - padding: .3em .5em; - font-size: .9em; -} -.dokuwiki form.search div.ajax_qsearch { - top: -.35em; - font-size: 1em; - text-overflow: ellipsis; -} - -.JSpopup ul, -.JSpopup ol { - padding-left: 0; -} -[dir=rtl] .JSpopup ul, -[dir=rtl] .JSpopup ol { - padding-right: 0; -} - - -/* changes to underscored CSS files -********************************************************************/ - -#acl__tree li { - margin: 0; -} - -#dokuwiki__content span.curid a { - font-weight: normal; -} -#dokuwiki__content strong span.curid a { - font-weight: bold; -} - - -/*____________ changes to _edit ____________*/ - -.dokuwiki div.toolbar button.toolbutton { - border-radius: 0; - border-left-width: 0; - padding: .1em .35em; -} -.dokuwiki div.toolbar button.toolbutton:first-child { - border-top-left-radius: 4px; - border-bottom-left-radius: 4px; - border-left-width: 1px; -} -[dir=rtl] .dokuwiki div.toolbar button.toolbutton:first-child { - border-top-left-radius: 0; - border-bottom-left-radius: 0; - border-top-right-radius: 4px; - border-bottom-right-radius: 4px; - border-left-width: 0; - border-right-width: 1px; -} -.dokuwiki div.toolbar button.toolbutton:last-child { - border-top-right-radius: 4px; - border-bottom-right-radius: 4px; -} -[dir=rtl] .dokuwiki div.toolbar button.toolbutton:last-child { - border-top-left-radius: 4px; - border-bottom-left-radius: 4px; - border-top-right-radius: 0; - border-bottom-right-radius: 0; - border-left-width: 1px; -} - -.dokuwiki div.section_highlight { - margin: 0 -2em; - padding: 0 1em; - border-width: 0 1em; -} - -.dokuwiki textarea.edit { - font-family: Consolas, "Andale Mono WT", "Andale Mono", "Bitstream Vera Sans Mono", "Nimbus Mono L", Monaco, "Courier New", monospace; -} - -.dokuwiki div.preview { - margin: 0 -2em; - padding: 0 2em; -} -.dokuwiki.hasSidebar div.preview { - border-right: __sidebar_width__ solid __background_alt__; -} -[dir=rtl] .dokuwiki.hasSidebar div.preview { - border-right-width: 0; - border-left: __sidebar_width__ solid __background_alt__; -} -.dokuwiki div.preview div.pad { - padding: 1.556em 0 2em; -} - - -/*____________ changes to _toc ____________*/ - -#dw__toc { - margin: -1.556em -2em .5em 1.4em; - width: __sidebar_width__; - border-left: 1px solid __border__; - background: __background__; - color: inherit; -} -[dir=rtl] #dw__toc { - margin: -1.556em 1.4em .5em -2em; - border-left-width: 0; - border-right: 1px solid __border__; -} - -.dokuwiki h3.toggle { - padding: .5em 1em; - margin-bottom: 0; - font-size: .875em; - letter-spacing: .1em; -} -#dokuwiki__aside h3.toggle { - display: none; -} - -.dokuwiki .toggle strong { - background: transparent url(images/toc-arrows.png) 0 0; - width: 8px; - height: 5px; - margin: .4em 0 0; -} -.dokuwiki .toggle.closed strong { - background-position: 0 -5px; -} - -.dokuwiki .toggle strong span { - display: none; -} - - -#dw__toc > div { - font-size: 0.875em; - padding: .5em 1em 1em; -} -#dw__toc ul { - padding: 0 0 0 1.2em; -} -[dir=rtl] #dw__toc ul { - padding: 0 1.5em 0 0; -} -#dw__toc ul li { - list-style-image: url(images/toc-bullet.png); -} -#dw__toc ul li.clear { - list-style: none; -} -#dw__toc ul li div.li { - padding: .2em 0; -} - - -/*____________ changes to _imgdetail ____________*/ - -#dokuwiki__detail { - padding: 0; -} -#dokuwiki__detail img { - float: none; - margin-bottom: 1.4em; -} -#dokuwiki__detail div.img_detail { - float: none; -} - -#dokuwiki__detail div.img_detail dl { - overflow: hidden; -} -#dokuwiki__detail div.img_detail dl dt { - float: left; - width: 9em; - text-align: right; - clear: left; -} -[dir=rtl] #dokuwiki__detail div.img_detail dl dt { - float: right; - text-align: left; - clear: right; -} -#dokuwiki__detail div.img_detail dl dd { - margin-left: 9.5em; -} -[dir=rtl] #dokuwiki__detail div.img_detail dl dd { - margin-left: 0; - margin-right: 9.5em; -} diff --git a/lib/tpl/dokuwiki/css/content.less b/lib/tpl/dokuwiki/css/content.less new file mode 100644 index 000000000..f6022b4e9 --- /dev/null +++ b/lib/tpl/dokuwiki/css/content.less @@ -0,0 +1,391 @@ +/** + * This file provides the main design styles for the page content. + * + * @author Anika Henke + * @author Andreas Gohr + * @author Clarence Lee + */ + +/*____________ section indenting ____________ + +.dokuwiki .page h1 {margin-left: 0;} +.dokuwiki .page h2 {margin-left: .666em;} +.dokuwiki .page h3 {margin-left: 1.776em;} +.dokuwiki .page h4 {margin-left: 3em;} +.dokuwiki .page h5 {margin-left: 4.5712em;} +.dokuwiki .page div.level1 {margin-left: 0;} +.dokuwiki .page div.level2 {margin-left: 1em;} +.dokuwiki .page div.level3 {margin-left: 2em;} +.dokuwiki .page div.level4 {margin-left: 3em;} +.dokuwiki .page div.level5 {margin-left: 4em;} + +[dir=rtl] .dokuwiki .page h1 {margin-left: 0; margin-right: 0;} +[dir=rtl] .dokuwiki .page h2 {margin-left: 0; margin-right: .666em;} +[dir=rtl] .dokuwiki .page h3 {margin-left: 0; margin-right: 1.776em;} +[dir=rtl] .dokuwiki .page h4 {margin-left: 0; margin-right: 3em;} +[dir=rtl] .dokuwiki .page h5 {margin-left: 0; margin-right: 4.5712em;} +[dir=rtl] .dokuwiki .page div.level1 {margin-left: 0; margin-right: 0;} +[dir=rtl] .dokuwiki .page div.level2 {margin-left: 0; margin-right: 1em;} +[dir=rtl] .dokuwiki .page div.level3 {margin-left: 0; margin-right: 2em;} +[dir=rtl] .dokuwiki .page div.level4 {margin-left: 0; margin-right: 3em;} +[dir=rtl] .dokuwiki .page div.level5 {margin-left: 0; margin-right: 4em;} +*/ +/* hx margin-left = (1 / font-size) * .levelx-margin */ + +/*____________ links to wiki pages (addition to _links) ____________*/ + +/* existing wikipage */ +.dokuwiki a.wikilink1 { + color: @ini_existing; + background-color: inherit; +} + +/* not existing wikipage */ +.dokuwiki a.wikilink2 { + color: @ini_missing; + background-color: inherit; +} + +/*____________ images ____________*/ + +/* embedded images (styles are already partly set in lib/styles/all.css) */ +.dokuwiki img.media { + margin: .2em 0; +} + +.dokuwiki img.medialeft { + margin: .2em 1em .2em 0; +} + +.dokuwiki img.mediaright { + margin: .2em 0 .2em 1em; +} + +.dokuwiki img.mediacenter { + margin: .2em auto; +} + +/*____________ lists ____________*/ + +#dokuwiki__content ul li, +#dokuwiki__aside ul li { + color: @ini_text_alt; +} + +#dokuwiki__content ol li, +#dokuwiki__aside ol li { + color: @ini_text_neu; +} + +#dokuwiki__content li .li, +#dokuwiki__aside li .li { + color: @ini_text; +} + +/*____________ tables ____________*/ + +/* div around each table */ +.dokuwiki div.table { + overflow-x: auto; + margin-bottom: 1.4em; +} + +.dokuwiki div.table table { + margin-bottom: 0; +} + +.dokuwiki table.inline { + min-width: 50%; +} + +.dokuwiki table.inline tr:hover td { + background-color: @ini_background_alt; +} + +.dokuwiki table.inline tr:hover th { + background-color: @ini_border; +} + +/*____________ code ____________*/ + +/* fix if background-color hides underlining */ +.dokuwiki em.u code { + text-decoration: underline; +} + +/* for code in */ +.dokuwiki pre.file { +} + +/* filenames for downloadable file and code blocks */ +.dokuwiki dl.code, +.dokuwiki dl.file { + dt, + dt { + .linear-gradient(@ini_background_site, @ini_background_alt, @ini_background_site); + color: inherit; + border: 1px solid @ini_border; + border-bottom-color: @ini_background_site; + border-top-left-radius: .3em; + border-top-right-radius: .3em; + padding: .3em .6em .1em; + margin-bottom: -1px; + float: left; + } + dt a, + dt a { + background-color: transparent; + font-size: 0.875em; + font-weight: normal; + display: block; + min-height: 16px; + } + + dd, + dd { + margin: 0; + clear: left; + min-height: 1px; /* for IE7 */ + } + + pre, + pre { + box-shadow: inset -4px -4px .5em -.3em @ini_border; + } +} + +[dir=rtl] .dokuwiki dl.code, +[dir=rtl] .dokuwiki dl.file { + dt, + dt { + float: right; + } + + dd, + dd { + clear: right; + } +} + +/*____________ JS popup ____________*/ + +.JSpopup { + background-color: @ini_background; + color: @ini_text; + border: 1px solid @ini_border; + box-shadow: .1em .1em .1em @ini_border; + border-radius: 2px; + padding: .3em .5em; + font-size: .9em; +} + +.dokuwiki form.search div.ajax_qsearch { + top: -.35em; + font-size: 1em; + text-overflow: ellipsis; +} + +.JSpopup ul, +.JSpopup ol { + padding-left: 0; +} + +[dir=rtl] .JSpopup ul, +[dir=rtl] .JSpopup ol { + padding-right: 0; +} + +/* changes to underscored CSS files +********************************************************************/ + +#acl__tree li { + margin: 0; +} + +#dokuwiki__content span.curid a { + font-weight: normal; +} + +#dokuwiki__content strong span.curid a { + font-weight: bold; +} + +/*____________ changes to _edit ____________*/ + +.dokuwiki div.toolbar { + button.toolbutton { + border-radius: 0; + border-left-width: 0; + padding: .1em .35em; + } + + button.toolbutton:first-child { + border-top-left-radius: 4px; + border-bottom-left-radius: 4px; + border-left-width: 1px; + } + + button.toolbutton:last-child { + border-top-right-radius: 4px; + border-bottom-right-radius: 4px; + } +} + +[dir=rtl] .dokuwiki div.toolbar { + button.toolbutton:last-child { + border-top-left-radius: 4px; + border-bottom-left-radius: 4px; + border-top-right-radius: 0; + border-bottom-right-radius: 0; + border-left-width: 1px; + } + + button.toolbutton:first-child { + border-top-left-radius: 0; + border-bottom-left-radius: 0; + border-top-right-radius: 4px; + border-bottom-right-radius: 4px; + border-left-width: 0; + border-right-width: 1px; + } +} + +.dokuwiki div.section_highlight { + margin: 0 -2em; + padding: 0 1em; + border-width: 0 1em; +} + +.dokuwiki textarea.edit { + font-family: Consolas, "Andale Mono WT", "Andale Mono", "Bitstream Vera Sans Mono", "Nimbus Mono L", Monaco, "Courier New", monospace; +} + +.dokuwiki div.preview { + margin: 0 -2em; + padding: 0 2em; +} + +.dokuwiki.hasSidebar div.preview { + border-right: @ini_sidebar_width solid @ini_background_alt; +} + +[dir=rtl] .dokuwiki.hasSidebar div.preview { + border-right-width: 0; + border-left: @ini_sidebar_width solid @ini_background_alt; +} + +.dokuwiki div.preview div.pad { + padding: 1.556em 0 2em; +} + +/*____________ changes to _toc ____________*/ + +#dw__toc { + margin: -1.556em -2em .5em 1.4em; + width: @ini_sidebar_width; + border-left: 1px solid @ini_border; + background: @ini_background; + color: inherit; +} + +[dir=rtl] #dw__toc { + margin: -1.556em 1.4em .5em -2em; + border-left-width: 0; + border-right: 1px solid @ini_border; +} + +.dokuwiki h3.toggle { + padding: .5em 1em; + margin-bottom: 0; + font-size: .875em; + letter-spacing: .1em; +} + +#dokuwiki__aside h3.toggle { + display: none; +} + +.dokuwiki .toggle strong { + background: transparent url(images/toc-arrows.png) 0 0; + width: 8px; + height: 5px; + margin: .4em 0 0; +} + +.dokuwiki .toggle.closed strong { + background-position: 0 -5px; +} + +.dokuwiki .toggle strong span { + display: none; +} + +#dw__toc { + > div { + font-size: 0.875em; + padding: .5em 1em 1em; + } + + ul { + padding: 0 0 0 1.2em; + } + + ul li { + list-style-image: url(images/toc-bullet.png); + } + + ul li.clear { + list-style: none; + } + + ul li div.li { + padding: .2em 0; + } +} + +[dir=rtl] #dw__toc ul { + padding: 0 1.5em 0 0; +} + +/*____________ changes to _imgdetail ____________*/ + +#dokuwiki__detail { + padding: 0; + + img { + float: none; + margin-bottom: 1.4em; + } + + div.img_detail { + float: none; + } + + div.img_detail dl { + overflow: hidden; + } + + div.img_detail dl dt { + float: left; + width: 9em; + text-align: right; + clear: left; + } + + div.img_detail dl dd { + margin-left: 9.5em; + } +} + +[dir=rtl] #dokuwiki__detail div.img_detail { + dl dt { + float: right; + text-align: left; + clear: right; + } + + dl dd { + margin-left: 0; + margin-right: 9.5em; + } +} \ No newline at end of file diff --git a/lib/tpl/dokuwiki/css/mixins.less b/lib/tpl/dokuwiki/css/mixins.less new file mode 100644 index 000000000..7ecae4a0b --- /dev/null +++ b/lib/tpl/dokuwiki/css/mixins.less @@ -0,0 +1,15 @@ +/** + * linear gradient x-browser support + * + * @param color fallback background color + * @param start start color + * @param stop end color + */ +.linear-gradient(@color: #F5F5F5, @start: #EEE, @stop: #FFF) { + background: @color; + background: -moz-linear-gradient( top, @start 0%, @stop 100%); + background: -webkit-linear-gradient(top, @start 0%, @stop 100%); + background: -o-linear-gradient( top, @start 0%, @stop 100%); + background: -ms-linear-gradient( top, @start 0%, @stop 100%); + background: linear-gradient( top, @start 0%, @stop 100%); +} \ No newline at end of file diff --git a/lib/tpl/dokuwiki/style.ini b/lib/tpl/dokuwiki/style.ini index e4725a4fd..9cf6cb64f 100644 --- a/lib/tpl/dokuwiki/style.ini +++ b/lib/tpl/dokuwiki/style.ini @@ -12,6 +12,8 @@ [stylesheets] +css/mixins.less = screen + css/basic.css = screen css/_imgdetail.css = screen css/_media_popup.css = screen -- cgit v1.2.3 From 45d3363005120ca17df1184280e1a9df0fddc062 Mon Sep 17 00:00:00 2001 From: Andreas Gohr Date: Tue, 30 Jul 2013 14:48:06 +0200 Subject: lessified more files --- lib/tpl/dokuwiki/css/basic.css | 468 ------------------------------------ lib/tpl/dokuwiki/css/basic.less | 460 +++++++++++++++++++++++++++++++++++ lib/tpl/dokuwiki/css/content.less | 3 +- lib/tpl/dokuwiki/css/includes.css | 4 - lib/tpl/dokuwiki/css/mixins.less | 17 +- lib/tpl/dokuwiki/css/mobile.css | 288 ---------------------- lib/tpl/dokuwiki/css/mobile.less | 288 ++++++++++++++++++++++ lib/tpl/dokuwiki/css/pagetools.css | 421 -------------------------------- lib/tpl/dokuwiki/css/pagetools.less | 421 ++++++++++++++++++++++++++++++++ lib/tpl/dokuwiki/css/structure.css | 81 ------- lib/tpl/dokuwiki/css/structure.less | 94 ++++++++ lib/tpl/dokuwiki/style.ini | 14 +- 12 files changed, 1280 insertions(+), 1279 deletions(-) delete mode 100644 lib/tpl/dokuwiki/css/basic.css create mode 100644 lib/tpl/dokuwiki/css/basic.less delete mode 100644 lib/tpl/dokuwiki/css/includes.css delete mode 100644 lib/tpl/dokuwiki/css/mobile.css create mode 100644 lib/tpl/dokuwiki/css/mobile.less delete mode 100644 lib/tpl/dokuwiki/css/pagetools.css create mode 100644 lib/tpl/dokuwiki/css/pagetools.less delete mode 100644 lib/tpl/dokuwiki/css/structure.css create mode 100644 lib/tpl/dokuwiki/css/structure.less diff --git a/lib/tpl/dokuwiki/css/basic.css b/lib/tpl/dokuwiki/css/basic.css deleted file mode 100644 index ad04f7c41..000000000 --- a/lib/tpl/dokuwiki/css/basic.css +++ /dev/null @@ -1,468 +0,0 @@ -/** - * This file provides the most basic styles. - * - * If you integrate DokuWiki into another project, you might either - * want to integrate this file into the other project as well, or use - * the other project's basic CSS for DokuWiki instead of this one. - * - * @author Anika Henke - */ - -html { - overflow-x: auto; - overflow-y: scroll; -} -html, -body { - color: __text__; - background: __background_site__ url(images/page-gradient.png) top left repeat-x; - margin: 0; - padding: 0; -} -body { - font: normal 87.5%/1.4 Arial, sans-serif; - /* default font size: 100% => 16px; 93.75% => 15px; 87.5% => 14px; 81.25% => 13px; 75% => 12px */ - -webkit-text-size-adjust: 100%; -} - - -/*____________ headers ____________*/ - -caption, -figcaption, -summary, -legend { - padding: 0; - margin: 0 0 .35em; - line-height: 1.2; -} -h1, -h2, -h3, -h4, -h5, -h6 { - font-weight: bold; - padding: 0; - line-height: 1.2; - clear: left; /* ideally 'both', but problems with toc */ -} -[dir=rtl] h1, -[dir=rtl] h2, -[dir=rtl] h3, -[dir=rtl] h4, -[dir=rtl] h5, -[dir=rtl] h6 { - clear: right; -} - -h1 { - font-size: 2em; - margin: 0 0 0.444em; -} -h2 { - font-size: 1.5em; - margin: 0 0 0.666em; -} -h3 { - font-size: 1.125em; - margin: 0 0 0.888em; -} -h4 { - font-size: 1em; - margin: 0 0 1.0em; -} -h5 { - font-size: .875em; - margin: 0 0 1.1428em; -} -h6 { - font-size: .75em; - margin: 0 0 1.333em; -} -/* bottom margin = 1 / font-size */ - - -/*____________ basic margins and paddings ____________*/ - -p, -ul, -ol, -dl, -pre, -table, -hr, -blockquote, -figure, -details, -fieldset, -address { - margin: 0 0 1.4em 0; /* bottom margin = line-height */ - padding: 0; -} - -div { - margin: 0; - padding: 0; -} - - -/*____________ lists ____________*/ - -ul, -ol { - padding: 0 0 0 1.5em; -} -[dir=rtl] ul, -[dir=rtl] ol { - padding: 0 1.5em 0 0; -} - -li, -dd { - padding: 0; - margin: 0 0 0 1.5em; -} -[dir=rtl] li, -[dir=rtl] dd { - margin: 0 1.5em 0 0; -} -dt { - font-weight: bold; - margin: 0; - padding: 0; -} - -li ul, -li ol, -li dl, -dl ul, -dl ol, -dl dl { - margin-bottom: 0; - padding: 0; -} -li li { - font-size: 100%; -} - -ul { list-style: square outside; } -ol { list-style: decimal outside; } -ol ol { list-style-type: lower-alpha; } -ol ol ol { list-style-type: upper-roman; } -ol ol ol ol { list-style-type: upper-alpha; } -ol ol ol ol ol { list-style-type: lower-roman; } - - -/*____________ tables ____________*/ - -table { - border-collapse: collapse; - empty-cells: show; - border-spacing: 0; - border: 1px solid __border__; -} - -caption { - caption-side: top; - text-align: left; -} -[dir=rtl] caption { - text-align: right; -} - -th, -td { - padding: .3em .5em; - margin: 0; - vertical-align: top; - border: 1px solid __border__; -} -th { - font-weight: bold; - background-color: __background_alt__; - text-align: left; -} -[dir=rtl] th { - text-align: right; -} - - -/*____________ links ____________*/ - -a { - outline: none; -} -a:link, -a:visited { - text-decoration: none; - color: __link__; -} -a:link:hover, -a:visited:hover, -a:link:focus, -a:visited:focus, -a:link:active, -a:visited:active { - text-decoration: underline; -} - - -/*____________ misc ____________*/ - -img { - border-width: 0; - vertical-align: middle; - color: #666; - background-color: transparent; - font-style: italic; - height: auto; -} -img, -object, -embed, -iframe, -video, -audio { - max-width: 100%; -} -#IE7 img, -#IE8 img, -button img { - max-width: none; -} - -hr { - border-top: solid __border__; - border-bottom: solid __background__; - border-width: 1px 0; - height: 0; - text-align: center; - clear: both; -} - -acronym, -abbr { - cursor: help; - border-bottom: 1px dotted; - font-style: normal; -} -em acronym, -em abbr { - font-style: italic; -} - -mark { - background-color: __highlight__; - color: inherit; -} - -pre, -code, -samp, -kbd { - font-family: Consolas, "Andale Mono WT", "Andale Mono", "Bitstream Vera Sans Mono", "Nimbus Mono L", Monaco, "Courier New", monospace; - /* same font stack should be used for ".dokuwiki table.diff td" in _diff.css */ - font-size: 1em; - direction: ltr; - text-align: left; - background-color: __background_site__; - color: __text__; - box-shadow: inset 0 0 .3em __border__; - border-radius: 2px; -} -pre { - overflow: auto; - word-wrap: normal; - border: 1px solid __border__; - border-radius: 2px; - box-shadow: inset 0 0 .5em __border__; - padding: .7em 1em; -} - -blockquote { - padding: 0 .5em; - border: solid __border__; - border-width: 0 0 0 .25em; -} -[dir=rtl] blockquote { - border-width: 0 .25em 0 0; -} -q:before, -q:after { - content: ''; -} - -sub, -sup { - font-size: .8em; - line-height: 1; -} -sub { - vertical-align: sub; -} -sup { - vertical-align: super; -} - -small { - font-size: .8em; -} - -/*____________ forms ____________*/ - -/* for all of the form styles, style.ini colours are not used on purpose (except for fieldset border) */ - -form { - display: inline; - margin: 0; - padding: 0; -} -fieldset { - padding: .7em 1em 0; - padding: .7rem 1rem; /* for those browsers understanding :last-child */ - border: 1px solid __text_alt__; -} -fieldset > :last-child { - margin-bottom: 0; -} -legend { - margin: 0; - padding: 0 .1em; -} -label { - vertical-align: middle; - cursor: pointer; -} - -input, -textarea, -button, -select, -optgroup, -option, -keygen, -output, -meter, -progress { - font: inherit; - font-weight: normal; - color: #333; - background-color: #fff; - line-height: normal; - margin: 0; - vertical-align: middle; - -moz-box-sizing: border-box; - -webkit-box-sizing: border-box; - box-sizing: border-box; -} - -optgroup { - font-style: italic; - font-weight: bold; -} -option { - font-style: normal; - font-weight: normal; -} - -input, -textarea, -select, -keygen { - border: 1px solid #ccc; - box-shadow: inset 0 0 1px #eee; - border-radius: 2px; -} -input:active, -input:focus, -textarea:active, -textarea:focus, -select:active, -select:focus, -keygen:active, -keygen:focus { - border-color: #999; -} -input[type=radio], -input[type=checkbox], -input[type=image] { - padding: 0; - border-style: none; - box-shadow: none; -} - -/* all types of buttons */ -input[type=submit], -input[type=button], -input[type=reset], -input.button, -a.button, -button, -.qq-upload-button { - color: #333; - background-color: #eee; - background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIHZpZXdCb3g9IjAgMCAxIDEiIHByZXNlcnZlQXNwZWN0UmF0aW89Im5vbmUiPgo8bGluZWFyR3JhZGllbnQgaWQ9Imc4MjQiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIiB4MT0iMCUiIHkxPSIwJSIgeDI9IjAlIiB5Mj0iMTAwJSI+CjxzdG9wIHN0b3AtY29sb3I9IiNGRkZGRkYiIG9mZnNldD0iMCIvPjxzdG9wIHN0b3AtY29sb3I9IiNGNEY0RjQiIG9mZnNldD0iMC4zIi8+PHN0b3Agc3RvcC1jb2xvcj0iI0VFRUVFRSIgb2Zmc2V0PSIwLjk5Ii8+PHN0b3Agc3RvcC1jb2xvcj0iI0NDQ0NDQyIgb2Zmc2V0PSIuOTkiLz4KPC9saW5lYXJHcmFkaWVudD4KPHJlY3QgeD0iMCIgeT0iMCIgd2lkdGg9IjEiIGhlaWdodD0iMSIgZmlsbD0idXJsKCNnODI0KSIgLz4KPC9zdmc+); - background: -moz-linear-gradient( top, #ffffff 0%, #f4f4f4 30%, #eeeeee 99%, #cccccc 99%); - background: -webkit-linear-gradient(top, #ffffff 0%, #f4f4f4 30%, #eeeeee 99%, #cccccc 99%); - background: -o-linear-gradient( top, #ffffff 0%, #f4f4f4 30%, #eeeeee 99%, #cccccc 99%); - background: -ms-linear-gradient( top, #ffffff 0%, #f4f4f4 30%, #eeeeee 99%, #cccccc 99%); - background: linear-gradient( top, #ffffff 0%, #f4f4f4 30%, #eeeeee 99%, #cccccc 99%); - border: 1px solid #ccc; - border-radius: 2px; - padding: .1em .5em; - cursor: pointer; -} -#IE7 input.button, -#IE7 button { - line-height: 1.4; - overflow: visible; -} - -input[type=submit]:hover, -input[type=submit]:active, -input[type=submit]:focus, -input[type=button]:hover, -input[type=button]:active, -input[type=button]:hover, -input[type=reset]:hover, -input[type=reset]:active, -input[type=reset]:hover, -input.button:hover, -input.button:active, -input.button:focus, -a.button:hover, -a.button:active, -a.button:focus, -button:hover, -button:active, -button:focus, -.qq-upload-button:hover { - border-color: #999; - background-color: #ddd; - background-image:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIHZpZXdCb3g9IjAgMCAxIDEiIHByZXNlcnZlQXNwZWN0UmF0aW89Im5vbmUiPgo8bGluZWFyR3JhZGllbnQgaWQ9Imc2NzAiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIiB4MT0iMCUiIHkxPSIwJSIgeDI9IjAlIiB5Mj0iMTAwJSI+CjxzdG9wIHN0b3AtY29sb3I9IiNGRkZGRkYiIG9mZnNldD0iMCIvPjxzdG9wIHN0b3AtY29sb3I9IiNGNEY0RjQiIG9mZnNldD0iMC4zIi8+PHN0b3Agc3RvcC1jb2xvcj0iI0RERERERCIgb2Zmc2V0PSIwLjk5Ii8+PHN0b3Agc3RvcC1jb2xvcj0iI0JCQkJCQiIgb2Zmc2V0PSIuOTkiLz4KPC9saW5lYXJHcmFkaWVudD4KPHJlY3QgeD0iMCIgeT0iMCIgd2lkdGg9IjEiIGhlaWdodD0iMSIgZmlsbD0idXJsKCNnNjcwKSIgLz4KPC9zdmc+); - background: -moz-linear-gradient( top, #ffffff 0%, #f4f4f4 30%, #dddddd 99%, #bbbbbb 99%); - background: -webkit-linear-gradient(top, #ffffff 0%, #f4f4f4 30%, #dddddd 99%, #bbbbbb 99%); - background: -o-linear-gradient( top, #ffffff 0%, #f4f4f4 30%, #dddddd 99%, #bbbbbb 99%); - background: -ms-linear-gradient( top, #ffffff 0%, #f4f4f4 30%, #dddddd 99%, #bbbbbb 99%); - background: linear-gradient( top, #ffffff 0%, #f4f4f4 30%, #dddddd 99%, #bbbbbb 99%); -} - -input::-moz-focus-inner, -button::-moz-focus-inner { - border: 0; - padding: 0; -} - -input[disabled], -button[disabled], -select[disabled], -textarea[disabled], -input[readonly], -button[readonly], -select[readonly], -textarea[readonly] { - cursor: auto; - opacity: .5; - background-color: #eee; -} diff --git a/lib/tpl/dokuwiki/css/basic.less b/lib/tpl/dokuwiki/css/basic.less new file mode 100644 index 000000000..1dd56813e --- /dev/null +++ b/lib/tpl/dokuwiki/css/basic.less @@ -0,0 +1,460 @@ +/** + * This file provides the most basic styles. + * + * If you integrate DokuWiki into another project, you might either + * want to integrate this file into the other project as well, or use + * the other project's basic CSS for DokuWiki instead of this one. + * + * @author Anika Henke + */ + +html { + overflow-x: auto; + overflow-y: scroll; +} +html, +body { + color: @ini_text; + background: @ini_background_site url(images/page-gradient.png) top left repeat-x; + margin: 0; + padding: 0; +} +body { + font: normal 87.5%/1.4 Arial, sans-serif; + /* default font size: 100% => 16px; 93.75% => 15px; 87.5% => 14px; 81.25% => 13px; 75% => 12px */ + -webkit-text-size-adjust: 100%; +} + + +/*____________ headers ____________*/ + +caption, +figcaption, +summary, +legend { + padding: 0; + margin: 0 0 .35em; + line-height: 1.2; +} +h1, +h2, +h3, +h4, +h5, +h6 { + font-weight: bold; + padding: 0; + line-height: 1.2; + clear: left; /* ideally 'both', but problems with toc */ +} +[dir=rtl] h1, +[dir=rtl] h2, +[dir=rtl] h3, +[dir=rtl] h4, +[dir=rtl] h5, +[dir=rtl] h6 { + clear: right; +} + +h1 { + font-size: 2em; + margin: 0 0 0.444em; +} +h2 { + font-size: 1.5em; + margin: 0 0 0.666em; +} +h3 { + font-size: 1.125em; + margin: 0 0 0.888em; +} +h4 { + font-size: 1em; + margin: 0 0 1.0em; +} +h5 { + font-size: .875em; + margin: 0 0 1.1428em; +} +h6 { + font-size: .75em; + margin: 0 0 1.333em; +} +/* bottom margin = 1 / font-size */ + + +/*____________ basic margins and paddings ____________*/ + +p, +ul, +ol, +dl, +pre, +table, +hr, +blockquote, +figure, +details, +fieldset, +address { + margin: 0 0 1.4em 0; /* bottom margin = line-height */ + padding: 0; +} + +div { + margin: 0; + padding: 0; +} + + +/*____________ lists ____________*/ + +ul, +ol { + padding: 0 0 0 1.5em; +} +[dir=rtl] ul, +[dir=rtl] ol { + padding: 0 1.5em 0 0; +} + +li, +dd { + padding: 0; + margin: 0 0 0 1.5em; +} +[dir=rtl] li, +[dir=rtl] dd { + margin: 0 1.5em 0 0; +} +dt { + font-weight: bold; + margin: 0; + padding: 0; +} + +li ul, +li ol, +li dl, +dl ul, +dl ol, +dl dl { + margin-bottom: 0; + padding: 0; +} +li li { + font-size: 100%; +} + +ul { list-style: square outside; } +ol { list-style: decimal outside; } +ol ol { list-style-type: lower-alpha; } +ol ol ol { list-style-type: upper-roman; } +ol ol ol ol { list-style-type: upper-alpha; } +ol ol ol ol ol { list-style-type: lower-roman; } + + +/*____________ tables ____________*/ + +table { + border-collapse: collapse; + empty-cells: show; + border-spacing: 0; + border: 1px solid @ini_border; +} + +caption { + caption-side: top; + text-align: left; +} +[dir=rtl] caption { + text-align: right; +} + +th, +td { + padding: .3em .5em; + margin: 0; + vertical-align: top; + border: 1px solid @ini_border; +} +th { + font-weight: bold; + background-color: @ini_background_alt; + text-align: left; +} +[dir=rtl] th { + text-align: right; +} + + +/*____________ links ____________*/ + +a { + outline: none; +} +a:link, +a:visited { + text-decoration: none; + color: @ini_link; +} +a:link:hover, +a:visited:hover, +a:link:focus, +a:visited:focus, +a:link:active, +a:visited:active { + text-decoration: underline; +} + + +/*____________ misc ____________*/ + +img { + border-width: 0; + vertical-align: middle; + color: #666; + background-color: transparent; + font-style: italic; + height: auto; +} +img, +object, +embed, +iframe, +video, +audio { + max-width: 100%; +} +#IE7 img, +#IE8 img, +button img { + max-width: none; +} + +hr { + border-top: solid @ini_border; + border-bottom: solid @ini_background; + border-width: 1px 0; + height: 0; + text-align: center; + clear: both; +} + +acronym, +abbr { + cursor: help; + border-bottom: 1px dotted; + font-style: normal; +} +em acronym, +em abbr { + font-style: italic; +} + +mark { + background-color: @ini_highlight; + color: inherit; +} + +pre, +code, +samp, +kbd { + font-family: Consolas, "Andale Mono WT", "Andale Mono", "Bitstream Vera Sans Mono", "Nimbus Mono L", Monaco, "Courier New", monospace; + /* same font stack should be used for ".dokuwiki table.diff td" in _diff.css */ + font-size: 1em; + direction: ltr; + text-align: left; + background-color: @ini_background_site; + color: @ini_text; + box-shadow: inset 0 0 .3em @ini_border; + border-radius: 2px; +} +pre { + overflow: auto; + word-wrap: normal; + border: 1px solid @ini_border; + border-radius: 2px; + box-shadow: inset 0 0 .5em @ini_border; + padding: .7em 1em; +} + +blockquote { + padding: 0 .5em; + border: solid @ini_border; + border-width: 0 0 0 .25em; +} +[dir=rtl] blockquote { + border-width: 0 .25em 0 0; +} +q:before, +q:after { + content: ''; +} + +sub, +sup { + font-size: .8em; + line-height: 1; +} +sub { + vertical-align: sub; +} +sup { + vertical-align: super; +} + +small { + font-size: .8em; +} + +/*____________ forms ____________*/ + +/* for all of the form styles, style.ini colours are not used on purpose (except for fieldset border) */ + +form { + display: inline; + margin: 0; + padding: 0; +} +fieldset { + padding: .7em 1em 0; + padding: .7rem 1rem; /* for those browsers understanding :last-child */ + border: 1px solid @ini_text_alt; +} +fieldset > :last-child { + margin-bottom: 0; +} +legend { + margin: 0; + padding: 0 .1em; +} +label { + vertical-align: middle; + cursor: pointer; +} + +input, +textarea, +button, +select, +optgroup, +option, +keygen, +output, +meter, +progress { + font: inherit; + font-weight: normal; + color: #333; + background-color: #fff; + line-height: normal; + margin: 0; + vertical-align: middle; + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; + box-sizing: border-box; +} + +optgroup { + font-style: italic; + font-weight: bold; +} +option { + font-style: normal; + font-weight: normal; +} + +input, +textarea, +select, +keygen { + border: 1px solid #ccc; + box-shadow: inset 0 0 1px #eee; + border-radius: 2px; +} +input:active, +input:focus, +textarea:active, +textarea:focus, +select:active, +select:focus, +keygen:active, +keygen:focus { + border-color: #999; +} +input[type=radio], +input[type=checkbox], +input[type=image] { + padding: 0; + border-style: none; + box-shadow: none; +} + +/* all types of buttons */ +input[type=submit], +input[type=button], +input[type=reset], +input.button, +a.button, +button, +.qq-upload-button { + color: #333; + background-color: #eee; + background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIHZpZXdCb3g9IjAgMCAxIDEiIHByZXNlcnZlQXNwZWN0UmF0aW89Im5vbmUiPgo8bGluZWFyR3JhZGllbnQgaWQ9Imc4MjQiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIiB4MT0iMCUiIHkxPSIwJSIgeDI9IjAlIiB5Mj0iMTAwJSI+CjxzdG9wIHN0b3AtY29sb3I9IiNGRkZGRkYiIG9mZnNldD0iMCIvPjxzdG9wIHN0b3AtY29sb3I9IiNGNEY0RjQiIG9mZnNldD0iMC4zIi8+PHN0b3Agc3RvcC1jb2xvcj0iI0VFRUVFRSIgb2Zmc2V0PSIwLjk5Ii8+PHN0b3Agc3RvcC1jb2xvcj0iI0NDQ0NDQyIgb2Zmc2V0PSIuOTkiLz4KPC9saW5lYXJHcmFkaWVudD4KPHJlY3QgeD0iMCIgeT0iMCIgd2lkdGg9IjEiIGhlaWdodD0iMSIgZmlsbD0idXJsKCNnODI0KSIgLz4KPC9zdmc+); + .linear-gradient("top, #ffffff 0%, #f4f4f4 30%, #eeeeee 99%, #cccccc 99%"); + border: 1px solid #ccc; + border-radius: 2px; + padding: .1em .5em; + cursor: pointer; +} +#IE7 input.button, +#IE7 button { + line-height: 1.4; + overflow: visible; +} + +input[type=submit]:hover, +input[type=submit]:active, +input[type=submit]:focus, +input[type=button]:hover, +input[type=button]:active, +input[type=button]:hover, +input[type=reset]:hover, +input[type=reset]:active, +input[type=reset]:hover, +input.button:hover, +input.button:active, +input.button:focus, +a.button:hover, +a.button:active, +a.button:focus, +button:hover, +button:active, +button:focus, +.qq-upload-button:hover { + border-color: #999; + background-color: #ddd; + background-image:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIHZpZXdCb3g9IjAgMCAxIDEiIHByZXNlcnZlQXNwZWN0UmF0aW89Im5vbmUiPgo8bGluZWFyR3JhZGllbnQgaWQ9Imc2NzAiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIiB4MT0iMCUiIHkxPSIwJSIgeDI9IjAlIiB5Mj0iMTAwJSI+CjxzdG9wIHN0b3AtY29sb3I9IiNGRkZGRkYiIG9mZnNldD0iMCIvPjxzdG9wIHN0b3AtY29sb3I9IiNGNEY0RjQiIG9mZnNldD0iMC4zIi8+PHN0b3Agc3RvcC1jb2xvcj0iI0RERERERCIgb2Zmc2V0PSIwLjk5Ii8+PHN0b3Agc3RvcC1jb2xvcj0iI0JCQkJCQiIgb2Zmc2V0PSIuOTkiLz4KPC9saW5lYXJHcmFkaWVudD4KPHJlY3QgeD0iMCIgeT0iMCIgd2lkdGg9IjEiIGhlaWdodD0iMSIgZmlsbD0idXJsKCNnNjcwKSIgLz4KPC9zdmc+); + .linear-gradient("top, #ffffff 0%, #f4f4f4 30%, #dddddd 99%, #bbbbbb 99%"); +} + +input::-moz-focus-inner, +button::-moz-focus-inner { + border: 0; + padding: 0; +} + +input[disabled], +button[disabled], +select[disabled], +textarea[disabled], +input[readonly], +button[readonly], +select[readonly], +textarea[readonly] { + cursor: auto; + opacity: .5; + background-color: #eee; +} diff --git a/lib/tpl/dokuwiki/css/content.less b/lib/tpl/dokuwiki/css/content.less index f6022b4e9..ae97d7d5e 100644 --- a/lib/tpl/dokuwiki/css/content.less +++ b/lib/tpl/dokuwiki/css/content.less @@ -122,7 +122,8 @@ .dokuwiki dl.file { dt, dt { - .linear-gradient(@ini_background_site, @ini_background_alt, @ini_background_site); + background-color: @ini_background_site; + .linear-gradient(~"top, @{ini_background_alt} 0%, @{ini_background_site} 100%"); color: inherit; border: 1px solid @ini_border; border-bottom-color: @ini_background_site; diff --git a/lib/tpl/dokuwiki/css/includes.css b/lib/tpl/dokuwiki/css/includes.css deleted file mode 100644 index bc189962f..000000000 --- a/lib/tpl/dokuwiki/css/includes.css +++ /dev/null @@ -1,4 +0,0 @@ -/** - * This file provides styles for included seperate html files - * (added through "include hooks"). - */ diff --git a/lib/tpl/dokuwiki/css/mixins.less b/lib/tpl/dokuwiki/css/mixins.less index 7ecae4a0b..a88767e97 100644 --- a/lib/tpl/dokuwiki/css/mixins.less +++ b/lib/tpl/dokuwiki/css/mixins.less @@ -1,15 +1,10 @@ /** * linear gradient x-browser support - * - * @param color fallback background color - * @param start start color - * @param stop end color */ -.linear-gradient(@color: #F5F5F5, @start: #EEE, @stop: #FFF) { - background: @color; - background: -moz-linear-gradient( top, @start 0%, @stop 100%); - background: -webkit-linear-gradient(top, @start 0%, @stop 100%); - background: -o-linear-gradient( top, @start 0%, @stop 100%); - background: -ms-linear-gradient( top, @start 0%, @stop 100%); - background: linear-gradient( top, @start 0%, @stop 100%); +.linear-gradient(@declaration: 0) { + background: -moz-linear-gradient( @declaration); + background: -webkit-linear-gradient(@declaration); + background: -o-linear-gradient( @declaration); + background: -ms-linear-gradient( @declaration); + background: linear-gradient( @declaration); } \ No newline at end of file diff --git a/lib/tpl/dokuwiki/css/mobile.css b/lib/tpl/dokuwiki/css/mobile.css deleted file mode 100644 index 71f80599d..000000000 --- a/lib/tpl/dokuwiki/css/mobile.css +++ /dev/null @@ -1,288 +0,0 @@ -/** - * This file provides styles for mobile devices - * and smaller screens (up to 480px and 768px width). - * - * @author Anika Henke - */ - -/* for detecting media queries in JavaScript (see script.js): */ -#screen__mode { - position: relative; - z-index: 0; -} - -/* for screen widths in the tablet range -********************************************************************/ -@media only screen and (max-width: __tablet_width__) { - -#screen__mode { - z-index: 1; /* for detecting media queries in JavaScript (see script.js) */ -} - -/* structure */ -#dokuwiki__aside { - width: 100%; - float: none; -} - -#dokuwiki__aside > .pad, -[dir=rtl] #dokuwiki__aside > .pad { - margin: 0 0 .5em; - /* style like .page */ - background: __background__; - color: inherit; - border: 1px solid #eee; - box-shadow: 0 0 .5em __text_alt__; - border-radius: 2px; - padding: 1em; - margin-bottom: .5em; -} - -#dokuwiki__aside h3.toggle { - font-size: 1em; -} -#dokuwiki__aside h3.toggle.closed { - margin-bottom: 0; - padding-bottom: 0; -} -#dokuwiki__aside h3.toggle.open { - border-bottom: 1px solid __border__; -} - -.showSidebar #dokuwiki__content { - float: none; - margin-left: 0; - width: 100%; -} -.showSidebar #dokuwiki__content > .pad { - margin-left: 0; -} - -[dir=rtl] .showSidebar #dokuwiki__content, -[dir=rtl] .showSidebar #dokuwiki__content > .pad { - margin-right: 0; -} - -/* toc */ -#dw__toc { - float: none; - margin: 0 0 1em 0; - width: auto; - border-left-width: 0; - border-bottom: 1px solid __border__; -} -[dir=rtl] #dw__toc { - float: none; - margin: 0 0 1em 0; - border-right-width: 0; -} - -.dokuwiki h3.toggle { - padding: 0 .5em .5em 0; -} -#dw__toc > div, -#dokuwiki__aside div.content { - padding: .2em 0 .5em; -} - -/* page */ -.dokuwiki div.page { - padding: 1em; -} -/* enable horizontal scrolling in media manager */ -.mode_media div.page { - overflow: auto; -} - -/* _edit */ -.dokuwiki div.section_highlight { - margin: 0 -1em; - padding: 0 .5em; - border-width: 0 .5em; -} -.dokuwiki div.preview { - margin: 0 -1em; - padding: 1em; -} - -/* _recent */ -.dokuwiki form.changes ul { - padding-left: 0; -} -[dir=rtl] .dokuwiki form.changes ul { - padding-right: 0; -} - - -} /* /@media */ - - -/* for screen widths in the smartphone range -********************************************************************/ -@media only screen and (max-width: __phone_width__) { - -#screen__mode { - z-index: 2; /* for detecting media queries in JavaScript (see script.js) */ -} - -body { - font-size: 100%; -} - -/*____________ structure ____________*/ - -#dokuwiki__site { - max-width: 100%; -} -#dokuwiki__site > .site { - padding: 0 .5em; -} -#dokuwiki__header { - padding: .5em 0; -} - - -/*____________ header ____________*/ - -#dokuwiki__header ul.a11y.skip { - position: static !important; - left: 0 !important; - width: auto !important; - height: auto !important; - float: right; - font-size: 0.875em; - list-style: none; - padding-left: 0; - margin: 0; -} -[dir=rtl] #dokuwiki__header ul.a11y.skip { - left: auto !important; - right: 0 !important; - float: left; - padding-right: 0; -} -#dokuwiki__header ul.a11y.skip li { - margin-left: .35em; - display: inline; -} -[dir=rtl] #dokuwiki__header ul.a11y.skip li { - margin: 0 .35em 0 0; -} - -#dokuwiki__header .headings, -#dokuwiki__header .tools { - float: none; - text-align: left; - width: auto; - margin-bottom: .5em; -} -[dir=rtl] #dokuwiki__header .headings, -[dir=rtl] #dokuwiki__header .tools { - float: none; - text-align: right; - width: auto; -} -#dokuwiki__sitetools { - text-align: left; -} -[dir=rtl] #dokuwiki__sitetools { - text-align: right; -} -#dokuwiki__usertools, -#dokuwiki__sitetools ul, -#dokuwiki__sitetools h3, -#dokuwiki__pagetools, -.dokuwiki div.breadcrumbs, /* @todo: maybe move breadcrumbs to the bottom? */ -.dokuwiki .pageId { - display: none; -} - -/* search form */ -#dokuwiki__sitetools form.search { - float: left; - margin: 0 .2em .2em 0; - width: 49%; -} -[dir=rtl] #dokuwiki__sitetools form.search { - float: right; - margin: 0 0 .2em .2em; -} - -#dokuwiki__sitetools form.search input.edit { - width: 100% !important; -} -.dokuwiki form.search div.ajax_qsearch { - display: none !important; -} - -/* action dropdown is alternative for all hidden tools */ -#dokuwiki__header .mobileTools { - display: block; - font-size: 0.875em; - margin: 0 0 .2em 0; - float: right; - width: 49%; -} -[dir=rtl] #dokuwiki__header .mobileTools { - float: left; -} -#dokuwiki__header .mobileTools select { - padding: .3em .1em; - width: 100% !important; -} - -/* force same height on search input and tools select */ -#dokuwiki__sitetools form.search input.edit, -#dokuwiki__header .mobileTools select { - height: 2.1em; - line-height: 2.1em; - overflow: visible; -} - - -/*____________ content ____________*/ - -#dokuwiki__aside > .pad, -.dokuwiki div.page { - padding: .5em; -} - -/* form elements */ -#config__manager fieldset td.value, -#config__manager td .input, -.dokuwiki fieldset, -.dokuwiki input.edit, -.dokuwiki textarea, -.dokuwiki select { - width: auto !important; - max-width: 100% !important; -} -#config__manager fieldset { - margin-left: 0; - margin-right: 0; -} - -.dokuwiki label.block { - text-align: left; -} -[dir=rtl] .dokuwiki label.block { - text-align: right; -} -.dokuwiki label.block span { - display: block; -} - -/* _edit */ -.dokuwiki div.section_highlight { - margin: 0; - padding: 0; - border-width: 0; -} -.dokuwiki div.preview { - margin: 0 -.5em; - padding: .5em; -} - - - -} /* /@media */ diff --git a/lib/tpl/dokuwiki/css/mobile.less b/lib/tpl/dokuwiki/css/mobile.less new file mode 100644 index 000000000..4362656a1 --- /dev/null +++ b/lib/tpl/dokuwiki/css/mobile.less @@ -0,0 +1,288 @@ +/** + * This file provides styles for mobile devices + * and smaller screens (up to 480px and 768px width). + * + * @author Anika Henke + */ + +/* for detecting media queries in JavaScript (see script.js): */ +#screen__mode { + position: relative; + z-index: 0; +} + +/* for screen widths in the tablet range +********************************************************************/ +@media only screen and (max-width: @ini_tablet_width) { + +#screen__mode { + z-index: 1; /* for detecting media queries in JavaScript (see script.js) */ +} + +/* structure */ +#dokuwiki__aside { + width: 100%; + float: none; +} + +#dokuwiki__aside > .pad, +[dir=rtl] #dokuwiki__aside > .pad { + margin: 0 0 .5em; + /* style like .page */ + background: @ini_background; + color: inherit; + border: 1px solid #eee; + box-shadow: 0 0 .5em @ini_text_alt; + border-radius: 2px; + padding: 1em; + margin-bottom: .5em; +} + +#dokuwiki__aside h3.toggle { + font-size: 1em; +} +#dokuwiki__aside h3.toggle.closed { + margin-bottom: 0; + padding-bottom: 0; +} +#dokuwiki__aside h3.toggle.open { + border-bottom: 1px solid @ini_border; +} + +.showSidebar #dokuwiki__content { + float: none; + margin-left: 0; + width: 100%; +} +.showSidebar #dokuwiki__content > .pad { + margin-left: 0; +} + +[dir=rtl] .showSidebar #dokuwiki__content, +[dir=rtl] .showSidebar #dokuwiki__content > .pad { + margin-right: 0; +} + +/* toc */ +#dw__toc { + float: none; + margin: 0 0 1em 0; + width: auto; + border-left-width: 0; + border-bottom: 1px solid @ini_border; +} +[dir=rtl] #dw__toc { + float: none; + margin: 0 0 1em 0; + border-right-width: 0; +} + +.dokuwiki h3.toggle { + padding: 0 .5em .5em 0; +} +#dw__toc > div, +#dokuwiki__aside div.content { + padding: .2em 0 .5em; +} + +/* page */ +.dokuwiki div.page { + padding: 1em; +} +/* enable horizontal scrolling in media manager */ +.mode_media div.page { + overflow: auto; +} + +/* _edit */ +.dokuwiki div.section_highlight { + margin: 0 -1em; + padding: 0 .5em; + border-width: 0 .5em; +} +.dokuwiki div.preview { + margin: 0 -1em; + padding: 1em; +} + +/* _recent */ +.dokuwiki form.changes ul { + padding-left: 0; +} +[dir=rtl] .dokuwiki form.changes ul { + padding-right: 0; +} + + +} /* /@media */ + + +/* for screen widths in the smartphone range +********************************************************************/ +@media only screen and (max-width: @ini_phone_width) { + +#screen__mode { + z-index: 2; /* for detecting media queries in JavaScript (see script.js) */ +} + +body { + font-size: 100%; +} + +/*____________ structure ____________*/ + +#dokuwiki__site { + max-width: 100%; +} +#dokuwiki__site > .site { + padding: 0 .5em; +} +#dokuwiki__header { + padding: .5em 0; +} + + +/*____________ header ____________*/ + +#dokuwiki__header ul.a11y.skip { + position: static !important; + left: 0 !important; + width: auto !important; + height: auto !important; + float: right; + font-size: 0.875em; + list-style: none; + padding-left: 0; + margin: 0; +} +[dir=rtl] #dokuwiki__header ul.a11y.skip { + left: auto !important; + right: 0 !important; + float: left; + padding-right: 0; +} +#dokuwiki__header ul.a11y.skip li { + margin-left: .35em; + display: inline; +} +[dir=rtl] #dokuwiki__header ul.a11y.skip li { + margin: 0 .35em 0 0; +} + +#dokuwiki__header .headings, +#dokuwiki__header .tools { + float: none; + text-align: left; + width: auto; + margin-bottom: .5em; +} +[dir=rtl] #dokuwiki__header .headings, +[dir=rtl] #dokuwiki__header .tools { + float: none; + text-align: right; + width: auto; +} +#dokuwiki__sitetools { + text-align: left; +} +[dir=rtl] #dokuwiki__sitetools { + text-align: right; +} +#dokuwiki__usertools, +#dokuwiki__sitetools ul, +#dokuwiki__sitetools h3, +#dokuwiki__pagetools, +.dokuwiki div.breadcrumbs, /* @todo: maybe move breadcrumbs to the bottom? */ +.dokuwiki .pageId { + display: none; +} + +/* search form */ +#dokuwiki__sitetools form.search { + float: left; + margin: 0 .2em .2em 0; + width: 49%; +} +[dir=rtl] #dokuwiki__sitetools form.search { + float: right; + margin: 0 0 .2em .2em; +} + +#dokuwiki__sitetools form.search input.edit { + width: 100% !important; +} +.dokuwiki form.search div.ajax_qsearch { + display: none !important; +} + +/* action dropdown is alternative for all hidden tools */ +#dokuwiki__header .mobileTools { + display: block; + font-size: 0.875em; + margin: 0 0 .2em 0; + float: right; + width: 49%; +} +[dir=rtl] #dokuwiki__header .mobileTools { + float: left; +} +#dokuwiki__header .mobileTools select { + padding: .3em .1em; + width: 100% !important; +} + +/* force same height on search input and tools select */ +#dokuwiki__sitetools form.search input.edit, +#dokuwiki__header .mobileTools select { + height: 2.1em; + line-height: 2.1em; + overflow: visible; +} + + +/*____________ content ____________*/ + +#dokuwiki__aside > .pad, +.dokuwiki div.page { + padding: .5em; +} + +/* form elements */ +#config__manager fieldset td.value, +#config__manager td .input, +.dokuwiki fieldset, +.dokuwiki input.edit, +.dokuwiki textarea, +.dokuwiki select { + width: auto !important; + max-width: 100% !important; +} +#config__manager fieldset { + margin-left: 0; + margin-right: 0; +} + +.dokuwiki label.block { + text-align: left; +} +[dir=rtl] .dokuwiki label.block { + text-align: right; +} +.dokuwiki label.block span { + display: block; +} + +/* _edit */ +.dokuwiki div.section_highlight { + margin: 0; + padding: 0; + border-width: 0; +} +.dokuwiki div.preview { + margin: 0 -.5em; + padding: .5em; +} + + + +} /* /@media */ diff --git a/lib/tpl/dokuwiki/css/pagetools.css b/lib/tpl/dokuwiki/css/pagetools.css deleted file mode 100644 index 21e5c13ec..000000000 --- a/lib/tpl/dokuwiki/css/pagetools.css +++ /dev/null @@ -1,421 +0,0 @@ -/** - * This file provides the styles for the page tools - * (fly out navigation beside the page to edit, etc). - * - * @author Anika Henke - * @author Andreas Gohr - */ - -#dokuwiki__site > .site { - /* give space to the right so the tools won't disappear on smaller screens */ - /* it's 40px because the 30px wide icons will have 5px more spacing to the left and right */ - padding-right: 40px; - /* give the same space to the left to balance it out */ - padding-left: 40px; -} -.dokuwiki div.page { - height: 190px; - min-height: 190px; /* 30 (= height of icons) x 6 (= maximum number of possible tools) + 2x5 */ - height: auto; -} -#dokuwiki__usertools { - /* move the tools just outside of the site */ - right: 40px; -} -[dir=rtl] #dokuwiki__usertools { - right: auto; - left: 40px; -} - - -#dokuwiki__pagetools { - position: absolute; - right: -40px; - /* on same vertical level as first headline, because .page has 2em padding */ - top: 2em; - width: 40px; -} -[dir=rtl] #dokuwiki__pagetools { - right: auto; - left: -40px; -} - -#dokuwiki__pagetools div.tools { - position: fixed; - width: 40px; -} - -#dokuwiki__pagetools ul { - position: absolute; - right: 0; - text-align: right; - margin: 0; - padding: 0; - /* add transparent border to prevent jumping when proper border is added on hover */ - border: 1px solid transparent; - z-index: 10; -} -[dir=rtl] #dokuwiki__pagetools ul { - right: auto; - left: 0; - text-align: left; -} - -#dokuwiki__pagetools ul li { - padding: 0; - margin: 0; - list-style: none; - font-size: 0.875em; -} - -#dokuwiki__pagetools ul li a { - display: block; - min-height: 20px; /* 30 - 2x5 */ - line-height: 20px; - padding: 0; - background-position: right 0; - background-repeat: no-repeat; - /* add transparent border to prevent jumping when proper border is added on focus */ - border: 1px solid transparent; - white-space: nowrap; - width: 30px; - height: 30px; - overflow: hidden; - margin-left: auto; /* align right if the ul is larger because one item is focused */ -} - -#dokuwiki__pagetools ul li a:before { - content: url(images/pagetools-sprite.png); - display: inline-block; - font-size: 0; - line-height: 0; -} - -[dir=rtl] #dokuwiki__pagetools ul li a { - background-position: left 0; - margin-right: auto; - margin-left: 0; -} - -/* show all tools on hover and individual tools on focus */ -#dokuwiki__pagetools:hover ul, -#dokuwiki__pagetools ul li a:focus, -#dokuwiki__pagetools ul li a:active { - background-color: __background__; - border-color: __border__; - border-radius: 2px; - box-shadow: 2px 2px 2px __text_alt__; -} - -#dokuwiki__pagetools:hover ul li a, -#dokuwiki__pagetools ul li a:focus, -#dokuwiki__pagetools ul li a:active { - width: auto; - height: auto; - overflow: visible; - padding: 5px 40px 5px 5px; - background-image: url(images/pagetools-sprite.png); -} - -#dokuwiki__pagetools:hover ul li a:before, -#dokuwiki__pagetools ul li a:focus:before { - content: none; -} - -[dir=rtl] #dokuwiki__pagetools:hover ul, -[dir=rtl] #dokuwiki__pagetools ul li a:focus { - box-shadow: -2px 2px 2px __text_alt__; -} - -[dir=rtl] #dokuwiki__pagetools:hover li a, -[dir=rtl] #dokuwiki__pagetools ul li a:focus, -[dir=rtl] #dokuwiki__pagetools ul li a:active { - padding: 5px 5px 5px 40px; -} - -/* IE7 fixes, doesn't work without images */ - -#IE7 #dokuwiki__pagetools ul li a { - background-image: url(images/pagetools-sprite.png); -} - -#IE7 #dokuwiki__pagetools:hover ul li a span, -#IE7 #dokuwiki__pagetools ul li a:focus span, -#IE7 #dokuwiki__pagetools ul li a:active span { - clip: auto; - display: inline; - position: static; -} - -#IE7 #dokuwiki__pagetools ul li a span { - clip: rect(0 0 0 0); - position: absolute; -} - -#dokuwiki__pagetools ul li a:hover, -#dokuwiki__pagetools ul li a:active, -#dokuwiki__pagetools ul li a:focus { - text-decoration: none; -} -#dokuwiki__pagetools ul li a:hover { - background-color: __background_alt__; -} - -/*____________ all available icons in sprite ____________*/ - -#dokuwiki__pagetools ul li a.edit { - background-position: right 0; -} -#dokuwiki__pagetools ul li a.edit:hover, -#dokuwiki__pagetools ul li a.edit:active, -#dokuwiki__pagetools ul li a.edit:focus { - background-position: right -45px; -} -[dir=rtl] #dokuwiki__pagetools ul li a.edit { - background-position: left 0; -} -[dir=rtl] #dokuwiki__pagetools ul li a.edit:hover, -[dir=rtl] #dokuwiki__pagetools ul li a.edit:active, -[dir=rtl] #dokuwiki__pagetools ul li a.edit:focus { - background-position: left -45px; -} - -#dokuwiki__pagetools ul li a.create:before { - margin-top: -90px; -} -#dokuwiki__pagetools ul li a.create { - background-position: right -90px; -} -#dokuwiki__pagetools ul li a.create:hover, -#dokuwiki__pagetools ul li a.create:active, -#dokuwiki__pagetools ul li a.create:focus { - background-position: right -135px; -} -[dir=rtl] #dokuwiki__pagetools ul li a.create { - background-position: left -90px; -} -[dir=rtl] #dokuwiki__pagetools ul li a.create:hover, -[dir=rtl] #dokuwiki__pagetools ul li a.create:active, -[dir=rtl] #dokuwiki__pagetools ul li a.create:focus { - background-position: left -135px; -} - -#dokuwiki__pagetools ul li a.show { - background-position: right -270px; -} -#dokuwiki__pagetools ul li a.show:before { - margin-top: -270px; -} -#dokuwiki__pagetools ul li a.show:hover, -#dokuwiki__pagetools ul li a.show:active, -#dokuwiki__pagetools ul li a.show:focus { - background-position: right -315px; -} -[dir=rtl] #dokuwiki__pagetools ul li a.show { - background-position: left -270px; -} -[dir=rtl] #dokuwiki__pagetools ul li a.show:hover, -[dir=rtl] #dokuwiki__pagetools ul li a.show:active, -[dir=rtl] #dokuwiki__pagetools ul li a.show:focus { - background-position: left -315px; -} - -#dokuwiki__pagetools ul li a.source { - background-position: right -360px; -} -#dokuwiki__pagetools ul li a.source:before { - margin-top: -360px; -} -#dokuwiki__pagetools ul li a.source:hover, -#dokuwiki__pagetools ul li a.source:active, -#dokuwiki__pagetools ul li a.source:focus { - background-position: right -405px; -} -[dir=rtl] #dokuwiki__pagetools ul li a.source { - background-position: left -360px; -} -[dir=rtl] #dokuwiki__pagetools ul li a.source:hover, -[dir=rtl] #dokuwiki__pagetools ul li a.source:active, -[dir=rtl] #dokuwiki__pagetools ul li a.source:focus { - background-position: left -405px; -} - -#dokuwiki__pagetools ul li a.draft { - background-position: right -180px; -} -#dokuwiki__pagetools ul li a.draft:before { - margin-top: -180px; -} -#dokuwiki__pagetools ul li a.draft:hover, -#dokuwiki__pagetools ul li a.draft:active, -#dokuwiki__pagetools ul li a.draft:focus { - background-position: right -225px; -} -[dir=rtl] #dokuwiki__pagetools ul li a.draft { - background-position: left -180px; -} -[dir=rtl] #dokuwiki__pagetools ul li a.draft:hover, -[dir=rtl] #dokuwiki__pagetools ul li a.draft:active, -[dir=rtl] #dokuwiki__pagetools ul li a.draft:focus { - background-position: left -225px; -} - -#dokuwiki__pagetools ul li a.revs { - background-position: right -540px; -} -#dokuwiki__pagetools ul li a.revs:before { - margin-top: -540px; -} -#dokuwiki__pagetools ul li a.revs:hover, -#dokuwiki__pagetools ul li a.revs:active, -#dokuwiki__pagetools ul li a.revs:focus, -.mode_revisions #dokuwiki__pagetools ul li a.revs { - background-position: right -585px; -} -.mode_revisions #dokuwiki__pagetools ul li a.revs:before { - margin-top: -585px; -} -[dir=rtl] #dokuwiki__pagetools ul li a.revs { - background-position: left -540px; -} -[dir=rtl] #dokuwiki__pagetools ul li a.revs:hover, -[dir=rtl] #dokuwiki__pagetools ul li a.revs:active, -[dir=rtl] #dokuwiki__pagetools ul li a.revs:focus, -[dir=rtl] .mode_revisions #dokuwiki__pagetools ul li a.revs { - background-position: left -585px; -} - -#dokuwiki__pagetools ul li a.backlink { - background-position: right -630px; -} -#dokuwiki__pagetools ul li a.backlink:before { - margin-top: -630px; -} -#dokuwiki__pagetools ul li a.backlink:hover, -#dokuwiki__pagetools ul li a.backlink:active, -#dokuwiki__pagetools ul li a.backlink:focus, -.mode_backlink #dokuwiki__pagetools ul li a.backlink { - background-position: right -675px; -} -.mode_backlink #dokuwiki__pagetools ul li a.backlink:before { - margin-top: -675px; -} -[dir=rtl] #dokuwiki__pagetools ul li a.backlink { - background-position: left -630px; -} -[dir=rtl] #dokuwiki__pagetools ul li a.backlink:hover, -[dir=rtl] #dokuwiki__pagetools ul li a.backlink:active, -[dir=rtl] #dokuwiki__pagetools ul li a.backlink:focus, -[dir=rtl] .mode_backlink #dokuwiki__pagetools ul li a.backlink { - background-position: left -675px; -} - -#dokuwiki__pagetools ul li a.top { - background-position: right -810px; -} -#dokuwiki__pagetools ul li a.top:before{ - margin-top: -810px; -} -#dokuwiki__pagetools ul li a.top:hover, -#dokuwiki__pagetools ul li a.top:active, -#dokuwiki__pagetools ul li a.top:focus { - background-position: right -855px; -} -[dir=rtl] #dokuwiki__pagetools ul li a.top { - background-position: left -810px; -} -[dir=rtl] #dokuwiki__pagetools ul li a.top:hover, -[dir=rtl] #dokuwiki__pagetools ul li a.top:active, -[dir=rtl] #dokuwiki__pagetools ul li a.top:focus { - background-position: left -855px; -} - -#dokuwiki__pagetools ul li a.revert { - background-position: right -450px; -} -#dokuwiki__pagetools ul li a.revert:before { - margin-top: -450px; -} -#dokuwiki__pagetools ul li a.revert:hover, -#dokuwiki__pagetools ul li a.revert:active, -#dokuwiki__pagetools ul li a.revert:focus, -.mode_revert #dokuwiki__pagetools ul li a.revert { - background-position: right -495px; -} -.mode_revert #dokuwiki__pagetools ul li a.revert:before { - margin-top: -450px; -} -[dir=rtl] #dokuwiki__pagetools ul li a.revert { - background-position: left -450px; -} -[dir=rtl] #dokuwiki__pagetools ul li a.revert:hover, -[dir=rtl] #dokuwiki__pagetools ul li a.revert:active, -[dir=rtl] #dokuwiki__pagetools ul li a.revert:focus, -[dir=rtl] .mode_revert #dokuwiki__pagetools ul li a.revert { - background-position: left -495px; -} - -#dokuwiki__pagetools ul li a.subscribe { - background-position: right -720px; -} -#dokuwiki__pagetools ul li a.subscribe:before { - margin-top: -720px; -} -#dokuwiki__pagetools ul li a.subscribe:hover, -#dokuwiki__pagetools ul li a.subscribe:active, -#dokuwiki__pagetools ul li a.subscribe:focus, -.mode_subscribe #dokuwiki__pagetools ul li a.subscribe { - background-position: right -765px; -} -.mode_subscribe #dokuwiki__pagetools ul li a.subscribe:before { - margin-top: -765px; -} -[dir=rtl] #dokuwiki__pagetools ul li a.subscribe { - background-position: left -720px; -} -[dir=rtl] #dokuwiki__pagetools ul li a.subscribe:hover, -[dir=rtl] #dokuwiki__pagetools ul li a.subscribe:active, -[dir=rtl] #dokuwiki__pagetools ul li a.subscribe:focus, -[dir=rtl] .mode_subscribe #dokuwiki__pagetools ul li a.subscribe { - background-position: left -765px; -} - -#dokuwiki__pagetools ul li a.mediaManager { - background-position: right -900px; -} -#dokuwiki__pagetools ul li a.mediaManager:before { - margin-top: -900px; -} -#dokuwiki__pagetools ul li a.mediaManager:hover, -#dokuwiki__pagetools ul li a.mediaManager:active, -#dokuwiki__pagetools ul li a.mediaManager:focus { - background-position: right -945px; -} -[dir=rtl] #dokuwiki__pagetools ul li a.mediaManager { - background-position: left -900px; -} -[dir=rtl] #dokuwiki__pagetools ul li a.mediaManager:hover, -[dir=rtl] #dokuwiki__pagetools ul li a.mediaManager:active, -[dir=rtl] #dokuwiki__pagetools ul li a.mediaManager:focus { - background-position: left -945px; -} - -#dokuwiki__pagetools ul li a.back { - background-position: right -990px; -} -#dokuwiki__pagetools ul li a.back { - margin-top: -990px; -} -#dokuwiki__pagetools ul li a.back:hover, -#dokuwiki__pagetools ul li a.back:active, -#dokuwiki__pagetools ul li a.back:focus { - background-position: right -1035px; -} -[dir=rtl] #dokuwiki__pagetools ul li a.back { - background-position: left -990px; -} -[dir=rtl] #dokuwiki__pagetools ul li a.back:hover, -[dir=rtl] #dokuwiki__pagetools ul li a.back:active, -[dir=rtl] #dokuwiki__pagetools ul li a.back:focus { - background-position: left -1035px; -} diff --git a/lib/tpl/dokuwiki/css/pagetools.less b/lib/tpl/dokuwiki/css/pagetools.less new file mode 100644 index 000000000..21e5c13ec --- /dev/null +++ b/lib/tpl/dokuwiki/css/pagetools.less @@ -0,0 +1,421 @@ +/** + * This file provides the styles for the page tools + * (fly out navigation beside the page to edit, etc). + * + * @author Anika Henke + * @author Andreas Gohr + */ + +#dokuwiki__site > .site { + /* give space to the right so the tools won't disappear on smaller screens */ + /* it's 40px because the 30px wide icons will have 5px more spacing to the left and right */ + padding-right: 40px; + /* give the same space to the left to balance it out */ + padding-left: 40px; +} +.dokuwiki div.page { + height: 190px; + min-height: 190px; /* 30 (= height of icons) x 6 (= maximum number of possible tools) + 2x5 */ + height: auto; +} +#dokuwiki__usertools { + /* move the tools just outside of the site */ + right: 40px; +} +[dir=rtl] #dokuwiki__usertools { + right: auto; + left: 40px; +} + + +#dokuwiki__pagetools { + position: absolute; + right: -40px; + /* on same vertical level as first headline, because .page has 2em padding */ + top: 2em; + width: 40px; +} +[dir=rtl] #dokuwiki__pagetools { + right: auto; + left: -40px; +} + +#dokuwiki__pagetools div.tools { + position: fixed; + width: 40px; +} + +#dokuwiki__pagetools ul { + position: absolute; + right: 0; + text-align: right; + margin: 0; + padding: 0; + /* add transparent border to prevent jumping when proper border is added on hover */ + border: 1px solid transparent; + z-index: 10; +} +[dir=rtl] #dokuwiki__pagetools ul { + right: auto; + left: 0; + text-align: left; +} + +#dokuwiki__pagetools ul li { + padding: 0; + margin: 0; + list-style: none; + font-size: 0.875em; +} + +#dokuwiki__pagetools ul li a { + display: block; + min-height: 20px; /* 30 - 2x5 */ + line-height: 20px; + padding: 0; + background-position: right 0; + background-repeat: no-repeat; + /* add transparent border to prevent jumping when proper border is added on focus */ + border: 1px solid transparent; + white-space: nowrap; + width: 30px; + height: 30px; + overflow: hidden; + margin-left: auto; /* align right if the ul is larger because one item is focused */ +} + +#dokuwiki__pagetools ul li a:before { + content: url(images/pagetools-sprite.png); + display: inline-block; + font-size: 0; + line-height: 0; +} + +[dir=rtl] #dokuwiki__pagetools ul li a { + background-position: left 0; + margin-right: auto; + margin-left: 0; +} + +/* show all tools on hover and individual tools on focus */ +#dokuwiki__pagetools:hover ul, +#dokuwiki__pagetools ul li a:focus, +#dokuwiki__pagetools ul li a:active { + background-color: __background__; + border-color: __border__; + border-radius: 2px; + box-shadow: 2px 2px 2px __text_alt__; +} + +#dokuwiki__pagetools:hover ul li a, +#dokuwiki__pagetools ul li a:focus, +#dokuwiki__pagetools ul li a:active { + width: auto; + height: auto; + overflow: visible; + padding: 5px 40px 5px 5px; + background-image: url(images/pagetools-sprite.png); +} + +#dokuwiki__pagetools:hover ul li a:before, +#dokuwiki__pagetools ul li a:focus:before { + content: none; +} + +[dir=rtl] #dokuwiki__pagetools:hover ul, +[dir=rtl] #dokuwiki__pagetools ul li a:focus { + box-shadow: -2px 2px 2px __text_alt__; +} + +[dir=rtl] #dokuwiki__pagetools:hover li a, +[dir=rtl] #dokuwiki__pagetools ul li a:focus, +[dir=rtl] #dokuwiki__pagetools ul li a:active { + padding: 5px 5px 5px 40px; +} + +/* IE7 fixes, doesn't work without images */ + +#IE7 #dokuwiki__pagetools ul li a { + background-image: url(images/pagetools-sprite.png); +} + +#IE7 #dokuwiki__pagetools:hover ul li a span, +#IE7 #dokuwiki__pagetools ul li a:focus span, +#IE7 #dokuwiki__pagetools ul li a:active span { + clip: auto; + display: inline; + position: static; +} + +#IE7 #dokuwiki__pagetools ul li a span { + clip: rect(0 0 0 0); + position: absolute; +} + +#dokuwiki__pagetools ul li a:hover, +#dokuwiki__pagetools ul li a:active, +#dokuwiki__pagetools ul li a:focus { + text-decoration: none; +} +#dokuwiki__pagetools ul li a:hover { + background-color: __background_alt__; +} + +/*____________ all available icons in sprite ____________*/ + +#dokuwiki__pagetools ul li a.edit { + background-position: right 0; +} +#dokuwiki__pagetools ul li a.edit:hover, +#dokuwiki__pagetools ul li a.edit:active, +#dokuwiki__pagetools ul li a.edit:focus { + background-position: right -45px; +} +[dir=rtl] #dokuwiki__pagetools ul li a.edit { + background-position: left 0; +} +[dir=rtl] #dokuwiki__pagetools ul li a.edit:hover, +[dir=rtl] #dokuwiki__pagetools ul li a.edit:active, +[dir=rtl] #dokuwiki__pagetools ul li a.edit:focus { + background-position: left -45px; +} + +#dokuwiki__pagetools ul li a.create:before { + margin-top: -90px; +} +#dokuwiki__pagetools ul li a.create { + background-position: right -90px; +} +#dokuwiki__pagetools ul li a.create:hover, +#dokuwiki__pagetools ul li a.create:active, +#dokuwiki__pagetools ul li a.create:focus { + background-position: right -135px; +} +[dir=rtl] #dokuwiki__pagetools ul li a.create { + background-position: left -90px; +} +[dir=rtl] #dokuwiki__pagetools ul li a.create:hover, +[dir=rtl] #dokuwiki__pagetools ul li a.create:active, +[dir=rtl] #dokuwiki__pagetools ul li a.create:focus { + background-position: left -135px; +} + +#dokuwiki__pagetools ul li a.show { + background-position: right -270px; +} +#dokuwiki__pagetools ul li a.show:before { + margin-top: -270px; +} +#dokuwiki__pagetools ul li a.show:hover, +#dokuwiki__pagetools ul li a.show:active, +#dokuwiki__pagetools ul li a.show:focus { + background-position: right -315px; +} +[dir=rtl] #dokuwiki__pagetools ul li a.show { + background-position: left -270px; +} +[dir=rtl] #dokuwiki__pagetools ul li a.show:hover, +[dir=rtl] #dokuwiki__pagetools ul li a.show:active, +[dir=rtl] #dokuwiki__pagetools ul li a.show:focus { + background-position: left -315px; +} + +#dokuwiki__pagetools ul li a.source { + background-position: right -360px; +} +#dokuwiki__pagetools ul li a.source:before { + margin-top: -360px; +} +#dokuwiki__pagetools ul li a.source:hover, +#dokuwiki__pagetools ul li a.source:active, +#dokuwiki__pagetools ul li a.source:focus { + background-position: right -405px; +} +[dir=rtl] #dokuwiki__pagetools ul li a.source { + background-position: left -360px; +} +[dir=rtl] #dokuwiki__pagetools ul li a.source:hover, +[dir=rtl] #dokuwiki__pagetools ul li a.source:active, +[dir=rtl] #dokuwiki__pagetools ul li a.source:focus { + background-position: left -405px; +} + +#dokuwiki__pagetools ul li a.draft { + background-position: right -180px; +} +#dokuwiki__pagetools ul li a.draft:before { + margin-top: -180px; +} +#dokuwiki__pagetools ul li a.draft:hover, +#dokuwiki__pagetools ul li a.draft:active, +#dokuwiki__pagetools ul li a.draft:focus { + background-position: right -225px; +} +[dir=rtl] #dokuwiki__pagetools ul li a.draft { + background-position: left -180px; +} +[dir=rtl] #dokuwiki__pagetools ul li a.draft:hover, +[dir=rtl] #dokuwiki__pagetools ul li a.draft:active, +[dir=rtl] #dokuwiki__pagetools ul li a.draft:focus { + background-position: left -225px; +} + +#dokuwiki__pagetools ul li a.revs { + background-position: right -540px; +} +#dokuwiki__pagetools ul li a.revs:before { + margin-top: -540px; +} +#dokuwiki__pagetools ul li a.revs:hover, +#dokuwiki__pagetools ul li a.revs:active, +#dokuwiki__pagetools ul li a.revs:focus, +.mode_revisions #dokuwiki__pagetools ul li a.revs { + background-position: right -585px; +} +.mode_revisions #dokuwiki__pagetools ul li a.revs:before { + margin-top: -585px; +} +[dir=rtl] #dokuwiki__pagetools ul li a.revs { + background-position: left -540px; +} +[dir=rtl] #dokuwiki__pagetools ul li a.revs:hover, +[dir=rtl] #dokuwiki__pagetools ul li a.revs:active, +[dir=rtl] #dokuwiki__pagetools ul li a.revs:focus, +[dir=rtl] .mode_revisions #dokuwiki__pagetools ul li a.revs { + background-position: left -585px; +} + +#dokuwiki__pagetools ul li a.backlink { + background-position: right -630px; +} +#dokuwiki__pagetools ul li a.backlink:before { + margin-top: -630px; +} +#dokuwiki__pagetools ul li a.backlink:hover, +#dokuwiki__pagetools ul li a.backlink:active, +#dokuwiki__pagetools ul li a.backlink:focus, +.mode_backlink #dokuwiki__pagetools ul li a.backlink { + background-position: right -675px; +} +.mode_backlink #dokuwiki__pagetools ul li a.backlink:before { + margin-top: -675px; +} +[dir=rtl] #dokuwiki__pagetools ul li a.backlink { + background-position: left -630px; +} +[dir=rtl] #dokuwiki__pagetools ul li a.backlink:hover, +[dir=rtl] #dokuwiki__pagetools ul li a.backlink:active, +[dir=rtl] #dokuwiki__pagetools ul li a.backlink:focus, +[dir=rtl] .mode_backlink #dokuwiki__pagetools ul li a.backlink { + background-position: left -675px; +} + +#dokuwiki__pagetools ul li a.top { + background-position: right -810px; +} +#dokuwiki__pagetools ul li a.top:before{ + margin-top: -810px; +} +#dokuwiki__pagetools ul li a.top:hover, +#dokuwiki__pagetools ul li a.top:active, +#dokuwiki__pagetools ul li a.top:focus { + background-position: right -855px; +} +[dir=rtl] #dokuwiki__pagetools ul li a.top { + background-position: left -810px; +} +[dir=rtl] #dokuwiki__pagetools ul li a.top:hover, +[dir=rtl] #dokuwiki__pagetools ul li a.top:active, +[dir=rtl] #dokuwiki__pagetools ul li a.top:focus { + background-position: left -855px; +} + +#dokuwiki__pagetools ul li a.revert { + background-position: right -450px; +} +#dokuwiki__pagetools ul li a.revert:before { + margin-top: -450px; +} +#dokuwiki__pagetools ul li a.revert:hover, +#dokuwiki__pagetools ul li a.revert:active, +#dokuwiki__pagetools ul li a.revert:focus, +.mode_revert #dokuwiki__pagetools ul li a.revert { + background-position: right -495px; +} +.mode_revert #dokuwiki__pagetools ul li a.revert:before { + margin-top: -450px; +} +[dir=rtl] #dokuwiki__pagetools ul li a.revert { + background-position: left -450px; +} +[dir=rtl] #dokuwiki__pagetools ul li a.revert:hover, +[dir=rtl] #dokuwiki__pagetools ul li a.revert:active, +[dir=rtl] #dokuwiki__pagetools ul li a.revert:focus, +[dir=rtl] .mode_revert #dokuwiki__pagetools ul li a.revert { + background-position: left -495px; +} + +#dokuwiki__pagetools ul li a.subscribe { + background-position: right -720px; +} +#dokuwiki__pagetools ul li a.subscribe:before { + margin-top: -720px; +} +#dokuwiki__pagetools ul li a.subscribe:hover, +#dokuwiki__pagetools ul li a.subscribe:active, +#dokuwiki__pagetools ul li a.subscribe:focus, +.mode_subscribe #dokuwiki__pagetools ul li a.subscribe { + background-position: right -765px; +} +.mode_subscribe #dokuwiki__pagetools ul li a.subscribe:before { + margin-top: -765px; +} +[dir=rtl] #dokuwiki__pagetools ul li a.subscribe { + background-position: left -720px; +} +[dir=rtl] #dokuwiki__pagetools ul li a.subscribe:hover, +[dir=rtl] #dokuwiki__pagetools ul li a.subscribe:active, +[dir=rtl] #dokuwiki__pagetools ul li a.subscribe:focus, +[dir=rtl] .mode_subscribe #dokuwiki__pagetools ul li a.subscribe { + background-position: left -765px; +} + +#dokuwiki__pagetools ul li a.mediaManager { + background-position: right -900px; +} +#dokuwiki__pagetools ul li a.mediaManager:before { + margin-top: -900px; +} +#dokuwiki__pagetools ul li a.mediaManager:hover, +#dokuwiki__pagetools ul li a.mediaManager:active, +#dokuwiki__pagetools ul li a.mediaManager:focus { + background-position: right -945px; +} +[dir=rtl] #dokuwiki__pagetools ul li a.mediaManager { + background-position: left -900px; +} +[dir=rtl] #dokuwiki__pagetools ul li a.mediaManager:hover, +[dir=rtl] #dokuwiki__pagetools ul li a.mediaManager:active, +[dir=rtl] #dokuwiki__pagetools ul li a.mediaManager:focus { + background-position: left -945px; +} + +#dokuwiki__pagetools ul li a.back { + background-position: right -990px; +} +#dokuwiki__pagetools ul li a.back { + margin-top: -990px; +} +#dokuwiki__pagetools ul li a.back:hover, +#dokuwiki__pagetools ul li a.back:active, +#dokuwiki__pagetools ul li a.back:focus { + background-position: right -1035px; +} +[dir=rtl] #dokuwiki__pagetools ul li a.back { + background-position: left -990px; +} +[dir=rtl] #dokuwiki__pagetools ul li a.back:hover, +[dir=rtl] #dokuwiki__pagetools ul li a.back:active, +[dir=rtl] #dokuwiki__pagetools ul li a.back:focus { + background-position: left -1035px; +} diff --git a/lib/tpl/dokuwiki/css/structure.css b/lib/tpl/dokuwiki/css/structure.css deleted file mode 100644 index 00642e90b..000000000 --- a/lib/tpl/dokuwiki/css/structure.css +++ /dev/null @@ -1,81 +0,0 @@ -/** - * This file provides styles for the general layout structure. - * - * @author Anika Henke - */ - -body { - margin: 0 auto; -} -#dokuwiki__site { - margin: 0 auto; - max-width: __site_width__; -} -#dokuwiki__site > .site { - padding: 0 .5em; -} - -#dokuwiki__header { - width: 100%; -} -#dokuwiki__header > .pad { -} - #dokuwiki__header .headings { - float: left; - } - [dir=rtl] #dokuwiki__header .headings { - float: right; - text-align: right; - } - #dokuwiki__header .tools { - float: right; - text-align: right; - } - [dir=rtl] #dokuwiki__header .tools { - float: left; - text-align: left; - } - -#dokuwiki__site .wrapper { - position: relative; -} - - #dokuwiki__aside { - width: __sidebar_width__; - float: left; - position: relative; - display: block; - } - [dir=rtl] #dokuwiki__aside { - float: right; - } - #dokuwiki__aside > .pad { - margin: 0 1.5em 0 0; - } - [dir=rtl] #dokuwiki__aside > .pad { - margin: 0 0 0 1.5em; - } - - .showSidebar #dokuwiki__content { - float: right; - margin-left: -__sidebar_width__; - width: 100%; - } - [dir=rtl] .showSidebar #dokuwiki__content { - float: left; - margin-left: 0; - margin-right: -__sidebar_width__; - } - .showSidebar #dokuwiki__content > .pad { - margin-left: __sidebar_width__; - } - [dir=rtl] .showSidebar #dokuwiki__content > .pad { - margin-left: 0; - margin-right: __sidebar_width__; - } - -#dokuwiki__footer { - clear: both; -} -#dokuwiki__footer > .pad { -} diff --git a/lib/tpl/dokuwiki/css/structure.less b/lib/tpl/dokuwiki/css/structure.less new file mode 100644 index 000000000..3f22f57e3 --- /dev/null +++ b/lib/tpl/dokuwiki/css/structure.less @@ -0,0 +1,94 @@ +/** + * This file provides styles for the general layout structure. + * + * @author Anika Henke + */ +body { + margin: 0 auto; +} + +#dokuwiki__site { + margin: 0 auto; + max-width: @ini_site_width; +} + +#dokuwiki__site > .site { + padding: 0 .5em; +} + +#dokuwiki__header { + width: 100%; +} + +#dokuwiki__header > .pad { +} + +#dokuwiki__header .headings { + float: left; +} + +[dir=rtl] #dokuwiki__header .headings { + float: right; + text-align: right; +} + +#dokuwiki__header .tools { + float: right; + text-align: right; +} + +[dir=rtl] #dokuwiki__header .tools { + float: left; + text-align: left; +} + +#dokuwiki__site .wrapper { + position: relative; +} + +#dokuwiki__aside { + width: @ini_sidebar_width; + float: left; + position: relative; + display: block; +} + +[dir=rtl] #dokuwiki__aside { + float: right; +} + +#dokuwiki__aside > .pad { + margin: 0 1.5em 0 0; +} + +[dir=rtl] #dokuwiki__aside > .pad { + margin: 0 0 0 1.5em; +} + +.showSidebar #dokuwiki__content { + float: right; + margin-left: -@ini_sidebar_width; + width: 100%; +} + +[dir=rtl] .showSidebar #dokuwiki__content { + float: left; + margin-left: 0; + margin-right: -@ini_sidebar_width; +} + +.showSidebar #dokuwiki__content > .pad { + margin-left: @ini_sidebar_width; +} + +[dir=rtl] .showSidebar #dokuwiki__content > .pad { + margin-left: 0; + margin-right: @ini_sidebar_width; +} + +#dokuwiki__footer { + clear: both; +} + +#dokuwiki__footer > .pad { +} diff --git a/lib/tpl/dokuwiki/style.ini b/lib/tpl/dokuwiki/style.ini index 9cf6cb64f..c6962fcd2 100644 --- a/lib/tpl/dokuwiki/style.ini +++ b/lib/tpl/dokuwiki/style.ini @@ -9,12 +9,15 @@ ; Define the stylesheets your template uses here. The second value ; defines for which output media the style should be loaded. Currently ; print, screen and all are supported. +; You can reference CSS and LESS files here. Files referenced here will +; be checked for updates when considering a cache rebuild while files +; included through LESS' @import statements are not [stylesheets] css/mixins.less = screen -css/basic.css = screen +css/basic.less = screen css/_imgdetail.css = screen css/_media_popup.css = screen css/_media_fullscreen.css = screen @@ -32,17 +35,18 @@ css/_forms.css = screen css/_admin.css = screen css/structure.css = screen css/design.less = screen -css/pagetools.css = screen -css/content.css = screen -css/includes.css = screen +css/pagetools.less = screen +css/content.less = screen -css/mobile.css = all +css/mobile.less = all css/print.css = print ; This section is used to configure some placeholder values used in ; the stylesheets. Changing this file is the simplest method to ; give your wiki a new look. +; Placeholders defined here will also be made available as LESS variables +; (with surrounding underscores removed, and the prefix @ini_ added) [replacements] -- cgit v1.2.3 From b0df08e2753e34829c2d27f82d25807a4f5bd4b8 Mon Sep 17 00:00:00 2001 From: Andreas Gohr Date: Tue, 30 Jul 2013 15:55:34 +0200 Subject: make sure calculations are correct --- lib/tpl/dokuwiki/css/structure.less | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/tpl/dokuwiki/css/structure.less b/lib/tpl/dokuwiki/css/structure.less index 3f22f57e3..f24440f08 100644 --- a/lib/tpl/dokuwiki/css/structure.less +++ b/lib/tpl/dokuwiki/css/structure.less @@ -67,14 +67,14 @@ body { .showSidebar #dokuwiki__content { float: right; - margin-left: -@ini_sidebar_width; + margin-left: (-1 * @ini_sidebar_width); width: 100%; } [dir=rtl] .showSidebar #dokuwiki__content { float: left; margin-left: 0; - margin-right: -@ini_sidebar_width; + margin-right: (-1 * @ini_sidebar_width); } .showSidebar #dokuwiki__content > .pad { -- cgit v1.2.3 From cbe37079b2519e6a79696ab6525a61498ab3c3a6 Mon Sep 17 00:00:00 2001 From: Andreas Gohr Date: Tue, 30 Jul 2013 15:56:29 +0200 Subject: convert ini replacements to less vars first This makes it possible to safely overwrite ini replacements from within any less file --- lib/exe/css.php | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/lib/exe/css.php b/lib/exe/css.php index 04516e8ba..0157e6a40 100644 --- a/lib/exe/css.php +++ b/lib/exe/css.php @@ -154,6 +154,9 @@ function css_out(){ // apply style replacements $css = css_applystyle($css,$tplinc); + print $css; + + // parse LESS $less = new lessc(); $css = $less->compile($css); @@ -188,15 +191,21 @@ function css_applystyle($css,$tplinc){ $styleini = css_styleini($tplinc); if($styleini){ - $css = strtr($css,$styleini['replacements']); - + // we convert ini replacements to LESS variable names + // and build a list of variable: value; pairs $less = ''; foreach($styleini['replacements'] as $key => $value){ - $key = trim($key, '_'); - $key = '@ini_'.$key; - $less .= "$key: $value;\n"; + $lkey = trim($key, '_'); + $lkey = '@ini_'.$lkey; + $less .= "$lkey: $value;\n"; + + $styleini['replacements'][$key] = $lkey; } + // we now replace all old ini replacements with LESS variables + $css = strtr($css, $styleini['replacements']); + + // now prepend the list of LESS variables as the very first thing $css = $less.$css; } return $css; -- cgit v1.2.3 From fbaa87779929e23ede8a79fd3890ef493fdb1d81 Mon Sep 17 00:00:00 2001 From: Andreas Gohr Date: Tue, 30 Jul 2013 16:00:28 +0200 Subject: removed debug statement. sorry --- lib/exe/css.php | 3 --- 1 file changed, 3 deletions(-) diff --git a/lib/exe/css.php b/lib/exe/css.php index 0157e6a40..cd531ef35 100644 --- a/lib/exe/css.php +++ b/lib/exe/css.php @@ -154,9 +154,6 @@ function css_out(){ // apply style replacements $css = css_applystyle($css,$tplinc); - print $css; - - // parse LESS $less = new lessc(); $css = $less->compile($css); -- cgit v1.2.3 From c6f665dd924dfa715fc19140c26d25eddcef9841 Mon Sep 17 00:00:00 2001 From: Michael Hamann Date: Tue, 30 Jul 2013 17:50:17 +0200 Subject: Don't recommend the deprecated default template for JS debugging --- lib/scripts/helpers.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/scripts/helpers.js b/lib/scripts/helpers.js index fdac13b71..677abbad7 100644 --- a/lib/scripts/helpers.js +++ b/lib/scripts/helpers.js @@ -79,7 +79,7 @@ function logError(e, file) { if (window.console && console.error) { console.error('The error "%s: %s" occurred in file "%s". ' + 'If this is in a plugin try updating or disabling the plugin, ' + - 'if this is in a template try updating the template or switching to the "default" or "dokuwiki" template.', + 'if this is in a template try updating the template or switching to the "dokuwiki" template.', e.name, e.message, file); } -} \ No newline at end of file +} -- cgit v1.2.3 From ea9bf4168ca264f9e7ca66fe468f61b9df1fc62a Mon Sep 17 00:00:00 2001 From: Anika Henke Date: Tue, 30 Jul 2013 17:23:55 +0100 Subject: fixed broken structure --- lib/tpl/dokuwiki/style.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/tpl/dokuwiki/style.ini b/lib/tpl/dokuwiki/style.ini index c6962fcd2..24faffdb3 100644 --- a/lib/tpl/dokuwiki/style.ini +++ b/lib/tpl/dokuwiki/style.ini @@ -33,7 +33,7 @@ css/_edit.css = screen css/_modal.css = screen css/_forms.css = screen css/_admin.css = screen -css/structure.css = screen +css/structure.less = screen css/design.less = screen css/pagetools.less = screen css/content.less = screen -- cgit v1.2.3 From b0a0b422439fd5c86ced0c8a7f89bb2b93a11564 Mon Sep 17 00:00:00 2001 From: Anika Henke Date: Tue, 30 Jul 2013 17:24:54 +0100 Subject: unlessified and lessified a few more css --- lib/tpl/dokuwiki/css/content.less | 27 +++++------ lib/tpl/dokuwiki/css/design.less | 94 ++++++++++++++++++------------------- lib/tpl/dokuwiki/css/mobile.less | 52 +++++++++++--------- lib/tpl/dokuwiki/css/structure.less | 67 ++++++++++++-------------- 4 files changed, 116 insertions(+), 124 deletions(-) diff --git a/lib/tpl/dokuwiki/css/content.less b/lib/tpl/dokuwiki/css/content.less index ae97d7d5e..56551fe3b 100644 --- a/lib/tpl/dokuwiki/css/content.less +++ b/lib/tpl/dokuwiki/css/content.less @@ -120,7 +120,6 @@ /* filenames for downloadable file and code blocks */ .dokuwiki dl.code, .dokuwiki dl.file { - dt, dt { background-color: @ini_background_site; .linear-gradient(~"top, @{ini_background_alt} 0%, @{ini_background_site} 100%"); @@ -132,24 +131,22 @@ padding: .3em .6em .1em; margin-bottom: -1px; float: left; - } - dt a, - dt a { - background-color: transparent; - font-size: 0.875em; - font-weight: normal; - display: block; - min-height: 16px; + + a { + background-color: transparent; + font-size: 0.875em; + font-weight: normal; + display: block; + min-height: 16px; + } } - dd, dd { margin: 0; clear: left; min-height: 1px; /* for IE7 */ } - pre, pre { box-shadow: inset -4px -4px .5em -.3em @ini_border; } @@ -157,12 +154,10 @@ [dir=rtl] .dokuwiki dl.code, [dir=rtl] .dokuwiki dl.file { - dt, dt { float: right; } - dd, dd { clear: right; } @@ -329,10 +324,10 @@ ul { padding: 0 0 0 1.2em; - } - ul li { - list-style-image: url(images/toc-bullet.png); + li { + list-style-image: url(images/toc-bullet.png); + } } ul li.clear { diff --git a/lib/tpl/dokuwiki/css/design.less b/lib/tpl/dokuwiki/css/design.less index aba9c9c7b..42292de49 100644 --- a/lib/tpl/dokuwiki/css/design.less +++ b/lib/tpl/dokuwiki/css/design.less @@ -100,11 +100,9 @@ margin-left: 0; } -#dokuwiki__usertools { - a.action { - padding-left: 20px; - background: transparent url(images/usertools.png) no-repeat 0 0; - } +#dokuwiki__usertools a.action { + padding-left: 20px; + background: transparent url(images/usertools.png) no-repeat 0 0; } [dir=rtl] #dokuwiki__usertools a.action { @@ -350,17 +348,14 @@ /* content ********************************************************************/ -.dokuwiki { - - .pageId { - position: absolute; - top: -2.3em; - right: -1em; - overflow: hidden; - padding: 1em 1em 0; - } +.dokuwiki .pageId { + position: absolute; + top: -2.3em; + right: -1em; + overflow: hidden; + padding: 1em 1em 0; - .pageId span { + span { font-size: 0.875em; border: solid @ini_background_alt; border-width: 1px 1px 0; @@ -372,39 +367,37 @@ box-shadow: 0 0 .5em @ini_text_alt; display: block; } +} - div.page { - background: @ini_background; - color: inherit; - border: 1px solid @ini_background_alt; - box-shadow: 0 0 .5em @ini_text_alt; - border-radius: 2px; - padding: 1.556em 2em 2em; - margin-bottom: .5em; - overflow: hidden; - word-wrap: break-word; - } +.dokuwiki div.page { + background: @ini_background; + color: inherit; + border: 1px solid @ini_background_alt; + box-shadow: 0 0 .5em @ini_text_alt; + border-radius: 2px; + padding: 1.556em 2em 2em; + margin-bottom: .5em; + overflow: hidden; + word-wrap: break-word; +} - .docInfo { - font-size: 0.875em; - text-align: right; - } +.dokuwiki .docInfo { + font-size: 0.875em; + text-align: right; +} - /* license note under edit window */ - div.license { - font-size: 93.75%; - } +/* license note under edit window */ +.dokuwiki div.license { + font-size: 93.75%; } -[dir=rtl] .dokuwiki { - .docInfo { - text-align: left; - } +[dir=rtl] .dokuwiki .docInfo { + text-align: left; +} - .pageId { - right: auto; - left: -1em; - } +[dir=rtl] .dokuwiki .pageId { + right: auto; + left: -1em; } /* footer @@ -427,15 +420,18 @@ font-size: 100%; } - div.buttons a img { - opacity: 0.5; - } + div.buttons a { + img { + opacity: 0.5; + } - div.buttons a:hover img, - div.buttons a:active img, - div.buttons a:focus img { - opacity: 1; + &:hover img, + &:active img, + &:focus img { + opacity: 1; + } } + } [dir=rtl] #dokuwiki__footer .license img { diff --git a/lib/tpl/dokuwiki/css/mobile.less b/lib/tpl/dokuwiki/css/mobile.less index 4362656a1..289f5afa3 100644 --- a/lib/tpl/dokuwiki/css/mobile.less +++ b/lib/tpl/dokuwiki/css/mobile.less @@ -40,22 +40,24 @@ #dokuwiki__aside h3.toggle { font-size: 1em; -} -#dokuwiki__aside h3.toggle.closed { - margin-bottom: 0; - padding-bottom: 0; -} -#dokuwiki__aside h3.toggle.open { - border-bottom: 1px solid @ini_border; + + &.closed { + margin-bottom: 0; + padding-bottom: 0; + } + &.open { + border-bottom: 1px solid @ini_border; + } } .showSidebar #dokuwiki__content { float: none; margin-left: 0; width: 100%; -} -.showSidebar #dokuwiki__content > .pad { - margin-left: 0; + + > .pad { + margin-left: 0; + } } [dir=rtl] .showSidebar #dokuwiki__content, @@ -133,9 +135,10 @@ body { #dokuwiki__site { max-width: 100%; -} -#dokuwiki__site > .site { - padding: 0 .5em; + + > .site { + padding: 0 .5em; + } } #dokuwiki__header { padding: .5em 0; @@ -154,19 +157,21 @@ body { list-style: none; padding-left: 0; margin: 0; + + li { + margin-left: .35em; + display: inline; + } } [dir=rtl] #dokuwiki__header ul.a11y.skip { left: auto !important; right: 0 !important; float: left; padding-right: 0; -} -#dokuwiki__header ul.a11y.skip li { - margin-left: .35em; - display: inline; -} -[dir=rtl] #dokuwiki__header ul.a11y.skip li { - margin: 0 .35em 0 0; + + li { + margin: 0 .35em 0 0; + } } #dokuwiki__header .headings, @@ -264,13 +269,14 @@ body { .dokuwiki label.block { text-align: left; + + span { + display: block; + } } [dir=rtl] .dokuwiki label.block { text-align: right; } -.dokuwiki label.block span { - display: block; -} /* _edit */ .dokuwiki div.section_highlight { diff --git a/lib/tpl/dokuwiki/css/structure.less b/lib/tpl/dokuwiki/css/structure.less index f24440f08..3ea2f83eb 100644 --- a/lib/tpl/dokuwiki/css/structure.less +++ b/lib/tpl/dokuwiki/css/structure.less @@ -18,28 +18,27 @@ body { #dokuwiki__header { width: 100%; -} -#dokuwiki__header > .pad { -} + .headings { + float: left; + } -#dokuwiki__header .headings { - float: left; + .tools { + float: right; + text-align: right; + } } -[dir=rtl] #dokuwiki__header .headings { - float: right; - text-align: right; -} +[dir=rtl] #dokuwiki__header { + .headings { + float: right; + text-align: right; + } -#dokuwiki__header .tools { - float: right; - text-align: right; -} - -[dir=rtl] #dokuwiki__header .tools { - float: left; - text-align: left; + .tools { + float: left; + text-align: left; + } } #dokuwiki__site .wrapper { @@ -51,44 +50,40 @@ body { float: left; position: relative; display: block; + + > .pad { + margin: 0 1.5em 0 0; + } } [dir=rtl] #dokuwiki__aside { float: right; -} - -#dokuwiki__aside > .pad { - margin: 0 1.5em 0 0; -} - -[dir=rtl] #dokuwiki__aside > .pad { - margin: 0 0 0 1.5em; + > .pad { + margin: 0 0 0 1.5em; + } } .showSidebar #dokuwiki__content { float: right; margin-left: (-1 * @ini_sidebar_width); width: 100%; + + > .pad { + margin-left: @ini_sidebar_width; + } } [dir=rtl] .showSidebar #dokuwiki__content { float: left; margin-left: 0; margin-right: (-1 * @ini_sidebar_width); -} -.showSidebar #dokuwiki__content > .pad { - margin-left: @ini_sidebar_width; -} - -[dir=rtl] .showSidebar #dokuwiki__content > .pad { - margin-left: 0; - margin-right: @ini_sidebar_width; + > .pad { + margin-left: 0; + margin-right: @ini_sidebar_width; + } } #dokuwiki__footer { clear: both; } - -#dokuwiki__footer > .pad { -} -- cgit v1.2.3 From fc498a423a295d14127239e3838b6fb7bb0c8529 Mon Sep 17 00:00:00 2001 From: Christopher Smith Date: Tue, 30 Jul 2013 18:48:02 +0200 Subject: FS#2770 - prevent and syntax regex matching token names which start 'Lexer->addEntryPattern(')',$mode,'code'); + $this->Lexer->addEntryPattern(')',$mode,'code'); } function postConnect() { @@ -571,7 +571,7 @@ class Doku_Parser_Mode_code extends Doku_Parser_Mode { class Doku_Parser_Mode_file extends Doku_Parser_Mode { function connectTo($mode) { - $this->Lexer->addEntryPattern(')',$mode,'file'); + $this->Lexer->addEntryPattern(')',$mode,'file'); } function postConnect() { -- cgit v1.2.3 From 483b6238a3599595a678f995b2c7c9e9f07a7ce7 Mon Sep 17 00:00:00 2001 From: Michael Hamann Date: Tue, 30 Jul 2013 18:46:02 +0200 Subject: Add truly random numbers and use them in places where randomness matters --- _test/tests/inc/auth_random.test.php | 20 +++++++ inc/PassHash.class.php | 2 +- inc/auth.php | 108 +++++++++++++++++++++++++++++++++-- 3 files changed, 123 insertions(+), 7 deletions(-) create mode 100644 _test/tests/inc/auth_random.test.php diff --git a/_test/tests/inc/auth_random.test.php b/_test/tests/inc/auth_random.test.php new file mode 100644 index 000000000..f380eba53 --- /dev/null +++ b/_test/tests/inc/auth_random.test.php @@ -0,0 +1,20 @@ +assertTrue($rand <= 2000, 'The generated number was above the limit'); + $this->assertTrue($rand >= 300, 'The generate number was too low'); + } + + function testLargeRandoms() { + $min = (1 << 30); + $max = $min + (1 << 33) + 17; + $rand = auth_random($min, $max); + $this->assertTrue($rand >= $min, 'The generated number was too low'); + $this->assertTrue($rand <= $max, 'The generated number was too high'); + } +} diff --git a/inc/PassHash.class.php b/inc/PassHash.class.php index 61bd74939..607661a22 100644 --- a/inc/PassHash.class.php +++ b/inc/PassHash.class.php @@ -98,7 +98,7 @@ class PassHash { $salt = ''; $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; for($i = 0; $i < $len; $i++) { - $salt .= $chars[mt_rand(0, 61)]; + $salt .= $chars[auth_random(0, 61)]; } return $salt; } diff --git a/inc/auth.php b/inc/auth.php index 537d44c01..ace98f51f 100644 --- a/inc/auth.php +++ b/inc/auth.php @@ -294,7 +294,7 @@ function auth_validateToken($token) { * @return string The auth token */ function auth_createToken() { - $token = md5(mt_rand()); + $token = md5(auth_randombytes(16)); @session_start(); // reopen the session if needed $_SESSION[DOKU_COOKIE]['auth']['token'] = $token; session_write_close(); @@ -349,6 +349,102 @@ function auth_cookiesalt($addsession = false) { return $salt; } +/** + * Return truly (pseudo) random bytes if available, otherwise fall back to mt_rand + * + * @author Mark Seecof + * @author Michael Hamann + * @link http://www.php.net/manual/de/function.mt-rand.php#83655 + * @param int $length number of bytes to get + * @throws Exception when no usable random generator is found + * @return string binary random strings + */ +function auth_randombytes($length) { + $strong = false; + $rbytes = false; + + if (function_exists('openssl_random_pseudo_bytes') + && (version_compare(PHP_VERSION, '5.3.4') >= 0 + || strtoupper(substr(PHP_OS, 0, 3)) !== 'WIN') + ) { + $rbytes = openssl_random_pseudo_bytes($length, $strong); + } + + if (!$strong && function_exists('mcrypt_create_iv') + && (version_compare(PHP_VERSION, '5.3.7') >= 0 + || strtoupper(substr(PHP_OS, 0, 3)) !== 'WIN') + ) { + $rbytes = mcrypt_create_iv($length, MCRYPT_DEV_URANDOM); + if ($rbytes !== false && strlen($rbytes) === $length) { + $strong = true; + } + } + + + // If no strong randoms available, try OS the specific ways + if(!$strong) { + // Unix/Linux platform + $fp = @fopen('/dev/urandom', 'rb'); + if($fp !== false) { + $rbytes = fread($fp, $length); + fclose($fp); + } + + // MS-Windows platform + if(class_exists('COM')) { + // http://msdn.microsoft.com/en-us/library/aa388176(VS.85).aspx + try { + $CAPI_Util = new COM('CAPICOM.Utilities.1'); + $rbytes = $CAPI_Util->GetRandom($length, 0); + + // if we ask for binary data PHP munges it, so we + // request base64 return value. + if($rbytes) $rbytes = base64_decode($rbytes); + } catch(Exception $ex) { + // fail + } + } + } + if(strlen($rbytes) < $length) $rbytes = false; + + // still no random bytes available - fall back to mt_rand() + if($rbytes === false) { + $rbytes = ''; + for ($i = 0; $i < $length; ++$i) { + $rbytes .= chr(mt_rand(0, 255)); + } + } + + return $rbytes; +} + +/** + * Random number generator using the best available source + * + * @author Michael Samuel + * @author Michael Hamann + * @param int $min + * @param int $max + * @return int + */ +function auth_random($min, $max) { + $abs_max = $max - $min; + + $nbits = 0; + for ($n = $abs_max; $n > 0; $n >>= 1) { + ++$nbits; + } + + $mask = (1 << $nbits) - 1; + do { + $bytes = auth_randombytes(PHP_INT_SIZE); + $integers = unpack('Inum', $bytes); + $integer = $integers["num"] & $mask; + } while ($integer > $abs_max); + + return $min + $integer; +} + /** * Log out the current user * @@ -703,12 +799,12 @@ function auth_pwgen($foruser = '') { //use thre syllables... for($i = 0; $i < 3; $i++) { - $data['password'] .= $c[mt_rand(0, strlen($c) - 1)]; - $data['password'] .= $v[mt_rand(0, strlen($v) - 1)]; - $data['password'] .= $a[mt_rand(0, strlen($a) - 1)]; + $data['password'] .= $c[auth_random(0, strlen($c) - 1)]; + $data['password'] .= $v[auth_random(0, strlen($v) - 1)]; + $data['password'] .= $a[auth_random(0, strlen($a) - 1)]; } //... and add a nice number and special - $data['password'] .= mt_rand(10, 99).$s[mt_rand(0, strlen($s) - 1)]; + $data['password'] .= auth_random(10, 99).$s[auth_random(0, strlen($s) - 1)]; } $evt->advise_after(); @@ -1007,7 +1103,7 @@ function act_resendpwd() { } // generate auth token - $token = md5(uniqid(mt_rand(), true)); // random secret + $token = md5(auth_randombytes(16)); // random secret $tfile = $conf['cachedir'].'/'.$token{0}.'/'.$token.'.pwauth'; $url = wl('', array('do'=> 'resendpwd', 'pwauth'=> $token), true, '&'); -- cgit v1.2.3 From 27058a053ea6ffa90fee7aaf26f81ab1109d6df3 Mon Sep 17 00:00:00 2001 From: Michael Hamann Date: Tue, 30 Jul 2013 13:40:59 +0200 Subject: Fix and add type declarations for the auth system --- inc/auth.php | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/inc/auth.php b/inc/auth.php index 47b29eff7..537d44c01 100644 --- a/inc/auth.php +++ b/inc/auth.php @@ -40,7 +40,7 @@ function auth_setup() { global $INPUT; global $AUTH_ACL; global $lang; - global $config_cascade; + /* @var Doku_Plugin_Controller $plugin_controller */ global $plugin_controller; $AUTH_ACL = array(); @@ -207,7 +207,7 @@ function auth_login($user, $pass, $sticky = false, $silent = false) { global $USERINFO; global $conf; global $lang; - /* @var auth_basic $auth */ + /* @var DokuWiki_Auth_Plugin $auth */ global $auth; $sticky ? $sticky = true : $sticky = false; //sanity check @@ -361,7 +361,7 @@ function auth_cookiesalt($addsession = false) { function auth_logoff($keepbc = false) { global $conf; global $USERINFO; - /* @var auth_basic $auth */ + /* @var DokuWiki_Auth_Plugin $auth */ global $auth; // make sure the session is writable (it usually is) @@ -407,7 +407,7 @@ function auth_logoff($keepbc = false) { function auth_ismanager($user = null, $groups = null, $adminonly = false) { global $conf; global $USERINFO; - /* @var auth_basic $auth */ + /* @var DokuWiki_Auth_Plugin $auth */ global $auth; if(!$auth) return false; @@ -460,7 +460,7 @@ function auth_isadmin($user = null, $groups = null) { * @return bool true for membership acknowledged */ function auth_isMember($memberlist, $user, array $groups) { - /* @var auth_basic $auth */ + /* @var DokuWiki_Auth_Plugin $auth */ global $auth; if(!$auth) return false; @@ -526,7 +526,7 @@ function auth_quickaclcheck($id) { function auth_aclcheck($id, $user, $groups) { global $conf; global $AUTH_ACL; - /* @var auth_basic $auth */ + /* @var DokuWiki_Auth_Plugin $auth */ global $auth; // if no ACL is used always return upload rights @@ -725,7 +725,7 @@ function auth_pwgen($foruser = '') { */ function auth_sendPassword($user, $password) { global $lang; - /* @var auth_basic $auth */ + /* @var DokuWiki_Auth_Plugin $auth */ global $auth; if(!$auth) return false; @@ -759,7 +759,7 @@ function auth_sendPassword($user, $password) { function register() { global $lang; global $conf; - /* @var auth_basic $auth */ + /* @var DokuWiki_Auth_Plugin $auth */ global $auth; global $INPUT; @@ -828,7 +828,7 @@ function register() { function updateprofile() { global $conf; global $lang; - /* @var auth_basic $auth */ + /* @var DokuWiki_Auth_Plugin $auth */ global $auth; /* @var Input $INPUT */ global $INPUT; @@ -918,7 +918,7 @@ function updateprofile() { function act_resendpwd() { global $lang; global $conf; - /* @var auth_basic $auth */ + /* @var DokuWiki_Auth_Plugin $auth */ global $auth; /* @var Input $INPUT */ global $INPUT; @@ -1084,7 +1084,7 @@ function auth_verifyPassword($clear, $crypt) { */ function auth_setCookie($user, $pass, $sticky) { global $conf; - /* @var auth_basic $auth */ + /* @var DokuWiki_Auth_Plugin $auth */ global $auth; global $USERINFO; -- cgit v1.2.3 From 30d544a4c371bf69023e4d9958bc2b00d84387d9 Mon Sep 17 00:00:00 2001 From: Michael Hamann Date: Tue, 30 Jul 2013 18:47:58 +0200 Subject: Use a new, truly random secret for cookie encryption --- inc/auth.php | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/inc/auth.php b/inc/auth.php index ace98f51f..a1da971ae 100644 --- a/inc/auth.php +++ b/inc/auth.php @@ -219,7 +219,7 @@ function auth_login($user, $pass, $sticky = false, $silent = false) { if($auth->checkPass($user, $pass)) { // make logininfo globally available $_SERVER['REMOTE_USER'] = $user; - $secret = auth_cookiesalt(!$sticky); //bind non-sticky to session + $secret = auth_cookiesalt(!$sticky, true); //bind non-sticky to session auth_setCookie($user, PMA_blowfish_encrypt($pass, $secret), $sticky); return true; } else { @@ -250,7 +250,7 @@ function auth_login($user, $pass, $sticky = false, $silent = false) { return true; } // no we don't trust it yet - recheck pass but silent - $secret = auth_cookiesalt(!$sticky); //bind non-sticky to session + $secret = auth_cookiesalt(!$sticky, true); //bind non-sticky to session $pass = PMA_blowfish_decrypt($pass, $secret); return auth_login($user, $pass, $sticky, true); } @@ -333,14 +333,18 @@ function auth_browseruid() { * * @author Andreas Gohr * @param bool $addsession if true, the sessionid is added to the salt + * @param bool $secure if security is more important than keeping the old value * @return string */ -function auth_cookiesalt($addsession = false) { +function auth_cookiesalt($addsession = false, $secure = false) { global $conf; $file = $conf['metadir'].'/_htcookiesalt'; + if ($secure || !file_exists($file)) { + $file = $conf['metadir'].'/_htcookiesalt2'; + } $salt = io_readFile($file); if(empty($salt)) { - $salt = uniqid(rand(), true); + $salt = bin2hex(auth_randombytes(64)); io_saveFile($file, $salt); } if($addsession) { @@ -988,7 +992,7 @@ function updateprofile() { // update cookie and session with the changed data if($changes['pass']) { list( /*user*/, $sticky, /*pass*/) = auth_getCookie(); - $pass = PMA_blowfish_encrypt($changes['pass'], auth_cookiesalt(!$sticky)); + $pass = PMA_blowfish_encrypt($changes['pass'], auth_cookiesalt(!$sticky, true)); auth_setCookie($_SERVER['REMOTE_USER'], $pass, (bool) $sticky); } return true; -- cgit v1.2.3 From 04369c3eae728e14962c41d1ab259f9e7ed99144 Mon Sep 17 00:00:00 2001 From: Michael Hamann Date: Tue, 30 Jul 2013 18:50:28 +0200 Subject: Add AES from phpseclib and use it for cookie encryption This replaces the deprecated and broken Blowfish implementation that has previously been used and should provide a lot more security. --- _test/tests/inc/auth_encryption.test.php | 12 + inc/auth.php | 40 +- inc/load.php | 4 + inc/phpseclib/Crypt_AES.php | 188 ++ inc/phpseclib/Crypt_Base.php | 1989 ++++++++++++++++ inc/phpseclib/Crypt_Hash.php | 823 +++++++ inc/phpseclib/Crypt_Rijndael.php | 1374 +++++++++++ inc/phpseclib/LICENSE | 21 + inc/phpseclib/Math_BigInteger.php | 3651 ++++++++++++++++++++++++++++++ inc/phpseclib/update.sh | 8 + 10 files changed, 8107 insertions(+), 3 deletions(-) create mode 100644 _test/tests/inc/auth_encryption.test.php create mode 100644 inc/phpseclib/Crypt_AES.php create mode 100644 inc/phpseclib/Crypt_Base.php create mode 100644 inc/phpseclib/Crypt_Hash.php create mode 100644 inc/phpseclib/Crypt_Rijndael.php create mode 100644 inc/phpseclib/LICENSE create mode 100644 inc/phpseclib/Math_BigInteger.php create mode 100755 inc/phpseclib/update.sh diff --git a/_test/tests/inc/auth_encryption.test.php b/_test/tests/inc/auth_encryption.test.php new file mode 100644 index 000000000..041eba00e --- /dev/null +++ b/_test/tests/inc/auth_encryption.test.php @@ -0,0 +1,12 @@ +assertEquals($data, auth_decrypt(auth_encrypt($data, $secret), $secret)); + } +} diff --git a/inc/auth.php b/inc/auth.php index a1da971ae..f02bfebca 100644 --- a/inc/auth.php +++ b/inc/auth.php @@ -220,7 +220,7 @@ function auth_login($user, $pass, $sticky = false, $silent = false) { // make logininfo globally available $_SERVER['REMOTE_USER'] = $user; $secret = auth_cookiesalt(!$sticky, true); //bind non-sticky to session - auth_setCookie($user, PMA_blowfish_encrypt($pass, $secret), $sticky); + auth_setCookie($user, auth_encrypt($pass, $secret), $sticky); return true; } else { //invalid credentials - log off @@ -251,7 +251,7 @@ function auth_login($user, $pass, $sticky = false, $silent = false) { } // no we don't trust it yet - recheck pass but silent $secret = auth_cookiesalt(!$sticky, true); //bind non-sticky to session - $pass = PMA_blowfish_decrypt($pass, $secret); + $pass = auth_decrypt($pass, $secret); return auth_login($user, $pass, $sticky, true); } } @@ -449,6 +449,40 @@ function auth_random($min, $max) { return $min + $integer; } +/** + * Encrypt data using the given secret using AES + * + * The mode is CBC with a random initialization vector, the key is derived + * using pbkdf2. + * + * @param string $data The data that shall be encrypted + * @param string $secret The secret/password that shall be used + * @return string The ciphertext + */ +function auth_encrypt($data, $secret) { + $iv = auth_randombytes(16); + $cipher = new Crypt_AES(); + $cipher->setPassword($secret); + + return $cipher->encrypt($iv.$data); +} + +/** + * Decrypt the given AES ciphertext + * + * The mode is CBC, the key is derived using pbkdf2 + * + * @param string $ciphertext The encrypted data + * @param string $secret The secret/password that shall be used + * @return string The decrypted data + */ +function auth_decrypt($ciphertext, $secret) { + $cipher = new Crypt_AES(); + $cipher->setPassword($secret); + + return substr($cipher->decrypt($ciphertext), 16); +} + /** * Log out the current user * @@ -992,7 +1026,7 @@ function updateprofile() { // update cookie and session with the changed data if($changes['pass']) { list( /*user*/, $sticky, /*pass*/) = auth_getCookie(); - $pass = PMA_blowfish_encrypt($changes['pass'], auth_cookiesalt(!$sticky, true)); + $pass = auth_encrypt($changes['pass'], auth_cookiesalt(!$sticky, true)); auth_setCookie($_SERVER['REMOTE_USER'], $pass, (bool) $sticky); } return true; diff --git a/inc/load.php b/inc/load.php index 5ca9b4cd8..7fb328215 100644 --- a/inc/load.php +++ b/inc/load.php @@ -82,6 +82,10 @@ function load_autoload($name){ 'RemoteAPI' => DOKU_INC.'inc/remote.php', 'RemoteAPICore' => DOKU_INC.'inc/RemoteAPICore.php', 'Subscription' => DOKU_INC.'inc/subscription.php', + 'Crypt_Base' => DOKU_INC.'inc/phpseclib/Crypt_Base.php', + 'Crypt_Rijndael' => DOKU_INC.'inc/phpseclib/Crypt_Rijndael.php', + 'Crypt_AES' => DOKU_INC.'inc/phpseclib/Crypt_AES.php', + 'Crypt_Hash' => DOKU_INC.'inc/phpseclib/Crypt_Hash.php', 'DokuWiki_Action_Plugin' => DOKU_PLUGIN.'action.php', 'DokuWiki_Admin_Plugin' => DOKU_PLUGIN.'admin.php', diff --git a/inc/phpseclib/Crypt_AES.php b/inc/phpseclib/Crypt_AES.php new file mode 100644 index 000000000..81fa2feab --- /dev/null +++ b/inc/phpseclib/Crypt_AES.php @@ -0,0 +1,188 @@ + + * setKey('abcdefghijklmnop'); + * + * $size = 10 * 1024; + * $plaintext = ''; + * for ($i = 0; $i < $size; $i++) { + * $plaintext.= 'a'; + * } + * + * echo $aes->decrypt($aes->encrypt($plaintext)); + * ?> + * + * + * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @category Crypt + * @package Crypt_AES + * @author Jim Wigginton + * @copyright MMVIII Jim Wigginton + * @license http://www.opensource.org/licenses/mit-license.html MIT License + * @link http://phpseclib.sourceforge.net + */ + +/** + * Include Crypt_Rijndael + */ +if (!class_exists('Crypt_Rijndael')) { + require_once('Rijndael.php'); +} + +/**#@+ + * @access public + * @see Crypt_AES::encrypt() + * @see Crypt_AES::decrypt() + */ +/** + * Encrypt / decrypt using the Counter mode. + * + * Set to -1 since that's what Crypt/Random.php uses to index the CTR mode. + * + * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Counter_.28CTR.29 + */ +define('CRYPT_AES_MODE_CTR', CRYPT_MODE_CTR); +/** + * Encrypt / decrypt using the Electronic Code Book mode. + * + * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Electronic_codebook_.28ECB.29 + */ +define('CRYPT_AES_MODE_ECB', CRYPT_MODE_ECB); +/** + * Encrypt / decrypt using the Code Book Chaining mode. + * + * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher-block_chaining_.28CBC.29 + */ +define('CRYPT_AES_MODE_CBC', CRYPT_MODE_CBC); +/** + * Encrypt / decrypt using the Cipher Feedback mode. + * + * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher_feedback_.28CFB.29 + */ +define('CRYPT_AES_MODE_CFB', CRYPT_MODE_CFB); +/** + * Encrypt / decrypt using the Cipher Feedback mode. + * + * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Output_feedback_.28OFB.29 + */ +define('CRYPT_AES_MODE_OFB', CRYPT_MODE_OFB); +/**#@-*/ + +/**#@+ + * @access private + * @see Crypt_AES::Crypt_AES() + */ +/** + * Toggles the internal implementation + */ +define('CRYPT_AES_MODE_INTERNAL', CRYPT_MODE_INTERNAL); +/** + * Toggles the mcrypt implementation + */ +define('CRYPT_AES_MODE_MCRYPT', CRYPT_MODE_MCRYPT); +/**#@-*/ + +/** + * Pure-PHP implementation of AES. + * + * @author Jim Wigginton + * @version 0.1.0 + * @access public + * @package Crypt_AES + */ +class Crypt_AES extends Crypt_Rijndael { + /** + * The namespace used by the cipher for its constants. + * + * @see Crypt_Base::const_namespace + * @var String + * @access private + */ + var $const_namespace = 'AES'; + + /** + * Default Constructor. + * + * Determines whether or not the mcrypt extension should be used. + * + * $mode could be: + * + * - CRYPT_AES_MODE_ECB + * + * - CRYPT_AES_MODE_CBC + * + * - CRYPT_AES_MODE_CTR + * + * - CRYPT_AES_MODE_CFB + * + * - CRYPT_AES_MODE_OFB + * + * If not explictly set, CRYPT_AES_MODE_CBC will be used. + * + * @see Crypt_Rijndael::Crypt_Rijndael() + * @see Crypt_Base::Crypt_Base() + * @param optional Integer $mode + * @access public + */ + function Crypt_AES($mode = CRYPT_AES_MODE_CBC) + { + parent::Crypt_Rijndael($mode); + } + + /** + * Dummy function + * + * Since Crypt_AES extends Crypt_Rijndael, this function is, technically, available, but it doesn't do anything. + * + * @see Crypt_Rijndael::setBlockLength() + * @access public + * @param Integer $length + */ + function setBlockLength($length) + { + return; + } +} + +// vim: ts=4:sw=4:et: +// vim6: fdl=1: diff --git a/inc/phpseclib/Crypt_Base.php b/inc/phpseclib/Crypt_Base.php new file mode 100644 index 000000000..7c650ca72 --- /dev/null +++ b/inc/phpseclib/Crypt_Base.php @@ -0,0 +1,1989 @@ + + * @author Hans-Juergen Petrich + * @copyright MMVII Jim Wigginton + * @license http://www.opensource.org/licenses/mit-license.html MIT License + * @version 1.0.1 + * @link http://phpseclib.sourceforge.net + */ + +/**#@+ + * @access public + * @see Crypt_Base::encrypt() + * @see Crypt_Base::decrypt() + */ +/** + * Encrypt / decrypt using the Counter mode. + * + * Set to -1 since that's what Crypt/Random.php uses to index the CTR mode. + * + * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Counter_.28CTR.29 + */ +define('CRYPT_MODE_CTR', -1); +/** + * Encrypt / decrypt using the Electronic Code Book mode. + * + * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Electronic_codebook_.28ECB.29 + */ +define('CRYPT_MODE_ECB', 1); +/** + * Encrypt / decrypt using the Code Book Chaining mode. + * + * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher-block_chaining_.28CBC.29 + */ +define('CRYPT_MODE_CBC', 2); +/** + * Encrypt / decrypt using the Cipher Feedback mode. + * + * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher_feedback_.28CFB.29 + */ +define('CRYPT_MODE_CFB', 3); +/** + * Encrypt / decrypt using the Output Feedback mode. + * + * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Output_feedback_.28OFB.29 + */ +define('CRYPT_MODE_OFB', 4); +/** + * Encrypt / decrypt using streaming mode. + * + */ +define('CRYPT_MODE_STREAM', 5); +/**#@-*/ + +/**#@+ + * @access private + * @see Crypt_Base::Crypt_Base() + */ +/** + * Base value for the internal implementation $engine switch + */ +define('CRYPT_MODE_INTERNAL', 1); +/** + * Base value for the mcrypt implementation $engine switch + */ +define('CRYPT_MODE_MCRYPT', 2); +/**#@-*/ + +/** + * Base Class for all Crypt_* cipher classes + * + * @author Jim Wigginton + * @author Hans-Juergen Petrich + * @version 1.0.0 + * @access public + * @package Crypt_Base + */ +class Crypt_Base { + /** + * The Encryption Mode + * + * @see Crypt_Base::Crypt_Base() + * @var Integer + * @access private + */ + var $mode; + + /** + * The Block Length of the block cipher + * + * @var Integer + * @access private + */ + var $block_size = 16; + + /** + * The Key + * + * @see Crypt_Base::setKey() + * @var String + * @access private + */ + var $key = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; + + /** + * The Initialization Vector + * + * @see Crypt_Base::setIV() + * @var String + * @access private + */ + var $iv; + + /** + * A "sliding" Initialization Vector + * + * @see Crypt_Base::enableContinuousBuffer() + * @see Crypt_Base::_clearBuffers() + * @var String + * @access private + */ + var $encryptIV; + + /** + * A "sliding" Initialization Vector + * + * @see Crypt_Base::enableContinuousBuffer() + * @see Crypt_Base::_clearBuffers() + * @var String + * @access private + */ + var $decryptIV; + + /** + * Continuous Buffer status + * + * @see Crypt_Base::enableContinuousBuffer() + * @var Boolean + * @access private + */ + var $continuousBuffer = false; + + /** + * Encryption buffer for CTR, OFB and CFB modes + * + * @see Crypt_Base::encrypt() + * @see Crypt_Base::_clearBuffers() + * @var Array + * @access private + */ + var $enbuffer; + + /** + * Decryption buffer for CTR, OFB and CFB modes + * + * @see Crypt_Base::decrypt() + * @see Crypt_Base::_clearBuffers() + * @var Array + * @access private + */ + var $debuffer; + + /** + * mcrypt resource for encryption + * + * The mcrypt resource can be recreated every time something needs to be created or it can be created just once. + * Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode. + * + * @see Crypt_Base::encrypt() + * @var Resource + * @access private + */ + var $enmcrypt; + + /** + * mcrypt resource for decryption + * + * The mcrypt resource can be recreated every time something needs to be created or it can be created just once. + * Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode. + * + * @see Crypt_Base::decrypt() + * @var Resource + * @access private + */ + var $demcrypt; + + /** + * Does the enmcrypt resource need to be (re)initialized? + * + * @see Crypt_Twofish::setKey() + * @see Crypt_Twofish::setIV() + * @var Boolean + * @access private + */ + var $enchanged = true; + + /** + * Does the demcrypt resource need to be (re)initialized? + * + * @see Crypt_Twofish::setKey() + * @see Crypt_Twofish::setIV() + * @var Boolean + * @access private + */ + var $dechanged = true; + + /** + * mcrypt resource for CFB mode + * + * mcrypt's CFB mode, in (and only in) buffered context, + * is broken, so phpseclib implements the CFB mode by it self, + * even when the mcrypt php extension is available. + * + * In order to do the CFB-mode work (fast) phpseclib + * use a separate ECB-mode mcrypt resource. + * + * @link http://phpseclib.sourceforge.net/cfb-demo.phps + * @see Crypt_Base::encrypt() + * @see Crypt_Base::decrypt() + * @see Crypt_Base::_setupMcrypt() + * @var Resource + * @access private + */ + var $ecb; + + /** + * Optimizing value while CFB-encrypting + * + * Only relevant if $continuousBuffer enabled + * and $engine == CRYPT_MODE_MCRYPT + * + * It's faster to re-init $enmcrypt if + * $buffer bytes > $cfb_init_len than + * using the $ecb resource furthermore. + * + * This value depends of the choosen cipher + * and the time it would be needed for it's + * initialization [by mcrypt_generic_init()] + * which, typically, depends on the complexity + * on its internaly Key-expanding algorithm. + * + * @see Crypt_Base::encrypt() + * @var Integer + * @access private + */ + var $cfb_init_len = 600; + + /** + * Does internal cipher state need to be (re)initialized? + * + * @see setKey() + * @see setIV() + * @see disableContinuousBuffer() + * @var Boolean + * @access private + */ + var $changed = true; + + /** + * Padding status + * + * @see Crypt_Base::enablePadding() + * @var Boolean + * @access private + */ + var $padding = true; + + /** + * Is the mode one that is paddable? + * + * @see Crypt_Base::Crypt_Base() + * @var Boolean + * @access private + */ + var $paddable = false; + + /** + * Holds which crypt engine internaly should be use, + * which will be determined automatically on __construct() + * + * Currently available $engines are: + * - CRYPT_MODE_MCRYPT (fast, php-extension: mcrypt, extension_loaded('mcrypt') required) + * - CRYPT_MODE_INTERNAL (slower, pure php-engine, no php-extension required) + * + * In the pipeline... maybe. But currently not available: + * - CRYPT_MODE_OPENSSL (very fast, php-extension: openssl, extension_loaded('openssl') required) + * + * If possible, CRYPT_MODE_MCRYPT will be used for each cipher. + * Otherwise CRYPT_MODE_INTERNAL + * + * @see Crypt_Base::encrypt() + * @see Crypt_Base::decrypt() + * @var Integer + * @access private + */ + var $engine; + + /** + * The mcrypt specific name of the cipher + * + * Only used if $engine == CRYPT_MODE_MCRYPT + * + * @link http://www.php.net/mcrypt_module_open + * @link http://www.php.net/mcrypt_list_algorithms + * @see Crypt_Base::_setupMcrypt() + * @var String + * @access private + */ + var $cipher_name_mcrypt; + + /** + * The default password key_size used by setPassword() + * + * @see Crypt_Base::setPassword() + * @var Integer + * @access private + */ + var $password_key_size = 32; + + /** + * The default salt used by setPassword() + * + * @see Crypt_Base::setPassword() + * @var String + * @access private + */ + var $password_default_salt = 'phpseclib/salt'; + + /** + * The namespace used by the cipher for its constants. + * + * ie: AES.php is using CRYPT_AES_MODE_* for its constants + * so $const_namespace is AES + * + * DES.php is using CRYPT_DES_MODE_* for its constants + * so $const_namespace is DES... and so on + * + * All CRYPT_<$const_namespace>_MODE_* are aliases of + * the generic CRYPT_MODE_* constants, so both could be used + * for each cipher. + * + * Example: + * $aes = new Crypt_AES(CRYPT_AES_MODE_CFB); // $aes will operate in cfb mode + * $aes = new Crypt_AES(CRYPT_MODE_CFB); // identical + * + * @see Crypt_Base::Crypt_Base() + * @var String + * @access private + */ + var $const_namespace; + + /** + * The name of the performance-optimized callback function + * + * Used by encrypt() / decrypt() + * only if $engine == CRYPT_MODE_INTERNAL + * + * @see Crypt_Base::encrypt() + * @see Crypt_Base::decrypt() + * @see Crypt_Base::_setupInlineCrypt() + * @see Crypt_Base::$use_inline_crypt + * @var Callback + * @access private + */ + var $inline_crypt; + + /** + * Holds whether performance-optimized $inline_crypt() can/should be used. + * + * @see Crypt_Base::encrypt() + * @see Crypt_Base::decrypt() + * @see Crypt_Base::inline_crypt + * @var mixed + * @access private + */ + var $use_inline_crypt; + + /** + * Default Constructor. + * + * Determines whether or not the mcrypt extension should be used. + * + * $mode could be: + * + * - CRYPT_MODE_ECB + * + * - CRYPT_MODE_CBC + * + * - CRYPT_MODE_CTR + * + * - CRYPT_MODE_CFB + * + * - CRYPT_MODE_OFB + * + * (or the alias constants of the choosen cipher, for example for AES: CRYPT_AES_MODE_ECB or CRYPT_AES_MODE_CBC ...) + * + * If not explictly set, CRYPT_MODE_CBC will be used. + * + * @param optional Integer $mode + * @access public + */ + function Crypt_Base($mode = CRYPT_MODE_CBC) + { + $const_crypt_mode = 'CRYPT_' . $this->const_namespace . '_MODE'; + + // Determining the availibility of mcrypt support for the cipher + if (!defined($const_crypt_mode)) { + switch (true) { + case extension_loaded('mcrypt') && in_array($this->cipher_name_mcrypt, mcrypt_list_algorithms()): + define($const_crypt_mode, CRYPT_MODE_MCRYPT); + break; + default: + define($const_crypt_mode, CRYPT_MODE_INTERNAL); + } + } + + // Determining which internal $engine should be used. + // The fastes possible first. + switch (true) { + case empty($this->cipher_name_mcrypt): // The cipher module has no mcrypt-engine support at all so we force CRYPT_MODE_INTERNAL + $this->engine = CRYPT_MODE_INTERNAL; + break; + case constant($const_crypt_mode) == CRYPT_MODE_MCRYPT: + $this->engine = CRYPT_MODE_MCRYPT; + break; + default: + $this->engine = CRYPT_MODE_INTERNAL; + } + + // $mode dependent settings + switch ($mode) { + case CRYPT_MODE_ECB: + $this->paddable = true; + $this->mode = $mode; + break; + case CRYPT_MODE_CTR: + case CRYPT_MODE_CFB: + case CRYPT_MODE_OFB: + case CRYPT_MODE_STREAM: + $this->mode = $mode; + break; + case CRYPT_MODE_CBC: + default: + $this->paddable = true; + $this->mode = CRYPT_MODE_CBC; + } + + // Determining whether inline crypting can be used by the cipher + if ($this->use_inline_crypt !== false && function_exists('create_function')) { + $this->use_inline_crypt = true; + } + } + + /** + * Sets the initialization vector. (optional) + * + * SetIV is not required when CRYPT_MODE_ECB (or ie for AES: CRYPT_AES_MODE_ECB) is being used. If not explictly set, it'll be assumed + * to be all zero's. + * + * Note: Could, but not must, extend by the child Crypt_* class + * + * @access public + * @param String $iv + */ + function setIV($iv) + { + if ($this->mode == CRYPT_MODE_ECB) { + return; + } + + $this->iv = $iv; + $this->changed = true; + } + + /** + * Sets the key. + * + * The min/max length(s) of the key depends on the cipher which is used. + * If the key not fits the length(s) of the cipher it will paded with null bytes + * up to the closest valid key length. If the key is more than max length, + * we trim the excess bits. + * + * If the key is not explicitly set, it'll be assumed to be all null bytes. + * + * Note: Could, but not must, extend by the child Crypt_* class + * + * @access public + * @param String $key + */ + function setKey($key) + { + $this->key = $key; + $this->changed = true; + } + + /** + * Sets the password. + * + * Depending on what $method is set to, setPassword()'s (optional) parameters are as follows: + * {@link http://en.wikipedia.org/wiki/PBKDF2 pbkdf2}: + * $hash, $salt, $count, $dkLen + * + * Where $hash (default = sha1) currently supports the following hashes: see: Crypt/Hash.php + * + * Note: Could, but not must, extend by the child Crypt_* class + * + * @see Crypt/Hash.php + * @param String $password + * @param optional String $method + * @access public + */ + function setPassword($password, $method = 'pbkdf2') + { + $key = ''; + + switch ($method) { + default: // 'pbkdf2' + $func_args = func_get_args(); + + // Hash function + $hash = isset($func_args[2]) ? $func_args[2] : 'sha1'; + + // WPA and WPA2 use the SSID as the salt + $salt = isset($func_args[3]) ? $func_args[3] : $this->password_default_salt; + + // RFC2898#section-4.2 uses 1,000 iterations by default + // WPA and WPA2 use 4,096. + $count = isset($func_args[4]) ? $func_args[4] : 1000; + + // Keylength + $dkLen = isset($func_args[5]) ? $func_args[5] : $this->password_key_size; + + // Determining if php[>=5.5.0]'s hash_pbkdf2() function avail- and useable + switch (true) { + case !function_exists('hash_pbkdf2'): + case !function_exists('hash_algos'): + case !in_array($hash, hash_algos()): + if (!class_exists('Crypt_Hash')) { + require_once('Crypt/Hash.php'); + } + $i = 1; + while (strlen($key) < $dkLen) { + $hmac = new Crypt_Hash(); + $hmac->setHash($hash); + $hmac->setKey($password); + $f = $u = $hmac->hash($salt . pack('N', $i++)); + for ($j = 2; $j <= $count; ++$j) { + $u = $hmac->hash($u); + $f^= $u; + } + $key.= $f; + } + $key = substr($key, 0, $dkLen); + break; + default: + $key = hash_pbkdf2($hash, $password, $salt, $count, $dkLen, true); + } + } + + $this->setKey($key); + } + + /** + * Encrypts a message. + * + * $plaintext will be padded with additional bytes such that it's length is a multiple of the block size. Other cipher + * implementations may or may not pad in the same manner. Other common approaches to padding and the reasons why it's + * necessary are discussed in the following + * URL: + * + * {@link http://www.di-mgt.com.au/cryptopad.html http://www.di-mgt.com.au/cryptopad.html} + * + * An alternative to padding is to, separately, send the length of the file. This is what SSH, in fact, does. + * strlen($plaintext) will still need to be a multiple of the block size, however, arbitrary values can be added to make it that + * length. + * + * Note: Could, but not must, extend by the child Crypt_* class + * + * @see Crypt_Base::decrypt() + * @access public + * @param String $plaintext + * @return String $cipertext + */ + function encrypt($plaintext) + { + if ($this->engine == CRYPT_MODE_MCRYPT) { + if ($this->changed) { + $this->_setupMcrypt(); + $this->changed = false; + } + if ($this->enchanged) { + mcrypt_generic_init($this->enmcrypt, $this->key, $this->encryptIV); + $this->enchanged = false; + } + + // re: {@link http://phpseclib.sourceforge.net/cfb-demo.phps} + // using mcrypt's default handing of CFB the above would output two different things. using phpseclib's + // rewritten CFB implementation the above outputs the same thing twice. + if ($this->mode == CRYPT_MODE_CFB && $this->continuousBuffer) { + $block_size = $this->block_size; + $iv = &$this->encryptIV; + $pos = &$this->enbuffer['pos']; + $len = strlen($plaintext); + $ciphertext = ''; + $i = 0; + if ($pos) { + $orig_pos = $pos; + $max = $block_size - $pos; + if ($len >= $max) { + $i = $max; + $len-= $max; + $pos = 0; + } else { + $i = $len; + $pos+= $len; + $len = 0; + } + $ciphertext = substr($iv, $orig_pos) ^ $plaintext; + $iv = substr_replace($iv, $ciphertext, $orig_pos, $i); + $this->enbuffer['enmcrypt_init'] = true; + } + if ($len >= $block_size) { + if ($this->enbuffer['enmcrypt_init'] === false || $len > $this->cfb_init_len) { + if ($this->enbuffer['enmcrypt_init'] === true) { + mcrypt_generic_init($this->enmcrypt, $this->key, $iv); + $this->enbuffer['enmcrypt_init'] = false; + } + $ciphertext.= mcrypt_generic($this->enmcrypt, substr($plaintext, $i, $len - $len % $block_size)); + $iv = substr($ciphertext, -$block_size); + $len%= $block_size; + } else { + while ($len >= $block_size) { + $iv = mcrypt_generic($this->ecb, $iv) ^ substr($plaintext, $i, $block_size); + $ciphertext.= $iv; + $len-= $block_size; + $i+= $block_size; + } + } + } + + if ($len) { + $iv = mcrypt_generic($this->ecb, $iv); + $block = $iv ^ substr($plaintext, -$len); + $iv = substr_replace($iv, $block, 0, $len); + $ciphertext.= $block; + $pos = $len; + } + + return $ciphertext; + } + + if ($this->paddable) { + $plaintext = $this->_pad($plaintext); + } + + $ciphertext = mcrypt_generic($this->enmcrypt, $plaintext); + + if (!$this->continuousBuffer) { + mcrypt_generic_init($this->enmcrypt, $this->key, $this->encryptIV); + } + + return $ciphertext; + } + + if ($this->changed) { + $this->_setup(); + $this->changed = false; + } + if ($this->use_inline_crypt) { + $inline = $this->inline_crypt; + return $inline('encrypt', $this, $plaintext); + } + if ($this->paddable) { + $plaintext = $this->_pad($plaintext); + } + + $buffer = &$this->enbuffer; + $block_size = $this->block_size; + $ciphertext = ''; + switch ($this->mode) { + case CRYPT_MODE_ECB: + for ($i = 0; $i < strlen($plaintext); $i+=$block_size) { + $ciphertext.= $this->_encryptBlock(substr($plaintext, $i, $block_size)); + } + break; + case CRYPT_MODE_CBC: + $xor = $this->encryptIV; + for ($i = 0; $i < strlen($plaintext); $i+=$block_size) { + $block = substr($plaintext, $i, $block_size); + $block = $this->_encryptBlock($block ^ $xor); + $xor = $block; + $ciphertext.= $block; + } + if ($this->continuousBuffer) { + $this->encryptIV = $xor; + } + break; + case CRYPT_MODE_CTR: + $xor = $this->encryptIV; + if (strlen($buffer['encrypted'])) { + for ($i = 0; $i < strlen($plaintext); $i+=$block_size) { + $block = substr($plaintext, $i, $block_size); + if (strlen($block) > strlen($buffer['encrypted'])) { + $buffer['encrypted'].= $this->_encryptBlock($this->_generateXor($xor, $block_size)); + } + $key = $this->_stringShift($buffer['encrypted'], $block_size); + $ciphertext.= $block ^ $key; + } + } else { + for ($i = 0; $i < strlen($plaintext); $i+=$block_size) { + $block = substr($plaintext, $i, $block_size); + $key = $this->_encryptBlock($this->_generateXor($xor, $block_size)); + $ciphertext.= $block ^ $key; + } + } + if ($this->continuousBuffer) { + $this->encryptIV = $xor; + if ($start = strlen($plaintext) % $block_size) { + $buffer['encrypted'] = substr($key, $start) . $buffer['encrypted']; + } + } + break; + case CRYPT_MODE_CFB: + // cfb loosely routines inspired by openssl's: + // {@link http://cvs.openssl.org/fileview?f=openssl/crypto/modes/cfb128.c&v=1.3.2.2.2.1} + if ($this->continuousBuffer) { + $iv = &$this->encryptIV; + $pos = &$buffer['pos']; + } else { + $iv = $this->encryptIV; + $pos = 0; + } + $len = strlen($plaintext); + $i = 0; + if ($pos) { + $orig_pos = $pos; + $max = $block_size - $pos; + if ($len >= $max) { + $i = $max; + $len-= $max; + $pos = 0; + } else { + $i = $len; + $pos+= $len; + $len = 0; + } + // ie. $i = min($max, $len), $len-= $i, $pos+= $i, $pos%= $blocksize + $ciphertext = substr($iv, $orig_pos) ^ $plaintext; + $iv = substr_replace($iv, $ciphertext, $orig_pos, $i); + } + while ($len >= $block_size) { + $iv = $this->_encryptBlock($iv) ^ substr($plaintext, $i, $block_size); + $ciphertext.= $iv; + $len-= $block_size; + $i+= $block_size; + } + if ($len) { + $iv = $this->_encryptBlock($iv); + $block = $iv ^ substr($plaintext, $i); + $iv = substr_replace($iv, $block, 0, $len); + $ciphertext.= $block; + $pos = $len; + } + break; + case CRYPT_MODE_OFB: + $xor = $this->encryptIV; + if (strlen($buffer['xor'])) { + for ($i = 0; $i < strlen($plaintext); $i+=$block_size) { + $block = substr($plaintext, $i, $block_size); + if (strlen($block) > strlen($buffer['xor'])) { + $xor = $this->_encryptBlock($xor); + $buffer['xor'].= $xor; + } + $key = $this->_stringShift($buffer['xor'], $block_size); + $ciphertext.= $block ^ $key; + } + } else { + for ($i = 0; $i < strlen($plaintext); $i+=$block_size) { + $xor = $this->_encryptBlock($xor); + $ciphertext.= substr($plaintext, $i, $block_size) ^ $xor; + } + $key = $xor; + } + if ($this->continuousBuffer) { + $this->encryptIV = $xor; + if ($start = strlen($plaintext) % $block_size) { + $buffer['xor'] = substr($key, $start) . $buffer['xor']; + } + } + break; + case CRYPT_MODE_STREAM: + $ciphertext = $this->_encryptBlock($plaintext); + break; + } + + return $ciphertext; + } + + /** + * Decrypts a message. + * + * If strlen($ciphertext) is not a multiple of the block size, null bytes will be added to the end of the string until + * it is. + * + * Note: Could, but not must, extend by the child Crypt_* class + * + * @see Crypt_Base::encrypt() + * @access public + * @param String $ciphertext + * @return String $plaintext + */ + function decrypt($ciphertext) + { + if ($this->engine == CRYPT_MODE_MCRYPT) { + $block_size = $this->block_size; + if ($this->changed) { + $this->_setupMcrypt(); + $this->changed = false; + } + if ($this->dechanged) { + mcrypt_generic_init($this->demcrypt, $this->key, $this->decryptIV); + $this->dechanged = false; + } + + if ($this->mode == CRYPT_MODE_CFB && $this->continuousBuffer) { + $iv = &$this->decryptIV; + $pos = &$this->debuffer['pos']; + $len = strlen($ciphertext); + $plaintext = ''; + $i = 0; + if ($pos) { + $orig_pos = $pos; + $max = $block_size - $pos; + if ($len >= $max) { + $i = $max; + $len-= $max; + $pos = 0; + } else { + $i = $len; + $pos+= $len; + $len = 0; + } + // ie. $i = min($max, $len), $len-= $i, $pos+= $i, $pos%= $blocksize + $plaintext = substr($iv, $orig_pos) ^ $ciphertext; + $iv = substr_replace($iv, substr($ciphertext, 0, $i), $orig_pos, $i); + } + if ($len >= $block_size) { + $cb = substr($ciphertext, $i, $len - $len % $block_size); + $plaintext.= mcrypt_generic($this->ecb, $iv . $cb) ^ $cb; + $iv = substr($cb, -$block_size); + $len%= $block_size; + } + if ($len) { + $iv = mcrypt_generic($this->ecb, $iv); + $plaintext.= $iv ^ substr($ciphertext, -$len); + $iv = substr_replace($iv, substr($ciphertext, -$len), 0, $len); + $pos = $len; + } + + return $plaintext; + } + + if ($this->paddable) { + // we pad with chr(0) since that's what mcrypt_generic does. to quote from {@link http://www.php.net/function.mcrypt-generic}: + // "The data is padded with "\0" to make sure the length of the data is n * blocksize." + $ciphertext = str_pad($ciphertext, strlen($ciphertext) + ($block_size - strlen($ciphertext) % $block_size) % $block_size, chr(0)); + } + + $plaintext = mdecrypt_generic($this->demcrypt, $ciphertext); + + if (!$this->continuousBuffer) { + mcrypt_generic_init($this->demcrypt, $this->key, $this->decryptIV); + } + + return $this->paddable ? $this->_unpad($plaintext) : $plaintext; + } + + if ($this->changed) { + $this->_setup(); + $this->changed = false; + } + if ($this->use_inline_crypt) { + $inline = $this->inline_crypt; + return $inline('decrypt', $this, $ciphertext); + } + + $block_size = $this->block_size; + if ($this->paddable) { + // we pad with chr(0) since that's what mcrypt_generic does [...] + $ciphertext = str_pad($ciphertext, strlen($ciphertext) + ($block_size - strlen($ciphertext) % $block_size) % $block_size, chr(0)); + } + + $buffer = &$this->debuffer; + $plaintext = ''; + switch ($this->mode) { + case CRYPT_MODE_ECB: + for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) { + $plaintext.= $this->_decryptBlock(substr($ciphertext, $i, $block_size)); + } + break; + case CRYPT_MODE_CBC: + $xor = $this->decryptIV; + for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) { + $block = substr($ciphertext, $i, $block_size); + $plaintext.= $this->_decryptBlock($block) ^ $xor; + $xor = $block; + } + if ($this->continuousBuffer) { + $this->decryptIV = $xor; + } + break; + case CRYPT_MODE_CTR: + $xor = $this->decryptIV; + if (strlen($buffer['ciphertext'])) { + for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) { + $block = substr($ciphertext, $i, $block_size); + if (strlen($block) > strlen($buffer['ciphertext'])) { + $buffer['ciphertext'].= $this->_encryptBlock($this->_generateXor($xor, $block_size)); + } + $key = $this->_stringShift($buffer['ciphertext'], $block_size); + $plaintext.= $block ^ $key; + } + } else { + for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) { + $block = substr($ciphertext, $i, $block_size); + $key = $this->_encryptBlock($this->_generateXor($xor, $block_size)); + $plaintext.= $block ^ $key; + } + } + if ($this->continuousBuffer) { + $this->decryptIV = $xor; + if ($start = strlen($ciphertext) % $block_size) { + $buffer['ciphertext'] = substr($key, $start) . $buffer['ciphertext']; + } + } + break; + case CRYPT_MODE_CFB: + if ($this->continuousBuffer) { + $iv = &$this->decryptIV; + $pos = &$buffer['pos']; + } else { + $iv = $this->decryptIV; + $pos = 0; + } + $len = strlen($ciphertext); + $i = 0; + if ($pos) { + $orig_pos = $pos; + $max = $block_size - $pos; + if ($len >= $max) { + $i = $max; + $len-= $max; + $pos = 0; + } else { + $i = $len; + $pos+= $len; + $len = 0; + } + // ie. $i = min($max, $len), $len-= $i, $pos+= $i, $pos%= $blocksize + $plaintext = substr($iv, $orig_pos) ^ $ciphertext; + $iv = substr_replace($iv, substr($ciphertext, 0, $i), $orig_pos, $i); + } + while ($len >= $block_size) { + $iv = $this->_encryptBlock($iv); + $cb = substr($ciphertext, $i, $block_size); + $plaintext.= $iv ^ $cb; + $iv = $cb; + $len-= $block_size; + $i+= $block_size; + } + if ($len) { + $iv = $this->_encryptBlock($iv); + $plaintext.= $iv ^ substr($ciphertext, $i); + $iv = substr_replace($iv, substr($ciphertext, $i), 0, $len); + $pos = $len; + } + break; + case CRYPT_MODE_OFB: + $xor = $this->decryptIV; + if (strlen($buffer['xor'])) { + for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) { + $block = substr($ciphertext, $i, $block_size); + if (strlen($block) > strlen($buffer['xor'])) { + $xor = $this->_encryptBlock($xor); + $buffer['xor'].= $xor; + } + $key = $this->_stringShift($buffer['xor'], $block_size); + $plaintext.= $block ^ $key; + } + } else { + for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) { + $xor = $this->_encryptBlock($xor); + $plaintext.= substr($ciphertext, $i, $block_size) ^ $xor; + } + $key = $xor; + } + if ($this->continuousBuffer) { + $this->decryptIV = $xor; + if ($start = strlen($ciphertext) % $block_size) { + $buffer['xor'] = substr($key, $start) . $buffer['xor']; + } + } + break; + case CRYPT_MODE_STREAM: + $plaintext = $this->_decryptBlock($ciphertext); + break; + } + return $this->paddable ? $this->_unpad($plaintext) : $plaintext; + } + + /** + * Pad "packets". + * + * Block ciphers working by encrypting between their specified [$this->]block_size at a time + * If you ever need to encrypt or decrypt something that isn't of the proper length, it becomes necessary to + * pad the input so that it is of the proper length. + * + * Padding is enabled by default. Sometimes, however, it is undesirable to pad strings. Such is the case in SSH, + * where "packets" are padded with random bytes before being encrypted. Unpad these packets and you risk stripping + * away characters that shouldn't be stripped away. (SSH knows how many bytes are added because the length is + * transmitted separately) + * + * @see Crypt_Base::disablePadding() + * @access public + */ + function enablePadding() + { + $this->padding = true; + } + + /** + * Do not pad packets. + * + * @see Crypt_Base::enablePadding() + * @access public + */ + function disablePadding() + { + $this->padding = false; + } + + /** + * Treat consecutive "packets" as if they are a continuous buffer. + * + * Say you have a 32-byte plaintext $plaintext. Using the default behavior, the two following code snippets + * will yield different outputs: + * + * + * echo $rijndael->encrypt(substr($plaintext, 0, 16)); + * echo $rijndael->encrypt(substr($plaintext, 16, 16)); + * + * + * echo $rijndael->encrypt($plaintext); + * + * + * The solution is to enable the continuous buffer. Although this will resolve the above discrepancy, it creates + * another, as demonstrated with the following: + * + * + * $rijndael->encrypt(substr($plaintext, 0, 16)); + * echo $rijndael->decrypt($rijndael->encrypt(substr($plaintext, 16, 16))); + * + * + * echo $rijndael->decrypt($rijndael->encrypt(substr($plaintext, 16, 16))); + * + * + * With the continuous buffer disabled, these would yield the same output. With it enabled, they yield different + * outputs. The reason is due to the fact that the initialization vector's change after every encryption / + * decryption round when the continuous buffer is enabled. When it's disabled, they remain constant. + * + * Put another way, when the continuous buffer is enabled, the state of the Crypt_*() object changes after each + * encryption / decryption round, whereas otherwise, it'd remain constant. For this reason, it's recommended that + * continuous buffers not be used. They do offer better security and are, in fact, sometimes required (SSH uses them), + * however, they are also less intuitive and more likely to cause you problems. + * + * Note: Could, but not must, extend by the child Crypt_* class + * + * @see Crypt_Base::disableContinuousBuffer() + * @access public + */ + function enableContinuousBuffer() + { + if ($this->mode == CRYPT_MODE_ECB) { + return; + } + + $this->continuousBuffer = true; + } + + /** + * Treat consecutive packets as if they are a discontinuous buffer. + * + * The default behavior. + * + * Note: Could, but not must, extend by the child Crypt_* class + * + * @see Crypt_Base::enableContinuousBuffer() + * @access public + */ + function disableContinuousBuffer() + { + if ($this->mode == CRYPT_MODE_ECB) { + return; + } + if (!$this->continuousBuffer) { + return; + } + + $this->continuousBuffer = false; + $this->changed = true; + } + + /** + * Encrypts a block + * + * Note: Must extend by the child Crypt_* class + * + * @access private + * @param String $in + * @return String + */ + function _encryptBlock($in) + { + user_error((version_compare(PHP_VERSION, '5.0.0', '>=') ? __METHOD__ : __FUNCTION__) . '() must extend by class ' . get_class($this), E_USER_ERROR); + } + + /** + * Decrypts a block + * + * Note: Must extend by the child Crypt_* class + * + * @access private + * @param String $in + * @return String + */ + function _decryptBlock($in) + { + user_error((version_compare(PHP_VERSION, '5.0.0', '>=') ? __METHOD__ : __FUNCTION__) . '() must extend by class ' . get_class($this), E_USER_ERROR); + } + + /** + * Setup the key (expansion) + * + * Only used if $engine == CRYPT_MODE_INTERNAL + * + * Note: Must extend by the child Crypt_* class + * + * @see Crypt_Base::_setup() + * @access private + */ + function _setupKey() + { + user_error((version_compare(PHP_VERSION, '5.0.0', '>=') ? __METHOD__ : __FUNCTION__) . '() must extend by class ' . get_class($this), E_USER_ERROR); + } + + /** + * Setup the CRYPT_MODE_INTERNAL $engine + * + * (re)init, if necessary, the internal cipher $engine and flush all $buffers + * Used (only) if $engine == CRYPT_MODE_INTERNAL + * + * _setup() will be called each time if $changed === true + * typically this happens when using one or more of following public methods: + * + * - setKey() + * + * - setIV() + * + * - disableContinuousBuffer() + * + * - First run of encrypt() / decrypt() with no init-settings + * + * Internally: _setup() is called always before(!) en/decryption. + * + * Note: Could, but not must, extend by the child Crypt_* class + * + * @see setKey() + * @see setIV() + * @see disableContinuousBuffer() + * @access private + */ + function _setup() + { + $this->_clearBuffers(); + $this->_setupKey(); + + if ($this->use_inline_crypt) { + $this->_setupInlineCrypt(); + } + } + + /** + * Setup the CRYPT_MODE_MCRYPT $engine + * + * (re)init, if necessary, the (ext)mcrypt resources and flush all $buffers + * Used (only) if $engine = CRYPT_MODE_MCRYPT + * + * _setupMcrypt() will be called each time if $changed === true + * typically this happens when using one or more of following public methods: + * + * - setKey() + * + * - setIV() + * + * - disableContinuousBuffer() + * + * - First run of encrypt() / decrypt() + * + * + * Note: Could, but not must, extend by the child Crypt_* class + * + * @see setKey() + * @see setIV() + * @see disableContinuousBuffer() + * @access private + */ + function _setupMcrypt() + { + $this->_clearBuffers(); + $this->enchanged = $this->dechanged = true; + + if (!isset($this->enmcrypt)) { + static $mcrypt_modes = array( + CRYPT_MODE_CTR => 'ctr', + CRYPT_MODE_ECB => MCRYPT_MODE_ECB, + CRYPT_MODE_CBC => MCRYPT_MODE_CBC, + CRYPT_MODE_CFB => 'ncfb', + CRYPT_MODE_OFB => MCRYPT_MODE_NOFB, + CRYPT_MODE_STREAM => MCRYPT_MODE_STREAM, + ); + + $this->demcrypt = mcrypt_module_open($this->cipher_name_mcrypt, '', $mcrypt_modes[$this->mode], ''); + $this->enmcrypt = mcrypt_module_open($this->cipher_name_mcrypt, '', $mcrypt_modes[$this->mode], ''); + + // we need the $ecb mcrypt resource (only) in MODE_CFB with enableContinuousBuffer() + // to workaround mcrypt's broken ncfb implementation in buffered mode + // see: {@link http://phpseclib.sourceforge.net/cfb-demo.phps} + if ($this->mode == CRYPT_MODE_CFB) { + $this->ecb = mcrypt_module_open($this->cipher_name_mcrypt, '', MCRYPT_MODE_ECB, ''); + } + + } // else should mcrypt_generic_deinit be called? + + if ($this->mode == CRYPT_MODE_CFB) { + mcrypt_generic_init($this->ecb, $this->key, str_repeat("\0", $this->block_size)); + } + } + + /** + * Pads a string + * + * Pads a string using the RSA PKCS padding standards so that its length is a multiple of the blocksize. + * $this->block_size - (strlen($text) % $this->block_size) bytes are added, each of which is equal to + * chr($this->block_size - (strlen($text) % $this->block_size) + * + * If padding is disabled and $text is not a multiple of the blocksize, the string will be padded regardless + * and padding will, hence forth, be enabled. + * + * @see Crypt_Base::_unpad() + * @param String $text + * @access private + * @return String + */ + function _pad($text) + { + $length = strlen($text); + + if (!$this->padding) { + if ($length % $this->block_size == 0) { + return $text; + } else { + user_error("The plaintext's length ($length) is not a multiple of the block size ({$this->block_size})"); + $this->padding = true; + } + } + + $pad = $this->block_size - ($length % $this->block_size); + + return str_pad($text, $length + $pad, chr($pad)); + } + + /** + * Unpads a string. + * + * If padding is enabled and the reported padding length is invalid the encryption key will be assumed to be wrong + * and false will be returned. + * + * @see Crypt_Base::_pad() + * @param String $text + * @access private + * @return String + */ + function _unpad($text) + { + if (!$this->padding) { + return $text; + } + + $length = ord($text[strlen($text) - 1]); + + if (!$length || $length > $this->block_size) { + return false; + } + + return substr($text, 0, -$length); + } + + /** + * Clears internal buffers + * + * Clearing/resetting the internal buffers is done everytime + * after disableContinuousBuffer() or on cipher $engine (re)init + * ie after setKey() or setIV() + * + * Note: Could, but not must, extend by the child Crypt_* class + * + * @access public + */ + function _clearBuffers() + { + $this->enbuffer = array('encrypted' => '', 'xor' => '', 'pos' => 0, 'enmcrypt_init' => true); + $this->debuffer = array('ciphertext' => '', 'xor' => '', 'pos' => 0, 'demcrypt_init' => true); + + // mcrypt's handling of invalid's $iv: + // $this->encryptIV = $this->decryptIV = strlen($this->iv) == $this->block_size ? $this->iv : str_repeat("\0", $this->block_size); + $this->encryptIV = $this->decryptIV = str_pad(substr($this->iv, 0, $this->block_size), $this->block_size, "\0"); + } + + /** + * String Shift + * + * Inspired by array_shift + * + * @param String $string + * @param optional Integer $index + * @access private + * @return String + */ + function _stringShift(&$string, $index = 1) + { + $substr = substr($string, 0, $index); + $string = substr($string, $index); + return $substr; + } + + /** + * Generate CTR XOR encryption key + * + * Encrypt the output of this and XOR it against the ciphertext / plaintext to get the + * plaintext / ciphertext in CTR mode. + * + * @see Crypt_Base::decrypt() + * @see Crypt_Base::encrypt() + * @param String $iv + * @param Integer $length + * @access private + * @return String $xor + */ + function _generateXor(&$iv, $length) + { + $xor = ''; + $block_size = $this->block_size; + $num_blocks = floor(($length + ($block_size - 1)) / $block_size); + for ($i = 0; $i < $num_blocks; $i++) { + $xor.= $iv; + for ($j = 4; $j <= $block_size; $j+= 4) { + $temp = substr($iv, -$j, 4); + switch ($temp) { + case "\xFF\xFF\xFF\xFF": + $iv = substr_replace($iv, "\x00\x00\x00\x00", -$j, 4); + break; + case "\x7F\xFF\xFF\xFF": + $iv = substr_replace($iv, "\x80\x00\x00\x00", -$j, 4); + break 2; + default: + extract(unpack('Ncount', $temp)); + $iv = substr_replace($iv, pack('N', $count + 1), -$j, 4); + break 2; + } + } + } + + return $xor; + } + + /** + * Setup the performance-optimized function for de/encrypt() + * + * Stores the created (or existing) callback function-name + * in $this->inline_crypt + * + * Internally for phpseclib developers: + * + * _setupInlineCrypt() would be called only if: + * + * - $engine == CRYPT_MODE_INTERNAL and + * + * - $use_inline_crypt === true + * + * - each time on _setup(), after(!) _setupKey() + * + * + * This ensures that _setupInlineCrypt() has allways a + * full ready2go initializated internal cipher $engine state + * where, for example, the keys allready expanded, + * keys/block_size calculated and such. + * + * It is, each time if called, the responsibility of _setupInlineCrypt(): + * + * - to set $this->inline_crypt to a valid and fully working callback function + * as a (faster) replacement for encrypt() / decrypt() + * + * - NOT to create unlimited callback functions (for memory reasons!) + * no matter how often _setupInlineCrypt() would be called. At some + * point of amount they must be generic re-useable. + * + * - the code of _setupInlineCrypt() it self, + * and the generated callback code, + * must be, in following order: + * - 100% safe + * - 100% compatible to encrypt()/decrypt() + * - using only php5+ features/lang-constructs/php-extensions if + * compatibility (down to php4) or fallback is provided + * - readable/maintainable/understandable/commented and... not-cryptic-styled-code :-) + * - >= 10% faster than encrypt()/decrypt() [which is, by the way, + * the reason for the existence of _setupInlineCrypt() :-)] + * - memory-nice + * - short (as good as possible) + * + * Note: - _setupInlineCrypt() is using _createInlineCryptFunction() to create the full callback function code. + * - In case of using inline crypting, _setupInlineCrypt() must extend by the child Crypt_* class. + * - The following variable names are reserved: + * - $_* (all variable names prefixed with an underscore) + * - $self (object reference to it self. Do not use $this, but $self instead) + * - $in (the content of $in has to en/decrypt by the generated code) + * - The callback function should not use the 'return' statement, but en/decrypt'ing the content of $in only + * + * + * @see Crypt_Base::_setup() + * @see Crypt_Base::_createInlineCryptFunction() + * @see Crypt_Base::encrypt() + * @see Crypt_Base::decrypt() + * @access private + */ + function _setupInlineCrypt() + { + // If a Crypt_* class providing inline crypting it must extend _setupInlineCrypt() + + // If, for any reason, an extending Crypt_Base() Crypt_* class + // not using inline crypting then it must be ensured that: $this->use_inline_crypt = false + // ie in the class var declaration of $use_inline_crypt in general for the Crypt_* class, + // in the constructor at object instance-time + // or, if it's runtime-specific, at runtime + + $this->use_inline_crypt = false; + } + + /** + * Creates the performance-optimized function for en/decrypt() + * + * Internally for phpseclib developers: + * + * _createInlineCryptFunction(): + * + * - merge the $cipher_code [setup'ed by _setupInlineCrypt()] + * with the current [$this->]mode of operation code + * + * - create the $inline function, which called by encrypt() / decrypt() + * as its replacement to speed up the en/decryption operations. + * + * - return the name of the created $inline callback function + * + * - used to speed up en/decryption + * + * + * + * The main reason why can speed up things [up to 50%] this way are: + * + * - using variables more effective then regular. + * (ie no use of expensive arrays but integers $k_0, $k_1 ... + * or even, for example, the pure $key[] values hardcoded) + * + * - avoiding 1000's of function calls of ie _encryptBlock() + * but inlining the crypt operations. + * in the mode of operation for() loop. + * + * - full loop unroll the (sometimes key-dependent) rounds + * avoiding this way ++$i counters and runtime-if's etc... + * + * The basic code architectur of the generated $inline en/decrypt() + * lambda function, in pseudo php, is: + * + * + * +----------------------------------------------------------------------------------------------+ + * | callback $inline = create_function: | + * | lambda_function_0001_crypt_ECB($action, $text) | + * | { | + * | INSERT PHP CODE OF: | + * | $cipher_code['init_crypt']; // general init code. | + * | // ie: $sbox'es declarations used for | + * | // encrypt and decrypt'ing. | + * | | + * | switch ($action) { | + * | case 'encrypt': | + * | INSERT PHP CODE OF: | + * | $cipher_code['init_encrypt']; // encrypt sepcific init code. | + * | ie: specified $key or $box | + * | declarations for encrypt'ing. | + * | | + * | foreach ($ciphertext) { | + * | $in = $block_size of $ciphertext; | + * | | + * | INSERT PHP CODE OF: | + * | $cipher_code['encrypt_block']; // encrypt's (string) $in, which is always: | + * | // strlen($in) == $this->block_size | + * | // here comes the cipher algorithm in action | + * | // for encryption. | + * | // $cipher_code['encrypt_block'] has to | + * | // encrypt the content of the $in variable | + * | | + * | $plaintext .= $in; | + * | } | + * | return $plaintext; | + * | | + * | case 'decrypt': | + * | INSERT PHP CODE OF: | + * | $cipher_code['init_decrypt']; // decrypt sepcific init code | + * | ie: specified $key or $box | + * | declarations for decrypt'ing. | + * | foreach ($plaintext) { | + * | $in = $block_size of $plaintext; | + * | | + * | INSERT PHP CODE OF: | + * | $cipher_code['decrypt_block']; // decrypt's (string) $in, which is always | + * | // strlen($in) == $this->block_size | + * | // here comes the cipher algorithm in action | + * | // for decryption. | + * | // $cipher_code['decrypt_block'] has to | + * | // decrypt the content of the $in variable | + * | $ciphertext .= $in; | + * | } | + * | return $ciphertext; | + * | } | + * | } | + * +----------------------------------------------------------------------------------------------+ + * + * + * See also the Crypt_*::_setupInlineCrypt()'s for + * productive inline $cipher_code's how they works. + * + * Structure of: + * + * $cipher_code = array( + * 'init_crypt' => (string) '', // optional + * 'init_encrypt' => (string) '', // optional + * 'init_decrypt' => (string) '', // optional + * 'encrypt_block' => (string) '', // required + * 'decrypt_block' => (string) '' // required + * ); + * + * + * @see Crypt_Base::_setupInlineCrypt() + * @see Crypt_Base::encrypt() + * @see Crypt_Base::decrypt() + * @param Array $cipher_code + * @access private + * @return String (the name of the created callback function) + */ + function _createInlineCryptFunction($cipher_code) + { + $block_size = $this->block_size; + + // optional + $init_crypt = isset($cipher_code['init_crypt']) ? $cipher_code['init_crypt'] : ''; + $init_encrypt = isset($cipher_code['init_encrypt']) ? $cipher_code['init_encrypt'] : ''; + $init_decrypt = isset($cipher_code['init_decrypt']) ? $cipher_code['init_decrypt'] : ''; + // required + $encrypt_block = $cipher_code['encrypt_block']; + $decrypt_block = $cipher_code['decrypt_block']; + + // Generating mode of operation inline code, + // merged with the $cipher_code algorithm + // for encrypt- and decryption. + switch ($this->mode) { + case CRYPT_MODE_ECB: + $encrypt = $init_encrypt . ' + $_ciphertext = ""; + $_text = $self->_pad($_text); + $_plaintext_len = strlen($_text); + + for ($_i = 0; $_i < $_plaintext_len; $_i+= '.$block_size.') { + $in = substr($_text, $_i, '.$block_size.'); + '.$encrypt_block.' + $_ciphertext.= $in; + } + + return $_ciphertext; + '; + + $decrypt = $init_decrypt . ' + $_plaintext = ""; + $_text = str_pad($_text, strlen($_text) + ('.$block_size.' - strlen($_text) % '.$block_size.') % '.$block_size.', chr(0)); + $_ciphertext_len = strlen($_text); + + for ($_i = 0; $_i < $_ciphertext_len; $_i+= '.$block_size.') { + $in = substr($_text, $_i, '.$block_size.'); + '.$decrypt_block.' + $_plaintext.= $in; + } + + return $self->_unpad($_plaintext); + '; + break; + case CRYPT_MODE_CTR: + $encrypt = $init_encrypt . ' + $_ciphertext = ""; + $_plaintext_len = strlen($_text); + $_xor = $self->encryptIV; + $_buffer = &$self->enbuffer; + + if (strlen($_buffer["encrypted"])) { + for ($_i = 0; $_i < $_plaintext_len; $_i+= '.$block_size.') { + $_block = substr($_text, $_i, '.$block_size.'); + if (strlen($_block) > strlen($_buffer["encrypted"])) { + $in = $self->_generateXor($_xor, '.$block_size.'); + '.$encrypt_block.' + $_buffer["encrypted"].= $in; + } + $_key = $self->_stringShift($_buffer["encrypted"], '.$block_size.'); + $_ciphertext.= $_block ^ $_key; + } + } else { + for ($_i = 0; $_i < $_plaintext_len; $_i+= '.$block_size.') { + $_block = substr($_text, $_i, '.$block_size.'); + $in = $self->_generateXor($_xor, '.$block_size.'); + '.$encrypt_block.' + $_key = $in; + $_ciphertext.= $_block ^ $_key; + } + } + if ($self->continuousBuffer) { + $self->encryptIV = $_xor; + if ($_start = $_plaintext_len % '.$block_size.') { + $_buffer["encrypted"] = substr($_key, $_start) . $_buffer["encrypted"]; + } + } + + return $_ciphertext; + '; + + $decrypt = $init_encrypt . ' + $_plaintext = ""; + $_ciphertext_len = strlen($_text); + $_xor = $self->decryptIV; + $_buffer = &$self->debuffer; + + if (strlen($_buffer["ciphertext"])) { + for ($_i = 0; $_i < $_ciphertext_len; $_i+= '.$block_size.') { + $_block = substr($_text, $_i, '.$block_size.'); + if (strlen($_block) > strlen($_buffer["ciphertext"])) { + $in = $self->_generateXor($_xor, '.$block_size.'); + '.$encrypt_block.' + $_buffer["ciphertext"].= $in; + } + $_key = $self->_stringShift($_buffer["ciphertext"], '.$block_size.'); + $_plaintext.= $_block ^ $_key; + } + } else { + for ($_i = 0; $_i < $_ciphertext_len; $_i+= '.$block_size.') { + $_block = substr($_text, $_i, '.$block_size.'); + $in = $self->_generateXor($_xor, '.$block_size.'); + '.$encrypt_block.' + $_key = $in; + $_plaintext.= $_block ^ $_key; + } + } + if ($self->continuousBuffer) { + $self->decryptIV = $_xor; + if ($_start = $_ciphertext_len % '.$block_size.') { + $_buffer["ciphertext"] = substr($_key, $_start) . $_buffer["ciphertext"]; + } + } + + return $_plaintext; + '; + break; + case CRYPT_MODE_CFB: + $encrypt = $init_encrypt . ' + $_ciphertext = ""; + $_buffer = &$self->enbuffer; + + if ($self->continuousBuffer) { + $_iv = &$self->encryptIV; + $_pos = &$_buffer["pos"]; + } else { + $_iv = $self->encryptIV; + $_pos = 0; + } + $_len = strlen($_text); + $_i = 0; + if ($_pos) { + $_orig_pos = $_pos; + $_max = '.$block_size.' - $_pos; + if ($_len >= $_max) { + $_i = $_max; + $_len-= $_max; + $_pos = 0; + } else { + $_i = $_len; + $_pos+= $_len; + $_len = 0; + } + $_ciphertext = substr($_iv, $_orig_pos) ^ $_text; + $_iv = substr_replace($_iv, $_ciphertext, $_orig_pos, $_i); + } + while ($_len >= '.$block_size.') { + $in = $_iv; + '.$encrypt_block.'; + $_iv = $in ^ substr($_text, $_i, '.$block_size.'); + $_ciphertext.= $_iv; + $_len-= '.$block_size.'; + $_i+= '.$block_size.'; + } + if ($_len) { + $in = $_iv; + '.$encrypt_block.' + $_iv = $in; + $_block = $_iv ^ substr($_text, $_i); + $_iv = substr_replace($_iv, $_block, 0, $_len); + $_ciphertext.= $_block; + $_pos = $_len; + } + return $_ciphertext; + '; + + $decrypt = $init_encrypt . ' + $_plaintext = ""; + $_buffer = &$self->debuffer; + + if ($self->continuousBuffer) { + $_iv = &$self->decryptIV; + $_pos = &$_buffer["pos"]; + } else { + $_iv = $self->decryptIV; + $_pos = 0; + } + $_len = strlen($_text); + $_i = 0; + if ($_pos) { + $_orig_pos = $_pos; + $_max = '.$block_size.' - $_pos; + if ($_len >= $_max) { + $_i = $_max; + $_len-= $_max; + $_pos = 0; + } else { + $_i = $_len; + $_pos+= $_len; + $_len = 0; + } + $_plaintext = substr($_iv, $_orig_pos) ^ $_text; + $_iv = substr_replace($_iv, substr($_text, 0, $_i), $_orig_pos, $_i); + } + while ($_len >= '.$block_size.') { + $in = $_iv; + '.$encrypt_block.' + $_iv = $in; + $cb = substr($_text, $_i, '.$block_size.'); + $_plaintext.= $_iv ^ $cb; + $_iv = $cb; + $_len-= '.$block_size.'; + $_i+= '.$block_size.'; + } + if ($_len) { + $in = $_iv; + '.$encrypt_block.' + $_iv = $in; + $_plaintext.= $_iv ^ substr($_text, $_i); + $_iv = substr_replace($_iv, substr($_text, $_i), 0, $_len); + $_pos = $_len; + } + + return $_plaintext; + '; + break; + case CRYPT_MODE_OFB: + $encrypt = $init_encrypt . ' + $_ciphertext = ""; + $_plaintext_len = strlen($_text); + $_xor = $self->encryptIV; + $_buffer = &$self->enbuffer; + + if (strlen($_buffer["xor"])) { + for ($_i = 0; $_i < $_plaintext_len; $_i+= '.$block_size.') { + $_block = substr($_text, $_i, '.$block_size.'); + if (strlen($_block) > strlen($_buffer["xor"])) { + $in = $_xor; + '.$encrypt_block.' + $_xor = $in; + $_buffer["xor"].= $_xor; + } + $_key = $self->_stringShift($_buffer["xor"], '.$block_size.'); + $_ciphertext.= $_block ^ $_key; + } + } else { + for ($_i = 0; $_i < $_plaintext_len; $_i+= '.$block_size.') { + $in = $_xor; + '.$encrypt_block.' + $_xor = $in; + $_ciphertext.= substr($_text, $_i, '.$block_size.') ^ $_xor; + } + $_key = $_xor; + } + if ($self->continuousBuffer) { + $self->encryptIV = $_xor; + if ($_start = $_plaintext_len % '.$block_size.') { + $_buffer["xor"] = substr($_key, $_start) . $_buffer["xor"]; + } + } + return $_ciphertext; + '; + + $decrypt = $init_encrypt . ' + $_plaintext = ""; + $_ciphertext_len = strlen($_text); + $_xor = $self->decryptIV; + $_buffer = &$self->debuffer; + + if (strlen($_buffer["xor"])) { + for ($_i = 0; $_i < $_ciphertext_len; $_i+= '.$block_size.') { + $_block = substr($_text, $_i, '.$block_size.'); + if (strlen($_block) > strlen($_buffer["xor"])) { + $in = $_xor; + '.$encrypt_block.' + $_xor = $in; + $_buffer["xor"].= $_xor; + } + $_key = $self->_stringShift($_buffer["xor"], '.$block_size.'); + $_plaintext.= $_block ^ $_key; + } + } else { + for ($_i = 0; $_i < $_ciphertext_len; $_i+= '.$block_size.') { + $in = $_xor; + '.$encrypt_block.' + $_xor = $in; + $_plaintext.= substr($_text, $_i, '.$block_size.') ^ $_xor; + } + $_key = $_xor; + } + if ($self->continuousBuffer) { + $self->decryptIV = $_xor; + if ($_start = $_ciphertext_len % '.$block_size.') { + $_buffer["xor"] = substr($_key, $_start) . $_buffer["xor"]; + } + } + return $_plaintext; + '; + break; + case CRYPT_MODE_STREAM: + $encrypt = $init_encrypt . ' + $_ciphertext = ""; + '.$encrypt_block.' + return $_ciphertext; + '; + $decrypt = $init_decrypt . ' + $_plaintext = ""; + '.$decrypt_block.' + return $_plaintext; + '; + break; + // case CRYPT_MODE_CBC: + default: + $encrypt = $init_encrypt . ' + $_ciphertext = ""; + $_text = $self->_pad($_text); + $_plaintext_len = strlen($_text); + + $in = $self->encryptIV; + + for ($_i = 0; $_i < $_plaintext_len; $_i+= '.$block_size.') { + $in = substr($_text, $_i, '.$block_size.') ^ $in; + '.$encrypt_block.' + $_ciphertext.= $in; + } + + if ($self->continuousBuffer) { + $self->encryptIV = $in; + } + + return $_ciphertext; + '; + + $decrypt = $init_decrypt . ' + $_plaintext = ""; + $_text = str_pad($_text, strlen($_text) + ('.$block_size.' - strlen($_text) % '.$block_size.') % '.$block_size.', chr(0)); + $_ciphertext_len = strlen($_text); + + $_iv = $self->decryptIV; + + for ($_i = 0; $_i < $_ciphertext_len; $_i+= '.$block_size.') { + $in = $_block = substr($_text, $_i, '.$block_size.'); + '.$decrypt_block.' + $_plaintext.= $in ^ $_iv; + $_iv = $_block; + } + + if ($self->continuousBuffer) { + $self->decryptIV = $_iv; + } + + return $self->_unpad($_plaintext); + '; + break; + } + + // Create the $inline function and return its name as string. Ready to run! + return create_function('$_action, &$self, $_text', $init_crypt . 'if ($_action == "encrypt") { ' . $encrypt . ' } else { ' . $decrypt . ' }'); + } + + /** + * Holds the lambda_functions table (classwide) + * + * Each name of the lambda function, created from + * _setupInlineCrypt() && _createInlineCryptFunction() + * is stored, classwide (!), here for reusing. + * + * The string-based index of $function is a classwide + * uniqe value representing, at least, the $mode of + * operation (or more... depends of the optimizing level) + * for which $mode the lambda function was created. + * + * @access private + * @return &Array + */ + function &_getLambdaFunctions() + { + static $functions = array(); + return $functions; + } +} + +// vim: ts=4:sw=4:et: +// vim6: fdl=1: diff --git a/inc/phpseclib/Crypt_Hash.php b/inc/phpseclib/Crypt_Hash.php new file mode 100644 index 000000000..840fcd508 --- /dev/null +++ b/inc/phpseclib/Crypt_Hash.php @@ -0,0 +1,823 @@ + + * setKey('abcdefg'); + * + * echo base64_encode($hash->hash('abcdefg')); + * ?> + * + * + * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @category Crypt + * @package Crypt_Hash + * @author Jim Wigginton + * @copyright MMVII Jim Wigginton + * @license http://www.opensource.org/licenses/mit-license.html MIT License + * @link http://phpseclib.sourceforge.net + */ + +/**#@+ + * @access private + * @see Crypt_Hash::Crypt_Hash() + */ +/** + * Toggles the internal implementation + */ +define('CRYPT_HASH_MODE_INTERNAL', 1); +/** + * Toggles the mhash() implementation, which has been deprecated on PHP 5.3.0+. + */ +define('CRYPT_HASH_MODE_MHASH', 2); +/** + * Toggles the hash() implementation, which works on PHP 5.1.2+. + */ +define('CRYPT_HASH_MODE_HASH', 3); +/**#@-*/ + +/** + * Pure-PHP implementations of keyed-hash message authentication codes (HMACs) and various cryptographic hashing functions. + * + * @author Jim Wigginton + * @version 0.1.0 + * @access public + * @package Crypt_Hash + */ +class Crypt_Hash { + /** + * Byte-length of compression blocks / key (Internal HMAC) + * + * @see Crypt_Hash::setAlgorithm() + * @var Integer + * @access private + */ + var $b; + + /** + * Byte-length of hash output (Internal HMAC) + * + * @see Crypt_Hash::setHash() + * @var Integer + * @access private + */ + var $l = false; + + /** + * Hash Algorithm + * + * @see Crypt_Hash::setHash() + * @var String + * @access private + */ + var $hash; + + /** + * Key + * + * @see Crypt_Hash::setKey() + * @var String + * @access private + */ + var $key = false; + + /** + * Outer XOR (Internal HMAC) + * + * @see Crypt_Hash::setKey() + * @var String + * @access private + */ + var $opad; + + /** + * Inner XOR (Internal HMAC) + * + * @see Crypt_Hash::setKey() + * @var String + * @access private + */ + var $ipad; + + /** + * Default Constructor. + * + * @param optional String $hash + * @return Crypt_Hash + * @access public + */ + function Crypt_Hash($hash = 'sha1') + { + if ( !defined('CRYPT_HASH_MODE') ) { + switch (true) { + case extension_loaded('hash'): + define('CRYPT_HASH_MODE', CRYPT_HASH_MODE_HASH); + break; + case extension_loaded('mhash'): + define('CRYPT_HASH_MODE', CRYPT_HASH_MODE_MHASH); + break; + default: + define('CRYPT_HASH_MODE', CRYPT_HASH_MODE_INTERNAL); + } + } + + $this->setHash($hash); + } + + /** + * Sets the key for HMACs + * + * Keys can be of any length. + * + * @access public + * @param optional String $key + */ + function setKey($key = false) + { + $this->key = $key; + } + + /** + * Sets the hash function. + * + * @access public + * @param String $hash + */ + function setHash($hash) + { + $hash = strtolower($hash); + switch ($hash) { + case 'md5-96': + case 'sha1-96': + $this->l = 12; // 96 / 8 = 12 + break; + case 'md2': + case 'md5': + $this->l = 16; + break; + case 'sha1': + $this->l = 20; + break; + case 'sha256': + $this->l = 32; + break; + case 'sha384': + $this->l = 48; + break; + case 'sha512': + $this->l = 64; + } + + switch ($hash) { + case 'md2': + $mode = CRYPT_HASH_MODE == CRYPT_HASH_MODE_HASH && in_array('md2', hash_algos()) ? + CRYPT_HASH_MODE_HASH : CRYPT_HASH_MODE_INTERNAL; + break; + case 'sha384': + case 'sha512': + $mode = CRYPT_HASH_MODE == CRYPT_HASH_MODE_MHASH ? CRYPT_HASH_MODE_INTERNAL : CRYPT_HASH_MODE; + break; + default: + $mode = CRYPT_HASH_MODE; + } + + switch ( $mode ) { + case CRYPT_HASH_MODE_MHASH: + switch ($hash) { + case 'md5': + case 'md5-96': + $this->hash = MHASH_MD5; + break; + case 'sha256': + $this->hash = MHASH_SHA256; + break; + case 'sha1': + case 'sha1-96': + default: + $this->hash = MHASH_SHA1; + } + return; + case CRYPT_HASH_MODE_HASH: + switch ($hash) { + case 'md5': + case 'md5-96': + $this->hash = 'md5'; + return; + case 'md2': + case 'sha256': + case 'sha384': + case 'sha512': + $this->hash = $hash; + return; + case 'sha1': + case 'sha1-96': + default: + $this->hash = 'sha1'; + } + return; + } + + switch ($hash) { + case 'md2': + $this->b = 16; + $this->hash = array($this, '_md2'); + break; + case 'md5': + case 'md5-96': + $this->b = 64; + $this->hash = array($this, '_md5'); + break; + case 'sha256': + $this->b = 64; + $this->hash = array($this, '_sha256'); + break; + case 'sha384': + case 'sha512': + $this->b = 128; + $this->hash = array($this, '_sha512'); + break; + case 'sha1': + case 'sha1-96': + default: + $this->b = 64; + $this->hash = array($this, '_sha1'); + } + + $this->ipad = str_repeat(chr(0x36), $this->b); + $this->opad = str_repeat(chr(0x5C), $this->b); + } + + /** + * Compute the HMAC. + * + * @access public + * @param String $text + * @return String + */ + function hash($text) + { + $mode = is_array($this->hash) ? CRYPT_HASH_MODE_INTERNAL : CRYPT_HASH_MODE; + + if (!empty($this->key) || is_string($this->key)) { + switch ( $mode ) { + case CRYPT_HASH_MODE_MHASH: + $output = mhash($this->hash, $text, $this->key); + break; + case CRYPT_HASH_MODE_HASH: + $output = hash_hmac($this->hash, $text, $this->key, true); + break; + case CRYPT_HASH_MODE_INTERNAL: + /* "Applications that use keys longer than B bytes will first hash the key using H and then use the + resultant L byte string as the actual key to HMAC." + + -- http://tools.ietf.org/html/rfc2104#section-2 */ + $key = strlen($this->key) > $this->b ? call_user_func($this->hash, $this->key) : $this->key; + + $key = str_pad($key, $this->b, chr(0)); // step 1 + $temp = $this->ipad ^ $key; // step 2 + $temp .= $text; // step 3 + $temp = call_user_func($this->hash, $temp); // step 4 + $output = $this->opad ^ $key; // step 5 + $output.= $temp; // step 6 + $output = call_user_func($this->hash, $output); // step 7 + } + } else { + switch ( $mode ) { + case CRYPT_HASH_MODE_MHASH: + $output = mhash($this->hash, $text); + break; + case CRYPT_HASH_MODE_HASH: + $output = hash($this->hash, $text, true); + break; + case CRYPT_HASH_MODE_INTERNAL: + $output = call_user_func($this->hash, $text); + } + } + + return substr($output, 0, $this->l); + } + + /** + * Returns the hash length (in bytes) + * + * @access public + * @return Integer + */ + function getLength() + { + return $this->l; + } + + /** + * Wrapper for MD5 + * + * @access private + * @param String $m + */ + function _md5($m) + { + return pack('H*', md5($m)); + } + + /** + * Wrapper for SHA1 + * + * @access private + * @param String $m + */ + function _sha1($m) + { + return pack('H*', sha1($m)); + } + + /** + * Pure-PHP implementation of MD2 + * + * See {@link http://tools.ietf.org/html/rfc1319 RFC1319}. + * + * @access private + * @param String $m + */ + function _md2($m) + { + static $s = array( + 41, 46, 67, 201, 162, 216, 124, 1, 61, 54, 84, 161, 236, 240, 6, + 19, 98, 167, 5, 243, 192, 199, 115, 140, 152, 147, 43, 217, 188, + 76, 130, 202, 30, 155, 87, 60, 253, 212, 224, 22, 103, 66, 111, 24, + 138, 23, 229, 18, 190, 78, 196, 214, 218, 158, 222, 73, 160, 251, + 245, 142, 187, 47, 238, 122, 169, 104, 121, 145, 21, 178, 7, 63, + 148, 194, 16, 137, 11, 34, 95, 33, 128, 127, 93, 154, 90, 144, 50, + 39, 53, 62, 204, 231, 191, 247, 151, 3, 255, 25, 48, 179, 72, 165, + 181, 209, 215, 94, 146, 42, 172, 86, 170, 198, 79, 184, 56, 210, + 150, 164, 125, 182, 118, 252, 107, 226, 156, 116, 4, 241, 69, 157, + 112, 89, 100, 113, 135, 32, 134, 91, 207, 101, 230, 45, 168, 2, 27, + 96, 37, 173, 174, 176, 185, 246, 28, 70, 97, 105, 52, 64, 126, 15, + 85, 71, 163, 35, 221, 81, 175, 58, 195, 92, 249, 206, 186, 197, + 234, 38, 44, 83, 13, 110, 133, 40, 132, 9, 211, 223, 205, 244, 65, + 129, 77, 82, 106, 220, 55, 200, 108, 193, 171, 250, 36, 225, 123, + 8, 12, 189, 177, 74, 120, 136, 149, 139, 227, 99, 232, 109, 233, + 203, 213, 254, 59, 0, 29, 57, 242, 239, 183, 14, 102, 88, 208, 228, + 166, 119, 114, 248, 235, 117, 75, 10, 49, 68, 80, 180, 143, 237, + 31, 26, 219, 153, 141, 51, 159, 17, 131, 20 + ); + + // Step 1. Append Padding Bytes + $pad = 16 - (strlen($m) & 0xF); + $m.= str_repeat(chr($pad), $pad); + + $length = strlen($m); + + // Step 2. Append Checksum + $c = str_repeat(chr(0), 16); + $l = chr(0); + for ($i = 0; $i < $length; $i+= 16) { + for ($j = 0; $j < 16; $j++) { + // RFC1319 incorrectly states that C[j] should be set to S[c xor L] + //$c[$j] = chr($s[ord($m[$i + $j] ^ $l)]); + // per , however, C[j] should be set to S[c xor L] xor C[j] + $c[$j] = chr($s[ord($m[$i + $j] ^ $l)] ^ ord($c[$j])); + $l = $c[$j]; + } + } + $m.= $c; + + $length+= 16; + + // Step 3. Initialize MD Buffer + $x = str_repeat(chr(0), 48); + + // Step 4. Process Message in 16-Byte Blocks + for ($i = 0; $i < $length; $i+= 16) { + for ($j = 0; $j < 16; $j++) { + $x[$j + 16] = $m[$i + $j]; + $x[$j + 32] = $x[$j + 16] ^ $x[$j]; + } + $t = chr(0); + for ($j = 0; $j < 18; $j++) { + for ($k = 0; $k < 48; $k++) { + $x[$k] = $t = $x[$k] ^ chr($s[ord($t)]); + //$t = $x[$k] = $x[$k] ^ chr($s[ord($t)]); + } + $t = chr(ord($t) + $j); + } + } + + // Step 5. Output + return substr($x, 0, 16); + } + + /** + * Pure-PHP implementation of SHA256 + * + * See {@link http://en.wikipedia.org/wiki/SHA_hash_functions#SHA-256_.28a_SHA-2_variant.29_pseudocode SHA-256 (a SHA-2 variant) pseudocode - Wikipedia}. + * + * @access private + * @param String $m + */ + function _sha256($m) + { + if (extension_loaded('suhosin')) { + return pack('H*', sha256($m)); + } + + // Initialize variables + $hash = array( + 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19 + ); + // Initialize table of round constants + // (first 32 bits of the fractional parts of the cube roots of the first 64 primes 2..311) + static $k = array( + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, + 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, + 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, + 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, + 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 + ); + + // Pre-processing + $length = strlen($m); + // to round to nearest 56 mod 64, we'll add 64 - (length + (64 - 56)) % 64 + $m.= str_repeat(chr(0), 64 - (($length + 8) & 0x3F)); + $m[$length] = chr(0x80); + // we don't support hashing strings 512MB long + $m.= pack('N2', 0, $length << 3); + + // Process the message in successive 512-bit chunks + $chunks = str_split($m, 64); + foreach ($chunks as $chunk) { + $w = array(); + for ($i = 0; $i < 16; $i++) { + extract(unpack('Ntemp', $this->_string_shift($chunk, 4))); + $w[] = $temp; + } + + // Extend the sixteen 32-bit words into sixty-four 32-bit words + for ($i = 16; $i < 64; $i++) { + $s0 = $this->_rightRotate($w[$i - 15], 7) ^ + $this->_rightRotate($w[$i - 15], 18) ^ + $this->_rightShift( $w[$i - 15], 3); + $s1 = $this->_rightRotate($w[$i - 2], 17) ^ + $this->_rightRotate($w[$i - 2], 19) ^ + $this->_rightShift( $w[$i - 2], 10); + $w[$i] = $this->_add($w[$i - 16], $s0, $w[$i - 7], $s1); + + } + + // Initialize hash value for this chunk + list($a, $b, $c, $d, $e, $f, $g, $h) = $hash; + + // Main loop + for ($i = 0; $i < 64; $i++) { + $s0 = $this->_rightRotate($a, 2) ^ + $this->_rightRotate($a, 13) ^ + $this->_rightRotate($a, 22); + $maj = ($a & $b) ^ + ($a & $c) ^ + ($b & $c); + $t2 = $this->_add($s0, $maj); + + $s1 = $this->_rightRotate($e, 6) ^ + $this->_rightRotate($e, 11) ^ + $this->_rightRotate($e, 25); + $ch = ($e & $f) ^ + ($this->_not($e) & $g); + $t1 = $this->_add($h, $s1, $ch, $k[$i], $w[$i]); + + $h = $g; + $g = $f; + $f = $e; + $e = $this->_add($d, $t1); + $d = $c; + $c = $b; + $b = $a; + $a = $this->_add($t1, $t2); + } + + // Add this chunk's hash to result so far + $hash = array( + $this->_add($hash[0], $a), + $this->_add($hash[1], $b), + $this->_add($hash[2], $c), + $this->_add($hash[3], $d), + $this->_add($hash[4], $e), + $this->_add($hash[5], $f), + $this->_add($hash[6], $g), + $this->_add($hash[7], $h) + ); + } + + // Produce the final hash value (big-endian) + return pack('N8', $hash[0], $hash[1], $hash[2], $hash[3], $hash[4], $hash[5], $hash[6], $hash[7]); + } + + /** + * Pure-PHP implementation of SHA384 and SHA512 + * + * @access private + * @param String $m + */ + function _sha512($m) + { + if (!class_exists('Math_BigInteger')) { + require_once('Math/BigInteger.php'); + } + + static $init384, $init512, $k; + + if (!isset($k)) { + // Initialize variables + $init384 = array( // initial values for SHA384 + 'cbbb9d5dc1059ed8', '629a292a367cd507', '9159015a3070dd17', '152fecd8f70e5939', + '67332667ffc00b31', '8eb44a8768581511', 'db0c2e0d64f98fa7', '47b5481dbefa4fa4' + ); + $init512 = array( // initial values for SHA512 + '6a09e667f3bcc908', 'bb67ae8584caa73b', '3c6ef372fe94f82b', 'a54ff53a5f1d36f1', + '510e527fade682d1', '9b05688c2b3e6c1f', '1f83d9abfb41bd6b', '5be0cd19137e2179' + ); + + for ($i = 0; $i < 8; $i++) { + $init384[$i] = new Math_BigInteger($init384[$i], 16); + $init384[$i]->setPrecision(64); + $init512[$i] = new Math_BigInteger($init512[$i], 16); + $init512[$i]->setPrecision(64); + } + + // Initialize table of round constants + // (first 64 bits of the fractional parts of the cube roots of the first 80 primes 2..409) + $k = array( + '428a2f98d728ae22', '7137449123ef65cd', 'b5c0fbcfec4d3b2f', 'e9b5dba58189dbbc', + '3956c25bf348b538', '59f111f1b605d019', '923f82a4af194f9b', 'ab1c5ed5da6d8118', + 'd807aa98a3030242', '12835b0145706fbe', '243185be4ee4b28c', '550c7dc3d5ffb4e2', + '72be5d74f27b896f', '80deb1fe3b1696b1', '9bdc06a725c71235', 'c19bf174cf692694', + 'e49b69c19ef14ad2', 'efbe4786384f25e3', '0fc19dc68b8cd5b5', '240ca1cc77ac9c65', + '2de92c6f592b0275', '4a7484aa6ea6e483', '5cb0a9dcbd41fbd4', '76f988da831153b5', + '983e5152ee66dfab', 'a831c66d2db43210', 'b00327c898fb213f', 'bf597fc7beef0ee4', + 'c6e00bf33da88fc2', 'd5a79147930aa725', '06ca6351e003826f', '142929670a0e6e70', + '27b70a8546d22ffc', '2e1b21385c26c926', '4d2c6dfc5ac42aed', '53380d139d95b3df', + '650a73548baf63de', '766a0abb3c77b2a8', '81c2c92e47edaee6', '92722c851482353b', + 'a2bfe8a14cf10364', 'a81a664bbc423001', 'c24b8b70d0f89791', 'c76c51a30654be30', + 'd192e819d6ef5218', 'd69906245565a910', 'f40e35855771202a', '106aa07032bbd1b8', + '19a4c116b8d2d0c8', '1e376c085141ab53', '2748774cdf8eeb99', '34b0bcb5e19b48a8', + '391c0cb3c5c95a63', '4ed8aa4ae3418acb', '5b9cca4f7763e373', '682e6ff3d6b2b8a3', + '748f82ee5defb2fc', '78a5636f43172f60', '84c87814a1f0ab72', '8cc702081a6439ec', + '90befffa23631e28', 'a4506cebde82bde9', 'bef9a3f7b2c67915', 'c67178f2e372532b', + 'ca273eceea26619c', 'd186b8c721c0c207', 'eada7dd6cde0eb1e', 'f57d4f7fee6ed178', + '06f067aa72176fba', '0a637dc5a2c898a6', '113f9804bef90dae', '1b710b35131c471b', + '28db77f523047d84', '32caab7b40c72493', '3c9ebe0a15c9bebc', '431d67c49c100d4c', + '4cc5d4becb3e42b6', '597f299cfc657e2a', '5fcb6fab3ad6faec', '6c44198c4a475817' + ); + + for ($i = 0; $i < 80; $i++) { + $k[$i] = new Math_BigInteger($k[$i], 16); + } + } + + $hash = $this->l == 48 ? $init384 : $init512; + + // Pre-processing + $length = strlen($m); + // to round to nearest 112 mod 128, we'll add 128 - (length + (128 - 112)) % 128 + $m.= str_repeat(chr(0), 128 - (($length + 16) & 0x7F)); + $m[$length] = chr(0x80); + // we don't support hashing strings 512MB long + $m.= pack('N4', 0, 0, 0, $length << 3); + + // Process the message in successive 1024-bit chunks + $chunks = str_split($m, 128); + foreach ($chunks as $chunk) { + $w = array(); + for ($i = 0; $i < 16; $i++) { + $temp = new Math_BigInteger($this->_string_shift($chunk, 8), 256); + $temp->setPrecision(64); + $w[] = $temp; + } + + // Extend the sixteen 32-bit words into eighty 32-bit words + for ($i = 16; $i < 80; $i++) { + $temp = array( + $w[$i - 15]->bitwise_rightRotate(1), + $w[$i - 15]->bitwise_rightRotate(8), + $w[$i - 15]->bitwise_rightShift(7) + ); + $s0 = $temp[0]->bitwise_xor($temp[1]); + $s0 = $s0->bitwise_xor($temp[2]); + $temp = array( + $w[$i - 2]->bitwise_rightRotate(19), + $w[$i - 2]->bitwise_rightRotate(61), + $w[$i - 2]->bitwise_rightShift(6) + ); + $s1 = $temp[0]->bitwise_xor($temp[1]); + $s1 = $s1->bitwise_xor($temp[2]); + $w[$i] = $w[$i - 16]->copy(); + $w[$i] = $w[$i]->add($s0); + $w[$i] = $w[$i]->add($w[$i - 7]); + $w[$i] = $w[$i]->add($s1); + } + + // Initialize hash value for this chunk + $a = $hash[0]->copy(); + $b = $hash[1]->copy(); + $c = $hash[2]->copy(); + $d = $hash[3]->copy(); + $e = $hash[4]->copy(); + $f = $hash[5]->copy(); + $g = $hash[6]->copy(); + $h = $hash[7]->copy(); + + // Main loop + for ($i = 0; $i < 80; $i++) { + $temp = array( + $a->bitwise_rightRotate(28), + $a->bitwise_rightRotate(34), + $a->bitwise_rightRotate(39) + ); + $s0 = $temp[0]->bitwise_xor($temp[1]); + $s0 = $s0->bitwise_xor($temp[2]); + $temp = array( + $a->bitwise_and($b), + $a->bitwise_and($c), + $b->bitwise_and($c) + ); + $maj = $temp[0]->bitwise_xor($temp[1]); + $maj = $maj->bitwise_xor($temp[2]); + $t2 = $s0->add($maj); + + $temp = array( + $e->bitwise_rightRotate(14), + $e->bitwise_rightRotate(18), + $e->bitwise_rightRotate(41) + ); + $s1 = $temp[0]->bitwise_xor($temp[1]); + $s1 = $s1->bitwise_xor($temp[2]); + $temp = array( + $e->bitwise_and($f), + $g->bitwise_and($e->bitwise_not()) + ); + $ch = $temp[0]->bitwise_xor($temp[1]); + $t1 = $h->add($s1); + $t1 = $t1->add($ch); + $t1 = $t1->add($k[$i]); + $t1 = $t1->add($w[$i]); + + $h = $g->copy(); + $g = $f->copy(); + $f = $e->copy(); + $e = $d->add($t1); + $d = $c->copy(); + $c = $b->copy(); + $b = $a->copy(); + $a = $t1->add($t2); + } + + // Add this chunk's hash to result so far + $hash = array( + $hash[0]->add($a), + $hash[1]->add($b), + $hash[2]->add($c), + $hash[3]->add($d), + $hash[4]->add($e), + $hash[5]->add($f), + $hash[6]->add($g), + $hash[7]->add($h) + ); + } + + // Produce the final hash value (big-endian) + // (Crypt_Hash::hash() trims the output for hashes but not for HMACs. as such, we trim the output here) + $temp = $hash[0]->toBytes() . $hash[1]->toBytes() . $hash[2]->toBytes() . $hash[3]->toBytes() . + $hash[4]->toBytes() . $hash[5]->toBytes(); + if ($this->l != 48) { + $temp.= $hash[6]->toBytes() . $hash[7]->toBytes(); + } + + return $temp; + } + + /** + * Right Rotate + * + * @access private + * @param Integer $int + * @param Integer $amt + * @see _sha256() + * @return Integer + */ + function _rightRotate($int, $amt) + { + $invamt = 32 - $amt; + $mask = (1 << $invamt) - 1; + return (($int << $invamt) & 0xFFFFFFFF) | (($int >> $amt) & $mask); + } + + /** + * Right Shift + * + * @access private + * @param Integer $int + * @param Integer $amt + * @see _sha256() + * @return Integer + */ + function _rightShift($int, $amt) + { + $mask = (1 << (32 - $amt)) - 1; + return ($int >> $amt) & $mask; + } + + /** + * Not + * + * @access private + * @param Integer $int + * @see _sha256() + * @return Integer + */ + function _not($int) + { + return ~$int & 0xFFFFFFFF; + } + + /** + * Add + * + * _sha256() adds multiple unsigned 32-bit integers. Since PHP doesn't support unsigned integers and since the + * possibility of overflow exists, care has to be taken. Math_BigInteger() could be used but this should be faster. + * + * @param Integer $... + * @return Integer + * @see _sha256() + * @access private + */ + function _add() + { + static $mod; + if (!isset($mod)) { + $mod = pow(2, 32); + } + + $result = 0; + $arguments = func_get_args(); + foreach ($arguments as $argument) { + $result+= $argument < 0 ? ($argument & 0x7FFFFFFF) + 0x80000000 : $argument; + } + + return fmod($result, $mod); + } + + /** + * String Shift + * + * Inspired by array_shift + * + * @param String $string + * @param optional Integer $index + * @return String + * @access private + */ + function _string_shift(&$string, $index = 1) + { + $substr = substr($string, 0, $index); + $string = substr($string, $index); + return $substr; + } +} diff --git a/inc/phpseclib/Crypt_Rijndael.php b/inc/phpseclib/Crypt_Rijndael.php new file mode 100644 index 000000000..c63e0ff7e --- /dev/null +++ b/inc/phpseclib/Crypt_Rijndael.php @@ -0,0 +1,1374 @@ + + * setKey('abcdefghijklmnop'); + * + * $size = 10 * 1024; + * $plaintext = ''; + * for ($i = 0; $i < $size; $i++) { + * $plaintext.= 'a'; + * } + * + * echo $rijndael->decrypt($rijndael->encrypt($plaintext)); + * ?> + * + * + * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @category Crypt + * @package Crypt_Rijndael + * @author Jim Wigginton + * @copyright MMVIII Jim Wigginton + * @license http://www.opensource.org/licenses/mit-license.html MIT License + * @link http://phpseclib.sourceforge.net + */ + +/** + * Include Crypt_Base + * + * Base cipher class + */ +if (!class_exists('Crypt_Base')) { + require_once('Base.php'); +} + +/**#@+ + * @access public + * @see Crypt_Rijndael::encrypt() + * @see Crypt_Rijndael::decrypt() + */ +/** + * Encrypt / decrypt using the Counter mode. + * + * Set to -1 since that's what Crypt/Random.php uses to index the CTR mode. + * + * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Counter_.28CTR.29 + */ +define('CRYPT_RIJNDAEL_MODE_CTR', CRYPT_MODE_CTR); +/** + * Encrypt / decrypt using the Electronic Code Book mode. + * + * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Electronic_codebook_.28ECB.29 + */ +define('CRYPT_RIJNDAEL_MODE_ECB', CRYPT_MODE_ECB); +/** + * Encrypt / decrypt using the Code Book Chaining mode. + * + * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher-block_chaining_.28CBC.29 + */ +define('CRYPT_RIJNDAEL_MODE_CBC', CRYPT_MODE_CBC); +/** + * Encrypt / decrypt using the Cipher Feedback mode. + * + * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher_feedback_.28CFB.29 + */ +define('CRYPT_RIJNDAEL_MODE_CFB', CRYPT_MODE_CFB); +/** + * Encrypt / decrypt using the Cipher Feedback mode. + * + * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Output_feedback_.28OFB.29 + */ +define('CRYPT_RIJNDAEL_MODE_OFB', CRYPT_MODE_OFB); +/**#@-*/ + +/**#@+ + * @access private + * @see Crypt_Rijndael::Crypt_Rijndael() + */ +/** + * Toggles the internal implementation + */ +define('CRYPT_RIJNDAEL_MODE_INTERNAL', CRYPT_MODE_INTERNAL); +/** + * Toggles the mcrypt implementation + */ +define('CRYPT_RIJNDAEL_MODE_MCRYPT', CRYPT_MODE_MCRYPT); +/**#@-*/ + +/** + * Pure-PHP implementation of Rijndael. + * + * @author Jim Wigginton + * @version 0.1.0 + * @access public + * @package Crypt_Rijndael + */ +class Crypt_Rijndael extends Crypt_Base { + /** + * The default password key_size used by setPassword() + * + * @see Crypt_Base::password_key_size + * @see Crypt_Base::setPassword() + * @var Integer + * @access private + */ + var $password_key_size = 16; + + /** + * The namespace used by the cipher for its constants. + * + * @see Crypt_Base::const_namespace + * @var String + * @access private + */ + var $const_namespace = 'RIJNDAEL'; + + /** + * The mcrypt specific name of the cipher + * + * Mcrypt is useable for 128/192/256-bit $block_size/$key_size. For 160/224 not. + * Crypt_Rijndael determines automatically whether mcrypt is useable + * or not for the current $block_size/$key_size. + * In case of, $cipher_name_mcrypt will be set dynamicaly at run time accordingly. + * + * @see Crypt_Base::cipher_name_mcrypt + * @see Crypt_Base::engine + * @see _setupEngine() + * @var String + * @access private + */ + var $cipher_name_mcrypt = 'rijndael-128'; + + /** + * The default salt used by setPassword() + * + * @see Crypt_Base::password_default_salt + * @see Crypt_Base::setPassword() + * @var String + * @access private + */ + var $password_default_salt = 'phpseclib'; + + /** + * Has the key length explicitly been set or should it be derived from the key, itself? + * + * @see setKeyLength() + * @var Boolean + * @access private + */ + var $explicit_key_length = false; + + /** + * The Key Schedule + * + * @see _setup() + * @var Array + * @access private + */ + var $w; + + /** + * The Inverse Key Schedule + * + * @see _setup() + * @var Array + * @access private + */ + var $dw; + + /** + * The Block Length divided by 32 + * + * @see setBlockLength() + * @var Integer + * @access private + * @internal The max value is 256 / 32 = 8, the min value is 128 / 32 = 4. Exists in conjunction with $block_size + * because the encryption / decryption / key schedule creation requires this number and not $block_size. We could + * derive this from $block_size or vice versa, but that'd mean we'd have to do multiple shift operations, so in lieu + * of that, we'll just precompute it once. + * + */ + var $Nb = 4; + + /** + * The Key Length + * + * @see setKeyLength() + * @var Integer + * @access private + * @internal The max value is 256 / 8 = 32, the min value is 128 / 8 = 16. Exists in conjunction with $Nk + * because the encryption / decryption / key schedule creation requires this number and not $key_size. We could + * derive this from $key_size or vice versa, but that'd mean we'd have to do multiple shift operations, so in lieu + * of that, we'll just precompute it once. + */ + var $key_size = 16; + + /** + * The Key Length divided by 32 + * + * @see setKeyLength() + * @var Integer + * @access private + * @internal The max value is 256 / 32 = 8, the min value is 128 / 32 = 4 + */ + var $Nk = 4; + + /** + * The Number of Rounds + * + * @var Integer + * @access private + * @internal The max value is 14, the min value is 10. + */ + var $Nr; + + /** + * Shift offsets + * + * @var Array + * @access private + */ + var $c; + + /** + * Holds the last used key- and block_size information + * + * @var Array + * @access private + */ + var $kl; + + /** + * Precomputed mixColumns table + * + * According to (section 5.2.1), + * precomputed tables can be used in the mixColumns phase. in that example, they're assigned t0...t3, so + * those are the names we'll use. + * + * @see Crypt_Rijndael:_encryptBlock() + * @see Crypt_Rijndael:_decryptBlock() + * @var Array + * @access private + */ + var $t0 = array( + 0xC66363A5, 0xF87C7C84, 0xEE777799, 0xF67B7B8D, 0xFFF2F20D, 0xD66B6BBD, 0xDE6F6FB1, 0x91C5C554, + 0x60303050, 0x02010103, 0xCE6767A9, 0x562B2B7D, 0xE7FEFE19, 0xB5D7D762, 0x4DABABE6, 0xEC76769A, + 0x8FCACA45, 0x1F82829D, 0x89C9C940, 0xFA7D7D87, 0xEFFAFA15, 0xB25959EB, 0x8E4747C9, 0xFBF0F00B, + 0x41ADADEC, 0xB3D4D467, 0x5FA2A2FD, 0x45AFAFEA, 0x239C9CBF, 0x53A4A4F7, 0xE4727296, 0x9BC0C05B, + 0x75B7B7C2, 0xE1FDFD1C, 0x3D9393AE, 0x4C26266A, 0x6C36365A, 0x7E3F3F41, 0xF5F7F702, 0x83CCCC4F, + 0x6834345C, 0x51A5A5F4, 0xD1E5E534, 0xF9F1F108, 0xE2717193, 0xABD8D873, 0x62313153, 0x2A15153F, + 0x0804040C, 0x95C7C752, 0x46232365, 0x9DC3C35E, 0x30181828, 0x379696A1, 0x0A05050F, 0x2F9A9AB5, + 0x0E070709, 0x24121236, 0x1B80809B, 0xDFE2E23D, 0xCDEBEB26, 0x4E272769, 0x7FB2B2CD, 0xEA75759F, + 0x1209091B, 0x1D83839E, 0x582C2C74, 0x341A1A2E, 0x361B1B2D, 0xDC6E6EB2, 0xB45A5AEE, 0x5BA0A0FB, + 0xA45252F6, 0x763B3B4D, 0xB7D6D661, 0x7DB3B3CE, 0x5229297B, 0xDDE3E33E, 0x5E2F2F71, 0x13848497, + 0xA65353F5, 0xB9D1D168, 0x00000000, 0xC1EDED2C, 0x40202060, 0xE3FCFC1F, 0x79B1B1C8, 0xB65B5BED, + 0xD46A6ABE, 0x8DCBCB46, 0x67BEBED9, 0x7239394B, 0x944A4ADE, 0x984C4CD4, 0xB05858E8, 0x85CFCF4A, + 0xBBD0D06B, 0xC5EFEF2A, 0x4FAAAAE5, 0xEDFBFB16, 0x864343C5, 0x9A4D4DD7, 0x66333355, 0x11858594, + 0x8A4545CF, 0xE9F9F910, 0x04020206, 0xFE7F7F81, 0xA05050F0, 0x783C3C44, 0x259F9FBA, 0x4BA8A8E3, + 0xA25151F3, 0x5DA3A3FE, 0x804040C0, 0x058F8F8A, 0x3F9292AD, 0x219D9DBC, 0x70383848, 0xF1F5F504, + 0x63BCBCDF, 0x77B6B6C1, 0xAFDADA75, 0x42212163, 0x20101030, 0xE5FFFF1A, 0xFDF3F30E, 0xBFD2D26D, + 0x81CDCD4C, 0x180C0C14, 0x26131335, 0xC3ECEC2F, 0xBE5F5FE1, 0x359797A2, 0x884444CC, 0x2E171739, + 0x93C4C457, 0x55A7A7F2, 0xFC7E7E82, 0x7A3D3D47, 0xC86464AC, 0xBA5D5DE7, 0x3219192B, 0xE6737395, + 0xC06060A0, 0x19818198, 0x9E4F4FD1, 0xA3DCDC7F, 0x44222266, 0x542A2A7E, 0x3B9090AB, 0x0B888883, + 0x8C4646CA, 0xC7EEEE29, 0x6BB8B8D3, 0x2814143C, 0xA7DEDE79, 0xBC5E5EE2, 0x160B0B1D, 0xADDBDB76, + 0xDBE0E03B, 0x64323256, 0x743A3A4E, 0x140A0A1E, 0x924949DB, 0x0C06060A, 0x4824246C, 0xB85C5CE4, + 0x9FC2C25D, 0xBDD3D36E, 0x43ACACEF, 0xC46262A6, 0x399191A8, 0x319595A4, 0xD3E4E437, 0xF279798B, + 0xD5E7E732, 0x8BC8C843, 0x6E373759, 0xDA6D6DB7, 0x018D8D8C, 0xB1D5D564, 0x9C4E4ED2, 0x49A9A9E0, + 0xD86C6CB4, 0xAC5656FA, 0xF3F4F407, 0xCFEAEA25, 0xCA6565AF, 0xF47A7A8E, 0x47AEAEE9, 0x10080818, + 0x6FBABAD5, 0xF0787888, 0x4A25256F, 0x5C2E2E72, 0x381C1C24, 0x57A6A6F1, 0x73B4B4C7, 0x97C6C651, + 0xCBE8E823, 0xA1DDDD7C, 0xE874749C, 0x3E1F1F21, 0x964B4BDD, 0x61BDBDDC, 0x0D8B8B86, 0x0F8A8A85, + 0xE0707090, 0x7C3E3E42, 0x71B5B5C4, 0xCC6666AA, 0x904848D8, 0x06030305, 0xF7F6F601, 0x1C0E0E12, + 0xC26161A3, 0x6A35355F, 0xAE5757F9, 0x69B9B9D0, 0x17868691, 0x99C1C158, 0x3A1D1D27, 0x279E9EB9, + 0xD9E1E138, 0xEBF8F813, 0x2B9898B3, 0x22111133, 0xD26969BB, 0xA9D9D970, 0x078E8E89, 0x339494A7, + 0x2D9B9BB6, 0x3C1E1E22, 0x15878792, 0xC9E9E920, 0x87CECE49, 0xAA5555FF, 0x50282878, 0xA5DFDF7A, + 0x038C8C8F, 0x59A1A1F8, 0x09898980, 0x1A0D0D17, 0x65BFBFDA, 0xD7E6E631, 0x844242C6, 0xD06868B8, + 0x824141C3, 0x299999B0, 0x5A2D2D77, 0x1E0F0F11, 0x7BB0B0CB, 0xA85454FC, 0x6DBBBBD6, 0x2C16163A + ); + + /** + * Precomputed mixColumns table + * + * @see Crypt_Rijndael:_encryptBlock() + * @see Crypt_Rijndael:_decryptBlock() + * @var Array + * @access private + */ + var $t1 = array( + 0xA5C66363, 0x84F87C7C, 0x99EE7777, 0x8DF67B7B, 0x0DFFF2F2, 0xBDD66B6B, 0xB1DE6F6F, 0x5491C5C5, + 0x50603030, 0x03020101, 0xA9CE6767, 0x7D562B2B, 0x19E7FEFE, 0x62B5D7D7, 0xE64DABAB, 0x9AEC7676, + 0x458FCACA, 0x9D1F8282, 0x4089C9C9, 0x87FA7D7D, 0x15EFFAFA, 0xEBB25959, 0xC98E4747, 0x0BFBF0F0, + 0xEC41ADAD, 0x67B3D4D4, 0xFD5FA2A2, 0xEA45AFAF, 0xBF239C9C, 0xF753A4A4, 0x96E47272, 0x5B9BC0C0, + 0xC275B7B7, 0x1CE1FDFD, 0xAE3D9393, 0x6A4C2626, 0x5A6C3636, 0x417E3F3F, 0x02F5F7F7, 0x4F83CCCC, + 0x5C683434, 0xF451A5A5, 0x34D1E5E5, 0x08F9F1F1, 0x93E27171, 0x73ABD8D8, 0x53623131, 0x3F2A1515, + 0x0C080404, 0x5295C7C7, 0x65462323, 0x5E9DC3C3, 0x28301818, 0xA1379696, 0x0F0A0505, 0xB52F9A9A, + 0x090E0707, 0x36241212, 0x9B1B8080, 0x3DDFE2E2, 0x26CDEBEB, 0x694E2727, 0xCD7FB2B2, 0x9FEA7575, + 0x1B120909, 0x9E1D8383, 0x74582C2C, 0x2E341A1A, 0x2D361B1B, 0xB2DC6E6E, 0xEEB45A5A, 0xFB5BA0A0, + 0xF6A45252, 0x4D763B3B, 0x61B7D6D6, 0xCE7DB3B3, 0x7B522929, 0x3EDDE3E3, 0x715E2F2F, 0x97138484, + 0xF5A65353, 0x68B9D1D1, 0x00000000, 0x2CC1EDED, 0x60402020, 0x1FE3FCFC, 0xC879B1B1, 0xEDB65B5B, + 0xBED46A6A, 0x468DCBCB, 0xD967BEBE, 0x4B723939, 0xDE944A4A, 0xD4984C4C, 0xE8B05858, 0x4A85CFCF, + 0x6BBBD0D0, 0x2AC5EFEF, 0xE54FAAAA, 0x16EDFBFB, 0xC5864343, 0xD79A4D4D, 0x55663333, 0x94118585, + 0xCF8A4545, 0x10E9F9F9, 0x06040202, 0x81FE7F7F, 0xF0A05050, 0x44783C3C, 0xBA259F9F, 0xE34BA8A8, + 0xF3A25151, 0xFE5DA3A3, 0xC0804040, 0x8A058F8F, 0xAD3F9292, 0xBC219D9D, 0x48703838, 0x04F1F5F5, + 0xDF63BCBC, 0xC177B6B6, 0x75AFDADA, 0x63422121, 0x30201010, 0x1AE5FFFF, 0x0EFDF3F3, 0x6DBFD2D2, + 0x4C81CDCD, 0x14180C0C, 0x35261313, 0x2FC3ECEC, 0xE1BE5F5F, 0xA2359797, 0xCC884444, 0x392E1717, + 0x5793C4C4, 0xF255A7A7, 0x82FC7E7E, 0x477A3D3D, 0xACC86464, 0xE7BA5D5D, 0x2B321919, 0x95E67373, + 0xA0C06060, 0x98198181, 0xD19E4F4F, 0x7FA3DCDC, 0x66442222, 0x7E542A2A, 0xAB3B9090, 0x830B8888, + 0xCA8C4646, 0x29C7EEEE, 0xD36BB8B8, 0x3C281414, 0x79A7DEDE, 0xE2BC5E5E, 0x1D160B0B, 0x76ADDBDB, + 0x3BDBE0E0, 0x56643232, 0x4E743A3A, 0x1E140A0A, 0xDB924949, 0x0A0C0606, 0x6C482424, 0xE4B85C5C, + 0x5D9FC2C2, 0x6EBDD3D3, 0xEF43ACAC, 0xA6C46262, 0xA8399191, 0xA4319595, 0x37D3E4E4, 0x8BF27979, + 0x32D5E7E7, 0x438BC8C8, 0x596E3737, 0xB7DA6D6D, 0x8C018D8D, 0x64B1D5D5, 0xD29C4E4E, 0xE049A9A9, + 0xB4D86C6C, 0xFAAC5656, 0x07F3F4F4, 0x25CFEAEA, 0xAFCA6565, 0x8EF47A7A, 0xE947AEAE, 0x18100808, + 0xD56FBABA, 0x88F07878, 0x6F4A2525, 0x725C2E2E, 0x24381C1C, 0xF157A6A6, 0xC773B4B4, 0x5197C6C6, + 0x23CBE8E8, 0x7CA1DDDD, 0x9CE87474, 0x213E1F1F, 0xDD964B4B, 0xDC61BDBD, 0x860D8B8B, 0x850F8A8A, + 0x90E07070, 0x427C3E3E, 0xC471B5B5, 0xAACC6666, 0xD8904848, 0x05060303, 0x01F7F6F6, 0x121C0E0E, + 0xA3C26161, 0x5F6A3535, 0xF9AE5757, 0xD069B9B9, 0x91178686, 0x5899C1C1, 0x273A1D1D, 0xB9279E9E, + 0x38D9E1E1, 0x13EBF8F8, 0xB32B9898, 0x33221111, 0xBBD26969, 0x70A9D9D9, 0x89078E8E, 0xA7339494, + 0xB62D9B9B, 0x223C1E1E, 0x92158787, 0x20C9E9E9, 0x4987CECE, 0xFFAA5555, 0x78502828, 0x7AA5DFDF, + 0x8F038C8C, 0xF859A1A1, 0x80098989, 0x171A0D0D, 0xDA65BFBF, 0x31D7E6E6, 0xC6844242, 0xB8D06868, + 0xC3824141, 0xB0299999, 0x775A2D2D, 0x111E0F0F, 0xCB7BB0B0, 0xFCA85454, 0xD66DBBBB, 0x3A2C1616 + ); + + /** + * Precomputed mixColumns table + * + * @see Crypt_Rijndael:_encryptBlock() + * @see Crypt_Rijndael:_decryptBlock() + * @var Array + * @access private + */ + var $t2 = array( + 0x63A5C663, 0x7C84F87C, 0x7799EE77, 0x7B8DF67B, 0xF20DFFF2, 0x6BBDD66B, 0x6FB1DE6F, 0xC55491C5, + 0x30506030, 0x01030201, 0x67A9CE67, 0x2B7D562B, 0xFE19E7FE, 0xD762B5D7, 0xABE64DAB, 0x769AEC76, + 0xCA458FCA, 0x829D1F82, 0xC94089C9, 0x7D87FA7D, 0xFA15EFFA, 0x59EBB259, 0x47C98E47, 0xF00BFBF0, + 0xADEC41AD, 0xD467B3D4, 0xA2FD5FA2, 0xAFEA45AF, 0x9CBF239C, 0xA4F753A4, 0x7296E472, 0xC05B9BC0, + 0xB7C275B7, 0xFD1CE1FD, 0x93AE3D93, 0x266A4C26, 0x365A6C36, 0x3F417E3F, 0xF702F5F7, 0xCC4F83CC, + 0x345C6834, 0xA5F451A5, 0xE534D1E5, 0xF108F9F1, 0x7193E271, 0xD873ABD8, 0x31536231, 0x153F2A15, + 0x040C0804, 0xC75295C7, 0x23654623, 0xC35E9DC3, 0x18283018, 0x96A13796, 0x050F0A05, 0x9AB52F9A, + 0x07090E07, 0x12362412, 0x809B1B80, 0xE23DDFE2, 0xEB26CDEB, 0x27694E27, 0xB2CD7FB2, 0x759FEA75, + 0x091B1209, 0x839E1D83, 0x2C74582C, 0x1A2E341A, 0x1B2D361B, 0x6EB2DC6E, 0x5AEEB45A, 0xA0FB5BA0, + 0x52F6A452, 0x3B4D763B, 0xD661B7D6, 0xB3CE7DB3, 0x297B5229, 0xE33EDDE3, 0x2F715E2F, 0x84971384, + 0x53F5A653, 0xD168B9D1, 0x00000000, 0xED2CC1ED, 0x20604020, 0xFC1FE3FC, 0xB1C879B1, 0x5BEDB65B, + 0x6ABED46A, 0xCB468DCB, 0xBED967BE, 0x394B7239, 0x4ADE944A, 0x4CD4984C, 0x58E8B058, 0xCF4A85CF, + 0xD06BBBD0, 0xEF2AC5EF, 0xAAE54FAA, 0xFB16EDFB, 0x43C58643, 0x4DD79A4D, 0x33556633, 0x85941185, + 0x45CF8A45, 0xF910E9F9, 0x02060402, 0x7F81FE7F, 0x50F0A050, 0x3C44783C, 0x9FBA259F, 0xA8E34BA8, + 0x51F3A251, 0xA3FE5DA3, 0x40C08040, 0x8F8A058F, 0x92AD3F92, 0x9DBC219D, 0x38487038, 0xF504F1F5, + 0xBCDF63BC, 0xB6C177B6, 0xDA75AFDA, 0x21634221, 0x10302010, 0xFF1AE5FF, 0xF30EFDF3, 0xD26DBFD2, + 0xCD4C81CD, 0x0C14180C, 0x13352613, 0xEC2FC3EC, 0x5FE1BE5F, 0x97A23597, 0x44CC8844, 0x17392E17, + 0xC45793C4, 0xA7F255A7, 0x7E82FC7E, 0x3D477A3D, 0x64ACC864, 0x5DE7BA5D, 0x192B3219, 0x7395E673, + 0x60A0C060, 0x81981981, 0x4FD19E4F, 0xDC7FA3DC, 0x22664422, 0x2A7E542A, 0x90AB3B90, 0x88830B88, + 0x46CA8C46, 0xEE29C7EE, 0xB8D36BB8, 0x143C2814, 0xDE79A7DE, 0x5EE2BC5E, 0x0B1D160B, 0xDB76ADDB, + 0xE03BDBE0, 0x32566432, 0x3A4E743A, 0x0A1E140A, 0x49DB9249, 0x060A0C06, 0x246C4824, 0x5CE4B85C, + 0xC25D9FC2, 0xD36EBDD3, 0xACEF43AC, 0x62A6C462, 0x91A83991, 0x95A43195, 0xE437D3E4, 0x798BF279, + 0xE732D5E7, 0xC8438BC8, 0x37596E37, 0x6DB7DA6D, 0x8D8C018D, 0xD564B1D5, 0x4ED29C4E, 0xA9E049A9, + 0x6CB4D86C, 0x56FAAC56, 0xF407F3F4, 0xEA25CFEA, 0x65AFCA65, 0x7A8EF47A, 0xAEE947AE, 0x08181008, + 0xBAD56FBA, 0x7888F078, 0x256F4A25, 0x2E725C2E, 0x1C24381C, 0xA6F157A6, 0xB4C773B4, 0xC65197C6, + 0xE823CBE8, 0xDD7CA1DD, 0x749CE874, 0x1F213E1F, 0x4BDD964B, 0xBDDC61BD, 0x8B860D8B, 0x8A850F8A, + 0x7090E070, 0x3E427C3E, 0xB5C471B5, 0x66AACC66, 0x48D89048, 0x03050603, 0xF601F7F6, 0x0E121C0E, + 0x61A3C261, 0x355F6A35, 0x57F9AE57, 0xB9D069B9, 0x86911786, 0xC15899C1, 0x1D273A1D, 0x9EB9279E, + 0xE138D9E1, 0xF813EBF8, 0x98B32B98, 0x11332211, 0x69BBD269, 0xD970A9D9, 0x8E89078E, 0x94A73394, + 0x9BB62D9B, 0x1E223C1E, 0x87921587, 0xE920C9E9, 0xCE4987CE, 0x55FFAA55, 0x28785028, 0xDF7AA5DF, + 0x8C8F038C, 0xA1F859A1, 0x89800989, 0x0D171A0D, 0xBFDA65BF, 0xE631D7E6, 0x42C68442, 0x68B8D068, + 0x41C38241, 0x99B02999, 0x2D775A2D, 0x0F111E0F, 0xB0CB7BB0, 0x54FCA854, 0xBBD66DBB, 0x163A2C16 + ); + + /** + * Precomputed mixColumns table + * + * @see Crypt_Rijndael:_encryptBlock() + * @see Crypt_Rijndael:_decryptBlock() + * @var Array + * @access private + */ + var $t3 = array( + 0x6363A5C6, 0x7C7C84F8, 0x777799EE, 0x7B7B8DF6, 0xF2F20DFF, 0x6B6BBDD6, 0x6F6FB1DE, 0xC5C55491, + 0x30305060, 0x01010302, 0x6767A9CE, 0x2B2B7D56, 0xFEFE19E7, 0xD7D762B5, 0xABABE64D, 0x76769AEC, + 0xCACA458F, 0x82829D1F, 0xC9C94089, 0x7D7D87FA, 0xFAFA15EF, 0x5959EBB2, 0x4747C98E, 0xF0F00BFB, + 0xADADEC41, 0xD4D467B3, 0xA2A2FD5F, 0xAFAFEA45, 0x9C9CBF23, 0xA4A4F753, 0x727296E4, 0xC0C05B9B, + 0xB7B7C275, 0xFDFD1CE1, 0x9393AE3D, 0x26266A4C, 0x36365A6C, 0x3F3F417E, 0xF7F702F5, 0xCCCC4F83, + 0x34345C68, 0xA5A5F451, 0xE5E534D1, 0xF1F108F9, 0x717193E2, 0xD8D873AB, 0x31315362, 0x15153F2A, + 0x04040C08, 0xC7C75295, 0x23236546, 0xC3C35E9D, 0x18182830, 0x9696A137, 0x05050F0A, 0x9A9AB52F, + 0x0707090E, 0x12123624, 0x80809B1B, 0xE2E23DDF, 0xEBEB26CD, 0x2727694E, 0xB2B2CD7F, 0x75759FEA, + 0x09091B12, 0x83839E1D, 0x2C2C7458, 0x1A1A2E34, 0x1B1B2D36, 0x6E6EB2DC, 0x5A5AEEB4, 0xA0A0FB5B, + 0x5252F6A4, 0x3B3B4D76, 0xD6D661B7, 0xB3B3CE7D, 0x29297B52, 0xE3E33EDD, 0x2F2F715E, 0x84849713, + 0x5353F5A6, 0xD1D168B9, 0x00000000, 0xEDED2CC1, 0x20206040, 0xFCFC1FE3, 0xB1B1C879, 0x5B5BEDB6, + 0x6A6ABED4, 0xCBCB468D, 0xBEBED967, 0x39394B72, 0x4A4ADE94, 0x4C4CD498, 0x5858E8B0, 0xCFCF4A85, + 0xD0D06BBB, 0xEFEF2AC5, 0xAAAAE54F, 0xFBFB16ED, 0x4343C586, 0x4D4DD79A, 0x33335566, 0x85859411, + 0x4545CF8A, 0xF9F910E9, 0x02020604, 0x7F7F81FE, 0x5050F0A0, 0x3C3C4478, 0x9F9FBA25, 0xA8A8E34B, + 0x5151F3A2, 0xA3A3FE5D, 0x4040C080, 0x8F8F8A05, 0x9292AD3F, 0x9D9DBC21, 0x38384870, 0xF5F504F1, + 0xBCBCDF63, 0xB6B6C177, 0xDADA75AF, 0x21216342, 0x10103020, 0xFFFF1AE5, 0xF3F30EFD, 0xD2D26DBF, + 0xCDCD4C81, 0x0C0C1418, 0x13133526, 0xECEC2FC3, 0x5F5FE1BE, 0x9797A235, 0x4444CC88, 0x1717392E, + 0xC4C45793, 0xA7A7F255, 0x7E7E82FC, 0x3D3D477A, 0x6464ACC8, 0x5D5DE7BA, 0x19192B32, 0x737395E6, + 0x6060A0C0, 0x81819819, 0x4F4FD19E, 0xDCDC7FA3, 0x22226644, 0x2A2A7E54, 0x9090AB3B, 0x8888830B, + 0x4646CA8C, 0xEEEE29C7, 0xB8B8D36B, 0x14143C28, 0xDEDE79A7, 0x5E5EE2BC, 0x0B0B1D16, 0xDBDB76AD, + 0xE0E03BDB, 0x32325664, 0x3A3A4E74, 0x0A0A1E14, 0x4949DB92, 0x06060A0C, 0x24246C48, 0x5C5CE4B8, + 0xC2C25D9F, 0xD3D36EBD, 0xACACEF43, 0x6262A6C4, 0x9191A839, 0x9595A431, 0xE4E437D3, 0x79798BF2, + 0xE7E732D5, 0xC8C8438B, 0x3737596E, 0x6D6DB7DA, 0x8D8D8C01, 0xD5D564B1, 0x4E4ED29C, 0xA9A9E049, + 0x6C6CB4D8, 0x5656FAAC, 0xF4F407F3, 0xEAEA25CF, 0x6565AFCA, 0x7A7A8EF4, 0xAEAEE947, 0x08081810, + 0xBABAD56F, 0x787888F0, 0x25256F4A, 0x2E2E725C, 0x1C1C2438, 0xA6A6F157, 0xB4B4C773, 0xC6C65197, + 0xE8E823CB, 0xDDDD7CA1, 0x74749CE8, 0x1F1F213E, 0x4B4BDD96, 0xBDBDDC61, 0x8B8B860D, 0x8A8A850F, + 0x707090E0, 0x3E3E427C, 0xB5B5C471, 0x6666AACC, 0x4848D890, 0x03030506, 0xF6F601F7, 0x0E0E121C, + 0x6161A3C2, 0x35355F6A, 0x5757F9AE, 0xB9B9D069, 0x86869117, 0xC1C15899, 0x1D1D273A, 0x9E9EB927, + 0xE1E138D9, 0xF8F813EB, 0x9898B32B, 0x11113322, 0x6969BBD2, 0xD9D970A9, 0x8E8E8907, 0x9494A733, + 0x9B9BB62D, 0x1E1E223C, 0x87879215, 0xE9E920C9, 0xCECE4987, 0x5555FFAA, 0x28287850, 0xDFDF7AA5, + 0x8C8C8F03, 0xA1A1F859, 0x89898009, 0x0D0D171A, 0xBFBFDA65, 0xE6E631D7, 0x4242C684, 0x6868B8D0, + 0x4141C382, 0x9999B029, 0x2D2D775A, 0x0F0F111E, 0xB0B0CB7B, 0x5454FCA8, 0xBBBBD66D, 0x16163A2C + ); + + /** + * Precomputed invMixColumns table + * + * @see Crypt_Rijndael:_encryptBlock() + * @see Crypt_Rijndael:_decryptBlock() + * @var Array + * @access private + */ + var $dt0 = array( + 0x51F4A750, 0x7E416553, 0x1A17A4C3, 0x3A275E96, 0x3BAB6BCB, 0x1F9D45F1, 0xACFA58AB, 0x4BE30393, + 0x2030FA55, 0xAD766DF6, 0x88CC7691, 0xF5024C25, 0x4FE5D7FC, 0xC52ACBD7, 0x26354480, 0xB562A38F, + 0xDEB15A49, 0x25BA1B67, 0x45EA0E98, 0x5DFEC0E1, 0xC32F7502, 0x814CF012, 0x8D4697A3, 0x6BD3F9C6, + 0x038F5FE7, 0x15929C95, 0xBF6D7AEB, 0x955259DA, 0xD4BE832D, 0x587421D3, 0x49E06929, 0x8EC9C844, + 0x75C2896A, 0xF48E7978, 0x99583E6B, 0x27B971DD, 0xBEE14FB6, 0xF088AD17, 0xC920AC66, 0x7DCE3AB4, + 0x63DF4A18, 0xE51A3182, 0x97513360, 0x62537F45, 0xB16477E0, 0xBB6BAE84, 0xFE81A01C, 0xF9082B94, + 0x70486858, 0x8F45FD19, 0x94DE6C87, 0x527BF8B7, 0xAB73D323, 0x724B02E2, 0xE31F8F57, 0x6655AB2A, + 0xB2EB2807, 0x2FB5C203, 0x86C57B9A, 0xD33708A5, 0x302887F2, 0x23BFA5B2, 0x02036ABA, 0xED16825C, + 0x8ACF1C2B, 0xA779B492, 0xF307F2F0, 0x4E69E2A1, 0x65DAF4CD, 0x0605BED5, 0xD134621F, 0xC4A6FE8A, + 0x342E539D, 0xA2F355A0, 0x058AE132, 0xA4F6EB75, 0x0B83EC39, 0x4060EFAA, 0x5E719F06, 0xBD6E1051, + 0x3E218AF9, 0x96DD063D, 0xDD3E05AE, 0x4DE6BD46, 0x91548DB5, 0x71C45D05, 0x0406D46F, 0x605015FF, + 0x1998FB24, 0xD6BDE997, 0x894043CC, 0x67D99E77, 0xB0E842BD, 0x07898B88, 0xE7195B38, 0x79C8EEDB, + 0xA17C0A47, 0x7C420FE9, 0xF8841EC9, 0x00000000, 0x09808683, 0x322BED48, 0x1E1170AC, 0x6C5A724E, + 0xFD0EFFFB, 0x0F853856, 0x3DAED51E, 0x362D3927, 0x0A0FD964, 0x685CA621, 0x9B5B54D1, 0x24362E3A, + 0x0C0A67B1, 0x9357E70F, 0xB4EE96D2, 0x1B9B919E, 0x80C0C54F, 0x61DC20A2, 0x5A774B69, 0x1C121A16, + 0xE293BA0A, 0xC0A02AE5, 0x3C22E043, 0x121B171D, 0x0E090D0B, 0xF28BC7AD, 0x2DB6A8B9, 0x141EA9C8, + 0x57F11985, 0xAF75074C, 0xEE99DDBB, 0xA37F60FD, 0xF701269F, 0x5C72F5BC, 0x44663BC5, 0x5BFB7E34, + 0x8B432976, 0xCB23C6DC, 0xB6EDFC68, 0xB8E4F163, 0xD731DCCA, 0x42638510, 0x13972240, 0x84C61120, + 0x854A247D, 0xD2BB3DF8, 0xAEF93211, 0xC729A16D, 0x1D9E2F4B, 0xDCB230F3, 0x0D8652EC, 0x77C1E3D0, + 0x2BB3166C, 0xA970B999, 0x119448FA, 0x47E96422, 0xA8FC8CC4, 0xA0F03F1A, 0x567D2CD8, 0x223390EF, + 0x87494EC7, 0xD938D1C1, 0x8CCAA2FE, 0x98D40B36, 0xA6F581CF, 0xA57ADE28, 0xDAB78E26, 0x3FADBFA4, + 0x2C3A9DE4, 0x5078920D, 0x6A5FCC9B, 0x547E4662, 0xF68D13C2, 0x90D8B8E8, 0x2E39F75E, 0x82C3AFF5, + 0x9F5D80BE, 0x69D0937C, 0x6FD52DA9, 0xCF2512B3, 0xC8AC993B, 0x10187DA7, 0xE89C636E, 0xDB3BBB7B, + 0xCD267809, 0x6E5918F4, 0xEC9AB701, 0x834F9AA8, 0xE6956E65, 0xAAFFE67E, 0x21BCCF08, 0xEF15E8E6, + 0xBAE79BD9, 0x4A6F36CE, 0xEA9F09D4, 0x29B07CD6, 0x31A4B2AF, 0x2A3F2331, 0xC6A59430, 0x35A266C0, + 0x744EBC37, 0xFC82CAA6, 0xE090D0B0, 0x33A7D815, 0xF104984A, 0x41ECDAF7, 0x7FCD500E, 0x1791F62F, + 0x764DD68D, 0x43EFB04D, 0xCCAA4D54, 0xE49604DF, 0x9ED1B5E3, 0x4C6A881B, 0xC12C1FB8, 0x4665517F, + 0x9D5EEA04, 0x018C355D, 0xFA877473, 0xFB0B412E, 0xB3671D5A, 0x92DBD252, 0xE9105633, 0x6DD64713, + 0x9AD7618C, 0x37A10C7A, 0x59F8148E, 0xEB133C89, 0xCEA927EE, 0xB761C935, 0xE11CE5ED, 0x7A47B13C, + 0x9CD2DF59, 0x55F2733F, 0x1814CE79, 0x73C737BF, 0x53F7CDEA, 0x5FFDAA5B, 0xDF3D6F14, 0x7844DB86, + 0xCAAFF381, 0xB968C43E, 0x3824342C, 0xC2A3405F, 0x161DC372, 0xBCE2250C, 0x283C498B, 0xFF0D9541, + 0x39A80171, 0x080CB3DE, 0xD8B4E49C, 0x6456C190, 0x7BCB8461, 0xD532B670, 0x486C5C74, 0xD0B85742 + ); + + /** + * Precomputed invMixColumns table + * + * @see Crypt_Rijndael:_encryptBlock() + * @see Crypt_Rijndael:_decryptBlock() + * @var Array + * @access private + */ + var $dt1 = array( + 0x5051F4A7, 0x537E4165, 0xC31A17A4, 0x963A275E, 0xCB3BAB6B, 0xF11F9D45, 0xABACFA58, 0x934BE303, + 0x552030FA, 0xF6AD766D, 0x9188CC76, 0x25F5024C, 0xFC4FE5D7, 0xD7C52ACB, 0x80263544, 0x8FB562A3, + 0x49DEB15A, 0x6725BA1B, 0x9845EA0E, 0xE15DFEC0, 0x02C32F75, 0x12814CF0, 0xA38D4697, 0xC66BD3F9, + 0xE7038F5F, 0x9515929C, 0xEBBF6D7A, 0xDA955259, 0x2DD4BE83, 0xD3587421, 0x2949E069, 0x448EC9C8, + 0x6A75C289, 0x78F48E79, 0x6B99583E, 0xDD27B971, 0xB6BEE14F, 0x17F088AD, 0x66C920AC, 0xB47DCE3A, + 0x1863DF4A, 0x82E51A31, 0x60975133, 0x4562537F, 0xE0B16477, 0x84BB6BAE, 0x1CFE81A0, 0x94F9082B, + 0x58704868, 0x198F45FD, 0x8794DE6C, 0xB7527BF8, 0x23AB73D3, 0xE2724B02, 0x57E31F8F, 0x2A6655AB, + 0x07B2EB28, 0x032FB5C2, 0x9A86C57B, 0xA5D33708, 0xF2302887, 0xB223BFA5, 0xBA02036A, 0x5CED1682, + 0x2B8ACF1C, 0x92A779B4, 0xF0F307F2, 0xA14E69E2, 0xCD65DAF4, 0xD50605BE, 0x1FD13462, 0x8AC4A6FE, + 0x9D342E53, 0xA0A2F355, 0x32058AE1, 0x75A4F6EB, 0x390B83EC, 0xAA4060EF, 0x065E719F, 0x51BD6E10, + 0xF93E218A, 0x3D96DD06, 0xAEDD3E05, 0x464DE6BD, 0xB591548D, 0x0571C45D, 0x6F0406D4, 0xFF605015, + 0x241998FB, 0x97D6BDE9, 0xCC894043, 0x7767D99E, 0xBDB0E842, 0x8807898B, 0x38E7195B, 0xDB79C8EE, + 0x47A17C0A, 0xE97C420F, 0xC9F8841E, 0x00000000, 0x83098086, 0x48322BED, 0xAC1E1170, 0x4E6C5A72, + 0xFBFD0EFF, 0x560F8538, 0x1E3DAED5, 0x27362D39, 0x640A0FD9, 0x21685CA6, 0xD19B5B54, 0x3A24362E, + 0xB10C0A67, 0x0F9357E7, 0xD2B4EE96, 0x9E1B9B91, 0x4F80C0C5, 0xA261DC20, 0x695A774B, 0x161C121A, + 0x0AE293BA, 0xE5C0A02A, 0x433C22E0, 0x1D121B17, 0x0B0E090D, 0xADF28BC7, 0xB92DB6A8, 0xC8141EA9, + 0x8557F119, 0x4CAF7507, 0xBBEE99DD, 0xFDA37F60, 0x9FF70126, 0xBC5C72F5, 0xC544663B, 0x345BFB7E, + 0x768B4329, 0xDCCB23C6, 0x68B6EDFC, 0x63B8E4F1, 0xCAD731DC, 0x10426385, 0x40139722, 0x2084C611, + 0x7D854A24, 0xF8D2BB3D, 0x11AEF932, 0x6DC729A1, 0x4B1D9E2F, 0xF3DCB230, 0xEC0D8652, 0xD077C1E3, + 0x6C2BB316, 0x99A970B9, 0xFA119448, 0x2247E964, 0xC4A8FC8C, 0x1AA0F03F, 0xD8567D2C, 0xEF223390, + 0xC787494E, 0xC1D938D1, 0xFE8CCAA2, 0x3698D40B, 0xCFA6F581, 0x28A57ADE, 0x26DAB78E, 0xA43FADBF, + 0xE42C3A9D, 0x0D507892, 0x9B6A5FCC, 0x62547E46, 0xC2F68D13, 0xE890D8B8, 0x5E2E39F7, 0xF582C3AF, + 0xBE9F5D80, 0x7C69D093, 0xA96FD52D, 0xB3CF2512, 0x3BC8AC99, 0xA710187D, 0x6EE89C63, 0x7BDB3BBB, + 0x09CD2678, 0xF46E5918, 0x01EC9AB7, 0xA8834F9A, 0x65E6956E, 0x7EAAFFE6, 0x0821BCCF, 0xE6EF15E8, + 0xD9BAE79B, 0xCE4A6F36, 0xD4EA9F09, 0xD629B07C, 0xAF31A4B2, 0x312A3F23, 0x30C6A594, 0xC035A266, + 0x37744EBC, 0xA6FC82CA, 0xB0E090D0, 0x1533A7D8, 0x4AF10498, 0xF741ECDA, 0x0E7FCD50, 0x2F1791F6, + 0x8D764DD6, 0x4D43EFB0, 0x54CCAA4D, 0xDFE49604, 0xE39ED1B5, 0x1B4C6A88, 0xB8C12C1F, 0x7F466551, + 0x049D5EEA, 0x5D018C35, 0x73FA8774, 0x2EFB0B41, 0x5AB3671D, 0x5292DBD2, 0x33E91056, 0x136DD647, + 0x8C9AD761, 0x7A37A10C, 0x8E59F814, 0x89EB133C, 0xEECEA927, 0x35B761C9, 0xEDE11CE5, 0x3C7A47B1, + 0x599CD2DF, 0x3F55F273, 0x791814CE, 0xBF73C737, 0xEA53F7CD, 0x5B5FFDAA, 0x14DF3D6F, 0x867844DB, + 0x81CAAFF3, 0x3EB968C4, 0x2C382434, 0x5FC2A340, 0x72161DC3, 0x0CBCE225, 0x8B283C49, 0x41FF0D95, + 0x7139A801, 0xDE080CB3, 0x9CD8B4E4, 0x906456C1, 0x617BCB84, 0x70D532B6, 0x74486C5C, 0x42D0B857 + ); + + /** + * Precomputed invMixColumns table + * + * @see Crypt_Rijndael:_encryptBlock() + * @see Crypt_Rijndael:_decryptBlock() + * @var Array + * @access private + */ + var $dt2 = array( + 0xA75051F4, 0x65537E41, 0xA4C31A17, 0x5E963A27, 0x6BCB3BAB, 0x45F11F9D, 0x58ABACFA, 0x03934BE3, + 0xFA552030, 0x6DF6AD76, 0x769188CC, 0x4C25F502, 0xD7FC4FE5, 0xCBD7C52A, 0x44802635, 0xA38FB562, + 0x5A49DEB1, 0x1B6725BA, 0x0E9845EA, 0xC0E15DFE, 0x7502C32F, 0xF012814C, 0x97A38D46, 0xF9C66BD3, + 0x5FE7038F, 0x9C951592, 0x7AEBBF6D, 0x59DA9552, 0x832DD4BE, 0x21D35874, 0x692949E0, 0xC8448EC9, + 0x896A75C2, 0x7978F48E, 0x3E6B9958, 0x71DD27B9, 0x4FB6BEE1, 0xAD17F088, 0xAC66C920, 0x3AB47DCE, + 0x4A1863DF, 0x3182E51A, 0x33609751, 0x7F456253, 0x77E0B164, 0xAE84BB6B, 0xA01CFE81, 0x2B94F908, + 0x68587048, 0xFD198F45, 0x6C8794DE, 0xF8B7527B, 0xD323AB73, 0x02E2724B, 0x8F57E31F, 0xAB2A6655, + 0x2807B2EB, 0xC2032FB5, 0x7B9A86C5, 0x08A5D337, 0x87F23028, 0xA5B223BF, 0x6ABA0203, 0x825CED16, + 0x1C2B8ACF, 0xB492A779, 0xF2F0F307, 0xE2A14E69, 0xF4CD65DA, 0xBED50605, 0x621FD134, 0xFE8AC4A6, + 0x539D342E, 0x55A0A2F3, 0xE132058A, 0xEB75A4F6, 0xEC390B83, 0xEFAA4060, 0x9F065E71, 0x1051BD6E, + 0x8AF93E21, 0x063D96DD, 0x05AEDD3E, 0xBD464DE6, 0x8DB59154, 0x5D0571C4, 0xD46F0406, 0x15FF6050, + 0xFB241998, 0xE997D6BD, 0x43CC8940, 0x9E7767D9, 0x42BDB0E8, 0x8B880789, 0x5B38E719, 0xEEDB79C8, + 0x0A47A17C, 0x0FE97C42, 0x1EC9F884, 0x00000000, 0x86830980, 0xED48322B, 0x70AC1E11, 0x724E6C5A, + 0xFFFBFD0E, 0x38560F85, 0xD51E3DAE, 0x3927362D, 0xD9640A0F, 0xA621685C, 0x54D19B5B, 0x2E3A2436, + 0x67B10C0A, 0xE70F9357, 0x96D2B4EE, 0x919E1B9B, 0xC54F80C0, 0x20A261DC, 0x4B695A77, 0x1A161C12, + 0xBA0AE293, 0x2AE5C0A0, 0xE0433C22, 0x171D121B, 0x0D0B0E09, 0xC7ADF28B, 0xA8B92DB6, 0xA9C8141E, + 0x198557F1, 0x074CAF75, 0xDDBBEE99, 0x60FDA37F, 0x269FF701, 0xF5BC5C72, 0x3BC54466, 0x7E345BFB, + 0x29768B43, 0xC6DCCB23, 0xFC68B6ED, 0xF163B8E4, 0xDCCAD731, 0x85104263, 0x22401397, 0x112084C6, + 0x247D854A, 0x3DF8D2BB, 0x3211AEF9, 0xA16DC729, 0x2F4B1D9E, 0x30F3DCB2, 0x52EC0D86, 0xE3D077C1, + 0x166C2BB3, 0xB999A970, 0x48FA1194, 0x642247E9, 0x8CC4A8FC, 0x3F1AA0F0, 0x2CD8567D, 0x90EF2233, + 0x4EC78749, 0xD1C1D938, 0xA2FE8CCA, 0x0B3698D4, 0x81CFA6F5, 0xDE28A57A, 0x8E26DAB7, 0xBFA43FAD, + 0x9DE42C3A, 0x920D5078, 0xCC9B6A5F, 0x4662547E, 0x13C2F68D, 0xB8E890D8, 0xF75E2E39, 0xAFF582C3, + 0x80BE9F5D, 0x937C69D0, 0x2DA96FD5, 0x12B3CF25, 0x993BC8AC, 0x7DA71018, 0x636EE89C, 0xBB7BDB3B, + 0x7809CD26, 0x18F46E59, 0xB701EC9A, 0x9AA8834F, 0x6E65E695, 0xE67EAAFF, 0xCF0821BC, 0xE8E6EF15, + 0x9BD9BAE7, 0x36CE4A6F, 0x09D4EA9F, 0x7CD629B0, 0xB2AF31A4, 0x23312A3F, 0x9430C6A5, 0x66C035A2, + 0xBC37744E, 0xCAA6FC82, 0xD0B0E090, 0xD81533A7, 0x984AF104, 0xDAF741EC, 0x500E7FCD, 0xF62F1791, + 0xD68D764D, 0xB04D43EF, 0x4D54CCAA, 0x04DFE496, 0xB5E39ED1, 0x881B4C6A, 0x1FB8C12C, 0x517F4665, + 0xEA049D5E, 0x355D018C, 0x7473FA87, 0x412EFB0B, 0x1D5AB367, 0xD25292DB, 0x5633E910, 0x47136DD6, + 0x618C9AD7, 0x0C7A37A1, 0x148E59F8, 0x3C89EB13, 0x27EECEA9, 0xC935B761, 0xE5EDE11C, 0xB13C7A47, + 0xDF599CD2, 0x733F55F2, 0xCE791814, 0x37BF73C7, 0xCDEA53F7, 0xAA5B5FFD, 0x6F14DF3D, 0xDB867844, + 0xF381CAAF, 0xC43EB968, 0x342C3824, 0x405FC2A3, 0xC372161D, 0x250CBCE2, 0x498B283C, 0x9541FF0D, + 0x017139A8, 0xB3DE080C, 0xE49CD8B4, 0xC1906456, 0x84617BCB, 0xB670D532, 0x5C74486C, 0x5742D0B8 + ); + + /** + * Precomputed invMixColumns table + * + * @see Crypt_Rijndael:_encryptBlock() + * @see Crypt_Rijndael:_decryptBlock() + * @var Array + * @access private + */ + var $dt3 = array( + 0xF4A75051, 0x4165537E, 0x17A4C31A, 0x275E963A, 0xAB6BCB3B, 0x9D45F11F, 0xFA58ABAC, 0xE303934B, + 0x30FA5520, 0x766DF6AD, 0xCC769188, 0x024C25F5, 0xE5D7FC4F, 0x2ACBD7C5, 0x35448026, 0x62A38FB5, + 0xB15A49DE, 0xBA1B6725, 0xEA0E9845, 0xFEC0E15D, 0x2F7502C3, 0x4CF01281, 0x4697A38D, 0xD3F9C66B, + 0x8F5FE703, 0x929C9515, 0x6D7AEBBF, 0x5259DA95, 0xBE832DD4, 0x7421D358, 0xE0692949, 0xC9C8448E, + 0xC2896A75, 0x8E7978F4, 0x583E6B99, 0xB971DD27, 0xE14FB6BE, 0x88AD17F0, 0x20AC66C9, 0xCE3AB47D, + 0xDF4A1863, 0x1A3182E5, 0x51336097, 0x537F4562, 0x6477E0B1, 0x6BAE84BB, 0x81A01CFE, 0x082B94F9, + 0x48685870, 0x45FD198F, 0xDE6C8794, 0x7BF8B752, 0x73D323AB, 0x4B02E272, 0x1F8F57E3, 0x55AB2A66, + 0xEB2807B2, 0xB5C2032F, 0xC57B9A86, 0x3708A5D3, 0x2887F230, 0xBFA5B223, 0x036ABA02, 0x16825CED, + 0xCF1C2B8A, 0x79B492A7, 0x07F2F0F3, 0x69E2A14E, 0xDAF4CD65, 0x05BED506, 0x34621FD1, 0xA6FE8AC4, + 0x2E539D34, 0xF355A0A2, 0x8AE13205, 0xF6EB75A4, 0x83EC390B, 0x60EFAA40, 0x719F065E, 0x6E1051BD, + 0x218AF93E, 0xDD063D96, 0x3E05AEDD, 0xE6BD464D, 0x548DB591, 0xC45D0571, 0x06D46F04, 0x5015FF60, + 0x98FB2419, 0xBDE997D6, 0x4043CC89, 0xD99E7767, 0xE842BDB0, 0x898B8807, 0x195B38E7, 0xC8EEDB79, + 0x7C0A47A1, 0x420FE97C, 0x841EC9F8, 0x00000000, 0x80868309, 0x2BED4832, 0x1170AC1E, 0x5A724E6C, + 0x0EFFFBFD, 0x8538560F, 0xAED51E3D, 0x2D392736, 0x0FD9640A, 0x5CA62168, 0x5B54D19B, 0x362E3A24, + 0x0A67B10C, 0x57E70F93, 0xEE96D2B4, 0x9B919E1B, 0xC0C54F80, 0xDC20A261, 0x774B695A, 0x121A161C, + 0x93BA0AE2, 0xA02AE5C0, 0x22E0433C, 0x1B171D12, 0x090D0B0E, 0x8BC7ADF2, 0xB6A8B92D, 0x1EA9C814, + 0xF1198557, 0x75074CAF, 0x99DDBBEE, 0x7F60FDA3, 0x01269FF7, 0x72F5BC5C, 0x663BC544, 0xFB7E345B, + 0x4329768B, 0x23C6DCCB, 0xEDFC68B6, 0xE4F163B8, 0x31DCCAD7, 0x63851042, 0x97224013, 0xC6112084, + 0x4A247D85, 0xBB3DF8D2, 0xF93211AE, 0x29A16DC7, 0x9E2F4B1D, 0xB230F3DC, 0x8652EC0D, 0xC1E3D077, + 0xB3166C2B, 0x70B999A9, 0x9448FA11, 0xE9642247, 0xFC8CC4A8, 0xF03F1AA0, 0x7D2CD856, 0x3390EF22, + 0x494EC787, 0x38D1C1D9, 0xCAA2FE8C, 0xD40B3698, 0xF581CFA6, 0x7ADE28A5, 0xB78E26DA, 0xADBFA43F, + 0x3A9DE42C, 0x78920D50, 0x5FCC9B6A, 0x7E466254, 0x8D13C2F6, 0xD8B8E890, 0x39F75E2E, 0xC3AFF582, + 0x5D80BE9F, 0xD0937C69, 0xD52DA96F, 0x2512B3CF, 0xAC993BC8, 0x187DA710, 0x9C636EE8, 0x3BBB7BDB, + 0x267809CD, 0x5918F46E, 0x9AB701EC, 0x4F9AA883, 0x956E65E6, 0xFFE67EAA, 0xBCCF0821, 0x15E8E6EF, + 0xE79BD9BA, 0x6F36CE4A, 0x9F09D4EA, 0xB07CD629, 0xA4B2AF31, 0x3F23312A, 0xA59430C6, 0xA266C035, + 0x4EBC3774, 0x82CAA6FC, 0x90D0B0E0, 0xA7D81533, 0x04984AF1, 0xECDAF741, 0xCD500E7F, 0x91F62F17, + 0x4DD68D76, 0xEFB04D43, 0xAA4D54CC, 0x9604DFE4, 0xD1B5E39E, 0x6A881B4C, 0x2C1FB8C1, 0x65517F46, + 0x5EEA049D, 0x8C355D01, 0x877473FA, 0x0B412EFB, 0x671D5AB3, 0xDBD25292, 0x105633E9, 0xD647136D, + 0xD7618C9A, 0xA10C7A37, 0xF8148E59, 0x133C89EB, 0xA927EECE, 0x61C935B7, 0x1CE5EDE1, 0x47B13C7A, + 0xD2DF599C, 0xF2733F55, 0x14CE7918, 0xC737BF73, 0xF7CDEA53, 0xFDAA5B5F, 0x3D6F14DF, 0x44DB8678, + 0xAFF381CA, 0x68C43EB9, 0x24342C38, 0xA3405FC2, 0x1DC37216, 0xE2250CBC, 0x3C498B28, 0x0D9541FF, + 0xA8017139, 0x0CB3DE08, 0xB4E49CD8, 0x56C19064, 0xCB84617B, 0x32B670D5, 0x6C5C7448, 0xB85742D0 + ); + + /** + * The SubByte S-Box + * + * @see Crypt_Rijndael::_encryptBlock() + * @var Array + * @access private + */ + var $sbox = array( + 0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76, + 0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0, + 0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15, + 0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75, + 0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84, + 0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF, + 0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8, + 0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2, + 0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73, + 0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB, + 0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79, + 0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08, + 0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A, + 0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E, + 0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF, + 0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16 + ); + + /** + * The inverse SubByte S-Box + * + * @see Crypt_Rijndael::_decryptBlock() + * @var Array + * @access private + */ + var $isbox = array( + 0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38, 0xBF, 0x40, 0xA3, 0x9E, 0x81, 0xF3, 0xD7, 0xFB, + 0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87, 0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB, + 0x54, 0x7B, 0x94, 0x32, 0xA6, 0xC2, 0x23, 0x3D, 0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E, + 0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2, 0x76, 0x5B, 0xA2, 0x49, 0x6D, 0x8B, 0xD1, 0x25, + 0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92, + 0x6C, 0x70, 0x48, 0x50, 0xFD, 0xED, 0xB9, 0xDA, 0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84, + 0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A, 0xF7, 0xE4, 0x58, 0x05, 0xB8, 0xB3, 0x45, 0x06, + 0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02, 0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B, + 0x3A, 0x91, 0x11, 0x41, 0x4F, 0x67, 0xDC, 0xEA, 0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73, + 0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85, 0xE2, 0xF9, 0x37, 0xE8, 0x1C, 0x75, 0xDF, 0x6E, + 0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89, 0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B, + 0xFC, 0x56, 0x3E, 0x4B, 0xC6, 0xD2, 0x79, 0x20, 0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4, + 0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31, 0xB1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xEC, 0x5F, + 0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D, 0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF, + 0xA0, 0xE0, 0x3B, 0x4D, 0xAE, 0x2A, 0xF5, 0xB0, 0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61, + 0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26, 0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D + ); + + /** + * Default Constructor. + * + * Determines whether or not the mcrypt extension should be used. + * + * $mode could be: + * + * - CRYPT_RIJNDAEL_MODE_ECB + * + * - CRYPT_RIJNDAEL_MODE_CBC + * + * - CRYPT_RIJNDAEL_MODE_CTR + * + * - CRYPT_RIJNDAEL_MODE_CFB + * + * - CRYPT_RIJNDAEL_MODE_OFB + * + * If not explictly set, CRYPT_RIJNDAEL_MODE_CBC will be used. + * + * @see Crypt_Base::Crypt_Base() + * @param optional Integer $mode + * @access public + */ + function Crypt_Rijndael($mode = CRYPT_RIJNDAEL_MODE_CBC) + { + parent::Crypt_Base($mode); + } + + /** + * Sets the key. + * + * Keys can be of any length. Rijndael, itself, requires the use of a key that's between 128-bits and 256-bits long and + * whose length is a multiple of 32. If the key is less than 256-bits and the key length isn't set, we round the length + * up to the closest valid key length, padding $key with null bytes. If the key is more than 256-bits, we trim the + * excess bits. + * + * If the key is not explicitly set, it'll be assumed to be all null bytes. + * + * Note: 160/224-bit keys must explicitly set by setKeyLength(), otherwise they will be round/pad up to 192/256 bits. + * + * @see Crypt_Base:setKey() + * @see setKeyLength() + * @access public + * @param String $key + */ + function setKey($key) + { + parent::setKey($key); + + if (!$this->explicit_key_length) { + $length = strlen($key); + switch (true) { + case $length <= 16: + $this->key_size = 16; + break; + case $length <= 24: + $this->key_size = 24; + break; + default: + $this->key_size = 32; + } + $this->_setupEngine(); + } + } + + /** + * Sets the key length + * + * Valid key lengths are 128, 160, 192, 224, and 256. If the length is less than 128, it will be rounded up to + * 128. If the length is greater than 128 and invalid, it will be rounded down to the closest valid amount. + * + * Note: phpseclib extends Rijndael (and AES) for using 160- and 224-bit keys but they are officially not defined + * and the most (if not all) implementations are not able using 160/224-bit keys but round/pad them up to + * 192/256 bits as, for example, mcrypt will do. + * + * That said, if you want be compatible with other Rijndael and AES implementations, + * you should not setKeyLength(160) or setKeyLength(224). + * + * Additional: In case of 160- and 224-bit keys, phpseclib will/can, for that reason, not use + * the mcrypt php extention, even if available. + * This results then in slower encryption. + * + * @access public + * @param Integer $length + */ + function setKeyLength($length) + { + switch (true) { + case $length == 160: + $this->key_size = 20; + break; + case $length == 224: + $this->key_size = 28; + break; + case $length <= 128: + $this->key_size = 16; + break; + case $length <= 192: + $this->key_size = 24; + break; + default: + $this->key_size = 32; + } + + $this->explicit_key_length = true; + $this->changed = true; + $this->_setupEngine(); + } + + /** + * Sets the block length + * + * Valid block lengths are 128, 160, 192, 224, and 256. If the length is less than 128, it will be rounded up to + * 128. If the length is greater than 128 and invalid, it will be rounded down to the closest valid amount. + * + * @access public + * @param Integer $length + */ + function setBlockLength($length) + { + $length >>= 5; + if ($length > 8) { + $length = 8; + } else if ($length < 4) { + $length = 4; + } + $this->Nb = $length; + $this->block_size = $length << 2; + $this->changed = true; + $this->_setupEngine(); + } + + /** + * Setup the fastest possible $engine + * + * Determines if the mcrypt (MODE_MCRYPT) $engine available + * and usable for the current $block_size and $key_size. + * + * If not, the slower MODE_INTERNAL $engine will be set. + * + * @see setKey() + * @see setKeyLength() + * @see setBlockLength() + * @access private + */ + function _setupEngine() + { + if (constant('CRYPT_' . $this->const_namespace . '_MODE') == CRYPT_MODE_INTERNAL) { + // No mcrypt support at all for rijndael + return; + } + + // The required mcrypt module name for the current $block_size of rijndael + $cipher_name_mcrypt = 'rijndael-' . ($this->block_size << 3); + + // Determining the availibility/usability of $cipher_name_mcrypt + switch (true) { + case $this->key_size % 8: // mcrypt is not usable for 160/224-bit keys, only for 128/192/256-bit keys + case !in_array($cipher_name_mcrypt, mcrypt_list_algorithms()): // $cipher_name_mcrypt is not available for the current $block_size + $engine = CRYPT_MODE_INTERNAL; + break; + default: + $engine = CRYPT_MODE_MCRYPT; + } + + if ($this->engine == $engine && $this->cipher_name_mcrypt == $cipher_name_mcrypt) { + // allready set, so we not unnecessary close $this->enmcrypt/demcrypt/ecb + return; + } + + // Set the $engine + $this->engine = $engine; + $this->cipher_name_mcrypt = $cipher_name_mcrypt; + + if ($this->enmcrypt) { + // Closing the current mcrypt resource(s). _mcryptSetup() will, if needed, + // (re)open them with the module named in $this->cipher_name_mcrypt + mcrypt_module_close($this->enmcrypt); + mcrypt_module_close($this->demcrypt); + $this->enmcrypt = null; + $this->demcrypt = null; + + if ($this->ecb) { + mcrypt_module_close($this->ecb); + $this->ecb = null; + } + } + } + + /** + * Setup the CRYPT_MODE_MCRYPT $engine + * + * @see Crypt_Base::_setupMcrypt() + * @access private + */ + function _setupMcrypt() + { + $this->key = str_pad(substr($this->key, 0, $this->key_size), $this->key_size, "\0"); + parent::_setupMcrypt(); + } + + /** + * Encrypts a block + * + * @access private + * @param String $in + * @return String + */ + function _encryptBlock($in) + { + static $t0, $t1, $t2, $t3, $sbox; + if (!$t0) { + for ($i = 0; $i < 256; ++$i) { + $t0[] = (int)$this->t0[$i]; + $t1[] = (int)$this->t1[$i]; + $t2[] = (int)$this->t2[$i]; + $t3[] = (int)$this->t3[$i]; + $sbox[] = (int)$this->sbox[$i]; + } + } + + $state = array(); + $words = unpack('N*', $in); + + $c = $this->c; + $w = $this->w; + $Nb = $this->Nb; + $Nr = $this->Nr; + + // addRoundKey + $i = -1; + foreach ($words as $word) { + $state[] = $word ^ $w[0][++$i]; + } + + // fips-197.pdf#page=19, "Figure 5. Pseudo Code for the Cipher", states that this loop has four components - + // subBytes, shiftRows, mixColumns, and addRoundKey. fips-197.pdf#page=30, "Implementation Suggestions Regarding + // Various Platforms" suggests that performs enhanced implementations are described in Rijndael-ammended.pdf. + // Rijndael-ammended.pdf#page=20, "Implementation aspects / 32-bit processor", discusses such an optimization. + // Unfortunately, the description given there is not quite correct. Per aes.spec.v316.pdf#page=19 [1], + // equation (7.4.7) is supposed to use addition instead of subtraction, so we'll do that here, as well. + + // [1] http://fp.gladman.plus.com/cryptography_technology/rijndael/aes.spec.v316.pdf + $temp = array(); + for ($round = 1; $round < $Nr; ++$round) { + $i = 0; // $c[0] == 0 + $j = $c[1]; + $k = $c[2]; + $l = $c[3]; + + while ($i < $Nb) { + $temp[$i] = $t0[$state[$i] >> 24 & 0x000000FF] ^ + $t1[$state[$j] >> 16 & 0x000000FF] ^ + $t2[$state[$k] >> 8 & 0x000000FF] ^ + $t3[$state[$l] & 0x000000FF] ^ + $w[$round][$i]; + ++$i; + $j = ($j + 1) % $Nb; + $k = ($k + 1) % $Nb; + $l = ($l + 1) % $Nb; + } + $state = $temp; + } + + // subWord + for ($i = 0; $i < $Nb; ++$i) { + $state[$i] = $sbox[$state[$i] & 0x000000FF] | + ($sbox[$state[$i] >> 8 & 0x000000FF] << 8) | + ($sbox[$state[$i] >> 16 & 0x000000FF] << 16) | + ($sbox[$state[$i] >> 24 & 0x000000FF] << 24); + } + + // shiftRows + addRoundKey + $i = 0; // $c[0] == 0 + $j = $c[1]; + $k = $c[2]; + $l = $c[3]; + while ($i < $Nb) { + $temp[$i] = ($state[$i] & 0xFF000000) ^ + ($state[$j] & 0x00FF0000) ^ + ($state[$k] & 0x0000FF00) ^ + ($state[$l] & 0x000000FF) ^ + $w[$Nr][$i]; + ++$i; + $j = ($j + 1) % $Nb; + $k = ($k + 1) % $Nb; + $l = ($l + 1) % $Nb; + } + + switch ($Nb) { + case 8: + return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4], $temp[5], $temp[6], $temp[7]); + case 7: + return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4], $temp[5], $temp[6]); + case 6: + return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4], $temp[5]); + case 5: + return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4]); + default: + return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3]); + } + } + + /** + * Decrypts a block + * + * @access private + * @param String $in + * @return String + */ + function _decryptBlock($in) + { + static $dt0, $dt1, $dt2, $dt3, $isbox; + if (!$dt0) { + for ($i = 0; $i < 256; ++$i) { + $dt0[] = (int)$this->dt0[$i]; + $dt1[] = (int)$this->dt1[$i]; + $dt2[] = (int)$this->dt2[$i]; + $dt3[] = (int)$this->dt3[$i]; + $isbox[] = (int)$this->isbox[$i]; + } + } + + $state = array(); + $words = unpack('N*', $in); + + $c = $this->c; + $dw = $this->dw; + $Nb = $this->Nb; + $Nr = $this->Nr; + + // addRoundKey + $i = -1; + foreach ($words as $word) { + $state[] = $word ^ $dw[$Nr][++$i]; + } + + $temp = array(); + for ($round = $Nr - 1; $round > 0; --$round) { + $i = 0; // $c[0] == 0 + $j = $Nb - $c[1]; + $k = $Nb - $c[2]; + $l = $Nb - $c[3]; + + while ($i < $Nb) { + $temp[$i] = $dt0[$state[$i] >> 24 & 0x000000FF] ^ + $dt1[$state[$j] >> 16 & 0x000000FF] ^ + $dt2[$state[$k] >> 8 & 0x000000FF] ^ + $dt3[$state[$l] & 0x000000FF] ^ + $dw[$round][$i]; + ++$i; + $j = ($j + 1) % $Nb; + $k = ($k + 1) % $Nb; + $l = ($l + 1) % $Nb; + } + $state = $temp; + } + + // invShiftRows + invSubWord + addRoundKey + $i = 0; // $c[0] == 0 + $j = $Nb - $c[1]; + $k = $Nb - $c[2]; + $l = $Nb - $c[3]; + + while ($i < $Nb) { + $word = ($state[$i] & 0xFF000000) | + ($state[$j] & 0x00FF0000) | + ($state[$k] & 0x0000FF00) | + ($state[$l] & 0x000000FF); + + $temp[$i] = $dw[0][$i] ^ ($isbox[$word & 0x000000FF] | + ($isbox[$word >> 8 & 0x000000FF] << 8) | + ($isbox[$word >> 16 & 0x000000FF] << 16) | + ($isbox[$word >> 24 & 0x000000FF] << 24)); + ++$i; + $j = ($j + 1) % $Nb; + $k = ($k + 1) % $Nb; + $l = ($l + 1) % $Nb; + } + + switch ($Nb) { + case 8: + return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4], $temp[5], $temp[6], $temp[7]); + case 7: + return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4], $temp[5], $temp[6]); + case 6: + return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4], $temp[5]); + case 5: + return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4]); + default: + return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3]); + } + } + + /** + * Setup the key (expansion) + * + * @see Crypt_Base::_setupKey() + * @access private + */ + function _setupKey() + { + // Each number in $rcon is equal to the previous number multiplied by two in Rijndael's finite field. + // See http://en.wikipedia.org/wiki/Finite_field_arithmetic#Multiplicative_inverse + static $rcon = array(0, + 0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000, + 0x20000000, 0x40000000, 0x80000000, 0x1B000000, 0x36000000, + 0x6C000000, 0xD8000000, 0xAB000000, 0x4D000000, 0x9A000000, + 0x2F000000, 0x5E000000, 0xBC000000, 0x63000000, 0xC6000000, + 0x97000000, 0x35000000, 0x6A000000, 0xD4000000, 0xB3000000, + 0x7D000000, 0xFA000000, 0xEF000000, 0xC5000000, 0x91000000 + ); + + $this->key = str_pad(substr($this->key, 0, $this->key_size), $this->key_size, "\0"); + + if (isset($this->kl['key']) && $this->key === $this->kl['key'] && $this->key_size === $this->kl['key_size'] && $this->block_size === $this->kl['block_size']) { + // already expanded + return; + } + $this->kl = array('key' => $this->key, 'key_size' => $this->key_size, 'block_size' => $this->block_size); + + $this->Nk = $this->key_size >> 2; + // see Rijndael-ammended.pdf#page=44 + $this->Nr = max($this->Nk, $this->Nb) + 6; + + // shift offsets for Nb = 5, 7 are defined in Rijndael-ammended.pdf#page=44, + // "Table 8: Shift offsets in Shiftrow for the alternative block lengths" + // shift offsets for Nb = 4, 6, 8 are defined in Rijndael-ammended.pdf#page=14, + // "Table 2: Shift offsets for different block lengths" + switch ($this->Nb) { + case 4: + case 5: + case 6: + $this->c = array(0, 1, 2, 3); + break; + case 7: + $this->c = array(0, 1, 2, 4); + break; + case 8: + $this->c = array(0, 1, 3, 4); + } + + $w = array_values(unpack('N*words', $this->key)); + + $length = $this->Nb * ($this->Nr + 1); + for ($i = $this->Nk; $i < $length; $i++) { + $temp = $w[$i - 1]; + if ($i % $this->Nk == 0) { + // according to , "the size of an integer is platform-dependent". + // on a 32-bit machine, it's 32-bits, and on a 64-bit machine, it's 64-bits. on a 32-bit machine, + // 0xFFFFFFFF << 8 == 0xFFFFFF00, but on a 64-bit machine, it equals 0xFFFFFFFF00. as such, doing 'and' + // with 0xFFFFFFFF (or 0xFFFFFF00) on a 32-bit machine is unnecessary, but on a 64-bit machine, it is. + $temp = (($temp << 8) & 0xFFFFFF00) | (($temp >> 24) & 0x000000FF); // rotWord + $temp = $this->_subWord($temp) ^ $rcon[$i / $this->Nk]; + } else if ($this->Nk > 6 && $i % $this->Nk == 4) { + $temp = $this->_subWord($temp); + } + $w[$i] = $w[$i - $this->Nk] ^ $temp; + } + + // convert the key schedule from a vector of $Nb * ($Nr + 1) length to a matrix with $Nr + 1 rows and $Nb columns + // and generate the inverse key schedule. more specifically, + // according to (section 5.3.3), + // "The key expansion for the Inverse Cipher is defined as follows: + // 1. Apply the Key Expansion. + // 2. Apply InvMixColumn to all Round Keys except the first and the last one." + // also, see fips-197.pdf#page=27, "5.3.5 Equivalent Inverse Cipher" + $temp = $this->w = $this->dw = array(); + for ($i = $row = $col = 0; $i < $length; $i++, $col++) { + if ($col == $this->Nb) { + if ($row == 0) { + $this->dw[0] = $this->w[0]; + } else { + // subWord + invMixColumn + invSubWord = invMixColumn + $j = 0; + while ($j < $this->Nb) { + $dw = $this->_subWord($this->w[$row][$j]); + $temp[$j] = $this->dt0[$dw >> 24 & 0x000000FF] ^ + $this->dt1[$dw >> 16 & 0x000000FF] ^ + $this->dt2[$dw >> 8 & 0x000000FF] ^ + $this->dt3[$dw & 0x000000FF]; + $j++; + } + $this->dw[$row] = $temp; + } + + $col = 0; + $row++; + } + $this->w[$row][$col] = $w[$i]; + } + + $this->dw[$row] = $this->w[$row]; + + // In case of $this->use_inline_crypt === true we have to use 1-dim key arrays (both ascending) + if ($this->use_inline_crypt) { + $this->dw = array_reverse($this->dw); + $w = array_pop($this->w); + $dw = array_pop($this->dw); + foreach ($this->w as $r => $wr) { + foreach ($wr as $c => $wc) { + $w[] = $wc; + $dw[] = $this->dw[$r][$c]; + } + } + $this->w = $w; + $this->dw = $dw; + } + } + + /** + * Performs S-Box substitutions + * + * @access private + * @param Integer $word + */ + function _subWord($word) + { + $sbox = $this->sbox; + + return $sbox[$word & 0x000000FF] | + ($sbox[$word >> 8 & 0x000000FF] << 8) | + ($sbox[$word >> 16 & 0x000000FF] << 16) | + ($sbox[$word >> 24 & 0x000000FF] << 24); + } + + /** + * Setup the performance-optimized function for de/encrypt() + * + * @see Crypt_Base::_setupInlineCrypt() + * @access private + */ + function _setupInlineCrypt() + { + // Note: _setupInlineCrypt() will be called only if $this->changed === true + // So here we are'nt under the same heavy timing-stress as we are in _de/encryptBlock() or de/encrypt(). + // However...the here generated function- $code, stored as php callback in $this->inline_crypt, must work as fast as even possible. + + $lambda_functions =& Crypt_Rijndael::_getLambdaFunctions(); + + // The first 10 generated $lambda_functions will use the key-words hardcoded for better performance. + // For memory reason we limit those ultra-optimized functions. + // After that, we use pure (extracted) integer vars for the key-words which is faster than accessing them via array. + if (count($lambda_functions) < 10) { + $w = $this->w; + $dw = $this->dw; + $init_encrypt = ''; + $init_decrypt = ''; + } else { + for ($i = 0, $cw = count($this->w); $i < $cw; ++$i) { + $w[] = '$w[' . $i . ']'; + $dw[] = '$dw[' . $i . ']'; + } + $init_encrypt = '$w = $self->w;'; + $init_decrypt = '$dw = $self->dw;'; + } + + $code_hash = md5(str_pad("Crypt_Rijndael, {$this->mode}, {$this->block_size}, ", 32, "\0") . implode(',', $w)); + + if (!isset($lambda_functions[$code_hash])) { + $Nr = $this->Nr; + $Nb = $this->Nb; + $c = $this->c; + + // Generating encrypt code: + $init_encrypt.= ' + static $t0, $t1, $t2, $t3, $sbox; + if (!$t0) { + for ($i = 0; $i < 256; ++$i) { + $t0[$i] = (int)$self->t0[$i]; + $t1[$i] = (int)$self->t1[$i]; + $t2[$i] = (int)$self->t2[$i]; + $t3[$i] = (int)$self->t3[$i]; + $sbox[$i] = (int)$self->sbox[$i]; + } + } + '; + + $s = 'e'; + $e = 's'; + $wc = $Nb - 1; + + // Preround: addRoundKey + $encrypt_block = '$in = unpack("N*", $in);'."\n"; + for ($i = 0; $i < $Nb; ++$i) { + $encrypt_block .= '$s'.$i.' = $in['.($i + 1).'] ^ '.$w[++$wc].";\n"; + } + + // Mainrounds: shiftRows + subWord + mixColumns + addRoundKey + for ($round = 1; $round < $Nr; ++$round) { + list($s, $e) = array($e, $s); + for ($i = 0; $i < $Nb; ++$i) { + $encrypt_block.= + '$'.$e.$i.' = + $t0[($'.$s.$i .' >> 24) & 0xff] ^ + $t1[($'.$s.(($i + $c[1]) % $Nb).' >> 16) & 0xff] ^ + $t2[($'.$s.(($i + $c[2]) % $Nb).' >> 8) & 0xff] ^ + $t3[ $'.$s.(($i + $c[3]) % $Nb).' & 0xff] ^ + '.$w[++$wc].";\n"; + } + } + + // Finalround: subWord + shiftRows + addRoundKey + for ($i = 0; $i < $Nb; ++$i) { + $encrypt_block.= + '$'.$e.$i.' = + $sbox[ $'.$e.$i.' & 0xff] | + ($sbox[($'.$e.$i.' >> 8) & 0xff] << 8) | + ($sbox[($'.$e.$i.' >> 16) & 0xff] << 16) | + ($sbox[($'.$e.$i.' >> 24) & 0xff] << 24);'."\n"; + } + $encrypt_block .= '$in = pack("N*"'."\n"; + for ($i = 0; $i < $Nb; ++$i) { + $encrypt_block.= ', + ($'.$e.$i .' & 0xFF000000) ^ + ($'.$e.(($i + $c[1]) % $Nb).' & 0x00FF0000) ^ + ($'.$e.(($i + $c[2]) % $Nb).' & 0x0000FF00) ^ + ($'.$e.(($i + $c[3]) % $Nb).' & 0x000000FF) ^ + '.$w[$i]."\n"; + } + $encrypt_block .= ');'; + + // Generating decrypt code: + $init_decrypt.= ' + static $dt0, $dt1, $dt2, $dt3, $isbox; + if (!$dt0) { + for ($i = 0; $i < 256; ++$i) { + $dt0[$i] = (int)$self->dt0[$i]; + $dt1[$i] = (int)$self->dt1[$i]; + $dt2[$i] = (int)$self->dt2[$i]; + $dt3[$i] = (int)$self->dt3[$i]; + $isbox[$i] = (int)$self->isbox[$i]; + } + } + '; + + $s = 'e'; + $e = 's'; + $wc = $Nb - 1; + + // Preround: addRoundKey + $decrypt_block = '$in = unpack("N*", $in);'."\n"; + for ($i = 0; $i < $Nb; ++$i) { + $decrypt_block .= '$s'.$i.' = $in['.($i + 1).'] ^ '.$dw[++$wc].';'."\n"; + } + + // Mainrounds: shiftRows + subWord + mixColumns + addRoundKey + for ($round = 1; $round < $Nr; ++$round) { + list($s, $e) = array($e, $s); + for ($i = 0; $i < $Nb; ++$i) { + $decrypt_block.= + '$'.$e.$i.' = + $dt0[($'.$s.$i .' >> 24) & 0xff] ^ + $dt1[($'.$s.(($Nb + $i - $c[1]) % $Nb).' >> 16) & 0xff] ^ + $dt2[($'.$s.(($Nb + $i - $c[2]) % $Nb).' >> 8) & 0xff] ^ + $dt3[ $'.$s.(($Nb + $i - $c[3]) % $Nb).' & 0xff] ^ + '.$dw[++$wc].";\n"; + } + } + + // Finalround: subWord + shiftRows + addRoundKey + for ($i = 0; $i < $Nb; ++$i) { + $decrypt_block.= + '$'.$e.$i.' = + $isbox[ $'.$e.$i.' & 0xff] | + ($isbox[($'.$e.$i.' >> 8) & 0xff] << 8) | + ($isbox[($'.$e.$i.' >> 16) & 0xff] << 16) | + ($isbox[($'.$e.$i.' >> 24) & 0xff] << 24);'."\n"; + } + $decrypt_block .= '$in = pack("N*"'."\n"; + for ($i = 0; $i < $Nb; ++$i) { + $decrypt_block.= ', + ($'.$e.$i. ' & 0xFF000000) ^ + ($'.$e.(($Nb + $i - $c[1]) % $Nb).' & 0x00FF0000) ^ + ($'.$e.(($Nb + $i - $c[2]) % $Nb).' & 0x0000FF00) ^ + ($'.$e.(($Nb + $i - $c[3]) % $Nb).' & 0x000000FF) ^ + '.$dw[$i]."\n"; + } + $decrypt_block .= ');'; + + $lambda_functions[$code_hash] = $this->_createInlineCryptFunction( + array( + 'init_crypt' => '', + 'init_encrypt' => $init_encrypt, + 'init_decrypt' => $init_decrypt, + 'encrypt_block' => $encrypt_block, + 'decrypt_block' => $decrypt_block + ) + ); + } + $this->inline_crypt = $lambda_functions[$code_hash]; + } +} + +// vim: ts=4:sw=4:et: +// vim6: fdl=1: diff --git a/inc/phpseclib/LICENSE b/inc/phpseclib/LICENSE new file mode 100644 index 000000000..6ecd9b9be --- /dev/null +++ b/inc/phpseclib/LICENSE @@ -0,0 +1,21 @@ +Copyright 2007-2012 TerraFrost and other contributors +http://phpseclib.sourceforge.net/ + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/inc/phpseclib/Math_BigInteger.php b/inc/phpseclib/Math_BigInteger.php new file mode 100644 index 000000000..a37662da9 --- /dev/null +++ b/inc/phpseclib/Math_BigInteger.php @@ -0,0 +1,3651 @@ +> and << cannot be used, nor can the modulo operator %, + * which only supports integers. Although this fact will slow this library down, the fact that such a high + * base is being used should more than compensate. + * + * When PHP version 6 is officially released, we'll be able to use 64-bit integers. This should, once again, + * allow bitwise operators, and will increase the maximum possible base to 2**31 (or 2**62 for addition / + * subtraction). + * + * Numbers are stored in {@link http://en.wikipedia.org/wiki/Endianness little endian} format. ie. + * (new Math_BigInteger(pow(2, 26)))->value = array(0, 1) + * + * Useful resources are as follows: + * + * - {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf Handbook of Applied Cryptography (HAC)} + * - {@link http://math.libtomcrypt.com/files/tommath.pdf Multi-Precision Math (MPM)} + * - Java's BigInteger classes. See /j2se/src/share/classes/java/math in jdk-1_5_0-src-jrl.zip + * + * Here's an example of how to use this library: + * + * add($b); + * + * echo $c->toString(); // outputs 5 + * ?> + * + * + * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @category Math + * @package Math_BigInteger + * @author Jim Wigginton + * @copyright MMVI Jim Wigginton + * @license http://www.opensource.org/licenses/mit-license.html MIT License + * @link http://pear.php.net/package/Math_BigInteger + */ + +/**#@+ + * Reduction constants + * + * @access private + * @see Math_BigInteger::_reduce() + */ +/** + * @see Math_BigInteger::_montgomery() + * @see Math_BigInteger::_prepMontgomery() + */ +define('MATH_BIGINTEGER_MONTGOMERY', 0); +/** + * @see Math_BigInteger::_barrett() + */ +define('MATH_BIGINTEGER_BARRETT', 1); +/** + * @see Math_BigInteger::_mod2() + */ +define('MATH_BIGINTEGER_POWEROF2', 2); +/** + * @see Math_BigInteger::_remainder() + */ +define('MATH_BIGINTEGER_CLASSIC', 3); +/** + * @see Math_BigInteger::__clone() + */ +define('MATH_BIGINTEGER_NONE', 4); +/**#@-*/ + +/**#@+ + * Array constants + * + * Rather than create a thousands and thousands of new Math_BigInteger objects in repeated function calls to add() and + * multiply() or whatever, we'll just work directly on arrays, taking them in as parameters and returning them. + * + * @access private + */ +/** + * $result[MATH_BIGINTEGER_VALUE] contains the value. + */ +define('MATH_BIGINTEGER_VALUE', 0); +/** + * $result[MATH_BIGINTEGER_SIGN] contains the sign. + */ +define('MATH_BIGINTEGER_SIGN', 1); +/**#@-*/ + +/**#@+ + * @access private + * @see Math_BigInteger::_montgomery() + * @see Math_BigInteger::_barrett() + */ +/** + * Cache constants + * + * $cache[MATH_BIGINTEGER_VARIABLE] tells us whether or not the cached data is still valid. + */ +define('MATH_BIGINTEGER_VARIABLE', 0); +/** + * $cache[MATH_BIGINTEGER_DATA] contains the cached data. + */ +define('MATH_BIGINTEGER_DATA', 1); +/**#@-*/ + +/**#@+ + * Mode constants. + * + * @access private + * @see Math_BigInteger::Math_BigInteger() + */ +/** + * To use the pure-PHP implementation + */ +define('MATH_BIGINTEGER_MODE_INTERNAL', 1); +/** + * To use the BCMath library + * + * (if enabled; otherwise, the internal implementation will be used) + */ +define('MATH_BIGINTEGER_MODE_BCMATH', 2); +/** + * To use the GMP library + * + * (if present; otherwise, either the BCMath or the internal implementation will be used) + */ +define('MATH_BIGINTEGER_MODE_GMP', 3); +/**#@-*/ + +/** + * Karatsuba Cutoff + * + * At what point do we switch between Karatsuba multiplication and schoolbook long multiplication? + * + * @access private + */ +define('MATH_BIGINTEGER_KARATSUBA_CUTOFF', 25); + +/** + * Pure-PHP arbitrary precision integer arithmetic library. Supports base-2, base-10, base-16, and base-256 + * numbers. + * + * @author Jim Wigginton + * @version 1.0.0RC4 + * @access public + * @package Math_BigInteger + */ +class Math_BigInteger { + /** + * Holds the BigInteger's value. + * + * @var Array + * @access private + */ + var $value; + + /** + * Holds the BigInteger's magnitude. + * + * @var Boolean + * @access private + */ + var $is_negative = false; + + /** + * Random number generator function + * + * @see setRandomGenerator() + * @access private + */ + var $generator = 'mt_rand'; + + /** + * Precision + * + * @see setPrecision() + * @access private + */ + var $precision = -1; + + /** + * Precision Bitmask + * + * @see setPrecision() + * @access private + */ + var $bitmask = false; + + /** + * Mode independent value used for serialization. + * + * If the bcmath or gmp extensions are installed $this->value will be a non-serializable resource, hence the need for + * a variable that'll be serializable regardless of whether or not extensions are being used. Unlike $this->value, + * however, $this->hex is only calculated when $this->__sleep() is called. + * + * @see __sleep() + * @see __wakeup() + * @var String + * @access private + */ + var $hex; + + /** + * Converts base-2, base-10, base-16, and binary strings (base-256) to BigIntegers. + * + * If the second parameter - $base - is negative, then it will be assumed that the number's are encoded using + * two's compliment. The sole exception to this is -10, which is treated the same as 10 is. + * + * Here's an example: + * + * <?php + * include('Math/BigInteger.php'); + * + * $a = new Math_BigInteger('0x32', 16); // 50 in base-16 + * + * echo $a->toString(); // outputs 50 + * ?> + * + * + * @param optional $x base-10 number or base-$base number if $base set. + * @param optional integer $base + * @return Math_BigInteger + * @access public + */ + function Math_BigInteger($x = 0, $base = 10) + { + if ( !defined('MATH_BIGINTEGER_MODE') ) { + switch (true) { + case extension_loaded('gmp'): + define('MATH_BIGINTEGER_MODE', MATH_BIGINTEGER_MODE_GMP); + break; + case extension_loaded('bcmath'): + define('MATH_BIGINTEGER_MODE', MATH_BIGINTEGER_MODE_BCMATH); + break; + default: + define('MATH_BIGINTEGER_MODE', MATH_BIGINTEGER_MODE_INTERNAL); + } + } + + if (function_exists('openssl_public_encrypt') && !defined('MATH_BIGINTEGER_OPENSSL_DISABLE') && !defined('MATH_BIGINTEGER_OPENSSL_ENABLED')) { + define('MATH_BIGINTEGER_OPENSSL_ENABLED', true); + } + + if (!defined('PHP_INT_SIZE')) { + define('PHP_INT_SIZE', 4); + } + + if (!defined('MATH_BIGINTEGER_BASE') && MATH_BIGINTEGER_MODE == MATH_BIGINTEGER_MODE_INTERNAL) { + switch (PHP_INT_SIZE) { + case 8: // use 64-bit integers if int size is 8 bytes + define('MATH_BIGINTEGER_BASE', 31); + define('MATH_BIGINTEGER_BASE_FULL', 0x80000000); + define('MATH_BIGINTEGER_MAX_DIGIT', 0x7FFFFFFF); + define('MATH_BIGINTEGER_MSB', 0x40000000); + // 10**9 is the closest we can get to 2**31 without passing it + define('MATH_BIGINTEGER_MAX10', 1000000000); + define('MATH_BIGINTEGER_MAX10_LEN', 9); + // the largest digit that may be used in addition / subtraction + define('MATH_BIGINTEGER_MAX_DIGIT2', pow(2, 62)); + break; + //case 4: // use 64-bit floats if int size is 4 bytes + default: + define('MATH_BIGINTEGER_BASE', 26); + define('MATH_BIGINTEGER_BASE_FULL', 0x4000000); + define('MATH_BIGINTEGER_MAX_DIGIT', 0x3FFFFFF); + define('MATH_BIGINTEGER_MSB', 0x2000000); + // 10**7 is the closest to 2**26 without passing it + define('MATH_BIGINTEGER_MAX10', 10000000); + define('MATH_BIGINTEGER_MAX10_LEN', 7); + // the largest digit that may be used in addition / subtraction + // we do pow(2, 52) instead of using 4503599627370496 directly because some + // PHP installations will truncate 4503599627370496. + define('MATH_BIGINTEGER_MAX_DIGIT2', pow(2, 52)); + } + } + + switch ( MATH_BIGINTEGER_MODE ) { + case MATH_BIGINTEGER_MODE_GMP: + if (is_resource($x) && get_resource_type($x) == 'GMP integer') { + $this->value = $x; + return; + } + $this->value = gmp_init(0); + break; + case MATH_BIGINTEGER_MODE_BCMATH: + $this->value = '0'; + break; + default: + $this->value = array(); + } + + // '0' counts as empty() but when the base is 256 '0' is equal to ord('0') or 48 + // '0' is the only value like this per http://php.net/empty + if (empty($x) && (abs($base) != 256 || $x !== '0')) { + return; + } + + switch ($base) { + case -256: + if (ord($x[0]) & 0x80) { + $x = ~$x; + $this->is_negative = true; + } + case 256: + switch ( MATH_BIGINTEGER_MODE ) { + case MATH_BIGINTEGER_MODE_GMP: + $sign = $this->is_negative ? '-' : ''; + $this->value = gmp_init($sign . '0x' . bin2hex($x)); + break; + case MATH_BIGINTEGER_MODE_BCMATH: + // round $len to the nearest 4 (thanks, DavidMJ!) + $len = (strlen($x) + 3) & 0xFFFFFFFC; + + $x = str_pad($x, $len, chr(0), STR_PAD_LEFT); + + for ($i = 0; $i < $len; $i+= 4) { + $this->value = bcmul($this->value, '4294967296', 0); // 4294967296 == 2**32 + $this->value = bcadd($this->value, 0x1000000 * ord($x[$i]) + ((ord($x[$i + 1]) << 16) | (ord($x[$i + 2]) << 8) | ord($x[$i + 3])), 0); + } + + if ($this->is_negative) { + $this->value = '-' . $this->value; + } + + break; + // converts a base-2**8 (big endian / msb) number to base-2**26 (little endian / lsb) + default: + while (strlen($x)) { + $this->value[] = $this->_bytes2int($this->_base256_rshift($x, MATH_BIGINTEGER_BASE)); + } + } + + if ($this->is_negative) { + if (MATH_BIGINTEGER_MODE != MATH_BIGINTEGER_MODE_INTERNAL) { + $this->is_negative = false; + } + $temp = $this->add(new Math_BigInteger('-1')); + $this->value = $temp->value; + } + break; + case 16: + case -16: + if ($base > 0 && $x[0] == '-') { + $this->is_negative = true; + $x = substr($x, 1); + } + + $x = preg_replace('#^(?:0x)?([A-Fa-f0-9]*).*#', '$1', $x); + + $is_negative = false; + if ($base < 0 && hexdec($x[0]) >= 8) { + $this->is_negative = $is_negative = true; + $x = bin2hex(~pack('H*', $x)); + } + + switch ( MATH_BIGINTEGER_MODE ) { + case MATH_BIGINTEGER_MODE_GMP: + $temp = $this->is_negative ? '-0x' . $x : '0x' . $x; + $this->value = gmp_init($temp); + $this->is_negative = false; + break; + case MATH_BIGINTEGER_MODE_BCMATH: + $x = ( strlen($x) & 1 ) ? '0' . $x : $x; + $temp = new Math_BigInteger(pack('H*', $x), 256); + $this->value = $this->is_negative ? '-' . $temp->value : $temp->value; + $this->is_negative = false; + break; + default: + $x = ( strlen($x) & 1 ) ? '0' . $x : $x; + $temp = new Math_BigInteger(pack('H*', $x), 256); + $this->value = $temp->value; + } + + if ($is_negative) { + $temp = $this->add(new Math_BigInteger('-1')); + $this->value = $temp->value; + } + break; + case 10: + case -10: + // (?value = gmp_init($x); + break; + case MATH_BIGINTEGER_MODE_BCMATH: + // explicitly casting $x to a string is necessary, here, since doing $x[0] on -1 yields different + // results then doing it on '-1' does (modInverse does $x[0]) + $this->value = $x === '-' ? '0' : (string) $x; + break; + default: + $temp = new Math_BigInteger(); + + $multiplier = new Math_BigInteger(); + $multiplier->value = array(MATH_BIGINTEGER_MAX10); + + if ($x[0] == '-') { + $this->is_negative = true; + $x = substr($x, 1); + } + + $x = str_pad($x, strlen($x) + ((MATH_BIGINTEGER_MAX10_LEN - 1) * strlen($x)) % MATH_BIGINTEGER_MAX10_LEN, 0, STR_PAD_LEFT); + + while (strlen($x)) { + $temp = $temp->multiply($multiplier); + $temp = $temp->add(new Math_BigInteger($this->_int2bytes(substr($x, 0, MATH_BIGINTEGER_MAX10_LEN)), 256)); + $x = substr($x, MATH_BIGINTEGER_MAX10_LEN); + } + + $this->value = $temp->value; + } + break; + case 2: // base-2 support originally implemented by Lluis Pamies - thanks! + case -2: + if ($base > 0 && $x[0] == '-') { + $this->is_negative = true; + $x = substr($x, 1); + } + + $x = preg_replace('#^([01]*).*#', '$1', $x); + $x = str_pad($x, strlen($x) + (3 * strlen($x)) % 4, 0, STR_PAD_LEFT); + + $str = '0x'; + while (strlen($x)) { + $part = substr($x, 0, 4); + $str.= dechex(bindec($part)); + $x = substr($x, 4); + } + + if ($this->is_negative) { + $str = '-' . $str; + } + + $temp = new Math_BigInteger($str, 8 * $base); // ie. either -16 or +16 + $this->value = $temp->value; + $this->is_negative = $temp->is_negative; + + break; + default: + // base not supported, so we'll let $this == 0 + } + } + + /** + * Converts a BigInteger to a byte string (eg. base-256). + * + * Negative numbers are saved as positive numbers, unless $twos_compliment is set to true, at which point, they're + * saved as two's compliment. + * + * Here's an example: + * + * toBytes(); // outputs chr(65) + * ?> + * + * + * @param Boolean $twos_compliment + * @return String + * @access public + * @internal Converts a base-2**26 number to base-2**8 + */ + function toBytes($twos_compliment = false) + { + if ($twos_compliment) { + $comparison = $this->compare(new Math_BigInteger()); + if ($comparison == 0) { + return $this->precision > 0 ? str_repeat(chr(0), ($this->precision + 1) >> 3) : ''; + } + + $temp = $comparison < 0 ? $this->add(new Math_BigInteger(1)) : $this->copy(); + $bytes = $temp->toBytes(); + + if (empty($bytes)) { // eg. if the number we're trying to convert is -1 + $bytes = chr(0); + } + + if (ord($bytes[0]) & 0x80) { + $bytes = chr(0) . $bytes; + } + + return $comparison < 0 ? ~$bytes : $bytes; + } + + switch ( MATH_BIGINTEGER_MODE ) { + case MATH_BIGINTEGER_MODE_GMP: + if (gmp_cmp($this->value, gmp_init(0)) == 0) { + return $this->precision > 0 ? str_repeat(chr(0), ($this->precision + 1) >> 3) : ''; + } + + $temp = gmp_strval(gmp_abs($this->value), 16); + $temp = ( strlen($temp) & 1 ) ? '0' . $temp : $temp; + $temp = pack('H*', $temp); + + return $this->precision > 0 ? + substr(str_pad($temp, $this->precision >> 3, chr(0), STR_PAD_LEFT), -($this->precision >> 3)) : + ltrim($temp, chr(0)); + case MATH_BIGINTEGER_MODE_BCMATH: + if ($this->value === '0') { + return $this->precision > 0 ? str_repeat(chr(0), ($this->precision + 1) >> 3) : ''; + } + + $value = ''; + $current = $this->value; + + if ($current[0] == '-') { + $current = substr($current, 1); + } + + while (bccomp($current, '0', 0) > 0) { + $temp = bcmod($current, '16777216'); + $value = chr($temp >> 16) . chr($temp >> 8) . chr($temp) . $value; + $current = bcdiv($current, '16777216', 0); + } + + return $this->precision > 0 ? + substr(str_pad($value, $this->precision >> 3, chr(0), STR_PAD_LEFT), -($this->precision >> 3)) : + ltrim($value, chr(0)); + } + + if (!count($this->value)) { + return $this->precision > 0 ? str_repeat(chr(0), ($this->precision + 1) >> 3) : ''; + } + $result = $this->_int2bytes($this->value[count($this->value) - 1]); + + $temp = $this->copy(); + + for ($i = count($temp->value) - 2; $i >= 0; --$i) { + $temp->_base256_lshift($result, MATH_BIGINTEGER_BASE); + $result = $result | str_pad($temp->_int2bytes($temp->value[$i]), strlen($result), chr(0), STR_PAD_LEFT); + } + + return $this->precision > 0 ? + str_pad(substr($result, -(($this->precision + 7) >> 3)), ($this->precision + 7) >> 3, chr(0), STR_PAD_LEFT) : + $result; + } + + /** + * Converts a BigInteger to a hex string (eg. base-16)). + * + * Negative numbers are saved as positive numbers, unless $twos_compliment is set to true, at which point, they're + * saved as two's compliment. + * + * Here's an example: + * + * toHex(); // outputs '41' + * ?> + * + * + * @param Boolean $twos_compliment + * @return String + * @access public + * @internal Converts a base-2**26 number to base-2**8 + */ + function toHex($twos_compliment = false) + { + return bin2hex($this->toBytes($twos_compliment)); + } + + /** + * Converts a BigInteger to a bit string (eg. base-2). + * + * Negative numbers are saved as positive numbers, unless $twos_compliment is set to true, at which point, they're + * saved as two's compliment. + * + * Here's an example: + * + * toBits(); // outputs '1000001' + * ?> + * + * + * @param Boolean $twos_compliment + * @return String + * @access public + * @internal Converts a base-2**26 number to base-2**2 + */ + function toBits($twos_compliment = false) + { + $hex = $this->toHex($twos_compliment); + $bits = ''; + for ($i = strlen($hex) - 8, $start = strlen($hex) & 7; $i >= $start; $i-=8) { + $bits = str_pad(decbin(hexdec(substr($hex, $i, 8))), 32, '0', STR_PAD_LEFT) . $bits; + } + if ($start) { // hexdec('') == 0 + $bits = str_pad(decbin(hexdec(substr($hex, 0, $start))), 8, '0', STR_PAD_LEFT) . $bits; + } + $result = $this->precision > 0 ? substr($bits, -$this->precision) : ltrim($bits, '0'); + + if ($twos_compliment && $this->compare(new Math_BigInteger()) > 0 && $this->precision <= 0) { + return '0' . $result; + } + + return $result; + } + + /** + * Converts a BigInteger to a base-10 number. + * + * Here's an example: + * + * toString(); // outputs 50 + * ?> + * + * + * @return String + * @access public + * @internal Converts a base-2**26 number to base-10**7 (which is pretty much base-10) + */ + function toString() + { + switch ( MATH_BIGINTEGER_MODE ) { + case MATH_BIGINTEGER_MODE_GMP: + return gmp_strval($this->value); + case MATH_BIGINTEGER_MODE_BCMATH: + if ($this->value === '0') { + return '0'; + } + + return ltrim($this->value, '0'); + } + + if (!count($this->value)) { + return '0'; + } + + $temp = $this->copy(); + $temp->is_negative = false; + + $divisor = new Math_BigInteger(); + $divisor->value = array(MATH_BIGINTEGER_MAX10); + $result = ''; + while (count($temp->value)) { + list($temp, $mod) = $temp->divide($divisor); + $result = str_pad(isset($mod->value[0]) ? $mod->value[0] : '', MATH_BIGINTEGER_MAX10_LEN, '0', STR_PAD_LEFT) . $result; + } + $result = ltrim($result, '0'); + if (empty($result)) { + $result = '0'; + } + + if ($this->is_negative) { + $result = '-' . $result; + } + + return $result; + } + + /** + * Copy an object + * + * PHP5 passes objects by reference while PHP4 passes by value. As such, we need a function to guarantee + * that all objects are passed by value, when appropriate. More information can be found here: + * + * {@link http://php.net/language.oop5.basic#51624} + * + * @access public + * @see __clone() + * @return Math_BigInteger + */ + function copy() + { + $temp = new Math_BigInteger(); + $temp->value = $this->value; + $temp->is_negative = $this->is_negative; + $temp->generator = $this->generator; + $temp->precision = $this->precision; + $temp->bitmask = $this->bitmask; + return $temp; + } + + /** + * __toString() magic method + * + * Will be called, automatically, if you're supporting just PHP5. If you're supporting PHP4, you'll need to call + * toString(). + * + * @access public + * @internal Implemented per a suggestion by Techie-Michael - thanks! + */ + function __toString() + { + return $this->toString(); + } + + /** + * __clone() magic method + * + * Although you can call Math_BigInteger::__toString() directly in PHP5, you cannot call Math_BigInteger::__clone() + * directly in PHP5. You can in PHP4 since it's not a magic method, but in PHP5, you have to call it by using the PHP5 + * only syntax of $y = clone $x. As such, if you're trying to write an application that works on both PHP4 and PHP5, + * call Math_BigInteger::copy(), instead. + * + * @access public + * @see copy() + * @return Math_BigInteger + */ + function __clone() + { + return $this->copy(); + } + + /** + * __sleep() magic method + * + * Will be called, automatically, when serialize() is called on a Math_BigInteger object. + * + * @see __wakeup() + * @access public + */ + function __sleep() + { + $this->hex = $this->toHex(true); + $vars = array('hex'); + if ($this->generator != 'mt_rand') { + $vars[] = 'generator'; + } + if ($this->precision > 0) { + $vars[] = 'precision'; + } + return $vars; + + } + + /** + * __wakeup() magic method + * + * Will be called, automatically, when unserialize() is called on a Math_BigInteger object. + * + * @see __sleep() + * @access public + */ + function __wakeup() + { + $temp = new Math_BigInteger($this->hex, -16); + $this->value = $temp->value; + $this->is_negative = $temp->is_negative; + $this->setRandomGenerator($this->generator); + if ($this->precision > 0) { + // recalculate $this->bitmask + $this->setPrecision($this->precision); + } + } + + /** + * Adds two BigIntegers. + * + * Here's an example: + * + * add($b); + * + * echo $c->toString(); // outputs 30 + * ?> + * + * + * @param Math_BigInteger $y + * @return Math_BigInteger + * @access public + * @internal Performs base-2**52 addition + */ + function add($y) + { + switch ( MATH_BIGINTEGER_MODE ) { + case MATH_BIGINTEGER_MODE_GMP: + $temp = new Math_BigInteger(); + $temp->value = gmp_add($this->value, $y->value); + + return $this->_normalize($temp); + case MATH_BIGINTEGER_MODE_BCMATH: + $temp = new Math_BigInteger(); + $temp->value = bcadd($this->value, $y->value, 0); + + return $this->_normalize($temp); + } + + $temp = $this->_add($this->value, $this->is_negative, $y->value, $y->is_negative); + + $result = new Math_BigInteger(); + $result->value = $temp[MATH_BIGINTEGER_VALUE]; + $result->is_negative = $temp[MATH_BIGINTEGER_SIGN]; + + return $this->_normalize($result); + } + + /** + * Performs addition. + * + * @param Array $x_value + * @param Boolean $x_negative + * @param Array $y_value + * @param Boolean $y_negative + * @return Array + * @access private + */ + function _add($x_value, $x_negative, $y_value, $y_negative) + { + $x_size = count($x_value); + $y_size = count($y_value); + + if ($x_size == 0) { + return array( + MATH_BIGINTEGER_VALUE => $y_value, + MATH_BIGINTEGER_SIGN => $y_negative + ); + } else if ($y_size == 0) { + return array( + MATH_BIGINTEGER_VALUE => $x_value, + MATH_BIGINTEGER_SIGN => $x_negative + ); + } + + // subtract, if appropriate + if ( $x_negative != $y_negative ) { + if ( $x_value == $y_value ) { + return array( + MATH_BIGINTEGER_VALUE => array(), + MATH_BIGINTEGER_SIGN => false + ); + } + + $temp = $this->_subtract($x_value, false, $y_value, false); + $temp[MATH_BIGINTEGER_SIGN] = $this->_compare($x_value, false, $y_value, false) > 0 ? + $x_negative : $y_negative; + + return $temp; + } + + if ($x_size < $y_size) { + $size = $x_size; + $value = $y_value; + } else { + $size = $y_size; + $value = $x_value; + } + + $value[] = 0; // just in case the carry adds an extra digit + + $carry = 0; + for ($i = 0, $j = 1; $j < $size; $i+=2, $j+=2) { + $sum = $x_value[$j] * MATH_BIGINTEGER_BASE_FULL + $x_value[$i] + $y_value[$j] * MATH_BIGINTEGER_BASE_FULL + $y_value[$i] + $carry; + $carry = $sum >= MATH_BIGINTEGER_MAX_DIGIT2; // eg. floor($sum / 2**52); only possible values (in any base) are 0 and 1 + $sum = $carry ? $sum - MATH_BIGINTEGER_MAX_DIGIT2 : $sum; + + $temp = (int) ($sum / MATH_BIGINTEGER_BASE_FULL); + + $value[$i] = (int) ($sum - MATH_BIGINTEGER_BASE_FULL * $temp); // eg. a faster alternative to fmod($sum, 0x4000000) + $value[$j] = $temp; + } + + if ($j == $size) { // ie. if $y_size is odd + $sum = $x_value[$i] + $y_value[$i] + $carry; + $carry = $sum >= MATH_BIGINTEGER_BASE_FULL; + $value[$i] = $carry ? $sum - MATH_BIGINTEGER_BASE_FULL : $sum; + ++$i; // ie. let $i = $j since we've just done $value[$i] + } + + if ($carry) { + for (; $value[$i] == MATH_BIGINTEGER_MAX_DIGIT; ++$i) { + $value[$i] = 0; + } + ++$value[$i]; + } + + return array( + MATH_BIGINTEGER_VALUE => $this->_trim($value), + MATH_BIGINTEGER_SIGN => $x_negative + ); + } + + /** + * Subtracts two BigIntegers. + * + * Here's an example: + * + * subtract($b); + * + * echo $c->toString(); // outputs -10 + * ?> + * + * + * @param Math_BigInteger $y + * @return Math_BigInteger + * @access public + * @internal Performs base-2**52 subtraction + */ + function subtract($y) + { + switch ( MATH_BIGINTEGER_MODE ) { + case MATH_BIGINTEGER_MODE_GMP: + $temp = new Math_BigInteger(); + $temp->value = gmp_sub($this->value, $y->value); + + return $this->_normalize($temp); + case MATH_BIGINTEGER_MODE_BCMATH: + $temp = new Math_BigInteger(); + $temp->value = bcsub($this->value, $y->value, 0); + + return $this->_normalize($temp); + } + + $temp = $this->_subtract($this->value, $this->is_negative, $y->value, $y->is_negative); + + $result = new Math_BigInteger(); + $result->value = $temp[MATH_BIGINTEGER_VALUE]; + $result->is_negative = $temp[MATH_BIGINTEGER_SIGN]; + + return $this->_normalize($result); + } + + /** + * Performs subtraction. + * + * @param Array $x_value + * @param Boolean $x_negative + * @param Array $y_value + * @param Boolean $y_negative + * @return Array + * @access private + */ + function _subtract($x_value, $x_negative, $y_value, $y_negative) + { + $x_size = count($x_value); + $y_size = count($y_value); + + if ($x_size == 0) { + return array( + MATH_BIGINTEGER_VALUE => $y_value, + MATH_BIGINTEGER_SIGN => !$y_negative + ); + } else if ($y_size == 0) { + return array( + MATH_BIGINTEGER_VALUE => $x_value, + MATH_BIGINTEGER_SIGN => $x_negative + ); + } + + // add, if appropriate (ie. -$x - +$y or +$x - -$y) + if ( $x_negative != $y_negative ) { + $temp = $this->_add($x_value, false, $y_value, false); + $temp[MATH_BIGINTEGER_SIGN] = $x_negative; + + return $temp; + } + + $diff = $this->_compare($x_value, $x_negative, $y_value, $y_negative); + + if ( !$diff ) { + return array( + MATH_BIGINTEGER_VALUE => array(), + MATH_BIGINTEGER_SIGN => false + ); + } + + // switch $x and $y around, if appropriate. + if ( (!$x_negative && $diff < 0) || ($x_negative && $diff > 0) ) { + $temp = $x_value; + $x_value = $y_value; + $y_value = $temp; + + $x_negative = !$x_negative; + + $x_size = count($x_value); + $y_size = count($y_value); + } + + // at this point, $x_value should be at least as big as - if not bigger than - $y_value + + $carry = 0; + for ($i = 0, $j = 1; $j < $y_size; $i+=2, $j+=2) { + $sum = $x_value[$j] * MATH_BIGINTEGER_BASE_FULL + $x_value[$i] - $y_value[$j] * MATH_BIGINTEGER_BASE_FULL - $y_value[$i] - $carry; + $carry = $sum < 0; // eg. floor($sum / 2**52); only possible values (in any base) are 0 and 1 + $sum = $carry ? $sum + MATH_BIGINTEGER_MAX_DIGIT2 : $sum; + + $temp = (int) ($sum / MATH_BIGINTEGER_BASE_FULL); + + $x_value[$i] = (int) ($sum - MATH_BIGINTEGER_BASE_FULL * $temp); + $x_value[$j] = $temp; + } + + if ($j == $y_size) { // ie. if $y_size is odd + $sum = $x_value[$i] - $y_value[$i] - $carry; + $carry = $sum < 0; + $x_value[$i] = $carry ? $sum + MATH_BIGINTEGER_BASE_FULL : $sum; + ++$i; + } + + if ($carry) { + for (; !$x_value[$i]; ++$i) { + $x_value[$i] = MATH_BIGINTEGER_MAX_DIGIT; + } + --$x_value[$i]; + } + + return array( + MATH_BIGINTEGER_VALUE => $this->_trim($x_value), + MATH_BIGINTEGER_SIGN => $x_negative + ); + } + + /** + * Multiplies two BigIntegers + * + * Here's an example: + * + * multiply($b); + * + * echo $c->toString(); // outputs 200 + * ?> + * + * + * @param Math_BigInteger $x + * @return Math_BigInteger + * @access public + */ + function multiply($x) + { + switch ( MATH_BIGINTEGER_MODE ) { + case MATH_BIGINTEGER_MODE_GMP: + $temp = new Math_BigInteger(); + $temp->value = gmp_mul($this->value, $x->value); + + return $this->_normalize($temp); + case MATH_BIGINTEGER_MODE_BCMATH: + $temp = new Math_BigInteger(); + $temp->value = bcmul($this->value, $x->value, 0); + + return $this->_normalize($temp); + } + + $temp = $this->_multiply($this->value, $this->is_negative, $x->value, $x->is_negative); + + $product = new Math_BigInteger(); + $product->value = $temp[MATH_BIGINTEGER_VALUE]; + $product->is_negative = $temp[MATH_BIGINTEGER_SIGN]; + + return $this->_normalize($product); + } + + /** + * Performs multiplication. + * + * @param Array $x_value + * @param Boolean $x_negative + * @param Array $y_value + * @param Boolean $y_negative + * @return Array + * @access private + */ + function _multiply($x_value, $x_negative, $y_value, $y_negative) + { + //if ( $x_value == $y_value ) { + // return array( + // MATH_BIGINTEGER_VALUE => $this->_square($x_value), + // MATH_BIGINTEGER_SIGN => $x_sign != $y_value + // ); + //} + + $x_length = count($x_value); + $y_length = count($y_value); + + if ( !$x_length || !$y_length ) { // a 0 is being multiplied + return array( + MATH_BIGINTEGER_VALUE => array(), + MATH_BIGINTEGER_SIGN => false + ); + } + + return array( + MATH_BIGINTEGER_VALUE => min($x_length, $y_length) < 2 * MATH_BIGINTEGER_KARATSUBA_CUTOFF ? + $this->_trim($this->_regularMultiply($x_value, $y_value)) : + $this->_trim($this->_karatsuba($x_value, $y_value)), + MATH_BIGINTEGER_SIGN => $x_negative != $y_negative + ); + } + + /** + * Performs long multiplication on two BigIntegers + * + * Modeled after 'multiply' in MutableBigInteger.java. + * + * @param Array $x_value + * @param Array $y_value + * @return Array + * @access private + */ + function _regularMultiply($x_value, $y_value) + { + $x_length = count($x_value); + $y_length = count($y_value); + + if ( !$x_length || !$y_length ) { // a 0 is being multiplied + return array(); + } + + if ( $x_length < $y_length ) { + $temp = $x_value; + $x_value = $y_value; + $y_value = $temp; + + $x_length = count($x_value); + $y_length = count($y_value); + } + + $product_value = $this->_array_repeat(0, $x_length + $y_length); + + // the following for loop could be removed if the for loop following it + // (the one with nested for loops) initially set $i to 0, but + // doing so would also make the result in one set of unnecessary adds, + // since on the outermost loops first pass, $product->value[$k] is going + // to always be 0 + + $carry = 0; + + for ($j = 0; $j < $x_length; ++$j) { // ie. $i = 0 + $temp = $x_value[$j] * $y_value[0] + $carry; // $product_value[$k] == 0 + $carry = (int) ($temp / MATH_BIGINTEGER_BASE_FULL); + $product_value[$j] = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * $carry); + } + + $product_value[$j] = $carry; + + // the above for loop is what the previous comment was talking about. the + // following for loop is the "one with nested for loops" + for ($i = 1; $i < $y_length; ++$i) { + $carry = 0; + + for ($j = 0, $k = $i; $j < $x_length; ++$j, ++$k) { + $temp = $product_value[$k] + $x_value[$j] * $y_value[$i] + $carry; + $carry = (int) ($temp / MATH_BIGINTEGER_BASE_FULL); + $product_value[$k] = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * $carry); + } + + $product_value[$k] = $carry; + } + + return $product_value; + } + + /** + * Performs Karatsuba multiplication on two BigIntegers + * + * See {@link http://en.wikipedia.org/wiki/Karatsuba_algorithm Karatsuba algorithm} and + * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=120 MPM 5.2.3}. + * + * @param Array $x_value + * @param Array $y_value + * @return Array + * @access private + */ + function _karatsuba($x_value, $y_value) + { + $m = min(count($x_value) >> 1, count($y_value) >> 1); + + if ($m < MATH_BIGINTEGER_KARATSUBA_CUTOFF) { + return $this->_regularMultiply($x_value, $y_value); + } + + $x1 = array_slice($x_value, $m); + $x0 = array_slice($x_value, 0, $m); + $y1 = array_slice($y_value, $m); + $y0 = array_slice($y_value, 0, $m); + + $z2 = $this->_karatsuba($x1, $y1); + $z0 = $this->_karatsuba($x0, $y0); + + $z1 = $this->_add($x1, false, $x0, false); + $temp = $this->_add($y1, false, $y0, false); + $z1 = $this->_karatsuba($z1[MATH_BIGINTEGER_VALUE], $temp[MATH_BIGINTEGER_VALUE]); + $temp = $this->_add($z2, false, $z0, false); + $z1 = $this->_subtract($z1, false, $temp[MATH_BIGINTEGER_VALUE], false); + + $z2 = array_merge(array_fill(0, 2 * $m, 0), $z2); + $z1[MATH_BIGINTEGER_VALUE] = array_merge(array_fill(0, $m, 0), $z1[MATH_BIGINTEGER_VALUE]); + + $xy = $this->_add($z2, false, $z1[MATH_BIGINTEGER_VALUE], $z1[MATH_BIGINTEGER_SIGN]); + $xy = $this->_add($xy[MATH_BIGINTEGER_VALUE], $xy[MATH_BIGINTEGER_SIGN], $z0, false); + + return $xy[MATH_BIGINTEGER_VALUE]; + } + + /** + * Performs squaring + * + * @param Array $x + * @return Array + * @access private + */ + function _square($x = false) + { + return count($x) < 2 * MATH_BIGINTEGER_KARATSUBA_CUTOFF ? + $this->_trim($this->_baseSquare($x)) : + $this->_trim($this->_karatsubaSquare($x)); + } + + /** + * Performs traditional squaring on two BigIntegers + * + * Squaring can be done faster than multiplying a number by itself can be. See + * {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=7 HAC 14.2.4} / + * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=141 MPM 5.3} for more information. + * + * @param Array $value + * @return Array + * @access private + */ + function _baseSquare($value) + { + if ( empty($value) ) { + return array(); + } + $square_value = $this->_array_repeat(0, 2 * count($value)); + + for ($i = 0, $max_index = count($value) - 1; $i <= $max_index; ++$i) { + $i2 = $i << 1; + + $temp = $square_value[$i2] + $value[$i] * $value[$i]; + $carry = (int) ($temp / MATH_BIGINTEGER_BASE_FULL); + $square_value[$i2] = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * $carry); + + // note how we start from $i+1 instead of 0 as we do in multiplication. + for ($j = $i + 1, $k = $i2 + 1; $j <= $max_index; ++$j, ++$k) { + $temp = $square_value[$k] + 2 * $value[$j] * $value[$i] + $carry; + $carry = (int) ($temp / MATH_BIGINTEGER_BASE_FULL); + $square_value[$k] = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * $carry); + } + + // the following line can yield values larger 2**15. at this point, PHP should switch + // over to floats. + $square_value[$i + $max_index + 1] = $carry; + } + + return $square_value; + } + + /** + * Performs Karatsuba "squaring" on two BigIntegers + * + * See {@link http://en.wikipedia.org/wiki/Karatsuba_algorithm Karatsuba algorithm} and + * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=151 MPM 5.3.4}. + * + * @param Array $value + * @return Array + * @access private + */ + function _karatsubaSquare($value) + { + $m = count($value) >> 1; + + if ($m < MATH_BIGINTEGER_KARATSUBA_CUTOFF) { + return $this->_baseSquare($value); + } + + $x1 = array_slice($value, $m); + $x0 = array_slice($value, 0, $m); + + $z2 = $this->_karatsubaSquare($x1); + $z0 = $this->_karatsubaSquare($x0); + + $z1 = $this->_add($x1, false, $x0, false); + $z1 = $this->_karatsubaSquare($z1[MATH_BIGINTEGER_VALUE]); + $temp = $this->_add($z2, false, $z0, false); + $z1 = $this->_subtract($z1, false, $temp[MATH_BIGINTEGER_VALUE], false); + + $z2 = array_merge(array_fill(0, 2 * $m, 0), $z2); + $z1[MATH_BIGINTEGER_VALUE] = array_merge(array_fill(0, $m, 0), $z1[MATH_BIGINTEGER_VALUE]); + + $xx = $this->_add($z2, false, $z1[MATH_BIGINTEGER_VALUE], $z1[MATH_BIGINTEGER_SIGN]); + $xx = $this->_add($xx[MATH_BIGINTEGER_VALUE], $xx[MATH_BIGINTEGER_SIGN], $z0, false); + + return $xx[MATH_BIGINTEGER_VALUE]; + } + + /** + * Divides two BigIntegers. + * + * Returns an array whose first element contains the quotient and whose second element contains the + * "common residue". If the remainder would be positive, the "common residue" and the remainder are the + * same. If the remainder would be negative, the "common residue" is equal to the sum of the remainder + * and the divisor (basically, the "common residue" is the first positive modulo). + * + * Here's an example: + * + * divide($b); + * + * echo $quotient->toString(); // outputs 0 + * echo "\r\n"; + * echo $remainder->toString(); // outputs 10 + * ?> + * + * + * @param Math_BigInteger $y + * @return Array + * @access public + * @internal This function is based off of {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=9 HAC 14.20}. + */ + function divide($y) + { + switch ( MATH_BIGINTEGER_MODE ) { + case MATH_BIGINTEGER_MODE_GMP: + $quotient = new Math_BigInteger(); + $remainder = new Math_BigInteger(); + + list($quotient->value, $remainder->value) = gmp_div_qr($this->value, $y->value); + + if (gmp_sign($remainder->value) < 0) { + $remainder->value = gmp_add($remainder->value, gmp_abs($y->value)); + } + + return array($this->_normalize($quotient), $this->_normalize($remainder)); + case MATH_BIGINTEGER_MODE_BCMATH: + $quotient = new Math_BigInteger(); + $remainder = new Math_BigInteger(); + + $quotient->value = bcdiv($this->value, $y->value, 0); + $remainder->value = bcmod($this->value, $y->value); + + if ($remainder->value[0] == '-') { + $remainder->value = bcadd($remainder->value, $y->value[0] == '-' ? substr($y->value, 1) : $y->value, 0); + } + + return array($this->_normalize($quotient), $this->_normalize($remainder)); + } + + if (count($y->value) == 1) { + list($q, $r) = $this->_divide_digit($this->value, $y->value[0]); + $quotient = new Math_BigInteger(); + $remainder = new Math_BigInteger(); + $quotient->value = $q; + $remainder->value = array($r); + $quotient->is_negative = $this->is_negative != $y->is_negative; + return array($this->_normalize($quotient), $this->_normalize($remainder)); + } + + static $zero; + if ( !isset($zero) ) { + $zero = new Math_BigInteger(); + } + + $x = $this->copy(); + $y = $y->copy(); + + $x_sign = $x->is_negative; + $y_sign = $y->is_negative; + + $x->is_negative = $y->is_negative = false; + + $diff = $x->compare($y); + + if ( !$diff ) { + $temp = new Math_BigInteger(); + $temp->value = array(1); + $temp->is_negative = $x_sign != $y_sign; + return array($this->_normalize($temp), $this->_normalize(new Math_BigInteger())); + } + + if ( $diff < 0 ) { + // if $x is negative, "add" $y. + if ( $x_sign ) { + $x = $y->subtract($x); + } + return array($this->_normalize(new Math_BigInteger()), $this->_normalize($x)); + } + + // normalize $x and $y as described in HAC 14.23 / 14.24 + $msb = $y->value[count($y->value) - 1]; + for ($shift = 0; !($msb & MATH_BIGINTEGER_MSB); ++$shift) { + $msb <<= 1; + } + $x->_lshift($shift); + $y->_lshift($shift); + $y_value = &$y->value; + + $x_max = count($x->value) - 1; + $y_max = count($y->value) - 1; + + $quotient = new Math_BigInteger(); + $quotient_value = &$quotient->value; + $quotient_value = $this->_array_repeat(0, $x_max - $y_max + 1); + + static $temp, $lhs, $rhs; + if (!isset($temp)) { + $temp = new Math_BigInteger(); + $lhs = new Math_BigInteger(); + $rhs = new Math_BigInteger(); + } + $temp_value = &$temp->value; + $rhs_value = &$rhs->value; + + // $temp = $y << ($x_max - $y_max-1) in base 2**26 + $temp_value = array_merge($this->_array_repeat(0, $x_max - $y_max), $y_value); + + while ( $x->compare($temp) >= 0 ) { + // calculate the "common residue" + ++$quotient_value[$x_max - $y_max]; + $x = $x->subtract($temp); + $x_max = count($x->value) - 1; + } + + for ($i = $x_max; $i >= $y_max + 1; --$i) { + $x_value = &$x->value; + $x_window = array( + isset($x_value[$i]) ? $x_value[$i] : 0, + isset($x_value[$i - 1]) ? $x_value[$i - 1] : 0, + isset($x_value[$i - 2]) ? $x_value[$i - 2] : 0 + ); + $y_window = array( + $y_value[$y_max], + ( $y_max > 0 ) ? $y_value[$y_max - 1] : 0 + ); + + $q_index = $i - $y_max - 1; + if ($x_window[0] == $y_window[0]) { + $quotient_value[$q_index] = MATH_BIGINTEGER_MAX_DIGIT; + } else { + $quotient_value[$q_index] = (int) ( + ($x_window[0] * MATH_BIGINTEGER_BASE_FULL + $x_window[1]) + / + $y_window[0] + ); + } + + $temp_value = array($y_window[1], $y_window[0]); + + $lhs->value = array($quotient_value[$q_index]); + $lhs = $lhs->multiply($temp); + + $rhs_value = array($x_window[2], $x_window[1], $x_window[0]); + + while ( $lhs->compare($rhs) > 0 ) { + --$quotient_value[$q_index]; + + $lhs->value = array($quotient_value[$q_index]); + $lhs = $lhs->multiply($temp); + } + + $adjust = $this->_array_repeat(0, $q_index); + $temp_value = array($quotient_value[$q_index]); + $temp = $temp->multiply($y); + $temp_value = &$temp->value; + $temp_value = array_merge($adjust, $temp_value); + + $x = $x->subtract($temp); + + if ($x->compare($zero) < 0) { + $temp_value = array_merge($adjust, $y_value); + $x = $x->add($temp); + + --$quotient_value[$q_index]; + } + + $x_max = count($x_value) - 1; + } + + // unnormalize the remainder + $x->_rshift($shift); + + $quotient->is_negative = $x_sign != $y_sign; + + // calculate the "common residue", if appropriate + if ( $x_sign ) { + $y->_rshift($shift); + $x = $y->subtract($x); + } + + return array($this->_normalize($quotient), $this->_normalize($x)); + } + + /** + * Divides a BigInteger by a regular integer + * + * abc / x = a00 / x + b0 / x + c / x + * + * @param Array $dividend + * @param Array $divisor + * @return Array + * @access private + */ + function _divide_digit($dividend, $divisor) + { + $carry = 0; + $result = array(); + + for ($i = count($dividend) - 1; $i >= 0; --$i) { + $temp = MATH_BIGINTEGER_BASE_FULL * $carry + $dividend[$i]; + $result[$i] = (int) ($temp / $divisor); + $carry = (int) ($temp - $divisor * $result[$i]); + } + + return array($result, $carry); + } + + /** + * Performs modular exponentiation. + * + * Here's an example: + * + * modPow($b, $c); + * + * echo $c->toString(); // outputs 10 + * ?> + * + * + * @param Math_BigInteger $e + * @param Math_BigInteger $n + * @return Math_BigInteger + * @access public + * @internal The most naive approach to modular exponentiation has very unreasonable requirements, and + * and although the approach involving repeated squaring does vastly better, it, too, is impractical + * for our purposes. The reason being that division - by far the most complicated and time-consuming + * of the basic operations (eg. +,-,*,/) - occurs multiple times within it. + * + * Modular reductions resolve this issue. Although an individual modular reduction takes more time + * then an individual division, when performed in succession (with the same modulo), they're a lot faster. + * + * The two most commonly used modular reductions are Barrett and Montgomery reduction. Montgomery reduction, + * although faster, only works when the gcd of the modulo and of the base being used is 1. In RSA, when the + * base is a power of two, the modulo - a product of two primes - is always going to have a gcd of 1 (because + * the product of two odd numbers is odd), but what about when RSA isn't used? + * + * In contrast, Barrett reduction has no such constraint. As such, some bigint implementations perform a + * Barrett reduction after every operation in the modpow function. Others perform Barrett reductions when the + * modulo is even and Montgomery reductions when the modulo is odd. BigInteger.java's modPow method, however, + * uses a trick involving the Chinese Remainder Theorem to factor the even modulo into two numbers - one odd and + * the other, a power of two - and recombine them, later. This is the method that this modPow function uses. + * {@link http://islab.oregonstate.edu/papers/j34monex.pdf Montgomery Reduction with Even Modulus} elaborates. + */ + function modPow($e, $n) + { + $n = $this->bitmask !== false && $this->bitmask->compare($n) < 0 ? $this->bitmask : $n->abs(); + + if ($e->compare(new Math_BigInteger()) < 0) { + $e = $e->abs(); + + $temp = $this->modInverse($n); + if ($temp === false) { + return false; + } + + return $this->_normalize($temp->modPow($e, $n)); + } + + if ( MATH_BIGINTEGER_MODE == MATH_BIGINTEGER_MODE_GMP ) { + $temp = new Math_BigInteger(); + $temp->value = gmp_powm($this->value, $e->value, $n->value); + + return $this->_normalize($temp); + } + + if ($this->compare(new Math_BigInteger()) < 0 || $this->compare($n) > 0) { + list(, $temp) = $this->divide($n); + return $temp->modPow($e, $n); + } + + if (defined('MATH_BIGINTEGER_OPENSSL_ENABLED')) { + $components = array( + 'modulus' => $n->toBytes(true), + 'publicExponent' => $e->toBytes(true) + ); + + $components = array( + 'modulus' => pack('Ca*a*', 2, $this->_encodeASN1Length(strlen($components['modulus'])), $components['modulus']), + 'publicExponent' => pack('Ca*a*', 2, $this->_encodeASN1Length(strlen($components['publicExponent'])), $components['publicExponent']) + ); + + $RSAPublicKey = pack('Ca*a*a*', + 48, $this->_encodeASN1Length(strlen($components['modulus']) + strlen($components['publicExponent'])), + $components['modulus'], $components['publicExponent'] + ); + + $rsaOID = pack('H*', '300d06092a864886f70d0101010500'); // hex version of MA0GCSqGSIb3DQEBAQUA + $RSAPublicKey = chr(0) . $RSAPublicKey; + $RSAPublicKey = chr(3) . $this->_encodeASN1Length(strlen($RSAPublicKey)) . $RSAPublicKey; + + $encapsulated = pack('Ca*a*', + 48, $this->_encodeASN1Length(strlen($rsaOID . $RSAPublicKey)), $rsaOID . $RSAPublicKey + ); + + $RSAPublicKey = "-----BEGIN PUBLIC KEY-----\r\n" . + chunk_split(base64_encode($encapsulated)) . + '-----END PUBLIC KEY-----'; + + $plaintext = str_pad($this->toBytes(), strlen($n->toBytes(true)) - 1, "\0", STR_PAD_LEFT); + + if (openssl_public_encrypt($plaintext, $result, $RSAPublicKey, OPENSSL_NO_PADDING)) { + return new Math_BigInteger($result, 256); + } + } + + if ( MATH_BIGINTEGER_MODE == MATH_BIGINTEGER_MODE_BCMATH ) { + $temp = new Math_BigInteger(); + $temp->value = bcpowmod($this->value, $e->value, $n->value, 0); + + return $this->_normalize($temp); + } + + if ( empty($e->value) ) { + $temp = new Math_BigInteger(); + $temp->value = array(1); + return $this->_normalize($temp); + } + + if ( $e->value == array(1) ) { + list(, $temp) = $this->divide($n); + return $this->_normalize($temp); + } + + if ( $e->value == array(2) ) { + $temp = new Math_BigInteger(); + $temp->value = $this->_square($this->value); + list(, $temp) = $temp->divide($n); + return $this->_normalize($temp); + } + + return $this->_normalize($this->_slidingWindow($e, $n, MATH_BIGINTEGER_BARRETT)); + + // is the modulo odd? + if ( $n->value[0] & 1 ) { + return $this->_normalize($this->_slidingWindow($e, $n, MATH_BIGINTEGER_MONTGOMERY)); + } + // if it's not, it's even + + // find the lowest set bit (eg. the max pow of 2 that divides $n) + for ($i = 0; $i < count($n->value); ++$i) { + if ( $n->value[$i] ) { + $temp = decbin($n->value[$i]); + $j = strlen($temp) - strrpos($temp, '1') - 1; + $j+= 26 * $i; + break; + } + } + // at this point, 2^$j * $n/(2^$j) == $n + + $mod1 = $n->copy(); + $mod1->_rshift($j); + $mod2 = new Math_BigInteger(); + $mod2->value = array(1); + $mod2->_lshift($j); + + $part1 = ( $mod1->value != array(1) ) ? $this->_slidingWindow($e, $mod1, MATH_BIGINTEGER_MONTGOMERY) : new Math_BigInteger(); + $part2 = $this->_slidingWindow($e, $mod2, MATH_BIGINTEGER_POWEROF2); + + $y1 = $mod2->modInverse($mod1); + $y2 = $mod1->modInverse($mod2); + + $result = $part1->multiply($mod2); + $result = $result->multiply($y1); + + $temp = $part2->multiply($mod1); + $temp = $temp->multiply($y2); + + $result = $result->add($temp); + list(, $result) = $result->divide($n); + + return $this->_normalize($result); + } + + /** + * Performs modular exponentiation. + * + * Alias for Math_BigInteger::modPow() + * + * @param Math_BigInteger $e + * @param Math_BigInteger $n + * @return Math_BigInteger + * @access public + */ + function powMod($e, $n) + { + return $this->modPow($e, $n); + } + + /** + * Sliding Window k-ary Modular Exponentiation + * + * Based on {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=27 HAC 14.85} / + * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=210 MPM 7.7}. In a departure from those algorithims, + * however, this function performs a modular reduction after every multiplication and squaring operation. + * As such, this function has the same preconditions that the reductions being used do. + * + * @param Math_BigInteger $e + * @param Math_BigInteger $n + * @param Integer $mode + * @return Math_BigInteger + * @access private + */ + function _slidingWindow($e, $n, $mode) + { + static $window_ranges = array(7, 25, 81, 241, 673, 1793); // from BigInteger.java's oddModPow function + //static $window_ranges = array(0, 7, 36, 140, 450, 1303, 3529); // from MPM 7.3.1 + + $e_value = $e->value; + $e_length = count($e_value) - 1; + $e_bits = decbin($e_value[$e_length]); + for ($i = $e_length - 1; $i >= 0; --$i) { + $e_bits.= str_pad(decbin($e_value[$i]), MATH_BIGINTEGER_BASE, '0', STR_PAD_LEFT); + } + + $e_length = strlen($e_bits); + + // calculate the appropriate window size. + // $window_size == 3 if $window_ranges is between 25 and 81, for example. + for ($i = 0, $window_size = 1; $e_length > $window_ranges[$i] && $i < count($window_ranges); ++$window_size, ++$i); + + $n_value = $n->value; + + // precompute $this^0 through $this^$window_size + $powers = array(); + $powers[1] = $this->_prepareReduce($this->value, $n_value, $mode); + $powers[2] = $this->_squareReduce($powers[1], $n_value, $mode); + + // we do every other number since substr($e_bits, $i, $j+1) (see below) is supposed to end + // in a 1. ie. it's supposed to be odd. + $temp = 1 << ($window_size - 1); + for ($i = 1; $i < $temp; ++$i) { + $i2 = $i << 1; + $powers[$i2 + 1] = $this->_multiplyReduce($powers[$i2 - 1], $powers[2], $n_value, $mode); + } + + $result = array(1); + $result = $this->_prepareReduce($result, $n_value, $mode); + + for ($i = 0; $i < $e_length; ) { + if ( !$e_bits[$i] ) { + $result = $this->_squareReduce($result, $n_value, $mode); + ++$i; + } else { + for ($j = $window_size - 1; $j > 0; --$j) { + if ( !empty($e_bits[$i + $j]) ) { + break; + } + } + + for ($k = 0; $k <= $j; ++$k) {// eg. the length of substr($e_bits, $i, $j+1) + $result = $this->_squareReduce($result, $n_value, $mode); + } + + $result = $this->_multiplyReduce($result, $powers[bindec(substr($e_bits, $i, $j + 1))], $n_value, $mode); + + $i+=$j + 1; + } + } + + $temp = new Math_BigInteger(); + $temp->value = $this->_reduce($result, $n_value, $mode); + + return $temp; + } + + /** + * Modular reduction + * + * For most $modes this will return the remainder. + * + * @see _slidingWindow() + * @access private + * @param Array $x + * @param Array $n + * @param Integer $mode + * @return Array + */ + function _reduce($x, $n, $mode) + { + switch ($mode) { + case MATH_BIGINTEGER_MONTGOMERY: + return $this->_montgomery($x, $n); + case MATH_BIGINTEGER_BARRETT: + return $this->_barrett($x, $n); + case MATH_BIGINTEGER_POWEROF2: + $lhs = new Math_BigInteger(); + $lhs->value = $x; + $rhs = new Math_BigInteger(); + $rhs->value = $n; + return $x->_mod2($n); + case MATH_BIGINTEGER_CLASSIC: + $lhs = new Math_BigInteger(); + $lhs->value = $x; + $rhs = new Math_BigInteger(); + $rhs->value = $n; + list(, $temp) = $lhs->divide($rhs); + return $temp->value; + case MATH_BIGINTEGER_NONE: + return $x; + default: + // an invalid $mode was provided + } + } + + /** + * Modular reduction preperation + * + * @see _slidingWindow() + * @access private + * @param Array $x + * @param Array $n + * @param Integer $mode + * @return Array + */ + function _prepareReduce($x, $n, $mode) + { + if ($mode == MATH_BIGINTEGER_MONTGOMERY) { + return $this->_prepMontgomery($x, $n); + } + return $this->_reduce($x, $n, $mode); + } + + /** + * Modular multiply + * + * @see _slidingWindow() + * @access private + * @param Array $x + * @param Array $y + * @param Array $n + * @param Integer $mode + * @return Array + */ + function _multiplyReduce($x, $y, $n, $mode) + { + if ($mode == MATH_BIGINTEGER_MONTGOMERY) { + return $this->_montgomeryMultiply($x, $y, $n); + } + $temp = $this->_multiply($x, false, $y, false); + return $this->_reduce($temp[MATH_BIGINTEGER_VALUE], $n, $mode); + } + + /** + * Modular square + * + * @see _slidingWindow() + * @access private + * @param Array $x + * @param Array $n + * @param Integer $mode + * @return Array + */ + function _squareReduce($x, $n, $mode) + { + if ($mode == MATH_BIGINTEGER_MONTGOMERY) { + return $this->_montgomeryMultiply($x, $x, $n); + } + return $this->_reduce($this->_square($x), $n, $mode); + } + + /** + * Modulos for Powers of Two + * + * Calculates $x%$n, where $n = 2**$e, for some $e. Since this is basically the same as doing $x & ($n-1), + * we'll just use this function as a wrapper for doing that. + * + * @see _slidingWindow() + * @access private + * @param Math_BigInteger + * @return Math_BigInteger + */ + function _mod2($n) + { + $temp = new Math_BigInteger(); + $temp->value = array(1); + return $this->bitwise_and($n->subtract($temp)); + } + + /** + * Barrett Modular Reduction + * + * See {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=14 HAC 14.3.3} / + * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=165 MPM 6.2.5} for more information. Modified slightly, + * so as not to require negative numbers (initially, this script didn't support negative numbers). + * + * Employs "folding", as described at + * {@link http://www.cosic.esat.kuleuven.be/publications/thesis-149.pdf#page=66 thesis-149.pdf#page=66}. To quote from + * it, "the idea [behind folding] is to find a value x' such that x (mod m) = x' (mod m), with x' being smaller than x." + * + * Unfortunately, the "Barrett Reduction with Folding" algorithm described in thesis-149.pdf is not, as written, all that + * usable on account of (1) its not using reasonable radix points as discussed in + * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=162 MPM 6.2.2} and (2) the fact that, even with reasonable + * radix points, it only works when there are an even number of digits in the denominator. The reason for (2) is that + * (x >> 1) + (x >> 1) != x / 2 + x / 2. If x is even, they're the same, but if x is odd, they're not. See the in-line + * comments for details. + * + * @see _slidingWindow() + * @access private + * @param Array $n + * @param Array $m + * @return Array + */ + function _barrett($n, $m) + { + static $cache = array( + MATH_BIGINTEGER_VARIABLE => array(), + MATH_BIGINTEGER_DATA => array() + ); + + $m_length = count($m); + + // if ($this->_compare($n, $this->_square($m)) >= 0) { + if (count($n) > 2 * $m_length) { + $lhs = new Math_BigInteger(); + $rhs = new Math_BigInteger(); + $lhs->value = $n; + $rhs->value = $m; + list(, $temp) = $lhs->divide($rhs); + return $temp->value; + } + + // if (m.length >> 1) + 2 <= m.length then m is too small and n can't be reduced + if ($m_length < 5) { + return $this->_regularBarrett($n, $m); + } + + // n = 2 * m.length + + if ( ($key = array_search($m, $cache[MATH_BIGINTEGER_VARIABLE])) === false ) { + $key = count($cache[MATH_BIGINTEGER_VARIABLE]); + $cache[MATH_BIGINTEGER_VARIABLE][] = $m; + + $lhs = new Math_BigInteger(); + $lhs_value = &$lhs->value; + $lhs_value = $this->_array_repeat(0, $m_length + ($m_length >> 1)); + $lhs_value[] = 1; + $rhs = new Math_BigInteger(); + $rhs->value = $m; + + list($u, $m1) = $lhs->divide($rhs); + $u = $u->value; + $m1 = $m1->value; + + $cache[MATH_BIGINTEGER_DATA][] = array( + 'u' => $u, // m.length >> 1 (technically (m.length >> 1) + 1) + 'm1'=> $m1 // m.length + ); + } else { + extract($cache[MATH_BIGINTEGER_DATA][$key]); + } + + $cutoff = $m_length + ($m_length >> 1); + $lsd = array_slice($n, 0, $cutoff); // m.length + (m.length >> 1) + $msd = array_slice($n, $cutoff); // m.length >> 1 + $lsd = $this->_trim($lsd); + $temp = $this->_multiply($msd, false, $m1, false); + $n = $this->_add($lsd, false, $temp[MATH_BIGINTEGER_VALUE], false); // m.length + (m.length >> 1) + 1 + + if ($m_length & 1) { + return $this->_regularBarrett($n[MATH_BIGINTEGER_VALUE], $m); + } + + // (m.length + (m.length >> 1) + 1) - (m.length - 1) == (m.length >> 1) + 2 + $temp = array_slice($n[MATH_BIGINTEGER_VALUE], $m_length - 1); + // if even: ((m.length >> 1) + 2) + (m.length >> 1) == m.length + 2 + // if odd: ((m.length >> 1) + 2) + (m.length >> 1) == (m.length - 1) + 2 == m.length + 1 + $temp = $this->_multiply($temp, false, $u, false); + // if even: (m.length + 2) - ((m.length >> 1) + 1) = m.length - (m.length >> 1) + 1 + // if odd: (m.length + 1) - ((m.length >> 1) + 1) = m.length - (m.length >> 1) + $temp = array_slice($temp[MATH_BIGINTEGER_VALUE], ($m_length >> 1) + 1); + // if even: (m.length - (m.length >> 1) + 1) + m.length = 2 * m.length - (m.length >> 1) + 1 + // if odd: (m.length - (m.length >> 1)) + m.length = 2 * m.length - (m.length >> 1) + $temp = $this->_multiply($temp, false, $m, false); + + // at this point, if m had an odd number of digits, we'd be subtracting a 2 * m.length - (m.length >> 1) digit + // number from a m.length + (m.length >> 1) + 1 digit number. ie. there'd be an extra digit and the while loop + // following this comment would loop a lot (hence our calling _regularBarrett() in that situation). + + $result = $this->_subtract($n[MATH_BIGINTEGER_VALUE], false, $temp[MATH_BIGINTEGER_VALUE], false); + + while ($this->_compare($result[MATH_BIGINTEGER_VALUE], $result[MATH_BIGINTEGER_SIGN], $m, false) >= 0) { + $result = $this->_subtract($result[MATH_BIGINTEGER_VALUE], $result[MATH_BIGINTEGER_SIGN], $m, false); + } + + return $result[MATH_BIGINTEGER_VALUE]; + } + + /** + * (Regular) Barrett Modular Reduction + * + * For numbers with more than four digits Math_BigInteger::_barrett() is faster. The difference between that and this + * is that this function does not fold the denominator into a smaller form. + * + * @see _slidingWindow() + * @access private + * @param Array $x + * @param Array $n + * @return Array + */ + function _regularBarrett($x, $n) + { + static $cache = array( + MATH_BIGINTEGER_VARIABLE => array(), + MATH_BIGINTEGER_DATA => array() + ); + + $n_length = count($n); + + if (count($x) > 2 * $n_length) { + $lhs = new Math_BigInteger(); + $rhs = new Math_BigInteger(); + $lhs->value = $x; + $rhs->value = $n; + list(, $temp) = $lhs->divide($rhs); + return $temp->value; + } + + if ( ($key = array_search($n, $cache[MATH_BIGINTEGER_VARIABLE])) === false ) { + $key = count($cache[MATH_BIGINTEGER_VARIABLE]); + $cache[MATH_BIGINTEGER_VARIABLE][] = $n; + $lhs = new Math_BigInteger(); + $lhs_value = &$lhs->value; + $lhs_value = $this->_array_repeat(0, 2 * $n_length); + $lhs_value[] = 1; + $rhs = new Math_BigInteger(); + $rhs->value = $n; + list($temp, ) = $lhs->divide($rhs); // m.length + $cache[MATH_BIGINTEGER_DATA][] = $temp->value; + } + + // 2 * m.length - (m.length - 1) = m.length + 1 + $temp = array_slice($x, $n_length - 1); + // (m.length + 1) + m.length = 2 * m.length + 1 + $temp = $this->_multiply($temp, false, $cache[MATH_BIGINTEGER_DATA][$key], false); + // (2 * m.length + 1) - (m.length - 1) = m.length + 2 + $temp = array_slice($temp[MATH_BIGINTEGER_VALUE], $n_length + 1); + + // m.length + 1 + $result = array_slice($x, 0, $n_length + 1); + // m.length + 1 + $temp = $this->_multiplyLower($temp, false, $n, false, $n_length + 1); + // $temp == array_slice($temp->_multiply($temp, false, $n, false)->value, 0, $n_length + 1) + + if ($this->_compare($result, false, $temp[MATH_BIGINTEGER_VALUE], $temp[MATH_BIGINTEGER_SIGN]) < 0) { + $corrector_value = $this->_array_repeat(0, $n_length + 1); + $corrector_value[] = 1; + $result = $this->_add($result, false, $corrector_value, false); + $result = $result[MATH_BIGINTEGER_VALUE]; + } + + // at this point, we're subtracting a number with m.length + 1 digits from another number with m.length + 1 digits + $result = $this->_subtract($result, false, $temp[MATH_BIGINTEGER_VALUE], $temp[MATH_BIGINTEGER_SIGN]); + while ($this->_compare($result[MATH_BIGINTEGER_VALUE], $result[MATH_BIGINTEGER_SIGN], $n, false) > 0) { + $result = $this->_subtract($result[MATH_BIGINTEGER_VALUE], $result[MATH_BIGINTEGER_SIGN], $n, false); + } + + return $result[MATH_BIGINTEGER_VALUE]; + } + + /** + * Performs long multiplication up to $stop digits + * + * If you're going to be doing array_slice($product->value, 0, $stop), some cycles can be saved. + * + * @see _regularBarrett() + * @param Array $x_value + * @param Boolean $x_negative + * @param Array $y_value + * @param Boolean $y_negative + * @param Integer $stop + * @return Array + * @access private + */ + function _multiplyLower($x_value, $x_negative, $y_value, $y_negative, $stop) + { + $x_length = count($x_value); + $y_length = count($y_value); + + if ( !$x_length || !$y_length ) { // a 0 is being multiplied + return array( + MATH_BIGINTEGER_VALUE => array(), + MATH_BIGINTEGER_SIGN => false + ); + } + + if ( $x_length < $y_length ) { + $temp = $x_value; + $x_value = $y_value; + $y_value = $temp; + + $x_length = count($x_value); + $y_length = count($y_value); + } + + $product_value = $this->_array_repeat(0, $x_length + $y_length); + + // the following for loop could be removed if the for loop following it + // (the one with nested for loops) initially set $i to 0, but + // doing so would also make the result in one set of unnecessary adds, + // since on the outermost loops first pass, $product->value[$k] is going + // to always be 0 + + $carry = 0; + + for ($j = 0; $j < $x_length; ++$j) { // ie. $i = 0, $k = $i + $temp = $x_value[$j] * $y_value[0] + $carry; // $product_value[$k] == 0 + $carry = (int) ($temp / MATH_BIGINTEGER_BASE_FULL); + $product_value[$j] = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * $carry); + } + + if ($j < $stop) { + $product_value[$j] = $carry; + } + + // the above for loop is what the previous comment was talking about. the + // following for loop is the "one with nested for loops" + + for ($i = 1; $i < $y_length; ++$i) { + $carry = 0; + + for ($j = 0, $k = $i; $j < $x_length && $k < $stop; ++$j, ++$k) { + $temp = $product_value[$k] + $x_value[$j] * $y_value[$i] + $carry; + $carry = (int) ($temp / MATH_BIGINTEGER_BASE_FULL); + $product_value[$k] = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * $carry); + } + + if ($k < $stop) { + $product_value[$k] = $carry; + } + } + + return array( + MATH_BIGINTEGER_VALUE => $this->_trim($product_value), + MATH_BIGINTEGER_SIGN => $x_negative != $y_negative + ); + } + + /** + * Montgomery Modular Reduction + * + * ($x->_prepMontgomery($n))->_montgomery($n) yields $x % $n. + * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=170 MPM 6.3} provides insights on how this can be + * improved upon (basically, by using the comba method). gcd($n, 2) must be equal to one for this function + * to work correctly. + * + * @see _prepMontgomery() + * @see _slidingWindow() + * @access private + * @param Array $x + * @param Array $n + * @return Array + */ + function _montgomery($x, $n) + { + static $cache = array( + MATH_BIGINTEGER_VARIABLE => array(), + MATH_BIGINTEGER_DATA => array() + ); + + if ( ($key = array_search($n, $cache[MATH_BIGINTEGER_VARIABLE])) === false ) { + $key = count($cache[MATH_BIGINTEGER_VARIABLE]); + $cache[MATH_BIGINTEGER_VARIABLE][] = $x; + $cache[MATH_BIGINTEGER_DATA][] = $this->_modInverse67108864($n); + } + + $k = count($n); + + $result = array(MATH_BIGINTEGER_VALUE => $x); + + for ($i = 0; $i < $k; ++$i) { + $temp = $result[MATH_BIGINTEGER_VALUE][$i] * $cache[MATH_BIGINTEGER_DATA][$key]; + $temp = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * ((int) ($temp / MATH_BIGINTEGER_BASE_FULL))); + $temp = $this->_regularMultiply(array($temp), $n); + $temp = array_merge($this->_array_repeat(0, $i), $temp); + $result = $this->_add($result[MATH_BIGINTEGER_VALUE], false, $temp, false); + } + + $result[MATH_BIGINTEGER_VALUE] = array_slice($result[MATH_BIGINTEGER_VALUE], $k); + + if ($this->_compare($result, false, $n, false) >= 0) { + $result = $this->_subtract($result[MATH_BIGINTEGER_VALUE], false, $n, false); + } + + return $result[MATH_BIGINTEGER_VALUE]; + } + + /** + * Montgomery Multiply + * + * Interleaves the montgomery reduction and long multiplication algorithms together as described in + * {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=13 HAC 14.36} + * + * @see _prepMontgomery() + * @see _montgomery() + * @access private + * @param Array $x + * @param Array $y + * @param Array $m + * @return Array + */ + function _montgomeryMultiply($x, $y, $m) + { + $temp = $this->_multiply($x, false, $y, false); + return $this->_montgomery($temp[MATH_BIGINTEGER_VALUE], $m); + + static $cache = array( + MATH_BIGINTEGER_VARIABLE => array(), + MATH_BIGINTEGER_DATA => array() + ); + + if ( ($key = array_search($m, $cache[MATH_BIGINTEGER_VARIABLE])) === false ) { + $key = count($cache[MATH_BIGINTEGER_VARIABLE]); + $cache[MATH_BIGINTEGER_VARIABLE][] = $m; + $cache[MATH_BIGINTEGER_DATA][] = $this->_modInverse67108864($m); + } + + $n = max(count($x), count($y), count($m)); + $x = array_pad($x, $n, 0); + $y = array_pad($y, $n, 0); + $m = array_pad($m, $n, 0); + $a = array(MATH_BIGINTEGER_VALUE => $this->_array_repeat(0, $n + 1)); + for ($i = 0; $i < $n; ++$i) { + $temp = $a[MATH_BIGINTEGER_VALUE][0] + $x[$i] * $y[0]; + $temp = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * ((int) ($temp / MATH_BIGINTEGER_BASE_FULL))); + $temp = $temp * $cache[MATH_BIGINTEGER_DATA][$key]; + $temp = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * ((int) ($temp / MATH_BIGINTEGER_BASE_FULL))); + $temp = $this->_add($this->_regularMultiply(array($x[$i]), $y), false, $this->_regularMultiply(array($temp), $m), false); + $a = $this->_add($a[MATH_BIGINTEGER_VALUE], false, $temp[MATH_BIGINTEGER_VALUE], false); + $a[MATH_BIGINTEGER_VALUE] = array_slice($a[MATH_BIGINTEGER_VALUE], 1); + } + if ($this->_compare($a[MATH_BIGINTEGER_VALUE], false, $m, false) >= 0) { + $a = $this->_subtract($a[MATH_BIGINTEGER_VALUE], false, $m, false); + } + return $a[MATH_BIGINTEGER_VALUE]; + } + + /** + * Prepare a number for use in Montgomery Modular Reductions + * + * @see _montgomery() + * @see _slidingWindow() + * @access private + * @param Array $x + * @param Array $n + * @return Array + */ + function _prepMontgomery($x, $n) + { + $lhs = new Math_BigInteger(); + $lhs->value = array_merge($this->_array_repeat(0, count($n)), $x); + $rhs = new Math_BigInteger(); + $rhs->value = $n; + + list(, $temp) = $lhs->divide($rhs); + return $temp->value; + } + + /** + * Modular Inverse of a number mod 2**26 (eg. 67108864) + * + * Based off of the bnpInvDigit function implemented and justified in the following URL: + * + * {@link http://www-cs-students.stanford.edu/~tjw/jsbn/jsbn.js} + * + * The following URL provides more info: + * + * {@link http://groups.google.com/group/sci.crypt/msg/7a137205c1be7d85} + * + * As for why we do all the bitmasking... strange things can happen when converting from floats to ints. For + * instance, on some computers, var_dump((int) -4294967297) yields int(-1) and on others, it yields + * int(-2147483648). To avoid problems stemming from this, we use bitmasks to guarantee that ints aren't + * auto-converted to floats. The outermost bitmask is present because without it, there's no guarantee that + * the "residue" returned would be the so-called "common residue". We use fmod, in the last step, because the + * maximum possible $x is 26 bits and the maximum $result is 16 bits. Thus, we have to be able to handle up to + * 40 bits, which only 64-bit floating points will support. + * + * Thanks to Pedro Gimeno Fortea for input! + * + * @see _montgomery() + * @access private + * @param Array $x + * @return Integer + */ + function _modInverse67108864($x) // 2**26 == 67,108,864 + { + $x = -$x[0]; + $result = $x & 0x3; // x**-1 mod 2**2 + $result = ($result * (2 - $x * $result)) & 0xF; // x**-1 mod 2**4 + $result = ($result * (2 - ($x & 0xFF) * $result)) & 0xFF; // x**-1 mod 2**8 + $result = ($result * ((2 - ($x & 0xFFFF) * $result) & 0xFFFF)) & 0xFFFF; // x**-1 mod 2**16 + $result = fmod($result * (2 - fmod($x * $result, MATH_BIGINTEGER_BASE_FULL)), MATH_BIGINTEGER_BASE_FULL); // x**-1 mod 2**26 + return $result & MATH_BIGINTEGER_MAX_DIGIT; + } + + /** + * Calculates modular inverses. + * + * Say you have (30 mod 17 * x mod 17) mod 17 == 1. x can be found using modular inverses. + * + * Here's an example: + * + * modInverse($b); + * echo $c->toString(); // outputs 4 + * + * echo "\r\n"; + * + * $d = $a->multiply($c); + * list(, $d) = $d->divide($b); + * echo $d; // outputs 1 (as per the definition of modular inverse) + * ?> + * + * + * @param Math_BigInteger $n + * @return mixed false, if no modular inverse exists, Math_BigInteger, otherwise. + * @access public + * @internal See {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=21 HAC 14.64} for more information. + */ + function modInverse($n) + { + switch ( MATH_BIGINTEGER_MODE ) { + case MATH_BIGINTEGER_MODE_GMP: + $temp = new Math_BigInteger(); + $temp->value = gmp_invert($this->value, $n->value); + + return ( $temp->value === false ) ? false : $this->_normalize($temp); + } + + static $zero, $one; + if (!isset($zero)) { + $zero = new Math_BigInteger(); + $one = new Math_BigInteger(1); + } + + // $x mod -$n == $x mod $n. + $n = $n->abs(); + + if ($this->compare($zero) < 0) { + $temp = $this->abs(); + $temp = $temp->modInverse($n); + return $this->_normalize($n->subtract($temp)); + } + + extract($this->extendedGCD($n)); + + if (!$gcd->equals($one)) { + return false; + } + + $x = $x->compare($zero) < 0 ? $x->add($n) : $x; + + return $this->compare($zero) < 0 ? $this->_normalize($n->subtract($x)) : $this->_normalize($x); + } + + /** + * Calculates the greatest common divisor and Bezout's identity. + * + * Say you have 693 and 609. The GCD is 21. Bezout's identity states that there exist integers x and y such that + * 693*x + 609*y == 21. In point of fact, there are actually an infinite number of x and y combinations and which + * combination is returned is dependant upon which mode is in use. See + * {@link http://en.wikipedia.org/wiki/B%C3%A9zout%27s_identity Bezout's identity - Wikipedia} for more information. + * + * Here's an example: + * + * extendedGCD($b)); + * + * echo $gcd->toString() . "\r\n"; // outputs 21 + * echo $a->toString() * $x->toString() + $b->toString() * $y->toString(); // outputs 21 + * ?> + * + * + * @param Math_BigInteger $n + * @return Math_BigInteger + * @access public + * @internal Calculates the GCD using the binary xGCD algorithim described in + * {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=19 HAC 14.61}. As the text above 14.61 notes, + * the more traditional algorithim requires "relatively costly multiple-precision divisions". + */ + function extendedGCD($n) + { + switch ( MATH_BIGINTEGER_MODE ) { + case MATH_BIGINTEGER_MODE_GMP: + extract(gmp_gcdext($this->value, $n->value)); + + return array( + 'gcd' => $this->_normalize(new Math_BigInteger($g)), + 'x' => $this->_normalize(new Math_BigInteger($s)), + 'y' => $this->_normalize(new Math_BigInteger($t)) + ); + case MATH_BIGINTEGER_MODE_BCMATH: + // it might be faster to use the binary xGCD algorithim here, as well, but (1) that algorithim works + // best when the base is a power of 2 and (2) i don't think it'd make much difference, anyway. as is, + // the basic extended euclidean algorithim is what we're using. + + $u = $this->value; + $v = $n->value; + + $a = '1'; + $b = '0'; + $c = '0'; + $d = '1'; + + while (bccomp($v, '0', 0) != 0) { + $q = bcdiv($u, $v, 0); + + $temp = $u; + $u = $v; + $v = bcsub($temp, bcmul($v, $q, 0), 0); + + $temp = $a; + $a = $c; + $c = bcsub($temp, bcmul($a, $q, 0), 0); + + $temp = $b; + $b = $d; + $d = bcsub($temp, bcmul($b, $q, 0), 0); + } + + return array( + 'gcd' => $this->_normalize(new Math_BigInteger($u)), + 'x' => $this->_normalize(new Math_BigInteger($a)), + 'y' => $this->_normalize(new Math_BigInteger($b)) + ); + } + + $y = $n->copy(); + $x = $this->copy(); + $g = new Math_BigInteger(); + $g->value = array(1); + + while ( !(($x->value[0] & 1)|| ($y->value[0] & 1)) ) { + $x->_rshift(1); + $y->_rshift(1); + $g->_lshift(1); + } + + $u = $x->copy(); + $v = $y->copy(); + + $a = new Math_BigInteger(); + $b = new Math_BigInteger(); + $c = new Math_BigInteger(); + $d = new Math_BigInteger(); + + $a->value = $d->value = $g->value = array(1); + $b->value = $c->value = array(); + + while ( !empty($u->value) ) { + while ( !($u->value[0] & 1) ) { + $u->_rshift(1); + if ( (!empty($a->value) && ($a->value[0] & 1)) || (!empty($b->value) && ($b->value[0] & 1)) ) { + $a = $a->add($y); + $b = $b->subtract($x); + } + $a->_rshift(1); + $b->_rshift(1); + } + + while ( !($v->value[0] & 1) ) { + $v->_rshift(1); + if ( (!empty($d->value) && ($d->value[0] & 1)) || (!empty($c->value) && ($c->value[0] & 1)) ) { + $c = $c->add($y); + $d = $d->subtract($x); + } + $c->_rshift(1); + $d->_rshift(1); + } + + if ($u->compare($v) >= 0) { + $u = $u->subtract($v); + $a = $a->subtract($c); + $b = $b->subtract($d); + } else { + $v = $v->subtract($u); + $c = $c->subtract($a); + $d = $d->subtract($b); + } + } + + return array( + 'gcd' => $this->_normalize($g->multiply($v)), + 'x' => $this->_normalize($c), + 'y' => $this->_normalize($d) + ); + } + + /** + * Calculates the greatest common divisor + * + * Say you have 693 and 609. The GCD is 21. + * + * Here's an example: + * + * extendedGCD($b); + * + * echo $gcd->toString() . "\r\n"; // outputs 21 + * ?> + * + * + * @param Math_BigInteger $n + * @return Math_BigInteger + * @access public + */ + function gcd($n) + { + extract($this->extendedGCD($n)); + return $gcd; + } + + /** + * Absolute value. + * + * @return Math_BigInteger + * @access public + */ + function abs() + { + $temp = new Math_BigInteger(); + + switch ( MATH_BIGINTEGER_MODE ) { + case MATH_BIGINTEGER_MODE_GMP: + $temp->value = gmp_abs($this->value); + break; + case MATH_BIGINTEGER_MODE_BCMATH: + $temp->value = (bccomp($this->value, '0', 0) < 0) ? substr($this->value, 1) : $this->value; + break; + default: + $temp->value = $this->value; + } + + return $temp; + } + + /** + * Compares two numbers. + * + * Although one might think !$x->compare($y) means $x != $y, it, in fact, means the opposite. The reason for this is + * demonstrated thusly: + * + * $x > $y: $x->compare($y) > 0 + * $x < $y: $x->compare($y) < 0 + * $x == $y: $x->compare($y) == 0 + * + * Note how the same comparison operator is used. If you want to test for equality, use $x->equals($y). + * + * @param Math_BigInteger $y + * @return Integer < 0 if $this is less than $y; > 0 if $this is greater than $y, and 0 if they are equal. + * @access public + * @see equals() + * @internal Could return $this->subtract($x), but that's not as fast as what we do do. + */ + function compare($y) + { + switch ( MATH_BIGINTEGER_MODE ) { + case MATH_BIGINTEGER_MODE_GMP: + return gmp_cmp($this->value, $y->value); + case MATH_BIGINTEGER_MODE_BCMATH: + return bccomp($this->value, $y->value, 0); + } + + return $this->_compare($this->value, $this->is_negative, $y->value, $y->is_negative); + } + + /** + * Compares two numbers. + * + * @param Array $x_value + * @param Boolean $x_negative + * @param Array $y_value + * @param Boolean $y_negative + * @return Integer + * @see compare() + * @access private + */ + function _compare($x_value, $x_negative, $y_value, $y_negative) + { + if ( $x_negative != $y_negative ) { + return ( !$x_negative && $y_negative ) ? 1 : -1; + } + + $result = $x_negative ? -1 : 1; + + if ( count($x_value) != count($y_value) ) { + return ( count($x_value) > count($y_value) ) ? $result : -$result; + } + $size = max(count($x_value), count($y_value)); + + $x_value = array_pad($x_value, $size, 0); + $y_value = array_pad($y_value, $size, 0); + + for ($i = count($x_value) - 1; $i >= 0; --$i) { + if ($x_value[$i] != $y_value[$i]) { + return ( $x_value[$i] > $y_value[$i] ) ? $result : -$result; + } + } + + return 0; + } + + /** + * Tests the equality of two numbers. + * + * If you need to see if one number is greater than or less than another number, use Math_BigInteger::compare() + * + * @param Math_BigInteger $x + * @return Boolean + * @access public + * @see compare() + */ + function equals($x) + { + switch ( MATH_BIGINTEGER_MODE ) { + case MATH_BIGINTEGER_MODE_GMP: + return gmp_cmp($this->value, $x->value) == 0; + default: + return $this->value === $x->value && $this->is_negative == $x->is_negative; + } + } + + /** + * Set Precision + * + * Some bitwise operations give different results depending on the precision being used. Examples include left + * shift, not, and rotates. + * + * @param Integer $bits + * @access public + */ + function setPrecision($bits) + { + $this->precision = $bits; + if ( MATH_BIGINTEGER_MODE != MATH_BIGINTEGER_MODE_BCMATH ) { + $this->bitmask = new Math_BigInteger(chr((1 << ($bits & 0x7)) - 1) . str_repeat(chr(0xFF), $bits >> 3), 256); + } else { + $this->bitmask = new Math_BigInteger(bcpow('2', $bits, 0)); + } + + $temp = $this->_normalize($this); + $this->value = $temp->value; + } + + /** + * Logical And + * + * @param Math_BigInteger $x + * @access public + * @internal Implemented per a request by Lluis Pamies i Juarez + * @return Math_BigInteger + */ + function bitwise_and($x) + { + switch ( MATH_BIGINTEGER_MODE ) { + case MATH_BIGINTEGER_MODE_GMP: + $temp = new Math_BigInteger(); + $temp->value = gmp_and($this->value, $x->value); + + return $this->_normalize($temp); + case MATH_BIGINTEGER_MODE_BCMATH: + $left = $this->toBytes(); + $right = $x->toBytes(); + + $length = max(strlen($left), strlen($right)); + + $left = str_pad($left, $length, chr(0), STR_PAD_LEFT); + $right = str_pad($right, $length, chr(0), STR_PAD_LEFT); + + return $this->_normalize(new Math_BigInteger($left & $right, 256)); + } + + $result = $this->copy(); + + $length = min(count($x->value), count($this->value)); + + $result->value = array_slice($result->value, 0, $length); + + for ($i = 0; $i < $length; ++$i) { + $result->value[$i]&= $x->value[$i]; + } + + return $this->_normalize($result); + } + + /** + * Logical Or + * + * @param Math_BigInteger $x + * @access public + * @internal Implemented per a request by Lluis Pamies i Juarez + * @return Math_BigInteger + */ + function bitwise_or($x) + { + switch ( MATH_BIGINTEGER_MODE ) { + case MATH_BIGINTEGER_MODE_GMP: + $temp = new Math_BigInteger(); + $temp->value = gmp_or($this->value, $x->value); + + return $this->_normalize($temp); + case MATH_BIGINTEGER_MODE_BCMATH: + $left = $this->toBytes(); + $right = $x->toBytes(); + + $length = max(strlen($left), strlen($right)); + + $left = str_pad($left, $length, chr(0), STR_PAD_LEFT); + $right = str_pad($right, $length, chr(0), STR_PAD_LEFT); + + return $this->_normalize(new Math_BigInteger($left | $right, 256)); + } + + $length = max(count($this->value), count($x->value)); + $result = $this->copy(); + $result->value = array_pad($result->value, $length, 0); + $x->value = array_pad($x->value, $length, 0); + + for ($i = 0; $i < $length; ++$i) { + $result->value[$i]|= $x->value[$i]; + } + + return $this->_normalize($result); + } + + /** + * Logical Exclusive-Or + * + * @param Math_BigInteger $x + * @access public + * @internal Implemented per a request by Lluis Pamies i Juarez + * @return Math_BigInteger + */ + function bitwise_xor($x) + { + switch ( MATH_BIGINTEGER_MODE ) { + case MATH_BIGINTEGER_MODE_GMP: + $temp = new Math_BigInteger(); + $temp->value = gmp_xor($this->value, $x->value); + + return $this->_normalize($temp); + case MATH_BIGINTEGER_MODE_BCMATH: + $left = $this->toBytes(); + $right = $x->toBytes(); + + $length = max(strlen($left), strlen($right)); + + $left = str_pad($left, $length, chr(0), STR_PAD_LEFT); + $right = str_pad($right, $length, chr(0), STR_PAD_LEFT); + + return $this->_normalize(new Math_BigInteger($left ^ $right, 256)); + } + + $length = max(count($this->value), count($x->value)); + $result = $this->copy(); + $result->value = array_pad($result->value, $length, 0); + $x->value = array_pad($x->value, $length, 0); + + for ($i = 0; $i < $length; ++$i) { + $result->value[$i]^= $x->value[$i]; + } + + return $this->_normalize($result); + } + + /** + * Logical Not + * + * @access public + * @internal Implemented per a request by Lluis Pamies i Juarez + * @return Math_BigInteger + */ + function bitwise_not() + { + // calculuate "not" without regard to $this->precision + // (will always result in a smaller number. ie. ~1 isn't 1111 1110 - it's 0) + $temp = $this->toBytes(); + $pre_msb = decbin(ord($temp[0])); + $temp = ~$temp; + $msb = decbin(ord($temp[0])); + if (strlen($msb) == 8) { + $msb = substr($msb, strpos($msb, '0')); + } + $temp[0] = chr(bindec($msb)); + + // see if we need to add extra leading 1's + $current_bits = strlen($pre_msb) + 8 * strlen($temp) - 8; + $new_bits = $this->precision - $current_bits; + if ($new_bits <= 0) { + return $this->_normalize(new Math_BigInteger($temp, 256)); + } + + // generate as many leading 1's as we need to. + $leading_ones = chr((1 << ($new_bits & 0x7)) - 1) . str_repeat(chr(0xFF), $new_bits >> 3); + $this->_base256_lshift($leading_ones, $current_bits); + + $temp = str_pad($temp, ceil($this->bits / 8), chr(0), STR_PAD_LEFT); + + return $this->_normalize(new Math_BigInteger($leading_ones | $temp, 256)); + } + + /** + * Logical Right Shift + * + * Shifts BigInteger's by $shift bits, effectively dividing by 2**$shift. + * + * @param Integer $shift + * @return Math_BigInteger + * @access public + * @internal The only version that yields any speed increases is the internal version. + */ + function bitwise_rightShift($shift) + { + $temp = new Math_BigInteger(); + + switch ( MATH_BIGINTEGER_MODE ) { + case MATH_BIGINTEGER_MODE_GMP: + static $two; + + if (!isset($two)) { + $two = gmp_init('2'); + } + + $temp->value = gmp_div_q($this->value, gmp_pow($two, $shift)); + + break; + case MATH_BIGINTEGER_MODE_BCMATH: + $temp->value = bcdiv($this->value, bcpow('2', $shift, 0), 0); + + break; + default: // could just replace _lshift with this, but then all _lshift() calls would need to be rewritten + // and I don't want to do that... + $temp->value = $this->value; + $temp->_rshift($shift); + } + + return $this->_normalize($temp); + } + + /** + * Logical Left Shift + * + * Shifts BigInteger's by $shift bits, effectively multiplying by 2**$shift. + * + * @param Integer $shift + * @return Math_BigInteger + * @access public + * @internal The only version that yields any speed increases is the internal version. + */ + function bitwise_leftShift($shift) + { + $temp = new Math_BigInteger(); + + switch ( MATH_BIGINTEGER_MODE ) { + case MATH_BIGINTEGER_MODE_GMP: + static $two; + + if (!isset($two)) { + $two = gmp_init('2'); + } + + $temp->value = gmp_mul($this->value, gmp_pow($two, $shift)); + + break; + case MATH_BIGINTEGER_MODE_BCMATH: + $temp->value = bcmul($this->value, bcpow('2', $shift, 0), 0); + + break; + default: // could just replace _rshift with this, but then all _lshift() calls would need to be rewritten + // and I don't want to do that... + $temp->value = $this->value; + $temp->_lshift($shift); + } + + return $this->_normalize($temp); + } + + /** + * Logical Left Rotate + * + * Instead of the top x bits being dropped they're appended to the shifted bit string. + * + * @param Integer $shift + * @return Math_BigInteger + * @access public + */ + function bitwise_leftRotate($shift) + { + $bits = $this->toBytes(); + + if ($this->precision > 0) { + $precision = $this->precision; + if ( MATH_BIGINTEGER_MODE == MATH_BIGINTEGER_MODE_BCMATH ) { + $mask = $this->bitmask->subtract(new Math_BigInteger(1)); + $mask = $mask->toBytes(); + } else { + $mask = $this->bitmask->toBytes(); + } + } else { + $temp = ord($bits[0]); + for ($i = 0; $temp >> $i; ++$i); + $precision = 8 * strlen($bits) - 8 + $i; + $mask = chr((1 << ($precision & 0x7)) - 1) . str_repeat(chr(0xFF), $precision >> 3); + } + + if ($shift < 0) { + $shift+= $precision; + } + $shift%= $precision; + + if (!$shift) { + return $this->copy(); + } + + $left = $this->bitwise_leftShift($shift); + $left = $left->bitwise_and(new Math_BigInteger($mask, 256)); + $right = $this->bitwise_rightShift($precision - $shift); + $result = MATH_BIGINTEGER_MODE != MATH_BIGINTEGER_MODE_BCMATH ? $left->bitwise_or($right) : $left->add($right); + return $this->_normalize($result); + } + + /** + * Logical Right Rotate + * + * Instead of the bottom x bits being dropped they're prepended to the shifted bit string. + * + * @param Integer $shift + * @return Math_BigInteger + * @access public + */ + function bitwise_rightRotate($shift) + { + return $this->bitwise_leftRotate(-$shift); + } + + /** + * Set random number generator function + * + * This function is deprecated. + * + * @param String $generator + * @access public + */ + function setRandomGenerator($generator) + { + } + + /** + * Generate a random number + * + * @param optional Integer $min + * @param optional Integer $max + * @return Math_BigInteger + * @access public + */ + function random($min = false, $max = false) + { + if ($min === false) { + $min = new Math_BigInteger(0); + } + + if ($max === false) { + $max = new Math_BigInteger(0x7FFFFFFF); + } + + $compare = $max->compare($min); + + if (!$compare) { + return $this->_normalize($min); + } else if ($compare < 0) { + // if $min is bigger then $max, swap $min and $max + $temp = $max; + $max = $min; + $min = $temp; + } + + $max = $max->subtract($min); + $max = ltrim($max->toBytes(), chr(0)); + $size = strlen($max) - 1; + + $crypt_random = function_exists('crypt_random_string') || (!class_exists('Crypt_Random') && function_exists('crypt_random_string')); + if ($crypt_random) { + $random = crypt_random_string($size); + } else { + $random = ''; + + if ($size & 1) { + $random.= chr(mt_rand(0, 255)); + } + + $blocks = $size >> 1; + for ($i = 0; $i < $blocks; ++$i) { + // mt_rand(-2147483648, 0x7FFFFFFF) always produces -2147483648 on some systems + $random.= pack('n', mt_rand(0, 0xFFFF)); + } + } + + $fragment = new Math_BigInteger($random, 256); + $leading = $fragment->compare(new Math_BigInteger(substr($max, 1), 256)) > 0 ? + ord($max[0]) - 1 : ord($max[0]); + + if (!$crypt_random) { + $msb = chr(mt_rand(0, $leading)); + } else { + $cutoff = floor(0xFF / $leading) * $leading; + while (true) { + $msb = ord(crypt_random_string(1)); + if ($msb <= $cutoff) { + $msb%= $leading; + break; + } + } + $msb = chr($msb); + } + + $random = new Math_BigInteger($msb . $random, 256); + + return $this->_normalize($random->add($min)); + } + + /** + * Generate a random prime number. + * + * If there's not a prime within the given range, false will be returned. If more than $timeout seconds have elapsed, + * give up and return false. + * + * @param optional Integer $min + * @param optional Integer $max + * @param optional Integer $timeout + * @return Math_BigInteger + * @access public + * @internal See {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap4.pdf#page=15 HAC 4.44}. + */ + function randomPrime($min = false, $max = false, $timeout = false) + { + if ($min === false) { + $min = new Math_BigInteger(0); + } + + if ($max === false) { + $max = new Math_BigInteger(0x7FFFFFFF); + } + + $compare = $max->compare($min); + + if (!$compare) { + return $min->isPrime() ? $min : false; + } else if ($compare < 0) { + // if $min is bigger then $max, swap $min and $max + $temp = $max; + $max = $min; + $min = $temp; + } + + static $one, $two; + if (!isset($one)) { + $one = new Math_BigInteger(1); + $two = new Math_BigInteger(2); + } + + $start = time(); + + $x = $this->random($min, $max); + + // gmp_nextprime() requires PHP 5 >= 5.2.0 per . + if ( MATH_BIGINTEGER_MODE == MATH_BIGINTEGER_MODE_GMP && function_exists('gmp_nextprime') ) { + $p = new Math_BigInteger(); + $p->value = gmp_nextprime($x->value); + + if ($p->compare($max) <= 0) { + return $p; + } + + if (!$min->equals($x)) { + $x = $x->subtract($one); + } + + return $x->randomPrime($min, $x); + } + + if ($x->equals($two)) { + return $x; + } + + $x->_make_odd(); + if ($x->compare($max) > 0) { + // if $x > $max then $max is even and if $min == $max then no prime number exists between the specified range + if ($min->equals($max)) { + return false; + } + $x = $min->copy(); + $x->_make_odd(); + } + + $initial_x = $x->copy(); + + while (true) { + if ($timeout !== false && time() - $start > $timeout) { + return false; + } + + if ($x->isPrime()) { + return $x; + } + + $x = $x->add($two); + + if ($x->compare($max) > 0) { + $x = $min->copy(); + if ($x->equals($two)) { + return $x; + } + $x->_make_odd(); + } + + if ($x->equals($initial_x)) { + return false; + } + } + } + + /** + * Make the current number odd + * + * If the current number is odd it'll be unchanged. If it's even, one will be added to it. + * + * @see randomPrime() + * @access private + */ + function _make_odd() + { + switch ( MATH_BIGINTEGER_MODE ) { + case MATH_BIGINTEGER_MODE_GMP: + gmp_setbit($this->value, 0); + break; + case MATH_BIGINTEGER_MODE_BCMATH: + if ($this->value[strlen($this->value) - 1] % 2 == 0) { + $this->value = bcadd($this->value, '1'); + } + break; + default: + $this->value[0] |= 1; + } + } + + /** + * Checks a numer to see if it's prime + * + * Assuming the $t parameter is not set, this function has an error rate of 2**-80. The main motivation for the + * $t parameter is distributability. Math_BigInteger::randomPrime() can be distributed accross multiple pageloads + * on a website instead of just one. + * + * @param optional Integer $t + * @return Boolean + * @access public + * @internal Uses the + * {@link http://en.wikipedia.org/wiki/Miller%E2%80%93Rabin_primality_test Miller-Rabin primality test}. See + * {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap4.pdf#page=8 HAC 4.24}. + */ + function isPrime($t = false) + { + $length = strlen($this->toBytes()); + + if (!$t) { + // see HAC 4.49 "Note (controlling the error probability)" + if ($length >= 163) { $t = 2; } // floor(1300 / 8) + else if ($length >= 106) { $t = 3; } // floor( 850 / 8) + else if ($length >= 81 ) { $t = 4; } // floor( 650 / 8) + else if ($length >= 68 ) { $t = 5; } // floor( 550 / 8) + else if ($length >= 56 ) { $t = 6; } // floor( 450 / 8) + else if ($length >= 50 ) { $t = 7; } // floor( 400 / 8) + else if ($length >= 43 ) { $t = 8; } // floor( 350 / 8) + else if ($length >= 37 ) { $t = 9; } // floor( 300 / 8) + else if ($length >= 31 ) { $t = 12; } // floor( 250 / 8) + else if ($length >= 25 ) { $t = 15; } // floor( 200 / 8) + else if ($length >= 18 ) { $t = 18; } // floor( 150 / 8) + else { $t = 27; } + } + + // ie. gmp_testbit($this, 0) + // ie. isEven() or !isOdd() + switch ( MATH_BIGINTEGER_MODE ) { + case MATH_BIGINTEGER_MODE_GMP: + return gmp_prob_prime($this->value, $t) != 0; + case MATH_BIGINTEGER_MODE_BCMATH: + if ($this->value === '2') { + return true; + } + if ($this->value[strlen($this->value) - 1] % 2 == 0) { + return false; + } + break; + default: + if ($this->value == array(2)) { + return true; + } + if (~$this->value[0] & 1) { + return false; + } + } + + static $primes, $zero, $one, $two; + + if (!isset($primes)) { + $primes = array( + 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, + 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, + 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, + 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, + 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, + 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, + 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, + 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, + 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, + 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, + 953, 967, 971, 977, 983, 991, 997 + ); + + if ( MATH_BIGINTEGER_MODE != MATH_BIGINTEGER_MODE_INTERNAL ) { + for ($i = 0; $i < count($primes); ++$i) { + $primes[$i] = new Math_BigInteger($primes[$i]); + } + } + + $zero = new Math_BigInteger(); + $one = new Math_BigInteger(1); + $two = new Math_BigInteger(2); + } + + if ($this->equals($one)) { + return false; + } + + // see HAC 4.4.1 "Random search for probable primes" + if ( MATH_BIGINTEGER_MODE != MATH_BIGINTEGER_MODE_INTERNAL ) { + foreach ($primes as $prime) { + list(, $r) = $this->divide($prime); + if ($r->equals($zero)) { + return $this->equals($prime); + } + } + } else { + $value = $this->value; + foreach ($primes as $prime) { + list(, $r) = $this->_divide_digit($value, $prime); + if (!$r) { + return count($value) == 1 && $value[0] == $prime; + } + } + } + + $n = $this->copy(); + $n_1 = $n->subtract($one); + $n_2 = $n->subtract($two); + + $r = $n_1->copy(); + $r_value = $r->value; + // ie. $s = gmp_scan1($n, 0) and $r = gmp_div_q($n, gmp_pow(gmp_init('2'), $s)); + if ( MATH_BIGINTEGER_MODE == MATH_BIGINTEGER_MODE_BCMATH ) { + $s = 0; + // if $n was 1, $r would be 0 and this would be an infinite loop, hence our $this->equals($one) check earlier + while ($r->value[strlen($r->value) - 1] % 2 == 0) { + $r->value = bcdiv($r->value, '2', 0); + ++$s; + } + } else { + for ($i = 0, $r_length = count($r_value); $i < $r_length; ++$i) { + $temp = ~$r_value[$i] & 0xFFFFFF; + for ($j = 1; ($temp >> $j) & 1; ++$j); + if ($j != 25) { + break; + } + } + $s = 26 * $i + $j - 1; + $r->_rshift($s); + } + + for ($i = 0; $i < $t; ++$i) { + $a = $this->random($two, $n_2); + $y = $a->modPow($r, $n); + + if (!$y->equals($one) && !$y->equals($n_1)) { + for ($j = 1; $j < $s && !$y->equals($n_1); ++$j) { + $y = $y->modPow($two, $n); + if ($y->equals($one)) { + return false; + } + } + + if (!$y->equals($n_1)) { + return false; + } + } + } + return true; + } + + /** + * Logical Left Shift + * + * Shifts BigInteger's by $shift bits. + * + * @param Integer $shift + * @access private + */ + function _lshift($shift) + { + if ( $shift == 0 ) { + return; + } + + $num_digits = (int) ($shift / MATH_BIGINTEGER_BASE); + $shift %= MATH_BIGINTEGER_BASE; + $shift = 1 << $shift; + + $carry = 0; + + for ($i = 0; $i < count($this->value); ++$i) { + $temp = $this->value[$i] * $shift + $carry; + $carry = (int) ($temp / MATH_BIGINTEGER_BASE_FULL); + $this->value[$i] = (int) ($temp - $carry * MATH_BIGINTEGER_BASE_FULL); + } + + if ( $carry ) { + $this->value[] = $carry; + } + + while ($num_digits--) { + array_unshift($this->value, 0); + } + } + + /** + * Logical Right Shift + * + * Shifts BigInteger's by $shift bits. + * + * @param Integer $shift + * @access private + */ + function _rshift($shift) + { + if ($shift == 0) { + return; + } + + $num_digits = (int) ($shift / MATH_BIGINTEGER_BASE); + $shift %= MATH_BIGINTEGER_BASE; + $carry_shift = MATH_BIGINTEGER_BASE - $shift; + $carry_mask = (1 << $shift) - 1; + + if ( $num_digits ) { + $this->value = array_slice($this->value, $num_digits); + } + + $carry = 0; + + for ($i = count($this->value) - 1; $i >= 0; --$i) { + $temp = $this->value[$i] >> $shift | $carry; + $carry = ($this->value[$i] & $carry_mask) << $carry_shift; + $this->value[$i] = $temp; + } + + $this->value = $this->_trim($this->value); + } + + /** + * Normalize + * + * Removes leading zeros and truncates (if necessary) to maintain the appropriate precision + * + * @param Math_BigInteger + * @return Math_BigInteger + * @see _trim() + * @access private + */ + function _normalize($result) + { + $result->precision = $this->precision; + $result->bitmask = $this->bitmask; + + switch ( MATH_BIGINTEGER_MODE ) { + case MATH_BIGINTEGER_MODE_GMP: + if (!empty($result->bitmask->value)) { + $result->value = gmp_and($result->value, $result->bitmask->value); + } + + return $result; + case MATH_BIGINTEGER_MODE_BCMATH: + if (!empty($result->bitmask->value)) { + $result->value = bcmod($result->value, $result->bitmask->value); + } + + return $result; + } + + $value = &$result->value; + + if ( !count($value) ) { + return $result; + } + + $value = $this->_trim($value); + + if (!empty($result->bitmask->value)) { + $length = min(count($value), count($this->bitmask->value)); + $value = array_slice($value, 0, $length); + + for ($i = 0; $i < $length; ++$i) { + $value[$i] = $value[$i] & $this->bitmask->value[$i]; + } + } + + return $result; + } + + /** + * Trim + * + * Removes leading zeros + * + * @param Array $value + * @return Math_BigInteger + * @access private + */ + function _trim($value) + { + for ($i = count($value) - 1; $i >= 0; --$i) { + if ( $value[$i] ) { + break; + } + unset($value[$i]); + } + + return $value; + } + + /** + * Array Repeat + * + * @param $input Array + * @param $multiplier mixed + * @return Array + * @access private + */ + function _array_repeat($input, $multiplier) + { + return ($multiplier) ? array_fill(0, $multiplier, $input) : array(); + } + + /** + * Logical Left Shift + * + * Shifts binary strings $shift bits, essentially multiplying by 2**$shift. + * + * @param $x String + * @param $shift Integer + * @return String + * @access private + */ + function _base256_lshift(&$x, $shift) + { + if ($shift == 0) { + return; + } + + $num_bytes = $shift >> 3; // eg. floor($shift/8) + $shift &= 7; // eg. $shift % 8 + + $carry = 0; + for ($i = strlen($x) - 1; $i >= 0; --$i) { + $temp = ord($x[$i]) << $shift | $carry; + $x[$i] = chr($temp); + $carry = $temp >> 8; + } + $carry = ($carry != 0) ? chr($carry) : ''; + $x = $carry . $x . str_repeat(chr(0), $num_bytes); + } + + /** + * Logical Right Shift + * + * Shifts binary strings $shift bits, essentially dividing by 2**$shift and returning the remainder. + * + * @param $x String + * @param $shift Integer + * @return String + * @access private + */ + function _base256_rshift(&$x, $shift) + { + if ($shift == 0) { + $x = ltrim($x, chr(0)); + return ''; + } + + $num_bytes = $shift >> 3; // eg. floor($shift/8) + $shift &= 7; // eg. $shift % 8 + + $remainder = ''; + if ($num_bytes) { + $start = $num_bytes > strlen($x) ? -strlen($x) : -$num_bytes; + $remainder = substr($x, $start); + $x = substr($x, 0, -$num_bytes); + } + + $carry = 0; + $carry_shift = 8 - $shift; + for ($i = 0; $i < strlen($x); ++$i) { + $temp = (ord($x[$i]) >> $shift) | $carry; + $carry = (ord($x[$i]) << $carry_shift) & 0xFF; + $x[$i] = chr($temp); + } + $x = ltrim($x, chr(0)); + + $remainder = chr($carry >> $carry_shift) . $remainder; + + return ltrim($remainder, chr(0)); + } + + // one quirk about how the following functions are implemented is that PHP defines N to be an unsigned long + // at 32-bits, while java's longs are 64-bits. + + /** + * Converts 32-bit integers to bytes. + * + * @param Integer $x + * @return String + * @access private + */ + function _int2bytes($x) + { + return ltrim(pack('N', $x), chr(0)); + } + + /** + * Converts bytes to 32-bit integers + * + * @param String $x + * @return Integer + * @access private + */ + function _bytes2int($x) + { + $temp = unpack('Nint', str_pad($x, 4, chr(0), STR_PAD_LEFT)); + return $temp['int']; + } + + /** + * DER-encode an integer + * + * The ability to DER-encode integers is needed to create RSA public keys for use with OpenSSL + * + * @see modPow() + * @access private + * @param Integer $length + * @return String + */ + function _encodeASN1Length($length) + { + if ($length <= 0x7F) { + return chr($length); + } + + $temp = ltrim(pack('N', $length), chr(0)); + return pack('Ca*', 0x80 | strlen($temp), $temp); + } +} diff --git a/inc/phpseclib/update.sh b/inc/phpseclib/update.sh new file mode 100755 index 000000000..ff3747a14 --- /dev/null +++ b/inc/phpseclib/update.sh @@ -0,0 +1,8 @@ +#!/bin/sh + +wget -nv https://raw.github.com/phpseclib/phpseclib/master/LICENSE -O LICENSE +wget -nv https://raw.github.com/phpseclib/phpseclib/master/phpseclib/Math/BigInteger.php -O Math_BigInteger.php +wget -nv https://raw.github.com/phpseclib/phpseclib/master/phpseclib/Crypt/AES.php -O Crypt_AES.php +wget -nv https://raw.github.com/phpseclib/phpseclib/master/phpseclib/Crypt/Rijndael.php -O Crypt_Rijndael.php +wget -nv https://raw.github.com/phpseclib/phpseclib/master/phpseclib/Crypt/Base.php -O Crypt_Base.php +wget -nv https://raw.github.com/phpseclib/phpseclib/master/phpseclib/Crypt/Hash.php -O Crypt_Hash.php -- cgit v1.2.3 From f2bbf30b71b15efa7a918944b4ffc74f8b1747a9 Mon Sep 17 00:00:00 2001 From: Guy Brand Date: Wed, 31 Jul 2013 11:38:44 +0200 Subject: Simple test cases for code and file token fix --- _test/tests/inc/parser/parser_code.test.php | 56 +++++++++++++++++++++++++++++ _test/tests/inc/parser/parser_file.test.php | 28 +++++++++++++++ 2 files changed, 84 insertions(+) create mode 100644 _test/tests/inc/parser/parser_code.test.php create mode 100644 _test/tests/inc/parser/parser_file.test.php diff --git a/_test/tests/inc/parser/parser_code.test.php b/_test/tests/inc/parser/parser_code.test.php new file mode 100644 index 000000000..4f89b4826 --- /dev/null +++ b/_test/tests/inc/parser/parser_code.test.php @@ -0,0 +1,56 @@ +P->addMode('code',new Doku_Parser_Mode_Code()); + } + + function testCode() { + $this->P->parse('Foo Test Bar'); + $calls = array ( + array('document_start',array()), + array('p_open',array()), + array('cdata',array("\n".'Foo ')), + array('p_close',array()), + array('code',array('Test',null,null)), + array('p_open',array()), + array('cdata',array(' Bar')), + array('p_close',array()), + array('document_end',array()), + ); + $this->assertEquals(array_map('stripbyteindex',$this->H->calls),$calls); + } + + function testCodeBash() { + $this->P->parse('Foo Test Bar'); + $calls = array ( + array('document_start',array()), + array('p_open',array()), + array('cdata',array("\n".'Foo ')), + array('p_close',array()), + array('code',array('Test','bash',null)), + array('p_open',array()), + array('cdata',array(' Bar')), + array('p_close',array()), + array('document_end',array()), + ); + $this->assertEquals(array_map('stripbyteindex',$this->H->calls),$calls); + } + + function testCodeToken() { + $this->P->parse('Foo BarTest'); + $calls = array ( + array('document_start',array()), + array('p_open',array()), + array('cdata',array("\n".'Foo Bar')), + array('p_close',array()), + array('code',array('Test',null,null)), + array('document_end',array()), + ); + $this->assertEquals(array_map('stripbyteindex',$this->H->calls),$calls); + } +} + diff --git a/_test/tests/inc/parser/parser_file.test.php b/_test/tests/inc/parser/parser_file.test.php new file mode 100644 index 000000000..924b00382 --- /dev/null +++ b/_test/tests/inc/parser/parser_file.test.php @@ -0,0 +1,28 @@ +P->addMode('file',new Doku_Parser_Mode_File()); + } + + function testFile() { + $this->P->parse('Foo Test Bar'); + $calls = array ( + array('document_start',array()), + array('p_open',array()), + array('cdata',array("\n".'Foo ')), + array('p_close',array()), + array('file',array('Test',null,null)), + array('p_open',array()), + array('cdata',array(' Bar')), + array('p_close',array()), + array('document_end',array()), + ); + $this->assertEquals(array_map('stripbyteindex',$this->H->calls),$calls); + } + +} + -- cgit v1.2.3 From 21134337f0a0d72b198e4be0561fe4dd729d1f07 Mon Sep 17 00:00:00 2001 From: Anika Henke Date: Wed, 31 Jul 2013 10:39:11 +0100 Subject: updated intro text on wiki:dokuwiki --- data/pages/wiki/dokuwiki.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/pages/wiki/dokuwiki.txt b/data/pages/wiki/dokuwiki.txt index 2db4dbef3..808aea68a 100644 --- a/data/pages/wiki/dokuwiki.txt +++ b/data/pages/wiki/dokuwiki.txt @@ -1,6 +1,6 @@ ====== DokuWiki ====== -[[doku>wiki:dokuwiki|{{wiki:dokuwiki-128.png }}]] DokuWiki is a standards compliant, simple to use [[wp>Wiki]], mainly aimed at creating documentation of any kind. It is targeted at developer teams, workgroups and small companies. It has a simple but powerful [[wiki:syntax]] which makes sure the datafiles remain readable outside the Wiki and eases the creation of structured texts. All data is stored in plain text files -- no database is required. +[[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. -- cgit v1.2.3 From 8269996a43469c1ce5295a22248ad9a9ab34efc8 Mon Sep 17 00:00:00 2001 From: Michael Hamann Date: Wed, 31 Jul 2013 11:56:16 +0200 Subject: auth_random: remove exception comment as there is no exception --- inc/auth.php | 1 - 1 file changed, 1 deletion(-) diff --git a/inc/auth.php b/inc/auth.php index f02bfebca..227ee80fd 100644 --- a/inc/auth.php +++ b/inc/auth.php @@ -360,7 +360,6 @@ function auth_cookiesalt($addsession = false, $secure = false) { * @author Michael Hamann * @link http://www.php.net/manual/de/function.mt-rand.php#83655 * @param int $length number of bytes to get - * @throws Exception when no usable random generator is found * @return string binary random strings */ function auth_randombytes($length) { -- cgit v1.2.3 From 7b650cef79bb603087a8ef43b22a1f7c3d86b7ef Mon Sep 17 00:00:00 2001 From: Michael Hamann Date: Wed, 31 Jul 2013 11:56:58 +0200 Subject: auth_en/decrypt: Add explanation and more efficient decryption Added an explanation that what we do is like normal CBC but that we additionally encrypt the IV which is actually suggested by the NIST for non-random (but unique) IVs. In the decryption process it's not necessary to decrypt the IV, this should save some time. --- inc/auth.php | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/inc/auth.php b/inc/auth.php index 227ee80fd..96b80e19e 100644 --- a/inc/auth.php +++ b/inc/auth.php @@ -459,10 +459,16 @@ function auth_random($min, $max) { * @return string The ciphertext */ function auth_encrypt($data, $secret) { - $iv = auth_randombytes(16); + $iv = auth_randombytes(16); $cipher = new Crypt_AES(); $cipher->setPassword($secret); + /* + this uses the encrypted IV as IV as suggested in + http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf, Appendix C + for unique but necessarily random IVs. The resulting ciphertext is + compatible to ciphertext that was created using a "normal" IV. + */ return $cipher->encrypt($iv.$data); } @@ -476,10 +482,12 @@ function auth_encrypt($data, $secret) { * @return string The decrypted data */ function auth_decrypt($ciphertext, $secret) { + $iv = substr($ciphertext, 0, 16); $cipher = new Crypt_AES(); $cipher->setPassword($secret); + $cipher->setIV($iv); - return substr($cipher->decrypt($ciphertext), 16); + return $cipher->decrypt(substr($ciphertext, 16)); } /** -- cgit v1.2.3 From b25974c4272787f8c66d36398d9578e630888451 Mon Sep 17 00:00:00 2001 From: Guy Brand Date: Wed, 31 Jul 2013 12:31:35 +0200 Subject: Fixed instructions on PHPunit --- _test/README | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/_test/README b/_test/README index a4206f489..5220248b2 100644 --- a/_test/README +++ b/_test/README @@ -1,6 +1,6 @@ ====== DokuWiki Test Suite ====== -This is the test suit to automatically test various parts of DokuWiki. +This is the test suite to automatically test various parts of DokuWiki. ===== Requirements ===== @@ -9,22 +9,33 @@ This is the test suit to automatically test various parts of DokuWiki. ===== PHPUnit Installation ====== -via PEAR: +==== via PEAR installer ==== pear config-set auto_discover 1 - pear upgrade pear install pear.phpunit.de/PHPUnit -on Windows: +==== via Composer ==== - FIXME +Include a composer.json file in your project, which can be as minimal as: + + +{ + "require-dev": { + "phpunit/phpunit": "3.7.*" + } +} + + +==== via PHP archive (PHAR) ==== + +Download http://pear.phpunit.de/get/phpunit.phar and make it executable on your system. -===== Running all Tests ===== +===== Running all tests ===== Just change to the ''_test'' directory and run phpunit: - cd _testing/ + cd _test/ phpunit PHPUnit will fail on some systems with a //headers already sent// error. -- cgit v1.2.3 From e8e5221c8fef184d755602564343787c9e3196d9 Mon Sep 17 00:00:00 2001 From: Anika Henke Date: Wed, 31 Jul 2013 11:56:08 +0100 Subject: switched to LESS variables in rest of template's css files --- lib/tpl/dokuwiki/css/_admin.css | 2 +- lib/tpl/dokuwiki/css/_diff.css | 2 +- lib/tpl/dokuwiki/css/_edit.css | 12 ++++----- lib/tpl/dokuwiki/css/_fileuploader.css | 8 +++--- lib/tpl/dokuwiki/css/_footnotes.css | 2 +- lib/tpl/dokuwiki/css/_forms.css | 2 +- lib/tpl/dokuwiki/css/_media_fullscreen.css | 40 +++++++++++++++--------------- lib/tpl/dokuwiki/css/_media_popup.css | 12 ++++----- lib/tpl/dokuwiki/css/_modal.css | 10 ++++---- lib/tpl/dokuwiki/css/_search.css | 6 ++--- lib/tpl/dokuwiki/css/_tabs.css | 14 +++++------ lib/tpl/dokuwiki/css/_toc.css | 2 +- lib/tpl/dokuwiki/css/pagetools.less | 10 ++++---- lib/tpl/dokuwiki/style.ini | 32 ++++++++++++------------ 14 files changed, 77 insertions(+), 77 deletions(-) diff --git a/lib/tpl/dokuwiki/css/_admin.css b/lib/tpl/dokuwiki/css/_admin.css index c8f3694b5..a9518d0ed 100644 --- a/lib/tpl/dokuwiki/css/_admin.css +++ b/lib/tpl/dokuwiki/css/_admin.css @@ -50,7 +50,7 @@ .dokuwiki #admin__version { clear: left; float: right; - color: __text_neu__; + color: @ini_text_neu; background-color: inherit; } [dir=rtl] .dokuwiki #admin__version { diff --git a/lib/tpl/dokuwiki/css/_diff.css b/lib/tpl/dokuwiki/css/_diff.css index 58c24b5c7..b7c82d829 100644 --- a/lib/tpl/dokuwiki/css/_diff.css +++ b/lib/tpl/dokuwiki/css/_diff.css @@ -19,7 +19,7 @@ /* table header */ .dokuwiki table.diff th { - border-bottom: 1px solid __border__; + border-bottom: 1px solid @ini_border; font-size: 110%; font-weight: normal; } diff --git a/lib/tpl/dokuwiki/css/_edit.css b/lib/tpl/dokuwiki/css/_edit.css index 92ce62126..f40aaa891 100644 --- a/lib/tpl/dokuwiki/css/_edit.css +++ b/lib/tpl/dokuwiki/css/_edit.css @@ -16,7 +16,7 @@ } #draft__status { float: right; - color: __text_alt__; + color: @ini_text_alt; background-color: inherit; } [dir=rtl] #draft__status { @@ -35,8 +35,8 @@ /* picker popups (outside of .dokuwiki) */ div.picker { width: 300px; - border: 1px solid __border__; - background-color: __background_alt__; + border: 1px solid @ini_border; + background-color: @ini_background_alt; color: inherit; } /* picker for headlines */ @@ -106,7 +106,7 @@ div.picker button.toolbutton { } /* change background colour if summary is missing */ .dokuwiki .editBar .summary input.missing { - color: __text__; + color: @ini_text; background-color: #ffcccc; } @@ -114,7 +114,7 @@ div.picker button.toolbutton { ********************************************************************/ .dokuwiki div.preview { - border: dotted __border__; + border: dotted @ini_border; border-width: .2em 0; padding: 1.4em 0; margin-bottom: 1.4em; @@ -138,6 +138,6 @@ div.picker button.toolbutton { .dokuwiki div.section_highlight { margin: 0 -1em; /* negative side margin = side padding + side border */ padding: 0 .5em; - border: solid __background_alt__; + border: solid @ini_background_alt; border-width: 0 .5em; } diff --git a/lib/tpl/dokuwiki/css/_fileuploader.css b/lib/tpl/dokuwiki/css/_fileuploader.css index 42004de28..3c2cd4683 100644 --- a/lib/tpl/dokuwiki/css/_fileuploader.css +++ b/lib/tpl/dokuwiki/css/_fileuploader.css @@ -42,8 +42,8 @@ height: 100%; min-height: 70px; z-index: 2; - background: __background_neu__; - color: __text__; + background: @ini_background_neu; + color: @ini_text; text-align: center; } @@ -57,7 +57,7 @@ } .qq-upload-drop-area-active { - background: __background_alt__; + background: @ini_background_alt; } /* list of files to upload */ @@ -70,7 +70,7 @@ div.qq-uploader ul { .qq-uploader li { margin: 0 0 5px; - color: __text__; + color: @ini_text; } .qq-uploader li span, diff --git a/lib/tpl/dokuwiki/css/_footnotes.css b/lib/tpl/dokuwiki/css/_footnotes.css index a20f2964e..5d5f7ca30 100644 --- a/lib/tpl/dokuwiki/css/_footnotes.css +++ b/lib/tpl/dokuwiki/css/_footnotes.css @@ -16,7 +16,7 @@ div.insitu-footnote { /*____________ footnotes at the bottom of the page ____________*/ .dokuwiki div.footnotes { - border-top: 1px solid __border__; + border-top: 1px solid @ini_border; padding: .5em 0 0 0; margin: 1em 0 0 0; clear: both; diff --git a/lib/tpl/dokuwiki/css/_forms.css b/lib/tpl/dokuwiki/css/_forms.css index 6744750ba..940a27f80 100644 --- a/lib/tpl/dokuwiki/css/_forms.css +++ b/lib/tpl/dokuwiki/css/_forms.css @@ -48,7 +48,7 @@ .dokuwiki fieldset { width: 400px; text-align: center; - border: 1px solid __border__; + border: 1px solid @ini_border; padding: 0.5em; margin: auto; } diff --git a/lib/tpl/dokuwiki/css/_media_fullscreen.css b/lib/tpl/dokuwiki/css/_media_fullscreen.css index 8d5e1e8ca..28e347882 100644 --- a/lib/tpl/dokuwiki/css/_media_fullscreen.css +++ b/lib/tpl/dokuwiki/css/_media_fullscreen.css @@ -38,7 +38,7 @@ } #mediamanager__page .panelHeader { - background-color: __background_alt__; + background-color: @ini_background_alt; margin: 0 10px 10px 0; padding: 10px 10px 8px; text-align: left; @@ -68,7 +68,7 @@ background: transparent url(../../images/resizecol.png) center center no-repeat; } #mediamanager__page .ui-resizable-e:hover { - background-color: __background_alt__; + background-color: @ini_background_alt; } @@ -99,10 +99,10 @@ margin: 0 0 0 .3em; border-radius: .5em .5em 0 0; font-weight: normal; - background-color: __background_alt__; - color: __text__; - border: 1px solid __border__; - border-bottom-color: __background_alt__; + background-color: @ini_background_alt; + color: @ini_text; + border: 1px solid @ini_border; + border-bottom-color: @ini_background_alt; line-height: 1.4em; position: relative; bottom: -1px; @@ -118,7 +118,7 @@ right: 10px; } #mediamanager__page .namespaces .panelHeader { - border-top: 1px solid __border__; + border-top: 1px solid @ini_border; z-index: 1; } @@ -164,7 +164,7 @@ padding: 0; } #mediamanager__page .panelHeader ul li { - color: __text__; + color: @ini_text; float: left; line-height: 1; padding-left: 3px; @@ -205,7 +205,7 @@ } #mediamanager__page .filelist .panelContent ul li:hover { - background-color: __background_alt__; + background-color: @ini_background_alt; } #mediamanager__page .filelist li dt a { @@ -231,8 +231,8 @@ display: -moz-inline-stack; /* the right margin should visually be 10px, but because of its inline-block nature the whitespace inbetween is about 4px more */ margin: 0 6px 10px 0; - background-color: __background_neu__; - color: __text__; + background-color: @ini_background_neu; + color: @ini_text; padding: 5px; vertical-align: top; text-align: center; @@ -287,13 +287,13 @@ max-height: 50px; margin: 0; margin-bottom: 3px; - background-color: __background__; - color: __text__; + background-color: @ini_background; + color: @ini_text; overflow: hidden; } #mediamanager__page .filelist .rows li:nth-child(2n+1) { - background-color: __background_neu__; + background-color: @ini_background_neu; } #mediamanager__page .filelist .rows li dt { @@ -372,11 +372,11 @@ #mediamanager__page .file dl dt { font-weight: bold; display: block; - background-color: __background_alt__; + background-color: @ini_background_alt; } #mediamanager__page .file dl dd { display: block; - background-color: __background_neu__; + background-color: @ini_background_neu; } @@ -415,7 +415,7 @@ #mediamanager__page #page__revisions ul li div.li div { font-size: 90%; - color: __text_neu__; + color: @ini_text_neu; padding-left: 18px; } @@ -438,7 +438,7 @@ padding: 0; vertical-align: top; text-align: left; - border-color: __background__; + border-color: @ini_background; } [dir=rtl] #mediamanager__diff td, [dir=rtl] #mediamanager__diff th { @@ -447,7 +447,7 @@ #mediamanager__diff th { font-weight: normal; - background-color: __background__; + background-color: @ini_background; line-height: 1.2; } #mediamanager__diff th a { @@ -459,7 +459,7 @@ #mediamanager__diff dl dd strong{ background-color: __highlight__; - color: __text__; + color: @ini_text; font-weight: normal; } diff --git a/lib/tpl/dokuwiki/css/_media_popup.css b/lib/tpl/dokuwiki/css/_media_popup.css index c776e6b8a..1fefd68b6 100644 --- a/lib/tpl/dokuwiki/css/_media_popup.css +++ b/lib/tpl/dokuwiki/css/_media_popup.css @@ -20,13 +20,13 @@ html.popup { overflow: auto; position: absolute; left: 0; - border-right: 1px solid __border__; + border-right: 1px solid @ini_border; } [dir=rtl] #mediamgr__aside { left: auto; right: 0; border-right-width: 0; - border-left: 1px solid __border__; + border-left: 1px solid @ini_border; } #mediamgr__aside .pad { padding: .5em; @@ -52,7 +52,7 @@ html.popup { font-size: 1.5em; margin-bottom: .5em; padding-bottom: .2em; - border-bottom: 1px solid __border__; + border-bottom: 1px solid @ini_border; } /* left side @@ -141,13 +141,13 @@ html.popup { padding: .5em; } #media__content .odd { - background-color: __background_alt__; + background-color: @ini_background_alt; } #media__content .even { } /* highlight newly uploaded or edited file */ #media__content #scroll__here { - border: 1px dashed __border__; + border: 1px dashed @ini_border; } /* link which inserts media file */ @@ -167,7 +167,7 @@ html.popup { /* info how to insert media, if JS disabled */ #media__content div.example { - color: __text_neu__; + color: @ini_text_neu; margin-left: 1em; } diff --git a/lib/tpl/dokuwiki/css/_modal.css b/lib/tpl/dokuwiki/css/_modal.css index a3d3be194..a46dff30e 100644 --- a/lib/tpl/dokuwiki/css/_modal.css +++ b/lib/tpl/dokuwiki/css/_modal.css @@ -18,11 +18,11 @@ } #link__wiz_result { - background-color: __background__; + background-color: @ini_background; width: 293px; height: 193px; overflow: auto; - border: 1px solid __border__; + border: 1px solid @ini_border; margin: 3px auto; text-align: left; line-height: 1; @@ -57,16 +57,16 @@ } #link__wiz_result div.even { - background-color: __background_neu__; + background-color: @ini_background_neu; } #link__wiz_result div.selected { - background-color: __background_alt__; + background-color: @ini_background_alt; } #link__wiz_result span { display: block; - color: __text_neu__; + color: @ini_text_neu; margin-left: 22px; } diff --git a/lib/tpl/dokuwiki/css/_search.css b/lib/tpl/dokuwiki/css/_search.css index 0090308c9..a8972ae72 100644 --- a/lib/tpl/dokuwiki/css/_search.css +++ b/lib/tpl/dokuwiki/css/_search.css @@ -44,14 +44,14 @@ } /* search snippet */ .dokuwiki dl.search_results dd { - color: __text_alt__; + color: @ini_text_alt; background-color: inherit; margin: 0 0 1.2em 0; } /* search hit in normal text */ .dokuwiki .search_hit { - color: __text__; + color: @ini_text; background-color: __highlight__; } /* search hit in search results */ @@ -60,7 +60,7 @@ } /* ellipsis separating snippets */ .dokuwiki .search_results .search_sep { - color: __text__; + color: @ini_text; background-color: inherit; } diff --git a/lib/tpl/dokuwiki/css/_tabs.css b/lib/tpl/dokuwiki/css/_tabs.css index 845ec9a57..860545a27 100644 --- a/lib/tpl/dokuwiki/css/_tabs.css +++ b/lib/tpl/dokuwiki/css/_tabs.css @@ -17,7 +17,7 @@ width: 100%; bottom: 0; left: 0; - border-bottom: 1px solid __border__; + border-bottom: 1px solid @ini_border; z-index: 1; } @@ -39,9 +39,9 @@ display: inline-block; padding: .3em .8em; margin: 0 0 0 .3em; - background-color: __background_neu__; - color: __text__; - border: 1px solid __border__; + background-color: @ini_background_neu; + color: @ini_text; + border: 1px solid @ini_border; border-radius: .5em .5em 0 0; position: relative; z-index: 0; @@ -68,8 +68,8 @@ .dokuwiki ul.tabs li a:active, .dokuwiki ul.tabs li a:focus, .dokuwiki ul.tabs li strong { - background-color: __background_alt__; - color: __text__; + background-color: @ini_background_alt; + color: @ini_text; text-decoration: none; font-weight: normal; } @@ -78,5 +78,5 @@ .dokuwiki .tabs > ul li .active a, .dokuwiki ul.tabs li strong { z-index: 2; - border-bottom-color: __background_alt__; + border-bottom-color: @ini_background_alt; } diff --git a/lib/tpl/dokuwiki/css/_toc.css b/lib/tpl/dokuwiki/css/_toc.css index 1226b5b5b..469e9278c 100644 --- a/lib/tpl/dokuwiki/css/_toc.css +++ b/lib/tpl/dokuwiki/css/_toc.css @@ -11,7 +11,7 @@ float: right; margin: 0 0 1.4em 1.4em; width: 12em; - background-color: __background_alt__; + background-color: @ini_background_alt; color: inherit; } [dir=rtl] #dw__toc { diff --git a/lib/tpl/dokuwiki/css/pagetools.less b/lib/tpl/dokuwiki/css/pagetools.less index 21e5c13ec..2e316122f 100644 --- a/lib/tpl/dokuwiki/css/pagetools.less +++ b/lib/tpl/dokuwiki/css/pagetools.less @@ -101,10 +101,10 @@ #dokuwiki__pagetools:hover ul, #dokuwiki__pagetools ul li a:focus, #dokuwiki__pagetools ul li a:active { - background-color: __background__; - border-color: __border__; + background-color: @ini_background; + border-color: @ini_border; border-radius: 2px; - box-shadow: 2px 2px 2px __text_alt__; + box-shadow: 2px 2px 2px @ini_text_alt; } #dokuwiki__pagetools:hover ul li a, @@ -124,7 +124,7 @@ [dir=rtl] #dokuwiki__pagetools:hover ul, [dir=rtl] #dokuwiki__pagetools ul li a:focus { - box-shadow: -2px 2px 2px __text_alt__; + box-shadow: -2px 2px 2px @ini_text_alt; } [dir=rtl] #dokuwiki__pagetools:hover li a, @@ -158,7 +158,7 @@ text-decoration: none; } #dokuwiki__pagetools ul li a:hover { - background-color: __background_alt__; + background-color: @ini_background_alt; } /*____________ all available icons in sprite ____________*/ diff --git a/lib/tpl/dokuwiki/style.ini b/lib/tpl/dokuwiki/style.ini index 24faffdb3..897b6e6da 100644 --- a/lib/tpl/dokuwiki/style.ini +++ b/lib/tpl/dokuwiki/style.ini @@ -54,32 +54,32 @@ css/print.css = print ;------ guaranteed dokuwiki color placeholders that every plugin can use ; main text and background colors -__text__ = "#333" -__background__ = "#fff" +__text__ = "#333" ; @ini_text +__background__ = "#fff" ; @ini_background ; alternative text and background colors -__text_alt__ = "#999" -__background_alt__ = "#eee" +__text_alt__ = "#999" ; @ini_text_alt +__background_alt__ = "#eee" ; @ini_background_alt ; neutral text and background colors -__text_neu__ = "#666" -__background_neu__ = "#ddd" +__text_neu__ = "#666" ; @ini_text_neu +__background_neu__ = "#ddd" ; @ini_background_neu ; border color -__border__ = "#ccc" +__border__ = "#ccc" ; @ini_border ; highlighted text (e.g. search snippets) -__highlight__ = "#ff9" +__highlight__ = "#ff9" ; @ini_highlight ;-------------------------------------------------------------------------- -__background_site__ = "#fbfaf9" +__background_site__ = "#fbfaf9" ; @ini_background_site ; these are used for links -__link__ = "#2b73b7" -__existing__ = "#080" -__missing__ = "#d30" +__link__ = "#2b73b7" ; @ini_link +__existing__ = "#080" ; @ini_existing +__missing__ = "#d30" ; @ini_missing ; site and sidebar widths -__site_width__ = "75em" -__sidebar_width__ = "16em" +__site_width__ = "75em" ; @ini_site_width +__sidebar_width__ = "16em" ; @ini_sidebar_width ; cut off points for mobile devices -__tablet_width__ = "800px" -__phone_width__ = "480px" +__tablet_width__ = "800px" ; @ini_tablet_width +__phone_width__ = "480px" ; @ini_phone_width -- cgit v1.2.3 From fd975da73e627193ca68a681ea6b2556c8327f63 Mon Sep 17 00:00:00 2001 From: Anika Henke Date: Wed, 31 Jul 2013 11:58:47 +0100 Subject: removed possibility to have rtl.less files in plugins --- lib/exe/css.php | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/exe/css.php b/lib/exe/css.php index cd531ef35..5c966db82 100644 --- a/lib/exe/css.php +++ b/lib/exe/css.php @@ -365,7 +365,6 @@ function css_pluginstyles($mediatype='screen'){ // please use "[dir=rtl]" in any css file in all, screen or print mode instead if($lang['direction'] == 'rtl'){ $list[DOKU_PLUGIN."$p/rtl.css"] = DOKU_BASE."lib/plugins/$p/"; - $list[DOKU_PLUGIN."$p/rtl.less"] = DOKU_BASE."lib/plugins/$p/"; } } return $list; -- cgit v1.2.3 From cd997f938b450010efa93aa8a65ecbed9a68a32e Mon Sep 17 00:00:00 2001 From: Andreas Gohr Date: Wed, 31 Jul 2013 14:04:56 +0200 Subject: include updateVersion in CSS/JS tseed to force reload on update --- inc/template.php | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/inc/template.php b/inc/template.php index a87650b84..b8129f914 100644 --- a/inc/template.php +++ b/inc/template.php @@ -291,12 +291,10 @@ function tpl_metaheaders($alt = true) { $head = array(); // prepare seed for js and css - $tseed = 0; + $tseed = $updateVersion; $depends = getConfigFiles('main'); - foreach($depends as $f) { - $time = @filemtime($f); - if($time > $tseed) $tseed = $time; - } + foreach($depends as $f) $tseed .= @filemtime($f); + $tseed = md5($tseed); // the usual stuff $head['meta'][] = array('name'=> 'generator', 'content'=> 'DokuWiki'); -- cgit v1.2.3 From 07ff0babae240ba072a3bc8b83a989c4305c24cd Mon Sep 17 00:00:00 2001 From: Michael Hamann Date: Wed, 31 Jul 2013 17:20:00 +0200 Subject: Fix the useheading cache invalidation for hidden pages, add tests This adds a new parameter to ft_backlinks() to ignore permissions which is needed for invalidating the cache of linking pages with useheading enabled. This also adds various test cases for ft_backlinks(). --- _test/tests/inc/fulltext_backlinks.test.php | 77 +++++++++++++++++++++++++++++ inc/common.php | 2 +- inc/fulltext.php | 12 +++-- 3 files changed, 86 insertions(+), 5 deletions(-) create mode 100644 _test/tests/inc/fulltext_backlinks.test.php diff --git a/_test/tests/inc/fulltext_backlinks.test.php b/_test/tests/inc/fulltext_backlinks.test.php new file mode 100644 index 000000000..058e13498 --- /dev/null +++ b/_test/tests/inc/fulltext_backlinks.test.php @@ -0,0 +1,77 @@ + + */ +class fultext_backlinks_test extends DokuWikiTest { + + public function test_internallink() { + saveWikiText('test:internallinks', '[[internälLink]] [[..:internal link]]', 'Test initialization'); + idx_addPage('test:internallinks'); + + $this->assertEquals(array('test:internallinks'), ft_backlinks('internal_link')); + $this->assertEquals(array('test:internallinks'), ft_backlinks('test:internaellink')); + } + + public function test_links_in_footnotes() { + saveWikiText('test:link_footnotes', '(([[footnote]] [[:foÖtnotel]]))', 'Test initialization'); + idx_addPage('test:link_footnotes'); + + $this->assertEquals(array('test:link_footnotes'), ft_backlinks('test:footnote')); + $this->assertEquals(array('test:link_footnotes'), ft_backlinks('fooetnotel')); + } + + public function test_links_in_hidden_pages() { + global $conf; + $conf['hidepages'] = 'hidden:.*'; + saveWikiText('hidden:links', '[[wiki:hiddenlink|linktitle]]', 'Test initialization'); + idx_addPage('hidden:links'); + saveWikiText('visible:links', '[[wiki:hiddenlink]]', 'Test initialization'); + idx_addPage('visible:links'); + + $this->assertEquals(array('visible:links'), ft_backlinks('wiki:hiddenlink')); + $this->assertEquals(array('visible:links'), ft_backlinks('wiki:hiddenlink', false)); + $this->assertEquals(array('hidden:links', 'visible:links'), ft_backlinks('wiki:hiddenlink', true)); + } + + public function test_links_in_protected_pages() { + global $conf; + global $AUTH_ACL; + $conf['superuser'] = 'alice'; + $conf['useacl'] = 1; + + $AUTH_ACL = array( + '* @ALL 8', + 'secret:* @ALL 0', + ); + + $_SERVER['REMOTE_USER'] = 'eve'; + + saveWikiText('secret:links', '[[wiki:secretlink]]', 'Test initialization'); + idx_addPage('secret:links'); + saveWikiText('public:links', '[[wiki:secretlink]]', 'Test initialization'); + idx_addPage('public:links'); + + $this->assertEquals(array('public:links'), ft_backlinks('wiki:secretlink')); + $this->assertEquals(array('public:links'), ft_backlinks('wiki:secretlink', false)); + $this->assertEquals(array('public:links', 'secret:links'), ft_backlinks('wiki:secretlink', true)); + } + + public function test_links_in_deleted_pages() { + saveWikiText('test:internallinks', '[[internallink]] [[..:internal link]]', 'Test initialization'); + idx_addPage('test:internallinks'); + + $this->assertEquals(array('test:internallinks'), ft_backlinks('test:internallink')); + $this->assertEquals(array('test:internallinks'), ft_backlinks('internal_link')); + + saveWikiText('test:internallinks', '', 'Deleted'); + + $this->assertEquals(array(), ft_backlinks('test:internallink')); + $this->assertEquals(array(), ft_backlinks('internal_link')); + } +} diff --git a/inc/common.php b/inc/common.php index 1b4d9e8e4..bff6e80de 100644 --- a/inc/common.php +++ b/inc/common.php @@ -1130,7 +1130,7 @@ function saveWikiText($id, $text, $summary, $minor = false) { // if useheading is enabled, purge the cache of all linking pages if(useHeading('content')) { - $pages = ft_backlinks($id); + $pages = ft_backlinks($id, true); foreach($pages as $page) { $cache = new cache_renderer($page, wikiFN($page), 'xhtml'); $cache->removeCache(); diff --git a/inc/fulltext.php b/inc/fulltext.php index 2f073acea..1afff25dd 100644 --- a/inc/fulltext.php +++ b/inc/fulltext.php @@ -125,17 +125,21 @@ function _ft_pageSearch(&$data) { * Returns the backlinks for a given page * * Uses the metadata index. + * + * @param string $id The id for which links shall be returned + * @param bool $ignore_perms Ignore the fact that pages are hidden or read-protected + * @return array The pages that contain links to the given page */ -function ft_backlinks($id){ - $result = array(); - +function ft_backlinks($id, $ignore_perms = false){ $result = idx_get_indexer()->lookupKey('relation_references', $id); if(!count($result)) return $result; // check ACL permissions foreach(array_keys($result) as $idx){ - if(isHiddenPage($result[$idx]) || auth_quickaclcheck($result[$idx]) < AUTH_READ || !page_exists($result[$idx], '', false)){ + if(($ignore_perms !== true && ( + isHiddenPage($result[$idx]) || auth_quickaclcheck($result[$idx]) < AUTH_READ + )) || !page_exists($result[$idx], '', false)){ unset($result[$idx]); } } -- cgit v1.2.3 From 0e1777cbe86faf809f67198704842a01034a1a98 Mon Sep 17 00:00:00 2001 From: Anika Henke Date: Wed, 31 Jul 2013 17:05:07 +0100 Subject: added aria attributes to tree and show/hide functions --- lib/scripts/behaviour.js | 2 ++ lib/scripts/tree.js | 20 +++++++++++++++++--- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/lib/scripts/behaviour.js b/lib/scripts/behaviour.js index f1c46bf4c..85ddf503e 100644 --- a/lib/scripts/behaviour.js +++ b/lib/scripts/behaviour.js @@ -5,6 +5,7 @@ * @author Adrian Lang */ jQuery.fn.dw_hide = function(fn) { + this.attr('aria-expanded', 'false'); return this.slideUp('fast', fn); }; @@ -15,6 +16,7 @@ jQuery.fn.dw_hide = function(fn) { * @author Adrian Lang */ jQuery.fn.dw_show = function(fn) { + this.attr('aria-expanded', 'true'); return this.slideDown('fast', fn); }; diff --git a/lib/scripts/tree.js b/lib/scripts/tree.js index 96763053d..c4e1da3f7 100644 --- a/lib/scripts/tree.js +++ b/lib/scripts/tree.js @@ -14,6 +14,12 @@ jQuery.fn.dw_tree = function(overrides) { init: function () { this.$obj.delegate(this.toggle_selector, 'click', this, this.toggle); + jQuery('ul:first', this.$obj).attr('role', 'tree'); + jQuery('ul', this.$obj).not(':first').attr('role', 'group'); + jQuery('li', this.$obj).attr('role', 'treeitem'); + jQuery('li.open > ul', this.$obj).attr('aria-expanded', 'true'); + jQuery('li.closed > ul', this.$obj).attr('aria-expanded', 'false'); + jQuery('li.closed', this.$obj).attr('aria-live', 'assertive'); }, /** @@ -35,8 +41,14 @@ jQuery.fn.dw_tree = function(overrides) { $listitem = $clicky.closest('li'); $sublist = $listitem.find('ul').first(); opening = $listitem.hasClass('closed'); - $listitem.toggleClass('open closed'); dw_tree.toggle_display($clicky, opening); + if ($sublist.is(':visible')) { + $listitem.removeClass('open').addClass('closed'); + $sublist.attr('aria-expanded', 'false'); + } else { + $listitem.removeClass('closed').addClass('open'); + $sublist.attr('aria-expanded', 'true'); + } // if already open, close by hiding the sublist if (!opening) { @@ -48,6 +60,8 @@ jQuery.fn.dw_tree = function(overrides) { $sublist.hide(); if (typeof data !== 'undefined') { $sublist.html(data); + $sublist.parent().attr('aria-busy', 'false').removeAttr('aria-live'); + jQuery('li.closed', $sublist).attr('aria-live', 'assertive'); } if ($listitem.hasClass('open')) { // Only show if user didn’t close the list since starting @@ -63,11 +77,11 @@ jQuery.fn.dw_tree = function(overrides) { } //prepare the new ul - $sublist = jQuery('
    '); + $sublist = jQuery('
      '); $listitem.append($sublist); timeout = window.setTimeout( - bind(show_sublist, '
    • loading...
    • '), dw_tree.throbber_delay); + bind(show_sublist, '
    • loading...
    • '), dw_tree.throbber_delay); dw_tree.load_data(function (data) { window.clearTimeout(timeout); -- cgit v1.2.3 From ffec100965184c6bf045f0096101768def108b43 Mon Sep 17 00:00:00 2001 From: Michael Hamann Date: Wed, 31 Jul 2013 17:30:08 +0200 Subject: Index media file usage in the metadata index and use it in ft_mediause() --- _test/tests/inc/fulltext_mediause.test.php | 77 ++++++++++++++++++++++++++++++ inc/fulltext.php | 48 +++++++------------ inc/indexer.php | 8 +++- inc/media.php | 2 +- inc/parser/metadata.php | 30 ++++++++++-- 5 files changed, 127 insertions(+), 38 deletions(-) create mode 100644 _test/tests/inc/fulltext_mediause.test.php diff --git a/_test/tests/inc/fulltext_mediause.test.php b/_test/tests/inc/fulltext_mediause.test.php new file mode 100644 index 000000000..9d5b2dc84 --- /dev/null +++ b/_test/tests/inc/fulltext_mediause.test.php @@ -0,0 +1,77 @@ + + */ +class fultext_mediause_test extends DokuWikiTest { + + public function test_internalmedia() { + saveWikiText('test:internalmedia_usage', '{{internalmedia.png}} {{..:internal media.png}}', 'Test initialization'); + idx_addPage('test:internalmedia_usage'); + + $this->assertEquals(array('test:internalmedia_usage'), ft_mediause('internal_media.png')); + $this->assertEquals(array('test:internalmedia_usage'), ft_mediause('test:internalmedia.png')); + } + + public function test_media_in_links() { + saveWikiText('test:medialinks', '[[doku>wiki:dokuwiki|{{wiki:logo.png}}]] [[http://www.example.com|{{example.png?200x800}}]]', 'Test init'); + idx_addPage('test:medialinks'); + + $this->assertEquals(array('test:medialinks'), ft_mediause('wiki:logo.png')); + $this->assertEquals(array('test:medialinks'), ft_mediause('test:example.png')); + } + + public function test_media_in_footnotes() { + saveWikiText('test:media_footnotes', '(({{footnote.png?20x50}} [[foonote|{{:footlink.png}}]]))', 'Test initialization'); + idx_addPage('test:media_footnotes'); + + $this->assertEquals(array('test:media_footnotes'), ft_mediause('test:footnote.png')); + $this->assertEquals(array('test:media_footnotes'), ft_mediause('footlink.png')); + } + + public function test_media_in_hidden_pages() { + global $conf; + $conf['hidepages'] = 'hidden:.*'; + saveWikiText('hidden:medias', '[[doku>wiki:dokuwiki|{{wiki:hiddenlogo.png}}]]', 'Test initialization'); + idx_addPage('hidden:medias'); + + $this->assertEquals(array(), ft_mediause('wiki:hiddenlogo.png')); + $this->assertEquals(array(), ft_mediause('wiki:hiddenlogo.png', false)); + $this->assertEquals(array('hidden:medias'), ft_mediause('wiki:hiddenlogo.png', true)); + } + + public function test_media_in_protected_pages() { + global $conf; + global $AUTH_ACL; + $conf['superuser'] = 'alice'; + $conf['useacl'] = 1; + + $AUTH_ACL = array( + '* @ALL 8', + 'secret:* @ALL 0', + ); + + $_SERVER['REMOTE_USER'] = 'eve'; + + saveWikiText('secret:medias', '[[doku>wiki:dokuwiki|{{wiki:secretlogo.png}}]]', 'Test initialization'); + idx_addPage('secret:medias'); + + $this->assertEquals(array(), ft_mediause('wiki:secretlogo.png')); + $this->assertEquals(array(), ft_mediause('wiki:secretlogo.png', false)); + $this->assertEquals(array('secret:medias'), ft_mediause('wiki:secretlogo.png', true)); + } + + public function test_media_in_deleted_pages() { + saveWikiText('test:internalmedia_usage', '{{internalmedia.png}} {{..:internal media.png}}', 'Test initialization'); + idx_addPage('test:internalmedia_usage'); + saveWikiText('test:internalmedia_usage', '', 'Deleted'); + + $this->assertEquals(array(), ft_mediause('internal_media.png')); + $this->assertEquals(array(), ft_mediause('test:internalmedia.png')); + } +} diff --git a/inc/fulltext.php b/inc/fulltext.php index 1afff25dd..c03126994 100644 --- a/inc/fulltext.php +++ b/inc/fulltext.php @@ -151,42 +151,28 @@ function ft_backlinks($id, $ignore_perms = false){ /** * Returns the pages that use a given media file * - * Does a quick lookup with the fulltext index, then - * evaluates the instructions of the found pages + * Uses the relation media metadata property and the metadata index. * - * Aborts after $max found results + * Note that before 2013-07-31 the second parameter was the maximum number of results and + * permissions were ignored. That's why the parameter is now checked to be explicitely set + * to true (with type bool) in order to be compatible with older uses of the function. + * + * @param string $id The media id to look for + * @param bool $ignore_perms Ignore hidden pages and acls (optional, default: false) + * @return array A list of pages that use the given media file */ -function ft_mediause($id,$max){ - if(!$max) $max = 1; // need to find at least one +function ft_mediause($id, $ignore_perms = false){ + $result = idx_get_indexer()->lookupKey('relation_media', $id); - $result = array(); + if(!count($result)) return $result; - // quick lookup of the mediafile - // FIXME use metadata key lookup - $media = noNS($id); - $matches = idx_lookup(idx_tokenizer($media)); - $docs = array_keys(ft_resultCombine(array_values($matches))); - if(!count($docs)) return $result; - - // go through all found pages - $found = 0; - $pcre = preg_quote($media,'/'); - foreach($docs as $doc){ - $ns = getNS($doc); - preg_match_all('/\{\{([^|}]*'.$pcre.'[^|}]*)(|[^}]+)?\}\}/i',rawWiki($doc),$matches); - foreach($matches[1] as $img){ - $img = trim($img); - if(media_isexternal($img)) continue; // skip external images - list($img) = explode('?',$img); // remove any parameters - resolve_mediaid($ns,$img,$exists); // resolve the possibly relative img - - if($img == $id){ // we have a match - $result[] = $doc; - $found++; - break; - } + // check ACL permissions + foreach(array_keys($result) as $idx){ + if(($ignore_perms !== true && ( + isHiddenPage($result[$idx]) || auth_quickaclcheck($result[$idx]) < AUTH_READ + )) || !page_exists($result[$idx], '', false)){ + unset($result[$idx]); } - if($found >= $max) break; } sort($result); diff --git a/inc/indexer.php b/inc/indexer.php index 2f3ab25dc..8f0ba7ec6 100644 --- a/inc/indexer.php +++ b/inc/indexer.php @@ -10,7 +10,7 @@ if(!defined('DOKU_INC')) die('meh.'); // Version tag used to force rebuild on upgrade -define('INDEXER_VERSION', 5); +define('INDEXER_VERSION', 6); // set the minimum token length to use in the index (note, this doesn't apply to numeric tokens) if (!defined('IDX_MINWORDLENGTH')) define('IDX_MINWORDLENGTH',2); @@ -1365,6 +1365,12 @@ function idx_addPage($page, $verbose=false, $force=false) { $metadata['relation_references'] = array_keys($references); else $metadata['relation_references'] = array(); + + if (($media = p_get_metadata($page, 'relation media', METADATA_RENDER_UNLIMITED)) !== null) + $metadata['relation_media'] = array_keys($media); + else + $metadata['relation_media'] = array(); + $data = compact('page', 'body', 'metadata', 'pid'); $evt = new Doku_Event('INDEXER_PAGE_ADD', $data); if ($evt->advise_before()) $data['body'] = $data['body'] . " " . rawWiki($page); diff --git a/inc/media.php b/inc/media.php index fbe1363ec..c76f2986c 100644 --- a/inc/media.php +++ b/inc/media.php @@ -178,7 +178,7 @@ function media_inuse($id) { global $conf; $mediareferences = array(); if($conf['refcheck']){ - $mediareferences = ft_mediause($id,$conf['refshow']); + $mediareferences = ft_mediause($id,true); if(!count($mediareferences)) { return false; } else { diff --git a/inc/parser/metadata.php b/inc/parser/metadata.php index e17b82f8b..d64fe4d77 100644 --- a/inc/parser/metadata.php +++ b/inc/parser/metadata.php @@ -282,8 +282,10 @@ class Doku_Renderer_metadata extends Doku_Renderer { function internallink($id, $name = NULL){ global $ID; - if(is_array($name)) + if(is_array($name)) { $this->_firstimage($name['src']); + if ($name['type'] == 'internalmedia') $this->_recordMediaUsage($name['src']); + } $default = $this->_simpleTitle($id); @@ -304,8 +306,10 @@ class Doku_Renderer_metadata extends Doku_Renderer { } function externallink($url, $name = NULL){ - if(is_array($name)) + if(is_array($name)) { $this->_firstimage($name['src']); + if ($name['type'] == 'internalmedia') $this->_recordMediaUsage($name['src']); + } if ($this->capture){ $this->doc .= $this->_getLinkTitle($name, '<' . $url . '>'); @@ -313,8 +317,10 @@ class Doku_Renderer_metadata extends Doku_Renderer { } function interwikilink($match, $name = NULL, $wikiName, $wikiUri){ - if(is_array($name)) + if(is_array($name)) { $this->_firstimage($name['src']); + if ($name['type'] == 'internalmedia') $this->_recordMediaUsage($name['src']); + } if ($this->capture){ list($wikiUri, $hash) = explode('#', $wikiUri, 2); @@ -324,8 +330,10 @@ class Doku_Renderer_metadata extends Doku_Renderer { } function windowssharelink($url, $name = NULL){ - if(is_array($name)) + if(is_array($name)) { $this->_firstimage($name['src']); + if ($name['type'] == 'internalmedia') $this->_recordMediaUsage($name['src']); + } if ($this->capture){ if ($name) $this->doc .= $name; @@ -334,8 +342,10 @@ class Doku_Renderer_metadata extends Doku_Renderer { } function emaillink($address, $name = NULL){ - if(is_array($name)) + if(is_array($name)) { $this->_firstimage($name['src']); + if ($name['type'] == 'internalmedia') $this->_recordMediaUsage($name['src']); + } if ($this->capture){ if ($name) $this->doc .= $name; @@ -347,6 +357,7 @@ class Doku_Renderer_metadata extends Doku_Renderer { $height=NULL, $cache=NULL, $linking=NULL){ if ($this->capture && $title) $this->doc .= '['.$title.']'; $this->_firstimage($src); + $this->_recordMediaUsage($src); } function externalmedia($src, $title=NULL, $align=NULL, $width=NULL, @@ -439,6 +450,15 @@ class Doku_Renderer_metadata extends Doku_Renderer { $this->firstimage = $src; } } + + function _recordMediaUsage($src) { + global $ID; + + list ($src, $hash) = explode('#', $src, 2); + if (media_isexternal($src)) return; + resolve_mediaid(getNS($ID), $src, $exists); + $this->meta['relation']['media'][$src] = $exists; + } } //Setup VIM: ex: et ts=4 : -- cgit v1.2.3 From 0320882f767e5685df9d7ac4bec5a3e3f1b1f216 Mon Sep 17 00:00:00 2001 From: Michael Hamann Date: Wed, 31 Jul 2013 17:57:58 +0200 Subject: Remove search_references() and the refshow configuration option The refshow configuration option wasn't used as described anymore already in the latest release and after the introduction of the media usage index the parameter is also no longer relevant for internal optimization. The only place where it was still used is the no longer used search_references()-function which is removed here, too. --- conf/dokuwiki.php | 1 - inc/search.php | 39 ------------------------- lib/plugins/config/lang/ar/lang.php | 1 - lib/plugins/config/lang/bg/lang.php | 1 - lib/plugins/config/lang/ca-valencia/lang.php | 1 - lib/plugins/config/lang/ca/lang.php | 1 - lib/plugins/config/lang/cs/lang.php | 1 - lib/plugins/config/lang/da/lang.php | 1 - lib/plugins/config/lang/de-informal/lang.php | 1 - lib/plugins/config/lang/de/lang.php | 1 - lib/plugins/config/lang/el/lang.php | 1 - lib/plugins/config/lang/en/lang.php | 1 - lib/plugins/config/lang/eo/lang.php | 1 - lib/plugins/config/lang/es/lang.php | 1 - lib/plugins/config/lang/eu/lang.php | 1 - lib/plugins/config/lang/fa/lang.php | 1 - lib/plugins/config/lang/fi/lang.php | 1 - lib/plugins/config/lang/fr/lang.php | 1 - lib/plugins/config/lang/gl/lang.php | 1 - lib/plugins/config/lang/he/lang.php | 1 - lib/plugins/config/lang/hu/lang.php | 1 - lib/plugins/config/lang/ia/lang.php | 1 - lib/plugins/config/lang/it/lang.php | 1 - lib/plugins/config/lang/ja/lang.php | 1 - lib/plugins/config/lang/ko/lang.php | 1 - lib/plugins/config/lang/la/lang.php | 1 - lib/plugins/config/lang/lv/lang.php | 1 - lib/plugins/config/lang/mr/lang.php | 1 - lib/plugins/config/lang/nl/lang.php | 1 - lib/plugins/config/lang/no/lang.php | 1 - lib/plugins/config/lang/pl/lang.php | 1 - lib/plugins/config/lang/pt-br/lang.php | 1 - lib/plugins/config/lang/pt/lang.php | 1 - lib/plugins/config/lang/ro/lang.php | 1 - lib/plugins/config/lang/ru/lang.php | 1 - lib/plugins/config/lang/sk/lang.php | 1 - lib/plugins/config/lang/sl/lang.php | 1 - lib/plugins/config/lang/sq/lang.php | 1 - lib/plugins/config/lang/sr/lang.php | 1 - lib/plugins/config/lang/sv/lang.php | 1 - lib/plugins/config/lang/tr/lang.php | 1 - lib/plugins/config/lang/uk/lang.php | 1 - lib/plugins/config/lang/zh-tw/lang.php | 1 - lib/plugins/config/lang/zh/lang.php | 1 - lib/plugins/config/settings/config.metadata.php | 1 - 45 files changed, 83 deletions(-) diff --git a/conf/dokuwiki.php b/conf/dokuwiki.php index f5524de6b..bdc9739d1 100644 --- a/conf/dokuwiki.php +++ b/conf/dokuwiki.php @@ -96,7 +96,6 @@ $conf['target']['windows'] = ''; /* Media Settings */ $conf['mediarevisions'] = 1; //enable/disable media revisions $conf['refcheck'] = 1; //check for references before deleting media files -$conf['refshow'] = 0; //how many references should be shown, 5 is a good value $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) diff --git a/inc/search.php b/inc/search.php index 6927fff5f..884aa7b23 100644 --- a/inc/search.php +++ b/inc/search.php @@ -273,45 +273,6 @@ function search_allpages(&$data,$base,$file,$type,$lvl,$opts){ return true; } -/** - * Reference search - * This fuction searches for existing references to a given media file - * and returns an array with the found pages. It doesn't pay any - * attention to ACL permissions to find every reference. The caller - * must check if the user has the appropriate rights to see the found - * page and eventually have to prevent the result from displaying. - * - * @param array $data Reference to the result data structure - * @param string $base Base usually $conf['datadir'] - * @param string $file current file or directory relative to $base - * @param char $type Type either 'd' for directory or 'f' for file - * @param int $lvl Current recursion depht - * @param mixed $opts option array as given to search() - * - * $opts['query'] is the demanded media file name - * - * @author Andreas Gohr - * @author Matthias Grimm - */ -function search_reference(&$data,$base,$file,$type,$lvl,$opts){ - global $conf; - - //we do nothing with directories - if($type == 'd') return true; - - //only search txt files - if(substr($file,-4) != '.txt') return true; - - //we finish after 'cnt' references found. The return value - //'false' will skip subdirectories to speed search up. - $cnt = $conf['refshow'] > 0 ? $conf['refshow'] : 1; - if(count($data) >= $cnt) return false; - - $reg = '\{\{ *\:?'.$opts['query'].' *(\|.*)?\}\}'; - search_regex($data,$base,$file,$reg,array($opts['query'])); - return true; -} - /* ------------- helper functions below -------------- */ /** diff --git a/lib/plugins/config/lang/ar/lang.php b/lib/plugins/config/lang/ar/lang.php index 76c155812..11b59dacd 100644 --- a/lib/plugins/config/lang/ar/lang.php +++ b/lib/plugins/config/lang/ar/lang.php @@ -104,7 +104,6 @@ $lang['target____media'] = 'النافذة الهدف لروابط الو $lang['target____windows'] = 'النافذة الهدف لروابط النوافذ'; $lang['mediarevisions'] = 'تفعيل إصدارات الوسائط؟'; $lang['refcheck'] = 'التحقق من مرجع الوسائط'; -$lang['refshow'] = 'عدد مراجع الوسائط لتعرض'; $lang['gdlib'] = 'اصدار مكتبة GD'; $lang['im_convert'] = 'المسار إلى اداة تحويل ImageMagick'; $lang['jpg_quality'] = 'دقة ضغط JPG (0-100)'; diff --git a/lib/plugins/config/lang/bg/lang.php b/lib/plugins/config/lang/bg/lang.php index 43c961bfc..1a370eafe 100644 --- a/lib/plugins/config/lang/bg/lang.php +++ b/lib/plugins/config/lang/bg/lang.php @@ -136,7 +136,6 @@ $lang['target____windows'] = 'Прозорец за препратки към /* Media Settings */ $lang['mediarevisions'] = 'Да се пазят ли стари версии на качените файлове (Mediarevisions)?'; $lang['refcheck'] = 'Проверка за препратка към медия, преди да бъде изтрита'; -$lang['refshow'] = 'Брой на показваните медийни препратки'; $lang['gdlib'] = 'Версия на GD Lib'; $lang['im_convert'] = 'Път до инструмента за трансформация на ImageMagick'; $lang['jpg_quality'] = 'Качество на JPG компресията (0-100)'; diff --git a/lib/plugins/config/lang/ca-valencia/lang.php b/lib/plugins/config/lang/ca-valencia/lang.php index 4a8c10895..dd319bdb7 100644 --- a/lib/plugins/config/lang/ca-valencia/lang.php +++ b/lib/plugins/config/lang/ca-valencia/lang.php @@ -62,7 +62,6 @@ $lang['camelcase'] = 'Utilisar CamelCase per als vínculs'; $lang['deaccent'] = 'Depurar els noms de pàgines'; $lang['useheading'] = 'Utilisar el primer titular per al nom de pàgina'; $lang['refcheck'] = 'Comprovar referències a mijos'; -$lang['refshow'] = 'Número de referències a mijos a mostrar'; $lang['allowdebug'] = 'Permetre depurar (¡desactivar quan no es necessite!)'; $lang['usewordblock'] = 'Bloquejar spam basant-se en una llista de paraules'; $lang['indexdelay'] = 'Retart abans d\'indexar (seg.)'; diff --git a/lib/plugins/config/lang/ca/lang.php b/lib/plugins/config/lang/ca/lang.php index 205d7aa6b..6de8caf02 100644 --- a/lib/plugins/config/lang/ca/lang.php +++ b/lib/plugins/config/lang/ca/lang.php @@ -102,7 +102,6 @@ $lang['target____extern'] = 'Finestra de destinació en enllaços externs'; $lang['target____media'] = 'Finestra de destinació en enllaços de mitjans'; $lang['target____windows'] = 'Finestra de destinació en enllaços de Windows'; $lang['refcheck'] = 'Comprova la referència en els fitxers de mitjans'; -$lang['refshow'] = 'Nombre de referències de mitjans per mostrar'; $lang['gdlib'] = 'Versió GD Lib'; $lang['im_convert'] = 'Camí de la utilitat convert d\'ImageMagick'; $lang['jpg_quality'] = 'Qualitat de compressió JPEG (0-100)'; diff --git a/lib/plugins/config/lang/cs/lang.php b/lib/plugins/config/lang/cs/lang.php index d35ebec9b..921abb54a 100644 --- a/lib/plugins/config/lang/cs/lang.php +++ b/lib/plugins/config/lang/cs/lang.php @@ -119,7 +119,6 @@ $lang['target____media'] = 'Cílové okno pro odkazy na média'; $lang['target____windows'] = 'Cílové okno pro odkazy na windows sdílení'; $lang['mediarevisions'] = 'Aktivovat revize souborů'; $lang['refcheck'] = 'Kontrolovat odkazy na média (před vymazáním)'; -$lang['refshow'] = 'Počet zobrazených odkazů na média'; $lang['gdlib'] = 'Verze GD knihovny'; $lang['im_convert'] = 'Cesta k nástroji convert z balíku ImageMagick'; $lang['jpg_quality'] = 'Kvalita komprese JPEG (0-100)'; diff --git a/lib/plugins/config/lang/da/lang.php b/lib/plugins/config/lang/da/lang.php index 239a4986f..79d8dc852 100644 --- a/lib/plugins/config/lang/da/lang.php +++ b/lib/plugins/config/lang/da/lang.php @@ -110,7 +110,6 @@ $lang['target____media'] = 'Målvindue for mediehenvisninger'; $lang['target____windows'] = 'Målvindue til Windows-henvisninger'; $lang['mediarevisions'] = 'Akvtivér media udgaver?'; $lang['refcheck'] = 'Mediehenvisningerkontrol'; -$lang['refshow'] = 'Antal viste mediehenvisninger'; $lang['gdlib'] = 'Udgave af GD Lib'; $lang['im_convert'] = 'Sti til ImageMagick\'s omdannerværktøj'; $lang['jpg_quality'] = 'JPG komprimeringskvalitet (0-100)'; diff --git a/lib/plugins/config/lang/de-informal/lang.php b/lib/plugins/config/lang/de-informal/lang.php index 10fa363dc..81cdc0e70 100644 --- a/lib/plugins/config/lang/de-informal/lang.php +++ b/lib/plugins/config/lang/de-informal/lang.php @@ -108,7 +108,6 @@ $lang['target____media'] = 'Zielfenstername für Medienlinks'; $lang['target____windows'] = 'Zielfenstername für Windows-Freigaben-Links'; $lang['mediarevisions'] = 'Media-Revisionen (ältere Versionen) aktivieren?'; $lang['refcheck'] = 'Auf Verwendung beim Löschen von Media-Dateien testen'; -$lang['refshow'] = 'Wie viele Verwendungsorte der Media-Datei zeigen'; $lang['gdlib'] = 'GD Lib Version'; $lang['im_convert'] = 'Pfad zu ImageMagicks-Konvertierwerkzeug'; $lang['jpg_quality'] = 'JPEG Kompressionsqualität (0-100)'; diff --git a/lib/plugins/config/lang/de/lang.php b/lib/plugins/config/lang/de/lang.php index dd29f8038..f2ada5f7b 100644 --- a/lib/plugins/config/lang/de/lang.php +++ b/lib/plugins/config/lang/de/lang.php @@ -78,7 +78,6 @@ $lang['camelcase'] = 'CamelCase-Verlinkungen verwenden'; $lang['deaccent'] = 'Seitennamen bereinigen'; $lang['useheading'] = 'Erste Überschrift als Seitennamen verwenden'; $lang['refcheck'] = 'Auf Verwendung beim Löschen von Media-Dateien testen'; -$lang['refshow'] = 'Wiev iele Verwendungsorte der Media-Datei zeigen'; $lang['allowdebug'] = 'Debug-Ausgaben erlauben Abschalten wenn nicht benötigt!'; $lang['mediarevisions'] = 'Media-Revisionen (ältere Versionen) aktivieren?'; $lang['usewordblock'] = 'Spam-Blocking benutzen'; diff --git a/lib/plugins/config/lang/el/lang.php b/lib/plugins/config/lang/el/lang.php index d2801e507..e766c1a4c 100644 --- a/lib/plugins/config/lang/el/lang.php +++ b/lib/plugins/config/lang/el/lang.php @@ -111,7 +111,6 @@ $lang['target____media'] = 'Παράθυρο-στόχος για συνδ $lang['target____windows'] = 'Παράθυρο-στόχος για συνδέσμους σε Windows shares'; $lang['mediarevisions'] = 'Ενεργοποίηση Mediarevisions;'; $lang['refcheck'] = 'Πριν τη διαγραφή ενός αρχείου να ελέγχεται η ύπαρξη σελίδων που το χρησιμοποιούν'; -$lang['refshow'] = 'Εμφανιζόμενος αριθμός σελίδων που χρησιμοποιούν ένα αρχείο'; $lang['gdlib'] = 'Έκδοση βιβλιοθήκης GD'; $lang['im_convert'] = 'Διαδρομή προς το εργαλείο μετατροπής εικόνων του ImageMagick'; $lang['jpg_quality'] = 'Ποιότητα συμπίεσης JPG (0-100)'; diff --git a/lib/plugins/config/lang/en/lang.php b/lib/plugins/config/lang/en/lang.php index 83c843b3a..2d012701b 100644 --- a/lib/plugins/config/lang/en/lang.php +++ b/lib/plugins/config/lang/en/lang.php @@ -134,7 +134,6 @@ $lang['target____windows'] = 'Target window for windows links'; /* Media Settings */ $lang['mediarevisions'] = 'Enable Mediarevisions?'; $lang['refcheck'] = 'Check if a media file is still in use before deleting it'; -$lang['refshow'] = 'Number of media references to show when the above setting is enabled'; $lang['gdlib'] = 'GD Lib version'; $lang['im_convert'] = 'Path to ImageMagick\'s convert tool'; $lang['jpg_quality'] = 'JPG compression quality (0-100)'; diff --git a/lib/plugins/config/lang/eo/lang.php b/lib/plugins/config/lang/eo/lang.php index 36f865c28..b3300c1b5 100644 --- a/lib/plugins/config/lang/eo/lang.php +++ b/lib/plugins/config/lang/eo/lang.php @@ -108,7 +108,6 @@ $lang['target____media'] = 'Parametro "target" (celo) por aŭdvidaĵaj lig $lang['target____windows'] = 'Parametro "target" (celo) por Vindozaj ligiloj'; $lang['mediarevisions'] = 'Ĉu ebligi reviziadon de aŭdvidaĵoj?'; $lang['refcheck'] = 'Kontrolo por referencoj al aŭdvidaĵoj'; -$lang['refshow'] = 'Nombro da referencoj al aŭdvidaĵoj por montri'; $lang['gdlib'] = 'Versio de GD-Lib'; $lang['im_convert'] = 'Pado al la konvertilo de ImageMagick'; $lang['jpg_quality'] = 'Kompaktiga kvalito de JPG (0-100)'; diff --git a/lib/plugins/config/lang/es/lang.php b/lib/plugins/config/lang/es/lang.php index 5d03efb60..3a2db95b8 100644 --- a/lib/plugins/config/lang/es/lang.php +++ b/lib/plugins/config/lang/es/lang.php @@ -121,7 +121,6 @@ $lang['target____media'] = 'Ventana para enlaces a medios'; $lang['target____windows'] = 'Ventana para enlaces a ventanas'; $lang['mediarevisions'] = '¿Habilitar Mediarevisions?'; $lang['refcheck'] = 'Control de referencia a medios'; -$lang['refshow'] = 'Número de referencias a medios a mostrar'; $lang['gdlib'] = 'Versión de GD Lib'; $lang['im_convert'] = 'Ruta a la herramienta de conversión de ImageMagick'; $lang['jpg_quality'] = 'Calidad de compresión de JPG (0-100)'; diff --git a/lib/plugins/config/lang/eu/lang.php b/lib/plugins/config/lang/eu/lang.php index 4dd3ff351..280e57df9 100644 --- a/lib/plugins/config/lang/eu/lang.php +++ b/lib/plugins/config/lang/eu/lang.php @@ -97,7 +97,6 @@ $lang['target____media'] = 'Multimedia estekentzat helburu leihoa'; $lang['target____windows'] = 'Leihoen estekentzat helburu leihoa'; $lang['mediarevisions'] = 'Media rebisioak gaitu?'; $lang['refcheck'] = 'Multimedia erreferentzia kontrolatu'; -$lang['refshow'] = 'Erakusteko multimedia erreferentzia kopurua'; $lang['gdlib'] = 'GD Lib bertsioa'; $lang['im_convert'] = 'ImageMagick-en aldaketa tresnara bidea'; $lang['jpg_quality'] = 'JPG konprimitze kalitatea (0-100)'; diff --git a/lib/plugins/config/lang/fa/lang.php b/lib/plugins/config/lang/fa/lang.php index 34c76780c..229fe012e 100644 --- a/lib/plugins/config/lang/fa/lang.php +++ b/lib/plugins/config/lang/fa/lang.php @@ -106,7 +106,6 @@ $lang['target____media'] = 'پنجره‌ی هدف در پیوند‌ها $lang['target____windows'] = 'پنجره‌ی هدف در پیوند‌های پنجره‌ای'; $lang['mediarevisions'] = 'تجدید نظر رسانه ، فعال؟'; $lang['refcheck'] = 'بررسی کردن مرجع رسانه‌ها'; -$lang['refshow'] = 'تعداد مراجعی که برای یک رسانه نمایش داده شود'; $lang['gdlib'] = 'نگارش کتاب‌خانه‌ی GD'; $lang['im_convert'] = 'مسیر ابزار convert از برنامه‌ی ImageMagick'; $lang['jpg_quality'] = 'کیفیت فشرده سازی JPEG (از 0 تا 100)'; diff --git a/lib/plugins/config/lang/fi/lang.php b/lib/plugins/config/lang/fi/lang.php index 990852f99..a5075d2cf 100644 --- a/lib/plugins/config/lang/fi/lang.php +++ b/lib/plugins/config/lang/fi/lang.php @@ -105,7 +105,6 @@ $lang['target____media'] = 'Kohdeikkuna media-linkeissä'; $lang['target____windows'] = 'Kohdeikkuna Windows-linkeissä'; $lang['mediarevisions'] = 'Otetaan käyttään Media-versiointi'; $lang['refcheck'] = 'Mediaviitteen tarkistus'; -$lang['refshow'] = 'Montako mediaviitettä näytetään'; $lang['gdlib'] = 'GD Lib versio'; $lang['im_convert'] = 'ImageMagick-muunnostyökalun polku'; $lang['jpg_quality'] = 'JPG pakkauslaatu (0-100)'; diff --git a/lib/plugins/config/lang/fr/lang.php b/lib/plugins/config/lang/fr/lang.php index f9e89f603..a7b3d5e3b 100644 --- a/lib/plugins/config/lang/fr/lang.php +++ b/lib/plugins/config/lang/fr/lang.php @@ -118,7 +118,6 @@ $lang['target____media'] = 'Cible pour liens média'; $lang['target____windows'] = 'Cible pour liens vers partages Windows'; $lang['mediarevisions'] = 'Activer les révisions (gestion de versions) des médias'; $lang['refcheck'] = 'Vérifier si un média est toujours utilisé avant de le supprimer'; -$lang['refshow'] = 'Nombre de références de média à montrer lorsque le paramètre précédent est actif'; $lang['gdlib'] = 'Version de la librairie GD'; $lang['im_convert'] = 'Chemin vers l\'outil de conversion ImageMagick'; $lang['jpg_quality'] = 'Qualité de la compression JPEG (0-100)'; diff --git a/lib/plugins/config/lang/gl/lang.php b/lib/plugins/config/lang/gl/lang.php index 21fe17452..0dafd9271 100644 --- a/lib/plugins/config/lang/gl/lang.php +++ b/lib/plugins/config/lang/gl/lang.php @@ -104,7 +104,6 @@ $lang['target____media'] = 'Fiestra de destino para as ligazóns de media' $lang['target____windows'] = 'Fiestra de destino para as ligazóns de fiestras'; $lang['mediarevisions'] = 'Habilitar revisións dos arquivos-media?'; $lang['refcheck'] = 'Comprobar a referencia media'; -$lang['refshow'] = 'Número de referencias media a amosar'; $lang['gdlib'] = 'Versión da Libraría GD'; $lang['im_convert'] = 'Ruta deica a ferramenta de conversión ImageMagick'; $lang['jpg_quality'] = 'Calidade de compresión dos JPG (0-100)'; diff --git a/lib/plugins/config/lang/he/lang.php b/lib/plugins/config/lang/he/lang.php index b200082c9..687072764 100644 --- a/lib/plugins/config/lang/he/lang.php +++ b/lib/plugins/config/lang/he/lang.php @@ -60,7 +60,6 @@ $lang['camelcase'] = 'השתמש בראשיות גדולות לקי $lang['deaccent'] = 'נקה שמות דפים'; $lang['useheading'] = 'השתמש בכותרת הראשונה לשם הדף'; $lang['refcheck'] = 'בדוק שיוך מדיה'; -$lang['refshow'] = 'מספר שיוכי המדיה שיוצגו'; $lang['allowdebug'] = 'אפשר דיבוג יש לבטל אם אין צורך!'; $lang['usewordblock'] = 'חסימת דואר זבל לפי רשימת מילים'; $lang['indexdelay'] = 'השהיה בטרם הכנסה לאינדקס (שניות)'; diff --git a/lib/plugins/config/lang/hu/lang.php b/lib/plugins/config/lang/hu/lang.php index c68cf4337..6c47e09a3 100644 --- a/lib/plugins/config/lang/hu/lang.php +++ b/lib/plugins/config/lang/hu/lang.php @@ -108,7 +108,6 @@ $lang['target____media'] = 'Cél-ablak média-fájl hivatkozásokhoz'; $lang['target____windows'] = 'Cél-ablak Windows hivatkozásokhoz'; $lang['mediarevisions'] = 'Médiafájlok verziókövetésének engedélyezése'; $lang['refcheck'] = 'Médiafájlok hivatkozásainak ellenőrzése'; -$lang['refshow'] = 'Médiafájlok hivatkozásainak maximálisan mutatott szintje'; $lang['gdlib'] = 'GD Lib verzió'; $lang['im_convert'] = 'Útvonal az ImageMagick csomag convert parancsához'; $lang['jpg_quality'] = 'JPG tömörítés minősége (0-100)'; diff --git a/lib/plugins/config/lang/ia/lang.php b/lib/plugins/config/lang/ia/lang.php index fdb9d954e..1f4e881bb 100644 --- a/lib/plugins/config/lang/ia/lang.php +++ b/lib/plugins/config/lang/ia/lang.php @@ -59,7 +59,6 @@ $lang['camelcase'] = 'Usar CamelCase pro ligamines'; $lang['deaccent'] = 'Nomines nette de paginas'; $lang['useheading'] = 'Usar le prime titulo como nomine de pagina'; $lang['refcheck'] = 'Verification de referentias multimedia'; -$lang['refshow'] = 'Numero de referentias multimedia a monstrar'; $lang['allowdebug'] = 'Permitter debugging disactiva si non necessari!'; $lang['usewordblock'] = 'Blocar spam a base de lista de parolas'; $lang['indexdelay'] = 'Retardo ante generation de indice (secundas)'; diff --git a/lib/plugins/config/lang/it/lang.php b/lib/plugins/config/lang/it/lang.php index 62dd00f0c..d2272075a 100644 --- a/lib/plugins/config/lang/it/lang.php +++ b/lib/plugins/config/lang/it/lang.php @@ -114,7 +114,6 @@ $lang['target____media'] = 'Finestra di destinazione per i collegamenti ai $lang['target____windows'] = 'Finestra di destinazione per i collegamenti alle risorse condivise'; $lang['mediarevisions'] = 'Abilita Mediarevisions?'; $lang['refcheck'] = 'Controlla i riferimenti ai file'; -$lang['refshow'] = 'Numero di riferimenti da visualizzare'; $lang['gdlib'] = 'Versione GD Lib '; $lang['im_convert'] = 'Percorso per il convertitore di ImageMagick'; $lang['jpg_quality'] = 'Qualità di compressione JPG (0-100)'; diff --git a/lib/plugins/config/lang/ja/lang.php b/lib/plugins/config/lang/ja/lang.php index 807436cca..15eadf731 100644 --- a/lib/plugins/config/lang/ja/lang.php +++ b/lib/plugins/config/lang/ja/lang.php @@ -109,7 +109,6 @@ $lang['target____media'] = 'メディアリンクの表示先'; $lang['target____windows'] = 'Windowsリンクの表示先'; $lang['mediarevisions'] = 'メディアファイルの履歴を有効にしますか?'; $lang['refcheck'] = 'メディア参照元チェック'; -$lang['refshow'] = 'メディア参照元表示数'; $lang['gdlib'] = 'GDlibバージョン'; $lang['im_convert'] = 'ImageMagick変換ツールへのパス'; $lang['jpg_quality'] = 'JPG圧縮品質(0-100)'; diff --git a/lib/plugins/config/lang/ko/lang.php b/lib/plugins/config/lang/ko/lang.php index f0f7f60fa..74fe3d8a0 100644 --- a/lib/plugins/config/lang/ko/lang.php +++ b/lib/plugins/config/lang/ko/lang.php @@ -109,7 +109,6 @@ $lang['target____media'] = '미디어 링크에 대한 타겟 창'; $lang['target____windows'] = '창 링크에 대한 타겟 창'; $lang['mediarevisions'] = '미디어 판 관리를 사용하겠습니까?'; $lang['refcheck'] = '미디어 파일을 삭제하기 전에 사용하고 있는지 검사'; -$lang['refshow'] = '위의 설정이 활성화되었을 때 보여줄 미디어 참고 수'; $lang['gdlib'] = 'GD 라이브러리 버전'; $lang['im_convert'] = 'ImageMagick 변환 도구 위치'; $lang['jpg_quality'] = 'JPG 압축 품질 (0-100)'; diff --git a/lib/plugins/config/lang/la/lang.php b/lib/plugins/config/lang/la/lang.php index 057e69974..2aff60753 100644 --- a/lib/plugins/config/lang/la/lang.php +++ b/lib/plugins/config/lang/la/lang.php @@ -58,7 +58,6 @@ $lang['camelcase'] = 'SignaContinua nexis apta facere'; $lang['deaccent'] = 'Titulus paginarum abrogare'; $lang['useheading'] = 'Capite primo ut titulo paginae uti'; $lang['refcheck'] = 'Documenta uisiua inspicere'; -$lang['refshow'] = 'Numerus documentorum ostendorum'; $lang['allowdebug'] = 'ineptum facias si non necessarium! aptum facere'; $lang['usewordblock'] = 'Malum interretiale ob uerba delere'; $lang['indexdelay'] = 'Tempus transitum in ordinando (sec)'; diff --git a/lib/plugins/config/lang/lv/lang.php b/lib/plugins/config/lang/lv/lang.php index 3adfd1871..7fcf0fa45 100644 --- a/lib/plugins/config/lang/lv/lang.php +++ b/lib/plugins/config/lang/lv/lang.php @@ -95,7 +95,6 @@ $lang['target____extern'] = 'Kur atvērt ārējās saites'; $lang['target____media'] = 'Kur atvērt mēdiju saites'; $lang['target____windows'] = 'Kur atvērt saites uz tīkla mapēm'; $lang['refcheck'] = 'Pārbaudīt saites uz mēdiju failiem'; -$lang['refshow'] = 'Cik saites uz mēdiju failiem rādīt'; $lang['gdlib'] = 'GD Lib versija'; $lang['im_convert'] = 'Ceļš uz ImageMagick convert rīku'; $lang['jpg_quality'] = 'JPG saspiešanas kvalitāte'; diff --git a/lib/plugins/config/lang/mr/lang.php b/lib/plugins/config/lang/mr/lang.php index 4f33bfa7c..deef82690 100644 --- a/lib/plugins/config/lang/mr/lang.php +++ b/lib/plugins/config/lang/mr/lang.php @@ -62,7 +62,6 @@ $lang['camelcase'] = 'लिंकसाठी कॅमलकेस $lang['deaccent'] = 'सरळ्सोट पृष्ठ नाम'; $lang['useheading'] = 'पहिलं शीर्षक पृष्ठ नाम म्हणुन वापरा'; $lang['refcheck'] = 'दृक्श्राव्य माध्यमाचा संदर्भ तपासा'; -$lang['refshow'] = 'दृक्श्राव्य माध्यामाचे संदर्भ दाखवण्याची संख्या'; $lang['allowdebug'] = 'डिबगची परवानगी गरज नसल्यास बंद ठेवा !'; $lang['usewordblock'] = 'भंकस मजकूर थोपवण्यासाठी शब्दसमुह वापरा'; $lang['indexdelay'] = 'सूचीकरणापूर्वीचा अवकाश ( सेकंदात )'; diff --git a/lib/plugins/config/lang/nl/lang.php b/lib/plugins/config/lang/nl/lang.php index 26ea3d8c1..9aa17c23d 100644 --- a/lib/plugins/config/lang/nl/lang.php +++ b/lib/plugins/config/lang/nl/lang.php @@ -113,7 +113,6 @@ $lang['target____media'] = 'Doelvenster voor medialinks'; $lang['target____windows'] = 'Doelvenster voor windows links'; $lang['mediarevisions'] = 'Mediarevisies activeren?'; $lang['refcheck'] = 'Controleer of er verwijzingen bestaan naar een mediabestand voor het wijderen'; -$lang['refshow'] = 'Aantal te tonen mediaverwijzingen'; $lang['gdlib'] = 'Versie GD Lib '; $lang['im_convert'] = 'Path naar ImageMagick\'s convert tool'; $lang['jpg_quality'] = 'JPG compressiekwaliteit (0-100)'; diff --git a/lib/plugins/config/lang/no/lang.php b/lib/plugins/config/lang/no/lang.php index b01637dd1..c049c643a 100644 --- a/lib/plugins/config/lang/no/lang.php +++ b/lib/plugins/config/lang/no/lang.php @@ -76,7 +76,6 @@ $lang['camelcase'] = 'Gjør KamelKasse til lenke automatisk'; $lang['deaccent'] = 'Rensk sidenavn'; $lang['useheading'] = 'Bruk første overskrift som tittel'; $lang['refcheck'] = 'Sjekk referanser før mediafiler slettes'; -$lang['refshow'] = 'Antall viste referanser til mediafiler'; $lang['allowdebug'] = 'Tillat feilsøking skru av om det ikke behøves!'; $lang['mediarevisions'] = 'Slå på mediaversjonering?'; $lang['usewordblock'] = 'Blokker søppel basert på ordliste'; diff --git a/lib/plugins/config/lang/pl/lang.php b/lib/plugins/config/lang/pl/lang.php index 8441722cd..ede824d75 100644 --- a/lib/plugins/config/lang/pl/lang.php +++ b/lib/plugins/config/lang/pl/lang.php @@ -112,7 +112,6 @@ $lang['target____media'] = 'Okno docelowe odnośników do plików'; $lang['target____windows'] = 'Okno docelowe odnośników zasobów Windows'; $lang['mediarevisions'] = 'Włączyć wersjonowanie multimediów?'; $lang['refcheck'] = 'Sprawdzanie odwołań przed usunięciem pliku'; -$lang['refshow'] = 'Ilość pokazywanych odwołań do pliku'; $lang['gdlib'] = 'Wersja biblioteki GDLib'; $lang['im_convert'] = 'Ścieżka do programu imagemagick'; $lang['jpg_quality'] = 'Jakość kompresji JPG (0-100)'; diff --git a/lib/plugins/config/lang/pt-br/lang.php b/lib/plugins/config/lang/pt-br/lang.php index 85218439a..6633ab0c4 100644 --- a/lib/plugins/config/lang/pt-br/lang.php +++ b/lib/plugins/config/lang/pt-br/lang.php @@ -116,7 +116,6 @@ $lang['target____media'] = 'Parâmetro "target" para links de mídia'; $lang['target____windows'] = 'Parâmetro "target" para links do Windows'; $lang['mediarevisions'] = 'Habilitar revisões de mídias?'; $lang['refcheck'] = 'Verificação de referência da mídia'; -$lang['refshow'] = 'Número de referências de mídia a exibir'; $lang['gdlib'] = 'Versão da biblioteca "GD Lib"'; $lang['im_convert'] = 'Caminho para a ferramenta de conversão ImageMagick'; $lang['jpg_quality'] = 'Qualidade de compressão do JPG (0-100)'; diff --git a/lib/plugins/config/lang/pt/lang.php b/lib/plugins/config/lang/pt/lang.php index d0fe0ac0d..681ff487f 100644 --- a/lib/plugins/config/lang/pt/lang.php +++ b/lib/plugins/config/lang/pt/lang.php @@ -63,7 +63,6 @@ $lang['camelcase'] = 'Usar CamelCase'; $lang['deaccent'] = 'Nomes das páginas sem acentos'; $lang['useheading'] = 'Usar o primeiro cabeçalho para o nome da página'; $lang['refcheck'] = 'Verificação de referência da media'; -$lang['refshow'] = 'Número de referências de media a exibir'; $lang['allowdebug'] = 'Permitir depuração desabilite se não for necessário!'; $lang['usewordblock'] = 'Bloquear spam baseado em lista de palavras (wordlist)'; $lang['indexdelay'] = 'Tempo de espera antes da indexação (seg)'; diff --git a/lib/plugins/config/lang/ro/lang.php b/lib/plugins/config/lang/ro/lang.php index 72b205b90..5e853f7d0 100644 --- a/lib/plugins/config/lang/ro/lang.php +++ b/lib/plugins/config/lang/ro/lang.php @@ -69,7 +69,6 @@ $lang['camelcase'] = 'Foloseşte CamelCase pentru legături'; $lang['deaccent'] = 'numedepagină curate'; $lang['useheading'] = 'Foloseşte primul titlu pentru numele paginii'; $lang['refcheck'] = 'Verificare referinţă media'; -$lang['refshow'] = 'Numărul de referinţe media de arătat'; $lang['allowdebug'] = 'Permite depanarea dezactivaţi dacă cu e necesar!'; $lang['mediarevisions'] = 'Activare Revizii Media?'; $lang['usewordblock'] = 'Blochează spam-ul pe baza listei de cuvinte'; diff --git a/lib/plugins/config/lang/ru/lang.php b/lib/plugins/config/lang/ru/lang.php index 42cbbd35a..cdafacf8f 100644 --- a/lib/plugins/config/lang/ru/lang.php +++ b/lib/plugins/config/lang/ru/lang.php @@ -115,7 +115,6 @@ $lang['target____media'] = 'target для ссылок на медиафа $lang['target____windows'] = 'target для ссылок на сетевые каталоги'; $lang['mediarevisions'] = 'Включение версий медиафайлов'; $lang['refcheck'] = 'Проверять ссылки на медиафайлы'; -$lang['refshow'] = 'Показывать ссылок на медиафайлы'; $lang['gdlib'] = 'Версия LibGD'; $lang['im_convert'] = 'Путь к ImageMagick'; $lang['jpg_quality'] = 'Качество сжатия JPG (0–100). Значение по умолчанию — 70.'; diff --git a/lib/plugins/config/lang/sk/lang.php b/lib/plugins/config/lang/sk/lang.php index 9e18b3ed9..23a60db90 100644 --- a/lib/plugins/config/lang/sk/lang.php +++ b/lib/plugins/config/lang/sk/lang.php @@ -103,7 +103,6 @@ $lang['target____media'] = 'Cieľové okno (target) pre media odkazy'; $lang['target____windows'] = 'Cieľové okno (target) pre windows odkazy'; $lang['mediarevisions'] = 'Povoliť verzie súborov?'; $lang['refcheck'] = 'Kontrolovať odkazy na médiá (pred vymazaním)'; -$lang['refshow'] = 'Počet zobrazených odkazov na médiá'; $lang['gdlib'] = 'Verzia GD Lib'; $lang['im_convert'] = 'Cesta k ImageMagick convert tool'; $lang['jpg_quality'] = 'Kvalita JPG kompresie (0-100)'; diff --git a/lib/plugins/config/lang/sl/lang.php b/lib/plugins/config/lang/sl/lang.php index 364e0fd7f..dcec62288 100644 --- a/lib/plugins/config/lang/sl/lang.php +++ b/lib/plugins/config/lang/sl/lang.php @@ -64,7 +64,6 @@ $lang['camelcase'] = 'Uporabi EnoBesedni zapisa za povezave'; $lang['deaccent'] = 'Počisti imena strani'; $lang['useheading'] = 'Uporabi prvi naslov za ime strani'; $lang['refcheck'] = 'Preverjanje sklica predstavnih datotek'; -$lang['refshow'] = 'Število predstavih sklicev za prikaz'; $lang['allowdebug'] = 'Dovoli razhroščevanje (po potrebi!)'; $lang['mediarevisions'] = 'Ali naj se omogočijo objave predstavnih vsebin?'; $lang['usewordblock'] = 'Zaustavi neželeno besedilo glede na seznam besed'; diff --git a/lib/plugins/config/lang/sq/lang.php b/lib/plugins/config/lang/sq/lang.php index 69e283b11..972b2894c 100644 --- a/lib/plugins/config/lang/sq/lang.php +++ b/lib/plugins/config/lang/sq/lang.php @@ -59,7 +59,6 @@ $lang['camelcase'] = 'Përdor CamelCase (shkronja e parë e çdo fja $lang['deaccent'] = 'Emra faqesh të pastër'; $lang['useheading'] = 'Përdor titra të nivelit të parë për faqet e emrave'; $lang['refcheck'] = 'Kontroll për referim mediash'; -$lang['refshow'] = 'Numri i referimeve të medias që duhet të tregohet'; $lang['allowdebug'] = 'Lejo debug çaktivizoje nëse nuk nevojitet!'; $lang['usewordblock'] = 'Blloko spam-in duke u bazuar mbi listë fjalësh'; $lang['indexdelay'] = 'Vonesa në kohë para index-imit (sekonda)'; diff --git a/lib/plugins/config/lang/sr/lang.php b/lib/plugins/config/lang/sr/lang.php index c675b84e6..b6d7268aa 100644 --- a/lib/plugins/config/lang/sr/lang.php +++ b/lib/plugins/config/lang/sr/lang.php @@ -60,7 +60,6 @@ $lang['camelcase'] = 'Користи CamelCase за линкове'; $lang['deaccent'] = 'Чисти имена страница'; $lang['useheading'] = 'Преузми наслов првог нивоа за назив странице'; $lang['refcheck'] = 'Провери референце медијских датотека'; -$lang['refshow'] = 'Број референци које се приказују за медијске датотеке'; $lang['allowdebug'] = 'Укључи дебаговање искључи ако није потребно!'; $lang['usewordblock'] = 'Блокирај спам на основу листе речи'; $lang['indexdelay'] = 'Одлагање индексирања (секунде)'; diff --git a/lib/plugins/config/lang/sv/lang.php b/lib/plugins/config/lang/sv/lang.php index d59b4b17e..2a83195d7 100644 --- a/lib/plugins/config/lang/sv/lang.php +++ b/lib/plugins/config/lang/sv/lang.php @@ -111,7 +111,6 @@ $lang['target____extern'] = 'Målfönster för externa länkar'; $lang['target____media'] = 'Målfönster för medialänkar'; $lang['target____windows'] = 'Målfönster för windowslänkar'; $lang['refcheck'] = 'Kontrollera referenser till mediafiler'; -$lang['refshow'] = 'Antal mediareferenser som ska visas'; $lang['gdlib'] = 'Version av GD-biblioteket'; $lang['im_convert'] = 'Sökväg till ImageMagicks konverteringsverktyg'; $lang['jpg_quality'] = 'Kvalitet för JPG-komprimering (0-100)'; diff --git a/lib/plugins/config/lang/tr/lang.php b/lib/plugins/config/lang/tr/lang.php index 5bc4f3fc1..45d70eeb0 100644 --- a/lib/plugins/config/lang/tr/lang.php +++ b/lib/plugins/config/lang/tr/lang.php @@ -79,7 +79,6 @@ $lang['iexssprotect'] = 'Yüklenmiş dosyaları muhtemel kötu niyetli $lang['htmlok'] = 'Gömülü HTML koduna izin ver'; $lang['phpok'] = 'Gömülü PHP koduna izin ver'; $lang['refcheck'] = 'Araç kaynak denetimi'; -$lang['refshow'] = 'Gösterilecek araç kaynağı sayısı'; $lang['gdlib'] = 'GD Lib sürümü'; $lang['jpg_quality'] = 'JPG sıkıştırma kalitesi [0-100]'; $lang['mailfrom'] = 'Otomatik e-postalar için kullanılacak e-posta adresi'; diff --git a/lib/plugins/config/lang/uk/lang.php b/lib/plugins/config/lang/uk/lang.php index 3d463fc72..c938d911b 100644 --- a/lib/plugins/config/lang/uk/lang.php +++ b/lib/plugins/config/lang/uk/lang.php @@ -102,7 +102,6 @@ $lang['target____extern'] = 'Target для зовнішніх посила $lang['target____media'] = 'Target для медіа-посилань'; $lang['target____windows'] = 'Target для посилань на мережеві папки'; $lang['refcheck'] = 'Перевіряти посилання на медіа-файлі'; -$lang['refshow'] = 'Показувати кількість медіа-посилань'; $lang['gdlib'] = 'Версія GD Lib'; $lang['im_convert'] = 'Шлях до ImageMagick'; $lang['jpg_quality'] = 'Якість компресії JPG (0-100)'; diff --git a/lib/plugins/config/lang/zh-tw/lang.php b/lib/plugins/config/lang/zh-tw/lang.php index cc6e0246e..7890730a6 100644 --- a/lib/plugins/config/lang/zh-tw/lang.php +++ b/lib/plugins/config/lang/zh-tw/lang.php @@ -109,7 +109,6 @@ $lang['target____media'] = '媒體連結的目標視窗'; $lang['target____windows'] = 'Windows 連結的目標視窗'; $lang['mediarevisions'] = '啟用媒體修訂歷史嗎?'; $lang['refcheck'] = '媒體連結檢查'; -$lang['refshow'] = '媒體連結的顯示數量'; $lang['gdlib'] = 'GD Lib 版本'; $lang['im_convert'] = 'ImageMagick 的轉換工具路徑'; $lang['jpg_quality'] = 'JPG 壓縮品質(0-100)'; diff --git a/lib/plugins/config/lang/zh/lang.php b/lib/plugins/config/lang/zh/lang.php index 832dfe749..903e987a3 100644 --- a/lib/plugins/config/lang/zh/lang.php +++ b/lib/plugins/config/lang/zh/lang.php @@ -114,7 +114,6 @@ $lang['target____media'] = '媒体文件链接的目标窗口'; $lang['target____windows'] = 'Windows 链接的目标窗口'; $lang['mediarevisions'] = '激活媒体修订历史?'; $lang['refcheck'] = '检查媒体与页面的挂钩情况'; -$lang['refshow'] = '显示媒体与页面挂钩情况的数量'; $lang['gdlib'] = 'GD 库版本'; $lang['im_convert'] = 'ImageMagick 转换工具的路径'; $lang['jpg_quality'] = 'JPG 压缩质量(0-100)'; diff --git a/lib/plugins/config/settings/config.metadata.php b/lib/plugins/config/settings/config.metadata.php index 22e76a013..ec549d6b4 100644 --- a/lib/plugins/config/settings/config.metadata.php +++ b/lib/plugins/config/settings/config.metadata.php @@ -161,7 +161,6 @@ $meta['im_convert'] = array('im_convert'); $meta['jpg_quality'] = array('numeric','_pattern' => '/^100$|^[1-9]?[0-9]$/'); //(0-100) $meta['fetchsize'] = array('numeric'); $meta['refcheck'] = array('onoff'); -$meta['refshow'] = array('numeric'); $meta['_notifications'] = array('fieldset'); $meta['subscribers'] = array('onoff'); -- cgit v1.2.3 From 2a7abf2d7fee6a2d6418e5ad4b79e37e6049bd92 Mon Sep 17 00:00:00 2001 From: Christopher Smith Date: Wed, 31 Jul 2013 18:14:26 +0200 Subject: FS#2751 - self deletion of user account --- inc/actions.php | 28 +++++++++++++----- inc/auth.php | 39 +++++++++++++++++++++++++ inc/confutils.php | 3 ++ inc/html.php | 17 +++++++++++ inc/lang/en/lang.php | 7 +++++ lib/plugins/config/lang/en/lang.php | 1 + lib/plugins/config/settings/config.metadata.php | 2 +- lib/tpl/dokuwiki/css/_forms.css | 5 +++- 8 files changed, 92 insertions(+), 10 deletions(-) diff --git a/inc/actions.php b/inc/actions.php index da3414eb2..bf124c887 100644 --- a/inc/actions.php +++ b/inc/actions.php @@ -92,14 +92,26 @@ function act_dispatch(){ $ACT = 'login'; } - //update user profile - if ($ACT == 'profile') { + // user profile changes + if (in_array($ACT, array('profile','profile_delete'))) { if(!$_SERVER['REMOTE_USER']) { $ACT = 'login'; } else { - if(updateprofile()) { - msg($lang['profchanged'],1); - $ACT = 'show'; + 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; } } } @@ -247,7 +259,7 @@ function act_validate($act) { //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'))){ + 'resendpwd','profile_delete'))){ msg('Command unavailable: '.htmlspecialchars($act),-1); return 'show'; } @@ -258,7 +270,7 @@ function act_validate($act) { 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','resendpwd','recover', + 'unsubscribe','profile','profile_delete','resendpwd','recover', 'draftdel','sitemap','media')) && substr($act,0,7) != 'export_' ) { msg('Command unknown: '.htmlspecialchars($act),-1); return 'show'; @@ -287,7 +299,7 @@ function act_permcheck($act){ }else{ $permneed = AUTH_CREATE; } - }elseif(in_array($act,array('login','search','recent','profile','index', 'sitemap'))){ + }elseif(in_array($act,array('login','search','recent','profile','profile_delete','index', 'sitemap'))){ $permneed = AUTH_NONE; }elseif($act == 'revert'){ $permneed = AUTH_ADMIN; diff --git a/inc/auth.php b/inc/auth.php index 537d44c01..75ba9a9ba 100644 --- a/inc/auth.php +++ b/inc/auth.php @@ -901,6 +901,45 @@ function updateprofile() { return false; } +function auth_deleteprofile(){ + global $conf; + global $lang; + /* @var auth_basic $auth */ + global $auth; + /* @var Input $INPUT */ + global $INPUT; + + if(!$INPUT->post->bool('delete')) return false; + if(!checkSecurityToken()) return false; + + // action prevented or auth module disallows + if(!actionOK('profile_delete') || !$auth->canDo('delUser')) { + msg($lang['profnodelete'], -1); + return false; + } + + if(!$INPUT->post->bool('confirm_delete')){ + msg($lang['profconfdeletemissing'], -1); + return false; + } + + if($conf['profileconfirm']) { + if(!$auth->checkPass($_SERVER['REMOTE_USER'], $INPUT->post->str('oldpass'))) { + msg($lang['badpassconfirm'], -1); + return false; + } + } + + $deleted[] = $_SERVER['REMOTE_USER']; + if($result = $auth->triggerUserMod('delete', array($deleted))) { + // force and immediate logout including removing the sticky cookie + auth_logoff(); + return true; + } + + return false; +} + /** * Send a new password * diff --git a/inc/confutils.php b/inc/confutils.php index 404cc6050..02be0089c 100644 --- a/inc/confutils.php +++ b/inc/confutils.php @@ -261,6 +261,9 @@ function actionOK($action){ if (is_null($auth) || !$auth->canDo('Profile')) { $disabled[] = 'profile'; } + if (is_null($auth) || !$auth->canDo('delUser')) { + $disabled[] = 'profile_delete'; + } if (is_null($auth)) { $disabled[] = 'login'; } diff --git a/inc/html.php b/inc/html.php index fb39fcb3c..5e3388a52 100644 --- a/inc/html.php +++ b/inc/html.php @@ -1381,6 +1381,23 @@ function html_updateprofile(){ $form->addElement(form_makeButton('reset', '', $lang['btn_reset'])); $form->endFieldset(); html_form('updateprofile', $form); + + if ($auth->canDo('delUser') && actionOK('profile_delete')) { + $form_profiledelete = new Doku_Form(array('id' => 'dw__profiledelete')); + $form_profiledelete->startFieldset($lang['profdeleteuser']); + $form_profiledelete->addHidden('do', 'profile_delete'); + $form_profiledelete->addHidden('delete', '1'); + $form_profiledelete->addElement(form_makeCheckboxField('confirm_delete', '1', $lang['profconfdelete'],'dw__confirmdelete','', array('required' => 'required'))); + if ($conf['profileconfirm']) { + $form_profiledelete->addElement(form_makeTag('br')); + $form_profiledelete->addElement(form_makePasswordField('oldpass', $lang['oldpass'], '', 'block', array('size'=>'50', 'required' => 'required'))); + } + $form_profiledelete->addElement(form_makeButton('submit', '', $lang['btn_deleteuser'])); + $form_profiledelete->endFieldset(); + + html_form('profiledelete', $form_profiledelete); + } + print '
'.NL; } diff --git a/inc/lang/en/lang.php b/inc/lang/en/lang.php index cdad6c9a6..d4acfad6e 100644 --- a/inc/lang/en/lang.php +++ b/inc/lang/en/lang.php @@ -51,6 +51,7 @@ $lang['btn_revert'] = 'Restore'; $lang['btn_register'] = 'Register'; $lang['btn_apply'] = 'Apply'; $lang['btn_media'] = 'Media Manager'; +$lang['btn_deleteuser'] = 'Remove My Account'; $lang['loggedinas'] = 'Logged in as'; $lang['user'] = 'Username'; @@ -63,6 +64,7 @@ $lang['fullname'] = 'Real name'; $lang['email'] = 'E-Mail'; $lang['profile'] = 'User Profile'; $lang['badlogin'] = 'Sorry, username or password was wrong.'; +$lang['badpassconfirm'] = 'Sorry, the password was wrong'; $lang['minoredit'] = 'Minor Changes'; $lang['draftdate'] = 'Draft autosaved on'; // full dformat date will be added $lang['nosecedit'] = 'The page was changed in the meantime, section info was out of date loaded full page instead.'; @@ -81,6 +83,11 @@ $lang['profna'] = 'This wiki does not support profile modificatio $lang['profnochange'] = 'No changes, nothing to do.'; $lang['profnoempty'] = 'An empty name or email address is not allowed.'; $lang['profchanged'] = 'User profile successfully updated.'; +$lang['profnodelete'] = 'This wiki does not support deleting users'; +$lang['profdeleteuser'] = 'Delete Account'; +$lang['profdeleted'] = 'Your user account has been deleted from this wiki'; +$lang['profconfdelete'] = 'I wish to remove my account from this wiki.
This action can not be undone.'; +$lang['profconfdeletemissing'] = 'Confirmation check box not ticked'; $lang['pwdforget'] = 'Forgotten your password? Get a new one'; $lang['resendna'] = 'This wiki does not support password resending.'; diff --git a/lib/plugins/config/lang/en/lang.php b/lib/plugins/config/lang/en/lang.php index 83c843b3a..9558e53dc 100644 --- a/lib/plugins/config/lang/en/lang.php +++ b/lib/plugins/config/lang/en/lang.php @@ -104,6 +104,7 @@ $lang['disableactions'] = 'Disable DokuWiki actions'; $lang['disableactions_check'] = 'Check'; $lang['disableactions_subscription'] = 'Subscribe/Unsubscribe'; $lang['disableactions_wikicode'] = 'View source/Export Raw'; +$lang['disableactions_profile_delete'] = 'Delete Own Account'; $lang['disableactions_other'] = 'Other actions (comma separated)'; $lang['auth_security_timeout'] = 'Authentication Security Timeout (seconds)'; $lang['securecookie'] = 'Should cookies set via HTTPS only be sent via HTTPS by the browser? Disable this option when only the login of your wiki is secured with SSL but browsing the wiki is done unsecured.'; diff --git a/lib/plugins/config/settings/config.metadata.php b/lib/plugins/config/settings/config.metadata.php index 22e76a013..ffff15af5 100644 --- a/lib/plugins/config/settings/config.metadata.php +++ b/lib/plugins/config/settings/config.metadata.php @@ -126,7 +126,7 @@ $meta['manager'] = array('string'); $meta['profileconfirm'] = array('onoff'); $meta['rememberme'] = array('onoff'); $meta['disableactions'] = array('disableactions', - '_choices' => array('backlink','index','recent','revisions','search','subscription','register','resendpwd','profile','edit','wikicode','check'), + '_choices' => array('backlink','index','recent','revisions','search','subscription','register','resendpwd','profile','profile_delete','edit','wikicode','check'), '_combine' => array('subscription' => array('subscribe','unsubscribe'), 'wikicode' => array('source','export_raw'))); $meta['auth_security_timeout'] = array('numeric'); $meta['securecookie'] = array('onoff'); diff --git a/lib/tpl/dokuwiki/css/_forms.css b/lib/tpl/dokuwiki/css/_forms.css index 6744750ba..84b7db8e1 100644 --- a/lib/tpl/dokuwiki/css/_forms.css +++ b/lib/tpl/dokuwiki/css/_forms.css @@ -79,7 +79,10 @@ #dw__register fieldset { padding-bottom: 0.7em; } - +#dw__profiledelete { + display: block; + margin-top: 2.8em; +} /** * Styles for the subscription page -- cgit v1.2.3 From 020ea9e10577217f17372cb6510d872f9a5c647c Mon Sep 17 00:00:00 2001 From: Christopher Smith Date: Wed, 31 Jul 2013 18:15:57 +0200 Subject: unit tests for self deleting of user accounts --- _test/tests/inc/auth_deleteprofile.test.php | 179 ++++++++++++++++++++++++++++ inc/confutils.php | 2 +- 2 files changed, 180 insertions(+), 1 deletion(-) create mode 100644 _test/tests/inc/auth_deleteprofile.test.php diff --git a/_test/tests/inc/auth_deleteprofile.test.php b/_test/tests/inc/auth_deleteprofile.test.php new file mode 100644 index 000000000..dc38fcd16 --- /dev/null +++ b/_test/tests/inc/auth_deleteprofile.test.php @@ -0,0 +1,179 @@ +cando['delUser'] = $canDeleteUser; + } + + public function checkPass($user, $pass) { + return $pass == 'password'; + } + + public function deleteUsers($users) { + return in_array($_SERVER['REMOTE_USER'], $users); + } + + public function logoff() { + $this->loggedOff = true; + } + +} + +class auth_deleteprofile_test extends DokuWikiTest { + + /* + * Tests: + * + * 1. It works and the user is logged off + * 2. Password matches when config requires it + * 3,4. Auth plugin can prevent & wiki config can prevent + * 5. Any of invalid security token, missing/not set 'delete' flag, missing/unchecked 'confirm_delete' + * + */ + + function test_success() { + + global $ACT, $INPUT, $conf, $auth; + + $ACT = 'profile_delete'; + $conf['profileconfirm'] = false; + $_SERVER['REMOTE_USER'] = 'testuser'; + + $input = array( + 'do' => $ACT, + 'sectok' => getSecurityToken(), + 'delete' => '1', + 'confirm_delete' => '1', + ); + + $_POST = $input; + $_REQUEST = $input; + $INPUT = new Input(); + + $auth = new Mock_Auth_Plugin(); + + $this->assertTrue(auth_deleteprofile()); + $this->assertTrue($auth->loggedOff); + } + + function test_confirmation_required() { + + global $ACT, $INPUT, $conf, $auth; + + $ACT = 'profile_delete'; + $conf['profileconfirm'] = true; + $_SERVER['REMOTE_USER'] = 'testuser'; + + $input = array( + 'do' => $ACT, + 'sectok' => getSecurityToken(), + 'delete' => '1', + 'confirm_delete' => '1', + 'oldpass' => 'wrong', + ); + + $_POST = $input; + $_REQUEST = $input; + $INPUT = new Input(); + + $auth = new Mock_Auth_Plugin(); + + // password check required - it fails, so don't delete profile + $this->assertFalse(auth_deleteprofile()); + + // now it passes, we're good to go + $INPUT->set('oldpass','password'); + $INPUT->post->set('oldpass','password'); + $this->assertTrue(auth_deleteprofile()); + } + + function test_authconfig_prevents() { + + global $ACT, $INPUT, $conf, $auth; + + $ACT = 'profile_delete'; + $conf['profileconfirm'] = false; + $_SERVER['REMOTE_USER'] = 'testuser'; + + $input = array( + 'do' => $ACT, + 'sectok' => getSecurityToken(), + 'delete' => '1', + 'confirm_delete' => '1', + ); + + $_POST = $input; + $_REQUEST = $input; + $INPUT = new Input(); + + $auth = new Mock_Auth_Plugin(false); + $conf['disableactions'] = ''; + $this->assertFalse(auth_deleteprofile()); + } + + function test_wikiconfig_prevents() { + + global $ACT, $INPUT, $conf, $auth; + + $ACT = 'profile_delete'; + $conf['profileconfirm'] = false; + $_SERVER['REMOTE_USER'] = 'testuser'; + + $input = array( + 'do' => $ACT, + 'sectok' => getSecurityToken(), + 'delete' => '1', + 'confirm_delete' => '1', + ); + + $_POST = $input; + $_REQUEST = $input; + $INPUT = new Input(); + + $auth = new Mock_Auth_Plugin(); + $conf['disableactions'] = 'profile_delete'; + + $this->assertFalse(actionOK('profile_delete')); + $this->assertTrue($auth->canDo('delUser')); + + $this->assertFalse(auth_deleteprofile()); + } + + function test_basic_parameters() { + + global $ACT, $INPUT, $conf, $auth; + + $ACT = 'profile_delete'; + $conf['profileconfirm'] = true; + $_SERVER['REMOTE_USER'] = 'testuser'; + + $input = array( + 'do' => $ACT, + 'sectok' => getSecurityToken(), + 'delete' => '1', + 'confirm_delete' => '1', + 'oldpass' => 'password', + ); + + $_POST = $input; + $_REQUEST = $input; + $input_foundation = new Input(); + + $auth = new Mock_Auth_Plugin(); + + $INPUT = clone $input_foundation; + $INPUT->remove('delete'); + $this->assertFalse(auth_deleteprofile()); + + $INPUT = clone $input_foundation; + $INPUT->set('sectok','wrong'); + $this->assertFalse(auth_deleteprofile()); + + $INPUT = clone $input_foundation; + $INPUT->remove('confirm_delete'); + $this->assertFalse(auth_deleteprofile()); + } +} \ No newline at end of file diff --git a/inc/confutils.php b/inc/confutils.php index 02be0089c..0ac003b72 100644 --- a/inc/confutils.php +++ b/inc/confutils.php @@ -241,7 +241,7 @@ function getConfigFiles($type) { */ function actionOK($action){ static $disabled = null; - if(is_null($disabled)){ + if(is_null($disabled) || defined('SIMPLE_TEST')){ global $conf; /** @var auth_basic $auth */ global $auth; -- cgit v1.2.3 From a669bfe08c4c0ef180e38dd3189eaf81c0029f1c Mon Sep 17 00:00:00 2001 From: Christopher Smith Date: Wed, 31 Jul 2013 18:38:02 +0200 Subject: add html5 attributes to register form --- inc/html.php | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/inc/html.php b/inc/html.php index fb39fcb3c..d94291090 100644 --- a/inc/html.php +++ b/inc/html.php @@ -1318,19 +1318,22 @@ function html_register(){ global $conf; global $INPUT; + $base_attrs = array('size'=>50,'required'=>'required'); + $email_attrs = $base_attrs + array('type'=>'email','class'=>'edit'); + print p_locale_xhtml('register'); print '
'.NL; $form = new Doku_Form(array('id' => 'dw__register')); $form->startFieldset($lang['btn_register']); $form->addHidden('do', 'register'); $form->addHidden('save', '1'); - $form->addElement(form_makeTextField('login', $INPUT->post->str('login'), $lang['user'], '', 'block', array('size'=>'50'))); + $form->addElement(form_makeTextField('login', $INPUT->post->str('login'), $lang['user'], '', 'block', $base_attrs)); if (!$conf['autopasswd']) { - $form->addElement(form_makePasswordField('pass', $lang['pass'], '', 'block', array('size'=>'50'))); - $form->addElement(form_makePasswordField('passchk', $lang['passchk'], '', 'block', array('size'=>'50'))); + $form->addElement(form_makePasswordField('pass', $lang['pass'], '', 'block', $base_attrs)); + $form->addElement(form_makePasswordField('passchk', $lang['passchk'], '', 'block', $base_attrs)); } - $form->addElement(form_makeTextField('fullname', $INPUT->post->str('fullname'), $lang['fullname'], '', 'block', array('size'=>'50'))); - $form->addElement(form_makeTextField('email', $INPUT->post->str('email'), $lang['email'], '', 'block', array('size'=>'50'))); + $form->addElement(form_makeTextField('fullname', $INPUT->post->str('fullname'), $lang['fullname'], '', 'block', $base_attrs)); + $form->addElement(form_makeField('email','email', $INPUT->post->str('email'), $lang['email'], '', 'block', $email_attrs)); $form->addElement(form_makeButton('submit', '', $lang['btn_register'])); $form->endFieldset(); html_form('register', $form); -- cgit v1.2.3 From 3b1338fffdb38ad47f7d814bc8d61b2f06305d69 Mon Sep 17 00:00:00 2001 From: Christopher Smith Date: Wed, 31 Jul 2013 18:38:31 +0200 Subject: add html5 attributes to update profile form --- inc/html.php | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/inc/html.php b/inc/html.php index d94291090..53f4c45ff 100644 --- a/inc/html.php +++ b/inc/html.php @@ -1356,10 +1356,10 @@ function html_updateprofile(){ global $auth; print p_locale_xhtml('updateprofile'); + print '
'.NL; $fullname = $INPUT->post->str('fullname', $INFO['userinfo']['name'], true); $email = $INPUT->post->str('email', $INFO['userinfo']['mail'], true); - print '
'.NL; $form = new Doku_Form(array('id' => 'dw__register')); $form->startFieldset($lang['profile']); $form->addHidden('do', 'profile'); @@ -1368,9 +1368,9 @@ function html_updateprofile(){ $attr = array('size'=>'50'); if (!$auth->canDo('modName')) $attr['disabled'] = 'disabled'; $form->addElement(form_makeTextField('fullname', $fullname, $lang['fullname'], '', 'block', $attr)); - $attr = array('size'=>'50'); + $attr = array('size'=>'50', 'class'=>'edit'); if (!$auth->canDo('modMail')) $attr['disabled'] = 'disabled'; - $form->addElement(form_makeTextField('email', $email, $lang['email'], '', 'block', $attr)); + $form->addElement(form_makeField('email','email', $email, $lang['email'], '', 'block', $attr)); $form->addElement(form_makeTag('br')); if ($auth->canDo('modPass')) { $form->addElement(form_makePasswordField('newpass', $lang['newpass'], '', 'block', array('size'=>'50'))); @@ -1378,10 +1378,11 @@ function html_updateprofile(){ } if ($conf['profileconfirm']) { $form->addElement(form_makeTag('br')); - $form->addElement(form_makePasswordField('oldpass', $lang['oldpass'], '', 'block', array('size'=>'50'))); + $form->addElement(form_makePasswordField('oldpass', $lang['oldpass'], '', 'block', array('size'=>'50', 'required' => 'required'))); } $form->addElement(form_makeButton('submit', '', $lang['btn_save'])); $form->addElement(form_makeButton('reset', '', $lang['btn_reset'])); + $form->endFieldset(); html_form('updateprofile', $form); print '
'.NL; -- cgit v1.2.3 From 71422fc898ea54876cd58c3bf5c4c0d9de032b52 Mon Sep 17 00:00:00 2001 From: Christopher Smith Date: Wed, 31 Jul 2013 18:41:02 +0200 Subject: Change error message shown for incorrect current password on update profile form. The current message confusingly mentions bad 'username' when username is not involved. The new message is the same as that introduced for an incorrect current password on the self delete profile form (FS#2751) --- inc/auth.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/inc/auth.php b/inc/auth.php index 537d44c01..29ef46d03 100644 --- a/inc/auth.php +++ b/inc/auth.php @@ -883,7 +883,7 @@ function updateprofile() { if($conf['profileconfirm']) { if(!$auth->checkPass($_SERVER['REMOTE_USER'], $INPUT->post->str('oldpass'))) { - msg($lang['badlogin'], -1); + msg($lang['badpassconfirm'], -1); return false; } } -- cgit v1.2.3 From 7b3674bd7a2b20df3ba37b32b7cc33f574a95dc5 Mon Sep 17 00:00:00 2001 From: Christopher Smith Date: Wed, 31 Jul 2013 18:51:06 +0200 Subject: add html5 'email' type to the user manager forms --- lib/plugins/usermanager/admin.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/plugins/usermanager/admin.php b/lib/plugins/usermanager/admin.php index 445836a50..ca4c6a650 100644 --- a/lib/plugins/usermanager/admin.php +++ b/lib/plugins/usermanager/admin.php @@ -311,6 +311,9 @@ class admin_plugin_usermanager extends DokuWiki_Admin_Plugin { if($name == 'userpass'){ $fieldtype = 'password'; $autocomp = 'autocomplete="off"'; + }elseif($name == 'usermail'){ + $fieldtype = 'email'; + $autocomp = ''; }else{ $fieldtype = 'text'; $autocomp = ''; -- cgit v1.2.3 From 2586f61fa6012e65f30cd5e9004ea4d6dea25238 Mon Sep 17 00:00:00 2001 From: Christopher Smith Date: Wed, 31 Jul 2013 19:07:29 +0200 Subject: add html5 attributes to email fields of the config manager --- lib/plugins/config/settings/config.class.php | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/lib/plugins/config/settings/config.class.php b/lib/plugins/config/settings/config.class.php index 8eb99284d..63be3a726 100644 --- a/lib/plugins/config/settings/config.class.php +++ b/lib/plugins/config/settings/config.class.php @@ -717,6 +717,29 @@ if (!class_exists('setting_email')) { $this->_local = $input; return true; } + function html(&$plugin, $echo=false) { + $value = ''; + $disable = ''; + + if ($this->is_protected()) { + $value = $this->_protected; + $disable = 'disabled="disabled"'; + } else { + if ($echo && $this->_error) { + $value = $this->_input; + } else { + $value = is_null($this->_local) ? $this->_default : $this->_local; + } + } + + $multiple = $this->_multiple ? 'multiple="multiple"' : ''; + $key = htmlspecialchars($this->_key); + $value = htmlspecialchars($value); + + $label = ''; + $input = ''; + return array($label,$input); + } } } -- cgit v1.2.3 From b40098c3d8f4a41b62694ccd1e660c26301d6df0 Mon Sep 17 00:00:00 2001 From: Michael Hamann Date: Tue, 30 Jul 2013 18:46:02 +0200 Subject: Add truly random numbers and use them in places where randomness matters --- _test/tests/inc/auth_random.test.php | 20 +++++++ inc/PassHash.class.php | 2 +- inc/auth.php | 108 +++++++++++++++++++++++++++++++++-- 3 files changed, 123 insertions(+), 7 deletions(-) create mode 100644 _test/tests/inc/auth_random.test.php diff --git a/_test/tests/inc/auth_random.test.php b/_test/tests/inc/auth_random.test.php new file mode 100644 index 000000000..f380eba53 --- /dev/null +++ b/_test/tests/inc/auth_random.test.php @@ -0,0 +1,20 @@ +assertTrue($rand <= 2000, 'The generated number was above the limit'); + $this->assertTrue($rand >= 300, 'The generate number was too low'); + } + + function testLargeRandoms() { + $min = (1 << 30); + $max = $min + (1 << 33) + 17; + $rand = auth_random($min, $max); + $this->assertTrue($rand >= $min, 'The generated number was too low'); + $this->assertTrue($rand <= $max, 'The generated number was too high'); + } +} diff --git a/inc/PassHash.class.php b/inc/PassHash.class.php index 61bd74939..607661a22 100644 --- a/inc/PassHash.class.php +++ b/inc/PassHash.class.php @@ -98,7 +98,7 @@ class PassHash { $salt = ''; $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; for($i = 0; $i < $len; $i++) { - $salt .= $chars[mt_rand(0, 61)]; + $salt .= $chars[auth_random(0, 61)]; } return $salt; } diff --git a/inc/auth.php b/inc/auth.php index 47b29eff7..e840ef6d7 100644 --- a/inc/auth.php +++ b/inc/auth.php @@ -294,7 +294,7 @@ function auth_validateToken($token) { * @return string The auth token */ function auth_createToken() { - $token = md5(mt_rand()); + $token = md5(auth_randombytes(16)); @session_start(); // reopen the session if needed $_SESSION[DOKU_COOKIE]['auth']['token'] = $token; session_write_close(); @@ -349,6 +349,102 @@ function auth_cookiesalt($addsession = false) { return $salt; } +/** + * Return truly (pseudo) random bytes if available, otherwise fall back to mt_rand + * + * @author Mark Seecof + * @author Michael Hamann + * @link http://www.php.net/manual/de/function.mt-rand.php#83655 + * @param int $length number of bytes to get + * @throws Exception when no usable random generator is found + * @return string binary random strings + */ +function auth_randombytes($length) { + $strong = false; + $rbytes = false; + + if (function_exists('openssl_random_pseudo_bytes') + && (version_compare(PHP_VERSION, '5.3.4') >= 0 + || strtoupper(substr(PHP_OS, 0, 3)) !== 'WIN') + ) { + $rbytes = openssl_random_pseudo_bytes($length, $strong); + } + + if (!$strong && function_exists('mcrypt_create_iv') + && (version_compare(PHP_VERSION, '5.3.7') >= 0 + || strtoupper(substr(PHP_OS, 0, 3)) !== 'WIN') + ) { + $rbytes = mcrypt_create_iv($length, MCRYPT_DEV_URANDOM); + if ($rbytes !== false && strlen($rbytes) === $length) { + $strong = true; + } + } + + + // If no strong randoms available, try OS the specific ways + if(!$strong) { + // Unix/Linux platform + $fp = @fopen('/dev/urandom', 'rb'); + if($fp !== false) { + $rbytes = fread($fp, $length); + fclose($fp); + } + + // MS-Windows platform + if(class_exists('COM')) { + // http://msdn.microsoft.com/en-us/library/aa388176(VS.85).aspx + try { + $CAPI_Util = new COM('CAPICOM.Utilities.1'); + $rbytes = $CAPI_Util->GetRandom($length, 0); + + // if we ask for binary data PHP munges it, so we + // request base64 return value. + if($rbytes) $rbytes = base64_decode($rbytes); + } catch(Exception $ex) { + // fail + } + } + } + if(strlen($rbytes) < $length) $rbytes = false; + + // still no random bytes available - fall back to mt_rand() + if($rbytes === false) { + $rbytes = ''; + for ($i = 0; $i < $length; ++$i) { + $rbytes .= chr(mt_rand(0, 255)); + } + } + + return $rbytes; +} + +/** + * Random number generator using the best available source + * + * @author Michael Samuel + * @author Michael Hamann + * @param int $min + * @param int $max + * @return int + */ +function auth_random($min, $max) { + $abs_max = $max - $min; + + $nbits = 0; + for ($n = $abs_max; $n > 0; $n >>= 1) { + ++$nbits; + } + + $mask = (1 << $nbits) - 1; + do { + $bytes = auth_randombytes(PHP_INT_SIZE); + $integers = unpack('Inum', $bytes); + $integer = $integers["num"] & $mask; + } while ($integer > $abs_max); + + return $min + $integer; +} + /** * Log out the current user * @@ -703,12 +799,12 @@ function auth_pwgen($foruser = '') { //use thre syllables... for($i = 0; $i < 3; $i++) { - $data['password'] .= $c[mt_rand(0, strlen($c) - 1)]; - $data['password'] .= $v[mt_rand(0, strlen($v) - 1)]; - $data['password'] .= $a[mt_rand(0, strlen($a) - 1)]; + $data['password'] .= $c[auth_random(0, strlen($c) - 1)]; + $data['password'] .= $v[auth_random(0, strlen($v) - 1)]; + $data['password'] .= $a[auth_random(0, strlen($a) - 1)]; } //... and add a nice number and special - $data['password'] .= mt_rand(10, 99).$s[mt_rand(0, strlen($s) - 1)]; + $data['password'] .= auth_random(10, 99).$s[auth_random(0, strlen($s) - 1)]; } $evt->advise_after(); @@ -1007,7 +1103,7 @@ function act_resendpwd() { } // generate auth token - $token = md5(uniqid(mt_rand(), true)); // random secret + $token = md5(auth_randombytes(16)); // random secret $tfile = $conf['cachedir'].'/'.$token{0}.'/'.$token.'.pwauth'; $url = wl('', array('do'=> 'resendpwd', 'pwauth'=> $token), true, '&'); -- cgit v1.2.3 From 9c6747f21c0862b978017ec188b79a86bc973b2a Mon Sep 17 00:00:00 2001 From: Michael Hamann Date: Tue, 30 Jul 2013 13:40:59 +0200 Subject: Fix and add type declarations for the auth system --- inc/auth.php | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/inc/auth.php b/inc/auth.php index e840ef6d7..ace98f51f 100644 --- a/inc/auth.php +++ b/inc/auth.php @@ -40,7 +40,7 @@ function auth_setup() { global $INPUT; global $AUTH_ACL; global $lang; - global $config_cascade; + /* @var Doku_Plugin_Controller $plugin_controller */ global $plugin_controller; $AUTH_ACL = array(); @@ -207,7 +207,7 @@ function auth_login($user, $pass, $sticky = false, $silent = false) { global $USERINFO; global $conf; global $lang; - /* @var auth_basic $auth */ + /* @var DokuWiki_Auth_Plugin $auth */ global $auth; $sticky ? $sticky = true : $sticky = false; //sanity check @@ -457,7 +457,7 @@ function auth_random($min, $max) { function auth_logoff($keepbc = false) { global $conf; global $USERINFO; - /* @var auth_basic $auth */ + /* @var DokuWiki_Auth_Plugin $auth */ global $auth; // make sure the session is writable (it usually is) @@ -503,7 +503,7 @@ function auth_logoff($keepbc = false) { function auth_ismanager($user = null, $groups = null, $adminonly = false) { global $conf; global $USERINFO; - /* @var auth_basic $auth */ + /* @var DokuWiki_Auth_Plugin $auth */ global $auth; if(!$auth) return false; @@ -556,7 +556,7 @@ function auth_isadmin($user = null, $groups = null) { * @return bool true for membership acknowledged */ function auth_isMember($memberlist, $user, array $groups) { - /* @var auth_basic $auth */ + /* @var DokuWiki_Auth_Plugin $auth */ global $auth; if(!$auth) return false; @@ -622,7 +622,7 @@ function auth_quickaclcheck($id) { function auth_aclcheck($id, $user, $groups) { global $conf; global $AUTH_ACL; - /* @var auth_basic $auth */ + /* @var DokuWiki_Auth_Plugin $auth */ global $auth; // if no ACL is used always return upload rights @@ -821,7 +821,7 @@ function auth_pwgen($foruser = '') { */ function auth_sendPassword($user, $password) { global $lang; - /* @var auth_basic $auth */ + /* @var DokuWiki_Auth_Plugin $auth */ global $auth; if(!$auth) return false; @@ -855,7 +855,7 @@ function auth_sendPassword($user, $password) { function register() { global $lang; global $conf; - /* @var auth_basic $auth */ + /* @var DokuWiki_Auth_Plugin $auth */ global $auth; global $INPUT; @@ -924,7 +924,7 @@ function register() { function updateprofile() { global $conf; global $lang; - /* @var auth_basic $auth */ + /* @var DokuWiki_Auth_Plugin $auth */ global $auth; /* @var Input $INPUT */ global $INPUT; @@ -1014,7 +1014,7 @@ function updateprofile() { function act_resendpwd() { global $lang; global $conf; - /* @var auth_basic $auth */ + /* @var DokuWiki_Auth_Plugin $auth */ global $auth; /* @var Input $INPUT */ global $INPUT; @@ -1180,7 +1180,7 @@ function auth_verifyPassword($clear, $crypt) { */ function auth_setCookie($user, $pass, $sticky) { global $conf; - /* @var auth_basic $auth */ + /* @var DokuWiki_Auth_Plugin $auth */ global $auth; global $USERINFO; -- cgit v1.2.3 From ae27e120734c91b8f006928ec4e2f89e5b79393d Mon Sep 17 00:00:00 2001 From: Michael Hamann Date: Tue, 30 Jul 2013 18:47:58 +0200 Subject: Use a new, truly random secret for cookie encryption --- inc/auth.php | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/inc/auth.php b/inc/auth.php index ace98f51f..a1da971ae 100644 --- a/inc/auth.php +++ b/inc/auth.php @@ -219,7 +219,7 @@ function auth_login($user, $pass, $sticky = false, $silent = false) { if($auth->checkPass($user, $pass)) { // make logininfo globally available $_SERVER['REMOTE_USER'] = $user; - $secret = auth_cookiesalt(!$sticky); //bind non-sticky to session + $secret = auth_cookiesalt(!$sticky, true); //bind non-sticky to session auth_setCookie($user, PMA_blowfish_encrypt($pass, $secret), $sticky); return true; } else { @@ -250,7 +250,7 @@ function auth_login($user, $pass, $sticky = false, $silent = false) { return true; } // no we don't trust it yet - recheck pass but silent - $secret = auth_cookiesalt(!$sticky); //bind non-sticky to session + $secret = auth_cookiesalt(!$sticky, true); //bind non-sticky to session $pass = PMA_blowfish_decrypt($pass, $secret); return auth_login($user, $pass, $sticky, true); } @@ -333,14 +333,18 @@ function auth_browseruid() { * * @author Andreas Gohr * @param bool $addsession if true, the sessionid is added to the salt + * @param bool $secure if security is more important than keeping the old value * @return string */ -function auth_cookiesalt($addsession = false) { +function auth_cookiesalt($addsession = false, $secure = false) { global $conf; $file = $conf['metadir'].'/_htcookiesalt'; + if ($secure || !file_exists($file)) { + $file = $conf['metadir'].'/_htcookiesalt2'; + } $salt = io_readFile($file); if(empty($salt)) { - $salt = uniqid(rand(), true); + $salt = bin2hex(auth_randombytes(64)); io_saveFile($file, $salt); } if($addsession) { @@ -988,7 +992,7 @@ function updateprofile() { // update cookie and session with the changed data if($changes['pass']) { list( /*user*/, $sticky, /*pass*/) = auth_getCookie(); - $pass = PMA_blowfish_encrypt($changes['pass'], auth_cookiesalt(!$sticky)); + $pass = PMA_blowfish_encrypt($changes['pass'], auth_cookiesalt(!$sticky, true)); auth_setCookie($_SERVER['REMOTE_USER'], $pass, (bool) $sticky); } return true; -- cgit v1.2.3 From 865faf755070832ca9c794e1f1c190ddda7e0850 Mon Sep 17 00:00:00 2001 From: Michael Hamann Date: Tue, 30 Jul 2013 18:50:28 +0200 Subject: Add AES from phpseclib and use it for cookie encryption This replaces the deprecated and broken Blowfish implementation that has previously been used and should provide a lot more security. --- _test/tests/inc/auth_encryption.test.php | 12 + inc/auth.php | 40 +- inc/load.php | 4 + inc/phpseclib/Crypt_AES.php | 188 ++ inc/phpseclib/Crypt_Base.php | 1989 ++++++++++++++++ inc/phpseclib/Crypt_Hash.php | 823 +++++++ inc/phpseclib/Crypt_Rijndael.php | 1374 +++++++++++ inc/phpseclib/LICENSE | 21 + inc/phpseclib/Math_BigInteger.php | 3651 ++++++++++++++++++++++++++++++ inc/phpseclib/update.sh | 8 + 10 files changed, 8107 insertions(+), 3 deletions(-) create mode 100644 _test/tests/inc/auth_encryption.test.php create mode 100644 inc/phpseclib/Crypt_AES.php create mode 100644 inc/phpseclib/Crypt_Base.php create mode 100644 inc/phpseclib/Crypt_Hash.php create mode 100644 inc/phpseclib/Crypt_Rijndael.php create mode 100644 inc/phpseclib/LICENSE create mode 100644 inc/phpseclib/Math_BigInteger.php create mode 100755 inc/phpseclib/update.sh diff --git a/_test/tests/inc/auth_encryption.test.php b/_test/tests/inc/auth_encryption.test.php new file mode 100644 index 000000000..041eba00e --- /dev/null +++ b/_test/tests/inc/auth_encryption.test.php @@ -0,0 +1,12 @@ +assertEquals($data, auth_decrypt(auth_encrypt($data, $secret), $secret)); + } +} diff --git a/inc/auth.php b/inc/auth.php index a1da971ae..f02bfebca 100644 --- a/inc/auth.php +++ b/inc/auth.php @@ -220,7 +220,7 @@ function auth_login($user, $pass, $sticky = false, $silent = false) { // make logininfo globally available $_SERVER['REMOTE_USER'] = $user; $secret = auth_cookiesalt(!$sticky, true); //bind non-sticky to session - auth_setCookie($user, PMA_blowfish_encrypt($pass, $secret), $sticky); + auth_setCookie($user, auth_encrypt($pass, $secret), $sticky); return true; } else { //invalid credentials - log off @@ -251,7 +251,7 @@ function auth_login($user, $pass, $sticky = false, $silent = false) { } // no we don't trust it yet - recheck pass but silent $secret = auth_cookiesalt(!$sticky, true); //bind non-sticky to session - $pass = PMA_blowfish_decrypt($pass, $secret); + $pass = auth_decrypt($pass, $secret); return auth_login($user, $pass, $sticky, true); } } @@ -449,6 +449,40 @@ function auth_random($min, $max) { return $min + $integer; } +/** + * Encrypt data using the given secret using AES + * + * The mode is CBC with a random initialization vector, the key is derived + * using pbkdf2. + * + * @param string $data The data that shall be encrypted + * @param string $secret The secret/password that shall be used + * @return string The ciphertext + */ +function auth_encrypt($data, $secret) { + $iv = auth_randombytes(16); + $cipher = new Crypt_AES(); + $cipher->setPassword($secret); + + return $cipher->encrypt($iv.$data); +} + +/** + * Decrypt the given AES ciphertext + * + * The mode is CBC, the key is derived using pbkdf2 + * + * @param string $ciphertext The encrypted data + * @param string $secret The secret/password that shall be used + * @return string The decrypted data + */ +function auth_decrypt($ciphertext, $secret) { + $cipher = new Crypt_AES(); + $cipher->setPassword($secret); + + return substr($cipher->decrypt($ciphertext), 16); +} + /** * Log out the current user * @@ -992,7 +1026,7 @@ function updateprofile() { // update cookie and session with the changed data if($changes['pass']) { list( /*user*/, $sticky, /*pass*/) = auth_getCookie(); - $pass = PMA_blowfish_encrypt($changes['pass'], auth_cookiesalt(!$sticky, true)); + $pass = auth_encrypt($changes['pass'], auth_cookiesalt(!$sticky, true)); auth_setCookie($_SERVER['REMOTE_USER'], $pass, (bool) $sticky); } return true; diff --git a/inc/load.php b/inc/load.php index 5ca9b4cd8..7fb328215 100644 --- a/inc/load.php +++ b/inc/load.php @@ -82,6 +82,10 @@ function load_autoload($name){ 'RemoteAPI' => DOKU_INC.'inc/remote.php', 'RemoteAPICore' => DOKU_INC.'inc/RemoteAPICore.php', 'Subscription' => DOKU_INC.'inc/subscription.php', + 'Crypt_Base' => DOKU_INC.'inc/phpseclib/Crypt_Base.php', + 'Crypt_Rijndael' => DOKU_INC.'inc/phpseclib/Crypt_Rijndael.php', + 'Crypt_AES' => DOKU_INC.'inc/phpseclib/Crypt_AES.php', + 'Crypt_Hash' => DOKU_INC.'inc/phpseclib/Crypt_Hash.php', 'DokuWiki_Action_Plugin' => DOKU_PLUGIN.'action.php', 'DokuWiki_Admin_Plugin' => DOKU_PLUGIN.'admin.php', diff --git a/inc/phpseclib/Crypt_AES.php b/inc/phpseclib/Crypt_AES.php new file mode 100644 index 000000000..81fa2feab --- /dev/null +++ b/inc/phpseclib/Crypt_AES.php @@ -0,0 +1,188 @@ + + * setKey('abcdefghijklmnop'); + * + * $size = 10 * 1024; + * $plaintext = ''; + * for ($i = 0; $i < $size; $i++) { + * $plaintext.= 'a'; + * } + * + * echo $aes->decrypt($aes->encrypt($plaintext)); + * ?> + * + * + * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @category Crypt + * @package Crypt_AES + * @author Jim Wigginton + * @copyright MMVIII Jim Wigginton + * @license http://www.opensource.org/licenses/mit-license.html MIT License + * @link http://phpseclib.sourceforge.net + */ + +/** + * Include Crypt_Rijndael + */ +if (!class_exists('Crypt_Rijndael')) { + require_once('Rijndael.php'); +} + +/**#@+ + * @access public + * @see Crypt_AES::encrypt() + * @see Crypt_AES::decrypt() + */ +/** + * Encrypt / decrypt using the Counter mode. + * + * Set to -1 since that's what Crypt/Random.php uses to index the CTR mode. + * + * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Counter_.28CTR.29 + */ +define('CRYPT_AES_MODE_CTR', CRYPT_MODE_CTR); +/** + * Encrypt / decrypt using the Electronic Code Book mode. + * + * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Electronic_codebook_.28ECB.29 + */ +define('CRYPT_AES_MODE_ECB', CRYPT_MODE_ECB); +/** + * Encrypt / decrypt using the Code Book Chaining mode. + * + * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher-block_chaining_.28CBC.29 + */ +define('CRYPT_AES_MODE_CBC', CRYPT_MODE_CBC); +/** + * Encrypt / decrypt using the Cipher Feedback mode. + * + * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher_feedback_.28CFB.29 + */ +define('CRYPT_AES_MODE_CFB', CRYPT_MODE_CFB); +/** + * Encrypt / decrypt using the Cipher Feedback mode. + * + * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Output_feedback_.28OFB.29 + */ +define('CRYPT_AES_MODE_OFB', CRYPT_MODE_OFB); +/**#@-*/ + +/**#@+ + * @access private + * @see Crypt_AES::Crypt_AES() + */ +/** + * Toggles the internal implementation + */ +define('CRYPT_AES_MODE_INTERNAL', CRYPT_MODE_INTERNAL); +/** + * Toggles the mcrypt implementation + */ +define('CRYPT_AES_MODE_MCRYPT', CRYPT_MODE_MCRYPT); +/**#@-*/ + +/** + * Pure-PHP implementation of AES. + * + * @author Jim Wigginton + * @version 0.1.0 + * @access public + * @package Crypt_AES + */ +class Crypt_AES extends Crypt_Rijndael { + /** + * The namespace used by the cipher for its constants. + * + * @see Crypt_Base::const_namespace + * @var String + * @access private + */ + var $const_namespace = 'AES'; + + /** + * Default Constructor. + * + * Determines whether or not the mcrypt extension should be used. + * + * $mode could be: + * + * - CRYPT_AES_MODE_ECB + * + * - CRYPT_AES_MODE_CBC + * + * - CRYPT_AES_MODE_CTR + * + * - CRYPT_AES_MODE_CFB + * + * - CRYPT_AES_MODE_OFB + * + * If not explictly set, CRYPT_AES_MODE_CBC will be used. + * + * @see Crypt_Rijndael::Crypt_Rijndael() + * @see Crypt_Base::Crypt_Base() + * @param optional Integer $mode + * @access public + */ + function Crypt_AES($mode = CRYPT_AES_MODE_CBC) + { + parent::Crypt_Rijndael($mode); + } + + /** + * Dummy function + * + * Since Crypt_AES extends Crypt_Rijndael, this function is, technically, available, but it doesn't do anything. + * + * @see Crypt_Rijndael::setBlockLength() + * @access public + * @param Integer $length + */ + function setBlockLength($length) + { + return; + } +} + +// vim: ts=4:sw=4:et: +// vim6: fdl=1: diff --git a/inc/phpseclib/Crypt_Base.php b/inc/phpseclib/Crypt_Base.php new file mode 100644 index 000000000..7c650ca72 --- /dev/null +++ b/inc/phpseclib/Crypt_Base.php @@ -0,0 +1,1989 @@ + + * @author Hans-Juergen Petrich + * @copyright MMVII Jim Wigginton + * @license http://www.opensource.org/licenses/mit-license.html MIT License + * @version 1.0.1 + * @link http://phpseclib.sourceforge.net + */ + +/**#@+ + * @access public + * @see Crypt_Base::encrypt() + * @see Crypt_Base::decrypt() + */ +/** + * Encrypt / decrypt using the Counter mode. + * + * Set to -1 since that's what Crypt/Random.php uses to index the CTR mode. + * + * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Counter_.28CTR.29 + */ +define('CRYPT_MODE_CTR', -1); +/** + * Encrypt / decrypt using the Electronic Code Book mode. + * + * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Electronic_codebook_.28ECB.29 + */ +define('CRYPT_MODE_ECB', 1); +/** + * Encrypt / decrypt using the Code Book Chaining mode. + * + * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher-block_chaining_.28CBC.29 + */ +define('CRYPT_MODE_CBC', 2); +/** + * Encrypt / decrypt using the Cipher Feedback mode. + * + * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher_feedback_.28CFB.29 + */ +define('CRYPT_MODE_CFB', 3); +/** + * Encrypt / decrypt using the Output Feedback mode. + * + * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Output_feedback_.28OFB.29 + */ +define('CRYPT_MODE_OFB', 4); +/** + * Encrypt / decrypt using streaming mode. + * + */ +define('CRYPT_MODE_STREAM', 5); +/**#@-*/ + +/**#@+ + * @access private + * @see Crypt_Base::Crypt_Base() + */ +/** + * Base value for the internal implementation $engine switch + */ +define('CRYPT_MODE_INTERNAL', 1); +/** + * Base value for the mcrypt implementation $engine switch + */ +define('CRYPT_MODE_MCRYPT', 2); +/**#@-*/ + +/** + * Base Class for all Crypt_* cipher classes + * + * @author Jim Wigginton + * @author Hans-Juergen Petrich + * @version 1.0.0 + * @access public + * @package Crypt_Base + */ +class Crypt_Base { + /** + * The Encryption Mode + * + * @see Crypt_Base::Crypt_Base() + * @var Integer + * @access private + */ + var $mode; + + /** + * The Block Length of the block cipher + * + * @var Integer + * @access private + */ + var $block_size = 16; + + /** + * The Key + * + * @see Crypt_Base::setKey() + * @var String + * @access private + */ + var $key = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; + + /** + * The Initialization Vector + * + * @see Crypt_Base::setIV() + * @var String + * @access private + */ + var $iv; + + /** + * A "sliding" Initialization Vector + * + * @see Crypt_Base::enableContinuousBuffer() + * @see Crypt_Base::_clearBuffers() + * @var String + * @access private + */ + var $encryptIV; + + /** + * A "sliding" Initialization Vector + * + * @see Crypt_Base::enableContinuousBuffer() + * @see Crypt_Base::_clearBuffers() + * @var String + * @access private + */ + var $decryptIV; + + /** + * Continuous Buffer status + * + * @see Crypt_Base::enableContinuousBuffer() + * @var Boolean + * @access private + */ + var $continuousBuffer = false; + + /** + * Encryption buffer for CTR, OFB and CFB modes + * + * @see Crypt_Base::encrypt() + * @see Crypt_Base::_clearBuffers() + * @var Array + * @access private + */ + var $enbuffer; + + /** + * Decryption buffer for CTR, OFB and CFB modes + * + * @see Crypt_Base::decrypt() + * @see Crypt_Base::_clearBuffers() + * @var Array + * @access private + */ + var $debuffer; + + /** + * mcrypt resource for encryption + * + * The mcrypt resource can be recreated every time something needs to be created or it can be created just once. + * Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode. + * + * @see Crypt_Base::encrypt() + * @var Resource + * @access private + */ + var $enmcrypt; + + /** + * mcrypt resource for decryption + * + * The mcrypt resource can be recreated every time something needs to be created or it can be created just once. + * Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode. + * + * @see Crypt_Base::decrypt() + * @var Resource + * @access private + */ + var $demcrypt; + + /** + * Does the enmcrypt resource need to be (re)initialized? + * + * @see Crypt_Twofish::setKey() + * @see Crypt_Twofish::setIV() + * @var Boolean + * @access private + */ + var $enchanged = true; + + /** + * Does the demcrypt resource need to be (re)initialized? + * + * @see Crypt_Twofish::setKey() + * @see Crypt_Twofish::setIV() + * @var Boolean + * @access private + */ + var $dechanged = true; + + /** + * mcrypt resource for CFB mode + * + * mcrypt's CFB mode, in (and only in) buffered context, + * is broken, so phpseclib implements the CFB mode by it self, + * even when the mcrypt php extension is available. + * + * In order to do the CFB-mode work (fast) phpseclib + * use a separate ECB-mode mcrypt resource. + * + * @link http://phpseclib.sourceforge.net/cfb-demo.phps + * @see Crypt_Base::encrypt() + * @see Crypt_Base::decrypt() + * @see Crypt_Base::_setupMcrypt() + * @var Resource + * @access private + */ + var $ecb; + + /** + * Optimizing value while CFB-encrypting + * + * Only relevant if $continuousBuffer enabled + * and $engine == CRYPT_MODE_MCRYPT + * + * It's faster to re-init $enmcrypt if + * $buffer bytes > $cfb_init_len than + * using the $ecb resource furthermore. + * + * This value depends of the choosen cipher + * and the time it would be needed for it's + * initialization [by mcrypt_generic_init()] + * which, typically, depends on the complexity + * on its internaly Key-expanding algorithm. + * + * @see Crypt_Base::encrypt() + * @var Integer + * @access private + */ + var $cfb_init_len = 600; + + /** + * Does internal cipher state need to be (re)initialized? + * + * @see setKey() + * @see setIV() + * @see disableContinuousBuffer() + * @var Boolean + * @access private + */ + var $changed = true; + + /** + * Padding status + * + * @see Crypt_Base::enablePadding() + * @var Boolean + * @access private + */ + var $padding = true; + + /** + * Is the mode one that is paddable? + * + * @see Crypt_Base::Crypt_Base() + * @var Boolean + * @access private + */ + var $paddable = false; + + /** + * Holds which crypt engine internaly should be use, + * which will be determined automatically on __construct() + * + * Currently available $engines are: + * - CRYPT_MODE_MCRYPT (fast, php-extension: mcrypt, extension_loaded('mcrypt') required) + * - CRYPT_MODE_INTERNAL (slower, pure php-engine, no php-extension required) + * + * In the pipeline... maybe. But currently not available: + * - CRYPT_MODE_OPENSSL (very fast, php-extension: openssl, extension_loaded('openssl') required) + * + * If possible, CRYPT_MODE_MCRYPT will be used for each cipher. + * Otherwise CRYPT_MODE_INTERNAL + * + * @see Crypt_Base::encrypt() + * @see Crypt_Base::decrypt() + * @var Integer + * @access private + */ + var $engine; + + /** + * The mcrypt specific name of the cipher + * + * Only used if $engine == CRYPT_MODE_MCRYPT + * + * @link http://www.php.net/mcrypt_module_open + * @link http://www.php.net/mcrypt_list_algorithms + * @see Crypt_Base::_setupMcrypt() + * @var String + * @access private + */ + var $cipher_name_mcrypt; + + /** + * The default password key_size used by setPassword() + * + * @see Crypt_Base::setPassword() + * @var Integer + * @access private + */ + var $password_key_size = 32; + + /** + * The default salt used by setPassword() + * + * @see Crypt_Base::setPassword() + * @var String + * @access private + */ + var $password_default_salt = 'phpseclib/salt'; + + /** + * The namespace used by the cipher for its constants. + * + * ie: AES.php is using CRYPT_AES_MODE_* for its constants + * so $const_namespace is AES + * + * DES.php is using CRYPT_DES_MODE_* for its constants + * so $const_namespace is DES... and so on + * + * All CRYPT_<$const_namespace>_MODE_* are aliases of + * the generic CRYPT_MODE_* constants, so both could be used + * for each cipher. + * + * Example: + * $aes = new Crypt_AES(CRYPT_AES_MODE_CFB); // $aes will operate in cfb mode + * $aes = new Crypt_AES(CRYPT_MODE_CFB); // identical + * + * @see Crypt_Base::Crypt_Base() + * @var String + * @access private + */ + var $const_namespace; + + /** + * The name of the performance-optimized callback function + * + * Used by encrypt() / decrypt() + * only if $engine == CRYPT_MODE_INTERNAL + * + * @see Crypt_Base::encrypt() + * @see Crypt_Base::decrypt() + * @see Crypt_Base::_setupInlineCrypt() + * @see Crypt_Base::$use_inline_crypt + * @var Callback + * @access private + */ + var $inline_crypt; + + /** + * Holds whether performance-optimized $inline_crypt() can/should be used. + * + * @see Crypt_Base::encrypt() + * @see Crypt_Base::decrypt() + * @see Crypt_Base::inline_crypt + * @var mixed + * @access private + */ + var $use_inline_crypt; + + /** + * Default Constructor. + * + * Determines whether or not the mcrypt extension should be used. + * + * $mode could be: + * + * - CRYPT_MODE_ECB + * + * - CRYPT_MODE_CBC + * + * - CRYPT_MODE_CTR + * + * - CRYPT_MODE_CFB + * + * - CRYPT_MODE_OFB + * + * (or the alias constants of the choosen cipher, for example for AES: CRYPT_AES_MODE_ECB or CRYPT_AES_MODE_CBC ...) + * + * If not explictly set, CRYPT_MODE_CBC will be used. + * + * @param optional Integer $mode + * @access public + */ + function Crypt_Base($mode = CRYPT_MODE_CBC) + { + $const_crypt_mode = 'CRYPT_' . $this->const_namespace . '_MODE'; + + // Determining the availibility of mcrypt support for the cipher + if (!defined($const_crypt_mode)) { + switch (true) { + case extension_loaded('mcrypt') && in_array($this->cipher_name_mcrypt, mcrypt_list_algorithms()): + define($const_crypt_mode, CRYPT_MODE_MCRYPT); + break; + default: + define($const_crypt_mode, CRYPT_MODE_INTERNAL); + } + } + + // Determining which internal $engine should be used. + // The fastes possible first. + switch (true) { + case empty($this->cipher_name_mcrypt): // The cipher module has no mcrypt-engine support at all so we force CRYPT_MODE_INTERNAL + $this->engine = CRYPT_MODE_INTERNAL; + break; + case constant($const_crypt_mode) == CRYPT_MODE_MCRYPT: + $this->engine = CRYPT_MODE_MCRYPT; + break; + default: + $this->engine = CRYPT_MODE_INTERNAL; + } + + // $mode dependent settings + switch ($mode) { + case CRYPT_MODE_ECB: + $this->paddable = true; + $this->mode = $mode; + break; + case CRYPT_MODE_CTR: + case CRYPT_MODE_CFB: + case CRYPT_MODE_OFB: + case CRYPT_MODE_STREAM: + $this->mode = $mode; + break; + case CRYPT_MODE_CBC: + default: + $this->paddable = true; + $this->mode = CRYPT_MODE_CBC; + } + + // Determining whether inline crypting can be used by the cipher + if ($this->use_inline_crypt !== false && function_exists('create_function')) { + $this->use_inline_crypt = true; + } + } + + /** + * Sets the initialization vector. (optional) + * + * SetIV is not required when CRYPT_MODE_ECB (or ie for AES: CRYPT_AES_MODE_ECB) is being used. If not explictly set, it'll be assumed + * to be all zero's. + * + * Note: Could, but not must, extend by the child Crypt_* class + * + * @access public + * @param String $iv + */ + function setIV($iv) + { + if ($this->mode == CRYPT_MODE_ECB) { + return; + } + + $this->iv = $iv; + $this->changed = true; + } + + /** + * Sets the key. + * + * The min/max length(s) of the key depends on the cipher which is used. + * If the key not fits the length(s) of the cipher it will paded with null bytes + * up to the closest valid key length. If the key is more than max length, + * we trim the excess bits. + * + * If the key is not explicitly set, it'll be assumed to be all null bytes. + * + * Note: Could, but not must, extend by the child Crypt_* class + * + * @access public + * @param String $key + */ + function setKey($key) + { + $this->key = $key; + $this->changed = true; + } + + /** + * Sets the password. + * + * Depending on what $method is set to, setPassword()'s (optional) parameters are as follows: + * {@link http://en.wikipedia.org/wiki/PBKDF2 pbkdf2}: + * $hash, $salt, $count, $dkLen + * + * Where $hash (default = sha1) currently supports the following hashes: see: Crypt/Hash.php + * + * Note: Could, but not must, extend by the child Crypt_* class + * + * @see Crypt/Hash.php + * @param String $password + * @param optional String $method + * @access public + */ + function setPassword($password, $method = 'pbkdf2') + { + $key = ''; + + switch ($method) { + default: // 'pbkdf2' + $func_args = func_get_args(); + + // Hash function + $hash = isset($func_args[2]) ? $func_args[2] : 'sha1'; + + // WPA and WPA2 use the SSID as the salt + $salt = isset($func_args[3]) ? $func_args[3] : $this->password_default_salt; + + // RFC2898#section-4.2 uses 1,000 iterations by default + // WPA and WPA2 use 4,096. + $count = isset($func_args[4]) ? $func_args[4] : 1000; + + // Keylength + $dkLen = isset($func_args[5]) ? $func_args[5] : $this->password_key_size; + + // Determining if php[>=5.5.0]'s hash_pbkdf2() function avail- and useable + switch (true) { + case !function_exists('hash_pbkdf2'): + case !function_exists('hash_algos'): + case !in_array($hash, hash_algos()): + if (!class_exists('Crypt_Hash')) { + require_once('Crypt/Hash.php'); + } + $i = 1; + while (strlen($key) < $dkLen) { + $hmac = new Crypt_Hash(); + $hmac->setHash($hash); + $hmac->setKey($password); + $f = $u = $hmac->hash($salt . pack('N', $i++)); + for ($j = 2; $j <= $count; ++$j) { + $u = $hmac->hash($u); + $f^= $u; + } + $key.= $f; + } + $key = substr($key, 0, $dkLen); + break; + default: + $key = hash_pbkdf2($hash, $password, $salt, $count, $dkLen, true); + } + } + + $this->setKey($key); + } + + /** + * Encrypts a message. + * + * $plaintext will be padded with additional bytes such that it's length is a multiple of the block size. Other cipher + * implementations may or may not pad in the same manner. Other common approaches to padding and the reasons why it's + * necessary are discussed in the following + * URL: + * + * {@link http://www.di-mgt.com.au/cryptopad.html http://www.di-mgt.com.au/cryptopad.html} + * + * An alternative to padding is to, separately, send the length of the file. This is what SSH, in fact, does. + * strlen($plaintext) will still need to be a multiple of the block size, however, arbitrary values can be added to make it that + * length. + * + * Note: Could, but not must, extend by the child Crypt_* class + * + * @see Crypt_Base::decrypt() + * @access public + * @param String $plaintext + * @return String $cipertext + */ + function encrypt($plaintext) + { + if ($this->engine == CRYPT_MODE_MCRYPT) { + if ($this->changed) { + $this->_setupMcrypt(); + $this->changed = false; + } + if ($this->enchanged) { + mcrypt_generic_init($this->enmcrypt, $this->key, $this->encryptIV); + $this->enchanged = false; + } + + // re: {@link http://phpseclib.sourceforge.net/cfb-demo.phps} + // using mcrypt's default handing of CFB the above would output two different things. using phpseclib's + // rewritten CFB implementation the above outputs the same thing twice. + if ($this->mode == CRYPT_MODE_CFB && $this->continuousBuffer) { + $block_size = $this->block_size; + $iv = &$this->encryptIV; + $pos = &$this->enbuffer['pos']; + $len = strlen($plaintext); + $ciphertext = ''; + $i = 0; + if ($pos) { + $orig_pos = $pos; + $max = $block_size - $pos; + if ($len >= $max) { + $i = $max; + $len-= $max; + $pos = 0; + } else { + $i = $len; + $pos+= $len; + $len = 0; + } + $ciphertext = substr($iv, $orig_pos) ^ $plaintext; + $iv = substr_replace($iv, $ciphertext, $orig_pos, $i); + $this->enbuffer['enmcrypt_init'] = true; + } + if ($len >= $block_size) { + if ($this->enbuffer['enmcrypt_init'] === false || $len > $this->cfb_init_len) { + if ($this->enbuffer['enmcrypt_init'] === true) { + mcrypt_generic_init($this->enmcrypt, $this->key, $iv); + $this->enbuffer['enmcrypt_init'] = false; + } + $ciphertext.= mcrypt_generic($this->enmcrypt, substr($plaintext, $i, $len - $len % $block_size)); + $iv = substr($ciphertext, -$block_size); + $len%= $block_size; + } else { + while ($len >= $block_size) { + $iv = mcrypt_generic($this->ecb, $iv) ^ substr($plaintext, $i, $block_size); + $ciphertext.= $iv; + $len-= $block_size; + $i+= $block_size; + } + } + } + + if ($len) { + $iv = mcrypt_generic($this->ecb, $iv); + $block = $iv ^ substr($plaintext, -$len); + $iv = substr_replace($iv, $block, 0, $len); + $ciphertext.= $block; + $pos = $len; + } + + return $ciphertext; + } + + if ($this->paddable) { + $plaintext = $this->_pad($plaintext); + } + + $ciphertext = mcrypt_generic($this->enmcrypt, $plaintext); + + if (!$this->continuousBuffer) { + mcrypt_generic_init($this->enmcrypt, $this->key, $this->encryptIV); + } + + return $ciphertext; + } + + if ($this->changed) { + $this->_setup(); + $this->changed = false; + } + if ($this->use_inline_crypt) { + $inline = $this->inline_crypt; + return $inline('encrypt', $this, $plaintext); + } + if ($this->paddable) { + $plaintext = $this->_pad($plaintext); + } + + $buffer = &$this->enbuffer; + $block_size = $this->block_size; + $ciphertext = ''; + switch ($this->mode) { + case CRYPT_MODE_ECB: + for ($i = 0; $i < strlen($plaintext); $i+=$block_size) { + $ciphertext.= $this->_encryptBlock(substr($plaintext, $i, $block_size)); + } + break; + case CRYPT_MODE_CBC: + $xor = $this->encryptIV; + for ($i = 0; $i < strlen($plaintext); $i+=$block_size) { + $block = substr($plaintext, $i, $block_size); + $block = $this->_encryptBlock($block ^ $xor); + $xor = $block; + $ciphertext.= $block; + } + if ($this->continuousBuffer) { + $this->encryptIV = $xor; + } + break; + case CRYPT_MODE_CTR: + $xor = $this->encryptIV; + if (strlen($buffer['encrypted'])) { + for ($i = 0; $i < strlen($plaintext); $i+=$block_size) { + $block = substr($plaintext, $i, $block_size); + if (strlen($block) > strlen($buffer['encrypted'])) { + $buffer['encrypted'].= $this->_encryptBlock($this->_generateXor($xor, $block_size)); + } + $key = $this->_stringShift($buffer['encrypted'], $block_size); + $ciphertext.= $block ^ $key; + } + } else { + for ($i = 0; $i < strlen($plaintext); $i+=$block_size) { + $block = substr($plaintext, $i, $block_size); + $key = $this->_encryptBlock($this->_generateXor($xor, $block_size)); + $ciphertext.= $block ^ $key; + } + } + if ($this->continuousBuffer) { + $this->encryptIV = $xor; + if ($start = strlen($plaintext) % $block_size) { + $buffer['encrypted'] = substr($key, $start) . $buffer['encrypted']; + } + } + break; + case CRYPT_MODE_CFB: + // cfb loosely routines inspired by openssl's: + // {@link http://cvs.openssl.org/fileview?f=openssl/crypto/modes/cfb128.c&v=1.3.2.2.2.1} + if ($this->continuousBuffer) { + $iv = &$this->encryptIV; + $pos = &$buffer['pos']; + } else { + $iv = $this->encryptIV; + $pos = 0; + } + $len = strlen($plaintext); + $i = 0; + if ($pos) { + $orig_pos = $pos; + $max = $block_size - $pos; + if ($len >= $max) { + $i = $max; + $len-= $max; + $pos = 0; + } else { + $i = $len; + $pos+= $len; + $len = 0; + } + // ie. $i = min($max, $len), $len-= $i, $pos+= $i, $pos%= $blocksize + $ciphertext = substr($iv, $orig_pos) ^ $plaintext; + $iv = substr_replace($iv, $ciphertext, $orig_pos, $i); + } + while ($len >= $block_size) { + $iv = $this->_encryptBlock($iv) ^ substr($plaintext, $i, $block_size); + $ciphertext.= $iv; + $len-= $block_size; + $i+= $block_size; + } + if ($len) { + $iv = $this->_encryptBlock($iv); + $block = $iv ^ substr($plaintext, $i); + $iv = substr_replace($iv, $block, 0, $len); + $ciphertext.= $block; + $pos = $len; + } + break; + case CRYPT_MODE_OFB: + $xor = $this->encryptIV; + if (strlen($buffer['xor'])) { + for ($i = 0; $i < strlen($plaintext); $i+=$block_size) { + $block = substr($plaintext, $i, $block_size); + if (strlen($block) > strlen($buffer['xor'])) { + $xor = $this->_encryptBlock($xor); + $buffer['xor'].= $xor; + } + $key = $this->_stringShift($buffer['xor'], $block_size); + $ciphertext.= $block ^ $key; + } + } else { + for ($i = 0; $i < strlen($plaintext); $i+=$block_size) { + $xor = $this->_encryptBlock($xor); + $ciphertext.= substr($plaintext, $i, $block_size) ^ $xor; + } + $key = $xor; + } + if ($this->continuousBuffer) { + $this->encryptIV = $xor; + if ($start = strlen($plaintext) % $block_size) { + $buffer['xor'] = substr($key, $start) . $buffer['xor']; + } + } + break; + case CRYPT_MODE_STREAM: + $ciphertext = $this->_encryptBlock($plaintext); + break; + } + + return $ciphertext; + } + + /** + * Decrypts a message. + * + * If strlen($ciphertext) is not a multiple of the block size, null bytes will be added to the end of the string until + * it is. + * + * Note: Could, but not must, extend by the child Crypt_* class + * + * @see Crypt_Base::encrypt() + * @access public + * @param String $ciphertext + * @return String $plaintext + */ + function decrypt($ciphertext) + { + if ($this->engine == CRYPT_MODE_MCRYPT) { + $block_size = $this->block_size; + if ($this->changed) { + $this->_setupMcrypt(); + $this->changed = false; + } + if ($this->dechanged) { + mcrypt_generic_init($this->demcrypt, $this->key, $this->decryptIV); + $this->dechanged = false; + } + + if ($this->mode == CRYPT_MODE_CFB && $this->continuousBuffer) { + $iv = &$this->decryptIV; + $pos = &$this->debuffer['pos']; + $len = strlen($ciphertext); + $plaintext = ''; + $i = 0; + if ($pos) { + $orig_pos = $pos; + $max = $block_size - $pos; + if ($len >= $max) { + $i = $max; + $len-= $max; + $pos = 0; + } else { + $i = $len; + $pos+= $len; + $len = 0; + } + // ie. $i = min($max, $len), $len-= $i, $pos+= $i, $pos%= $blocksize + $plaintext = substr($iv, $orig_pos) ^ $ciphertext; + $iv = substr_replace($iv, substr($ciphertext, 0, $i), $orig_pos, $i); + } + if ($len >= $block_size) { + $cb = substr($ciphertext, $i, $len - $len % $block_size); + $plaintext.= mcrypt_generic($this->ecb, $iv . $cb) ^ $cb; + $iv = substr($cb, -$block_size); + $len%= $block_size; + } + if ($len) { + $iv = mcrypt_generic($this->ecb, $iv); + $plaintext.= $iv ^ substr($ciphertext, -$len); + $iv = substr_replace($iv, substr($ciphertext, -$len), 0, $len); + $pos = $len; + } + + return $plaintext; + } + + if ($this->paddable) { + // we pad with chr(0) since that's what mcrypt_generic does. to quote from {@link http://www.php.net/function.mcrypt-generic}: + // "The data is padded with "\0" to make sure the length of the data is n * blocksize." + $ciphertext = str_pad($ciphertext, strlen($ciphertext) + ($block_size - strlen($ciphertext) % $block_size) % $block_size, chr(0)); + } + + $plaintext = mdecrypt_generic($this->demcrypt, $ciphertext); + + if (!$this->continuousBuffer) { + mcrypt_generic_init($this->demcrypt, $this->key, $this->decryptIV); + } + + return $this->paddable ? $this->_unpad($plaintext) : $plaintext; + } + + if ($this->changed) { + $this->_setup(); + $this->changed = false; + } + if ($this->use_inline_crypt) { + $inline = $this->inline_crypt; + return $inline('decrypt', $this, $ciphertext); + } + + $block_size = $this->block_size; + if ($this->paddable) { + // we pad with chr(0) since that's what mcrypt_generic does [...] + $ciphertext = str_pad($ciphertext, strlen($ciphertext) + ($block_size - strlen($ciphertext) % $block_size) % $block_size, chr(0)); + } + + $buffer = &$this->debuffer; + $plaintext = ''; + switch ($this->mode) { + case CRYPT_MODE_ECB: + for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) { + $plaintext.= $this->_decryptBlock(substr($ciphertext, $i, $block_size)); + } + break; + case CRYPT_MODE_CBC: + $xor = $this->decryptIV; + for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) { + $block = substr($ciphertext, $i, $block_size); + $plaintext.= $this->_decryptBlock($block) ^ $xor; + $xor = $block; + } + if ($this->continuousBuffer) { + $this->decryptIV = $xor; + } + break; + case CRYPT_MODE_CTR: + $xor = $this->decryptIV; + if (strlen($buffer['ciphertext'])) { + for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) { + $block = substr($ciphertext, $i, $block_size); + if (strlen($block) > strlen($buffer['ciphertext'])) { + $buffer['ciphertext'].= $this->_encryptBlock($this->_generateXor($xor, $block_size)); + } + $key = $this->_stringShift($buffer['ciphertext'], $block_size); + $plaintext.= $block ^ $key; + } + } else { + for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) { + $block = substr($ciphertext, $i, $block_size); + $key = $this->_encryptBlock($this->_generateXor($xor, $block_size)); + $plaintext.= $block ^ $key; + } + } + if ($this->continuousBuffer) { + $this->decryptIV = $xor; + if ($start = strlen($ciphertext) % $block_size) { + $buffer['ciphertext'] = substr($key, $start) . $buffer['ciphertext']; + } + } + break; + case CRYPT_MODE_CFB: + if ($this->continuousBuffer) { + $iv = &$this->decryptIV; + $pos = &$buffer['pos']; + } else { + $iv = $this->decryptIV; + $pos = 0; + } + $len = strlen($ciphertext); + $i = 0; + if ($pos) { + $orig_pos = $pos; + $max = $block_size - $pos; + if ($len >= $max) { + $i = $max; + $len-= $max; + $pos = 0; + } else { + $i = $len; + $pos+= $len; + $len = 0; + } + // ie. $i = min($max, $len), $len-= $i, $pos+= $i, $pos%= $blocksize + $plaintext = substr($iv, $orig_pos) ^ $ciphertext; + $iv = substr_replace($iv, substr($ciphertext, 0, $i), $orig_pos, $i); + } + while ($len >= $block_size) { + $iv = $this->_encryptBlock($iv); + $cb = substr($ciphertext, $i, $block_size); + $plaintext.= $iv ^ $cb; + $iv = $cb; + $len-= $block_size; + $i+= $block_size; + } + if ($len) { + $iv = $this->_encryptBlock($iv); + $plaintext.= $iv ^ substr($ciphertext, $i); + $iv = substr_replace($iv, substr($ciphertext, $i), 0, $len); + $pos = $len; + } + break; + case CRYPT_MODE_OFB: + $xor = $this->decryptIV; + if (strlen($buffer['xor'])) { + for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) { + $block = substr($ciphertext, $i, $block_size); + if (strlen($block) > strlen($buffer['xor'])) { + $xor = $this->_encryptBlock($xor); + $buffer['xor'].= $xor; + } + $key = $this->_stringShift($buffer['xor'], $block_size); + $plaintext.= $block ^ $key; + } + } else { + for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) { + $xor = $this->_encryptBlock($xor); + $plaintext.= substr($ciphertext, $i, $block_size) ^ $xor; + } + $key = $xor; + } + if ($this->continuousBuffer) { + $this->decryptIV = $xor; + if ($start = strlen($ciphertext) % $block_size) { + $buffer['xor'] = substr($key, $start) . $buffer['xor']; + } + } + break; + case CRYPT_MODE_STREAM: + $plaintext = $this->_decryptBlock($ciphertext); + break; + } + return $this->paddable ? $this->_unpad($plaintext) : $plaintext; + } + + /** + * Pad "packets". + * + * Block ciphers working by encrypting between their specified [$this->]block_size at a time + * If you ever need to encrypt or decrypt something that isn't of the proper length, it becomes necessary to + * pad the input so that it is of the proper length. + * + * Padding is enabled by default. Sometimes, however, it is undesirable to pad strings. Such is the case in SSH, + * where "packets" are padded with random bytes before being encrypted. Unpad these packets and you risk stripping + * away characters that shouldn't be stripped away. (SSH knows how many bytes are added because the length is + * transmitted separately) + * + * @see Crypt_Base::disablePadding() + * @access public + */ + function enablePadding() + { + $this->padding = true; + } + + /** + * Do not pad packets. + * + * @see Crypt_Base::enablePadding() + * @access public + */ + function disablePadding() + { + $this->padding = false; + } + + /** + * Treat consecutive "packets" as if they are a continuous buffer. + * + * Say you have a 32-byte plaintext $plaintext. Using the default behavior, the two following code snippets + * will yield different outputs: + * + * + * echo $rijndael->encrypt(substr($plaintext, 0, 16)); + * echo $rijndael->encrypt(substr($plaintext, 16, 16)); + * + * + * echo $rijndael->encrypt($plaintext); + * + * + * The solution is to enable the continuous buffer. Although this will resolve the above discrepancy, it creates + * another, as demonstrated with the following: + * + * + * $rijndael->encrypt(substr($plaintext, 0, 16)); + * echo $rijndael->decrypt($rijndael->encrypt(substr($plaintext, 16, 16))); + * + * + * echo $rijndael->decrypt($rijndael->encrypt(substr($plaintext, 16, 16))); + * + * + * With the continuous buffer disabled, these would yield the same output. With it enabled, they yield different + * outputs. The reason is due to the fact that the initialization vector's change after every encryption / + * decryption round when the continuous buffer is enabled. When it's disabled, they remain constant. + * + * Put another way, when the continuous buffer is enabled, the state of the Crypt_*() object changes after each + * encryption / decryption round, whereas otherwise, it'd remain constant. For this reason, it's recommended that + * continuous buffers not be used. They do offer better security and are, in fact, sometimes required (SSH uses them), + * however, they are also less intuitive and more likely to cause you problems. + * + * Note: Could, but not must, extend by the child Crypt_* class + * + * @see Crypt_Base::disableContinuousBuffer() + * @access public + */ + function enableContinuousBuffer() + { + if ($this->mode == CRYPT_MODE_ECB) { + return; + } + + $this->continuousBuffer = true; + } + + /** + * Treat consecutive packets as if they are a discontinuous buffer. + * + * The default behavior. + * + * Note: Could, but not must, extend by the child Crypt_* class + * + * @see Crypt_Base::enableContinuousBuffer() + * @access public + */ + function disableContinuousBuffer() + { + if ($this->mode == CRYPT_MODE_ECB) { + return; + } + if (!$this->continuousBuffer) { + return; + } + + $this->continuousBuffer = false; + $this->changed = true; + } + + /** + * Encrypts a block + * + * Note: Must extend by the child Crypt_* class + * + * @access private + * @param String $in + * @return String + */ + function _encryptBlock($in) + { + user_error((version_compare(PHP_VERSION, '5.0.0', '>=') ? __METHOD__ : __FUNCTION__) . '() must extend by class ' . get_class($this), E_USER_ERROR); + } + + /** + * Decrypts a block + * + * Note: Must extend by the child Crypt_* class + * + * @access private + * @param String $in + * @return String + */ + function _decryptBlock($in) + { + user_error((version_compare(PHP_VERSION, '5.0.0', '>=') ? __METHOD__ : __FUNCTION__) . '() must extend by class ' . get_class($this), E_USER_ERROR); + } + + /** + * Setup the key (expansion) + * + * Only used if $engine == CRYPT_MODE_INTERNAL + * + * Note: Must extend by the child Crypt_* class + * + * @see Crypt_Base::_setup() + * @access private + */ + function _setupKey() + { + user_error((version_compare(PHP_VERSION, '5.0.0', '>=') ? __METHOD__ : __FUNCTION__) . '() must extend by class ' . get_class($this), E_USER_ERROR); + } + + /** + * Setup the CRYPT_MODE_INTERNAL $engine + * + * (re)init, if necessary, the internal cipher $engine and flush all $buffers + * Used (only) if $engine == CRYPT_MODE_INTERNAL + * + * _setup() will be called each time if $changed === true + * typically this happens when using one or more of following public methods: + * + * - setKey() + * + * - setIV() + * + * - disableContinuousBuffer() + * + * - First run of encrypt() / decrypt() with no init-settings + * + * Internally: _setup() is called always before(!) en/decryption. + * + * Note: Could, but not must, extend by the child Crypt_* class + * + * @see setKey() + * @see setIV() + * @see disableContinuousBuffer() + * @access private + */ + function _setup() + { + $this->_clearBuffers(); + $this->_setupKey(); + + if ($this->use_inline_crypt) { + $this->_setupInlineCrypt(); + } + } + + /** + * Setup the CRYPT_MODE_MCRYPT $engine + * + * (re)init, if necessary, the (ext)mcrypt resources and flush all $buffers + * Used (only) if $engine = CRYPT_MODE_MCRYPT + * + * _setupMcrypt() will be called each time if $changed === true + * typically this happens when using one or more of following public methods: + * + * - setKey() + * + * - setIV() + * + * - disableContinuousBuffer() + * + * - First run of encrypt() / decrypt() + * + * + * Note: Could, but not must, extend by the child Crypt_* class + * + * @see setKey() + * @see setIV() + * @see disableContinuousBuffer() + * @access private + */ + function _setupMcrypt() + { + $this->_clearBuffers(); + $this->enchanged = $this->dechanged = true; + + if (!isset($this->enmcrypt)) { + static $mcrypt_modes = array( + CRYPT_MODE_CTR => 'ctr', + CRYPT_MODE_ECB => MCRYPT_MODE_ECB, + CRYPT_MODE_CBC => MCRYPT_MODE_CBC, + CRYPT_MODE_CFB => 'ncfb', + CRYPT_MODE_OFB => MCRYPT_MODE_NOFB, + CRYPT_MODE_STREAM => MCRYPT_MODE_STREAM, + ); + + $this->demcrypt = mcrypt_module_open($this->cipher_name_mcrypt, '', $mcrypt_modes[$this->mode], ''); + $this->enmcrypt = mcrypt_module_open($this->cipher_name_mcrypt, '', $mcrypt_modes[$this->mode], ''); + + // we need the $ecb mcrypt resource (only) in MODE_CFB with enableContinuousBuffer() + // to workaround mcrypt's broken ncfb implementation in buffered mode + // see: {@link http://phpseclib.sourceforge.net/cfb-demo.phps} + if ($this->mode == CRYPT_MODE_CFB) { + $this->ecb = mcrypt_module_open($this->cipher_name_mcrypt, '', MCRYPT_MODE_ECB, ''); + } + + } // else should mcrypt_generic_deinit be called? + + if ($this->mode == CRYPT_MODE_CFB) { + mcrypt_generic_init($this->ecb, $this->key, str_repeat("\0", $this->block_size)); + } + } + + /** + * Pads a string + * + * Pads a string using the RSA PKCS padding standards so that its length is a multiple of the blocksize. + * $this->block_size - (strlen($text) % $this->block_size) bytes are added, each of which is equal to + * chr($this->block_size - (strlen($text) % $this->block_size) + * + * If padding is disabled and $text is not a multiple of the blocksize, the string will be padded regardless + * and padding will, hence forth, be enabled. + * + * @see Crypt_Base::_unpad() + * @param String $text + * @access private + * @return String + */ + function _pad($text) + { + $length = strlen($text); + + if (!$this->padding) { + if ($length % $this->block_size == 0) { + return $text; + } else { + user_error("The plaintext's length ($length) is not a multiple of the block size ({$this->block_size})"); + $this->padding = true; + } + } + + $pad = $this->block_size - ($length % $this->block_size); + + return str_pad($text, $length + $pad, chr($pad)); + } + + /** + * Unpads a string. + * + * If padding is enabled and the reported padding length is invalid the encryption key will be assumed to be wrong + * and false will be returned. + * + * @see Crypt_Base::_pad() + * @param String $text + * @access private + * @return String + */ + function _unpad($text) + { + if (!$this->padding) { + return $text; + } + + $length = ord($text[strlen($text) - 1]); + + if (!$length || $length > $this->block_size) { + return false; + } + + return substr($text, 0, -$length); + } + + /** + * Clears internal buffers + * + * Clearing/resetting the internal buffers is done everytime + * after disableContinuousBuffer() or on cipher $engine (re)init + * ie after setKey() or setIV() + * + * Note: Could, but not must, extend by the child Crypt_* class + * + * @access public + */ + function _clearBuffers() + { + $this->enbuffer = array('encrypted' => '', 'xor' => '', 'pos' => 0, 'enmcrypt_init' => true); + $this->debuffer = array('ciphertext' => '', 'xor' => '', 'pos' => 0, 'demcrypt_init' => true); + + // mcrypt's handling of invalid's $iv: + // $this->encryptIV = $this->decryptIV = strlen($this->iv) == $this->block_size ? $this->iv : str_repeat("\0", $this->block_size); + $this->encryptIV = $this->decryptIV = str_pad(substr($this->iv, 0, $this->block_size), $this->block_size, "\0"); + } + + /** + * String Shift + * + * Inspired by array_shift + * + * @param String $string + * @param optional Integer $index + * @access private + * @return String + */ + function _stringShift(&$string, $index = 1) + { + $substr = substr($string, 0, $index); + $string = substr($string, $index); + return $substr; + } + + /** + * Generate CTR XOR encryption key + * + * Encrypt the output of this and XOR it against the ciphertext / plaintext to get the + * plaintext / ciphertext in CTR mode. + * + * @see Crypt_Base::decrypt() + * @see Crypt_Base::encrypt() + * @param String $iv + * @param Integer $length + * @access private + * @return String $xor + */ + function _generateXor(&$iv, $length) + { + $xor = ''; + $block_size = $this->block_size; + $num_blocks = floor(($length + ($block_size - 1)) / $block_size); + for ($i = 0; $i < $num_blocks; $i++) { + $xor.= $iv; + for ($j = 4; $j <= $block_size; $j+= 4) { + $temp = substr($iv, -$j, 4); + switch ($temp) { + case "\xFF\xFF\xFF\xFF": + $iv = substr_replace($iv, "\x00\x00\x00\x00", -$j, 4); + break; + case "\x7F\xFF\xFF\xFF": + $iv = substr_replace($iv, "\x80\x00\x00\x00", -$j, 4); + break 2; + default: + extract(unpack('Ncount', $temp)); + $iv = substr_replace($iv, pack('N', $count + 1), -$j, 4); + break 2; + } + } + } + + return $xor; + } + + /** + * Setup the performance-optimized function for de/encrypt() + * + * Stores the created (or existing) callback function-name + * in $this->inline_crypt + * + * Internally for phpseclib developers: + * + * _setupInlineCrypt() would be called only if: + * + * - $engine == CRYPT_MODE_INTERNAL and + * + * - $use_inline_crypt === true + * + * - each time on _setup(), after(!) _setupKey() + * + * + * This ensures that _setupInlineCrypt() has allways a + * full ready2go initializated internal cipher $engine state + * where, for example, the keys allready expanded, + * keys/block_size calculated and such. + * + * It is, each time if called, the responsibility of _setupInlineCrypt(): + * + * - to set $this->inline_crypt to a valid and fully working callback function + * as a (faster) replacement for encrypt() / decrypt() + * + * - NOT to create unlimited callback functions (for memory reasons!) + * no matter how often _setupInlineCrypt() would be called. At some + * point of amount they must be generic re-useable. + * + * - the code of _setupInlineCrypt() it self, + * and the generated callback code, + * must be, in following order: + * - 100% safe + * - 100% compatible to encrypt()/decrypt() + * - using only php5+ features/lang-constructs/php-extensions if + * compatibility (down to php4) or fallback is provided + * - readable/maintainable/understandable/commented and... not-cryptic-styled-code :-) + * - >= 10% faster than encrypt()/decrypt() [which is, by the way, + * the reason for the existence of _setupInlineCrypt() :-)] + * - memory-nice + * - short (as good as possible) + * + * Note: - _setupInlineCrypt() is using _createInlineCryptFunction() to create the full callback function code. + * - In case of using inline crypting, _setupInlineCrypt() must extend by the child Crypt_* class. + * - The following variable names are reserved: + * - $_* (all variable names prefixed with an underscore) + * - $self (object reference to it self. Do not use $this, but $self instead) + * - $in (the content of $in has to en/decrypt by the generated code) + * - The callback function should not use the 'return' statement, but en/decrypt'ing the content of $in only + * + * + * @see Crypt_Base::_setup() + * @see Crypt_Base::_createInlineCryptFunction() + * @see Crypt_Base::encrypt() + * @see Crypt_Base::decrypt() + * @access private + */ + function _setupInlineCrypt() + { + // If a Crypt_* class providing inline crypting it must extend _setupInlineCrypt() + + // If, for any reason, an extending Crypt_Base() Crypt_* class + // not using inline crypting then it must be ensured that: $this->use_inline_crypt = false + // ie in the class var declaration of $use_inline_crypt in general for the Crypt_* class, + // in the constructor at object instance-time + // or, if it's runtime-specific, at runtime + + $this->use_inline_crypt = false; + } + + /** + * Creates the performance-optimized function for en/decrypt() + * + * Internally for phpseclib developers: + * + * _createInlineCryptFunction(): + * + * - merge the $cipher_code [setup'ed by _setupInlineCrypt()] + * with the current [$this->]mode of operation code + * + * - create the $inline function, which called by encrypt() / decrypt() + * as its replacement to speed up the en/decryption operations. + * + * - return the name of the created $inline callback function + * + * - used to speed up en/decryption + * + * + * + * The main reason why can speed up things [up to 50%] this way are: + * + * - using variables more effective then regular. + * (ie no use of expensive arrays but integers $k_0, $k_1 ... + * or even, for example, the pure $key[] values hardcoded) + * + * - avoiding 1000's of function calls of ie _encryptBlock() + * but inlining the crypt operations. + * in the mode of operation for() loop. + * + * - full loop unroll the (sometimes key-dependent) rounds + * avoiding this way ++$i counters and runtime-if's etc... + * + * The basic code architectur of the generated $inline en/decrypt() + * lambda function, in pseudo php, is: + * + * + * +----------------------------------------------------------------------------------------------+ + * | callback $inline = create_function: | + * | lambda_function_0001_crypt_ECB($action, $text) | + * | { | + * | INSERT PHP CODE OF: | + * | $cipher_code['init_crypt']; // general init code. | + * | // ie: $sbox'es declarations used for | + * | // encrypt and decrypt'ing. | + * | | + * | switch ($action) { | + * | case 'encrypt': | + * | INSERT PHP CODE OF: | + * | $cipher_code['init_encrypt']; // encrypt sepcific init code. | + * | ie: specified $key or $box | + * | declarations for encrypt'ing. | + * | | + * | foreach ($ciphertext) { | + * | $in = $block_size of $ciphertext; | + * | | + * | INSERT PHP CODE OF: | + * | $cipher_code['encrypt_block']; // encrypt's (string) $in, which is always: | + * | // strlen($in) == $this->block_size | + * | // here comes the cipher algorithm in action | + * | // for encryption. | + * | // $cipher_code['encrypt_block'] has to | + * | // encrypt the content of the $in variable | + * | | + * | $plaintext .= $in; | + * | } | + * | return $plaintext; | + * | | + * | case 'decrypt': | + * | INSERT PHP CODE OF: | + * | $cipher_code['init_decrypt']; // decrypt sepcific init code | + * | ie: specified $key or $box | + * | declarations for decrypt'ing. | + * | foreach ($plaintext) { | + * | $in = $block_size of $plaintext; | + * | | + * | INSERT PHP CODE OF: | + * | $cipher_code['decrypt_block']; // decrypt's (string) $in, which is always | + * | // strlen($in) == $this->block_size | + * | // here comes the cipher algorithm in action | + * | // for decryption. | + * | // $cipher_code['decrypt_block'] has to | + * | // decrypt the content of the $in variable | + * | $ciphertext .= $in; | + * | } | + * | return $ciphertext; | + * | } | + * | } | + * +----------------------------------------------------------------------------------------------+ + * + * + * See also the Crypt_*::_setupInlineCrypt()'s for + * productive inline $cipher_code's how they works. + * + * Structure of: + * + * $cipher_code = array( + * 'init_crypt' => (string) '', // optional + * 'init_encrypt' => (string) '', // optional + * 'init_decrypt' => (string) '', // optional + * 'encrypt_block' => (string) '', // required + * 'decrypt_block' => (string) '' // required + * ); + * + * + * @see Crypt_Base::_setupInlineCrypt() + * @see Crypt_Base::encrypt() + * @see Crypt_Base::decrypt() + * @param Array $cipher_code + * @access private + * @return String (the name of the created callback function) + */ + function _createInlineCryptFunction($cipher_code) + { + $block_size = $this->block_size; + + // optional + $init_crypt = isset($cipher_code['init_crypt']) ? $cipher_code['init_crypt'] : ''; + $init_encrypt = isset($cipher_code['init_encrypt']) ? $cipher_code['init_encrypt'] : ''; + $init_decrypt = isset($cipher_code['init_decrypt']) ? $cipher_code['init_decrypt'] : ''; + // required + $encrypt_block = $cipher_code['encrypt_block']; + $decrypt_block = $cipher_code['decrypt_block']; + + // Generating mode of operation inline code, + // merged with the $cipher_code algorithm + // for encrypt- and decryption. + switch ($this->mode) { + case CRYPT_MODE_ECB: + $encrypt = $init_encrypt . ' + $_ciphertext = ""; + $_text = $self->_pad($_text); + $_plaintext_len = strlen($_text); + + for ($_i = 0; $_i < $_plaintext_len; $_i+= '.$block_size.') { + $in = substr($_text, $_i, '.$block_size.'); + '.$encrypt_block.' + $_ciphertext.= $in; + } + + return $_ciphertext; + '; + + $decrypt = $init_decrypt . ' + $_plaintext = ""; + $_text = str_pad($_text, strlen($_text) + ('.$block_size.' - strlen($_text) % '.$block_size.') % '.$block_size.', chr(0)); + $_ciphertext_len = strlen($_text); + + for ($_i = 0; $_i < $_ciphertext_len; $_i+= '.$block_size.') { + $in = substr($_text, $_i, '.$block_size.'); + '.$decrypt_block.' + $_plaintext.= $in; + } + + return $self->_unpad($_plaintext); + '; + break; + case CRYPT_MODE_CTR: + $encrypt = $init_encrypt . ' + $_ciphertext = ""; + $_plaintext_len = strlen($_text); + $_xor = $self->encryptIV; + $_buffer = &$self->enbuffer; + + if (strlen($_buffer["encrypted"])) { + for ($_i = 0; $_i < $_plaintext_len; $_i+= '.$block_size.') { + $_block = substr($_text, $_i, '.$block_size.'); + if (strlen($_block) > strlen($_buffer["encrypted"])) { + $in = $self->_generateXor($_xor, '.$block_size.'); + '.$encrypt_block.' + $_buffer["encrypted"].= $in; + } + $_key = $self->_stringShift($_buffer["encrypted"], '.$block_size.'); + $_ciphertext.= $_block ^ $_key; + } + } else { + for ($_i = 0; $_i < $_plaintext_len; $_i+= '.$block_size.') { + $_block = substr($_text, $_i, '.$block_size.'); + $in = $self->_generateXor($_xor, '.$block_size.'); + '.$encrypt_block.' + $_key = $in; + $_ciphertext.= $_block ^ $_key; + } + } + if ($self->continuousBuffer) { + $self->encryptIV = $_xor; + if ($_start = $_plaintext_len % '.$block_size.') { + $_buffer["encrypted"] = substr($_key, $_start) . $_buffer["encrypted"]; + } + } + + return $_ciphertext; + '; + + $decrypt = $init_encrypt . ' + $_plaintext = ""; + $_ciphertext_len = strlen($_text); + $_xor = $self->decryptIV; + $_buffer = &$self->debuffer; + + if (strlen($_buffer["ciphertext"])) { + for ($_i = 0; $_i < $_ciphertext_len; $_i+= '.$block_size.') { + $_block = substr($_text, $_i, '.$block_size.'); + if (strlen($_block) > strlen($_buffer["ciphertext"])) { + $in = $self->_generateXor($_xor, '.$block_size.'); + '.$encrypt_block.' + $_buffer["ciphertext"].= $in; + } + $_key = $self->_stringShift($_buffer["ciphertext"], '.$block_size.'); + $_plaintext.= $_block ^ $_key; + } + } else { + for ($_i = 0; $_i < $_ciphertext_len; $_i+= '.$block_size.') { + $_block = substr($_text, $_i, '.$block_size.'); + $in = $self->_generateXor($_xor, '.$block_size.'); + '.$encrypt_block.' + $_key = $in; + $_plaintext.= $_block ^ $_key; + } + } + if ($self->continuousBuffer) { + $self->decryptIV = $_xor; + if ($_start = $_ciphertext_len % '.$block_size.') { + $_buffer["ciphertext"] = substr($_key, $_start) . $_buffer["ciphertext"]; + } + } + + return $_plaintext; + '; + break; + case CRYPT_MODE_CFB: + $encrypt = $init_encrypt . ' + $_ciphertext = ""; + $_buffer = &$self->enbuffer; + + if ($self->continuousBuffer) { + $_iv = &$self->encryptIV; + $_pos = &$_buffer["pos"]; + } else { + $_iv = $self->encryptIV; + $_pos = 0; + } + $_len = strlen($_text); + $_i = 0; + if ($_pos) { + $_orig_pos = $_pos; + $_max = '.$block_size.' - $_pos; + if ($_len >= $_max) { + $_i = $_max; + $_len-= $_max; + $_pos = 0; + } else { + $_i = $_len; + $_pos+= $_len; + $_len = 0; + } + $_ciphertext = substr($_iv, $_orig_pos) ^ $_text; + $_iv = substr_replace($_iv, $_ciphertext, $_orig_pos, $_i); + } + while ($_len >= '.$block_size.') { + $in = $_iv; + '.$encrypt_block.'; + $_iv = $in ^ substr($_text, $_i, '.$block_size.'); + $_ciphertext.= $_iv; + $_len-= '.$block_size.'; + $_i+= '.$block_size.'; + } + if ($_len) { + $in = $_iv; + '.$encrypt_block.' + $_iv = $in; + $_block = $_iv ^ substr($_text, $_i); + $_iv = substr_replace($_iv, $_block, 0, $_len); + $_ciphertext.= $_block; + $_pos = $_len; + } + return $_ciphertext; + '; + + $decrypt = $init_encrypt . ' + $_plaintext = ""; + $_buffer = &$self->debuffer; + + if ($self->continuousBuffer) { + $_iv = &$self->decryptIV; + $_pos = &$_buffer["pos"]; + } else { + $_iv = $self->decryptIV; + $_pos = 0; + } + $_len = strlen($_text); + $_i = 0; + if ($_pos) { + $_orig_pos = $_pos; + $_max = '.$block_size.' - $_pos; + if ($_len >= $_max) { + $_i = $_max; + $_len-= $_max; + $_pos = 0; + } else { + $_i = $_len; + $_pos+= $_len; + $_len = 0; + } + $_plaintext = substr($_iv, $_orig_pos) ^ $_text; + $_iv = substr_replace($_iv, substr($_text, 0, $_i), $_orig_pos, $_i); + } + while ($_len >= '.$block_size.') { + $in = $_iv; + '.$encrypt_block.' + $_iv = $in; + $cb = substr($_text, $_i, '.$block_size.'); + $_plaintext.= $_iv ^ $cb; + $_iv = $cb; + $_len-= '.$block_size.'; + $_i+= '.$block_size.'; + } + if ($_len) { + $in = $_iv; + '.$encrypt_block.' + $_iv = $in; + $_plaintext.= $_iv ^ substr($_text, $_i); + $_iv = substr_replace($_iv, substr($_text, $_i), 0, $_len); + $_pos = $_len; + } + + return $_plaintext; + '; + break; + case CRYPT_MODE_OFB: + $encrypt = $init_encrypt . ' + $_ciphertext = ""; + $_plaintext_len = strlen($_text); + $_xor = $self->encryptIV; + $_buffer = &$self->enbuffer; + + if (strlen($_buffer["xor"])) { + for ($_i = 0; $_i < $_plaintext_len; $_i+= '.$block_size.') { + $_block = substr($_text, $_i, '.$block_size.'); + if (strlen($_block) > strlen($_buffer["xor"])) { + $in = $_xor; + '.$encrypt_block.' + $_xor = $in; + $_buffer["xor"].= $_xor; + } + $_key = $self->_stringShift($_buffer["xor"], '.$block_size.'); + $_ciphertext.= $_block ^ $_key; + } + } else { + for ($_i = 0; $_i < $_plaintext_len; $_i+= '.$block_size.') { + $in = $_xor; + '.$encrypt_block.' + $_xor = $in; + $_ciphertext.= substr($_text, $_i, '.$block_size.') ^ $_xor; + } + $_key = $_xor; + } + if ($self->continuousBuffer) { + $self->encryptIV = $_xor; + if ($_start = $_plaintext_len % '.$block_size.') { + $_buffer["xor"] = substr($_key, $_start) . $_buffer["xor"]; + } + } + return $_ciphertext; + '; + + $decrypt = $init_encrypt . ' + $_plaintext = ""; + $_ciphertext_len = strlen($_text); + $_xor = $self->decryptIV; + $_buffer = &$self->debuffer; + + if (strlen($_buffer["xor"])) { + for ($_i = 0; $_i < $_ciphertext_len; $_i+= '.$block_size.') { + $_block = substr($_text, $_i, '.$block_size.'); + if (strlen($_block) > strlen($_buffer["xor"])) { + $in = $_xor; + '.$encrypt_block.' + $_xor = $in; + $_buffer["xor"].= $_xor; + } + $_key = $self->_stringShift($_buffer["xor"], '.$block_size.'); + $_plaintext.= $_block ^ $_key; + } + } else { + for ($_i = 0; $_i < $_ciphertext_len; $_i+= '.$block_size.') { + $in = $_xor; + '.$encrypt_block.' + $_xor = $in; + $_plaintext.= substr($_text, $_i, '.$block_size.') ^ $_xor; + } + $_key = $_xor; + } + if ($self->continuousBuffer) { + $self->decryptIV = $_xor; + if ($_start = $_ciphertext_len % '.$block_size.') { + $_buffer["xor"] = substr($_key, $_start) . $_buffer["xor"]; + } + } + return $_plaintext; + '; + break; + case CRYPT_MODE_STREAM: + $encrypt = $init_encrypt . ' + $_ciphertext = ""; + '.$encrypt_block.' + return $_ciphertext; + '; + $decrypt = $init_decrypt . ' + $_plaintext = ""; + '.$decrypt_block.' + return $_plaintext; + '; + break; + // case CRYPT_MODE_CBC: + default: + $encrypt = $init_encrypt . ' + $_ciphertext = ""; + $_text = $self->_pad($_text); + $_plaintext_len = strlen($_text); + + $in = $self->encryptIV; + + for ($_i = 0; $_i < $_plaintext_len; $_i+= '.$block_size.') { + $in = substr($_text, $_i, '.$block_size.') ^ $in; + '.$encrypt_block.' + $_ciphertext.= $in; + } + + if ($self->continuousBuffer) { + $self->encryptIV = $in; + } + + return $_ciphertext; + '; + + $decrypt = $init_decrypt . ' + $_plaintext = ""; + $_text = str_pad($_text, strlen($_text) + ('.$block_size.' - strlen($_text) % '.$block_size.') % '.$block_size.', chr(0)); + $_ciphertext_len = strlen($_text); + + $_iv = $self->decryptIV; + + for ($_i = 0; $_i < $_ciphertext_len; $_i+= '.$block_size.') { + $in = $_block = substr($_text, $_i, '.$block_size.'); + '.$decrypt_block.' + $_plaintext.= $in ^ $_iv; + $_iv = $_block; + } + + if ($self->continuousBuffer) { + $self->decryptIV = $_iv; + } + + return $self->_unpad($_plaintext); + '; + break; + } + + // Create the $inline function and return its name as string. Ready to run! + return create_function('$_action, &$self, $_text', $init_crypt . 'if ($_action == "encrypt") { ' . $encrypt . ' } else { ' . $decrypt . ' }'); + } + + /** + * Holds the lambda_functions table (classwide) + * + * Each name of the lambda function, created from + * _setupInlineCrypt() && _createInlineCryptFunction() + * is stored, classwide (!), here for reusing. + * + * The string-based index of $function is a classwide + * uniqe value representing, at least, the $mode of + * operation (or more... depends of the optimizing level) + * for which $mode the lambda function was created. + * + * @access private + * @return &Array + */ + function &_getLambdaFunctions() + { + static $functions = array(); + return $functions; + } +} + +// vim: ts=4:sw=4:et: +// vim6: fdl=1: diff --git a/inc/phpseclib/Crypt_Hash.php b/inc/phpseclib/Crypt_Hash.php new file mode 100644 index 000000000..840fcd508 --- /dev/null +++ b/inc/phpseclib/Crypt_Hash.php @@ -0,0 +1,823 @@ + + * setKey('abcdefg'); + * + * echo base64_encode($hash->hash('abcdefg')); + * ?> + * + * + * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @category Crypt + * @package Crypt_Hash + * @author Jim Wigginton + * @copyright MMVII Jim Wigginton + * @license http://www.opensource.org/licenses/mit-license.html MIT License + * @link http://phpseclib.sourceforge.net + */ + +/**#@+ + * @access private + * @see Crypt_Hash::Crypt_Hash() + */ +/** + * Toggles the internal implementation + */ +define('CRYPT_HASH_MODE_INTERNAL', 1); +/** + * Toggles the mhash() implementation, which has been deprecated on PHP 5.3.0+. + */ +define('CRYPT_HASH_MODE_MHASH', 2); +/** + * Toggles the hash() implementation, which works on PHP 5.1.2+. + */ +define('CRYPT_HASH_MODE_HASH', 3); +/**#@-*/ + +/** + * Pure-PHP implementations of keyed-hash message authentication codes (HMACs) and various cryptographic hashing functions. + * + * @author Jim Wigginton + * @version 0.1.0 + * @access public + * @package Crypt_Hash + */ +class Crypt_Hash { + /** + * Byte-length of compression blocks / key (Internal HMAC) + * + * @see Crypt_Hash::setAlgorithm() + * @var Integer + * @access private + */ + var $b; + + /** + * Byte-length of hash output (Internal HMAC) + * + * @see Crypt_Hash::setHash() + * @var Integer + * @access private + */ + var $l = false; + + /** + * Hash Algorithm + * + * @see Crypt_Hash::setHash() + * @var String + * @access private + */ + var $hash; + + /** + * Key + * + * @see Crypt_Hash::setKey() + * @var String + * @access private + */ + var $key = false; + + /** + * Outer XOR (Internal HMAC) + * + * @see Crypt_Hash::setKey() + * @var String + * @access private + */ + var $opad; + + /** + * Inner XOR (Internal HMAC) + * + * @see Crypt_Hash::setKey() + * @var String + * @access private + */ + var $ipad; + + /** + * Default Constructor. + * + * @param optional String $hash + * @return Crypt_Hash + * @access public + */ + function Crypt_Hash($hash = 'sha1') + { + if ( !defined('CRYPT_HASH_MODE') ) { + switch (true) { + case extension_loaded('hash'): + define('CRYPT_HASH_MODE', CRYPT_HASH_MODE_HASH); + break; + case extension_loaded('mhash'): + define('CRYPT_HASH_MODE', CRYPT_HASH_MODE_MHASH); + break; + default: + define('CRYPT_HASH_MODE', CRYPT_HASH_MODE_INTERNAL); + } + } + + $this->setHash($hash); + } + + /** + * Sets the key for HMACs + * + * Keys can be of any length. + * + * @access public + * @param optional String $key + */ + function setKey($key = false) + { + $this->key = $key; + } + + /** + * Sets the hash function. + * + * @access public + * @param String $hash + */ + function setHash($hash) + { + $hash = strtolower($hash); + switch ($hash) { + case 'md5-96': + case 'sha1-96': + $this->l = 12; // 96 / 8 = 12 + break; + case 'md2': + case 'md5': + $this->l = 16; + break; + case 'sha1': + $this->l = 20; + break; + case 'sha256': + $this->l = 32; + break; + case 'sha384': + $this->l = 48; + break; + case 'sha512': + $this->l = 64; + } + + switch ($hash) { + case 'md2': + $mode = CRYPT_HASH_MODE == CRYPT_HASH_MODE_HASH && in_array('md2', hash_algos()) ? + CRYPT_HASH_MODE_HASH : CRYPT_HASH_MODE_INTERNAL; + break; + case 'sha384': + case 'sha512': + $mode = CRYPT_HASH_MODE == CRYPT_HASH_MODE_MHASH ? CRYPT_HASH_MODE_INTERNAL : CRYPT_HASH_MODE; + break; + default: + $mode = CRYPT_HASH_MODE; + } + + switch ( $mode ) { + case CRYPT_HASH_MODE_MHASH: + switch ($hash) { + case 'md5': + case 'md5-96': + $this->hash = MHASH_MD5; + break; + case 'sha256': + $this->hash = MHASH_SHA256; + break; + case 'sha1': + case 'sha1-96': + default: + $this->hash = MHASH_SHA1; + } + return; + case CRYPT_HASH_MODE_HASH: + switch ($hash) { + case 'md5': + case 'md5-96': + $this->hash = 'md5'; + return; + case 'md2': + case 'sha256': + case 'sha384': + case 'sha512': + $this->hash = $hash; + return; + case 'sha1': + case 'sha1-96': + default: + $this->hash = 'sha1'; + } + return; + } + + switch ($hash) { + case 'md2': + $this->b = 16; + $this->hash = array($this, '_md2'); + break; + case 'md5': + case 'md5-96': + $this->b = 64; + $this->hash = array($this, '_md5'); + break; + case 'sha256': + $this->b = 64; + $this->hash = array($this, '_sha256'); + break; + case 'sha384': + case 'sha512': + $this->b = 128; + $this->hash = array($this, '_sha512'); + break; + case 'sha1': + case 'sha1-96': + default: + $this->b = 64; + $this->hash = array($this, '_sha1'); + } + + $this->ipad = str_repeat(chr(0x36), $this->b); + $this->opad = str_repeat(chr(0x5C), $this->b); + } + + /** + * Compute the HMAC. + * + * @access public + * @param String $text + * @return String + */ + function hash($text) + { + $mode = is_array($this->hash) ? CRYPT_HASH_MODE_INTERNAL : CRYPT_HASH_MODE; + + if (!empty($this->key) || is_string($this->key)) { + switch ( $mode ) { + case CRYPT_HASH_MODE_MHASH: + $output = mhash($this->hash, $text, $this->key); + break; + case CRYPT_HASH_MODE_HASH: + $output = hash_hmac($this->hash, $text, $this->key, true); + break; + case CRYPT_HASH_MODE_INTERNAL: + /* "Applications that use keys longer than B bytes will first hash the key using H and then use the + resultant L byte string as the actual key to HMAC." + + -- http://tools.ietf.org/html/rfc2104#section-2 */ + $key = strlen($this->key) > $this->b ? call_user_func($this->hash, $this->key) : $this->key; + + $key = str_pad($key, $this->b, chr(0)); // step 1 + $temp = $this->ipad ^ $key; // step 2 + $temp .= $text; // step 3 + $temp = call_user_func($this->hash, $temp); // step 4 + $output = $this->opad ^ $key; // step 5 + $output.= $temp; // step 6 + $output = call_user_func($this->hash, $output); // step 7 + } + } else { + switch ( $mode ) { + case CRYPT_HASH_MODE_MHASH: + $output = mhash($this->hash, $text); + break; + case CRYPT_HASH_MODE_HASH: + $output = hash($this->hash, $text, true); + break; + case CRYPT_HASH_MODE_INTERNAL: + $output = call_user_func($this->hash, $text); + } + } + + return substr($output, 0, $this->l); + } + + /** + * Returns the hash length (in bytes) + * + * @access public + * @return Integer + */ + function getLength() + { + return $this->l; + } + + /** + * Wrapper for MD5 + * + * @access private + * @param String $m + */ + function _md5($m) + { + return pack('H*', md5($m)); + } + + /** + * Wrapper for SHA1 + * + * @access private + * @param String $m + */ + function _sha1($m) + { + return pack('H*', sha1($m)); + } + + /** + * Pure-PHP implementation of MD2 + * + * See {@link http://tools.ietf.org/html/rfc1319 RFC1319}. + * + * @access private + * @param String $m + */ + function _md2($m) + { + static $s = array( + 41, 46, 67, 201, 162, 216, 124, 1, 61, 54, 84, 161, 236, 240, 6, + 19, 98, 167, 5, 243, 192, 199, 115, 140, 152, 147, 43, 217, 188, + 76, 130, 202, 30, 155, 87, 60, 253, 212, 224, 22, 103, 66, 111, 24, + 138, 23, 229, 18, 190, 78, 196, 214, 218, 158, 222, 73, 160, 251, + 245, 142, 187, 47, 238, 122, 169, 104, 121, 145, 21, 178, 7, 63, + 148, 194, 16, 137, 11, 34, 95, 33, 128, 127, 93, 154, 90, 144, 50, + 39, 53, 62, 204, 231, 191, 247, 151, 3, 255, 25, 48, 179, 72, 165, + 181, 209, 215, 94, 146, 42, 172, 86, 170, 198, 79, 184, 56, 210, + 150, 164, 125, 182, 118, 252, 107, 226, 156, 116, 4, 241, 69, 157, + 112, 89, 100, 113, 135, 32, 134, 91, 207, 101, 230, 45, 168, 2, 27, + 96, 37, 173, 174, 176, 185, 246, 28, 70, 97, 105, 52, 64, 126, 15, + 85, 71, 163, 35, 221, 81, 175, 58, 195, 92, 249, 206, 186, 197, + 234, 38, 44, 83, 13, 110, 133, 40, 132, 9, 211, 223, 205, 244, 65, + 129, 77, 82, 106, 220, 55, 200, 108, 193, 171, 250, 36, 225, 123, + 8, 12, 189, 177, 74, 120, 136, 149, 139, 227, 99, 232, 109, 233, + 203, 213, 254, 59, 0, 29, 57, 242, 239, 183, 14, 102, 88, 208, 228, + 166, 119, 114, 248, 235, 117, 75, 10, 49, 68, 80, 180, 143, 237, + 31, 26, 219, 153, 141, 51, 159, 17, 131, 20 + ); + + // Step 1. Append Padding Bytes + $pad = 16 - (strlen($m) & 0xF); + $m.= str_repeat(chr($pad), $pad); + + $length = strlen($m); + + // Step 2. Append Checksum + $c = str_repeat(chr(0), 16); + $l = chr(0); + for ($i = 0; $i < $length; $i+= 16) { + for ($j = 0; $j < 16; $j++) { + // RFC1319 incorrectly states that C[j] should be set to S[c xor L] + //$c[$j] = chr($s[ord($m[$i + $j] ^ $l)]); + // per , however, C[j] should be set to S[c xor L] xor C[j] + $c[$j] = chr($s[ord($m[$i + $j] ^ $l)] ^ ord($c[$j])); + $l = $c[$j]; + } + } + $m.= $c; + + $length+= 16; + + // Step 3. Initialize MD Buffer + $x = str_repeat(chr(0), 48); + + // Step 4. Process Message in 16-Byte Blocks + for ($i = 0; $i < $length; $i+= 16) { + for ($j = 0; $j < 16; $j++) { + $x[$j + 16] = $m[$i + $j]; + $x[$j + 32] = $x[$j + 16] ^ $x[$j]; + } + $t = chr(0); + for ($j = 0; $j < 18; $j++) { + for ($k = 0; $k < 48; $k++) { + $x[$k] = $t = $x[$k] ^ chr($s[ord($t)]); + //$t = $x[$k] = $x[$k] ^ chr($s[ord($t)]); + } + $t = chr(ord($t) + $j); + } + } + + // Step 5. Output + return substr($x, 0, 16); + } + + /** + * Pure-PHP implementation of SHA256 + * + * See {@link http://en.wikipedia.org/wiki/SHA_hash_functions#SHA-256_.28a_SHA-2_variant.29_pseudocode SHA-256 (a SHA-2 variant) pseudocode - Wikipedia}. + * + * @access private + * @param String $m + */ + function _sha256($m) + { + if (extension_loaded('suhosin')) { + return pack('H*', sha256($m)); + } + + // Initialize variables + $hash = array( + 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19 + ); + // Initialize table of round constants + // (first 32 bits of the fractional parts of the cube roots of the first 64 primes 2..311) + static $k = array( + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, + 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, + 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, + 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, + 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 + ); + + // Pre-processing + $length = strlen($m); + // to round to nearest 56 mod 64, we'll add 64 - (length + (64 - 56)) % 64 + $m.= str_repeat(chr(0), 64 - (($length + 8) & 0x3F)); + $m[$length] = chr(0x80); + // we don't support hashing strings 512MB long + $m.= pack('N2', 0, $length << 3); + + // Process the message in successive 512-bit chunks + $chunks = str_split($m, 64); + foreach ($chunks as $chunk) { + $w = array(); + for ($i = 0; $i < 16; $i++) { + extract(unpack('Ntemp', $this->_string_shift($chunk, 4))); + $w[] = $temp; + } + + // Extend the sixteen 32-bit words into sixty-four 32-bit words + for ($i = 16; $i < 64; $i++) { + $s0 = $this->_rightRotate($w[$i - 15], 7) ^ + $this->_rightRotate($w[$i - 15], 18) ^ + $this->_rightShift( $w[$i - 15], 3); + $s1 = $this->_rightRotate($w[$i - 2], 17) ^ + $this->_rightRotate($w[$i - 2], 19) ^ + $this->_rightShift( $w[$i - 2], 10); + $w[$i] = $this->_add($w[$i - 16], $s0, $w[$i - 7], $s1); + + } + + // Initialize hash value for this chunk + list($a, $b, $c, $d, $e, $f, $g, $h) = $hash; + + // Main loop + for ($i = 0; $i < 64; $i++) { + $s0 = $this->_rightRotate($a, 2) ^ + $this->_rightRotate($a, 13) ^ + $this->_rightRotate($a, 22); + $maj = ($a & $b) ^ + ($a & $c) ^ + ($b & $c); + $t2 = $this->_add($s0, $maj); + + $s1 = $this->_rightRotate($e, 6) ^ + $this->_rightRotate($e, 11) ^ + $this->_rightRotate($e, 25); + $ch = ($e & $f) ^ + ($this->_not($e) & $g); + $t1 = $this->_add($h, $s1, $ch, $k[$i], $w[$i]); + + $h = $g; + $g = $f; + $f = $e; + $e = $this->_add($d, $t1); + $d = $c; + $c = $b; + $b = $a; + $a = $this->_add($t1, $t2); + } + + // Add this chunk's hash to result so far + $hash = array( + $this->_add($hash[0], $a), + $this->_add($hash[1], $b), + $this->_add($hash[2], $c), + $this->_add($hash[3], $d), + $this->_add($hash[4], $e), + $this->_add($hash[5], $f), + $this->_add($hash[6], $g), + $this->_add($hash[7], $h) + ); + } + + // Produce the final hash value (big-endian) + return pack('N8', $hash[0], $hash[1], $hash[2], $hash[3], $hash[4], $hash[5], $hash[6], $hash[7]); + } + + /** + * Pure-PHP implementation of SHA384 and SHA512 + * + * @access private + * @param String $m + */ + function _sha512($m) + { + if (!class_exists('Math_BigInteger')) { + require_once('Math/BigInteger.php'); + } + + static $init384, $init512, $k; + + if (!isset($k)) { + // Initialize variables + $init384 = array( // initial values for SHA384 + 'cbbb9d5dc1059ed8', '629a292a367cd507', '9159015a3070dd17', '152fecd8f70e5939', + '67332667ffc00b31', '8eb44a8768581511', 'db0c2e0d64f98fa7', '47b5481dbefa4fa4' + ); + $init512 = array( // initial values for SHA512 + '6a09e667f3bcc908', 'bb67ae8584caa73b', '3c6ef372fe94f82b', 'a54ff53a5f1d36f1', + '510e527fade682d1', '9b05688c2b3e6c1f', '1f83d9abfb41bd6b', '5be0cd19137e2179' + ); + + for ($i = 0; $i < 8; $i++) { + $init384[$i] = new Math_BigInteger($init384[$i], 16); + $init384[$i]->setPrecision(64); + $init512[$i] = new Math_BigInteger($init512[$i], 16); + $init512[$i]->setPrecision(64); + } + + // Initialize table of round constants + // (first 64 bits of the fractional parts of the cube roots of the first 80 primes 2..409) + $k = array( + '428a2f98d728ae22', '7137449123ef65cd', 'b5c0fbcfec4d3b2f', 'e9b5dba58189dbbc', + '3956c25bf348b538', '59f111f1b605d019', '923f82a4af194f9b', 'ab1c5ed5da6d8118', + 'd807aa98a3030242', '12835b0145706fbe', '243185be4ee4b28c', '550c7dc3d5ffb4e2', + '72be5d74f27b896f', '80deb1fe3b1696b1', '9bdc06a725c71235', 'c19bf174cf692694', + 'e49b69c19ef14ad2', 'efbe4786384f25e3', '0fc19dc68b8cd5b5', '240ca1cc77ac9c65', + '2de92c6f592b0275', '4a7484aa6ea6e483', '5cb0a9dcbd41fbd4', '76f988da831153b5', + '983e5152ee66dfab', 'a831c66d2db43210', 'b00327c898fb213f', 'bf597fc7beef0ee4', + 'c6e00bf33da88fc2', 'd5a79147930aa725', '06ca6351e003826f', '142929670a0e6e70', + '27b70a8546d22ffc', '2e1b21385c26c926', '4d2c6dfc5ac42aed', '53380d139d95b3df', + '650a73548baf63de', '766a0abb3c77b2a8', '81c2c92e47edaee6', '92722c851482353b', + 'a2bfe8a14cf10364', 'a81a664bbc423001', 'c24b8b70d0f89791', 'c76c51a30654be30', + 'd192e819d6ef5218', 'd69906245565a910', 'f40e35855771202a', '106aa07032bbd1b8', + '19a4c116b8d2d0c8', '1e376c085141ab53', '2748774cdf8eeb99', '34b0bcb5e19b48a8', + '391c0cb3c5c95a63', '4ed8aa4ae3418acb', '5b9cca4f7763e373', '682e6ff3d6b2b8a3', + '748f82ee5defb2fc', '78a5636f43172f60', '84c87814a1f0ab72', '8cc702081a6439ec', + '90befffa23631e28', 'a4506cebde82bde9', 'bef9a3f7b2c67915', 'c67178f2e372532b', + 'ca273eceea26619c', 'd186b8c721c0c207', 'eada7dd6cde0eb1e', 'f57d4f7fee6ed178', + '06f067aa72176fba', '0a637dc5a2c898a6', '113f9804bef90dae', '1b710b35131c471b', + '28db77f523047d84', '32caab7b40c72493', '3c9ebe0a15c9bebc', '431d67c49c100d4c', + '4cc5d4becb3e42b6', '597f299cfc657e2a', '5fcb6fab3ad6faec', '6c44198c4a475817' + ); + + for ($i = 0; $i < 80; $i++) { + $k[$i] = new Math_BigInteger($k[$i], 16); + } + } + + $hash = $this->l == 48 ? $init384 : $init512; + + // Pre-processing + $length = strlen($m); + // to round to nearest 112 mod 128, we'll add 128 - (length + (128 - 112)) % 128 + $m.= str_repeat(chr(0), 128 - (($length + 16) & 0x7F)); + $m[$length] = chr(0x80); + // we don't support hashing strings 512MB long + $m.= pack('N4', 0, 0, 0, $length << 3); + + // Process the message in successive 1024-bit chunks + $chunks = str_split($m, 128); + foreach ($chunks as $chunk) { + $w = array(); + for ($i = 0; $i < 16; $i++) { + $temp = new Math_BigInteger($this->_string_shift($chunk, 8), 256); + $temp->setPrecision(64); + $w[] = $temp; + } + + // Extend the sixteen 32-bit words into eighty 32-bit words + for ($i = 16; $i < 80; $i++) { + $temp = array( + $w[$i - 15]->bitwise_rightRotate(1), + $w[$i - 15]->bitwise_rightRotate(8), + $w[$i - 15]->bitwise_rightShift(7) + ); + $s0 = $temp[0]->bitwise_xor($temp[1]); + $s0 = $s0->bitwise_xor($temp[2]); + $temp = array( + $w[$i - 2]->bitwise_rightRotate(19), + $w[$i - 2]->bitwise_rightRotate(61), + $w[$i - 2]->bitwise_rightShift(6) + ); + $s1 = $temp[0]->bitwise_xor($temp[1]); + $s1 = $s1->bitwise_xor($temp[2]); + $w[$i] = $w[$i - 16]->copy(); + $w[$i] = $w[$i]->add($s0); + $w[$i] = $w[$i]->add($w[$i - 7]); + $w[$i] = $w[$i]->add($s1); + } + + // Initialize hash value for this chunk + $a = $hash[0]->copy(); + $b = $hash[1]->copy(); + $c = $hash[2]->copy(); + $d = $hash[3]->copy(); + $e = $hash[4]->copy(); + $f = $hash[5]->copy(); + $g = $hash[6]->copy(); + $h = $hash[7]->copy(); + + // Main loop + for ($i = 0; $i < 80; $i++) { + $temp = array( + $a->bitwise_rightRotate(28), + $a->bitwise_rightRotate(34), + $a->bitwise_rightRotate(39) + ); + $s0 = $temp[0]->bitwise_xor($temp[1]); + $s0 = $s0->bitwise_xor($temp[2]); + $temp = array( + $a->bitwise_and($b), + $a->bitwise_and($c), + $b->bitwise_and($c) + ); + $maj = $temp[0]->bitwise_xor($temp[1]); + $maj = $maj->bitwise_xor($temp[2]); + $t2 = $s0->add($maj); + + $temp = array( + $e->bitwise_rightRotate(14), + $e->bitwise_rightRotate(18), + $e->bitwise_rightRotate(41) + ); + $s1 = $temp[0]->bitwise_xor($temp[1]); + $s1 = $s1->bitwise_xor($temp[2]); + $temp = array( + $e->bitwise_and($f), + $g->bitwise_and($e->bitwise_not()) + ); + $ch = $temp[0]->bitwise_xor($temp[1]); + $t1 = $h->add($s1); + $t1 = $t1->add($ch); + $t1 = $t1->add($k[$i]); + $t1 = $t1->add($w[$i]); + + $h = $g->copy(); + $g = $f->copy(); + $f = $e->copy(); + $e = $d->add($t1); + $d = $c->copy(); + $c = $b->copy(); + $b = $a->copy(); + $a = $t1->add($t2); + } + + // Add this chunk's hash to result so far + $hash = array( + $hash[0]->add($a), + $hash[1]->add($b), + $hash[2]->add($c), + $hash[3]->add($d), + $hash[4]->add($e), + $hash[5]->add($f), + $hash[6]->add($g), + $hash[7]->add($h) + ); + } + + // Produce the final hash value (big-endian) + // (Crypt_Hash::hash() trims the output for hashes but not for HMACs. as such, we trim the output here) + $temp = $hash[0]->toBytes() . $hash[1]->toBytes() . $hash[2]->toBytes() . $hash[3]->toBytes() . + $hash[4]->toBytes() . $hash[5]->toBytes(); + if ($this->l != 48) { + $temp.= $hash[6]->toBytes() . $hash[7]->toBytes(); + } + + return $temp; + } + + /** + * Right Rotate + * + * @access private + * @param Integer $int + * @param Integer $amt + * @see _sha256() + * @return Integer + */ + function _rightRotate($int, $amt) + { + $invamt = 32 - $amt; + $mask = (1 << $invamt) - 1; + return (($int << $invamt) & 0xFFFFFFFF) | (($int >> $amt) & $mask); + } + + /** + * Right Shift + * + * @access private + * @param Integer $int + * @param Integer $amt + * @see _sha256() + * @return Integer + */ + function _rightShift($int, $amt) + { + $mask = (1 << (32 - $amt)) - 1; + return ($int >> $amt) & $mask; + } + + /** + * Not + * + * @access private + * @param Integer $int + * @see _sha256() + * @return Integer + */ + function _not($int) + { + return ~$int & 0xFFFFFFFF; + } + + /** + * Add + * + * _sha256() adds multiple unsigned 32-bit integers. Since PHP doesn't support unsigned integers and since the + * possibility of overflow exists, care has to be taken. Math_BigInteger() could be used but this should be faster. + * + * @param Integer $... + * @return Integer + * @see _sha256() + * @access private + */ + function _add() + { + static $mod; + if (!isset($mod)) { + $mod = pow(2, 32); + } + + $result = 0; + $arguments = func_get_args(); + foreach ($arguments as $argument) { + $result+= $argument < 0 ? ($argument & 0x7FFFFFFF) + 0x80000000 : $argument; + } + + return fmod($result, $mod); + } + + /** + * String Shift + * + * Inspired by array_shift + * + * @param String $string + * @param optional Integer $index + * @return String + * @access private + */ + function _string_shift(&$string, $index = 1) + { + $substr = substr($string, 0, $index); + $string = substr($string, $index); + return $substr; + } +} diff --git a/inc/phpseclib/Crypt_Rijndael.php b/inc/phpseclib/Crypt_Rijndael.php new file mode 100644 index 000000000..c63e0ff7e --- /dev/null +++ b/inc/phpseclib/Crypt_Rijndael.php @@ -0,0 +1,1374 @@ + + * setKey('abcdefghijklmnop'); + * + * $size = 10 * 1024; + * $plaintext = ''; + * for ($i = 0; $i < $size; $i++) { + * $plaintext.= 'a'; + * } + * + * echo $rijndael->decrypt($rijndael->encrypt($plaintext)); + * ?> + * + * + * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @category Crypt + * @package Crypt_Rijndael + * @author Jim Wigginton + * @copyright MMVIII Jim Wigginton + * @license http://www.opensource.org/licenses/mit-license.html MIT License + * @link http://phpseclib.sourceforge.net + */ + +/** + * Include Crypt_Base + * + * Base cipher class + */ +if (!class_exists('Crypt_Base')) { + require_once('Base.php'); +} + +/**#@+ + * @access public + * @see Crypt_Rijndael::encrypt() + * @see Crypt_Rijndael::decrypt() + */ +/** + * Encrypt / decrypt using the Counter mode. + * + * Set to -1 since that's what Crypt/Random.php uses to index the CTR mode. + * + * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Counter_.28CTR.29 + */ +define('CRYPT_RIJNDAEL_MODE_CTR', CRYPT_MODE_CTR); +/** + * Encrypt / decrypt using the Electronic Code Book mode. + * + * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Electronic_codebook_.28ECB.29 + */ +define('CRYPT_RIJNDAEL_MODE_ECB', CRYPT_MODE_ECB); +/** + * Encrypt / decrypt using the Code Book Chaining mode. + * + * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher-block_chaining_.28CBC.29 + */ +define('CRYPT_RIJNDAEL_MODE_CBC', CRYPT_MODE_CBC); +/** + * Encrypt / decrypt using the Cipher Feedback mode. + * + * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher_feedback_.28CFB.29 + */ +define('CRYPT_RIJNDAEL_MODE_CFB', CRYPT_MODE_CFB); +/** + * Encrypt / decrypt using the Cipher Feedback mode. + * + * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Output_feedback_.28OFB.29 + */ +define('CRYPT_RIJNDAEL_MODE_OFB', CRYPT_MODE_OFB); +/**#@-*/ + +/**#@+ + * @access private + * @see Crypt_Rijndael::Crypt_Rijndael() + */ +/** + * Toggles the internal implementation + */ +define('CRYPT_RIJNDAEL_MODE_INTERNAL', CRYPT_MODE_INTERNAL); +/** + * Toggles the mcrypt implementation + */ +define('CRYPT_RIJNDAEL_MODE_MCRYPT', CRYPT_MODE_MCRYPT); +/**#@-*/ + +/** + * Pure-PHP implementation of Rijndael. + * + * @author Jim Wigginton + * @version 0.1.0 + * @access public + * @package Crypt_Rijndael + */ +class Crypt_Rijndael extends Crypt_Base { + /** + * The default password key_size used by setPassword() + * + * @see Crypt_Base::password_key_size + * @see Crypt_Base::setPassword() + * @var Integer + * @access private + */ + var $password_key_size = 16; + + /** + * The namespace used by the cipher for its constants. + * + * @see Crypt_Base::const_namespace + * @var String + * @access private + */ + var $const_namespace = 'RIJNDAEL'; + + /** + * The mcrypt specific name of the cipher + * + * Mcrypt is useable for 128/192/256-bit $block_size/$key_size. For 160/224 not. + * Crypt_Rijndael determines automatically whether mcrypt is useable + * or not for the current $block_size/$key_size. + * In case of, $cipher_name_mcrypt will be set dynamicaly at run time accordingly. + * + * @see Crypt_Base::cipher_name_mcrypt + * @see Crypt_Base::engine + * @see _setupEngine() + * @var String + * @access private + */ + var $cipher_name_mcrypt = 'rijndael-128'; + + /** + * The default salt used by setPassword() + * + * @see Crypt_Base::password_default_salt + * @see Crypt_Base::setPassword() + * @var String + * @access private + */ + var $password_default_salt = 'phpseclib'; + + /** + * Has the key length explicitly been set or should it be derived from the key, itself? + * + * @see setKeyLength() + * @var Boolean + * @access private + */ + var $explicit_key_length = false; + + /** + * The Key Schedule + * + * @see _setup() + * @var Array + * @access private + */ + var $w; + + /** + * The Inverse Key Schedule + * + * @see _setup() + * @var Array + * @access private + */ + var $dw; + + /** + * The Block Length divided by 32 + * + * @see setBlockLength() + * @var Integer + * @access private + * @internal The max value is 256 / 32 = 8, the min value is 128 / 32 = 4. Exists in conjunction with $block_size + * because the encryption / decryption / key schedule creation requires this number and not $block_size. We could + * derive this from $block_size or vice versa, but that'd mean we'd have to do multiple shift operations, so in lieu + * of that, we'll just precompute it once. + * + */ + var $Nb = 4; + + /** + * The Key Length + * + * @see setKeyLength() + * @var Integer + * @access private + * @internal The max value is 256 / 8 = 32, the min value is 128 / 8 = 16. Exists in conjunction with $Nk + * because the encryption / decryption / key schedule creation requires this number and not $key_size. We could + * derive this from $key_size or vice versa, but that'd mean we'd have to do multiple shift operations, so in lieu + * of that, we'll just precompute it once. + */ + var $key_size = 16; + + /** + * The Key Length divided by 32 + * + * @see setKeyLength() + * @var Integer + * @access private + * @internal The max value is 256 / 32 = 8, the min value is 128 / 32 = 4 + */ + var $Nk = 4; + + /** + * The Number of Rounds + * + * @var Integer + * @access private + * @internal The max value is 14, the min value is 10. + */ + var $Nr; + + /** + * Shift offsets + * + * @var Array + * @access private + */ + var $c; + + /** + * Holds the last used key- and block_size information + * + * @var Array + * @access private + */ + var $kl; + + /** + * Precomputed mixColumns table + * + * According to (section 5.2.1), + * precomputed tables can be used in the mixColumns phase. in that example, they're assigned t0...t3, so + * those are the names we'll use. + * + * @see Crypt_Rijndael:_encryptBlock() + * @see Crypt_Rijndael:_decryptBlock() + * @var Array + * @access private + */ + var $t0 = array( + 0xC66363A5, 0xF87C7C84, 0xEE777799, 0xF67B7B8D, 0xFFF2F20D, 0xD66B6BBD, 0xDE6F6FB1, 0x91C5C554, + 0x60303050, 0x02010103, 0xCE6767A9, 0x562B2B7D, 0xE7FEFE19, 0xB5D7D762, 0x4DABABE6, 0xEC76769A, + 0x8FCACA45, 0x1F82829D, 0x89C9C940, 0xFA7D7D87, 0xEFFAFA15, 0xB25959EB, 0x8E4747C9, 0xFBF0F00B, + 0x41ADADEC, 0xB3D4D467, 0x5FA2A2FD, 0x45AFAFEA, 0x239C9CBF, 0x53A4A4F7, 0xE4727296, 0x9BC0C05B, + 0x75B7B7C2, 0xE1FDFD1C, 0x3D9393AE, 0x4C26266A, 0x6C36365A, 0x7E3F3F41, 0xF5F7F702, 0x83CCCC4F, + 0x6834345C, 0x51A5A5F4, 0xD1E5E534, 0xF9F1F108, 0xE2717193, 0xABD8D873, 0x62313153, 0x2A15153F, + 0x0804040C, 0x95C7C752, 0x46232365, 0x9DC3C35E, 0x30181828, 0x379696A1, 0x0A05050F, 0x2F9A9AB5, + 0x0E070709, 0x24121236, 0x1B80809B, 0xDFE2E23D, 0xCDEBEB26, 0x4E272769, 0x7FB2B2CD, 0xEA75759F, + 0x1209091B, 0x1D83839E, 0x582C2C74, 0x341A1A2E, 0x361B1B2D, 0xDC6E6EB2, 0xB45A5AEE, 0x5BA0A0FB, + 0xA45252F6, 0x763B3B4D, 0xB7D6D661, 0x7DB3B3CE, 0x5229297B, 0xDDE3E33E, 0x5E2F2F71, 0x13848497, + 0xA65353F5, 0xB9D1D168, 0x00000000, 0xC1EDED2C, 0x40202060, 0xE3FCFC1F, 0x79B1B1C8, 0xB65B5BED, + 0xD46A6ABE, 0x8DCBCB46, 0x67BEBED9, 0x7239394B, 0x944A4ADE, 0x984C4CD4, 0xB05858E8, 0x85CFCF4A, + 0xBBD0D06B, 0xC5EFEF2A, 0x4FAAAAE5, 0xEDFBFB16, 0x864343C5, 0x9A4D4DD7, 0x66333355, 0x11858594, + 0x8A4545CF, 0xE9F9F910, 0x04020206, 0xFE7F7F81, 0xA05050F0, 0x783C3C44, 0x259F9FBA, 0x4BA8A8E3, + 0xA25151F3, 0x5DA3A3FE, 0x804040C0, 0x058F8F8A, 0x3F9292AD, 0x219D9DBC, 0x70383848, 0xF1F5F504, + 0x63BCBCDF, 0x77B6B6C1, 0xAFDADA75, 0x42212163, 0x20101030, 0xE5FFFF1A, 0xFDF3F30E, 0xBFD2D26D, + 0x81CDCD4C, 0x180C0C14, 0x26131335, 0xC3ECEC2F, 0xBE5F5FE1, 0x359797A2, 0x884444CC, 0x2E171739, + 0x93C4C457, 0x55A7A7F2, 0xFC7E7E82, 0x7A3D3D47, 0xC86464AC, 0xBA5D5DE7, 0x3219192B, 0xE6737395, + 0xC06060A0, 0x19818198, 0x9E4F4FD1, 0xA3DCDC7F, 0x44222266, 0x542A2A7E, 0x3B9090AB, 0x0B888883, + 0x8C4646CA, 0xC7EEEE29, 0x6BB8B8D3, 0x2814143C, 0xA7DEDE79, 0xBC5E5EE2, 0x160B0B1D, 0xADDBDB76, + 0xDBE0E03B, 0x64323256, 0x743A3A4E, 0x140A0A1E, 0x924949DB, 0x0C06060A, 0x4824246C, 0xB85C5CE4, + 0x9FC2C25D, 0xBDD3D36E, 0x43ACACEF, 0xC46262A6, 0x399191A8, 0x319595A4, 0xD3E4E437, 0xF279798B, + 0xD5E7E732, 0x8BC8C843, 0x6E373759, 0xDA6D6DB7, 0x018D8D8C, 0xB1D5D564, 0x9C4E4ED2, 0x49A9A9E0, + 0xD86C6CB4, 0xAC5656FA, 0xF3F4F407, 0xCFEAEA25, 0xCA6565AF, 0xF47A7A8E, 0x47AEAEE9, 0x10080818, + 0x6FBABAD5, 0xF0787888, 0x4A25256F, 0x5C2E2E72, 0x381C1C24, 0x57A6A6F1, 0x73B4B4C7, 0x97C6C651, + 0xCBE8E823, 0xA1DDDD7C, 0xE874749C, 0x3E1F1F21, 0x964B4BDD, 0x61BDBDDC, 0x0D8B8B86, 0x0F8A8A85, + 0xE0707090, 0x7C3E3E42, 0x71B5B5C4, 0xCC6666AA, 0x904848D8, 0x06030305, 0xF7F6F601, 0x1C0E0E12, + 0xC26161A3, 0x6A35355F, 0xAE5757F9, 0x69B9B9D0, 0x17868691, 0x99C1C158, 0x3A1D1D27, 0x279E9EB9, + 0xD9E1E138, 0xEBF8F813, 0x2B9898B3, 0x22111133, 0xD26969BB, 0xA9D9D970, 0x078E8E89, 0x339494A7, + 0x2D9B9BB6, 0x3C1E1E22, 0x15878792, 0xC9E9E920, 0x87CECE49, 0xAA5555FF, 0x50282878, 0xA5DFDF7A, + 0x038C8C8F, 0x59A1A1F8, 0x09898980, 0x1A0D0D17, 0x65BFBFDA, 0xD7E6E631, 0x844242C6, 0xD06868B8, + 0x824141C3, 0x299999B0, 0x5A2D2D77, 0x1E0F0F11, 0x7BB0B0CB, 0xA85454FC, 0x6DBBBBD6, 0x2C16163A + ); + + /** + * Precomputed mixColumns table + * + * @see Crypt_Rijndael:_encryptBlock() + * @see Crypt_Rijndael:_decryptBlock() + * @var Array + * @access private + */ + var $t1 = array( + 0xA5C66363, 0x84F87C7C, 0x99EE7777, 0x8DF67B7B, 0x0DFFF2F2, 0xBDD66B6B, 0xB1DE6F6F, 0x5491C5C5, + 0x50603030, 0x03020101, 0xA9CE6767, 0x7D562B2B, 0x19E7FEFE, 0x62B5D7D7, 0xE64DABAB, 0x9AEC7676, + 0x458FCACA, 0x9D1F8282, 0x4089C9C9, 0x87FA7D7D, 0x15EFFAFA, 0xEBB25959, 0xC98E4747, 0x0BFBF0F0, + 0xEC41ADAD, 0x67B3D4D4, 0xFD5FA2A2, 0xEA45AFAF, 0xBF239C9C, 0xF753A4A4, 0x96E47272, 0x5B9BC0C0, + 0xC275B7B7, 0x1CE1FDFD, 0xAE3D9393, 0x6A4C2626, 0x5A6C3636, 0x417E3F3F, 0x02F5F7F7, 0x4F83CCCC, + 0x5C683434, 0xF451A5A5, 0x34D1E5E5, 0x08F9F1F1, 0x93E27171, 0x73ABD8D8, 0x53623131, 0x3F2A1515, + 0x0C080404, 0x5295C7C7, 0x65462323, 0x5E9DC3C3, 0x28301818, 0xA1379696, 0x0F0A0505, 0xB52F9A9A, + 0x090E0707, 0x36241212, 0x9B1B8080, 0x3DDFE2E2, 0x26CDEBEB, 0x694E2727, 0xCD7FB2B2, 0x9FEA7575, + 0x1B120909, 0x9E1D8383, 0x74582C2C, 0x2E341A1A, 0x2D361B1B, 0xB2DC6E6E, 0xEEB45A5A, 0xFB5BA0A0, + 0xF6A45252, 0x4D763B3B, 0x61B7D6D6, 0xCE7DB3B3, 0x7B522929, 0x3EDDE3E3, 0x715E2F2F, 0x97138484, + 0xF5A65353, 0x68B9D1D1, 0x00000000, 0x2CC1EDED, 0x60402020, 0x1FE3FCFC, 0xC879B1B1, 0xEDB65B5B, + 0xBED46A6A, 0x468DCBCB, 0xD967BEBE, 0x4B723939, 0xDE944A4A, 0xD4984C4C, 0xE8B05858, 0x4A85CFCF, + 0x6BBBD0D0, 0x2AC5EFEF, 0xE54FAAAA, 0x16EDFBFB, 0xC5864343, 0xD79A4D4D, 0x55663333, 0x94118585, + 0xCF8A4545, 0x10E9F9F9, 0x06040202, 0x81FE7F7F, 0xF0A05050, 0x44783C3C, 0xBA259F9F, 0xE34BA8A8, + 0xF3A25151, 0xFE5DA3A3, 0xC0804040, 0x8A058F8F, 0xAD3F9292, 0xBC219D9D, 0x48703838, 0x04F1F5F5, + 0xDF63BCBC, 0xC177B6B6, 0x75AFDADA, 0x63422121, 0x30201010, 0x1AE5FFFF, 0x0EFDF3F3, 0x6DBFD2D2, + 0x4C81CDCD, 0x14180C0C, 0x35261313, 0x2FC3ECEC, 0xE1BE5F5F, 0xA2359797, 0xCC884444, 0x392E1717, + 0x5793C4C4, 0xF255A7A7, 0x82FC7E7E, 0x477A3D3D, 0xACC86464, 0xE7BA5D5D, 0x2B321919, 0x95E67373, + 0xA0C06060, 0x98198181, 0xD19E4F4F, 0x7FA3DCDC, 0x66442222, 0x7E542A2A, 0xAB3B9090, 0x830B8888, + 0xCA8C4646, 0x29C7EEEE, 0xD36BB8B8, 0x3C281414, 0x79A7DEDE, 0xE2BC5E5E, 0x1D160B0B, 0x76ADDBDB, + 0x3BDBE0E0, 0x56643232, 0x4E743A3A, 0x1E140A0A, 0xDB924949, 0x0A0C0606, 0x6C482424, 0xE4B85C5C, + 0x5D9FC2C2, 0x6EBDD3D3, 0xEF43ACAC, 0xA6C46262, 0xA8399191, 0xA4319595, 0x37D3E4E4, 0x8BF27979, + 0x32D5E7E7, 0x438BC8C8, 0x596E3737, 0xB7DA6D6D, 0x8C018D8D, 0x64B1D5D5, 0xD29C4E4E, 0xE049A9A9, + 0xB4D86C6C, 0xFAAC5656, 0x07F3F4F4, 0x25CFEAEA, 0xAFCA6565, 0x8EF47A7A, 0xE947AEAE, 0x18100808, + 0xD56FBABA, 0x88F07878, 0x6F4A2525, 0x725C2E2E, 0x24381C1C, 0xF157A6A6, 0xC773B4B4, 0x5197C6C6, + 0x23CBE8E8, 0x7CA1DDDD, 0x9CE87474, 0x213E1F1F, 0xDD964B4B, 0xDC61BDBD, 0x860D8B8B, 0x850F8A8A, + 0x90E07070, 0x427C3E3E, 0xC471B5B5, 0xAACC6666, 0xD8904848, 0x05060303, 0x01F7F6F6, 0x121C0E0E, + 0xA3C26161, 0x5F6A3535, 0xF9AE5757, 0xD069B9B9, 0x91178686, 0x5899C1C1, 0x273A1D1D, 0xB9279E9E, + 0x38D9E1E1, 0x13EBF8F8, 0xB32B9898, 0x33221111, 0xBBD26969, 0x70A9D9D9, 0x89078E8E, 0xA7339494, + 0xB62D9B9B, 0x223C1E1E, 0x92158787, 0x20C9E9E9, 0x4987CECE, 0xFFAA5555, 0x78502828, 0x7AA5DFDF, + 0x8F038C8C, 0xF859A1A1, 0x80098989, 0x171A0D0D, 0xDA65BFBF, 0x31D7E6E6, 0xC6844242, 0xB8D06868, + 0xC3824141, 0xB0299999, 0x775A2D2D, 0x111E0F0F, 0xCB7BB0B0, 0xFCA85454, 0xD66DBBBB, 0x3A2C1616 + ); + + /** + * Precomputed mixColumns table + * + * @see Crypt_Rijndael:_encryptBlock() + * @see Crypt_Rijndael:_decryptBlock() + * @var Array + * @access private + */ + var $t2 = array( + 0x63A5C663, 0x7C84F87C, 0x7799EE77, 0x7B8DF67B, 0xF20DFFF2, 0x6BBDD66B, 0x6FB1DE6F, 0xC55491C5, + 0x30506030, 0x01030201, 0x67A9CE67, 0x2B7D562B, 0xFE19E7FE, 0xD762B5D7, 0xABE64DAB, 0x769AEC76, + 0xCA458FCA, 0x829D1F82, 0xC94089C9, 0x7D87FA7D, 0xFA15EFFA, 0x59EBB259, 0x47C98E47, 0xF00BFBF0, + 0xADEC41AD, 0xD467B3D4, 0xA2FD5FA2, 0xAFEA45AF, 0x9CBF239C, 0xA4F753A4, 0x7296E472, 0xC05B9BC0, + 0xB7C275B7, 0xFD1CE1FD, 0x93AE3D93, 0x266A4C26, 0x365A6C36, 0x3F417E3F, 0xF702F5F7, 0xCC4F83CC, + 0x345C6834, 0xA5F451A5, 0xE534D1E5, 0xF108F9F1, 0x7193E271, 0xD873ABD8, 0x31536231, 0x153F2A15, + 0x040C0804, 0xC75295C7, 0x23654623, 0xC35E9DC3, 0x18283018, 0x96A13796, 0x050F0A05, 0x9AB52F9A, + 0x07090E07, 0x12362412, 0x809B1B80, 0xE23DDFE2, 0xEB26CDEB, 0x27694E27, 0xB2CD7FB2, 0x759FEA75, + 0x091B1209, 0x839E1D83, 0x2C74582C, 0x1A2E341A, 0x1B2D361B, 0x6EB2DC6E, 0x5AEEB45A, 0xA0FB5BA0, + 0x52F6A452, 0x3B4D763B, 0xD661B7D6, 0xB3CE7DB3, 0x297B5229, 0xE33EDDE3, 0x2F715E2F, 0x84971384, + 0x53F5A653, 0xD168B9D1, 0x00000000, 0xED2CC1ED, 0x20604020, 0xFC1FE3FC, 0xB1C879B1, 0x5BEDB65B, + 0x6ABED46A, 0xCB468DCB, 0xBED967BE, 0x394B7239, 0x4ADE944A, 0x4CD4984C, 0x58E8B058, 0xCF4A85CF, + 0xD06BBBD0, 0xEF2AC5EF, 0xAAE54FAA, 0xFB16EDFB, 0x43C58643, 0x4DD79A4D, 0x33556633, 0x85941185, + 0x45CF8A45, 0xF910E9F9, 0x02060402, 0x7F81FE7F, 0x50F0A050, 0x3C44783C, 0x9FBA259F, 0xA8E34BA8, + 0x51F3A251, 0xA3FE5DA3, 0x40C08040, 0x8F8A058F, 0x92AD3F92, 0x9DBC219D, 0x38487038, 0xF504F1F5, + 0xBCDF63BC, 0xB6C177B6, 0xDA75AFDA, 0x21634221, 0x10302010, 0xFF1AE5FF, 0xF30EFDF3, 0xD26DBFD2, + 0xCD4C81CD, 0x0C14180C, 0x13352613, 0xEC2FC3EC, 0x5FE1BE5F, 0x97A23597, 0x44CC8844, 0x17392E17, + 0xC45793C4, 0xA7F255A7, 0x7E82FC7E, 0x3D477A3D, 0x64ACC864, 0x5DE7BA5D, 0x192B3219, 0x7395E673, + 0x60A0C060, 0x81981981, 0x4FD19E4F, 0xDC7FA3DC, 0x22664422, 0x2A7E542A, 0x90AB3B90, 0x88830B88, + 0x46CA8C46, 0xEE29C7EE, 0xB8D36BB8, 0x143C2814, 0xDE79A7DE, 0x5EE2BC5E, 0x0B1D160B, 0xDB76ADDB, + 0xE03BDBE0, 0x32566432, 0x3A4E743A, 0x0A1E140A, 0x49DB9249, 0x060A0C06, 0x246C4824, 0x5CE4B85C, + 0xC25D9FC2, 0xD36EBDD3, 0xACEF43AC, 0x62A6C462, 0x91A83991, 0x95A43195, 0xE437D3E4, 0x798BF279, + 0xE732D5E7, 0xC8438BC8, 0x37596E37, 0x6DB7DA6D, 0x8D8C018D, 0xD564B1D5, 0x4ED29C4E, 0xA9E049A9, + 0x6CB4D86C, 0x56FAAC56, 0xF407F3F4, 0xEA25CFEA, 0x65AFCA65, 0x7A8EF47A, 0xAEE947AE, 0x08181008, + 0xBAD56FBA, 0x7888F078, 0x256F4A25, 0x2E725C2E, 0x1C24381C, 0xA6F157A6, 0xB4C773B4, 0xC65197C6, + 0xE823CBE8, 0xDD7CA1DD, 0x749CE874, 0x1F213E1F, 0x4BDD964B, 0xBDDC61BD, 0x8B860D8B, 0x8A850F8A, + 0x7090E070, 0x3E427C3E, 0xB5C471B5, 0x66AACC66, 0x48D89048, 0x03050603, 0xF601F7F6, 0x0E121C0E, + 0x61A3C261, 0x355F6A35, 0x57F9AE57, 0xB9D069B9, 0x86911786, 0xC15899C1, 0x1D273A1D, 0x9EB9279E, + 0xE138D9E1, 0xF813EBF8, 0x98B32B98, 0x11332211, 0x69BBD269, 0xD970A9D9, 0x8E89078E, 0x94A73394, + 0x9BB62D9B, 0x1E223C1E, 0x87921587, 0xE920C9E9, 0xCE4987CE, 0x55FFAA55, 0x28785028, 0xDF7AA5DF, + 0x8C8F038C, 0xA1F859A1, 0x89800989, 0x0D171A0D, 0xBFDA65BF, 0xE631D7E6, 0x42C68442, 0x68B8D068, + 0x41C38241, 0x99B02999, 0x2D775A2D, 0x0F111E0F, 0xB0CB7BB0, 0x54FCA854, 0xBBD66DBB, 0x163A2C16 + ); + + /** + * Precomputed mixColumns table + * + * @see Crypt_Rijndael:_encryptBlock() + * @see Crypt_Rijndael:_decryptBlock() + * @var Array + * @access private + */ + var $t3 = array( + 0x6363A5C6, 0x7C7C84F8, 0x777799EE, 0x7B7B8DF6, 0xF2F20DFF, 0x6B6BBDD6, 0x6F6FB1DE, 0xC5C55491, + 0x30305060, 0x01010302, 0x6767A9CE, 0x2B2B7D56, 0xFEFE19E7, 0xD7D762B5, 0xABABE64D, 0x76769AEC, + 0xCACA458F, 0x82829D1F, 0xC9C94089, 0x7D7D87FA, 0xFAFA15EF, 0x5959EBB2, 0x4747C98E, 0xF0F00BFB, + 0xADADEC41, 0xD4D467B3, 0xA2A2FD5F, 0xAFAFEA45, 0x9C9CBF23, 0xA4A4F753, 0x727296E4, 0xC0C05B9B, + 0xB7B7C275, 0xFDFD1CE1, 0x9393AE3D, 0x26266A4C, 0x36365A6C, 0x3F3F417E, 0xF7F702F5, 0xCCCC4F83, + 0x34345C68, 0xA5A5F451, 0xE5E534D1, 0xF1F108F9, 0x717193E2, 0xD8D873AB, 0x31315362, 0x15153F2A, + 0x04040C08, 0xC7C75295, 0x23236546, 0xC3C35E9D, 0x18182830, 0x9696A137, 0x05050F0A, 0x9A9AB52F, + 0x0707090E, 0x12123624, 0x80809B1B, 0xE2E23DDF, 0xEBEB26CD, 0x2727694E, 0xB2B2CD7F, 0x75759FEA, + 0x09091B12, 0x83839E1D, 0x2C2C7458, 0x1A1A2E34, 0x1B1B2D36, 0x6E6EB2DC, 0x5A5AEEB4, 0xA0A0FB5B, + 0x5252F6A4, 0x3B3B4D76, 0xD6D661B7, 0xB3B3CE7D, 0x29297B52, 0xE3E33EDD, 0x2F2F715E, 0x84849713, + 0x5353F5A6, 0xD1D168B9, 0x00000000, 0xEDED2CC1, 0x20206040, 0xFCFC1FE3, 0xB1B1C879, 0x5B5BEDB6, + 0x6A6ABED4, 0xCBCB468D, 0xBEBED967, 0x39394B72, 0x4A4ADE94, 0x4C4CD498, 0x5858E8B0, 0xCFCF4A85, + 0xD0D06BBB, 0xEFEF2AC5, 0xAAAAE54F, 0xFBFB16ED, 0x4343C586, 0x4D4DD79A, 0x33335566, 0x85859411, + 0x4545CF8A, 0xF9F910E9, 0x02020604, 0x7F7F81FE, 0x5050F0A0, 0x3C3C4478, 0x9F9FBA25, 0xA8A8E34B, + 0x5151F3A2, 0xA3A3FE5D, 0x4040C080, 0x8F8F8A05, 0x9292AD3F, 0x9D9DBC21, 0x38384870, 0xF5F504F1, + 0xBCBCDF63, 0xB6B6C177, 0xDADA75AF, 0x21216342, 0x10103020, 0xFFFF1AE5, 0xF3F30EFD, 0xD2D26DBF, + 0xCDCD4C81, 0x0C0C1418, 0x13133526, 0xECEC2FC3, 0x5F5FE1BE, 0x9797A235, 0x4444CC88, 0x1717392E, + 0xC4C45793, 0xA7A7F255, 0x7E7E82FC, 0x3D3D477A, 0x6464ACC8, 0x5D5DE7BA, 0x19192B32, 0x737395E6, + 0x6060A0C0, 0x81819819, 0x4F4FD19E, 0xDCDC7FA3, 0x22226644, 0x2A2A7E54, 0x9090AB3B, 0x8888830B, + 0x4646CA8C, 0xEEEE29C7, 0xB8B8D36B, 0x14143C28, 0xDEDE79A7, 0x5E5EE2BC, 0x0B0B1D16, 0xDBDB76AD, + 0xE0E03BDB, 0x32325664, 0x3A3A4E74, 0x0A0A1E14, 0x4949DB92, 0x06060A0C, 0x24246C48, 0x5C5CE4B8, + 0xC2C25D9F, 0xD3D36EBD, 0xACACEF43, 0x6262A6C4, 0x9191A839, 0x9595A431, 0xE4E437D3, 0x79798BF2, + 0xE7E732D5, 0xC8C8438B, 0x3737596E, 0x6D6DB7DA, 0x8D8D8C01, 0xD5D564B1, 0x4E4ED29C, 0xA9A9E049, + 0x6C6CB4D8, 0x5656FAAC, 0xF4F407F3, 0xEAEA25CF, 0x6565AFCA, 0x7A7A8EF4, 0xAEAEE947, 0x08081810, + 0xBABAD56F, 0x787888F0, 0x25256F4A, 0x2E2E725C, 0x1C1C2438, 0xA6A6F157, 0xB4B4C773, 0xC6C65197, + 0xE8E823CB, 0xDDDD7CA1, 0x74749CE8, 0x1F1F213E, 0x4B4BDD96, 0xBDBDDC61, 0x8B8B860D, 0x8A8A850F, + 0x707090E0, 0x3E3E427C, 0xB5B5C471, 0x6666AACC, 0x4848D890, 0x03030506, 0xF6F601F7, 0x0E0E121C, + 0x6161A3C2, 0x35355F6A, 0x5757F9AE, 0xB9B9D069, 0x86869117, 0xC1C15899, 0x1D1D273A, 0x9E9EB927, + 0xE1E138D9, 0xF8F813EB, 0x9898B32B, 0x11113322, 0x6969BBD2, 0xD9D970A9, 0x8E8E8907, 0x9494A733, + 0x9B9BB62D, 0x1E1E223C, 0x87879215, 0xE9E920C9, 0xCECE4987, 0x5555FFAA, 0x28287850, 0xDFDF7AA5, + 0x8C8C8F03, 0xA1A1F859, 0x89898009, 0x0D0D171A, 0xBFBFDA65, 0xE6E631D7, 0x4242C684, 0x6868B8D0, + 0x4141C382, 0x9999B029, 0x2D2D775A, 0x0F0F111E, 0xB0B0CB7B, 0x5454FCA8, 0xBBBBD66D, 0x16163A2C + ); + + /** + * Precomputed invMixColumns table + * + * @see Crypt_Rijndael:_encryptBlock() + * @see Crypt_Rijndael:_decryptBlock() + * @var Array + * @access private + */ + var $dt0 = array( + 0x51F4A750, 0x7E416553, 0x1A17A4C3, 0x3A275E96, 0x3BAB6BCB, 0x1F9D45F1, 0xACFA58AB, 0x4BE30393, + 0x2030FA55, 0xAD766DF6, 0x88CC7691, 0xF5024C25, 0x4FE5D7FC, 0xC52ACBD7, 0x26354480, 0xB562A38F, + 0xDEB15A49, 0x25BA1B67, 0x45EA0E98, 0x5DFEC0E1, 0xC32F7502, 0x814CF012, 0x8D4697A3, 0x6BD3F9C6, + 0x038F5FE7, 0x15929C95, 0xBF6D7AEB, 0x955259DA, 0xD4BE832D, 0x587421D3, 0x49E06929, 0x8EC9C844, + 0x75C2896A, 0xF48E7978, 0x99583E6B, 0x27B971DD, 0xBEE14FB6, 0xF088AD17, 0xC920AC66, 0x7DCE3AB4, + 0x63DF4A18, 0xE51A3182, 0x97513360, 0x62537F45, 0xB16477E0, 0xBB6BAE84, 0xFE81A01C, 0xF9082B94, + 0x70486858, 0x8F45FD19, 0x94DE6C87, 0x527BF8B7, 0xAB73D323, 0x724B02E2, 0xE31F8F57, 0x6655AB2A, + 0xB2EB2807, 0x2FB5C203, 0x86C57B9A, 0xD33708A5, 0x302887F2, 0x23BFA5B2, 0x02036ABA, 0xED16825C, + 0x8ACF1C2B, 0xA779B492, 0xF307F2F0, 0x4E69E2A1, 0x65DAF4CD, 0x0605BED5, 0xD134621F, 0xC4A6FE8A, + 0x342E539D, 0xA2F355A0, 0x058AE132, 0xA4F6EB75, 0x0B83EC39, 0x4060EFAA, 0x5E719F06, 0xBD6E1051, + 0x3E218AF9, 0x96DD063D, 0xDD3E05AE, 0x4DE6BD46, 0x91548DB5, 0x71C45D05, 0x0406D46F, 0x605015FF, + 0x1998FB24, 0xD6BDE997, 0x894043CC, 0x67D99E77, 0xB0E842BD, 0x07898B88, 0xE7195B38, 0x79C8EEDB, + 0xA17C0A47, 0x7C420FE9, 0xF8841EC9, 0x00000000, 0x09808683, 0x322BED48, 0x1E1170AC, 0x6C5A724E, + 0xFD0EFFFB, 0x0F853856, 0x3DAED51E, 0x362D3927, 0x0A0FD964, 0x685CA621, 0x9B5B54D1, 0x24362E3A, + 0x0C0A67B1, 0x9357E70F, 0xB4EE96D2, 0x1B9B919E, 0x80C0C54F, 0x61DC20A2, 0x5A774B69, 0x1C121A16, + 0xE293BA0A, 0xC0A02AE5, 0x3C22E043, 0x121B171D, 0x0E090D0B, 0xF28BC7AD, 0x2DB6A8B9, 0x141EA9C8, + 0x57F11985, 0xAF75074C, 0xEE99DDBB, 0xA37F60FD, 0xF701269F, 0x5C72F5BC, 0x44663BC5, 0x5BFB7E34, + 0x8B432976, 0xCB23C6DC, 0xB6EDFC68, 0xB8E4F163, 0xD731DCCA, 0x42638510, 0x13972240, 0x84C61120, + 0x854A247D, 0xD2BB3DF8, 0xAEF93211, 0xC729A16D, 0x1D9E2F4B, 0xDCB230F3, 0x0D8652EC, 0x77C1E3D0, + 0x2BB3166C, 0xA970B999, 0x119448FA, 0x47E96422, 0xA8FC8CC4, 0xA0F03F1A, 0x567D2CD8, 0x223390EF, + 0x87494EC7, 0xD938D1C1, 0x8CCAA2FE, 0x98D40B36, 0xA6F581CF, 0xA57ADE28, 0xDAB78E26, 0x3FADBFA4, + 0x2C3A9DE4, 0x5078920D, 0x6A5FCC9B, 0x547E4662, 0xF68D13C2, 0x90D8B8E8, 0x2E39F75E, 0x82C3AFF5, + 0x9F5D80BE, 0x69D0937C, 0x6FD52DA9, 0xCF2512B3, 0xC8AC993B, 0x10187DA7, 0xE89C636E, 0xDB3BBB7B, + 0xCD267809, 0x6E5918F4, 0xEC9AB701, 0x834F9AA8, 0xE6956E65, 0xAAFFE67E, 0x21BCCF08, 0xEF15E8E6, + 0xBAE79BD9, 0x4A6F36CE, 0xEA9F09D4, 0x29B07CD6, 0x31A4B2AF, 0x2A3F2331, 0xC6A59430, 0x35A266C0, + 0x744EBC37, 0xFC82CAA6, 0xE090D0B0, 0x33A7D815, 0xF104984A, 0x41ECDAF7, 0x7FCD500E, 0x1791F62F, + 0x764DD68D, 0x43EFB04D, 0xCCAA4D54, 0xE49604DF, 0x9ED1B5E3, 0x4C6A881B, 0xC12C1FB8, 0x4665517F, + 0x9D5EEA04, 0x018C355D, 0xFA877473, 0xFB0B412E, 0xB3671D5A, 0x92DBD252, 0xE9105633, 0x6DD64713, + 0x9AD7618C, 0x37A10C7A, 0x59F8148E, 0xEB133C89, 0xCEA927EE, 0xB761C935, 0xE11CE5ED, 0x7A47B13C, + 0x9CD2DF59, 0x55F2733F, 0x1814CE79, 0x73C737BF, 0x53F7CDEA, 0x5FFDAA5B, 0xDF3D6F14, 0x7844DB86, + 0xCAAFF381, 0xB968C43E, 0x3824342C, 0xC2A3405F, 0x161DC372, 0xBCE2250C, 0x283C498B, 0xFF0D9541, + 0x39A80171, 0x080CB3DE, 0xD8B4E49C, 0x6456C190, 0x7BCB8461, 0xD532B670, 0x486C5C74, 0xD0B85742 + ); + + /** + * Precomputed invMixColumns table + * + * @see Crypt_Rijndael:_encryptBlock() + * @see Crypt_Rijndael:_decryptBlock() + * @var Array + * @access private + */ + var $dt1 = array( + 0x5051F4A7, 0x537E4165, 0xC31A17A4, 0x963A275E, 0xCB3BAB6B, 0xF11F9D45, 0xABACFA58, 0x934BE303, + 0x552030FA, 0xF6AD766D, 0x9188CC76, 0x25F5024C, 0xFC4FE5D7, 0xD7C52ACB, 0x80263544, 0x8FB562A3, + 0x49DEB15A, 0x6725BA1B, 0x9845EA0E, 0xE15DFEC0, 0x02C32F75, 0x12814CF0, 0xA38D4697, 0xC66BD3F9, + 0xE7038F5F, 0x9515929C, 0xEBBF6D7A, 0xDA955259, 0x2DD4BE83, 0xD3587421, 0x2949E069, 0x448EC9C8, + 0x6A75C289, 0x78F48E79, 0x6B99583E, 0xDD27B971, 0xB6BEE14F, 0x17F088AD, 0x66C920AC, 0xB47DCE3A, + 0x1863DF4A, 0x82E51A31, 0x60975133, 0x4562537F, 0xE0B16477, 0x84BB6BAE, 0x1CFE81A0, 0x94F9082B, + 0x58704868, 0x198F45FD, 0x8794DE6C, 0xB7527BF8, 0x23AB73D3, 0xE2724B02, 0x57E31F8F, 0x2A6655AB, + 0x07B2EB28, 0x032FB5C2, 0x9A86C57B, 0xA5D33708, 0xF2302887, 0xB223BFA5, 0xBA02036A, 0x5CED1682, + 0x2B8ACF1C, 0x92A779B4, 0xF0F307F2, 0xA14E69E2, 0xCD65DAF4, 0xD50605BE, 0x1FD13462, 0x8AC4A6FE, + 0x9D342E53, 0xA0A2F355, 0x32058AE1, 0x75A4F6EB, 0x390B83EC, 0xAA4060EF, 0x065E719F, 0x51BD6E10, + 0xF93E218A, 0x3D96DD06, 0xAEDD3E05, 0x464DE6BD, 0xB591548D, 0x0571C45D, 0x6F0406D4, 0xFF605015, + 0x241998FB, 0x97D6BDE9, 0xCC894043, 0x7767D99E, 0xBDB0E842, 0x8807898B, 0x38E7195B, 0xDB79C8EE, + 0x47A17C0A, 0xE97C420F, 0xC9F8841E, 0x00000000, 0x83098086, 0x48322BED, 0xAC1E1170, 0x4E6C5A72, + 0xFBFD0EFF, 0x560F8538, 0x1E3DAED5, 0x27362D39, 0x640A0FD9, 0x21685CA6, 0xD19B5B54, 0x3A24362E, + 0xB10C0A67, 0x0F9357E7, 0xD2B4EE96, 0x9E1B9B91, 0x4F80C0C5, 0xA261DC20, 0x695A774B, 0x161C121A, + 0x0AE293BA, 0xE5C0A02A, 0x433C22E0, 0x1D121B17, 0x0B0E090D, 0xADF28BC7, 0xB92DB6A8, 0xC8141EA9, + 0x8557F119, 0x4CAF7507, 0xBBEE99DD, 0xFDA37F60, 0x9FF70126, 0xBC5C72F5, 0xC544663B, 0x345BFB7E, + 0x768B4329, 0xDCCB23C6, 0x68B6EDFC, 0x63B8E4F1, 0xCAD731DC, 0x10426385, 0x40139722, 0x2084C611, + 0x7D854A24, 0xF8D2BB3D, 0x11AEF932, 0x6DC729A1, 0x4B1D9E2F, 0xF3DCB230, 0xEC0D8652, 0xD077C1E3, + 0x6C2BB316, 0x99A970B9, 0xFA119448, 0x2247E964, 0xC4A8FC8C, 0x1AA0F03F, 0xD8567D2C, 0xEF223390, + 0xC787494E, 0xC1D938D1, 0xFE8CCAA2, 0x3698D40B, 0xCFA6F581, 0x28A57ADE, 0x26DAB78E, 0xA43FADBF, + 0xE42C3A9D, 0x0D507892, 0x9B6A5FCC, 0x62547E46, 0xC2F68D13, 0xE890D8B8, 0x5E2E39F7, 0xF582C3AF, + 0xBE9F5D80, 0x7C69D093, 0xA96FD52D, 0xB3CF2512, 0x3BC8AC99, 0xA710187D, 0x6EE89C63, 0x7BDB3BBB, + 0x09CD2678, 0xF46E5918, 0x01EC9AB7, 0xA8834F9A, 0x65E6956E, 0x7EAAFFE6, 0x0821BCCF, 0xE6EF15E8, + 0xD9BAE79B, 0xCE4A6F36, 0xD4EA9F09, 0xD629B07C, 0xAF31A4B2, 0x312A3F23, 0x30C6A594, 0xC035A266, + 0x37744EBC, 0xA6FC82CA, 0xB0E090D0, 0x1533A7D8, 0x4AF10498, 0xF741ECDA, 0x0E7FCD50, 0x2F1791F6, + 0x8D764DD6, 0x4D43EFB0, 0x54CCAA4D, 0xDFE49604, 0xE39ED1B5, 0x1B4C6A88, 0xB8C12C1F, 0x7F466551, + 0x049D5EEA, 0x5D018C35, 0x73FA8774, 0x2EFB0B41, 0x5AB3671D, 0x5292DBD2, 0x33E91056, 0x136DD647, + 0x8C9AD761, 0x7A37A10C, 0x8E59F814, 0x89EB133C, 0xEECEA927, 0x35B761C9, 0xEDE11CE5, 0x3C7A47B1, + 0x599CD2DF, 0x3F55F273, 0x791814CE, 0xBF73C737, 0xEA53F7CD, 0x5B5FFDAA, 0x14DF3D6F, 0x867844DB, + 0x81CAAFF3, 0x3EB968C4, 0x2C382434, 0x5FC2A340, 0x72161DC3, 0x0CBCE225, 0x8B283C49, 0x41FF0D95, + 0x7139A801, 0xDE080CB3, 0x9CD8B4E4, 0x906456C1, 0x617BCB84, 0x70D532B6, 0x74486C5C, 0x42D0B857 + ); + + /** + * Precomputed invMixColumns table + * + * @see Crypt_Rijndael:_encryptBlock() + * @see Crypt_Rijndael:_decryptBlock() + * @var Array + * @access private + */ + var $dt2 = array( + 0xA75051F4, 0x65537E41, 0xA4C31A17, 0x5E963A27, 0x6BCB3BAB, 0x45F11F9D, 0x58ABACFA, 0x03934BE3, + 0xFA552030, 0x6DF6AD76, 0x769188CC, 0x4C25F502, 0xD7FC4FE5, 0xCBD7C52A, 0x44802635, 0xA38FB562, + 0x5A49DEB1, 0x1B6725BA, 0x0E9845EA, 0xC0E15DFE, 0x7502C32F, 0xF012814C, 0x97A38D46, 0xF9C66BD3, + 0x5FE7038F, 0x9C951592, 0x7AEBBF6D, 0x59DA9552, 0x832DD4BE, 0x21D35874, 0x692949E0, 0xC8448EC9, + 0x896A75C2, 0x7978F48E, 0x3E6B9958, 0x71DD27B9, 0x4FB6BEE1, 0xAD17F088, 0xAC66C920, 0x3AB47DCE, + 0x4A1863DF, 0x3182E51A, 0x33609751, 0x7F456253, 0x77E0B164, 0xAE84BB6B, 0xA01CFE81, 0x2B94F908, + 0x68587048, 0xFD198F45, 0x6C8794DE, 0xF8B7527B, 0xD323AB73, 0x02E2724B, 0x8F57E31F, 0xAB2A6655, + 0x2807B2EB, 0xC2032FB5, 0x7B9A86C5, 0x08A5D337, 0x87F23028, 0xA5B223BF, 0x6ABA0203, 0x825CED16, + 0x1C2B8ACF, 0xB492A779, 0xF2F0F307, 0xE2A14E69, 0xF4CD65DA, 0xBED50605, 0x621FD134, 0xFE8AC4A6, + 0x539D342E, 0x55A0A2F3, 0xE132058A, 0xEB75A4F6, 0xEC390B83, 0xEFAA4060, 0x9F065E71, 0x1051BD6E, + 0x8AF93E21, 0x063D96DD, 0x05AEDD3E, 0xBD464DE6, 0x8DB59154, 0x5D0571C4, 0xD46F0406, 0x15FF6050, + 0xFB241998, 0xE997D6BD, 0x43CC8940, 0x9E7767D9, 0x42BDB0E8, 0x8B880789, 0x5B38E719, 0xEEDB79C8, + 0x0A47A17C, 0x0FE97C42, 0x1EC9F884, 0x00000000, 0x86830980, 0xED48322B, 0x70AC1E11, 0x724E6C5A, + 0xFFFBFD0E, 0x38560F85, 0xD51E3DAE, 0x3927362D, 0xD9640A0F, 0xA621685C, 0x54D19B5B, 0x2E3A2436, + 0x67B10C0A, 0xE70F9357, 0x96D2B4EE, 0x919E1B9B, 0xC54F80C0, 0x20A261DC, 0x4B695A77, 0x1A161C12, + 0xBA0AE293, 0x2AE5C0A0, 0xE0433C22, 0x171D121B, 0x0D0B0E09, 0xC7ADF28B, 0xA8B92DB6, 0xA9C8141E, + 0x198557F1, 0x074CAF75, 0xDDBBEE99, 0x60FDA37F, 0x269FF701, 0xF5BC5C72, 0x3BC54466, 0x7E345BFB, + 0x29768B43, 0xC6DCCB23, 0xFC68B6ED, 0xF163B8E4, 0xDCCAD731, 0x85104263, 0x22401397, 0x112084C6, + 0x247D854A, 0x3DF8D2BB, 0x3211AEF9, 0xA16DC729, 0x2F4B1D9E, 0x30F3DCB2, 0x52EC0D86, 0xE3D077C1, + 0x166C2BB3, 0xB999A970, 0x48FA1194, 0x642247E9, 0x8CC4A8FC, 0x3F1AA0F0, 0x2CD8567D, 0x90EF2233, + 0x4EC78749, 0xD1C1D938, 0xA2FE8CCA, 0x0B3698D4, 0x81CFA6F5, 0xDE28A57A, 0x8E26DAB7, 0xBFA43FAD, + 0x9DE42C3A, 0x920D5078, 0xCC9B6A5F, 0x4662547E, 0x13C2F68D, 0xB8E890D8, 0xF75E2E39, 0xAFF582C3, + 0x80BE9F5D, 0x937C69D0, 0x2DA96FD5, 0x12B3CF25, 0x993BC8AC, 0x7DA71018, 0x636EE89C, 0xBB7BDB3B, + 0x7809CD26, 0x18F46E59, 0xB701EC9A, 0x9AA8834F, 0x6E65E695, 0xE67EAAFF, 0xCF0821BC, 0xE8E6EF15, + 0x9BD9BAE7, 0x36CE4A6F, 0x09D4EA9F, 0x7CD629B0, 0xB2AF31A4, 0x23312A3F, 0x9430C6A5, 0x66C035A2, + 0xBC37744E, 0xCAA6FC82, 0xD0B0E090, 0xD81533A7, 0x984AF104, 0xDAF741EC, 0x500E7FCD, 0xF62F1791, + 0xD68D764D, 0xB04D43EF, 0x4D54CCAA, 0x04DFE496, 0xB5E39ED1, 0x881B4C6A, 0x1FB8C12C, 0x517F4665, + 0xEA049D5E, 0x355D018C, 0x7473FA87, 0x412EFB0B, 0x1D5AB367, 0xD25292DB, 0x5633E910, 0x47136DD6, + 0x618C9AD7, 0x0C7A37A1, 0x148E59F8, 0x3C89EB13, 0x27EECEA9, 0xC935B761, 0xE5EDE11C, 0xB13C7A47, + 0xDF599CD2, 0x733F55F2, 0xCE791814, 0x37BF73C7, 0xCDEA53F7, 0xAA5B5FFD, 0x6F14DF3D, 0xDB867844, + 0xF381CAAF, 0xC43EB968, 0x342C3824, 0x405FC2A3, 0xC372161D, 0x250CBCE2, 0x498B283C, 0x9541FF0D, + 0x017139A8, 0xB3DE080C, 0xE49CD8B4, 0xC1906456, 0x84617BCB, 0xB670D532, 0x5C74486C, 0x5742D0B8 + ); + + /** + * Precomputed invMixColumns table + * + * @see Crypt_Rijndael:_encryptBlock() + * @see Crypt_Rijndael:_decryptBlock() + * @var Array + * @access private + */ + var $dt3 = array( + 0xF4A75051, 0x4165537E, 0x17A4C31A, 0x275E963A, 0xAB6BCB3B, 0x9D45F11F, 0xFA58ABAC, 0xE303934B, + 0x30FA5520, 0x766DF6AD, 0xCC769188, 0x024C25F5, 0xE5D7FC4F, 0x2ACBD7C5, 0x35448026, 0x62A38FB5, + 0xB15A49DE, 0xBA1B6725, 0xEA0E9845, 0xFEC0E15D, 0x2F7502C3, 0x4CF01281, 0x4697A38D, 0xD3F9C66B, + 0x8F5FE703, 0x929C9515, 0x6D7AEBBF, 0x5259DA95, 0xBE832DD4, 0x7421D358, 0xE0692949, 0xC9C8448E, + 0xC2896A75, 0x8E7978F4, 0x583E6B99, 0xB971DD27, 0xE14FB6BE, 0x88AD17F0, 0x20AC66C9, 0xCE3AB47D, + 0xDF4A1863, 0x1A3182E5, 0x51336097, 0x537F4562, 0x6477E0B1, 0x6BAE84BB, 0x81A01CFE, 0x082B94F9, + 0x48685870, 0x45FD198F, 0xDE6C8794, 0x7BF8B752, 0x73D323AB, 0x4B02E272, 0x1F8F57E3, 0x55AB2A66, + 0xEB2807B2, 0xB5C2032F, 0xC57B9A86, 0x3708A5D3, 0x2887F230, 0xBFA5B223, 0x036ABA02, 0x16825CED, + 0xCF1C2B8A, 0x79B492A7, 0x07F2F0F3, 0x69E2A14E, 0xDAF4CD65, 0x05BED506, 0x34621FD1, 0xA6FE8AC4, + 0x2E539D34, 0xF355A0A2, 0x8AE13205, 0xF6EB75A4, 0x83EC390B, 0x60EFAA40, 0x719F065E, 0x6E1051BD, + 0x218AF93E, 0xDD063D96, 0x3E05AEDD, 0xE6BD464D, 0x548DB591, 0xC45D0571, 0x06D46F04, 0x5015FF60, + 0x98FB2419, 0xBDE997D6, 0x4043CC89, 0xD99E7767, 0xE842BDB0, 0x898B8807, 0x195B38E7, 0xC8EEDB79, + 0x7C0A47A1, 0x420FE97C, 0x841EC9F8, 0x00000000, 0x80868309, 0x2BED4832, 0x1170AC1E, 0x5A724E6C, + 0x0EFFFBFD, 0x8538560F, 0xAED51E3D, 0x2D392736, 0x0FD9640A, 0x5CA62168, 0x5B54D19B, 0x362E3A24, + 0x0A67B10C, 0x57E70F93, 0xEE96D2B4, 0x9B919E1B, 0xC0C54F80, 0xDC20A261, 0x774B695A, 0x121A161C, + 0x93BA0AE2, 0xA02AE5C0, 0x22E0433C, 0x1B171D12, 0x090D0B0E, 0x8BC7ADF2, 0xB6A8B92D, 0x1EA9C814, + 0xF1198557, 0x75074CAF, 0x99DDBBEE, 0x7F60FDA3, 0x01269FF7, 0x72F5BC5C, 0x663BC544, 0xFB7E345B, + 0x4329768B, 0x23C6DCCB, 0xEDFC68B6, 0xE4F163B8, 0x31DCCAD7, 0x63851042, 0x97224013, 0xC6112084, + 0x4A247D85, 0xBB3DF8D2, 0xF93211AE, 0x29A16DC7, 0x9E2F4B1D, 0xB230F3DC, 0x8652EC0D, 0xC1E3D077, + 0xB3166C2B, 0x70B999A9, 0x9448FA11, 0xE9642247, 0xFC8CC4A8, 0xF03F1AA0, 0x7D2CD856, 0x3390EF22, + 0x494EC787, 0x38D1C1D9, 0xCAA2FE8C, 0xD40B3698, 0xF581CFA6, 0x7ADE28A5, 0xB78E26DA, 0xADBFA43F, + 0x3A9DE42C, 0x78920D50, 0x5FCC9B6A, 0x7E466254, 0x8D13C2F6, 0xD8B8E890, 0x39F75E2E, 0xC3AFF582, + 0x5D80BE9F, 0xD0937C69, 0xD52DA96F, 0x2512B3CF, 0xAC993BC8, 0x187DA710, 0x9C636EE8, 0x3BBB7BDB, + 0x267809CD, 0x5918F46E, 0x9AB701EC, 0x4F9AA883, 0x956E65E6, 0xFFE67EAA, 0xBCCF0821, 0x15E8E6EF, + 0xE79BD9BA, 0x6F36CE4A, 0x9F09D4EA, 0xB07CD629, 0xA4B2AF31, 0x3F23312A, 0xA59430C6, 0xA266C035, + 0x4EBC3774, 0x82CAA6FC, 0x90D0B0E0, 0xA7D81533, 0x04984AF1, 0xECDAF741, 0xCD500E7F, 0x91F62F17, + 0x4DD68D76, 0xEFB04D43, 0xAA4D54CC, 0x9604DFE4, 0xD1B5E39E, 0x6A881B4C, 0x2C1FB8C1, 0x65517F46, + 0x5EEA049D, 0x8C355D01, 0x877473FA, 0x0B412EFB, 0x671D5AB3, 0xDBD25292, 0x105633E9, 0xD647136D, + 0xD7618C9A, 0xA10C7A37, 0xF8148E59, 0x133C89EB, 0xA927EECE, 0x61C935B7, 0x1CE5EDE1, 0x47B13C7A, + 0xD2DF599C, 0xF2733F55, 0x14CE7918, 0xC737BF73, 0xF7CDEA53, 0xFDAA5B5F, 0x3D6F14DF, 0x44DB8678, + 0xAFF381CA, 0x68C43EB9, 0x24342C38, 0xA3405FC2, 0x1DC37216, 0xE2250CBC, 0x3C498B28, 0x0D9541FF, + 0xA8017139, 0x0CB3DE08, 0xB4E49CD8, 0x56C19064, 0xCB84617B, 0x32B670D5, 0x6C5C7448, 0xB85742D0 + ); + + /** + * The SubByte S-Box + * + * @see Crypt_Rijndael::_encryptBlock() + * @var Array + * @access private + */ + var $sbox = array( + 0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76, + 0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0, + 0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15, + 0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75, + 0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84, + 0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF, + 0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8, + 0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2, + 0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73, + 0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB, + 0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79, + 0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08, + 0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A, + 0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E, + 0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF, + 0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16 + ); + + /** + * The inverse SubByte S-Box + * + * @see Crypt_Rijndael::_decryptBlock() + * @var Array + * @access private + */ + var $isbox = array( + 0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38, 0xBF, 0x40, 0xA3, 0x9E, 0x81, 0xF3, 0xD7, 0xFB, + 0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87, 0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB, + 0x54, 0x7B, 0x94, 0x32, 0xA6, 0xC2, 0x23, 0x3D, 0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E, + 0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2, 0x76, 0x5B, 0xA2, 0x49, 0x6D, 0x8B, 0xD1, 0x25, + 0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92, + 0x6C, 0x70, 0x48, 0x50, 0xFD, 0xED, 0xB9, 0xDA, 0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84, + 0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A, 0xF7, 0xE4, 0x58, 0x05, 0xB8, 0xB3, 0x45, 0x06, + 0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02, 0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B, + 0x3A, 0x91, 0x11, 0x41, 0x4F, 0x67, 0xDC, 0xEA, 0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73, + 0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85, 0xE2, 0xF9, 0x37, 0xE8, 0x1C, 0x75, 0xDF, 0x6E, + 0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89, 0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B, + 0xFC, 0x56, 0x3E, 0x4B, 0xC6, 0xD2, 0x79, 0x20, 0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4, + 0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31, 0xB1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xEC, 0x5F, + 0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D, 0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF, + 0xA0, 0xE0, 0x3B, 0x4D, 0xAE, 0x2A, 0xF5, 0xB0, 0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61, + 0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26, 0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D + ); + + /** + * Default Constructor. + * + * Determines whether or not the mcrypt extension should be used. + * + * $mode could be: + * + * - CRYPT_RIJNDAEL_MODE_ECB + * + * - CRYPT_RIJNDAEL_MODE_CBC + * + * - CRYPT_RIJNDAEL_MODE_CTR + * + * - CRYPT_RIJNDAEL_MODE_CFB + * + * - CRYPT_RIJNDAEL_MODE_OFB + * + * If not explictly set, CRYPT_RIJNDAEL_MODE_CBC will be used. + * + * @see Crypt_Base::Crypt_Base() + * @param optional Integer $mode + * @access public + */ + function Crypt_Rijndael($mode = CRYPT_RIJNDAEL_MODE_CBC) + { + parent::Crypt_Base($mode); + } + + /** + * Sets the key. + * + * Keys can be of any length. Rijndael, itself, requires the use of a key that's between 128-bits and 256-bits long and + * whose length is a multiple of 32. If the key is less than 256-bits and the key length isn't set, we round the length + * up to the closest valid key length, padding $key with null bytes. If the key is more than 256-bits, we trim the + * excess bits. + * + * If the key is not explicitly set, it'll be assumed to be all null bytes. + * + * Note: 160/224-bit keys must explicitly set by setKeyLength(), otherwise they will be round/pad up to 192/256 bits. + * + * @see Crypt_Base:setKey() + * @see setKeyLength() + * @access public + * @param String $key + */ + function setKey($key) + { + parent::setKey($key); + + if (!$this->explicit_key_length) { + $length = strlen($key); + switch (true) { + case $length <= 16: + $this->key_size = 16; + break; + case $length <= 24: + $this->key_size = 24; + break; + default: + $this->key_size = 32; + } + $this->_setupEngine(); + } + } + + /** + * Sets the key length + * + * Valid key lengths are 128, 160, 192, 224, and 256. If the length is less than 128, it will be rounded up to + * 128. If the length is greater than 128 and invalid, it will be rounded down to the closest valid amount. + * + * Note: phpseclib extends Rijndael (and AES) for using 160- and 224-bit keys but they are officially not defined + * and the most (if not all) implementations are not able using 160/224-bit keys but round/pad them up to + * 192/256 bits as, for example, mcrypt will do. + * + * That said, if you want be compatible with other Rijndael and AES implementations, + * you should not setKeyLength(160) or setKeyLength(224). + * + * Additional: In case of 160- and 224-bit keys, phpseclib will/can, for that reason, not use + * the mcrypt php extention, even if available. + * This results then in slower encryption. + * + * @access public + * @param Integer $length + */ + function setKeyLength($length) + { + switch (true) { + case $length == 160: + $this->key_size = 20; + break; + case $length == 224: + $this->key_size = 28; + break; + case $length <= 128: + $this->key_size = 16; + break; + case $length <= 192: + $this->key_size = 24; + break; + default: + $this->key_size = 32; + } + + $this->explicit_key_length = true; + $this->changed = true; + $this->_setupEngine(); + } + + /** + * Sets the block length + * + * Valid block lengths are 128, 160, 192, 224, and 256. If the length is less than 128, it will be rounded up to + * 128. If the length is greater than 128 and invalid, it will be rounded down to the closest valid amount. + * + * @access public + * @param Integer $length + */ + function setBlockLength($length) + { + $length >>= 5; + if ($length > 8) { + $length = 8; + } else if ($length < 4) { + $length = 4; + } + $this->Nb = $length; + $this->block_size = $length << 2; + $this->changed = true; + $this->_setupEngine(); + } + + /** + * Setup the fastest possible $engine + * + * Determines if the mcrypt (MODE_MCRYPT) $engine available + * and usable for the current $block_size and $key_size. + * + * If not, the slower MODE_INTERNAL $engine will be set. + * + * @see setKey() + * @see setKeyLength() + * @see setBlockLength() + * @access private + */ + function _setupEngine() + { + if (constant('CRYPT_' . $this->const_namespace . '_MODE') == CRYPT_MODE_INTERNAL) { + // No mcrypt support at all for rijndael + return; + } + + // The required mcrypt module name for the current $block_size of rijndael + $cipher_name_mcrypt = 'rijndael-' . ($this->block_size << 3); + + // Determining the availibility/usability of $cipher_name_mcrypt + switch (true) { + case $this->key_size % 8: // mcrypt is not usable for 160/224-bit keys, only for 128/192/256-bit keys + case !in_array($cipher_name_mcrypt, mcrypt_list_algorithms()): // $cipher_name_mcrypt is not available for the current $block_size + $engine = CRYPT_MODE_INTERNAL; + break; + default: + $engine = CRYPT_MODE_MCRYPT; + } + + if ($this->engine == $engine && $this->cipher_name_mcrypt == $cipher_name_mcrypt) { + // allready set, so we not unnecessary close $this->enmcrypt/demcrypt/ecb + return; + } + + // Set the $engine + $this->engine = $engine; + $this->cipher_name_mcrypt = $cipher_name_mcrypt; + + if ($this->enmcrypt) { + // Closing the current mcrypt resource(s). _mcryptSetup() will, if needed, + // (re)open them with the module named in $this->cipher_name_mcrypt + mcrypt_module_close($this->enmcrypt); + mcrypt_module_close($this->demcrypt); + $this->enmcrypt = null; + $this->demcrypt = null; + + if ($this->ecb) { + mcrypt_module_close($this->ecb); + $this->ecb = null; + } + } + } + + /** + * Setup the CRYPT_MODE_MCRYPT $engine + * + * @see Crypt_Base::_setupMcrypt() + * @access private + */ + function _setupMcrypt() + { + $this->key = str_pad(substr($this->key, 0, $this->key_size), $this->key_size, "\0"); + parent::_setupMcrypt(); + } + + /** + * Encrypts a block + * + * @access private + * @param String $in + * @return String + */ + function _encryptBlock($in) + { + static $t0, $t1, $t2, $t3, $sbox; + if (!$t0) { + for ($i = 0; $i < 256; ++$i) { + $t0[] = (int)$this->t0[$i]; + $t1[] = (int)$this->t1[$i]; + $t2[] = (int)$this->t2[$i]; + $t3[] = (int)$this->t3[$i]; + $sbox[] = (int)$this->sbox[$i]; + } + } + + $state = array(); + $words = unpack('N*', $in); + + $c = $this->c; + $w = $this->w; + $Nb = $this->Nb; + $Nr = $this->Nr; + + // addRoundKey + $i = -1; + foreach ($words as $word) { + $state[] = $word ^ $w[0][++$i]; + } + + // fips-197.pdf#page=19, "Figure 5. Pseudo Code for the Cipher", states that this loop has four components - + // subBytes, shiftRows, mixColumns, and addRoundKey. fips-197.pdf#page=30, "Implementation Suggestions Regarding + // Various Platforms" suggests that performs enhanced implementations are described in Rijndael-ammended.pdf. + // Rijndael-ammended.pdf#page=20, "Implementation aspects / 32-bit processor", discusses such an optimization. + // Unfortunately, the description given there is not quite correct. Per aes.spec.v316.pdf#page=19 [1], + // equation (7.4.7) is supposed to use addition instead of subtraction, so we'll do that here, as well. + + // [1] http://fp.gladman.plus.com/cryptography_technology/rijndael/aes.spec.v316.pdf + $temp = array(); + for ($round = 1; $round < $Nr; ++$round) { + $i = 0; // $c[0] == 0 + $j = $c[1]; + $k = $c[2]; + $l = $c[3]; + + while ($i < $Nb) { + $temp[$i] = $t0[$state[$i] >> 24 & 0x000000FF] ^ + $t1[$state[$j] >> 16 & 0x000000FF] ^ + $t2[$state[$k] >> 8 & 0x000000FF] ^ + $t3[$state[$l] & 0x000000FF] ^ + $w[$round][$i]; + ++$i; + $j = ($j + 1) % $Nb; + $k = ($k + 1) % $Nb; + $l = ($l + 1) % $Nb; + } + $state = $temp; + } + + // subWord + for ($i = 0; $i < $Nb; ++$i) { + $state[$i] = $sbox[$state[$i] & 0x000000FF] | + ($sbox[$state[$i] >> 8 & 0x000000FF] << 8) | + ($sbox[$state[$i] >> 16 & 0x000000FF] << 16) | + ($sbox[$state[$i] >> 24 & 0x000000FF] << 24); + } + + // shiftRows + addRoundKey + $i = 0; // $c[0] == 0 + $j = $c[1]; + $k = $c[2]; + $l = $c[3]; + while ($i < $Nb) { + $temp[$i] = ($state[$i] & 0xFF000000) ^ + ($state[$j] & 0x00FF0000) ^ + ($state[$k] & 0x0000FF00) ^ + ($state[$l] & 0x000000FF) ^ + $w[$Nr][$i]; + ++$i; + $j = ($j + 1) % $Nb; + $k = ($k + 1) % $Nb; + $l = ($l + 1) % $Nb; + } + + switch ($Nb) { + case 8: + return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4], $temp[5], $temp[6], $temp[7]); + case 7: + return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4], $temp[5], $temp[6]); + case 6: + return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4], $temp[5]); + case 5: + return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4]); + default: + return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3]); + } + } + + /** + * Decrypts a block + * + * @access private + * @param String $in + * @return String + */ + function _decryptBlock($in) + { + static $dt0, $dt1, $dt2, $dt3, $isbox; + if (!$dt0) { + for ($i = 0; $i < 256; ++$i) { + $dt0[] = (int)$this->dt0[$i]; + $dt1[] = (int)$this->dt1[$i]; + $dt2[] = (int)$this->dt2[$i]; + $dt3[] = (int)$this->dt3[$i]; + $isbox[] = (int)$this->isbox[$i]; + } + } + + $state = array(); + $words = unpack('N*', $in); + + $c = $this->c; + $dw = $this->dw; + $Nb = $this->Nb; + $Nr = $this->Nr; + + // addRoundKey + $i = -1; + foreach ($words as $word) { + $state[] = $word ^ $dw[$Nr][++$i]; + } + + $temp = array(); + for ($round = $Nr - 1; $round > 0; --$round) { + $i = 0; // $c[0] == 0 + $j = $Nb - $c[1]; + $k = $Nb - $c[2]; + $l = $Nb - $c[3]; + + while ($i < $Nb) { + $temp[$i] = $dt0[$state[$i] >> 24 & 0x000000FF] ^ + $dt1[$state[$j] >> 16 & 0x000000FF] ^ + $dt2[$state[$k] >> 8 & 0x000000FF] ^ + $dt3[$state[$l] & 0x000000FF] ^ + $dw[$round][$i]; + ++$i; + $j = ($j + 1) % $Nb; + $k = ($k + 1) % $Nb; + $l = ($l + 1) % $Nb; + } + $state = $temp; + } + + // invShiftRows + invSubWord + addRoundKey + $i = 0; // $c[0] == 0 + $j = $Nb - $c[1]; + $k = $Nb - $c[2]; + $l = $Nb - $c[3]; + + while ($i < $Nb) { + $word = ($state[$i] & 0xFF000000) | + ($state[$j] & 0x00FF0000) | + ($state[$k] & 0x0000FF00) | + ($state[$l] & 0x000000FF); + + $temp[$i] = $dw[0][$i] ^ ($isbox[$word & 0x000000FF] | + ($isbox[$word >> 8 & 0x000000FF] << 8) | + ($isbox[$word >> 16 & 0x000000FF] << 16) | + ($isbox[$word >> 24 & 0x000000FF] << 24)); + ++$i; + $j = ($j + 1) % $Nb; + $k = ($k + 1) % $Nb; + $l = ($l + 1) % $Nb; + } + + switch ($Nb) { + case 8: + return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4], $temp[5], $temp[6], $temp[7]); + case 7: + return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4], $temp[5], $temp[6]); + case 6: + return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4], $temp[5]); + case 5: + return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4]); + default: + return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3]); + } + } + + /** + * Setup the key (expansion) + * + * @see Crypt_Base::_setupKey() + * @access private + */ + function _setupKey() + { + // Each number in $rcon is equal to the previous number multiplied by two in Rijndael's finite field. + // See http://en.wikipedia.org/wiki/Finite_field_arithmetic#Multiplicative_inverse + static $rcon = array(0, + 0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000, + 0x20000000, 0x40000000, 0x80000000, 0x1B000000, 0x36000000, + 0x6C000000, 0xD8000000, 0xAB000000, 0x4D000000, 0x9A000000, + 0x2F000000, 0x5E000000, 0xBC000000, 0x63000000, 0xC6000000, + 0x97000000, 0x35000000, 0x6A000000, 0xD4000000, 0xB3000000, + 0x7D000000, 0xFA000000, 0xEF000000, 0xC5000000, 0x91000000 + ); + + $this->key = str_pad(substr($this->key, 0, $this->key_size), $this->key_size, "\0"); + + if (isset($this->kl['key']) && $this->key === $this->kl['key'] && $this->key_size === $this->kl['key_size'] && $this->block_size === $this->kl['block_size']) { + // already expanded + return; + } + $this->kl = array('key' => $this->key, 'key_size' => $this->key_size, 'block_size' => $this->block_size); + + $this->Nk = $this->key_size >> 2; + // see Rijndael-ammended.pdf#page=44 + $this->Nr = max($this->Nk, $this->Nb) + 6; + + // shift offsets for Nb = 5, 7 are defined in Rijndael-ammended.pdf#page=44, + // "Table 8: Shift offsets in Shiftrow for the alternative block lengths" + // shift offsets for Nb = 4, 6, 8 are defined in Rijndael-ammended.pdf#page=14, + // "Table 2: Shift offsets for different block lengths" + switch ($this->Nb) { + case 4: + case 5: + case 6: + $this->c = array(0, 1, 2, 3); + break; + case 7: + $this->c = array(0, 1, 2, 4); + break; + case 8: + $this->c = array(0, 1, 3, 4); + } + + $w = array_values(unpack('N*words', $this->key)); + + $length = $this->Nb * ($this->Nr + 1); + for ($i = $this->Nk; $i < $length; $i++) { + $temp = $w[$i - 1]; + if ($i % $this->Nk == 0) { + // according to , "the size of an integer is platform-dependent". + // on a 32-bit machine, it's 32-bits, and on a 64-bit machine, it's 64-bits. on a 32-bit machine, + // 0xFFFFFFFF << 8 == 0xFFFFFF00, but on a 64-bit machine, it equals 0xFFFFFFFF00. as such, doing 'and' + // with 0xFFFFFFFF (or 0xFFFFFF00) on a 32-bit machine is unnecessary, but on a 64-bit machine, it is. + $temp = (($temp << 8) & 0xFFFFFF00) | (($temp >> 24) & 0x000000FF); // rotWord + $temp = $this->_subWord($temp) ^ $rcon[$i / $this->Nk]; + } else if ($this->Nk > 6 && $i % $this->Nk == 4) { + $temp = $this->_subWord($temp); + } + $w[$i] = $w[$i - $this->Nk] ^ $temp; + } + + // convert the key schedule from a vector of $Nb * ($Nr + 1) length to a matrix with $Nr + 1 rows and $Nb columns + // and generate the inverse key schedule. more specifically, + // according to (section 5.3.3), + // "The key expansion for the Inverse Cipher is defined as follows: + // 1. Apply the Key Expansion. + // 2. Apply InvMixColumn to all Round Keys except the first and the last one." + // also, see fips-197.pdf#page=27, "5.3.5 Equivalent Inverse Cipher" + $temp = $this->w = $this->dw = array(); + for ($i = $row = $col = 0; $i < $length; $i++, $col++) { + if ($col == $this->Nb) { + if ($row == 0) { + $this->dw[0] = $this->w[0]; + } else { + // subWord + invMixColumn + invSubWord = invMixColumn + $j = 0; + while ($j < $this->Nb) { + $dw = $this->_subWord($this->w[$row][$j]); + $temp[$j] = $this->dt0[$dw >> 24 & 0x000000FF] ^ + $this->dt1[$dw >> 16 & 0x000000FF] ^ + $this->dt2[$dw >> 8 & 0x000000FF] ^ + $this->dt3[$dw & 0x000000FF]; + $j++; + } + $this->dw[$row] = $temp; + } + + $col = 0; + $row++; + } + $this->w[$row][$col] = $w[$i]; + } + + $this->dw[$row] = $this->w[$row]; + + // In case of $this->use_inline_crypt === true we have to use 1-dim key arrays (both ascending) + if ($this->use_inline_crypt) { + $this->dw = array_reverse($this->dw); + $w = array_pop($this->w); + $dw = array_pop($this->dw); + foreach ($this->w as $r => $wr) { + foreach ($wr as $c => $wc) { + $w[] = $wc; + $dw[] = $this->dw[$r][$c]; + } + } + $this->w = $w; + $this->dw = $dw; + } + } + + /** + * Performs S-Box substitutions + * + * @access private + * @param Integer $word + */ + function _subWord($word) + { + $sbox = $this->sbox; + + return $sbox[$word & 0x000000FF] | + ($sbox[$word >> 8 & 0x000000FF] << 8) | + ($sbox[$word >> 16 & 0x000000FF] << 16) | + ($sbox[$word >> 24 & 0x000000FF] << 24); + } + + /** + * Setup the performance-optimized function for de/encrypt() + * + * @see Crypt_Base::_setupInlineCrypt() + * @access private + */ + function _setupInlineCrypt() + { + // Note: _setupInlineCrypt() will be called only if $this->changed === true + // So here we are'nt under the same heavy timing-stress as we are in _de/encryptBlock() or de/encrypt(). + // However...the here generated function- $code, stored as php callback in $this->inline_crypt, must work as fast as even possible. + + $lambda_functions =& Crypt_Rijndael::_getLambdaFunctions(); + + // The first 10 generated $lambda_functions will use the key-words hardcoded for better performance. + // For memory reason we limit those ultra-optimized functions. + // After that, we use pure (extracted) integer vars for the key-words which is faster than accessing them via array. + if (count($lambda_functions) < 10) { + $w = $this->w; + $dw = $this->dw; + $init_encrypt = ''; + $init_decrypt = ''; + } else { + for ($i = 0, $cw = count($this->w); $i < $cw; ++$i) { + $w[] = '$w[' . $i . ']'; + $dw[] = '$dw[' . $i . ']'; + } + $init_encrypt = '$w = $self->w;'; + $init_decrypt = '$dw = $self->dw;'; + } + + $code_hash = md5(str_pad("Crypt_Rijndael, {$this->mode}, {$this->block_size}, ", 32, "\0") . implode(',', $w)); + + if (!isset($lambda_functions[$code_hash])) { + $Nr = $this->Nr; + $Nb = $this->Nb; + $c = $this->c; + + // Generating encrypt code: + $init_encrypt.= ' + static $t0, $t1, $t2, $t3, $sbox; + if (!$t0) { + for ($i = 0; $i < 256; ++$i) { + $t0[$i] = (int)$self->t0[$i]; + $t1[$i] = (int)$self->t1[$i]; + $t2[$i] = (int)$self->t2[$i]; + $t3[$i] = (int)$self->t3[$i]; + $sbox[$i] = (int)$self->sbox[$i]; + } + } + '; + + $s = 'e'; + $e = 's'; + $wc = $Nb - 1; + + // Preround: addRoundKey + $encrypt_block = '$in = unpack("N*", $in);'."\n"; + for ($i = 0; $i < $Nb; ++$i) { + $encrypt_block .= '$s'.$i.' = $in['.($i + 1).'] ^ '.$w[++$wc].";\n"; + } + + // Mainrounds: shiftRows + subWord + mixColumns + addRoundKey + for ($round = 1; $round < $Nr; ++$round) { + list($s, $e) = array($e, $s); + for ($i = 0; $i < $Nb; ++$i) { + $encrypt_block.= + '$'.$e.$i.' = + $t0[($'.$s.$i .' >> 24) & 0xff] ^ + $t1[($'.$s.(($i + $c[1]) % $Nb).' >> 16) & 0xff] ^ + $t2[($'.$s.(($i + $c[2]) % $Nb).' >> 8) & 0xff] ^ + $t3[ $'.$s.(($i + $c[3]) % $Nb).' & 0xff] ^ + '.$w[++$wc].";\n"; + } + } + + // Finalround: subWord + shiftRows + addRoundKey + for ($i = 0; $i < $Nb; ++$i) { + $encrypt_block.= + '$'.$e.$i.' = + $sbox[ $'.$e.$i.' & 0xff] | + ($sbox[($'.$e.$i.' >> 8) & 0xff] << 8) | + ($sbox[($'.$e.$i.' >> 16) & 0xff] << 16) | + ($sbox[($'.$e.$i.' >> 24) & 0xff] << 24);'."\n"; + } + $encrypt_block .= '$in = pack("N*"'."\n"; + for ($i = 0; $i < $Nb; ++$i) { + $encrypt_block.= ', + ($'.$e.$i .' & 0xFF000000) ^ + ($'.$e.(($i + $c[1]) % $Nb).' & 0x00FF0000) ^ + ($'.$e.(($i + $c[2]) % $Nb).' & 0x0000FF00) ^ + ($'.$e.(($i + $c[3]) % $Nb).' & 0x000000FF) ^ + '.$w[$i]."\n"; + } + $encrypt_block .= ');'; + + // Generating decrypt code: + $init_decrypt.= ' + static $dt0, $dt1, $dt2, $dt3, $isbox; + if (!$dt0) { + for ($i = 0; $i < 256; ++$i) { + $dt0[$i] = (int)$self->dt0[$i]; + $dt1[$i] = (int)$self->dt1[$i]; + $dt2[$i] = (int)$self->dt2[$i]; + $dt3[$i] = (int)$self->dt3[$i]; + $isbox[$i] = (int)$self->isbox[$i]; + } + } + '; + + $s = 'e'; + $e = 's'; + $wc = $Nb - 1; + + // Preround: addRoundKey + $decrypt_block = '$in = unpack("N*", $in);'."\n"; + for ($i = 0; $i < $Nb; ++$i) { + $decrypt_block .= '$s'.$i.' = $in['.($i + 1).'] ^ '.$dw[++$wc].';'."\n"; + } + + // Mainrounds: shiftRows + subWord + mixColumns + addRoundKey + for ($round = 1; $round < $Nr; ++$round) { + list($s, $e) = array($e, $s); + for ($i = 0; $i < $Nb; ++$i) { + $decrypt_block.= + '$'.$e.$i.' = + $dt0[($'.$s.$i .' >> 24) & 0xff] ^ + $dt1[($'.$s.(($Nb + $i - $c[1]) % $Nb).' >> 16) & 0xff] ^ + $dt2[($'.$s.(($Nb + $i - $c[2]) % $Nb).' >> 8) & 0xff] ^ + $dt3[ $'.$s.(($Nb + $i - $c[3]) % $Nb).' & 0xff] ^ + '.$dw[++$wc].";\n"; + } + } + + // Finalround: subWord + shiftRows + addRoundKey + for ($i = 0; $i < $Nb; ++$i) { + $decrypt_block.= + '$'.$e.$i.' = + $isbox[ $'.$e.$i.' & 0xff] | + ($isbox[($'.$e.$i.' >> 8) & 0xff] << 8) | + ($isbox[($'.$e.$i.' >> 16) & 0xff] << 16) | + ($isbox[($'.$e.$i.' >> 24) & 0xff] << 24);'."\n"; + } + $decrypt_block .= '$in = pack("N*"'."\n"; + for ($i = 0; $i < $Nb; ++$i) { + $decrypt_block.= ', + ($'.$e.$i. ' & 0xFF000000) ^ + ($'.$e.(($Nb + $i - $c[1]) % $Nb).' & 0x00FF0000) ^ + ($'.$e.(($Nb + $i - $c[2]) % $Nb).' & 0x0000FF00) ^ + ($'.$e.(($Nb + $i - $c[3]) % $Nb).' & 0x000000FF) ^ + '.$dw[$i]."\n"; + } + $decrypt_block .= ');'; + + $lambda_functions[$code_hash] = $this->_createInlineCryptFunction( + array( + 'init_crypt' => '', + 'init_encrypt' => $init_encrypt, + 'init_decrypt' => $init_decrypt, + 'encrypt_block' => $encrypt_block, + 'decrypt_block' => $decrypt_block + ) + ); + } + $this->inline_crypt = $lambda_functions[$code_hash]; + } +} + +// vim: ts=4:sw=4:et: +// vim6: fdl=1: diff --git a/inc/phpseclib/LICENSE b/inc/phpseclib/LICENSE new file mode 100644 index 000000000..6ecd9b9be --- /dev/null +++ b/inc/phpseclib/LICENSE @@ -0,0 +1,21 @@ +Copyright 2007-2012 TerraFrost and other contributors +http://phpseclib.sourceforge.net/ + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/inc/phpseclib/Math_BigInteger.php b/inc/phpseclib/Math_BigInteger.php new file mode 100644 index 000000000..a37662da9 --- /dev/null +++ b/inc/phpseclib/Math_BigInteger.php @@ -0,0 +1,3651 @@ +> and << cannot be used, nor can the modulo operator %, + * which only supports integers. Although this fact will slow this library down, the fact that such a high + * base is being used should more than compensate. + * + * When PHP version 6 is officially released, we'll be able to use 64-bit integers. This should, once again, + * allow bitwise operators, and will increase the maximum possible base to 2**31 (or 2**62 for addition / + * subtraction). + * + * Numbers are stored in {@link http://en.wikipedia.org/wiki/Endianness little endian} format. ie. + * (new Math_BigInteger(pow(2, 26)))->value = array(0, 1) + * + * Useful resources are as follows: + * + * - {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf Handbook of Applied Cryptography (HAC)} + * - {@link http://math.libtomcrypt.com/files/tommath.pdf Multi-Precision Math (MPM)} + * - Java's BigInteger classes. See /j2se/src/share/classes/java/math in jdk-1_5_0-src-jrl.zip + * + * Here's an example of how to use this library: + * + * add($b); + * + * echo $c->toString(); // outputs 5 + * ?> + * + * + * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @category Math + * @package Math_BigInteger + * @author Jim Wigginton + * @copyright MMVI Jim Wigginton + * @license http://www.opensource.org/licenses/mit-license.html MIT License + * @link http://pear.php.net/package/Math_BigInteger + */ + +/**#@+ + * Reduction constants + * + * @access private + * @see Math_BigInteger::_reduce() + */ +/** + * @see Math_BigInteger::_montgomery() + * @see Math_BigInteger::_prepMontgomery() + */ +define('MATH_BIGINTEGER_MONTGOMERY', 0); +/** + * @see Math_BigInteger::_barrett() + */ +define('MATH_BIGINTEGER_BARRETT', 1); +/** + * @see Math_BigInteger::_mod2() + */ +define('MATH_BIGINTEGER_POWEROF2', 2); +/** + * @see Math_BigInteger::_remainder() + */ +define('MATH_BIGINTEGER_CLASSIC', 3); +/** + * @see Math_BigInteger::__clone() + */ +define('MATH_BIGINTEGER_NONE', 4); +/**#@-*/ + +/**#@+ + * Array constants + * + * Rather than create a thousands and thousands of new Math_BigInteger objects in repeated function calls to add() and + * multiply() or whatever, we'll just work directly on arrays, taking them in as parameters and returning them. + * + * @access private + */ +/** + * $result[MATH_BIGINTEGER_VALUE] contains the value. + */ +define('MATH_BIGINTEGER_VALUE', 0); +/** + * $result[MATH_BIGINTEGER_SIGN] contains the sign. + */ +define('MATH_BIGINTEGER_SIGN', 1); +/**#@-*/ + +/**#@+ + * @access private + * @see Math_BigInteger::_montgomery() + * @see Math_BigInteger::_barrett() + */ +/** + * Cache constants + * + * $cache[MATH_BIGINTEGER_VARIABLE] tells us whether or not the cached data is still valid. + */ +define('MATH_BIGINTEGER_VARIABLE', 0); +/** + * $cache[MATH_BIGINTEGER_DATA] contains the cached data. + */ +define('MATH_BIGINTEGER_DATA', 1); +/**#@-*/ + +/**#@+ + * Mode constants. + * + * @access private + * @see Math_BigInteger::Math_BigInteger() + */ +/** + * To use the pure-PHP implementation + */ +define('MATH_BIGINTEGER_MODE_INTERNAL', 1); +/** + * To use the BCMath library + * + * (if enabled; otherwise, the internal implementation will be used) + */ +define('MATH_BIGINTEGER_MODE_BCMATH', 2); +/** + * To use the GMP library + * + * (if present; otherwise, either the BCMath or the internal implementation will be used) + */ +define('MATH_BIGINTEGER_MODE_GMP', 3); +/**#@-*/ + +/** + * Karatsuba Cutoff + * + * At what point do we switch between Karatsuba multiplication and schoolbook long multiplication? + * + * @access private + */ +define('MATH_BIGINTEGER_KARATSUBA_CUTOFF', 25); + +/** + * Pure-PHP arbitrary precision integer arithmetic library. Supports base-2, base-10, base-16, and base-256 + * numbers. + * + * @author Jim Wigginton + * @version 1.0.0RC4 + * @access public + * @package Math_BigInteger + */ +class Math_BigInteger { + /** + * Holds the BigInteger's value. + * + * @var Array + * @access private + */ + var $value; + + /** + * Holds the BigInteger's magnitude. + * + * @var Boolean + * @access private + */ + var $is_negative = false; + + /** + * Random number generator function + * + * @see setRandomGenerator() + * @access private + */ + var $generator = 'mt_rand'; + + /** + * Precision + * + * @see setPrecision() + * @access private + */ + var $precision = -1; + + /** + * Precision Bitmask + * + * @see setPrecision() + * @access private + */ + var $bitmask = false; + + /** + * Mode independent value used for serialization. + * + * If the bcmath or gmp extensions are installed $this->value will be a non-serializable resource, hence the need for + * a variable that'll be serializable regardless of whether or not extensions are being used. Unlike $this->value, + * however, $this->hex is only calculated when $this->__sleep() is called. + * + * @see __sleep() + * @see __wakeup() + * @var String + * @access private + */ + var $hex; + + /** + * Converts base-2, base-10, base-16, and binary strings (base-256) to BigIntegers. + * + * If the second parameter - $base - is negative, then it will be assumed that the number's are encoded using + * two's compliment. The sole exception to this is -10, which is treated the same as 10 is. + * + * Here's an example: + * + * <?php + * include('Math/BigInteger.php'); + * + * $a = new Math_BigInteger('0x32', 16); // 50 in base-16 + * + * echo $a->toString(); // outputs 50 + * ?> + * + * + * @param optional $x base-10 number or base-$base number if $base set. + * @param optional integer $base + * @return Math_BigInteger + * @access public + */ + function Math_BigInteger($x = 0, $base = 10) + { + if ( !defined('MATH_BIGINTEGER_MODE') ) { + switch (true) { + case extension_loaded('gmp'): + define('MATH_BIGINTEGER_MODE', MATH_BIGINTEGER_MODE_GMP); + break; + case extension_loaded('bcmath'): + define('MATH_BIGINTEGER_MODE', MATH_BIGINTEGER_MODE_BCMATH); + break; + default: + define('MATH_BIGINTEGER_MODE', MATH_BIGINTEGER_MODE_INTERNAL); + } + } + + if (function_exists('openssl_public_encrypt') && !defined('MATH_BIGINTEGER_OPENSSL_DISABLE') && !defined('MATH_BIGINTEGER_OPENSSL_ENABLED')) { + define('MATH_BIGINTEGER_OPENSSL_ENABLED', true); + } + + if (!defined('PHP_INT_SIZE')) { + define('PHP_INT_SIZE', 4); + } + + if (!defined('MATH_BIGINTEGER_BASE') && MATH_BIGINTEGER_MODE == MATH_BIGINTEGER_MODE_INTERNAL) { + switch (PHP_INT_SIZE) { + case 8: // use 64-bit integers if int size is 8 bytes + define('MATH_BIGINTEGER_BASE', 31); + define('MATH_BIGINTEGER_BASE_FULL', 0x80000000); + define('MATH_BIGINTEGER_MAX_DIGIT', 0x7FFFFFFF); + define('MATH_BIGINTEGER_MSB', 0x40000000); + // 10**9 is the closest we can get to 2**31 without passing it + define('MATH_BIGINTEGER_MAX10', 1000000000); + define('MATH_BIGINTEGER_MAX10_LEN', 9); + // the largest digit that may be used in addition / subtraction + define('MATH_BIGINTEGER_MAX_DIGIT2', pow(2, 62)); + break; + //case 4: // use 64-bit floats if int size is 4 bytes + default: + define('MATH_BIGINTEGER_BASE', 26); + define('MATH_BIGINTEGER_BASE_FULL', 0x4000000); + define('MATH_BIGINTEGER_MAX_DIGIT', 0x3FFFFFF); + define('MATH_BIGINTEGER_MSB', 0x2000000); + // 10**7 is the closest to 2**26 without passing it + define('MATH_BIGINTEGER_MAX10', 10000000); + define('MATH_BIGINTEGER_MAX10_LEN', 7); + // the largest digit that may be used in addition / subtraction + // we do pow(2, 52) instead of using 4503599627370496 directly because some + // PHP installations will truncate 4503599627370496. + define('MATH_BIGINTEGER_MAX_DIGIT2', pow(2, 52)); + } + } + + switch ( MATH_BIGINTEGER_MODE ) { + case MATH_BIGINTEGER_MODE_GMP: + if (is_resource($x) && get_resource_type($x) == 'GMP integer') { + $this->value = $x; + return; + } + $this->value = gmp_init(0); + break; + case MATH_BIGINTEGER_MODE_BCMATH: + $this->value = '0'; + break; + default: + $this->value = array(); + } + + // '0' counts as empty() but when the base is 256 '0' is equal to ord('0') or 48 + // '0' is the only value like this per http://php.net/empty + if (empty($x) && (abs($base) != 256 || $x !== '0')) { + return; + } + + switch ($base) { + case -256: + if (ord($x[0]) & 0x80) { + $x = ~$x; + $this->is_negative = true; + } + case 256: + switch ( MATH_BIGINTEGER_MODE ) { + case MATH_BIGINTEGER_MODE_GMP: + $sign = $this->is_negative ? '-' : ''; + $this->value = gmp_init($sign . '0x' . bin2hex($x)); + break; + case MATH_BIGINTEGER_MODE_BCMATH: + // round $len to the nearest 4 (thanks, DavidMJ!) + $len = (strlen($x) + 3) & 0xFFFFFFFC; + + $x = str_pad($x, $len, chr(0), STR_PAD_LEFT); + + for ($i = 0; $i < $len; $i+= 4) { + $this->value = bcmul($this->value, '4294967296', 0); // 4294967296 == 2**32 + $this->value = bcadd($this->value, 0x1000000 * ord($x[$i]) + ((ord($x[$i + 1]) << 16) | (ord($x[$i + 2]) << 8) | ord($x[$i + 3])), 0); + } + + if ($this->is_negative) { + $this->value = '-' . $this->value; + } + + break; + // converts a base-2**8 (big endian / msb) number to base-2**26 (little endian / lsb) + default: + while (strlen($x)) { + $this->value[] = $this->_bytes2int($this->_base256_rshift($x, MATH_BIGINTEGER_BASE)); + } + } + + if ($this->is_negative) { + if (MATH_BIGINTEGER_MODE != MATH_BIGINTEGER_MODE_INTERNAL) { + $this->is_negative = false; + } + $temp = $this->add(new Math_BigInteger('-1')); + $this->value = $temp->value; + } + break; + case 16: + case -16: + if ($base > 0 && $x[0] == '-') { + $this->is_negative = true; + $x = substr($x, 1); + } + + $x = preg_replace('#^(?:0x)?([A-Fa-f0-9]*).*#', '$1', $x); + + $is_negative = false; + if ($base < 0 && hexdec($x[0]) >= 8) { + $this->is_negative = $is_negative = true; + $x = bin2hex(~pack('H*', $x)); + } + + switch ( MATH_BIGINTEGER_MODE ) { + case MATH_BIGINTEGER_MODE_GMP: + $temp = $this->is_negative ? '-0x' . $x : '0x' . $x; + $this->value = gmp_init($temp); + $this->is_negative = false; + break; + case MATH_BIGINTEGER_MODE_BCMATH: + $x = ( strlen($x) & 1 ) ? '0' . $x : $x; + $temp = new Math_BigInteger(pack('H*', $x), 256); + $this->value = $this->is_negative ? '-' . $temp->value : $temp->value; + $this->is_negative = false; + break; + default: + $x = ( strlen($x) & 1 ) ? '0' . $x : $x; + $temp = new Math_BigInteger(pack('H*', $x), 256); + $this->value = $temp->value; + } + + if ($is_negative) { + $temp = $this->add(new Math_BigInteger('-1')); + $this->value = $temp->value; + } + break; + case 10: + case -10: + // (?value = gmp_init($x); + break; + case MATH_BIGINTEGER_MODE_BCMATH: + // explicitly casting $x to a string is necessary, here, since doing $x[0] on -1 yields different + // results then doing it on '-1' does (modInverse does $x[0]) + $this->value = $x === '-' ? '0' : (string) $x; + break; + default: + $temp = new Math_BigInteger(); + + $multiplier = new Math_BigInteger(); + $multiplier->value = array(MATH_BIGINTEGER_MAX10); + + if ($x[0] == '-') { + $this->is_negative = true; + $x = substr($x, 1); + } + + $x = str_pad($x, strlen($x) + ((MATH_BIGINTEGER_MAX10_LEN - 1) * strlen($x)) % MATH_BIGINTEGER_MAX10_LEN, 0, STR_PAD_LEFT); + + while (strlen($x)) { + $temp = $temp->multiply($multiplier); + $temp = $temp->add(new Math_BigInteger($this->_int2bytes(substr($x, 0, MATH_BIGINTEGER_MAX10_LEN)), 256)); + $x = substr($x, MATH_BIGINTEGER_MAX10_LEN); + } + + $this->value = $temp->value; + } + break; + case 2: // base-2 support originally implemented by Lluis Pamies - thanks! + case -2: + if ($base > 0 && $x[0] == '-') { + $this->is_negative = true; + $x = substr($x, 1); + } + + $x = preg_replace('#^([01]*).*#', '$1', $x); + $x = str_pad($x, strlen($x) + (3 * strlen($x)) % 4, 0, STR_PAD_LEFT); + + $str = '0x'; + while (strlen($x)) { + $part = substr($x, 0, 4); + $str.= dechex(bindec($part)); + $x = substr($x, 4); + } + + if ($this->is_negative) { + $str = '-' . $str; + } + + $temp = new Math_BigInteger($str, 8 * $base); // ie. either -16 or +16 + $this->value = $temp->value; + $this->is_negative = $temp->is_negative; + + break; + default: + // base not supported, so we'll let $this == 0 + } + } + + /** + * Converts a BigInteger to a byte string (eg. base-256). + * + * Negative numbers are saved as positive numbers, unless $twos_compliment is set to true, at which point, they're + * saved as two's compliment. + * + * Here's an example: + * + * toBytes(); // outputs chr(65) + * ?> + * + * + * @param Boolean $twos_compliment + * @return String + * @access public + * @internal Converts a base-2**26 number to base-2**8 + */ + function toBytes($twos_compliment = false) + { + if ($twos_compliment) { + $comparison = $this->compare(new Math_BigInteger()); + if ($comparison == 0) { + return $this->precision > 0 ? str_repeat(chr(0), ($this->precision + 1) >> 3) : ''; + } + + $temp = $comparison < 0 ? $this->add(new Math_BigInteger(1)) : $this->copy(); + $bytes = $temp->toBytes(); + + if (empty($bytes)) { // eg. if the number we're trying to convert is -1 + $bytes = chr(0); + } + + if (ord($bytes[0]) & 0x80) { + $bytes = chr(0) . $bytes; + } + + return $comparison < 0 ? ~$bytes : $bytes; + } + + switch ( MATH_BIGINTEGER_MODE ) { + case MATH_BIGINTEGER_MODE_GMP: + if (gmp_cmp($this->value, gmp_init(0)) == 0) { + return $this->precision > 0 ? str_repeat(chr(0), ($this->precision + 1) >> 3) : ''; + } + + $temp = gmp_strval(gmp_abs($this->value), 16); + $temp = ( strlen($temp) & 1 ) ? '0' . $temp : $temp; + $temp = pack('H*', $temp); + + return $this->precision > 0 ? + substr(str_pad($temp, $this->precision >> 3, chr(0), STR_PAD_LEFT), -($this->precision >> 3)) : + ltrim($temp, chr(0)); + case MATH_BIGINTEGER_MODE_BCMATH: + if ($this->value === '0') { + return $this->precision > 0 ? str_repeat(chr(0), ($this->precision + 1) >> 3) : ''; + } + + $value = ''; + $current = $this->value; + + if ($current[0] == '-') { + $current = substr($current, 1); + } + + while (bccomp($current, '0', 0) > 0) { + $temp = bcmod($current, '16777216'); + $value = chr($temp >> 16) . chr($temp >> 8) . chr($temp) . $value; + $current = bcdiv($current, '16777216', 0); + } + + return $this->precision > 0 ? + substr(str_pad($value, $this->precision >> 3, chr(0), STR_PAD_LEFT), -($this->precision >> 3)) : + ltrim($value, chr(0)); + } + + if (!count($this->value)) { + return $this->precision > 0 ? str_repeat(chr(0), ($this->precision + 1) >> 3) : ''; + } + $result = $this->_int2bytes($this->value[count($this->value) - 1]); + + $temp = $this->copy(); + + for ($i = count($temp->value) - 2; $i >= 0; --$i) { + $temp->_base256_lshift($result, MATH_BIGINTEGER_BASE); + $result = $result | str_pad($temp->_int2bytes($temp->value[$i]), strlen($result), chr(0), STR_PAD_LEFT); + } + + return $this->precision > 0 ? + str_pad(substr($result, -(($this->precision + 7) >> 3)), ($this->precision + 7) >> 3, chr(0), STR_PAD_LEFT) : + $result; + } + + /** + * Converts a BigInteger to a hex string (eg. base-16)). + * + * Negative numbers are saved as positive numbers, unless $twos_compliment is set to true, at which point, they're + * saved as two's compliment. + * + * Here's an example: + * + * toHex(); // outputs '41' + * ?> + * + * + * @param Boolean $twos_compliment + * @return String + * @access public + * @internal Converts a base-2**26 number to base-2**8 + */ + function toHex($twos_compliment = false) + { + return bin2hex($this->toBytes($twos_compliment)); + } + + /** + * Converts a BigInteger to a bit string (eg. base-2). + * + * Negative numbers are saved as positive numbers, unless $twos_compliment is set to true, at which point, they're + * saved as two's compliment. + * + * Here's an example: + * + * toBits(); // outputs '1000001' + * ?> + * + * + * @param Boolean $twos_compliment + * @return String + * @access public + * @internal Converts a base-2**26 number to base-2**2 + */ + function toBits($twos_compliment = false) + { + $hex = $this->toHex($twos_compliment); + $bits = ''; + for ($i = strlen($hex) - 8, $start = strlen($hex) & 7; $i >= $start; $i-=8) { + $bits = str_pad(decbin(hexdec(substr($hex, $i, 8))), 32, '0', STR_PAD_LEFT) . $bits; + } + if ($start) { // hexdec('') == 0 + $bits = str_pad(decbin(hexdec(substr($hex, 0, $start))), 8, '0', STR_PAD_LEFT) . $bits; + } + $result = $this->precision > 0 ? substr($bits, -$this->precision) : ltrim($bits, '0'); + + if ($twos_compliment && $this->compare(new Math_BigInteger()) > 0 && $this->precision <= 0) { + return '0' . $result; + } + + return $result; + } + + /** + * Converts a BigInteger to a base-10 number. + * + * Here's an example: + * + * toString(); // outputs 50 + * ?> + * + * + * @return String + * @access public + * @internal Converts a base-2**26 number to base-10**7 (which is pretty much base-10) + */ + function toString() + { + switch ( MATH_BIGINTEGER_MODE ) { + case MATH_BIGINTEGER_MODE_GMP: + return gmp_strval($this->value); + case MATH_BIGINTEGER_MODE_BCMATH: + if ($this->value === '0') { + return '0'; + } + + return ltrim($this->value, '0'); + } + + if (!count($this->value)) { + return '0'; + } + + $temp = $this->copy(); + $temp->is_negative = false; + + $divisor = new Math_BigInteger(); + $divisor->value = array(MATH_BIGINTEGER_MAX10); + $result = ''; + while (count($temp->value)) { + list($temp, $mod) = $temp->divide($divisor); + $result = str_pad(isset($mod->value[0]) ? $mod->value[0] : '', MATH_BIGINTEGER_MAX10_LEN, '0', STR_PAD_LEFT) . $result; + } + $result = ltrim($result, '0'); + if (empty($result)) { + $result = '0'; + } + + if ($this->is_negative) { + $result = '-' . $result; + } + + return $result; + } + + /** + * Copy an object + * + * PHP5 passes objects by reference while PHP4 passes by value. As such, we need a function to guarantee + * that all objects are passed by value, when appropriate. More information can be found here: + * + * {@link http://php.net/language.oop5.basic#51624} + * + * @access public + * @see __clone() + * @return Math_BigInteger + */ + function copy() + { + $temp = new Math_BigInteger(); + $temp->value = $this->value; + $temp->is_negative = $this->is_negative; + $temp->generator = $this->generator; + $temp->precision = $this->precision; + $temp->bitmask = $this->bitmask; + return $temp; + } + + /** + * __toString() magic method + * + * Will be called, automatically, if you're supporting just PHP5. If you're supporting PHP4, you'll need to call + * toString(). + * + * @access public + * @internal Implemented per a suggestion by Techie-Michael - thanks! + */ + function __toString() + { + return $this->toString(); + } + + /** + * __clone() magic method + * + * Although you can call Math_BigInteger::__toString() directly in PHP5, you cannot call Math_BigInteger::__clone() + * directly in PHP5. You can in PHP4 since it's not a magic method, but in PHP5, you have to call it by using the PHP5 + * only syntax of $y = clone $x. As such, if you're trying to write an application that works on both PHP4 and PHP5, + * call Math_BigInteger::copy(), instead. + * + * @access public + * @see copy() + * @return Math_BigInteger + */ + function __clone() + { + return $this->copy(); + } + + /** + * __sleep() magic method + * + * Will be called, automatically, when serialize() is called on a Math_BigInteger object. + * + * @see __wakeup() + * @access public + */ + function __sleep() + { + $this->hex = $this->toHex(true); + $vars = array('hex'); + if ($this->generator != 'mt_rand') { + $vars[] = 'generator'; + } + if ($this->precision > 0) { + $vars[] = 'precision'; + } + return $vars; + + } + + /** + * __wakeup() magic method + * + * Will be called, automatically, when unserialize() is called on a Math_BigInteger object. + * + * @see __sleep() + * @access public + */ + function __wakeup() + { + $temp = new Math_BigInteger($this->hex, -16); + $this->value = $temp->value; + $this->is_negative = $temp->is_negative; + $this->setRandomGenerator($this->generator); + if ($this->precision > 0) { + // recalculate $this->bitmask + $this->setPrecision($this->precision); + } + } + + /** + * Adds two BigIntegers. + * + * Here's an example: + * + * add($b); + * + * echo $c->toString(); // outputs 30 + * ?> + * + * + * @param Math_BigInteger $y + * @return Math_BigInteger + * @access public + * @internal Performs base-2**52 addition + */ + function add($y) + { + switch ( MATH_BIGINTEGER_MODE ) { + case MATH_BIGINTEGER_MODE_GMP: + $temp = new Math_BigInteger(); + $temp->value = gmp_add($this->value, $y->value); + + return $this->_normalize($temp); + case MATH_BIGINTEGER_MODE_BCMATH: + $temp = new Math_BigInteger(); + $temp->value = bcadd($this->value, $y->value, 0); + + return $this->_normalize($temp); + } + + $temp = $this->_add($this->value, $this->is_negative, $y->value, $y->is_negative); + + $result = new Math_BigInteger(); + $result->value = $temp[MATH_BIGINTEGER_VALUE]; + $result->is_negative = $temp[MATH_BIGINTEGER_SIGN]; + + return $this->_normalize($result); + } + + /** + * Performs addition. + * + * @param Array $x_value + * @param Boolean $x_negative + * @param Array $y_value + * @param Boolean $y_negative + * @return Array + * @access private + */ + function _add($x_value, $x_negative, $y_value, $y_negative) + { + $x_size = count($x_value); + $y_size = count($y_value); + + if ($x_size == 0) { + return array( + MATH_BIGINTEGER_VALUE => $y_value, + MATH_BIGINTEGER_SIGN => $y_negative + ); + } else if ($y_size == 0) { + return array( + MATH_BIGINTEGER_VALUE => $x_value, + MATH_BIGINTEGER_SIGN => $x_negative + ); + } + + // subtract, if appropriate + if ( $x_negative != $y_negative ) { + if ( $x_value == $y_value ) { + return array( + MATH_BIGINTEGER_VALUE => array(), + MATH_BIGINTEGER_SIGN => false + ); + } + + $temp = $this->_subtract($x_value, false, $y_value, false); + $temp[MATH_BIGINTEGER_SIGN] = $this->_compare($x_value, false, $y_value, false) > 0 ? + $x_negative : $y_negative; + + return $temp; + } + + if ($x_size < $y_size) { + $size = $x_size; + $value = $y_value; + } else { + $size = $y_size; + $value = $x_value; + } + + $value[] = 0; // just in case the carry adds an extra digit + + $carry = 0; + for ($i = 0, $j = 1; $j < $size; $i+=2, $j+=2) { + $sum = $x_value[$j] * MATH_BIGINTEGER_BASE_FULL + $x_value[$i] + $y_value[$j] * MATH_BIGINTEGER_BASE_FULL + $y_value[$i] + $carry; + $carry = $sum >= MATH_BIGINTEGER_MAX_DIGIT2; // eg. floor($sum / 2**52); only possible values (in any base) are 0 and 1 + $sum = $carry ? $sum - MATH_BIGINTEGER_MAX_DIGIT2 : $sum; + + $temp = (int) ($sum / MATH_BIGINTEGER_BASE_FULL); + + $value[$i] = (int) ($sum - MATH_BIGINTEGER_BASE_FULL * $temp); // eg. a faster alternative to fmod($sum, 0x4000000) + $value[$j] = $temp; + } + + if ($j == $size) { // ie. if $y_size is odd + $sum = $x_value[$i] + $y_value[$i] + $carry; + $carry = $sum >= MATH_BIGINTEGER_BASE_FULL; + $value[$i] = $carry ? $sum - MATH_BIGINTEGER_BASE_FULL : $sum; + ++$i; // ie. let $i = $j since we've just done $value[$i] + } + + if ($carry) { + for (; $value[$i] == MATH_BIGINTEGER_MAX_DIGIT; ++$i) { + $value[$i] = 0; + } + ++$value[$i]; + } + + return array( + MATH_BIGINTEGER_VALUE => $this->_trim($value), + MATH_BIGINTEGER_SIGN => $x_negative + ); + } + + /** + * Subtracts two BigIntegers. + * + * Here's an example: + * + * subtract($b); + * + * echo $c->toString(); // outputs -10 + * ?> + * + * + * @param Math_BigInteger $y + * @return Math_BigInteger + * @access public + * @internal Performs base-2**52 subtraction + */ + function subtract($y) + { + switch ( MATH_BIGINTEGER_MODE ) { + case MATH_BIGINTEGER_MODE_GMP: + $temp = new Math_BigInteger(); + $temp->value = gmp_sub($this->value, $y->value); + + return $this->_normalize($temp); + case MATH_BIGINTEGER_MODE_BCMATH: + $temp = new Math_BigInteger(); + $temp->value = bcsub($this->value, $y->value, 0); + + return $this->_normalize($temp); + } + + $temp = $this->_subtract($this->value, $this->is_negative, $y->value, $y->is_negative); + + $result = new Math_BigInteger(); + $result->value = $temp[MATH_BIGINTEGER_VALUE]; + $result->is_negative = $temp[MATH_BIGINTEGER_SIGN]; + + return $this->_normalize($result); + } + + /** + * Performs subtraction. + * + * @param Array $x_value + * @param Boolean $x_negative + * @param Array $y_value + * @param Boolean $y_negative + * @return Array + * @access private + */ + function _subtract($x_value, $x_negative, $y_value, $y_negative) + { + $x_size = count($x_value); + $y_size = count($y_value); + + if ($x_size == 0) { + return array( + MATH_BIGINTEGER_VALUE => $y_value, + MATH_BIGINTEGER_SIGN => !$y_negative + ); + } else if ($y_size == 0) { + return array( + MATH_BIGINTEGER_VALUE => $x_value, + MATH_BIGINTEGER_SIGN => $x_negative + ); + } + + // add, if appropriate (ie. -$x - +$y or +$x - -$y) + if ( $x_negative != $y_negative ) { + $temp = $this->_add($x_value, false, $y_value, false); + $temp[MATH_BIGINTEGER_SIGN] = $x_negative; + + return $temp; + } + + $diff = $this->_compare($x_value, $x_negative, $y_value, $y_negative); + + if ( !$diff ) { + return array( + MATH_BIGINTEGER_VALUE => array(), + MATH_BIGINTEGER_SIGN => false + ); + } + + // switch $x and $y around, if appropriate. + if ( (!$x_negative && $diff < 0) || ($x_negative && $diff > 0) ) { + $temp = $x_value; + $x_value = $y_value; + $y_value = $temp; + + $x_negative = !$x_negative; + + $x_size = count($x_value); + $y_size = count($y_value); + } + + // at this point, $x_value should be at least as big as - if not bigger than - $y_value + + $carry = 0; + for ($i = 0, $j = 1; $j < $y_size; $i+=2, $j+=2) { + $sum = $x_value[$j] * MATH_BIGINTEGER_BASE_FULL + $x_value[$i] - $y_value[$j] * MATH_BIGINTEGER_BASE_FULL - $y_value[$i] - $carry; + $carry = $sum < 0; // eg. floor($sum / 2**52); only possible values (in any base) are 0 and 1 + $sum = $carry ? $sum + MATH_BIGINTEGER_MAX_DIGIT2 : $sum; + + $temp = (int) ($sum / MATH_BIGINTEGER_BASE_FULL); + + $x_value[$i] = (int) ($sum - MATH_BIGINTEGER_BASE_FULL * $temp); + $x_value[$j] = $temp; + } + + if ($j == $y_size) { // ie. if $y_size is odd + $sum = $x_value[$i] - $y_value[$i] - $carry; + $carry = $sum < 0; + $x_value[$i] = $carry ? $sum + MATH_BIGINTEGER_BASE_FULL : $sum; + ++$i; + } + + if ($carry) { + for (; !$x_value[$i]; ++$i) { + $x_value[$i] = MATH_BIGINTEGER_MAX_DIGIT; + } + --$x_value[$i]; + } + + return array( + MATH_BIGINTEGER_VALUE => $this->_trim($x_value), + MATH_BIGINTEGER_SIGN => $x_negative + ); + } + + /** + * Multiplies two BigIntegers + * + * Here's an example: + * + * multiply($b); + * + * echo $c->toString(); // outputs 200 + * ?> + * + * + * @param Math_BigInteger $x + * @return Math_BigInteger + * @access public + */ + function multiply($x) + { + switch ( MATH_BIGINTEGER_MODE ) { + case MATH_BIGINTEGER_MODE_GMP: + $temp = new Math_BigInteger(); + $temp->value = gmp_mul($this->value, $x->value); + + return $this->_normalize($temp); + case MATH_BIGINTEGER_MODE_BCMATH: + $temp = new Math_BigInteger(); + $temp->value = bcmul($this->value, $x->value, 0); + + return $this->_normalize($temp); + } + + $temp = $this->_multiply($this->value, $this->is_negative, $x->value, $x->is_negative); + + $product = new Math_BigInteger(); + $product->value = $temp[MATH_BIGINTEGER_VALUE]; + $product->is_negative = $temp[MATH_BIGINTEGER_SIGN]; + + return $this->_normalize($product); + } + + /** + * Performs multiplication. + * + * @param Array $x_value + * @param Boolean $x_negative + * @param Array $y_value + * @param Boolean $y_negative + * @return Array + * @access private + */ + function _multiply($x_value, $x_negative, $y_value, $y_negative) + { + //if ( $x_value == $y_value ) { + // return array( + // MATH_BIGINTEGER_VALUE => $this->_square($x_value), + // MATH_BIGINTEGER_SIGN => $x_sign != $y_value + // ); + //} + + $x_length = count($x_value); + $y_length = count($y_value); + + if ( !$x_length || !$y_length ) { // a 0 is being multiplied + return array( + MATH_BIGINTEGER_VALUE => array(), + MATH_BIGINTEGER_SIGN => false + ); + } + + return array( + MATH_BIGINTEGER_VALUE => min($x_length, $y_length) < 2 * MATH_BIGINTEGER_KARATSUBA_CUTOFF ? + $this->_trim($this->_regularMultiply($x_value, $y_value)) : + $this->_trim($this->_karatsuba($x_value, $y_value)), + MATH_BIGINTEGER_SIGN => $x_negative != $y_negative + ); + } + + /** + * Performs long multiplication on two BigIntegers + * + * Modeled after 'multiply' in MutableBigInteger.java. + * + * @param Array $x_value + * @param Array $y_value + * @return Array + * @access private + */ + function _regularMultiply($x_value, $y_value) + { + $x_length = count($x_value); + $y_length = count($y_value); + + if ( !$x_length || !$y_length ) { // a 0 is being multiplied + return array(); + } + + if ( $x_length < $y_length ) { + $temp = $x_value; + $x_value = $y_value; + $y_value = $temp; + + $x_length = count($x_value); + $y_length = count($y_value); + } + + $product_value = $this->_array_repeat(0, $x_length + $y_length); + + // the following for loop could be removed if the for loop following it + // (the one with nested for loops) initially set $i to 0, but + // doing so would also make the result in one set of unnecessary adds, + // since on the outermost loops first pass, $product->value[$k] is going + // to always be 0 + + $carry = 0; + + for ($j = 0; $j < $x_length; ++$j) { // ie. $i = 0 + $temp = $x_value[$j] * $y_value[0] + $carry; // $product_value[$k] == 0 + $carry = (int) ($temp / MATH_BIGINTEGER_BASE_FULL); + $product_value[$j] = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * $carry); + } + + $product_value[$j] = $carry; + + // the above for loop is what the previous comment was talking about. the + // following for loop is the "one with nested for loops" + for ($i = 1; $i < $y_length; ++$i) { + $carry = 0; + + for ($j = 0, $k = $i; $j < $x_length; ++$j, ++$k) { + $temp = $product_value[$k] + $x_value[$j] * $y_value[$i] + $carry; + $carry = (int) ($temp / MATH_BIGINTEGER_BASE_FULL); + $product_value[$k] = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * $carry); + } + + $product_value[$k] = $carry; + } + + return $product_value; + } + + /** + * Performs Karatsuba multiplication on two BigIntegers + * + * See {@link http://en.wikipedia.org/wiki/Karatsuba_algorithm Karatsuba algorithm} and + * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=120 MPM 5.2.3}. + * + * @param Array $x_value + * @param Array $y_value + * @return Array + * @access private + */ + function _karatsuba($x_value, $y_value) + { + $m = min(count($x_value) >> 1, count($y_value) >> 1); + + if ($m < MATH_BIGINTEGER_KARATSUBA_CUTOFF) { + return $this->_regularMultiply($x_value, $y_value); + } + + $x1 = array_slice($x_value, $m); + $x0 = array_slice($x_value, 0, $m); + $y1 = array_slice($y_value, $m); + $y0 = array_slice($y_value, 0, $m); + + $z2 = $this->_karatsuba($x1, $y1); + $z0 = $this->_karatsuba($x0, $y0); + + $z1 = $this->_add($x1, false, $x0, false); + $temp = $this->_add($y1, false, $y0, false); + $z1 = $this->_karatsuba($z1[MATH_BIGINTEGER_VALUE], $temp[MATH_BIGINTEGER_VALUE]); + $temp = $this->_add($z2, false, $z0, false); + $z1 = $this->_subtract($z1, false, $temp[MATH_BIGINTEGER_VALUE], false); + + $z2 = array_merge(array_fill(0, 2 * $m, 0), $z2); + $z1[MATH_BIGINTEGER_VALUE] = array_merge(array_fill(0, $m, 0), $z1[MATH_BIGINTEGER_VALUE]); + + $xy = $this->_add($z2, false, $z1[MATH_BIGINTEGER_VALUE], $z1[MATH_BIGINTEGER_SIGN]); + $xy = $this->_add($xy[MATH_BIGINTEGER_VALUE], $xy[MATH_BIGINTEGER_SIGN], $z0, false); + + return $xy[MATH_BIGINTEGER_VALUE]; + } + + /** + * Performs squaring + * + * @param Array $x + * @return Array + * @access private + */ + function _square($x = false) + { + return count($x) < 2 * MATH_BIGINTEGER_KARATSUBA_CUTOFF ? + $this->_trim($this->_baseSquare($x)) : + $this->_trim($this->_karatsubaSquare($x)); + } + + /** + * Performs traditional squaring on two BigIntegers + * + * Squaring can be done faster than multiplying a number by itself can be. See + * {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=7 HAC 14.2.4} / + * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=141 MPM 5.3} for more information. + * + * @param Array $value + * @return Array + * @access private + */ + function _baseSquare($value) + { + if ( empty($value) ) { + return array(); + } + $square_value = $this->_array_repeat(0, 2 * count($value)); + + for ($i = 0, $max_index = count($value) - 1; $i <= $max_index; ++$i) { + $i2 = $i << 1; + + $temp = $square_value[$i2] + $value[$i] * $value[$i]; + $carry = (int) ($temp / MATH_BIGINTEGER_BASE_FULL); + $square_value[$i2] = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * $carry); + + // note how we start from $i+1 instead of 0 as we do in multiplication. + for ($j = $i + 1, $k = $i2 + 1; $j <= $max_index; ++$j, ++$k) { + $temp = $square_value[$k] + 2 * $value[$j] * $value[$i] + $carry; + $carry = (int) ($temp / MATH_BIGINTEGER_BASE_FULL); + $square_value[$k] = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * $carry); + } + + // the following line can yield values larger 2**15. at this point, PHP should switch + // over to floats. + $square_value[$i + $max_index + 1] = $carry; + } + + return $square_value; + } + + /** + * Performs Karatsuba "squaring" on two BigIntegers + * + * See {@link http://en.wikipedia.org/wiki/Karatsuba_algorithm Karatsuba algorithm} and + * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=151 MPM 5.3.4}. + * + * @param Array $value + * @return Array + * @access private + */ + function _karatsubaSquare($value) + { + $m = count($value) >> 1; + + if ($m < MATH_BIGINTEGER_KARATSUBA_CUTOFF) { + return $this->_baseSquare($value); + } + + $x1 = array_slice($value, $m); + $x0 = array_slice($value, 0, $m); + + $z2 = $this->_karatsubaSquare($x1); + $z0 = $this->_karatsubaSquare($x0); + + $z1 = $this->_add($x1, false, $x0, false); + $z1 = $this->_karatsubaSquare($z1[MATH_BIGINTEGER_VALUE]); + $temp = $this->_add($z2, false, $z0, false); + $z1 = $this->_subtract($z1, false, $temp[MATH_BIGINTEGER_VALUE], false); + + $z2 = array_merge(array_fill(0, 2 * $m, 0), $z2); + $z1[MATH_BIGINTEGER_VALUE] = array_merge(array_fill(0, $m, 0), $z1[MATH_BIGINTEGER_VALUE]); + + $xx = $this->_add($z2, false, $z1[MATH_BIGINTEGER_VALUE], $z1[MATH_BIGINTEGER_SIGN]); + $xx = $this->_add($xx[MATH_BIGINTEGER_VALUE], $xx[MATH_BIGINTEGER_SIGN], $z0, false); + + return $xx[MATH_BIGINTEGER_VALUE]; + } + + /** + * Divides two BigIntegers. + * + * Returns an array whose first element contains the quotient and whose second element contains the + * "common residue". If the remainder would be positive, the "common residue" and the remainder are the + * same. If the remainder would be negative, the "common residue" is equal to the sum of the remainder + * and the divisor (basically, the "common residue" is the first positive modulo). + * + * Here's an example: + * + * divide($b); + * + * echo $quotient->toString(); // outputs 0 + * echo "\r\n"; + * echo $remainder->toString(); // outputs 10 + * ?> + * + * + * @param Math_BigInteger $y + * @return Array + * @access public + * @internal This function is based off of {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=9 HAC 14.20}. + */ + function divide($y) + { + switch ( MATH_BIGINTEGER_MODE ) { + case MATH_BIGINTEGER_MODE_GMP: + $quotient = new Math_BigInteger(); + $remainder = new Math_BigInteger(); + + list($quotient->value, $remainder->value) = gmp_div_qr($this->value, $y->value); + + if (gmp_sign($remainder->value) < 0) { + $remainder->value = gmp_add($remainder->value, gmp_abs($y->value)); + } + + return array($this->_normalize($quotient), $this->_normalize($remainder)); + case MATH_BIGINTEGER_MODE_BCMATH: + $quotient = new Math_BigInteger(); + $remainder = new Math_BigInteger(); + + $quotient->value = bcdiv($this->value, $y->value, 0); + $remainder->value = bcmod($this->value, $y->value); + + if ($remainder->value[0] == '-') { + $remainder->value = bcadd($remainder->value, $y->value[0] == '-' ? substr($y->value, 1) : $y->value, 0); + } + + return array($this->_normalize($quotient), $this->_normalize($remainder)); + } + + if (count($y->value) == 1) { + list($q, $r) = $this->_divide_digit($this->value, $y->value[0]); + $quotient = new Math_BigInteger(); + $remainder = new Math_BigInteger(); + $quotient->value = $q; + $remainder->value = array($r); + $quotient->is_negative = $this->is_negative != $y->is_negative; + return array($this->_normalize($quotient), $this->_normalize($remainder)); + } + + static $zero; + if ( !isset($zero) ) { + $zero = new Math_BigInteger(); + } + + $x = $this->copy(); + $y = $y->copy(); + + $x_sign = $x->is_negative; + $y_sign = $y->is_negative; + + $x->is_negative = $y->is_negative = false; + + $diff = $x->compare($y); + + if ( !$diff ) { + $temp = new Math_BigInteger(); + $temp->value = array(1); + $temp->is_negative = $x_sign != $y_sign; + return array($this->_normalize($temp), $this->_normalize(new Math_BigInteger())); + } + + if ( $diff < 0 ) { + // if $x is negative, "add" $y. + if ( $x_sign ) { + $x = $y->subtract($x); + } + return array($this->_normalize(new Math_BigInteger()), $this->_normalize($x)); + } + + // normalize $x and $y as described in HAC 14.23 / 14.24 + $msb = $y->value[count($y->value) - 1]; + for ($shift = 0; !($msb & MATH_BIGINTEGER_MSB); ++$shift) { + $msb <<= 1; + } + $x->_lshift($shift); + $y->_lshift($shift); + $y_value = &$y->value; + + $x_max = count($x->value) - 1; + $y_max = count($y->value) - 1; + + $quotient = new Math_BigInteger(); + $quotient_value = &$quotient->value; + $quotient_value = $this->_array_repeat(0, $x_max - $y_max + 1); + + static $temp, $lhs, $rhs; + if (!isset($temp)) { + $temp = new Math_BigInteger(); + $lhs = new Math_BigInteger(); + $rhs = new Math_BigInteger(); + } + $temp_value = &$temp->value; + $rhs_value = &$rhs->value; + + // $temp = $y << ($x_max - $y_max-1) in base 2**26 + $temp_value = array_merge($this->_array_repeat(0, $x_max - $y_max), $y_value); + + while ( $x->compare($temp) >= 0 ) { + // calculate the "common residue" + ++$quotient_value[$x_max - $y_max]; + $x = $x->subtract($temp); + $x_max = count($x->value) - 1; + } + + for ($i = $x_max; $i >= $y_max + 1; --$i) { + $x_value = &$x->value; + $x_window = array( + isset($x_value[$i]) ? $x_value[$i] : 0, + isset($x_value[$i - 1]) ? $x_value[$i - 1] : 0, + isset($x_value[$i - 2]) ? $x_value[$i - 2] : 0 + ); + $y_window = array( + $y_value[$y_max], + ( $y_max > 0 ) ? $y_value[$y_max - 1] : 0 + ); + + $q_index = $i - $y_max - 1; + if ($x_window[0] == $y_window[0]) { + $quotient_value[$q_index] = MATH_BIGINTEGER_MAX_DIGIT; + } else { + $quotient_value[$q_index] = (int) ( + ($x_window[0] * MATH_BIGINTEGER_BASE_FULL + $x_window[1]) + / + $y_window[0] + ); + } + + $temp_value = array($y_window[1], $y_window[0]); + + $lhs->value = array($quotient_value[$q_index]); + $lhs = $lhs->multiply($temp); + + $rhs_value = array($x_window[2], $x_window[1], $x_window[0]); + + while ( $lhs->compare($rhs) > 0 ) { + --$quotient_value[$q_index]; + + $lhs->value = array($quotient_value[$q_index]); + $lhs = $lhs->multiply($temp); + } + + $adjust = $this->_array_repeat(0, $q_index); + $temp_value = array($quotient_value[$q_index]); + $temp = $temp->multiply($y); + $temp_value = &$temp->value; + $temp_value = array_merge($adjust, $temp_value); + + $x = $x->subtract($temp); + + if ($x->compare($zero) < 0) { + $temp_value = array_merge($adjust, $y_value); + $x = $x->add($temp); + + --$quotient_value[$q_index]; + } + + $x_max = count($x_value) - 1; + } + + // unnormalize the remainder + $x->_rshift($shift); + + $quotient->is_negative = $x_sign != $y_sign; + + // calculate the "common residue", if appropriate + if ( $x_sign ) { + $y->_rshift($shift); + $x = $y->subtract($x); + } + + return array($this->_normalize($quotient), $this->_normalize($x)); + } + + /** + * Divides a BigInteger by a regular integer + * + * abc / x = a00 / x + b0 / x + c / x + * + * @param Array $dividend + * @param Array $divisor + * @return Array + * @access private + */ + function _divide_digit($dividend, $divisor) + { + $carry = 0; + $result = array(); + + for ($i = count($dividend) - 1; $i >= 0; --$i) { + $temp = MATH_BIGINTEGER_BASE_FULL * $carry + $dividend[$i]; + $result[$i] = (int) ($temp / $divisor); + $carry = (int) ($temp - $divisor * $result[$i]); + } + + return array($result, $carry); + } + + /** + * Performs modular exponentiation. + * + * Here's an example: + * + * modPow($b, $c); + * + * echo $c->toString(); // outputs 10 + * ?> + * + * + * @param Math_BigInteger $e + * @param Math_BigInteger $n + * @return Math_BigInteger + * @access public + * @internal The most naive approach to modular exponentiation has very unreasonable requirements, and + * and although the approach involving repeated squaring does vastly better, it, too, is impractical + * for our purposes. The reason being that division - by far the most complicated and time-consuming + * of the basic operations (eg. +,-,*,/) - occurs multiple times within it. + * + * Modular reductions resolve this issue. Although an individual modular reduction takes more time + * then an individual division, when performed in succession (with the same modulo), they're a lot faster. + * + * The two most commonly used modular reductions are Barrett and Montgomery reduction. Montgomery reduction, + * although faster, only works when the gcd of the modulo and of the base being used is 1. In RSA, when the + * base is a power of two, the modulo - a product of two primes - is always going to have a gcd of 1 (because + * the product of two odd numbers is odd), but what about when RSA isn't used? + * + * In contrast, Barrett reduction has no such constraint. As such, some bigint implementations perform a + * Barrett reduction after every operation in the modpow function. Others perform Barrett reductions when the + * modulo is even and Montgomery reductions when the modulo is odd. BigInteger.java's modPow method, however, + * uses a trick involving the Chinese Remainder Theorem to factor the even modulo into two numbers - one odd and + * the other, a power of two - and recombine them, later. This is the method that this modPow function uses. + * {@link http://islab.oregonstate.edu/papers/j34monex.pdf Montgomery Reduction with Even Modulus} elaborates. + */ + function modPow($e, $n) + { + $n = $this->bitmask !== false && $this->bitmask->compare($n) < 0 ? $this->bitmask : $n->abs(); + + if ($e->compare(new Math_BigInteger()) < 0) { + $e = $e->abs(); + + $temp = $this->modInverse($n); + if ($temp === false) { + return false; + } + + return $this->_normalize($temp->modPow($e, $n)); + } + + if ( MATH_BIGINTEGER_MODE == MATH_BIGINTEGER_MODE_GMP ) { + $temp = new Math_BigInteger(); + $temp->value = gmp_powm($this->value, $e->value, $n->value); + + return $this->_normalize($temp); + } + + if ($this->compare(new Math_BigInteger()) < 0 || $this->compare($n) > 0) { + list(, $temp) = $this->divide($n); + return $temp->modPow($e, $n); + } + + if (defined('MATH_BIGINTEGER_OPENSSL_ENABLED')) { + $components = array( + 'modulus' => $n->toBytes(true), + 'publicExponent' => $e->toBytes(true) + ); + + $components = array( + 'modulus' => pack('Ca*a*', 2, $this->_encodeASN1Length(strlen($components['modulus'])), $components['modulus']), + 'publicExponent' => pack('Ca*a*', 2, $this->_encodeASN1Length(strlen($components['publicExponent'])), $components['publicExponent']) + ); + + $RSAPublicKey = pack('Ca*a*a*', + 48, $this->_encodeASN1Length(strlen($components['modulus']) + strlen($components['publicExponent'])), + $components['modulus'], $components['publicExponent'] + ); + + $rsaOID = pack('H*', '300d06092a864886f70d0101010500'); // hex version of MA0GCSqGSIb3DQEBAQUA + $RSAPublicKey = chr(0) . $RSAPublicKey; + $RSAPublicKey = chr(3) . $this->_encodeASN1Length(strlen($RSAPublicKey)) . $RSAPublicKey; + + $encapsulated = pack('Ca*a*', + 48, $this->_encodeASN1Length(strlen($rsaOID . $RSAPublicKey)), $rsaOID . $RSAPublicKey + ); + + $RSAPublicKey = "-----BEGIN PUBLIC KEY-----\r\n" . + chunk_split(base64_encode($encapsulated)) . + '-----END PUBLIC KEY-----'; + + $plaintext = str_pad($this->toBytes(), strlen($n->toBytes(true)) - 1, "\0", STR_PAD_LEFT); + + if (openssl_public_encrypt($plaintext, $result, $RSAPublicKey, OPENSSL_NO_PADDING)) { + return new Math_BigInteger($result, 256); + } + } + + if ( MATH_BIGINTEGER_MODE == MATH_BIGINTEGER_MODE_BCMATH ) { + $temp = new Math_BigInteger(); + $temp->value = bcpowmod($this->value, $e->value, $n->value, 0); + + return $this->_normalize($temp); + } + + if ( empty($e->value) ) { + $temp = new Math_BigInteger(); + $temp->value = array(1); + return $this->_normalize($temp); + } + + if ( $e->value == array(1) ) { + list(, $temp) = $this->divide($n); + return $this->_normalize($temp); + } + + if ( $e->value == array(2) ) { + $temp = new Math_BigInteger(); + $temp->value = $this->_square($this->value); + list(, $temp) = $temp->divide($n); + return $this->_normalize($temp); + } + + return $this->_normalize($this->_slidingWindow($e, $n, MATH_BIGINTEGER_BARRETT)); + + // is the modulo odd? + if ( $n->value[0] & 1 ) { + return $this->_normalize($this->_slidingWindow($e, $n, MATH_BIGINTEGER_MONTGOMERY)); + } + // if it's not, it's even + + // find the lowest set bit (eg. the max pow of 2 that divides $n) + for ($i = 0; $i < count($n->value); ++$i) { + if ( $n->value[$i] ) { + $temp = decbin($n->value[$i]); + $j = strlen($temp) - strrpos($temp, '1') - 1; + $j+= 26 * $i; + break; + } + } + // at this point, 2^$j * $n/(2^$j) == $n + + $mod1 = $n->copy(); + $mod1->_rshift($j); + $mod2 = new Math_BigInteger(); + $mod2->value = array(1); + $mod2->_lshift($j); + + $part1 = ( $mod1->value != array(1) ) ? $this->_slidingWindow($e, $mod1, MATH_BIGINTEGER_MONTGOMERY) : new Math_BigInteger(); + $part2 = $this->_slidingWindow($e, $mod2, MATH_BIGINTEGER_POWEROF2); + + $y1 = $mod2->modInverse($mod1); + $y2 = $mod1->modInverse($mod2); + + $result = $part1->multiply($mod2); + $result = $result->multiply($y1); + + $temp = $part2->multiply($mod1); + $temp = $temp->multiply($y2); + + $result = $result->add($temp); + list(, $result) = $result->divide($n); + + return $this->_normalize($result); + } + + /** + * Performs modular exponentiation. + * + * Alias for Math_BigInteger::modPow() + * + * @param Math_BigInteger $e + * @param Math_BigInteger $n + * @return Math_BigInteger + * @access public + */ + function powMod($e, $n) + { + return $this->modPow($e, $n); + } + + /** + * Sliding Window k-ary Modular Exponentiation + * + * Based on {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=27 HAC 14.85} / + * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=210 MPM 7.7}. In a departure from those algorithims, + * however, this function performs a modular reduction after every multiplication and squaring operation. + * As such, this function has the same preconditions that the reductions being used do. + * + * @param Math_BigInteger $e + * @param Math_BigInteger $n + * @param Integer $mode + * @return Math_BigInteger + * @access private + */ + function _slidingWindow($e, $n, $mode) + { + static $window_ranges = array(7, 25, 81, 241, 673, 1793); // from BigInteger.java's oddModPow function + //static $window_ranges = array(0, 7, 36, 140, 450, 1303, 3529); // from MPM 7.3.1 + + $e_value = $e->value; + $e_length = count($e_value) - 1; + $e_bits = decbin($e_value[$e_length]); + for ($i = $e_length - 1; $i >= 0; --$i) { + $e_bits.= str_pad(decbin($e_value[$i]), MATH_BIGINTEGER_BASE, '0', STR_PAD_LEFT); + } + + $e_length = strlen($e_bits); + + // calculate the appropriate window size. + // $window_size == 3 if $window_ranges is between 25 and 81, for example. + for ($i = 0, $window_size = 1; $e_length > $window_ranges[$i] && $i < count($window_ranges); ++$window_size, ++$i); + + $n_value = $n->value; + + // precompute $this^0 through $this^$window_size + $powers = array(); + $powers[1] = $this->_prepareReduce($this->value, $n_value, $mode); + $powers[2] = $this->_squareReduce($powers[1], $n_value, $mode); + + // we do every other number since substr($e_bits, $i, $j+1) (see below) is supposed to end + // in a 1. ie. it's supposed to be odd. + $temp = 1 << ($window_size - 1); + for ($i = 1; $i < $temp; ++$i) { + $i2 = $i << 1; + $powers[$i2 + 1] = $this->_multiplyReduce($powers[$i2 - 1], $powers[2], $n_value, $mode); + } + + $result = array(1); + $result = $this->_prepareReduce($result, $n_value, $mode); + + for ($i = 0; $i < $e_length; ) { + if ( !$e_bits[$i] ) { + $result = $this->_squareReduce($result, $n_value, $mode); + ++$i; + } else { + for ($j = $window_size - 1; $j > 0; --$j) { + if ( !empty($e_bits[$i + $j]) ) { + break; + } + } + + for ($k = 0; $k <= $j; ++$k) {// eg. the length of substr($e_bits, $i, $j+1) + $result = $this->_squareReduce($result, $n_value, $mode); + } + + $result = $this->_multiplyReduce($result, $powers[bindec(substr($e_bits, $i, $j + 1))], $n_value, $mode); + + $i+=$j + 1; + } + } + + $temp = new Math_BigInteger(); + $temp->value = $this->_reduce($result, $n_value, $mode); + + return $temp; + } + + /** + * Modular reduction + * + * For most $modes this will return the remainder. + * + * @see _slidingWindow() + * @access private + * @param Array $x + * @param Array $n + * @param Integer $mode + * @return Array + */ + function _reduce($x, $n, $mode) + { + switch ($mode) { + case MATH_BIGINTEGER_MONTGOMERY: + return $this->_montgomery($x, $n); + case MATH_BIGINTEGER_BARRETT: + return $this->_barrett($x, $n); + case MATH_BIGINTEGER_POWEROF2: + $lhs = new Math_BigInteger(); + $lhs->value = $x; + $rhs = new Math_BigInteger(); + $rhs->value = $n; + return $x->_mod2($n); + case MATH_BIGINTEGER_CLASSIC: + $lhs = new Math_BigInteger(); + $lhs->value = $x; + $rhs = new Math_BigInteger(); + $rhs->value = $n; + list(, $temp) = $lhs->divide($rhs); + return $temp->value; + case MATH_BIGINTEGER_NONE: + return $x; + default: + // an invalid $mode was provided + } + } + + /** + * Modular reduction preperation + * + * @see _slidingWindow() + * @access private + * @param Array $x + * @param Array $n + * @param Integer $mode + * @return Array + */ + function _prepareReduce($x, $n, $mode) + { + if ($mode == MATH_BIGINTEGER_MONTGOMERY) { + return $this->_prepMontgomery($x, $n); + } + return $this->_reduce($x, $n, $mode); + } + + /** + * Modular multiply + * + * @see _slidingWindow() + * @access private + * @param Array $x + * @param Array $y + * @param Array $n + * @param Integer $mode + * @return Array + */ + function _multiplyReduce($x, $y, $n, $mode) + { + if ($mode == MATH_BIGINTEGER_MONTGOMERY) { + return $this->_montgomeryMultiply($x, $y, $n); + } + $temp = $this->_multiply($x, false, $y, false); + return $this->_reduce($temp[MATH_BIGINTEGER_VALUE], $n, $mode); + } + + /** + * Modular square + * + * @see _slidingWindow() + * @access private + * @param Array $x + * @param Array $n + * @param Integer $mode + * @return Array + */ + function _squareReduce($x, $n, $mode) + { + if ($mode == MATH_BIGINTEGER_MONTGOMERY) { + return $this->_montgomeryMultiply($x, $x, $n); + } + return $this->_reduce($this->_square($x), $n, $mode); + } + + /** + * Modulos for Powers of Two + * + * Calculates $x%$n, where $n = 2**$e, for some $e. Since this is basically the same as doing $x & ($n-1), + * we'll just use this function as a wrapper for doing that. + * + * @see _slidingWindow() + * @access private + * @param Math_BigInteger + * @return Math_BigInteger + */ + function _mod2($n) + { + $temp = new Math_BigInteger(); + $temp->value = array(1); + return $this->bitwise_and($n->subtract($temp)); + } + + /** + * Barrett Modular Reduction + * + * See {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=14 HAC 14.3.3} / + * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=165 MPM 6.2.5} for more information. Modified slightly, + * so as not to require negative numbers (initially, this script didn't support negative numbers). + * + * Employs "folding", as described at + * {@link http://www.cosic.esat.kuleuven.be/publications/thesis-149.pdf#page=66 thesis-149.pdf#page=66}. To quote from + * it, "the idea [behind folding] is to find a value x' such that x (mod m) = x' (mod m), with x' being smaller than x." + * + * Unfortunately, the "Barrett Reduction with Folding" algorithm described in thesis-149.pdf is not, as written, all that + * usable on account of (1) its not using reasonable radix points as discussed in + * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=162 MPM 6.2.2} and (2) the fact that, even with reasonable + * radix points, it only works when there are an even number of digits in the denominator. The reason for (2) is that + * (x >> 1) + (x >> 1) != x / 2 + x / 2. If x is even, they're the same, but if x is odd, they're not. See the in-line + * comments for details. + * + * @see _slidingWindow() + * @access private + * @param Array $n + * @param Array $m + * @return Array + */ + function _barrett($n, $m) + { + static $cache = array( + MATH_BIGINTEGER_VARIABLE => array(), + MATH_BIGINTEGER_DATA => array() + ); + + $m_length = count($m); + + // if ($this->_compare($n, $this->_square($m)) >= 0) { + if (count($n) > 2 * $m_length) { + $lhs = new Math_BigInteger(); + $rhs = new Math_BigInteger(); + $lhs->value = $n; + $rhs->value = $m; + list(, $temp) = $lhs->divide($rhs); + return $temp->value; + } + + // if (m.length >> 1) + 2 <= m.length then m is too small and n can't be reduced + if ($m_length < 5) { + return $this->_regularBarrett($n, $m); + } + + // n = 2 * m.length + + if ( ($key = array_search($m, $cache[MATH_BIGINTEGER_VARIABLE])) === false ) { + $key = count($cache[MATH_BIGINTEGER_VARIABLE]); + $cache[MATH_BIGINTEGER_VARIABLE][] = $m; + + $lhs = new Math_BigInteger(); + $lhs_value = &$lhs->value; + $lhs_value = $this->_array_repeat(0, $m_length + ($m_length >> 1)); + $lhs_value[] = 1; + $rhs = new Math_BigInteger(); + $rhs->value = $m; + + list($u, $m1) = $lhs->divide($rhs); + $u = $u->value; + $m1 = $m1->value; + + $cache[MATH_BIGINTEGER_DATA][] = array( + 'u' => $u, // m.length >> 1 (technically (m.length >> 1) + 1) + 'm1'=> $m1 // m.length + ); + } else { + extract($cache[MATH_BIGINTEGER_DATA][$key]); + } + + $cutoff = $m_length + ($m_length >> 1); + $lsd = array_slice($n, 0, $cutoff); // m.length + (m.length >> 1) + $msd = array_slice($n, $cutoff); // m.length >> 1 + $lsd = $this->_trim($lsd); + $temp = $this->_multiply($msd, false, $m1, false); + $n = $this->_add($lsd, false, $temp[MATH_BIGINTEGER_VALUE], false); // m.length + (m.length >> 1) + 1 + + if ($m_length & 1) { + return $this->_regularBarrett($n[MATH_BIGINTEGER_VALUE], $m); + } + + // (m.length + (m.length >> 1) + 1) - (m.length - 1) == (m.length >> 1) + 2 + $temp = array_slice($n[MATH_BIGINTEGER_VALUE], $m_length - 1); + // if even: ((m.length >> 1) + 2) + (m.length >> 1) == m.length + 2 + // if odd: ((m.length >> 1) + 2) + (m.length >> 1) == (m.length - 1) + 2 == m.length + 1 + $temp = $this->_multiply($temp, false, $u, false); + // if even: (m.length + 2) - ((m.length >> 1) + 1) = m.length - (m.length >> 1) + 1 + // if odd: (m.length + 1) - ((m.length >> 1) + 1) = m.length - (m.length >> 1) + $temp = array_slice($temp[MATH_BIGINTEGER_VALUE], ($m_length >> 1) + 1); + // if even: (m.length - (m.length >> 1) + 1) + m.length = 2 * m.length - (m.length >> 1) + 1 + // if odd: (m.length - (m.length >> 1)) + m.length = 2 * m.length - (m.length >> 1) + $temp = $this->_multiply($temp, false, $m, false); + + // at this point, if m had an odd number of digits, we'd be subtracting a 2 * m.length - (m.length >> 1) digit + // number from a m.length + (m.length >> 1) + 1 digit number. ie. there'd be an extra digit and the while loop + // following this comment would loop a lot (hence our calling _regularBarrett() in that situation). + + $result = $this->_subtract($n[MATH_BIGINTEGER_VALUE], false, $temp[MATH_BIGINTEGER_VALUE], false); + + while ($this->_compare($result[MATH_BIGINTEGER_VALUE], $result[MATH_BIGINTEGER_SIGN], $m, false) >= 0) { + $result = $this->_subtract($result[MATH_BIGINTEGER_VALUE], $result[MATH_BIGINTEGER_SIGN], $m, false); + } + + return $result[MATH_BIGINTEGER_VALUE]; + } + + /** + * (Regular) Barrett Modular Reduction + * + * For numbers with more than four digits Math_BigInteger::_barrett() is faster. The difference between that and this + * is that this function does not fold the denominator into a smaller form. + * + * @see _slidingWindow() + * @access private + * @param Array $x + * @param Array $n + * @return Array + */ + function _regularBarrett($x, $n) + { + static $cache = array( + MATH_BIGINTEGER_VARIABLE => array(), + MATH_BIGINTEGER_DATA => array() + ); + + $n_length = count($n); + + if (count($x) > 2 * $n_length) { + $lhs = new Math_BigInteger(); + $rhs = new Math_BigInteger(); + $lhs->value = $x; + $rhs->value = $n; + list(, $temp) = $lhs->divide($rhs); + return $temp->value; + } + + if ( ($key = array_search($n, $cache[MATH_BIGINTEGER_VARIABLE])) === false ) { + $key = count($cache[MATH_BIGINTEGER_VARIABLE]); + $cache[MATH_BIGINTEGER_VARIABLE][] = $n; + $lhs = new Math_BigInteger(); + $lhs_value = &$lhs->value; + $lhs_value = $this->_array_repeat(0, 2 * $n_length); + $lhs_value[] = 1; + $rhs = new Math_BigInteger(); + $rhs->value = $n; + list($temp, ) = $lhs->divide($rhs); // m.length + $cache[MATH_BIGINTEGER_DATA][] = $temp->value; + } + + // 2 * m.length - (m.length - 1) = m.length + 1 + $temp = array_slice($x, $n_length - 1); + // (m.length + 1) + m.length = 2 * m.length + 1 + $temp = $this->_multiply($temp, false, $cache[MATH_BIGINTEGER_DATA][$key], false); + // (2 * m.length + 1) - (m.length - 1) = m.length + 2 + $temp = array_slice($temp[MATH_BIGINTEGER_VALUE], $n_length + 1); + + // m.length + 1 + $result = array_slice($x, 0, $n_length + 1); + // m.length + 1 + $temp = $this->_multiplyLower($temp, false, $n, false, $n_length + 1); + // $temp == array_slice($temp->_multiply($temp, false, $n, false)->value, 0, $n_length + 1) + + if ($this->_compare($result, false, $temp[MATH_BIGINTEGER_VALUE], $temp[MATH_BIGINTEGER_SIGN]) < 0) { + $corrector_value = $this->_array_repeat(0, $n_length + 1); + $corrector_value[] = 1; + $result = $this->_add($result, false, $corrector_value, false); + $result = $result[MATH_BIGINTEGER_VALUE]; + } + + // at this point, we're subtracting a number with m.length + 1 digits from another number with m.length + 1 digits + $result = $this->_subtract($result, false, $temp[MATH_BIGINTEGER_VALUE], $temp[MATH_BIGINTEGER_SIGN]); + while ($this->_compare($result[MATH_BIGINTEGER_VALUE], $result[MATH_BIGINTEGER_SIGN], $n, false) > 0) { + $result = $this->_subtract($result[MATH_BIGINTEGER_VALUE], $result[MATH_BIGINTEGER_SIGN], $n, false); + } + + return $result[MATH_BIGINTEGER_VALUE]; + } + + /** + * Performs long multiplication up to $stop digits + * + * If you're going to be doing array_slice($product->value, 0, $stop), some cycles can be saved. + * + * @see _regularBarrett() + * @param Array $x_value + * @param Boolean $x_negative + * @param Array $y_value + * @param Boolean $y_negative + * @param Integer $stop + * @return Array + * @access private + */ + function _multiplyLower($x_value, $x_negative, $y_value, $y_negative, $stop) + { + $x_length = count($x_value); + $y_length = count($y_value); + + if ( !$x_length || !$y_length ) { // a 0 is being multiplied + return array( + MATH_BIGINTEGER_VALUE => array(), + MATH_BIGINTEGER_SIGN => false + ); + } + + if ( $x_length < $y_length ) { + $temp = $x_value; + $x_value = $y_value; + $y_value = $temp; + + $x_length = count($x_value); + $y_length = count($y_value); + } + + $product_value = $this->_array_repeat(0, $x_length + $y_length); + + // the following for loop could be removed if the for loop following it + // (the one with nested for loops) initially set $i to 0, but + // doing so would also make the result in one set of unnecessary adds, + // since on the outermost loops first pass, $product->value[$k] is going + // to always be 0 + + $carry = 0; + + for ($j = 0; $j < $x_length; ++$j) { // ie. $i = 0, $k = $i + $temp = $x_value[$j] * $y_value[0] + $carry; // $product_value[$k] == 0 + $carry = (int) ($temp / MATH_BIGINTEGER_BASE_FULL); + $product_value[$j] = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * $carry); + } + + if ($j < $stop) { + $product_value[$j] = $carry; + } + + // the above for loop is what the previous comment was talking about. the + // following for loop is the "one with nested for loops" + + for ($i = 1; $i < $y_length; ++$i) { + $carry = 0; + + for ($j = 0, $k = $i; $j < $x_length && $k < $stop; ++$j, ++$k) { + $temp = $product_value[$k] + $x_value[$j] * $y_value[$i] + $carry; + $carry = (int) ($temp / MATH_BIGINTEGER_BASE_FULL); + $product_value[$k] = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * $carry); + } + + if ($k < $stop) { + $product_value[$k] = $carry; + } + } + + return array( + MATH_BIGINTEGER_VALUE => $this->_trim($product_value), + MATH_BIGINTEGER_SIGN => $x_negative != $y_negative + ); + } + + /** + * Montgomery Modular Reduction + * + * ($x->_prepMontgomery($n))->_montgomery($n) yields $x % $n. + * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=170 MPM 6.3} provides insights on how this can be + * improved upon (basically, by using the comba method). gcd($n, 2) must be equal to one for this function + * to work correctly. + * + * @see _prepMontgomery() + * @see _slidingWindow() + * @access private + * @param Array $x + * @param Array $n + * @return Array + */ + function _montgomery($x, $n) + { + static $cache = array( + MATH_BIGINTEGER_VARIABLE => array(), + MATH_BIGINTEGER_DATA => array() + ); + + if ( ($key = array_search($n, $cache[MATH_BIGINTEGER_VARIABLE])) === false ) { + $key = count($cache[MATH_BIGINTEGER_VARIABLE]); + $cache[MATH_BIGINTEGER_VARIABLE][] = $x; + $cache[MATH_BIGINTEGER_DATA][] = $this->_modInverse67108864($n); + } + + $k = count($n); + + $result = array(MATH_BIGINTEGER_VALUE => $x); + + for ($i = 0; $i < $k; ++$i) { + $temp = $result[MATH_BIGINTEGER_VALUE][$i] * $cache[MATH_BIGINTEGER_DATA][$key]; + $temp = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * ((int) ($temp / MATH_BIGINTEGER_BASE_FULL))); + $temp = $this->_regularMultiply(array($temp), $n); + $temp = array_merge($this->_array_repeat(0, $i), $temp); + $result = $this->_add($result[MATH_BIGINTEGER_VALUE], false, $temp, false); + } + + $result[MATH_BIGINTEGER_VALUE] = array_slice($result[MATH_BIGINTEGER_VALUE], $k); + + if ($this->_compare($result, false, $n, false) >= 0) { + $result = $this->_subtract($result[MATH_BIGINTEGER_VALUE], false, $n, false); + } + + return $result[MATH_BIGINTEGER_VALUE]; + } + + /** + * Montgomery Multiply + * + * Interleaves the montgomery reduction and long multiplication algorithms together as described in + * {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=13 HAC 14.36} + * + * @see _prepMontgomery() + * @see _montgomery() + * @access private + * @param Array $x + * @param Array $y + * @param Array $m + * @return Array + */ + function _montgomeryMultiply($x, $y, $m) + { + $temp = $this->_multiply($x, false, $y, false); + return $this->_montgomery($temp[MATH_BIGINTEGER_VALUE], $m); + + static $cache = array( + MATH_BIGINTEGER_VARIABLE => array(), + MATH_BIGINTEGER_DATA => array() + ); + + if ( ($key = array_search($m, $cache[MATH_BIGINTEGER_VARIABLE])) === false ) { + $key = count($cache[MATH_BIGINTEGER_VARIABLE]); + $cache[MATH_BIGINTEGER_VARIABLE][] = $m; + $cache[MATH_BIGINTEGER_DATA][] = $this->_modInverse67108864($m); + } + + $n = max(count($x), count($y), count($m)); + $x = array_pad($x, $n, 0); + $y = array_pad($y, $n, 0); + $m = array_pad($m, $n, 0); + $a = array(MATH_BIGINTEGER_VALUE => $this->_array_repeat(0, $n + 1)); + for ($i = 0; $i < $n; ++$i) { + $temp = $a[MATH_BIGINTEGER_VALUE][0] + $x[$i] * $y[0]; + $temp = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * ((int) ($temp / MATH_BIGINTEGER_BASE_FULL))); + $temp = $temp * $cache[MATH_BIGINTEGER_DATA][$key]; + $temp = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * ((int) ($temp / MATH_BIGINTEGER_BASE_FULL))); + $temp = $this->_add($this->_regularMultiply(array($x[$i]), $y), false, $this->_regularMultiply(array($temp), $m), false); + $a = $this->_add($a[MATH_BIGINTEGER_VALUE], false, $temp[MATH_BIGINTEGER_VALUE], false); + $a[MATH_BIGINTEGER_VALUE] = array_slice($a[MATH_BIGINTEGER_VALUE], 1); + } + if ($this->_compare($a[MATH_BIGINTEGER_VALUE], false, $m, false) >= 0) { + $a = $this->_subtract($a[MATH_BIGINTEGER_VALUE], false, $m, false); + } + return $a[MATH_BIGINTEGER_VALUE]; + } + + /** + * Prepare a number for use in Montgomery Modular Reductions + * + * @see _montgomery() + * @see _slidingWindow() + * @access private + * @param Array $x + * @param Array $n + * @return Array + */ + function _prepMontgomery($x, $n) + { + $lhs = new Math_BigInteger(); + $lhs->value = array_merge($this->_array_repeat(0, count($n)), $x); + $rhs = new Math_BigInteger(); + $rhs->value = $n; + + list(, $temp) = $lhs->divide($rhs); + return $temp->value; + } + + /** + * Modular Inverse of a number mod 2**26 (eg. 67108864) + * + * Based off of the bnpInvDigit function implemented and justified in the following URL: + * + * {@link http://www-cs-students.stanford.edu/~tjw/jsbn/jsbn.js} + * + * The following URL provides more info: + * + * {@link http://groups.google.com/group/sci.crypt/msg/7a137205c1be7d85} + * + * As for why we do all the bitmasking... strange things can happen when converting from floats to ints. For + * instance, on some computers, var_dump((int) -4294967297) yields int(-1) and on others, it yields + * int(-2147483648). To avoid problems stemming from this, we use bitmasks to guarantee that ints aren't + * auto-converted to floats. The outermost bitmask is present because without it, there's no guarantee that + * the "residue" returned would be the so-called "common residue". We use fmod, in the last step, because the + * maximum possible $x is 26 bits and the maximum $result is 16 bits. Thus, we have to be able to handle up to + * 40 bits, which only 64-bit floating points will support. + * + * Thanks to Pedro Gimeno Fortea for input! + * + * @see _montgomery() + * @access private + * @param Array $x + * @return Integer + */ + function _modInverse67108864($x) // 2**26 == 67,108,864 + { + $x = -$x[0]; + $result = $x & 0x3; // x**-1 mod 2**2 + $result = ($result * (2 - $x * $result)) & 0xF; // x**-1 mod 2**4 + $result = ($result * (2 - ($x & 0xFF) * $result)) & 0xFF; // x**-1 mod 2**8 + $result = ($result * ((2 - ($x & 0xFFFF) * $result) & 0xFFFF)) & 0xFFFF; // x**-1 mod 2**16 + $result = fmod($result * (2 - fmod($x * $result, MATH_BIGINTEGER_BASE_FULL)), MATH_BIGINTEGER_BASE_FULL); // x**-1 mod 2**26 + return $result & MATH_BIGINTEGER_MAX_DIGIT; + } + + /** + * Calculates modular inverses. + * + * Say you have (30 mod 17 * x mod 17) mod 17 == 1. x can be found using modular inverses. + * + * Here's an example: + * + * modInverse($b); + * echo $c->toString(); // outputs 4 + * + * echo "\r\n"; + * + * $d = $a->multiply($c); + * list(, $d) = $d->divide($b); + * echo $d; // outputs 1 (as per the definition of modular inverse) + * ?> + * + * + * @param Math_BigInteger $n + * @return mixed false, if no modular inverse exists, Math_BigInteger, otherwise. + * @access public + * @internal See {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=21 HAC 14.64} for more information. + */ + function modInverse($n) + { + switch ( MATH_BIGINTEGER_MODE ) { + case MATH_BIGINTEGER_MODE_GMP: + $temp = new Math_BigInteger(); + $temp->value = gmp_invert($this->value, $n->value); + + return ( $temp->value === false ) ? false : $this->_normalize($temp); + } + + static $zero, $one; + if (!isset($zero)) { + $zero = new Math_BigInteger(); + $one = new Math_BigInteger(1); + } + + // $x mod -$n == $x mod $n. + $n = $n->abs(); + + if ($this->compare($zero) < 0) { + $temp = $this->abs(); + $temp = $temp->modInverse($n); + return $this->_normalize($n->subtract($temp)); + } + + extract($this->extendedGCD($n)); + + if (!$gcd->equals($one)) { + return false; + } + + $x = $x->compare($zero) < 0 ? $x->add($n) : $x; + + return $this->compare($zero) < 0 ? $this->_normalize($n->subtract($x)) : $this->_normalize($x); + } + + /** + * Calculates the greatest common divisor and Bezout's identity. + * + * Say you have 693 and 609. The GCD is 21. Bezout's identity states that there exist integers x and y such that + * 693*x + 609*y == 21. In point of fact, there are actually an infinite number of x and y combinations and which + * combination is returned is dependant upon which mode is in use. See + * {@link http://en.wikipedia.org/wiki/B%C3%A9zout%27s_identity Bezout's identity - Wikipedia} for more information. + * + * Here's an example: + * + * extendedGCD($b)); + * + * echo $gcd->toString() . "\r\n"; // outputs 21 + * echo $a->toString() * $x->toString() + $b->toString() * $y->toString(); // outputs 21 + * ?> + * + * + * @param Math_BigInteger $n + * @return Math_BigInteger + * @access public + * @internal Calculates the GCD using the binary xGCD algorithim described in + * {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=19 HAC 14.61}. As the text above 14.61 notes, + * the more traditional algorithim requires "relatively costly multiple-precision divisions". + */ + function extendedGCD($n) + { + switch ( MATH_BIGINTEGER_MODE ) { + case MATH_BIGINTEGER_MODE_GMP: + extract(gmp_gcdext($this->value, $n->value)); + + return array( + 'gcd' => $this->_normalize(new Math_BigInteger($g)), + 'x' => $this->_normalize(new Math_BigInteger($s)), + 'y' => $this->_normalize(new Math_BigInteger($t)) + ); + case MATH_BIGINTEGER_MODE_BCMATH: + // it might be faster to use the binary xGCD algorithim here, as well, but (1) that algorithim works + // best when the base is a power of 2 and (2) i don't think it'd make much difference, anyway. as is, + // the basic extended euclidean algorithim is what we're using. + + $u = $this->value; + $v = $n->value; + + $a = '1'; + $b = '0'; + $c = '0'; + $d = '1'; + + while (bccomp($v, '0', 0) != 0) { + $q = bcdiv($u, $v, 0); + + $temp = $u; + $u = $v; + $v = bcsub($temp, bcmul($v, $q, 0), 0); + + $temp = $a; + $a = $c; + $c = bcsub($temp, bcmul($a, $q, 0), 0); + + $temp = $b; + $b = $d; + $d = bcsub($temp, bcmul($b, $q, 0), 0); + } + + return array( + 'gcd' => $this->_normalize(new Math_BigInteger($u)), + 'x' => $this->_normalize(new Math_BigInteger($a)), + 'y' => $this->_normalize(new Math_BigInteger($b)) + ); + } + + $y = $n->copy(); + $x = $this->copy(); + $g = new Math_BigInteger(); + $g->value = array(1); + + while ( !(($x->value[0] & 1)|| ($y->value[0] & 1)) ) { + $x->_rshift(1); + $y->_rshift(1); + $g->_lshift(1); + } + + $u = $x->copy(); + $v = $y->copy(); + + $a = new Math_BigInteger(); + $b = new Math_BigInteger(); + $c = new Math_BigInteger(); + $d = new Math_BigInteger(); + + $a->value = $d->value = $g->value = array(1); + $b->value = $c->value = array(); + + while ( !empty($u->value) ) { + while ( !($u->value[0] & 1) ) { + $u->_rshift(1); + if ( (!empty($a->value) && ($a->value[0] & 1)) || (!empty($b->value) && ($b->value[0] & 1)) ) { + $a = $a->add($y); + $b = $b->subtract($x); + } + $a->_rshift(1); + $b->_rshift(1); + } + + while ( !($v->value[0] & 1) ) { + $v->_rshift(1); + if ( (!empty($d->value) && ($d->value[0] & 1)) || (!empty($c->value) && ($c->value[0] & 1)) ) { + $c = $c->add($y); + $d = $d->subtract($x); + } + $c->_rshift(1); + $d->_rshift(1); + } + + if ($u->compare($v) >= 0) { + $u = $u->subtract($v); + $a = $a->subtract($c); + $b = $b->subtract($d); + } else { + $v = $v->subtract($u); + $c = $c->subtract($a); + $d = $d->subtract($b); + } + } + + return array( + 'gcd' => $this->_normalize($g->multiply($v)), + 'x' => $this->_normalize($c), + 'y' => $this->_normalize($d) + ); + } + + /** + * Calculates the greatest common divisor + * + * Say you have 693 and 609. The GCD is 21. + * + * Here's an example: + * + * extendedGCD($b); + * + * echo $gcd->toString() . "\r\n"; // outputs 21 + * ?> + * + * + * @param Math_BigInteger $n + * @return Math_BigInteger + * @access public + */ + function gcd($n) + { + extract($this->extendedGCD($n)); + return $gcd; + } + + /** + * Absolute value. + * + * @return Math_BigInteger + * @access public + */ + function abs() + { + $temp = new Math_BigInteger(); + + switch ( MATH_BIGINTEGER_MODE ) { + case MATH_BIGINTEGER_MODE_GMP: + $temp->value = gmp_abs($this->value); + break; + case MATH_BIGINTEGER_MODE_BCMATH: + $temp->value = (bccomp($this->value, '0', 0) < 0) ? substr($this->value, 1) : $this->value; + break; + default: + $temp->value = $this->value; + } + + return $temp; + } + + /** + * Compares two numbers. + * + * Although one might think !$x->compare($y) means $x != $y, it, in fact, means the opposite. The reason for this is + * demonstrated thusly: + * + * $x > $y: $x->compare($y) > 0 + * $x < $y: $x->compare($y) < 0 + * $x == $y: $x->compare($y) == 0 + * + * Note how the same comparison operator is used. If you want to test for equality, use $x->equals($y). + * + * @param Math_BigInteger $y + * @return Integer < 0 if $this is less than $y; > 0 if $this is greater than $y, and 0 if they are equal. + * @access public + * @see equals() + * @internal Could return $this->subtract($x), but that's not as fast as what we do do. + */ + function compare($y) + { + switch ( MATH_BIGINTEGER_MODE ) { + case MATH_BIGINTEGER_MODE_GMP: + return gmp_cmp($this->value, $y->value); + case MATH_BIGINTEGER_MODE_BCMATH: + return bccomp($this->value, $y->value, 0); + } + + return $this->_compare($this->value, $this->is_negative, $y->value, $y->is_negative); + } + + /** + * Compares two numbers. + * + * @param Array $x_value + * @param Boolean $x_negative + * @param Array $y_value + * @param Boolean $y_negative + * @return Integer + * @see compare() + * @access private + */ + function _compare($x_value, $x_negative, $y_value, $y_negative) + { + if ( $x_negative != $y_negative ) { + return ( !$x_negative && $y_negative ) ? 1 : -1; + } + + $result = $x_negative ? -1 : 1; + + if ( count($x_value) != count($y_value) ) { + return ( count($x_value) > count($y_value) ) ? $result : -$result; + } + $size = max(count($x_value), count($y_value)); + + $x_value = array_pad($x_value, $size, 0); + $y_value = array_pad($y_value, $size, 0); + + for ($i = count($x_value) - 1; $i >= 0; --$i) { + if ($x_value[$i] != $y_value[$i]) { + return ( $x_value[$i] > $y_value[$i] ) ? $result : -$result; + } + } + + return 0; + } + + /** + * Tests the equality of two numbers. + * + * If you need to see if one number is greater than or less than another number, use Math_BigInteger::compare() + * + * @param Math_BigInteger $x + * @return Boolean + * @access public + * @see compare() + */ + function equals($x) + { + switch ( MATH_BIGINTEGER_MODE ) { + case MATH_BIGINTEGER_MODE_GMP: + return gmp_cmp($this->value, $x->value) == 0; + default: + return $this->value === $x->value && $this->is_negative == $x->is_negative; + } + } + + /** + * Set Precision + * + * Some bitwise operations give different results depending on the precision being used. Examples include left + * shift, not, and rotates. + * + * @param Integer $bits + * @access public + */ + function setPrecision($bits) + { + $this->precision = $bits; + if ( MATH_BIGINTEGER_MODE != MATH_BIGINTEGER_MODE_BCMATH ) { + $this->bitmask = new Math_BigInteger(chr((1 << ($bits & 0x7)) - 1) . str_repeat(chr(0xFF), $bits >> 3), 256); + } else { + $this->bitmask = new Math_BigInteger(bcpow('2', $bits, 0)); + } + + $temp = $this->_normalize($this); + $this->value = $temp->value; + } + + /** + * Logical And + * + * @param Math_BigInteger $x + * @access public + * @internal Implemented per a request by Lluis Pamies i Juarez + * @return Math_BigInteger + */ + function bitwise_and($x) + { + switch ( MATH_BIGINTEGER_MODE ) { + case MATH_BIGINTEGER_MODE_GMP: + $temp = new Math_BigInteger(); + $temp->value = gmp_and($this->value, $x->value); + + return $this->_normalize($temp); + case MATH_BIGINTEGER_MODE_BCMATH: + $left = $this->toBytes(); + $right = $x->toBytes(); + + $length = max(strlen($left), strlen($right)); + + $left = str_pad($left, $length, chr(0), STR_PAD_LEFT); + $right = str_pad($right, $length, chr(0), STR_PAD_LEFT); + + return $this->_normalize(new Math_BigInteger($left & $right, 256)); + } + + $result = $this->copy(); + + $length = min(count($x->value), count($this->value)); + + $result->value = array_slice($result->value, 0, $length); + + for ($i = 0; $i < $length; ++$i) { + $result->value[$i]&= $x->value[$i]; + } + + return $this->_normalize($result); + } + + /** + * Logical Or + * + * @param Math_BigInteger $x + * @access public + * @internal Implemented per a request by Lluis Pamies i Juarez + * @return Math_BigInteger + */ + function bitwise_or($x) + { + switch ( MATH_BIGINTEGER_MODE ) { + case MATH_BIGINTEGER_MODE_GMP: + $temp = new Math_BigInteger(); + $temp->value = gmp_or($this->value, $x->value); + + return $this->_normalize($temp); + case MATH_BIGINTEGER_MODE_BCMATH: + $left = $this->toBytes(); + $right = $x->toBytes(); + + $length = max(strlen($left), strlen($right)); + + $left = str_pad($left, $length, chr(0), STR_PAD_LEFT); + $right = str_pad($right, $length, chr(0), STR_PAD_LEFT); + + return $this->_normalize(new Math_BigInteger($left | $right, 256)); + } + + $length = max(count($this->value), count($x->value)); + $result = $this->copy(); + $result->value = array_pad($result->value, $length, 0); + $x->value = array_pad($x->value, $length, 0); + + for ($i = 0; $i < $length; ++$i) { + $result->value[$i]|= $x->value[$i]; + } + + return $this->_normalize($result); + } + + /** + * Logical Exclusive-Or + * + * @param Math_BigInteger $x + * @access public + * @internal Implemented per a request by Lluis Pamies i Juarez + * @return Math_BigInteger + */ + function bitwise_xor($x) + { + switch ( MATH_BIGINTEGER_MODE ) { + case MATH_BIGINTEGER_MODE_GMP: + $temp = new Math_BigInteger(); + $temp->value = gmp_xor($this->value, $x->value); + + return $this->_normalize($temp); + case MATH_BIGINTEGER_MODE_BCMATH: + $left = $this->toBytes(); + $right = $x->toBytes(); + + $length = max(strlen($left), strlen($right)); + + $left = str_pad($left, $length, chr(0), STR_PAD_LEFT); + $right = str_pad($right, $length, chr(0), STR_PAD_LEFT); + + return $this->_normalize(new Math_BigInteger($left ^ $right, 256)); + } + + $length = max(count($this->value), count($x->value)); + $result = $this->copy(); + $result->value = array_pad($result->value, $length, 0); + $x->value = array_pad($x->value, $length, 0); + + for ($i = 0; $i < $length; ++$i) { + $result->value[$i]^= $x->value[$i]; + } + + return $this->_normalize($result); + } + + /** + * Logical Not + * + * @access public + * @internal Implemented per a request by Lluis Pamies i Juarez + * @return Math_BigInteger + */ + function bitwise_not() + { + // calculuate "not" without regard to $this->precision + // (will always result in a smaller number. ie. ~1 isn't 1111 1110 - it's 0) + $temp = $this->toBytes(); + $pre_msb = decbin(ord($temp[0])); + $temp = ~$temp; + $msb = decbin(ord($temp[0])); + if (strlen($msb) == 8) { + $msb = substr($msb, strpos($msb, '0')); + } + $temp[0] = chr(bindec($msb)); + + // see if we need to add extra leading 1's + $current_bits = strlen($pre_msb) + 8 * strlen($temp) - 8; + $new_bits = $this->precision - $current_bits; + if ($new_bits <= 0) { + return $this->_normalize(new Math_BigInteger($temp, 256)); + } + + // generate as many leading 1's as we need to. + $leading_ones = chr((1 << ($new_bits & 0x7)) - 1) . str_repeat(chr(0xFF), $new_bits >> 3); + $this->_base256_lshift($leading_ones, $current_bits); + + $temp = str_pad($temp, ceil($this->bits / 8), chr(0), STR_PAD_LEFT); + + return $this->_normalize(new Math_BigInteger($leading_ones | $temp, 256)); + } + + /** + * Logical Right Shift + * + * Shifts BigInteger's by $shift bits, effectively dividing by 2**$shift. + * + * @param Integer $shift + * @return Math_BigInteger + * @access public + * @internal The only version that yields any speed increases is the internal version. + */ + function bitwise_rightShift($shift) + { + $temp = new Math_BigInteger(); + + switch ( MATH_BIGINTEGER_MODE ) { + case MATH_BIGINTEGER_MODE_GMP: + static $two; + + if (!isset($two)) { + $two = gmp_init('2'); + } + + $temp->value = gmp_div_q($this->value, gmp_pow($two, $shift)); + + break; + case MATH_BIGINTEGER_MODE_BCMATH: + $temp->value = bcdiv($this->value, bcpow('2', $shift, 0), 0); + + break; + default: // could just replace _lshift with this, but then all _lshift() calls would need to be rewritten + // and I don't want to do that... + $temp->value = $this->value; + $temp->_rshift($shift); + } + + return $this->_normalize($temp); + } + + /** + * Logical Left Shift + * + * Shifts BigInteger's by $shift bits, effectively multiplying by 2**$shift. + * + * @param Integer $shift + * @return Math_BigInteger + * @access public + * @internal The only version that yields any speed increases is the internal version. + */ + function bitwise_leftShift($shift) + { + $temp = new Math_BigInteger(); + + switch ( MATH_BIGINTEGER_MODE ) { + case MATH_BIGINTEGER_MODE_GMP: + static $two; + + if (!isset($two)) { + $two = gmp_init('2'); + } + + $temp->value = gmp_mul($this->value, gmp_pow($two, $shift)); + + break; + case MATH_BIGINTEGER_MODE_BCMATH: + $temp->value = bcmul($this->value, bcpow('2', $shift, 0), 0); + + break; + default: // could just replace _rshift with this, but then all _lshift() calls would need to be rewritten + // and I don't want to do that... + $temp->value = $this->value; + $temp->_lshift($shift); + } + + return $this->_normalize($temp); + } + + /** + * Logical Left Rotate + * + * Instead of the top x bits being dropped they're appended to the shifted bit string. + * + * @param Integer $shift + * @return Math_BigInteger + * @access public + */ + function bitwise_leftRotate($shift) + { + $bits = $this->toBytes(); + + if ($this->precision > 0) { + $precision = $this->precision; + if ( MATH_BIGINTEGER_MODE == MATH_BIGINTEGER_MODE_BCMATH ) { + $mask = $this->bitmask->subtract(new Math_BigInteger(1)); + $mask = $mask->toBytes(); + } else { + $mask = $this->bitmask->toBytes(); + } + } else { + $temp = ord($bits[0]); + for ($i = 0; $temp >> $i; ++$i); + $precision = 8 * strlen($bits) - 8 + $i; + $mask = chr((1 << ($precision & 0x7)) - 1) . str_repeat(chr(0xFF), $precision >> 3); + } + + if ($shift < 0) { + $shift+= $precision; + } + $shift%= $precision; + + if (!$shift) { + return $this->copy(); + } + + $left = $this->bitwise_leftShift($shift); + $left = $left->bitwise_and(new Math_BigInteger($mask, 256)); + $right = $this->bitwise_rightShift($precision - $shift); + $result = MATH_BIGINTEGER_MODE != MATH_BIGINTEGER_MODE_BCMATH ? $left->bitwise_or($right) : $left->add($right); + return $this->_normalize($result); + } + + /** + * Logical Right Rotate + * + * Instead of the bottom x bits being dropped they're prepended to the shifted bit string. + * + * @param Integer $shift + * @return Math_BigInteger + * @access public + */ + function bitwise_rightRotate($shift) + { + return $this->bitwise_leftRotate(-$shift); + } + + /** + * Set random number generator function + * + * This function is deprecated. + * + * @param String $generator + * @access public + */ + function setRandomGenerator($generator) + { + } + + /** + * Generate a random number + * + * @param optional Integer $min + * @param optional Integer $max + * @return Math_BigInteger + * @access public + */ + function random($min = false, $max = false) + { + if ($min === false) { + $min = new Math_BigInteger(0); + } + + if ($max === false) { + $max = new Math_BigInteger(0x7FFFFFFF); + } + + $compare = $max->compare($min); + + if (!$compare) { + return $this->_normalize($min); + } else if ($compare < 0) { + // if $min is bigger then $max, swap $min and $max + $temp = $max; + $max = $min; + $min = $temp; + } + + $max = $max->subtract($min); + $max = ltrim($max->toBytes(), chr(0)); + $size = strlen($max) - 1; + + $crypt_random = function_exists('crypt_random_string') || (!class_exists('Crypt_Random') && function_exists('crypt_random_string')); + if ($crypt_random) { + $random = crypt_random_string($size); + } else { + $random = ''; + + if ($size & 1) { + $random.= chr(mt_rand(0, 255)); + } + + $blocks = $size >> 1; + for ($i = 0; $i < $blocks; ++$i) { + // mt_rand(-2147483648, 0x7FFFFFFF) always produces -2147483648 on some systems + $random.= pack('n', mt_rand(0, 0xFFFF)); + } + } + + $fragment = new Math_BigInteger($random, 256); + $leading = $fragment->compare(new Math_BigInteger(substr($max, 1), 256)) > 0 ? + ord($max[0]) - 1 : ord($max[0]); + + if (!$crypt_random) { + $msb = chr(mt_rand(0, $leading)); + } else { + $cutoff = floor(0xFF / $leading) * $leading; + while (true) { + $msb = ord(crypt_random_string(1)); + if ($msb <= $cutoff) { + $msb%= $leading; + break; + } + } + $msb = chr($msb); + } + + $random = new Math_BigInteger($msb . $random, 256); + + return $this->_normalize($random->add($min)); + } + + /** + * Generate a random prime number. + * + * If there's not a prime within the given range, false will be returned. If more than $timeout seconds have elapsed, + * give up and return false. + * + * @param optional Integer $min + * @param optional Integer $max + * @param optional Integer $timeout + * @return Math_BigInteger + * @access public + * @internal See {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap4.pdf#page=15 HAC 4.44}. + */ + function randomPrime($min = false, $max = false, $timeout = false) + { + if ($min === false) { + $min = new Math_BigInteger(0); + } + + if ($max === false) { + $max = new Math_BigInteger(0x7FFFFFFF); + } + + $compare = $max->compare($min); + + if (!$compare) { + return $min->isPrime() ? $min : false; + } else if ($compare < 0) { + // if $min is bigger then $max, swap $min and $max + $temp = $max; + $max = $min; + $min = $temp; + } + + static $one, $two; + if (!isset($one)) { + $one = new Math_BigInteger(1); + $two = new Math_BigInteger(2); + } + + $start = time(); + + $x = $this->random($min, $max); + + // gmp_nextprime() requires PHP 5 >= 5.2.0 per . + if ( MATH_BIGINTEGER_MODE == MATH_BIGINTEGER_MODE_GMP && function_exists('gmp_nextprime') ) { + $p = new Math_BigInteger(); + $p->value = gmp_nextprime($x->value); + + if ($p->compare($max) <= 0) { + return $p; + } + + if (!$min->equals($x)) { + $x = $x->subtract($one); + } + + return $x->randomPrime($min, $x); + } + + if ($x->equals($two)) { + return $x; + } + + $x->_make_odd(); + if ($x->compare($max) > 0) { + // if $x > $max then $max is even and if $min == $max then no prime number exists between the specified range + if ($min->equals($max)) { + return false; + } + $x = $min->copy(); + $x->_make_odd(); + } + + $initial_x = $x->copy(); + + while (true) { + if ($timeout !== false && time() - $start > $timeout) { + return false; + } + + if ($x->isPrime()) { + return $x; + } + + $x = $x->add($two); + + if ($x->compare($max) > 0) { + $x = $min->copy(); + if ($x->equals($two)) { + return $x; + } + $x->_make_odd(); + } + + if ($x->equals($initial_x)) { + return false; + } + } + } + + /** + * Make the current number odd + * + * If the current number is odd it'll be unchanged. If it's even, one will be added to it. + * + * @see randomPrime() + * @access private + */ + function _make_odd() + { + switch ( MATH_BIGINTEGER_MODE ) { + case MATH_BIGINTEGER_MODE_GMP: + gmp_setbit($this->value, 0); + break; + case MATH_BIGINTEGER_MODE_BCMATH: + if ($this->value[strlen($this->value) - 1] % 2 == 0) { + $this->value = bcadd($this->value, '1'); + } + break; + default: + $this->value[0] |= 1; + } + } + + /** + * Checks a numer to see if it's prime + * + * Assuming the $t parameter is not set, this function has an error rate of 2**-80. The main motivation for the + * $t parameter is distributability. Math_BigInteger::randomPrime() can be distributed accross multiple pageloads + * on a website instead of just one. + * + * @param optional Integer $t + * @return Boolean + * @access public + * @internal Uses the + * {@link http://en.wikipedia.org/wiki/Miller%E2%80%93Rabin_primality_test Miller-Rabin primality test}. See + * {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap4.pdf#page=8 HAC 4.24}. + */ + function isPrime($t = false) + { + $length = strlen($this->toBytes()); + + if (!$t) { + // see HAC 4.49 "Note (controlling the error probability)" + if ($length >= 163) { $t = 2; } // floor(1300 / 8) + else if ($length >= 106) { $t = 3; } // floor( 850 / 8) + else if ($length >= 81 ) { $t = 4; } // floor( 650 / 8) + else if ($length >= 68 ) { $t = 5; } // floor( 550 / 8) + else if ($length >= 56 ) { $t = 6; } // floor( 450 / 8) + else if ($length >= 50 ) { $t = 7; } // floor( 400 / 8) + else if ($length >= 43 ) { $t = 8; } // floor( 350 / 8) + else if ($length >= 37 ) { $t = 9; } // floor( 300 / 8) + else if ($length >= 31 ) { $t = 12; } // floor( 250 / 8) + else if ($length >= 25 ) { $t = 15; } // floor( 200 / 8) + else if ($length >= 18 ) { $t = 18; } // floor( 150 / 8) + else { $t = 27; } + } + + // ie. gmp_testbit($this, 0) + // ie. isEven() or !isOdd() + switch ( MATH_BIGINTEGER_MODE ) { + case MATH_BIGINTEGER_MODE_GMP: + return gmp_prob_prime($this->value, $t) != 0; + case MATH_BIGINTEGER_MODE_BCMATH: + if ($this->value === '2') { + return true; + } + if ($this->value[strlen($this->value) - 1] % 2 == 0) { + return false; + } + break; + default: + if ($this->value == array(2)) { + return true; + } + if (~$this->value[0] & 1) { + return false; + } + } + + static $primes, $zero, $one, $two; + + if (!isset($primes)) { + $primes = array( + 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, + 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, + 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, + 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, + 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, + 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, + 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, + 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, + 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, + 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, + 953, 967, 971, 977, 983, 991, 997 + ); + + if ( MATH_BIGINTEGER_MODE != MATH_BIGINTEGER_MODE_INTERNAL ) { + for ($i = 0; $i < count($primes); ++$i) { + $primes[$i] = new Math_BigInteger($primes[$i]); + } + } + + $zero = new Math_BigInteger(); + $one = new Math_BigInteger(1); + $two = new Math_BigInteger(2); + } + + if ($this->equals($one)) { + return false; + } + + // see HAC 4.4.1 "Random search for probable primes" + if ( MATH_BIGINTEGER_MODE != MATH_BIGINTEGER_MODE_INTERNAL ) { + foreach ($primes as $prime) { + list(, $r) = $this->divide($prime); + if ($r->equals($zero)) { + return $this->equals($prime); + } + } + } else { + $value = $this->value; + foreach ($primes as $prime) { + list(, $r) = $this->_divide_digit($value, $prime); + if (!$r) { + return count($value) == 1 && $value[0] == $prime; + } + } + } + + $n = $this->copy(); + $n_1 = $n->subtract($one); + $n_2 = $n->subtract($two); + + $r = $n_1->copy(); + $r_value = $r->value; + // ie. $s = gmp_scan1($n, 0) and $r = gmp_div_q($n, gmp_pow(gmp_init('2'), $s)); + if ( MATH_BIGINTEGER_MODE == MATH_BIGINTEGER_MODE_BCMATH ) { + $s = 0; + // if $n was 1, $r would be 0 and this would be an infinite loop, hence our $this->equals($one) check earlier + while ($r->value[strlen($r->value) - 1] % 2 == 0) { + $r->value = bcdiv($r->value, '2', 0); + ++$s; + } + } else { + for ($i = 0, $r_length = count($r_value); $i < $r_length; ++$i) { + $temp = ~$r_value[$i] & 0xFFFFFF; + for ($j = 1; ($temp >> $j) & 1; ++$j); + if ($j != 25) { + break; + } + } + $s = 26 * $i + $j - 1; + $r->_rshift($s); + } + + for ($i = 0; $i < $t; ++$i) { + $a = $this->random($two, $n_2); + $y = $a->modPow($r, $n); + + if (!$y->equals($one) && !$y->equals($n_1)) { + for ($j = 1; $j < $s && !$y->equals($n_1); ++$j) { + $y = $y->modPow($two, $n); + if ($y->equals($one)) { + return false; + } + } + + if (!$y->equals($n_1)) { + return false; + } + } + } + return true; + } + + /** + * Logical Left Shift + * + * Shifts BigInteger's by $shift bits. + * + * @param Integer $shift + * @access private + */ + function _lshift($shift) + { + if ( $shift == 0 ) { + return; + } + + $num_digits = (int) ($shift / MATH_BIGINTEGER_BASE); + $shift %= MATH_BIGINTEGER_BASE; + $shift = 1 << $shift; + + $carry = 0; + + for ($i = 0; $i < count($this->value); ++$i) { + $temp = $this->value[$i] * $shift + $carry; + $carry = (int) ($temp / MATH_BIGINTEGER_BASE_FULL); + $this->value[$i] = (int) ($temp - $carry * MATH_BIGINTEGER_BASE_FULL); + } + + if ( $carry ) { + $this->value[] = $carry; + } + + while ($num_digits--) { + array_unshift($this->value, 0); + } + } + + /** + * Logical Right Shift + * + * Shifts BigInteger's by $shift bits. + * + * @param Integer $shift + * @access private + */ + function _rshift($shift) + { + if ($shift == 0) { + return; + } + + $num_digits = (int) ($shift / MATH_BIGINTEGER_BASE); + $shift %= MATH_BIGINTEGER_BASE; + $carry_shift = MATH_BIGINTEGER_BASE - $shift; + $carry_mask = (1 << $shift) - 1; + + if ( $num_digits ) { + $this->value = array_slice($this->value, $num_digits); + } + + $carry = 0; + + for ($i = count($this->value) - 1; $i >= 0; --$i) { + $temp = $this->value[$i] >> $shift | $carry; + $carry = ($this->value[$i] & $carry_mask) << $carry_shift; + $this->value[$i] = $temp; + } + + $this->value = $this->_trim($this->value); + } + + /** + * Normalize + * + * Removes leading zeros and truncates (if necessary) to maintain the appropriate precision + * + * @param Math_BigInteger + * @return Math_BigInteger + * @see _trim() + * @access private + */ + function _normalize($result) + { + $result->precision = $this->precision; + $result->bitmask = $this->bitmask; + + switch ( MATH_BIGINTEGER_MODE ) { + case MATH_BIGINTEGER_MODE_GMP: + if (!empty($result->bitmask->value)) { + $result->value = gmp_and($result->value, $result->bitmask->value); + } + + return $result; + case MATH_BIGINTEGER_MODE_BCMATH: + if (!empty($result->bitmask->value)) { + $result->value = bcmod($result->value, $result->bitmask->value); + } + + return $result; + } + + $value = &$result->value; + + if ( !count($value) ) { + return $result; + } + + $value = $this->_trim($value); + + if (!empty($result->bitmask->value)) { + $length = min(count($value), count($this->bitmask->value)); + $value = array_slice($value, 0, $length); + + for ($i = 0; $i < $length; ++$i) { + $value[$i] = $value[$i] & $this->bitmask->value[$i]; + } + } + + return $result; + } + + /** + * Trim + * + * Removes leading zeros + * + * @param Array $value + * @return Math_BigInteger + * @access private + */ + function _trim($value) + { + for ($i = count($value) - 1; $i >= 0; --$i) { + if ( $value[$i] ) { + break; + } + unset($value[$i]); + } + + return $value; + } + + /** + * Array Repeat + * + * @param $input Array + * @param $multiplier mixed + * @return Array + * @access private + */ + function _array_repeat($input, $multiplier) + { + return ($multiplier) ? array_fill(0, $multiplier, $input) : array(); + } + + /** + * Logical Left Shift + * + * Shifts binary strings $shift bits, essentially multiplying by 2**$shift. + * + * @param $x String + * @param $shift Integer + * @return String + * @access private + */ + function _base256_lshift(&$x, $shift) + { + if ($shift == 0) { + return; + } + + $num_bytes = $shift >> 3; // eg. floor($shift/8) + $shift &= 7; // eg. $shift % 8 + + $carry = 0; + for ($i = strlen($x) - 1; $i >= 0; --$i) { + $temp = ord($x[$i]) << $shift | $carry; + $x[$i] = chr($temp); + $carry = $temp >> 8; + } + $carry = ($carry != 0) ? chr($carry) : ''; + $x = $carry . $x . str_repeat(chr(0), $num_bytes); + } + + /** + * Logical Right Shift + * + * Shifts binary strings $shift bits, essentially dividing by 2**$shift and returning the remainder. + * + * @param $x String + * @param $shift Integer + * @return String + * @access private + */ + function _base256_rshift(&$x, $shift) + { + if ($shift == 0) { + $x = ltrim($x, chr(0)); + return ''; + } + + $num_bytes = $shift >> 3; // eg. floor($shift/8) + $shift &= 7; // eg. $shift % 8 + + $remainder = ''; + if ($num_bytes) { + $start = $num_bytes > strlen($x) ? -strlen($x) : -$num_bytes; + $remainder = substr($x, $start); + $x = substr($x, 0, -$num_bytes); + } + + $carry = 0; + $carry_shift = 8 - $shift; + for ($i = 0; $i < strlen($x); ++$i) { + $temp = (ord($x[$i]) >> $shift) | $carry; + $carry = (ord($x[$i]) << $carry_shift) & 0xFF; + $x[$i] = chr($temp); + } + $x = ltrim($x, chr(0)); + + $remainder = chr($carry >> $carry_shift) . $remainder; + + return ltrim($remainder, chr(0)); + } + + // one quirk about how the following functions are implemented is that PHP defines N to be an unsigned long + // at 32-bits, while java's longs are 64-bits. + + /** + * Converts 32-bit integers to bytes. + * + * @param Integer $x + * @return String + * @access private + */ + function _int2bytes($x) + { + return ltrim(pack('N', $x), chr(0)); + } + + /** + * Converts bytes to 32-bit integers + * + * @param String $x + * @return Integer + * @access private + */ + function _bytes2int($x) + { + $temp = unpack('Nint', str_pad($x, 4, chr(0), STR_PAD_LEFT)); + return $temp['int']; + } + + /** + * DER-encode an integer + * + * The ability to DER-encode integers is needed to create RSA public keys for use with OpenSSL + * + * @see modPow() + * @access private + * @param Integer $length + * @return String + */ + function _encodeASN1Length($length) + { + if ($length <= 0x7F) { + return chr($length); + } + + $temp = ltrim(pack('N', $length), chr(0)); + return pack('Ca*', 0x80 | strlen($temp), $temp); + } +} diff --git a/inc/phpseclib/update.sh b/inc/phpseclib/update.sh new file mode 100755 index 000000000..ff3747a14 --- /dev/null +++ b/inc/phpseclib/update.sh @@ -0,0 +1,8 @@ +#!/bin/sh + +wget -nv https://raw.github.com/phpseclib/phpseclib/master/LICENSE -O LICENSE +wget -nv https://raw.github.com/phpseclib/phpseclib/master/phpseclib/Math/BigInteger.php -O Math_BigInteger.php +wget -nv https://raw.github.com/phpseclib/phpseclib/master/phpseclib/Crypt/AES.php -O Crypt_AES.php +wget -nv https://raw.github.com/phpseclib/phpseclib/master/phpseclib/Crypt/Rijndael.php -O Crypt_Rijndael.php +wget -nv https://raw.github.com/phpseclib/phpseclib/master/phpseclib/Crypt/Base.php -O Crypt_Base.php +wget -nv https://raw.github.com/phpseclib/phpseclib/master/phpseclib/Crypt/Hash.php -O Crypt_Hash.php -- cgit v1.2.3 From 3f7018f380583d266b9953cb45b2b4f16409250f Mon Sep 17 00:00:00 2001 From: Anika Henke Date: Wed, 31 Jul 2013 10:39:11 +0100 Subject: updated intro text on wiki:dokuwiki --- data/pages/wiki/dokuwiki.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/pages/wiki/dokuwiki.txt b/data/pages/wiki/dokuwiki.txt index 2db4dbef3..808aea68a 100644 --- a/data/pages/wiki/dokuwiki.txt +++ b/data/pages/wiki/dokuwiki.txt @@ -1,6 +1,6 @@ ====== DokuWiki ====== -[[doku>wiki:dokuwiki|{{wiki:dokuwiki-128.png }}]] DokuWiki is a standards compliant, simple to use [[wp>Wiki]], mainly aimed at creating documentation of any kind. It is targeted at developer teams, workgroups and small companies. It has a simple but powerful [[wiki:syntax]] which makes sure the datafiles remain readable outside the Wiki and eases the creation of structured texts. All data is stored in plain text files -- no database is required. +[[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. -- cgit v1.2.3 From 41878423ad837dcc9eba124c3d1ecbd32d958dac Mon Sep 17 00:00:00 2001 From: Michael Hamann Date: Wed, 31 Jul 2013 11:56:16 +0200 Subject: auth_random: remove exception comment as there is no exception --- inc/auth.php | 1 - 1 file changed, 1 deletion(-) diff --git a/inc/auth.php b/inc/auth.php index f02bfebca..227ee80fd 100644 --- a/inc/auth.php +++ b/inc/auth.php @@ -360,7 +360,6 @@ function auth_cookiesalt($addsession = false, $secure = false) { * @author Michael Hamann * @link http://www.php.net/manual/de/function.mt-rand.php#83655 * @param int $length number of bytes to get - * @throws Exception when no usable random generator is found * @return string binary random strings */ function auth_randombytes($length) { -- cgit v1.2.3 From 3094862ca5cce36390a6cc4e04c57e82795a68b4 Mon Sep 17 00:00:00 2001 From: Michael Hamann Date: Wed, 31 Jul 2013 11:56:58 +0200 Subject: auth_en/decrypt: Add explanation and more efficient decryption Added an explanation that what we do is like normal CBC but that we additionally encrypt the IV which is actually suggested by the NIST for non-random (but unique) IVs. In the decryption process it's not necessary to decrypt the IV, this should save some time. --- inc/auth.php | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/inc/auth.php b/inc/auth.php index 227ee80fd..96b80e19e 100644 --- a/inc/auth.php +++ b/inc/auth.php @@ -459,10 +459,16 @@ function auth_random($min, $max) { * @return string The ciphertext */ function auth_encrypt($data, $secret) { - $iv = auth_randombytes(16); + $iv = auth_randombytes(16); $cipher = new Crypt_AES(); $cipher->setPassword($secret); + /* + this uses the encrypted IV as IV as suggested in + http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf, Appendix C + for unique but necessarily random IVs. The resulting ciphertext is + compatible to ciphertext that was created using a "normal" IV. + */ return $cipher->encrypt($iv.$data); } @@ -476,10 +482,12 @@ function auth_encrypt($data, $secret) { * @return string The decrypted data */ function auth_decrypt($ciphertext, $secret) { + $iv = substr($ciphertext, 0, 16); $cipher = new Crypt_AES(); $cipher->setPassword($secret); + $cipher->setIV($iv); - return substr($cipher->decrypt($ciphertext), 16); + return $cipher->decrypt(substr($ciphertext, 16)); } /** -- cgit v1.2.3 From 87e03c3bebf87c1a71a40fbf873cdd1f836d4fb2 Mon Sep 17 00:00:00 2001 From: Guy Brand Date: Wed, 31 Jul 2013 12:31:35 +0200 Subject: Fixed instructions on PHPunit --- _test/README | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/_test/README b/_test/README index a4206f489..5220248b2 100644 --- a/_test/README +++ b/_test/README @@ -1,6 +1,6 @@ ====== DokuWiki Test Suite ====== -This is the test suit to automatically test various parts of DokuWiki. +This is the test suite to automatically test various parts of DokuWiki. ===== Requirements ===== @@ -9,22 +9,33 @@ This is the test suit to automatically test various parts of DokuWiki. ===== PHPUnit Installation ====== -via PEAR: +==== via PEAR installer ==== pear config-set auto_discover 1 - pear upgrade pear install pear.phpunit.de/PHPUnit -on Windows: +==== via Composer ==== - FIXME +Include a composer.json file in your project, which can be as minimal as: + + +{ + "require-dev": { + "phpunit/phpunit": "3.7.*" + } +} + + +==== via PHP archive (PHAR) ==== + +Download http://pear.phpunit.de/get/phpunit.phar and make it executable on your system. -===== Running all Tests ===== +===== Running all tests ===== Just change to the ''_test'' directory and run phpunit: - cd _testing/ + cd _test/ phpunit PHPUnit will fail on some systems with a //headers already sent// error. -- cgit v1.2.3 From 40960973d7ca45411e13e072595928d13534989e Mon Sep 17 00:00:00 2001 From: Andreas Gohr Date: Wed, 31 Jul 2013 14:04:56 +0200 Subject: include updateVersion in CSS/JS tseed to force reload on update --- inc/template.php | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/inc/template.php b/inc/template.php index a87650b84..b8129f914 100644 --- a/inc/template.php +++ b/inc/template.php @@ -291,12 +291,10 @@ function tpl_metaheaders($alt = true) { $head = array(); // prepare seed for js and css - $tseed = 0; + $tseed = $updateVersion; $depends = getConfigFiles('main'); - foreach($depends as $f) { - $time = @filemtime($f); - if($time > $tseed) $tseed = $time; - } + foreach($depends as $f) $tseed .= @filemtime($f); + $tseed = md5($tseed); // the usual stuff $head['meta'][] = array('name'=> 'generator', 'content'=> 'DokuWiki'); -- cgit v1.2.3 From 818d2283465b76931db168a9e2c72f2c0f004ecc Mon Sep 17 00:00:00 2001 From: Michael Hamann Date: Wed, 31 Jul 2013 17:20:00 +0200 Subject: Fix the useheading cache invalidation for hidden pages, add tests This adds a new parameter to ft_backlinks() to ignore permissions which is needed for invalidating the cache of linking pages with useheading enabled. This also adds various test cases for ft_backlinks(). --- _test/tests/inc/fulltext_backlinks.test.php | 77 +++++++++++++++++++++++++++++ inc/common.php | 2 +- inc/fulltext.php | 12 +++-- 3 files changed, 86 insertions(+), 5 deletions(-) create mode 100644 _test/tests/inc/fulltext_backlinks.test.php diff --git a/_test/tests/inc/fulltext_backlinks.test.php b/_test/tests/inc/fulltext_backlinks.test.php new file mode 100644 index 000000000..058e13498 --- /dev/null +++ b/_test/tests/inc/fulltext_backlinks.test.php @@ -0,0 +1,77 @@ + + */ +class fultext_backlinks_test extends DokuWikiTest { + + public function test_internallink() { + saveWikiText('test:internallinks', '[[internälLink]] [[..:internal link]]', 'Test initialization'); + idx_addPage('test:internallinks'); + + $this->assertEquals(array('test:internallinks'), ft_backlinks('internal_link')); + $this->assertEquals(array('test:internallinks'), ft_backlinks('test:internaellink')); + } + + public function test_links_in_footnotes() { + saveWikiText('test:link_footnotes', '(([[footnote]] [[:foÖtnotel]]))', 'Test initialization'); + idx_addPage('test:link_footnotes'); + + $this->assertEquals(array('test:link_footnotes'), ft_backlinks('test:footnote')); + $this->assertEquals(array('test:link_footnotes'), ft_backlinks('fooetnotel')); + } + + public function test_links_in_hidden_pages() { + global $conf; + $conf['hidepages'] = 'hidden:.*'; + saveWikiText('hidden:links', '[[wiki:hiddenlink|linktitle]]', 'Test initialization'); + idx_addPage('hidden:links'); + saveWikiText('visible:links', '[[wiki:hiddenlink]]', 'Test initialization'); + idx_addPage('visible:links'); + + $this->assertEquals(array('visible:links'), ft_backlinks('wiki:hiddenlink')); + $this->assertEquals(array('visible:links'), ft_backlinks('wiki:hiddenlink', false)); + $this->assertEquals(array('hidden:links', 'visible:links'), ft_backlinks('wiki:hiddenlink', true)); + } + + public function test_links_in_protected_pages() { + global $conf; + global $AUTH_ACL; + $conf['superuser'] = 'alice'; + $conf['useacl'] = 1; + + $AUTH_ACL = array( + '* @ALL 8', + 'secret:* @ALL 0', + ); + + $_SERVER['REMOTE_USER'] = 'eve'; + + saveWikiText('secret:links', '[[wiki:secretlink]]', 'Test initialization'); + idx_addPage('secret:links'); + saveWikiText('public:links', '[[wiki:secretlink]]', 'Test initialization'); + idx_addPage('public:links'); + + $this->assertEquals(array('public:links'), ft_backlinks('wiki:secretlink')); + $this->assertEquals(array('public:links'), ft_backlinks('wiki:secretlink', false)); + $this->assertEquals(array('public:links', 'secret:links'), ft_backlinks('wiki:secretlink', true)); + } + + public function test_links_in_deleted_pages() { + saveWikiText('test:internallinks', '[[internallink]] [[..:internal link]]', 'Test initialization'); + idx_addPage('test:internallinks'); + + $this->assertEquals(array('test:internallinks'), ft_backlinks('test:internallink')); + $this->assertEquals(array('test:internallinks'), ft_backlinks('internal_link')); + + saveWikiText('test:internallinks', '', 'Deleted'); + + $this->assertEquals(array(), ft_backlinks('test:internallink')); + $this->assertEquals(array(), ft_backlinks('internal_link')); + } +} diff --git a/inc/common.php b/inc/common.php index 1b4d9e8e4..bff6e80de 100644 --- a/inc/common.php +++ b/inc/common.php @@ -1130,7 +1130,7 @@ function saveWikiText($id, $text, $summary, $minor = false) { // if useheading is enabled, purge the cache of all linking pages if(useHeading('content')) { - $pages = ft_backlinks($id); + $pages = ft_backlinks($id, true); foreach($pages as $page) { $cache = new cache_renderer($page, wikiFN($page), 'xhtml'); $cache->removeCache(); diff --git a/inc/fulltext.php b/inc/fulltext.php index 2f073acea..1afff25dd 100644 --- a/inc/fulltext.php +++ b/inc/fulltext.php @@ -125,17 +125,21 @@ function _ft_pageSearch(&$data) { * Returns the backlinks for a given page * * Uses the metadata index. + * + * @param string $id The id for which links shall be returned + * @param bool $ignore_perms Ignore the fact that pages are hidden or read-protected + * @return array The pages that contain links to the given page */ -function ft_backlinks($id){ - $result = array(); - +function ft_backlinks($id, $ignore_perms = false){ $result = idx_get_indexer()->lookupKey('relation_references', $id); if(!count($result)) return $result; // check ACL permissions foreach(array_keys($result) as $idx){ - if(isHiddenPage($result[$idx]) || auth_quickaclcheck($result[$idx]) < AUTH_READ || !page_exists($result[$idx], '', false)){ + if(($ignore_perms !== true && ( + isHiddenPage($result[$idx]) || auth_quickaclcheck($result[$idx]) < AUTH_READ + )) || !page_exists($result[$idx], '', false)){ unset($result[$idx]); } } -- cgit v1.2.3 From e5d09fddcd17a2fe896650b64b81313a7d000975 Mon Sep 17 00:00:00 2001 From: Michael Hamann Date: Wed, 31 Jul 2013 17:30:08 +0200 Subject: Index media file usage in the metadata index and use it in ft_mediause() --- _test/tests/inc/fulltext_mediause.test.php | 77 ++++++++++++++++++++++++++++++ inc/fulltext.php | 48 +++++++------------ inc/indexer.php | 8 +++- inc/media.php | 2 +- inc/parser/metadata.php | 30 ++++++++++-- 5 files changed, 127 insertions(+), 38 deletions(-) create mode 100644 _test/tests/inc/fulltext_mediause.test.php diff --git a/_test/tests/inc/fulltext_mediause.test.php b/_test/tests/inc/fulltext_mediause.test.php new file mode 100644 index 000000000..9d5b2dc84 --- /dev/null +++ b/_test/tests/inc/fulltext_mediause.test.php @@ -0,0 +1,77 @@ + + */ +class fultext_mediause_test extends DokuWikiTest { + + public function test_internalmedia() { + saveWikiText('test:internalmedia_usage', '{{internalmedia.png}} {{..:internal media.png}}', 'Test initialization'); + idx_addPage('test:internalmedia_usage'); + + $this->assertEquals(array('test:internalmedia_usage'), ft_mediause('internal_media.png')); + $this->assertEquals(array('test:internalmedia_usage'), ft_mediause('test:internalmedia.png')); + } + + public function test_media_in_links() { + saveWikiText('test:medialinks', '[[doku>wiki:dokuwiki|{{wiki:logo.png}}]] [[http://www.example.com|{{example.png?200x800}}]]', 'Test init'); + idx_addPage('test:medialinks'); + + $this->assertEquals(array('test:medialinks'), ft_mediause('wiki:logo.png')); + $this->assertEquals(array('test:medialinks'), ft_mediause('test:example.png')); + } + + public function test_media_in_footnotes() { + saveWikiText('test:media_footnotes', '(({{footnote.png?20x50}} [[foonote|{{:footlink.png}}]]))', 'Test initialization'); + idx_addPage('test:media_footnotes'); + + $this->assertEquals(array('test:media_footnotes'), ft_mediause('test:footnote.png')); + $this->assertEquals(array('test:media_footnotes'), ft_mediause('footlink.png')); + } + + public function test_media_in_hidden_pages() { + global $conf; + $conf['hidepages'] = 'hidden:.*'; + saveWikiText('hidden:medias', '[[doku>wiki:dokuwiki|{{wiki:hiddenlogo.png}}]]', 'Test initialization'); + idx_addPage('hidden:medias'); + + $this->assertEquals(array(), ft_mediause('wiki:hiddenlogo.png')); + $this->assertEquals(array(), ft_mediause('wiki:hiddenlogo.png', false)); + $this->assertEquals(array('hidden:medias'), ft_mediause('wiki:hiddenlogo.png', true)); + } + + public function test_media_in_protected_pages() { + global $conf; + global $AUTH_ACL; + $conf['superuser'] = 'alice'; + $conf['useacl'] = 1; + + $AUTH_ACL = array( + '* @ALL 8', + 'secret:* @ALL 0', + ); + + $_SERVER['REMOTE_USER'] = 'eve'; + + saveWikiText('secret:medias', '[[doku>wiki:dokuwiki|{{wiki:secretlogo.png}}]]', 'Test initialization'); + idx_addPage('secret:medias'); + + $this->assertEquals(array(), ft_mediause('wiki:secretlogo.png')); + $this->assertEquals(array(), ft_mediause('wiki:secretlogo.png', false)); + $this->assertEquals(array('secret:medias'), ft_mediause('wiki:secretlogo.png', true)); + } + + public function test_media_in_deleted_pages() { + saveWikiText('test:internalmedia_usage', '{{internalmedia.png}} {{..:internal media.png}}', 'Test initialization'); + idx_addPage('test:internalmedia_usage'); + saveWikiText('test:internalmedia_usage', '', 'Deleted'); + + $this->assertEquals(array(), ft_mediause('internal_media.png')); + $this->assertEquals(array(), ft_mediause('test:internalmedia.png')); + } +} diff --git a/inc/fulltext.php b/inc/fulltext.php index 1afff25dd..c03126994 100644 --- a/inc/fulltext.php +++ b/inc/fulltext.php @@ -151,42 +151,28 @@ function ft_backlinks($id, $ignore_perms = false){ /** * Returns the pages that use a given media file * - * Does a quick lookup with the fulltext index, then - * evaluates the instructions of the found pages + * Uses the relation media metadata property and the metadata index. * - * Aborts after $max found results + * Note that before 2013-07-31 the second parameter was the maximum number of results and + * permissions were ignored. That's why the parameter is now checked to be explicitely set + * to true (with type bool) in order to be compatible with older uses of the function. + * + * @param string $id The media id to look for + * @param bool $ignore_perms Ignore hidden pages and acls (optional, default: false) + * @return array A list of pages that use the given media file */ -function ft_mediause($id,$max){ - if(!$max) $max = 1; // need to find at least one +function ft_mediause($id, $ignore_perms = false){ + $result = idx_get_indexer()->lookupKey('relation_media', $id); - $result = array(); + if(!count($result)) return $result; - // quick lookup of the mediafile - // FIXME use metadata key lookup - $media = noNS($id); - $matches = idx_lookup(idx_tokenizer($media)); - $docs = array_keys(ft_resultCombine(array_values($matches))); - if(!count($docs)) return $result; - - // go through all found pages - $found = 0; - $pcre = preg_quote($media,'/'); - foreach($docs as $doc){ - $ns = getNS($doc); - preg_match_all('/\{\{([^|}]*'.$pcre.'[^|}]*)(|[^}]+)?\}\}/i',rawWiki($doc),$matches); - foreach($matches[1] as $img){ - $img = trim($img); - if(media_isexternal($img)) continue; // skip external images - list($img) = explode('?',$img); // remove any parameters - resolve_mediaid($ns,$img,$exists); // resolve the possibly relative img - - if($img == $id){ // we have a match - $result[] = $doc; - $found++; - break; - } + // check ACL permissions + foreach(array_keys($result) as $idx){ + if(($ignore_perms !== true && ( + isHiddenPage($result[$idx]) || auth_quickaclcheck($result[$idx]) < AUTH_READ + )) || !page_exists($result[$idx], '', false)){ + unset($result[$idx]); } - if($found >= $max) break; } sort($result); diff --git a/inc/indexer.php b/inc/indexer.php index 2f3ab25dc..8f0ba7ec6 100644 --- a/inc/indexer.php +++ b/inc/indexer.php @@ -10,7 +10,7 @@ if(!defined('DOKU_INC')) die('meh.'); // Version tag used to force rebuild on upgrade -define('INDEXER_VERSION', 5); +define('INDEXER_VERSION', 6); // set the minimum token length to use in the index (note, this doesn't apply to numeric tokens) if (!defined('IDX_MINWORDLENGTH')) define('IDX_MINWORDLENGTH',2); @@ -1365,6 +1365,12 @@ function idx_addPage($page, $verbose=false, $force=false) { $metadata['relation_references'] = array_keys($references); else $metadata['relation_references'] = array(); + + if (($media = p_get_metadata($page, 'relation media', METADATA_RENDER_UNLIMITED)) !== null) + $metadata['relation_media'] = array_keys($media); + else + $metadata['relation_media'] = array(); + $data = compact('page', 'body', 'metadata', 'pid'); $evt = new Doku_Event('INDEXER_PAGE_ADD', $data); if ($evt->advise_before()) $data['body'] = $data['body'] . " " . rawWiki($page); diff --git a/inc/media.php b/inc/media.php index fbe1363ec..c76f2986c 100644 --- a/inc/media.php +++ b/inc/media.php @@ -178,7 +178,7 @@ function media_inuse($id) { global $conf; $mediareferences = array(); if($conf['refcheck']){ - $mediareferences = ft_mediause($id,$conf['refshow']); + $mediareferences = ft_mediause($id,true); if(!count($mediareferences)) { return false; } else { diff --git a/inc/parser/metadata.php b/inc/parser/metadata.php index e17b82f8b..d64fe4d77 100644 --- a/inc/parser/metadata.php +++ b/inc/parser/metadata.php @@ -282,8 +282,10 @@ class Doku_Renderer_metadata extends Doku_Renderer { function internallink($id, $name = NULL){ global $ID; - if(is_array($name)) + if(is_array($name)) { $this->_firstimage($name['src']); + if ($name['type'] == 'internalmedia') $this->_recordMediaUsage($name['src']); + } $default = $this->_simpleTitle($id); @@ -304,8 +306,10 @@ class Doku_Renderer_metadata extends Doku_Renderer { } function externallink($url, $name = NULL){ - if(is_array($name)) + if(is_array($name)) { $this->_firstimage($name['src']); + if ($name['type'] == 'internalmedia') $this->_recordMediaUsage($name['src']); + } if ($this->capture){ $this->doc .= $this->_getLinkTitle($name, '<' . $url . '>'); @@ -313,8 +317,10 @@ class Doku_Renderer_metadata extends Doku_Renderer { } function interwikilink($match, $name = NULL, $wikiName, $wikiUri){ - if(is_array($name)) + if(is_array($name)) { $this->_firstimage($name['src']); + if ($name['type'] == 'internalmedia') $this->_recordMediaUsage($name['src']); + } if ($this->capture){ list($wikiUri, $hash) = explode('#', $wikiUri, 2); @@ -324,8 +330,10 @@ class Doku_Renderer_metadata extends Doku_Renderer { } function windowssharelink($url, $name = NULL){ - if(is_array($name)) + if(is_array($name)) { $this->_firstimage($name['src']); + if ($name['type'] == 'internalmedia') $this->_recordMediaUsage($name['src']); + } if ($this->capture){ if ($name) $this->doc .= $name; @@ -334,8 +342,10 @@ class Doku_Renderer_metadata extends Doku_Renderer { } function emaillink($address, $name = NULL){ - if(is_array($name)) + if(is_array($name)) { $this->_firstimage($name['src']); + if ($name['type'] == 'internalmedia') $this->_recordMediaUsage($name['src']); + } if ($this->capture){ if ($name) $this->doc .= $name; @@ -347,6 +357,7 @@ class Doku_Renderer_metadata extends Doku_Renderer { $height=NULL, $cache=NULL, $linking=NULL){ if ($this->capture && $title) $this->doc .= '['.$title.']'; $this->_firstimage($src); + $this->_recordMediaUsage($src); } function externalmedia($src, $title=NULL, $align=NULL, $width=NULL, @@ -439,6 +450,15 @@ class Doku_Renderer_metadata extends Doku_Renderer { $this->firstimage = $src; } } + + function _recordMediaUsage($src) { + global $ID; + + list ($src, $hash) = explode('#', $src, 2); + if (media_isexternal($src)) return; + resolve_mediaid(getNS($ID), $src, $exists); + $this->meta['relation']['media'][$src] = $exists; + } } //Setup VIM: ex: et ts=4 : -- cgit v1.2.3 From 3e7e02779454686e1c639eb366a195bd1ab50458 Mon Sep 17 00:00:00 2001 From: Michael Hamann Date: Wed, 31 Jul 2013 17:57:58 +0200 Subject: Remove search_references() and the refshow configuration option The refshow configuration option wasn't used as described anymore already in the latest release and after the introduction of the media usage index the parameter is also no longer relevant for internal optimization. The only place where it was still used is the no longer used search_references()-function which is removed here, too. --- conf/dokuwiki.php | 1 - inc/search.php | 39 ------------------------- lib/plugins/config/lang/ar/lang.php | 1 - lib/plugins/config/lang/bg/lang.php | 1 - lib/plugins/config/lang/ca-valencia/lang.php | 1 - lib/plugins/config/lang/ca/lang.php | 1 - lib/plugins/config/lang/cs/lang.php | 1 - lib/plugins/config/lang/da/lang.php | 1 - lib/plugins/config/lang/de-informal/lang.php | 1 - lib/plugins/config/lang/de/lang.php | 1 - lib/plugins/config/lang/el/lang.php | 1 - lib/plugins/config/lang/en/lang.php | 1 - lib/plugins/config/lang/eo/lang.php | 1 - lib/plugins/config/lang/es/lang.php | 1 - lib/plugins/config/lang/eu/lang.php | 1 - lib/plugins/config/lang/fa/lang.php | 1 - lib/plugins/config/lang/fi/lang.php | 1 - lib/plugins/config/lang/fr/lang.php | 1 - lib/plugins/config/lang/gl/lang.php | 1 - lib/plugins/config/lang/he/lang.php | 1 - lib/plugins/config/lang/hu/lang.php | 1 - lib/plugins/config/lang/ia/lang.php | 1 - lib/plugins/config/lang/it/lang.php | 1 - lib/plugins/config/lang/ja/lang.php | 1 - lib/plugins/config/lang/ko/lang.php | 1 - lib/plugins/config/lang/la/lang.php | 1 - lib/plugins/config/lang/lv/lang.php | 1 - lib/plugins/config/lang/mr/lang.php | 1 - lib/plugins/config/lang/nl/lang.php | 1 - lib/plugins/config/lang/no/lang.php | 1 - lib/plugins/config/lang/pl/lang.php | 1 - lib/plugins/config/lang/pt-br/lang.php | 1 - lib/plugins/config/lang/pt/lang.php | 1 - lib/plugins/config/lang/ro/lang.php | 1 - lib/plugins/config/lang/ru/lang.php | 1 - lib/plugins/config/lang/sk/lang.php | 1 - lib/plugins/config/lang/sl/lang.php | 1 - lib/plugins/config/lang/sq/lang.php | 1 - lib/plugins/config/lang/sr/lang.php | 1 - lib/plugins/config/lang/sv/lang.php | 1 - lib/plugins/config/lang/tr/lang.php | 1 - lib/plugins/config/lang/uk/lang.php | 1 - lib/plugins/config/lang/zh-tw/lang.php | 1 - lib/plugins/config/lang/zh/lang.php | 1 - lib/plugins/config/settings/config.metadata.php | 1 - 45 files changed, 83 deletions(-) diff --git a/conf/dokuwiki.php b/conf/dokuwiki.php index f5524de6b..bdc9739d1 100644 --- a/conf/dokuwiki.php +++ b/conf/dokuwiki.php @@ -96,7 +96,6 @@ $conf['target']['windows'] = ''; /* Media Settings */ $conf['mediarevisions'] = 1; //enable/disable media revisions $conf['refcheck'] = 1; //check for references before deleting media files -$conf['refshow'] = 0; //how many references should be shown, 5 is a good value $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) diff --git a/inc/search.php b/inc/search.php index 6927fff5f..884aa7b23 100644 --- a/inc/search.php +++ b/inc/search.php @@ -273,45 +273,6 @@ function search_allpages(&$data,$base,$file,$type,$lvl,$opts){ return true; } -/** - * Reference search - * This fuction searches for existing references to a given media file - * and returns an array with the found pages. It doesn't pay any - * attention to ACL permissions to find every reference. The caller - * must check if the user has the appropriate rights to see the found - * page and eventually have to prevent the result from displaying. - * - * @param array $data Reference to the result data structure - * @param string $base Base usually $conf['datadir'] - * @param string $file current file or directory relative to $base - * @param char $type Type either 'd' for directory or 'f' for file - * @param int $lvl Current recursion depht - * @param mixed $opts option array as given to search() - * - * $opts['query'] is the demanded media file name - * - * @author Andreas Gohr - * @author Matthias Grimm - */ -function search_reference(&$data,$base,$file,$type,$lvl,$opts){ - global $conf; - - //we do nothing with directories - if($type == 'd') return true; - - //only search txt files - if(substr($file,-4) != '.txt') return true; - - //we finish after 'cnt' references found. The return value - //'false' will skip subdirectories to speed search up. - $cnt = $conf['refshow'] > 0 ? $conf['refshow'] : 1; - if(count($data) >= $cnt) return false; - - $reg = '\{\{ *\:?'.$opts['query'].' *(\|.*)?\}\}'; - search_regex($data,$base,$file,$reg,array($opts['query'])); - return true; -} - /* ------------- helper functions below -------------- */ /** diff --git a/lib/plugins/config/lang/ar/lang.php b/lib/plugins/config/lang/ar/lang.php index 76c155812..11b59dacd 100644 --- a/lib/plugins/config/lang/ar/lang.php +++ b/lib/plugins/config/lang/ar/lang.php @@ -104,7 +104,6 @@ $lang['target____media'] = 'النافذة الهدف لروابط الو $lang['target____windows'] = 'النافذة الهدف لروابط النوافذ'; $lang['mediarevisions'] = 'تفعيل إصدارات الوسائط؟'; $lang['refcheck'] = 'التحقق من مرجع الوسائط'; -$lang['refshow'] = 'عدد مراجع الوسائط لتعرض'; $lang['gdlib'] = 'اصدار مكتبة GD'; $lang['im_convert'] = 'المسار إلى اداة تحويل ImageMagick'; $lang['jpg_quality'] = 'دقة ضغط JPG (0-100)'; diff --git a/lib/plugins/config/lang/bg/lang.php b/lib/plugins/config/lang/bg/lang.php index 43c961bfc..1a370eafe 100644 --- a/lib/plugins/config/lang/bg/lang.php +++ b/lib/plugins/config/lang/bg/lang.php @@ -136,7 +136,6 @@ $lang['target____windows'] = 'Прозорец за препратки към /* Media Settings */ $lang['mediarevisions'] = 'Да се пазят ли стари версии на качените файлове (Mediarevisions)?'; $lang['refcheck'] = 'Проверка за препратка към медия, преди да бъде изтрита'; -$lang['refshow'] = 'Брой на показваните медийни препратки'; $lang['gdlib'] = 'Версия на GD Lib'; $lang['im_convert'] = 'Път до инструмента за трансформация на ImageMagick'; $lang['jpg_quality'] = 'Качество на JPG компресията (0-100)'; diff --git a/lib/plugins/config/lang/ca-valencia/lang.php b/lib/plugins/config/lang/ca-valencia/lang.php index 4a8c10895..dd319bdb7 100644 --- a/lib/plugins/config/lang/ca-valencia/lang.php +++ b/lib/plugins/config/lang/ca-valencia/lang.php @@ -62,7 +62,6 @@ $lang['camelcase'] = 'Utilisar CamelCase per als vínculs'; $lang['deaccent'] = 'Depurar els noms de pàgines'; $lang['useheading'] = 'Utilisar el primer titular per al nom de pàgina'; $lang['refcheck'] = 'Comprovar referències a mijos'; -$lang['refshow'] = 'Número de referències a mijos a mostrar'; $lang['allowdebug'] = 'Permetre depurar (¡desactivar quan no es necessite!)'; $lang['usewordblock'] = 'Bloquejar spam basant-se en una llista de paraules'; $lang['indexdelay'] = 'Retart abans d\'indexar (seg.)'; diff --git a/lib/plugins/config/lang/ca/lang.php b/lib/plugins/config/lang/ca/lang.php index 205d7aa6b..6de8caf02 100644 --- a/lib/plugins/config/lang/ca/lang.php +++ b/lib/plugins/config/lang/ca/lang.php @@ -102,7 +102,6 @@ $lang['target____extern'] = 'Finestra de destinació en enllaços externs'; $lang['target____media'] = 'Finestra de destinació en enllaços de mitjans'; $lang['target____windows'] = 'Finestra de destinació en enllaços de Windows'; $lang['refcheck'] = 'Comprova la referència en els fitxers de mitjans'; -$lang['refshow'] = 'Nombre de referències de mitjans per mostrar'; $lang['gdlib'] = 'Versió GD Lib'; $lang['im_convert'] = 'Camí de la utilitat convert d\'ImageMagick'; $lang['jpg_quality'] = 'Qualitat de compressió JPEG (0-100)'; diff --git a/lib/plugins/config/lang/cs/lang.php b/lib/plugins/config/lang/cs/lang.php index d35ebec9b..921abb54a 100644 --- a/lib/plugins/config/lang/cs/lang.php +++ b/lib/plugins/config/lang/cs/lang.php @@ -119,7 +119,6 @@ $lang['target____media'] = 'Cílové okno pro odkazy na média'; $lang['target____windows'] = 'Cílové okno pro odkazy na windows sdílení'; $lang['mediarevisions'] = 'Aktivovat revize souborů'; $lang['refcheck'] = 'Kontrolovat odkazy na média (před vymazáním)'; -$lang['refshow'] = 'Počet zobrazených odkazů na média'; $lang['gdlib'] = 'Verze GD knihovny'; $lang['im_convert'] = 'Cesta k nástroji convert z balíku ImageMagick'; $lang['jpg_quality'] = 'Kvalita komprese JPEG (0-100)'; diff --git a/lib/plugins/config/lang/da/lang.php b/lib/plugins/config/lang/da/lang.php index 239a4986f..79d8dc852 100644 --- a/lib/plugins/config/lang/da/lang.php +++ b/lib/plugins/config/lang/da/lang.php @@ -110,7 +110,6 @@ $lang['target____media'] = 'Målvindue for mediehenvisninger'; $lang['target____windows'] = 'Målvindue til Windows-henvisninger'; $lang['mediarevisions'] = 'Akvtivér media udgaver?'; $lang['refcheck'] = 'Mediehenvisningerkontrol'; -$lang['refshow'] = 'Antal viste mediehenvisninger'; $lang['gdlib'] = 'Udgave af GD Lib'; $lang['im_convert'] = 'Sti til ImageMagick\'s omdannerværktøj'; $lang['jpg_quality'] = 'JPG komprimeringskvalitet (0-100)'; diff --git a/lib/plugins/config/lang/de-informal/lang.php b/lib/plugins/config/lang/de-informal/lang.php index 10fa363dc..81cdc0e70 100644 --- a/lib/plugins/config/lang/de-informal/lang.php +++ b/lib/plugins/config/lang/de-informal/lang.php @@ -108,7 +108,6 @@ $lang['target____media'] = 'Zielfenstername für Medienlinks'; $lang['target____windows'] = 'Zielfenstername für Windows-Freigaben-Links'; $lang['mediarevisions'] = 'Media-Revisionen (ältere Versionen) aktivieren?'; $lang['refcheck'] = 'Auf Verwendung beim Löschen von Media-Dateien testen'; -$lang['refshow'] = 'Wie viele Verwendungsorte der Media-Datei zeigen'; $lang['gdlib'] = 'GD Lib Version'; $lang['im_convert'] = 'Pfad zu ImageMagicks-Konvertierwerkzeug'; $lang['jpg_quality'] = 'JPEG Kompressionsqualität (0-100)'; diff --git a/lib/plugins/config/lang/de/lang.php b/lib/plugins/config/lang/de/lang.php index dd29f8038..f2ada5f7b 100644 --- a/lib/plugins/config/lang/de/lang.php +++ b/lib/plugins/config/lang/de/lang.php @@ -78,7 +78,6 @@ $lang['camelcase'] = 'CamelCase-Verlinkungen verwenden'; $lang['deaccent'] = 'Seitennamen bereinigen'; $lang['useheading'] = 'Erste Überschrift als Seitennamen verwenden'; $lang['refcheck'] = 'Auf Verwendung beim Löschen von Media-Dateien testen'; -$lang['refshow'] = 'Wiev iele Verwendungsorte der Media-Datei zeigen'; $lang['allowdebug'] = 'Debug-Ausgaben erlauben Abschalten wenn nicht benötigt!'; $lang['mediarevisions'] = 'Media-Revisionen (ältere Versionen) aktivieren?'; $lang['usewordblock'] = 'Spam-Blocking benutzen'; diff --git a/lib/plugins/config/lang/el/lang.php b/lib/plugins/config/lang/el/lang.php index d2801e507..e766c1a4c 100644 --- a/lib/plugins/config/lang/el/lang.php +++ b/lib/plugins/config/lang/el/lang.php @@ -111,7 +111,6 @@ $lang['target____media'] = 'Παράθυρο-στόχος για συνδ $lang['target____windows'] = 'Παράθυρο-στόχος για συνδέσμους σε Windows shares'; $lang['mediarevisions'] = 'Ενεργοποίηση Mediarevisions;'; $lang['refcheck'] = 'Πριν τη διαγραφή ενός αρχείου να ελέγχεται η ύπαρξη σελίδων που το χρησιμοποιούν'; -$lang['refshow'] = 'Εμφανιζόμενος αριθμός σελίδων που χρησιμοποιούν ένα αρχείο'; $lang['gdlib'] = 'Έκδοση βιβλιοθήκης GD'; $lang['im_convert'] = 'Διαδρομή προς το εργαλείο μετατροπής εικόνων του ImageMagick'; $lang['jpg_quality'] = 'Ποιότητα συμπίεσης JPG (0-100)'; diff --git a/lib/plugins/config/lang/en/lang.php b/lib/plugins/config/lang/en/lang.php index 83c843b3a..2d012701b 100644 --- a/lib/plugins/config/lang/en/lang.php +++ b/lib/plugins/config/lang/en/lang.php @@ -134,7 +134,6 @@ $lang['target____windows'] = 'Target window for windows links'; /* Media Settings */ $lang['mediarevisions'] = 'Enable Mediarevisions?'; $lang['refcheck'] = 'Check if a media file is still in use before deleting it'; -$lang['refshow'] = 'Number of media references to show when the above setting is enabled'; $lang['gdlib'] = 'GD Lib version'; $lang['im_convert'] = 'Path to ImageMagick\'s convert tool'; $lang['jpg_quality'] = 'JPG compression quality (0-100)'; diff --git a/lib/plugins/config/lang/eo/lang.php b/lib/plugins/config/lang/eo/lang.php index 36f865c28..b3300c1b5 100644 --- a/lib/plugins/config/lang/eo/lang.php +++ b/lib/plugins/config/lang/eo/lang.php @@ -108,7 +108,6 @@ $lang['target____media'] = 'Parametro "target" (celo) por aŭdvidaĵaj lig $lang['target____windows'] = 'Parametro "target" (celo) por Vindozaj ligiloj'; $lang['mediarevisions'] = 'Ĉu ebligi reviziadon de aŭdvidaĵoj?'; $lang['refcheck'] = 'Kontrolo por referencoj al aŭdvidaĵoj'; -$lang['refshow'] = 'Nombro da referencoj al aŭdvidaĵoj por montri'; $lang['gdlib'] = 'Versio de GD-Lib'; $lang['im_convert'] = 'Pado al la konvertilo de ImageMagick'; $lang['jpg_quality'] = 'Kompaktiga kvalito de JPG (0-100)'; diff --git a/lib/plugins/config/lang/es/lang.php b/lib/plugins/config/lang/es/lang.php index 5d03efb60..3a2db95b8 100644 --- a/lib/plugins/config/lang/es/lang.php +++ b/lib/plugins/config/lang/es/lang.php @@ -121,7 +121,6 @@ $lang['target____media'] = 'Ventana para enlaces a medios'; $lang['target____windows'] = 'Ventana para enlaces a ventanas'; $lang['mediarevisions'] = '¿Habilitar Mediarevisions?'; $lang['refcheck'] = 'Control de referencia a medios'; -$lang['refshow'] = 'Número de referencias a medios a mostrar'; $lang['gdlib'] = 'Versión de GD Lib'; $lang['im_convert'] = 'Ruta a la herramienta de conversión de ImageMagick'; $lang['jpg_quality'] = 'Calidad de compresión de JPG (0-100)'; diff --git a/lib/plugins/config/lang/eu/lang.php b/lib/plugins/config/lang/eu/lang.php index 4dd3ff351..280e57df9 100644 --- a/lib/plugins/config/lang/eu/lang.php +++ b/lib/plugins/config/lang/eu/lang.php @@ -97,7 +97,6 @@ $lang['target____media'] = 'Multimedia estekentzat helburu leihoa'; $lang['target____windows'] = 'Leihoen estekentzat helburu leihoa'; $lang['mediarevisions'] = 'Media rebisioak gaitu?'; $lang['refcheck'] = 'Multimedia erreferentzia kontrolatu'; -$lang['refshow'] = 'Erakusteko multimedia erreferentzia kopurua'; $lang['gdlib'] = 'GD Lib bertsioa'; $lang['im_convert'] = 'ImageMagick-en aldaketa tresnara bidea'; $lang['jpg_quality'] = 'JPG konprimitze kalitatea (0-100)'; diff --git a/lib/plugins/config/lang/fa/lang.php b/lib/plugins/config/lang/fa/lang.php index 34c76780c..229fe012e 100644 --- a/lib/plugins/config/lang/fa/lang.php +++ b/lib/plugins/config/lang/fa/lang.php @@ -106,7 +106,6 @@ $lang['target____media'] = 'پنجره‌ی هدف در پیوند‌ها $lang['target____windows'] = 'پنجره‌ی هدف در پیوند‌های پنجره‌ای'; $lang['mediarevisions'] = 'تجدید نظر رسانه ، فعال؟'; $lang['refcheck'] = 'بررسی کردن مرجع رسانه‌ها'; -$lang['refshow'] = 'تعداد مراجعی که برای یک رسانه نمایش داده شود'; $lang['gdlib'] = 'نگارش کتاب‌خانه‌ی GD'; $lang['im_convert'] = 'مسیر ابزار convert از برنامه‌ی ImageMagick'; $lang['jpg_quality'] = 'کیفیت فشرده سازی JPEG (از 0 تا 100)'; diff --git a/lib/plugins/config/lang/fi/lang.php b/lib/plugins/config/lang/fi/lang.php index 990852f99..a5075d2cf 100644 --- a/lib/plugins/config/lang/fi/lang.php +++ b/lib/plugins/config/lang/fi/lang.php @@ -105,7 +105,6 @@ $lang['target____media'] = 'Kohdeikkuna media-linkeissä'; $lang['target____windows'] = 'Kohdeikkuna Windows-linkeissä'; $lang['mediarevisions'] = 'Otetaan käyttään Media-versiointi'; $lang['refcheck'] = 'Mediaviitteen tarkistus'; -$lang['refshow'] = 'Montako mediaviitettä näytetään'; $lang['gdlib'] = 'GD Lib versio'; $lang['im_convert'] = 'ImageMagick-muunnostyökalun polku'; $lang['jpg_quality'] = 'JPG pakkauslaatu (0-100)'; diff --git a/lib/plugins/config/lang/fr/lang.php b/lib/plugins/config/lang/fr/lang.php index f9e89f603..a7b3d5e3b 100644 --- a/lib/plugins/config/lang/fr/lang.php +++ b/lib/plugins/config/lang/fr/lang.php @@ -118,7 +118,6 @@ $lang['target____media'] = 'Cible pour liens média'; $lang['target____windows'] = 'Cible pour liens vers partages Windows'; $lang['mediarevisions'] = 'Activer les révisions (gestion de versions) des médias'; $lang['refcheck'] = 'Vérifier si un média est toujours utilisé avant de le supprimer'; -$lang['refshow'] = 'Nombre de références de média à montrer lorsque le paramètre précédent est actif'; $lang['gdlib'] = 'Version de la librairie GD'; $lang['im_convert'] = 'Chemin vers l\'outil de conversion ImageMagick'; $lang['jpg_quality'] = 'Qualité de la compression JPEG (0-100)'; diff --git a/lib/plugins/config/lang/gl/lang.php b/lib/plugins/config/lang/gl/lang.php index 21fe17452..0dafd9271 100644 --- a/lib/plugins/config/lang/gl/lang.php +++ b/lib/plugins/config/lang/gl/lang.php @@ -104,7 +104,6 @@ $lang['target____media'] = 'Fiestra de destino para as ligazóns de media' $lang['target____windows'] = 'Fiestra de destino para as ligazóns de fiestras'; $lang['mediarevisions'] = 'Habilitar revisións dos arquivos-media?'; $lang['refcheck'] = 'Comprobar a referencia media'; -$lang['refshow'] = 'Número de referencias media a amosar'; $lang['gdlib'] = 'Versión da Libraría GD'; $lang['im_convert'] = 'Ruta deica a ferramenta de conversión ImageMagick'; $lang['jpg_quality'] = 'Calidade de compresión dos JPG (0-100)'; diff --git a/lib/plugins/config/lang/he/lang.php b/lib/plugins/config/lang/he/lang.php index b200082c9..687072764 100644 --- a/lib/plugins/config/lang/he/lang.php +++ b/lib/plugins/config/lang/he/lang.php @@ -60,7 +60,6 @@ $lang['camelcase'] = 'השתמש בראשיות גדולות לקי $lang['deaccent'] = 'נקה שמות דפים'; $lang['useheading'] = 'השתמש בכותרת הראשונה לשם הדף'; $lang['refcheck'] = 'בדוק שיוך מדיה'; -$lang['refshow'] = 'מספר שיוכי המדיה שיוצגו'; $lang['allowdebug'] = 'אפשר דיבוג יש לבטל אם אין צורך!'; $lang['usewordblock'] = 'חסימת דואר זבל לפי רשימת מילים'; $lang['indexdelay'] = 'השהיה בטרם הכנסה לאינדקס (שניות)'; diff --git a/lib/plugins/config/lang/hu/lang.php b/lib/plugins/config/lang/hu/lang.php index c68cf4337..6c47e09a3 100644 --- a/lib/plugins/config/lang/hu/lang.php +++ b/lib/plugins/config/lang/hu/lang.php @@ -108,7 +108,6 @@ $lang['target____media'] = 'Cél-ablak média-fájl hivatkozásokhoz'; $lang['target____windows'] = 'Cél-ablak Windows hivatkozásokhoz'; $lang['mediarevisions'] = 'Médiafájlok verziókövetésének engedélyezése'; $lang['refcheck'] = 'Médiafájlok hivatkozásainak ellenőrzése'; -$lang['refshow'] = 'Médiafájlok hivatkozásainak maximálisan mutatott szintje'; $lang['gdlib'] = 'GD Lib verzió'; $lang['im_convert'] = 'Útvonal az ImageMagick csomag convert parancsához'; $lang['jpg_quality'] = 'JPG tömörítés minősége (0-100)'; diff --git a/lib/plugins/config/lang/ia/lang.php b/lib/plugins/config/lang/ia/lang.php index fdb9d954e..1f4e881bb 100644 --- a/lib/plugins/config/lang/ia/lang.php +++ b/lib/plugins/config/lang/ia/lang.php @@ -59,7 +59,6 @@ $lang['camelcase'] = 'Usar CamelCase pro ligamines'; $lang['deaccent'] = 'Nomines nette de paginas'; $lang['useheading'] = 'Usar le prime titulo como nomine de pagina'; $lang['refcheck'] = 'Verification de referentias multimedia'; -$lang['refshow'] = 'Numero de referentias multimedia a monstrar'; $lang['allowdebug'] = 'Permitter debugging disactiva si non necessari!'; $lang['usewordblock'] = 'Blocar spam a base de lista de parolas'; $lang['indexdelay'] = 'Retardo ante generation de indice (secundas)'; diff --git a/lib/plugins/config/lang/it/lang.php b/lib/plugins/config/lang/it/lang.php index 62dd00f0c..d2272075a 100644 --- a/lib/plugins/config/lang/it/lang.php +++ b/lib/plugins/config/lang/it/lang.php @@ -114,7 +114,6 @@ $lang['target____media'] = 'Finestra di destinazione per i collegamenti ai $lang['target____windows'] = 'Finestra di destinazione per i collegamenti alle risorse condivise'; $lang['mediarevisions'] = 'Abilita Mediarevisions?'; $lang['refcheck'] = 'Controlla i riferimenti ai file'; -$lang['refshow'] = 'Numero di riferimenti da visualizzare'; $lang['gdlib'] = 'Versione GD Lib '; $lang['im_convert'] = 'Percorso per il convertitore di ImageMagick'; $lang['jpg_quality'] = 'Qualità di compressione JPG (0-100)'; diff --git a/lib/plugins/config/lang/ja/lang.php b/lib/plugins/config/lang/ja/lang.php index 807436cca..15eadf731 100644 --- a/lib/plugins/config/lang/ja/lang.php +++ b/lib/plugins/config/lang/ja/lang.php @@ -109,7 +109,6 @@ $lang['target____media'] = 'メディアリンクの表示先'; $lang['target____windows'] = 'Windowsリンクの表示先'; $lang['mediarevisions'] = 'メディアファイルの履歴を有効にしますか?'; $lang['refcheck'] = 'メディア参照元チェック'; -$lang['refshow'] = 'メディア参照元表示数'; $lang['gdlib'] = 'GDlibバージョン'; $lang['im_convert'] = 'ImageMagick変換ツールへのパス'; $lang['jpg_quality'] = 'JPG圧縮品質(0-100)'; diff --git a/lib/plugins/config/lang/ko/lang.php b/lib/plugins/config/lang/ko/lang.php index f0f7f60fa..74fe3d8a0 100644 --- a/lib/plugins/config/lang/ko/lang.php +++ b/lib/plugins/config/lang/ko/lang.php @@ -109,7 +109,6 @@ $lang['target____media'] = '미디어 링크에 대한 타겟 창'; $lang['target____windows'] = '창 링크에 대한 타겟 창'; $lang['mediarevisions'] = '미디어 판 관리를 사용하겠습니까?'; $lang['refcheck'] = '미디어 파일을 삭제하기 전에 사용하고 있는지 검사'; -$lang['refshow'] = '위의 설정이 활성화되었을 때 보여줄 미디어 참고 수'; $lang['gdlib'] = 'GD 라이브러리 버전'; $lang['im_convert'] = 'ImageMagick 변환 도구 위치'; $lang['jpg_quality'] = 'JPG 압축 품질 (0-100)'; diff --git a/lib/plugins/config/lang/la/lang.php b/lib/plugins/config/lang/la/lang.php index 057e69974..2aff60753 100644 --- a/lib/plugins/config/lang/la/lang.php +++ b/lib/plugins/config/lang/la/lang.php @@ -58,7 +58,6 @@ $lang['camelcase'] = 'SignaContinua nexis apta facere'; $lang['deaccent'] = 'Titulus paginarum abrogare'; $lang['useheading'] = 'Capite primo ut titulo paginae uti'; $lang['refcheck'] = 'Documenta uisiua inspicere'; -$lang['refshow'] = 'Numerus documentorum ostendorum'; $lang['allowdebug'] = 'ineptum facias si non necessarium! aptum facere'; $lang['usewordblock'] = 'Malum interretiale ob uerba delere'; $lang['indexdelay'] = 'Tempus transitum in ordinando (sec)'; diff --git a/lib/plugins/config/lang/lv/lang.php b/lib/plugins/config/lang/lv/lang.php index 3adfd1871..7fcf0fa45 100644 --- a/lib/plugins/config/lang/lv/lang.php +++ b/lib/plugins/config/lang/lv/lang.php @@ -95,7 +95,6 @@ $lang['target____extern'] = 'Kur atvērt ārējās saites'; $lang['target____media'] = 'Kur atvērt mēdiju saites'; $lang['target____windows'] = 'Kur atvērt saites uz tīkla mapēm'; $lang['refcheck'] = 'Pārbaudīt saites uz mēdiju failiem'; -$lang['refshow'] = 'Cik saites uz mēdiju failiem rādīt'; $lang['gdlib'] = 'GD Lib versija'; $lang['im_convert'] = 'Ceļš uz ImageMagick convert rīku'; $lang['jpg_quality'] = 'JPG saspiešanas kvalitāte'; diff --git a/lib/plugins/config/lang/mr/lang.php b/lib/plugins/config/lang/mr/lang.php index 4f33bfa7c..deef82690 100644 --- a/lib/plugins/config/lang/mr/lang.php +++ b/lib/plugins/config/lang/mr/lang.php @@ -62,7 +62,6 @@ $lang['camelcase'] = 'लिंकसाठी कॅमलकेस $lang['deaccent'] = 'सरळ्सोट पृष्ठ नाम'; $lang['useheading'] = 'पहिलं शीर्षक पृष्ठ नाम म्हणुन वापरा'; $lang['refcheck'] = 'दृक्श्राव्य माध्यमाचा संदर्भ तपासा'; -$lang['refshow'] = 'दृक्श्राव्य माध्यामाचे संदर्भ दाखवण्याची संख्या'; $lang['allowdebug'] = 'डिबगची परवानगी गरज नसल्यास बंद ठेवा !'; $lang['usewordblock'] = 'भंकस मजकूर थोपवण्यासाठी शब्दसमुह वापरा'; $lang['indexdelay'] = 'सूचीकरणापूर्वीचा अवकाश ( सेकंदात )'; diff --git a/lib/plugins/config/lang/nl/lang.php b/lib/plugins/config/lang/nl/lang.php index 26ea3d8c1..9aa17c23d 100644 --- a/lib/plugins/config/lang/nl/lang.php +++ b/lib/plugins/config/lang/nl/lang.php @@ -113,7 +113,6 @@ $lang['target____media'] = 'Doelvenster voor medialinks'; $lang['target____windows'] = 'Doelvenster voor windows links'; $lang['mediarevisions'] = 'Mediarevisies activeren?'; $lang['refcheck'] = 'Controleer of er verwijzingen bestaan naar een mediabestand voor het wijderen'; -$lang['refshow'] = 'Aantal te tonen mediaverwijzingen'; $lang['gdlib'] = 'Versie GD Lib '; $lang['im_convert'] = 'Path naar ImageMagick\'s convert tool'; $lang['jpg_quality'] = 'JPG compressiekwaliteit (0-100)'; diff --git a/lib/plugins/config/lang/no/lang.php b/lib/plugins/config/lang/no/lang.php index b01637dd1..c049c643a 100644 --- a/lib/plugins/config/lang/no/lang.php +++ b/lib/plugins/config/lang/no/lang.php @@ -76,7 +76,6 @@ $lang['camelcase'] = 'Gjør KamelKasse til lenke automatisk'; $lang['deaccent'] = 'Rensk sidenavn'; $lang['useheading'] = 'Bruk første overskrift som tittel'; $lang['refcheck'] = 'Sjekk referanser før mediafiler slettes'; -$lang['refshow'] = 'Antall viste referanser til mediafiler'; $lang['allowdebug'] = 'Tillat feilsøking skru av om det ikke behøves!'; $lang['mediarevisions'] = 'Slå på mediaversjonering?'; $lang['usewordblock'] = 'Blokker søppel basert på ordliste'; diff --git a/lib/plugins/config/lang/pl/lang.php b/lib/plugins/config/lang/pl/lang.php index 8441722cd..ede824d75 100644 --- a/lib/plugins/config/lang/pl/lang.php +++ b/lib/plugins/config/lang/pl/lang.php @@ -112,7 +112,6 @@ $lang['target____media'] = 'Okno docelowe odnośników do plików'; $lang['target____windows'] = 'Okno docelowe odnośników zasobów Windows'; $lang['mediarevisions'] = 'Włączyć wersjonowanie multimediów?'; $lang['refcheck'] = 'Sprawdzanie odwołań przed usunięciem pliku'; -$lang['refshow'] = 'Ilość pokazywanych odwołań do pliku'; $lang['gdlib'] = 'Wersja biblioteki GDLib'; $lang['im_convert'] = 'Ścieżka do programu imagemagick'; $lang['jpg_quality'] = 'Jakość kompresji JPG (0-100)'; diff --git a/lib/plugins/config/lang/pt-br/lang.php b/lib/plugins/config/lang/pt-br/lang.php index 85218439a..6633ab0c4 100644 --- a/lib/plugins/config/lang/pt-br/lang.php +++ b/lib/plugins/config/lang/pt-br/lang.php @@ -116,7 +116,6 @@ $lang['target____media'] = 'Parâmetro "target" para links de mídia'; $lang['target____windows'] = 'Parâmetro "target" para links do Windows'; $lang['mediarevisions'] = 'Habilitar revisões de mídias?'; $lang['refcheck'] = 'Verificação de referência da mídia'; -$lang['refshow'] = 'Número de referências de mídia a exibir'; $lang['gdlib'] = 'Versão da biblioteca "GD Lib"'; $lang['im_convert'] = 'Caminho para a ferramenta de conversão ImageMagick'; $lang['jpg_quality'] = 'Qualidade de compressão do JPG (0-100)'; diff --git a/lib/plugins/config/lang/pt/lang.php b/lib/plugins/config/lang/pt/lang.php index d0fe0ac0d..681ff487f 100644 --- a/lib/plugins/config/lang/pt/lang.php +++ b/lib/plugins/config/lang/pt/lang.php @@ -63,7 +63,6 @@ $lang['camelcase'] = 'Usar CamelCase'; $lang['deaccent'] = 'Nomes das páginas sem acentos'; $lang['useheading'] = 'Usar o primeiro cabeçalho para o nome da página'; $lang['refcheck'] = 'Verificação de referência da media'; -$lang['refshow'] = 'Número de referências de media a exibir'; $lang['allowdebug'] = 'Permitir depuração desabilite se não for necessário!'; $lang['usewordblock'] = 'Bloquear spam baseado em lista de palavras (wordlist)'; $lang['indexdelay'] = 'Tempo de espera antes da indexação (seg)'; diff --git a/lib/plugins/config/lang/ro/lang.php b/lib/plugins/config/lang/ro/lang.php index 72b205b90..5e853f7d0 100644 --- a/lib/plugins/config/lang/ro/lang.php +++ b/lib/plugins/config/lang/ro/lang.php @@ -69,7 +69,6 @@ $lang['camelcase'] = 'Foloseşte CamelCase pentru legături'; $lang['deaccent'] = 'numedepagină curate'; $lang['useheading'] = 'Foloseşte primul titlu pentru numele paginii'; $lang['refcheck'] = 'Verificare referinţă media'; -$lang['refshow'] = 'Numărul de referinţe media de arătat'; $lang['allowdebug'] = 'Permite depanarea dezactivaţi dacă cu e necesar!'; $lang['mediarevisions'] = 'Activare Revizii Media?'; $lang['usewordblock'] = 'Blochează spam-ul pe baza listei de cuvinte'; diff --git a/lib/plugins/config/lang/ru/lang.php b/lib/plugins/config/lang/ru/lang.php index 42cbbd35a..cdafacf8f 100644 --- a/lib/plugins/config/lang/ru/lang.php +++ b/lib/plugins/config/lang/ru/lang.php @@ -115,7 +115,6 @@ $lang['target____media'] = 'target для ссылок на медиафа $lang['target____windows'] = 'target для ссылок на сетевые каталоги'; $lang['mediarevisions'] = 'Включение версий медиафайлов'; $lang['refcheck'] = 'Проверять ссылки на медиафайлы'; -$lang['refshow'] = 'Показывать ссылок на медиафайлы'; $lang['gdlib'] = 'Версия LibGD'; $lang['im_convert'] = 'Путь к ImageMagick'; $lang['jpg_quality'] = 'Качество сжатия JPG (0–100). Значение по умолчанию — 70.'; diff --git a/lib/plugins/config/lang/sk/lang.php b/lib/plugins/config/lang/sk/lang.php index 9e18b3ed9..23a60db90 100644 --- a/lib/plugins/config/lang/sk/lang.php +++ b/lib/plugins/config/lang/sk/lang.php @@ -103,7 +103,6 @@ $lang['target____media'] = 'Cieľové okno (target) pre media odkazy'; $lang['target____windows'] = 'Cieľové okno (target) pre windows odkazy'; $lang['mediarevisions'] = 'Povoliť verzie súborov?'; $lang['refcheck'] = 'Kontrolovať odkazy na médiá (pred vymazaním)'; -$lang['refshow'] = 'Počet zobrazených odkazov na médiá'; $lang['gdlib'] = 'Verzia GD Lib'; $lang['im_convert'] = 'Cesta k ImageMagick convert tool'; $lang['jpg_quality'] = 'Kvalita JPG kompresie (0-100)'; diff --git a/lib/plugins/config/lang/sl/lang.php b/lib/plugins/config/lang/sl/lang.php index 364e0fd7f..dcec62288 100644 --- a/lib/plugins/config/lang/sl/lang.php +++ b/lib/plugins/config/lang/sl/lang.php @@ -64,7 +64,6 @@ $lang['camelcase'] = 'Uporabi EnoBesedni zapisa za povezave'; $lang['deaccent'] = 'Počisti imena strani'; $lang['useheading'] = 'Uporabi prvi naslov za ime strani'; $lang['refcheck'] = 'Preverjanje sklica predstavnih datotek'; -$lang['refshow'] = 'Število predstavih sklicev za prikaz'; $lang['allowdebug'] = 'Dovoli razhroščevanje (po potrebi!)'; $lang['mediarevisions'] = 'Ali naj se omogočijo objave predstavnih vsebin?'; $lang['usewordblock'] = 'Zaustavi neželeno besedilo glede na seznam besed'; diff --git a/lib/plugins/config/lang/sq/lang.php b/lib/plugins/config/lang/sq/lang.php index 69e283b11..972b2894c 100644 --- a/lib/plugins/config/lang/sq/lang.php +++ b/lib/plugins/config/lang/sq/lang.php @@ -59,7 +59,6 @@ $lang['camelcase'] = 'Përdor CamelCase (shkronja e parë e çdo fja $lang['deaccent'] = 'Emra faqesh të pastër'; $lang['useheading'] = 'Përdor titra të nivelit të parë për faqet e emrave'; $lang['refcheck'] = 'Kontroll për referim mediash'; -$lang['refshow'] = 'Numri i referimeve të medias që duhet të tregohet'; $lang['allowdebug'] = 'Lejo debug çaktivizoje nëse nuk nevojitet!'; $lang['usewordblock'] = 'Blloko spam-in duke u bazuar mbi listë fjalësh'; $lang['indexdelay'] = 'Vonesa në kohë para index-imit (sekonda)'; diff --git a/lib/plugins/config/lang/sr/lang.php b/lib/plugins/config/lang/sr/lang.php index c675b84e6..b6d7268aa 100644 --- a/lib/plugins/config/lang/sr/lang.php +++ b/lib/plugins/config/lang/sr/lang.php @@ -60,7 +60,6 @@ $lang['camelcase'] = 'Користи CamelCase за линкове'; $lang['deaccent'] = 'Чисти имена страница'; $lang['useheading'] = 'Преузми наслов првог нивоа за назив странице'; $lang['refcheck'] = 'Провери референце медијских датотека'; -$lang['refshow'] = 'Број референци које се приказују за медијске датотеке'; $lang['allowdebug'] = 'Укључи дебаговање искључи ако није потребно!'; $lang['usewordblock'] = 'Блокирај спам на основу листе речи'; $lang['indexdelay'] = 'Одлагање индексирања (секунде)'; diff --git a/lib/plugins/config/lang/sv/lang.php b/lib/plugins/config/lang/sv/lang.php index d59b4b17e..2a83195d7 100644 --- a/lib/plugins/config/lang/sv/lang.php +++ b/lib/plugins/config/lang/sv/lang.php @@ -111,7 +111,6 @@ $lang['target____extern'] = 'Målfönster för externa länkar'; $lang['target____media'] = 'Målfönster för medialänkar'; $lang['target____windows'] = 'Målfönster för windowslänkar'; $lang['refcheck'] = 'Kontrollera referenser till mediafiler'; -$lang['refshow'] = 'Antal mediareferenser som ska visas'; $lang['gdlib'] = 'Version av GD-biblioteket'; $lang['im_convert'] = 'Sökväg till ImageMagicks konverteringsverktyg'; $lang['jpg_quality'] = 'Kvalitet för JPG-komprimering (0-100)'; diff --git a/lib/plugins/config/lang/tr/lang.php b/lib/plugins/config/lang/tr/lang.php index 5bc4f3fc1..45d70eeb0 100644 --- a/lib/plugins/config/lang/tr/lang.php +++ b/lib/plugins/config/lang/tr/lang.php @@ -79,7 +79,6 @@ $lang['iexssprotect'] = 'Yüklenmiş dosyaları muhtemel kötu niyetli $lang['htmlok'] = 'Gömülü HTML koduna izin ver'; $lang['phpok'] = 'Gömülü PHP koduna izin ver'; $lang['refcheck'] = 'Araç kaynak denetimi'; -$lang['refshow'] = 'Gösterilecek araç kaynağı sayısı'; $lang['gdlib'] = 'GD Lib sürümü'; $lang['jpg_quality'] = 'JPG sıkıştırma kalitesi [0-100]'; $lang['mailfrom'] = 'Otomatik e-postalar için kullanılacak e-posta adresi'; diff --git a/lib/plugins/config/lang/uk/lang.php b/lib/plugins/config/lang/uk/lang.php index 3d463fc72..c938d911b 100644 --- a/lib/plugins/config/lang/uk/lang.php +++ b/lib/plugins/config/lang/uk/lang.php @@ -102,7 +102,6 @@ $lang['target____extern'] = 'Target для зовнішніх посила $lang['target____media'] = 'Target для медіа-посилань'; $lang['target____windows'] = 'Target для посилань на мережеві папки'; $lang['refcheck'] = 'Перевіряти посилання на медіа-файлі'; -$lang['refshow'] = 'Показувати кількість медіа-посилань'; $lang['gdlib'] = 'Версія GD Lib'; $lang['im_convert'] = 'Шлях до ImageMagick'; $lang['jpg_quality'] = 'Якість компресії JPG (0-100)'; diff --git a/lib/plugins/config/lang/zh-tw/lang.php b/lib/plugins/config/lang/zh-tw/lang.php index cc6e0246e..7890730a6 100644 --- a/lib/plugins/config/lang/zh-tw/lang.php +++ b/lib/plugins/config/lang/zh-tw/lang.php @@ -109,7 +109,6 @@ $lang['target____media'] = '媒體連結的目標視窗'; $lang['target____windows'] = 'Windows 連結的目標視窗'; $lang['mediarevisions'] = '啟用媒體修訂歷史嗎?'; $lang['refcheck'] = '媒體連結檢查'; -$lang['refshow'] = '媒體連結的顯示數量'; $lang['gdlib'] = 'GD Lib 版本'; $lang['im_convert'] = 'ImageMagick 的轉換工具路徑'; $lang['jpg_quality'] = 'JPG 壓縮品質(0-100)'; diff --git a/lib/plugins/config/lang/zh/lang.php b/lib/plugins/config/lang/zh/lang.php index 832dfe749..903e987a3 100644 --- a/lib/plugins/config/lang/zh/lang.php +++ b/lib/plugins/config/lang/zh/lang.php @@ -114,7 +114,6 @@ $lang['target____media'] = '媒体文件链接的目标窗口'; $lang['target____windows'] = 'Windows 链接的目标窗口'; $lang['mediarevisions'] = '激活媒体修订历史?'; $lang['refcheck'] = '检查媒体与页面的挂钩情况'; -$lang['refshow'] = '显示媒体与页面挂钩情况的数量'; $lang['gdlib'] = 'GD 库版本'; $lang['im_convert'] = 'ImageMagick 转换工具的路径'; $lang['jpg_quality'] = 'JPG 压缩质量(0-100)'; diff --git a/lib/plugins/config/settings/config.metadata.php b/lib/plugins/config/settings/config.metadata.php index 22e76a013..ec549d6b4 100644 --- a/lib/plugins/config/settings/config.metadata.php +++ b/lib/plugins/config/settings/config.metadata.php @@ -161,7 +161,6 @@ $meta['im_convert'] = array('im_convert'); $meta['jpg_quality'] = array('numeric','_pattern' => '/^100$|^[1-9]?[0-9]$/'); //(0-100) $meta['fetchsize'] = array('numeric'); $meta['refcheck'] = array('onoff'); -$meta['refshow'] = array('numeric'); $meta['_notifications'] = array('fieldset'); $meta['subscribers'] = array('onoff'); -- cgit v1.2.3 From ae2cab4f84b5ccada7ace4108c30376a6f6214d3 Mon Sep 17 00:00:00 2001 From: Christopher Smith Date: Wed, 31 Jul 2013 18:38:02 +0200 Subject: add html5 attributes to register form --- inc/html.php | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/inc/html.php b/inc/html.php index fb39fcb3c..d94291090 100644 --- a/inc/html.php +++ b/inc/html.php @@ -1318,19 +1318,22 @@ function html_register(){ global $conf; global $INPUT; + $base_attrs = array('size'=>50,'required'=>'required'); + $email_attrs = $base_attrs + array('type'=>'email','class'=>'edit'); + print p_locale_xhtml('register'); print '
'.NL; $form = new Doku_Form(array('id' => 'dw__register')); $form->startFieldset($lang['btn_register']); $form->addHidden('do', 'register'); $form->addHidden('save', '1'); - $form->addElement(form_makeTextField('login', $INPUT->post->str('login'), $lang['user'], '', 'block', array('size'=>'50'))); + $form->addElement(form_makeTextField('login', $INPUT->post->str('login'), $lang['user'], '', 'block', $base_attrs)); if (!$conf['autopasswd']) { - $form->addElement(form_makePasswordField('pass', $lang['pass'], '', 'block', array('size'=>'50'))); - $form->addElement(form_makePasswordField('passchk', $lang['passchk'], '', 'block', array('size'=>'50'))); + $form->addElement(form_makePasswordField('pass', $lang['pass'], '', 'block', $base_attrs)); + $form->addElement(form_makePasswordField('passchk', $lang['passchk'], '', 'block', $base_attrs)); } - $form->addElement(form_makeTextField('fullname', $INPUT->post->str('fullname'), $lang['fullname'], '', 'block', array('size'=>'50'))); - $form->addElement(form_makeTextField('email', $INPUT->post->str('email'), $lang['email'], '', 'block', array('size'=>'50'))); + $form->addElement(form_makeTextField('fullname', $INPUT->post->str('fullname'), $lang['fullname'], '', 'block', $base_attrs)); + $form->addElement(form_makeField('email','email', $INPUT->post->str('email'), $lang['email'], '', 'block', $email_attrs)); $form->addElement(form_makeButton('submit', '', $lang['btn_register'])); $form->endFieldset(); html_form('register', $form); -- cgit v1.2.3 From 4ca5544873b7682dd9e905ad9d0028bf9bcddd5c Mon Sep 17 00:00:00 2001 From: Christopher Smith Date: Wed, 31 Jul 2013 18:38:31 +0200 Subject: add html5 attributes to update profile form --- inc/html.php | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/inc/html.php b/inc/html.php index d94291090..53f4c45ff 100644 --- a/inc/html.php +++ b/inc/html.php @@ -1356,10 +1356,10 @@ function html_updateprofile(){ global $auth; print p_locale_xhtml('updateprofile'); + print '
'.NL; $fullname = $INPUT->post->str('fullname', $INFO['userinfo']['name'], true); $email = $INPUT->post->str('email', $INFO['userinfo']['mail'], true); - print '
'.NL; $form = new Doku_Form(array('id' => 'dw__register')); $form->startFieldset($lang['profile']); $form->addHidden('do', 'profile'); @@ -1368,9 +1368,9 @@ function html_updateprofile(){ $attr = array('size'=>'50'); if (!$auth->canDo('modName')) $attr['disabled'] = 'disabled'; $form->addElement(form_makeTextField('fullname', $fullname, $lang['fullname'], '', 'block', $attr)); - $attr = array('size'=>'50'); + $attr = array('size'=>'50', 'class'=>'edit'); if (!$auth->canDo('modMail')) $attr['disabled'] = 'disabled'; - $form->addElement(form_makeTextField('email', $email, $lang['email'], '', 'block', $attr)); + $form->addElement(form_makeField('email','email', $email, $lang['email'], '', 'block', $attr)); $form->addElement(form_makeTag('br')); if ($auth->canDo('modPass')) { $form->addElement(form_makePasswordField('newpass', $lang['newpass'], '', 'block', array('size'=>'50'))); @@ -1378,10 +1378,11 @@ function html_updateprofile(){ } if ($conf['profileconfirm']) { $form->addElement(form_makeTag('br')); - $form->addElement(form_makePasswordField('oldpass', $lang['oldpass'], '', 'block', array('size'=>'50'))); + $form->addElement(form_makePasswordField('oldpass', $lang['oldpass'], '', 'block', array('size'=>'50', 'required' => 'required'))); } $form->addElement(form_makeButton('submit', '', $lang['btn_save'])); $form->addElement(form_makeButton('reset', '', $lang['btn_reset'])); + $form->endFieldset(); html_form('updateprofile', $form); print '
'.NL; -- cgit v1.2.3 From 4eb3462fac9bb0d739d48a98bba6a21c6a727e3b Mon Sep 17 00:00:00 2001 From: Christopher Smith Date: Wed, 31 Jul 2013 18:41:02 +0200 Subject: Change error message shown for incorrect current password on update profile form. The current message confusingly mentions bad 'username' when username is not involved. The new message is the same as that introduced for an incorrect current password on the self delete profile form (FS#2751) --- inc/auth.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/inc/auth.php b/inc/auth.php index 96b80e19e..a1c92ec80 100644 --- a/inc/auth.php +++ b/inc/auth.php @@ -1024,7 +1024,7 @@ function updateprofile() { if($conf['profileconfirm']) { if(!$auth->checkPass($_SERVER['REMOTE_USER'], $INPUT->post->str('oldpass'))) { - msg($lang['badlogin'], -1); + msg($lang['badpassconfirm'], -1); return false; } } -- cgit v1.2.3 From a588ab29f86cc2971ec131bec02e2810d6409a55 Mon Sep 17 00:00:00 2001 From: Christopher Smith Date: Wed, 31 Jul 2013 18:51:06 +0200 Subject: add html5 'email' type to the user manager forms --- lib/plugins/usermanager/admin.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/plugins/usermanager/admin.php b/lib/plugins/usermanager/admin.php index 445836a50..ca4c6a650 100644 --- a/lib/plugins/usermanager/admin.php +++ b/lib/plugins/usermanager/admin.php @@ -311,6 +311,9 @@ class admin_plugin_usermanager extends DokuWiki_Admin_Plugin { if($name == 'userpass'){ $fieldtype = 'password'; $autocomp = 'autocomplete="off"'; + }elseif($name == 'usermail'){ + $fieldtype = 'email'; + $autocomp = ''; }else{ $fieldtype = 'text'; $autocomp = ''; -- cgit v1.2.3 From 0d21c87f31bb8931973f720c04346bf5f8612470 Mon Sep 17 00:00:00 2001 From: Christopher Smith Date: Wed, 31 Jul 2013 19:07:29 +0200 Subject: add html5 attributes to email fields of the config manager --- lib/plugins/config/settings/config.class.php | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/lib/plugins/config/settings/config.class.php b/lib/plugins/config/settings/config.class.php index 8eb99284d..63be3a726 100644 --- a/lib/plugins/config/settings/config.class.php +++ b/lib/plugins/config/settings/config.class.php @@ -717,6 +717,29 @@ if (!class_exists('setting_email')) { $this->_local = $input; return true; } + function html(&$plugin, $echo=false) { + $value = ''; + $disable = ''; + + if ($this->is_protected()) { + $value = $this->_protected; + $disable = 'disabled="disabled"'; + } else { + if ($echo && $this->_error) { + $value = $this->_input; + } else { + $value = is_null($this->_local) ? $this->_default : $this->_local; + } + } + + $multiple = $this->_multiple ? 'multiple="multiple"' : ''; + $key = htmlspecialchars($this->_key); + $value = htmlspecialchars($value); + + $label = ''; + $input = ''; + return array($label,$input); + } } } -- cgit v1.2.3 From fdd9bab63c332a19e213c2cf7c986b8b95e25af6 Mon Sep 17 00:00:00 2001 From: Christopher Smith Date: Thu, 1 Aug 2013 11:37:00 +0200 Subject: increase test coverage for code and file code - test correct recognition of downloadable filename token file - test correct recognition of syntax name & downloadable filename tokens --- _test/tests/inc/parser/parser_code.test.php | 16 ++++++++++++++++ _test/tests/inc/parser/parser_file.test.php | 28 ++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/_test/tests/inc/parser/parser_code.test.php b/_test/tests/inc/parser/parser_code.test.php index 4f89b4826..c50d2d328 100644 --- a/_test/tests/inc/parser/parser_code.test.php +++ b/_test/tests/inc/parser/parser_code.test.php @@ -40,6 +40,22 @@ class TestOfDoku_Parser_Code extends TestOfDoku_Parser { $this->assertEquals(array_map('stripbyteindex',$this->H->calls),$calls); } + function testCodeDownload() { + $this->P->parse('Foo Test Bar'); + $calls = array ( + array('document_start',array()), + array('p_open',array()), + array('cdata',array("\n".'Foo ')), + array('p_close',array()), + array('code',array('Test','bash','script.sh')), + array('p_open',array()), + array('cdata',array(' Bar')), + array('p_close',array()), + array('document_end',array()), + ); + $this->assertEquals(array_map('stripbyteindex',$this->H->calls),$calls); + } + function testCodeToken() { $this->P->parse('Foo BarTest'); $calls = array ( diff --git a/_test/tests/inc/parser/parser_file.test.php b/_test/tests/inc/parser/parser_file.test.php index 924b00382..39bda8a58 100644 --- a/_test/tests/inc/parser/parser_file.test.php +++ b/_test/tests/inc/parser/parser_file.test.php @@ -24,5 +24,33 @@ class TestOfDoku_Parser_File extends TestOfDoku_Parser { $this->assertEquals(array_map('stripbyteindex',$this->H->calls),$calls); } + function testFileHighlightDownload() { + $this->P->parse('Foo Test Bar'); + $calls = array ( + array('document_start',array()), + array('p_open',array()), + array('cdata',array("\n".'Foo ')), + array('p_close',array()), + array('file',array('Test','txt','test.txt')), + array('p_open',array()), + array('cdata',array(' Bar')), + array('p_close',array()), + array('document_end',array()), + ); + $this->assertEquals(array_map('stripbyteindex',$this->H->calls),$calls); + } + + function testFileToken() { + $this->P->parse('Foo Test Bar'); + $calls = array ( + array('document_start',array()), + array('p_open',array()), + array('cdata',array("\n".'Foo Test Bar')), + array('p_close',array()), + array('document_end',array()), + ); + $this->assertEquals(array_map('stripbyteindex',$this->H->calls),$calls); + } + } -- cgit v1.2.3 From 65f0aa62806695ee51cc94679913449b7ad862d6 Mon Sep 17 00:00:00 2001 From: Christopher Smith Date: Thu, 1 Aug 2013 11:49:52 +0200 Subject: update config metadata comments for parameter '_multiple' --- lib/plugins/config/settings/config.metadata.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/plugins/config/settings/config.metadata.php b/lib/plugins/config/settings/config.metadata.php index ec549d6b4..2fb08037d 100644 --- a/lib/plugins/config/settings/config.metadata.php +++ b/lib/plugins/config/settings/config.metadata.php @@ -20,7 +20,8 @@ * 'numericopt' - like above, but accepts empty values * 'onoff' - checkbox input, setting output 0|1 * 'multichoice' - select input (single choice), setting output with quotes, required _choices parameter - * 'email' - text input, input must conform to email address format + * 'email' - text input, input must conform to email address format, supports optional '_multiple' + * parameter for multiple comma separated email addresses * 'password' - password input, minimal input validation, setting output text in quotes, maybe encoded * according to the _code parameter * 'dirchoice' - as multichoice, selection choices based on folders found at location specified in _dir @@ -58,6 +59,7 @@ * '_code' - encoding method to use, accepted values: 'base64','uuencode','plain'. defaults to plain. * '_min' - minimum numeric value, optional for 'numeric' and 'numericopt', ignored by others * '_max' - maximum numeric value, optional for 'numeric' and 'numericopt', ignored by others + * '_multiple' - bool, allow multiple comma separated email values; optional for 'email', ignored by others * * @author Chris Smith */ -- cgit v1.2.3 From b1af90141d42f8844159ff4fad76968a8ee78687 Mon Sep 17 00:00:00 2001 From: Christopher Smith Date: Thu, 1 Aug 2013 16:32:28 +0200 Subject: Improve nofollow behaviour for ?do=index In response to FS#2766 - make namespace links in the browser sitemap nofollow - remove nofollow from browser sitemap link on the wiki start page when sitemap.xml generation is disabled --- inc/html.php | 3 ++- inc/template.php | 12 ++++++++++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/inc/html.php b/inc/html.php index 53f4c45ff..53a100ec7 100644 --- a/inc/html.php +++ b/inc/html.php @@ -859,7 +859,8 @@ function html_list_index($item){ $base = ':'.$item['id']; $base = substr($base,strrpos($base,':')+1); if($item['type']=='d'){ - $ret .= ''; + // FS#2766, no need for search bots to follow namespace links in the index + $ret .= ''; $ret .= $base; $ret .= ''; }else{ diff --git a/inc/template.php b/inc/template.php index b8129f914..54407c2ab 100644 --- a/inc/template.php +++ b/inc/template.php @@ -541,6 +541,7 @@ function tpl_actionlink($type, $pre = '', $suf = '', $inner = '', $return = fals * @var string $accesskey * @var string $id * @var string $method + * @var bool $nofollow * @var array $params */ extract($data); @@ -555,10 +556,11 @@ function tpl_actionlink($type, $pre = '', $suf = '', $inner = '', $return = fals $akey = 'accesskey="'.$accesskey.'" '; $addTitle = ' ['.strtoupper($accesskey).']'; } + $rel = $nofollow ? 'rel="nofollow" ' : ''; $out = tpl_link( $linktarget, $pre.(($inner) ? $inner : $caption).$suf, 'class="action '.$type.'" '. - $akey.'rel="nofollow" '. + $akey.$rel. 'title="'.hsc($caption).$addTitle.'"', 1 ); } @@ -595,6 +597,7 @@ function tpl_get_action($type) { global $INFO; global $REV; global $ACT; + global $conf; // check disabled actions and fix the badly named ones if($type == 'history') $type = 'revisions'; @@ -604,6 +607,7 @@ function tpl_get_action($type) { $id = $ID; $method = 'get'; $params = array('do' => $type); + $nofollow = true; switch($type) { case 'edit': // most complicated type - we need to decide on current action @@ -641,6 +645,10 @@ function tpl_get_action($type) { break; case 'index': $accesskey = 'x'; + // allow searchbots to get to the sitemap from the homepage (when dokuwiki isn't providing a sitemap.xml) + if ($conf['start'] == $ID && !$conf['sitemap']) { + $nofollow = false; + } break; case 'top': $accesskey = 't'; @@ -711,7 +719,7 @@ function tpl_get_action($type) { return '[unknown %s type]'; break; } - return compact('accesskey', 'type', 'id', 'method', 'params'); + return compact('accesskey', 'type', 'id', 'method', 'params', 'nofollow'); } /** -- cgit v1.2.3 From 5a99d25b24f7e14f137084100f40325b7a2a71b4 Mon Sep 17 00:00:00 2001 From: Anika Henke Date: Thu, 1 Aug 2013 16:38:02 +0100 Subject: added aria attributes to edit mode --- inc/html.php | 2 +- inc/lang/de/lang.php | 2 +- inc/lang/en/lang.php | 2 +- lib/scripts/edit.js | 9 ++++++--- lib/scripts/editor.js | 1 + lib/scripts/toolbar.js | 29 ++++++++++++++++++++--------- 6 files changed, 30 insertions(+), 15 deletions(-) diff --git a/inc/html.php b/inc/html.php index fb39fcb3c..9c69c9845 100644 --- a/inc/html.php +++ b/inc/html.php @@ -1488,7 +1488,7 @@ function html_edit(){ echo 'textChanged = ' . ($mod ? 'true' : 'false'); echo '/*!]]>*/' . NL; } ?> -
+
diff --git a/inc/lang/de/lang.php b/inc/lang/de/lang.php index af6f32bf4..aa0a3d3b2 100644 --- a/inc/lang/de/lang.php +++ b/inc/lang/de/lang.php @@ -235,7 +235,7 @@ $lang['qb_extlink'] = 'Externer Link'; $lang['qb_hr'] = 'Horizontale Linie'; $lang['qb_ol'] = 'Nummerierter Listenpunkt'; $lang['qb_ul'] = 'Listenpunkt'; -$lang['qb_media'] = 'Bilder und andere Dateien hinzufügen'; +$lang['qb_media'] = 'Bilder und andere Dateien hinzufügen (öffnet sich in einem neuen Fenster)'; $lang['qb_sig'] = 'Unterschrift einfügen'; $lang['qb_smileys'] = 'Smileys'; $lang['qb_chars'] = 'Sonderzeichen'; diff --git a/inc/lang/en/lang.php b/inc/lang/en/lang.php index cdad6c9a6..00e71d254 100644 --- a/inc/lang/en/lang.php +++ b/inc/lang/en/lang.php @@ -234,7 +234,7 @@ $lang['qb_extlink'] = 'External Link'; $lang['qb_hr'] = 'Horizontal Rule'; $lang['qb_ol'] = 'Ordered List Item'; $lang['qb_ul'] = 'Unordered List Item'; -$lang['qb_media'] = 'Add Images and other files'; +$lang['qb_media'] = 'Add Images and other files (opens in a new window)'; $lang['qb_sig'] = 'Insert Signature'; $lang['qb_smileys'] = 'Smileys'; $lang['qb_chars'] = 'Special Chars'; diff --git a/lib/scripts/edit.js b/lib/scripts/edit.js index 5a5e829bd..b1dbff683 100644 --- a/lib/scripts/edit.js +++ b/lib/scripts/edit.js @@ -23,7 +23,7 @@ function createToolButton(icon,label,key,id,classname){ $btn.addClass(classname); } - $btn.attr('title', label); + $btn.attr('title', label).attr('aria-controls', 'wiki__text'); if(key){ $btn.attr('title', label + ' ['+key.toUpperCase()+']') .attr('accessKey', key); @@ -40,6 +40,7 @@ function createToolButton(icon,label,key,id,classname){ icon = DOKU_BASE + 'lib/images/toolbar/' + icon; } $ico.attr('src', icon); + $ico.attr('alt', ''); $ico.attr('width', 16); $ico.attr('height', 16); $btn.append($ico); @@ -76,6 +77,7 @@ function createPicker(id,props,edid){ function $makebutton(title) { var $btn = jQuery(document.createElement('button')) .addClass('pickerbutton').attr('title', title) + .attr('aria-controls', edid) .bind('click', bind(pickerInsert, title, edid)) .appendTo($picker); return $btn; @@ -93,6 +95,7 @@ function createPicker(id,props,edid){ } jQuery(document.createElement('img')) .attr('src', item) + .attr('alt', '') .appendTo($makebutton(key)); }else if (typeof item == 'string'){ // a list of text -> treat as text picker @@ -132,9 +135,9 @@ function pickerInsert(text,edid){ function addBtnActionSignature($btn, props, edid) { if(typeof SIG != 'undefined' && SIG != ''){ $btn.bind('click', bind(insertAtCarret,edid,SIG)); - return true; + return edid; } - return false; + return ''; } /** diff --git a/lib/scripts/editor.js b/lib/scripts/editor.js index 042e34608..2c0924eb7 100644 --- a/lib/scripts/editor.js +++ b/lib/scripts/editor.js @@ -65,6 +65,7 @@ var dw_editor = { ], function (_, img) { jQuery(document.createElement('IMG')) .attr('src', DOKU_BASE+'lib/images/' + img[0] + '.gif') + .attr('alt', '') .click(img[1]) .appendTo($ctl); }); diff --git a/lib/scripts/toolbar.js b/lib/scripts/toolbar.js index 6d75215e0..5fc4d835e 100644 --- a/lib/scripts/toolbar.js +++ b/lib/scripts/toolbar.js @@ -52,8 +52,13 @@ function initToolbar(tbid,edid,tb, allowblock){ // type is a init function -> execute it actionFunc = 'addBtnAction'+val.type.charAt(0).toUpperCase()+val.type.substring(1); if( jQuery.isFunction(window[actionFunc]) ){ - if(window[actionFunc]($btn, val, edid)){ + var pickerid = window[actionFunc]($btn, val, edid); + if(pickerid !== ''){ $toolbar.append($btn); + $btn.attr('aria-controls', pickerid); + if (actionFunc === 'addBtnActionPicker') { + $btn.attr('aria-haspopup', 'true'); + } } return; } @@ -190,16 +195,17 @@ function tb_autohead(btn, props, edid){ */ function addBtnActionPicker($btn, props, edid) { var pickerid = 'picker'+(pickercounter++); - createPicker(pickerid, props, edid); + var picker = createPicker(pickerid, props, edid); + jQuery(picker).attr('aria-hidden', 'true'); $btn.click( function() { pickerToggle(pickerid,$btn); - return false; + return ''; } ); - return true; + return pickerid; } /** @@ -215,22 +221,26 @@ function addBtnActionLinkwiz(btn, props, edid) { dw_linkwiz.init(jQuery('#'+edid)); jQuery(btn).click(function(){ dw_linkwiz.toggle(); - return false; + return ''; }); - return true; + return 'link__wiz'; } /** - * Show/Hide a previosly created picker window + * Show/Hide a previously created picker window * * @author Andreas Gohr */ function pickerToggle(pickerid,$btn){ var $picker = jQuery('#' + pickerid), pos = $btn.offset(); - $picker.toggleClass('a11y') - .offset({left: pos.left+3, top: pos.top+$btn[0].offsetHeight+3}); + if ($picker.hasClass('a11y')) { + $picker.removeClass('a11y').attr('aria-hidden', 'false'); + } else { + $picker.addClass('a11y').attr('aria-hidden', 'true'); + } + $picker.offset({left: pos.left+3, top: pos.top+$btn[0].offsetHeight+3}); } /** @@ -252,4 +262,5 @@ function fixtxt(str){ jQuery(function () { initToolbar('tool__bar','wiki__text',toolbar); + jQuery('#tool__bar').attr('role', 'toolbar'); }); -- cgit v1.2.3 From 193e22801d763e715f03f241b135a2e249c6132e Mon Sep 17 00:00:00 2001 From: Anika Henke Date: Thu, 1 Aug 2013 16:42:31 +0100 Subject: removed unused and old hasFlash() JS function --- lib/scripts/helpers.js | 19 ------------------- lib/scripts/media.js | 19 ------------------- 2 files changed, 38 deletions(-) diff --git a/lib/scripts/helpers.js b/lib/scripts/helpers.js index d6f36967d..632c4bff2 100644 --- a/lib/scripts/helpers.js +++ b/lib/scripts/helpers.js @@ -2,25 +2,6 @@ * Various helper functions */ -/** - * Very simplistic Flash plugin check, probably works for Flash 8 and higher only - * - * @author Andreas Gohr - */ -function hasFlash(version){ - var ver = 0; - try{ - if(navigator.plugins != null && navigator.plugins.length > 0){ - ver = navigator.plugins["Shockwave Flash"].description.split(' ')[2].split('.')[0]; - }else{ - ver = (new ActiveXObject("ShockwaveFlash.ShockwaveFlash")) - .GetVariable("$version").split(' ')[1].split(',')[0]; - } - }catch(e){ } - - return ver >= version; -} - /** * A PHP-style substr_replace * diff --git a/lib/scripts/media.js b/lib/scripts/media.js index 182d5fefe..8ca21ecab 100644 --- a/lib/scripts/media.js +++ b/lib/scripts/media.js @@ -921,23 +921,4 @@ var dw_mediamanager = { } }; -// moved from helpers.js temporarily here -/** - * Very simplistic Flash plugin check, probably works for Flash 8 and higher only - * - */ -function hasFlash(version){ - var ver = 0, axo; - try{ - if(navigator.plugins !== null && navigator.plugins.length > 0){ - ver = navigator.plugins["Shockwave Flash"].description.split(' ')[2].split('.')[0]; - }else{ - axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash"); - ver = axo.GetVariable("$version").split(' ')[1].split(',')[0]; - } - }catch(e){ } - - return ver >= version; -} - jQuery(dw_mediamanager.init); -- cgit v1.2.3 From 5c967d3d04622c1420313f1a514da5cda99827f3 Mon Sep 17 00:00:00 2001 From: Christopher Smith Date: Thu, 1 Aug 2013 18:04:01 +0200 Subject: add csv export functionality to the user manager --- lib/plugins/usermanager/admin.php | 39 +++++++++++++++++++++++++++++++- lib/plugins/usermanager/lang/en/lang.php | 2 ++ 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/lib/plugins/usermanager/admin.php b/lib/plugins/usermanager/admin.php index ca4c6a650..72ac47e15 100644 --- a/lib/plugins/usermanager/admin.php +++ b/lib/plugins/usermanager/admin.php @@ -101,6 +101,7 @@ class admin_plugin_usermanager extends DokuWiki_Admin_Plugin { case "search" : $this->_setFilter($param); $this->_start = 0; break; + case "export" : $this->_export(); break; } $this->_user_total = $this->_auth->canDo('getUserCount') ? $this->_auth->getUserCount($this->_filter) : -1; @@ -133,6 +134,7 @@ class admin_plugin_usermanager extends DokuWiki_Admin_Plugin { $delete_disable = $this->_auth->canDo('delUser') ? '' : 'disabled="disabled"'; $editable = $this->_auth->canDo('UserMod'); + $export_label = empty($this->_filter) ? $this->lang['export_all'] : $this->lang[export_filtered]; print $this->locale_xhtml('intro'); print $this->locale_xhtml('list'); @@ -196,7 +198,10 @@ class admin_plugin_usermanager extends DokuWiki_Admin_Plugin { ptln(" lang['next']."\" />"); ptln(" lang['last']."\" />"); ptln(" "); - ptln(" lang['clear']."\" />"); + if (!empty($this->_filter)) { + ptln(" lang['clear']."\" />"); + } + ptln(" "); ptln(" "); ptln(" "); @@ -629,4 +634,36 @@ class admin_plugin_usermanager extends DokuWiki_Admin_Plugin { return $buttons; } + + /* + * export a list of users in csv format using the current filter criteria + */ + function _export() { + // list of users for export - based on current filter criteria + $user_list = $this->_auth->retrieveUsers(0, 0, $this->_filter); + $column_headings = array( + $this->lang["user_id"], + $this->lang["user_name"], + $this->lang["user_mail"], + $this->lang["user_groups"] + ); + + // ============================================================================================== + // GENERATE OUTPUT + // normal headers for downloading... + header('Content-type: text/csv;charset=utf-8'); + header('Content-Disposition: attachment; filename="wikiusers.csv"'); +# // for debugging assistance, send as text plain to the browser +# header('Content-type: text/plain;charset=utf-8'); + + // output the csv + $fd = fopen('php://output','w'); + fputcsv($fd, $column_headings); + foreach ($user_list as $user => $info) { + $line = array($user, $info['name'], $info['mail'], join(',',$info['grps'])); + fputcsv($fd, $line); + } + fclose($fd); + die; + } } diff --git a/lib/plugins/usermanager/lang/en/lang.php b/lib/plugins/usermanager/lang/en/lang.php index 189a1db20..ae0ee1c16 100644 --- a/lib/plugins/usermanager/lang/en/lang.php +++ b/lib/plugins/usermanager/lang/en/lang.php @@ -31,6 +31,8 @@ $lang['search'] = 'Search'; $lang['search_prompt'] = 'Perform search'; $lang['clear'] = 'Reset Search Filter'; $lang['filter'] = 'Filter'; +$lang['export_all'] = 'Export All Users (CSV)'; +$lang['export_filtered'] = 'Export Filtered User list (CSV)'; $lang['summary'] = 'Displaying users %1$d-%2$d of %3$d found. %4$d users total.'; $lang['nonefound'] = 'No users found. %d users total.'; -- cgit v1.2.3 From 763ffe58812aba9b1e6fe2bca4bb74187ab16ea3 Mon Sep 17 00:00:00 2001 From: Anika Henke Date: Thu, 1 Aug 2013 17:11:29 +0100 Subject: added aria attributes for footnote tooltips --- lib/scripts/page.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/scripts/page.js b/lib/scripts/page.js index 4ab0bf9b5..7b4958d82 100644 --- a/lib/scripts/page.js +++ b/lib/scripts/page.js @@ -62,7 +62,9 @@ dw_page = { $fndiv = jQuery(document.createElement('div')) .attr('id', popup_id) .addClass('insitu-footnote JSpopup') - .mouseleave(function () {jQuery(this).hide();}); + .attr('aria-hidden', 'true') + .mouseleave(function () {jQuery(this).hide().attr('aria-hidden', 'true');}) + .attr('role', 'tooltip'); jQuery('.dokuwiki:first').append($fndiv); } @@ -97,7 +99,7 @@ dw_page = { content = content.replace(/\bid=(['"])([^"']+)\1/gi,'id="insitu__$2'); // now put the content into the wrapper - dw_page.insituPopup(this, 'insitu__fn').html(content).show(); + dw_page.insituPopup(this, 'insitu__fn').html(content).show().attr('aria-hidden', 'false'); }, /** -- cgit v1.2.3 From 9805efa058358e0fcbd3976fa553901cabe0b2e0 Mon Sep 17 00:00:00 2001 From: Anika Henke Date: Thu, 1 Aug 2013 17:20:25 +0100 Subject: added aria roles to search and acl manager --- inc/template.php | 2 +- lib/plugins/acl/script.js | 1 + lib/scripts/tw-sack.js | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/inc/template.php b/inc/template.php index a87650b84..0f2144275 100644 --- a/inc/template.php +++ b/inc/template.php @@ -766,7 +766,7 @@ function tpl_searchform($ajax = true, $autocomplete = true) { // don't print the search form if search action has been disabled if(!actionOK('search')) return false; - print '